From c8ab2909c67703ad1255aa27159049f058d1a361 Mon Sep 17 00:00:00 2001 From: Walter van Niftrik Date: Fri, 26 Feb 2016 23:32:06 +0100 Subject: ADL: Initial check-in for ADL engine --- engines/adl/adl.cpp | 155 ++++++++++ engines/adl/adl.h | 98 ++++++ engines/adl/adl_v1.cpp | 690 +++++++++++++++++++++++++++++++++++++++++++ engines/adl/adl_v1.h | 133 +++++++++ engines/adl/configure.engine | 3 + engines/adl/detection.cpp | 108 +++++++ engines/adl/display.cpp | 611 ++++++++++++++++++++++++++++++++++++++ engines/adl/display.h | 103 +++++++ engines/adl/module.mk | 19 ++ engines/adl/parser.cpp | 172 +++++++++++ engines/adl/parser.h | 66 +++++ 11 files changed, 2158 insertions(+) create mode 100644 engines/adl/adl.cpp create mode 100644 engines/adl/adl.h create mode 100644 engines/adl/adl_v1.cpp create mode 100644 engines/adl/adl_v1.h create mode 100644 engines/adl/configure.engine create mode 100644 engines/adl/detection.cpp create mode 100644 engines/adl/display.cpp create mode 100644 engines/adl/display.h create mode 100644 engines/adl/module.mk create mode 100644 engines/adl/parser.cpp create mode 100644 engines/adl/parser.h (limited to 'engines') diff --git a/engines/adl/adl.cpp b/engines/adl/adl.cpp new file mode 100644 index 0000000000..be3d8d7151 --- /dev/null +++ b/engines/adl/adl.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 "common/scummsys.h" + +#include "common/config-manager.h" +#include "common/debug.h" +#include "common/debug-channels.h" +#include "common/error.h" +#include "common/file.h" +#include "common/fs.h" +#include "common/system.h" +#include "common/events.h" +#include "common/stream.h" +#include "graphics/palette.h" + +#include "engines/util.h" + +#include "adl/adl.h" +#include "adl/display.h" +#include "adl/parser.h" + +namespace Adl { + +Common::String asciiToApple(Common::String str) { + Common::String ret(str); + Common::String::iterator it; + + for (it = ret.begin(); it != ret.end(); ++it) + *it = *it | 0x80; + + return ret; +} + +Common::String appleToAscii(Common::String str) { + Common::String ret(str); + Common::String::iterator it; + + for (it = ret.begin(); it != ret.end(); ++it) + *it = *it & 0x7f; + + return ret; +} + +AdlEngine::AdlEngine(OSystem *syst, const AdlGameDescription *gd) : + Engine(syst), + _gameDescription(gd), + _console(nullptr), + _display(nullptr) { + // Put your engine in a sane state, but do nothing big yet; + // in particular, do not load data from files; rather, if you + // need to do such things, do them from run(). + + // Do not initialize graphics here + // Do not initialize audio devices here + + // However this is the place to specify all default directories + const Common::FSNode gameDataDir(ConfMan.get("path")); + SearchMan.addSubDirectoryMatching(gameDataDir, "sound"); + + // Don't forget to register your random source + _rnd = new Common::RandomSource("adl"); + + debug("AdlEngine::AdlEngine"); +} + +AdlEngine::~AdlEngine() { + debug("AdlEngine::~AdlEngine"); + + delete _rnd; + delete _console; + delete _display; + + DebugMan.clearAllDebugChannels(); +} + +Common::Error AdlEngine::run() { + initGraphics(560, 384, true); + + byte palette[6 * 3] = { + 0x00, 0x00, 0x00, + 0xff, 0xff, 0xff, + 0xc7, 0x34, 0xff, + 0x38, 0xcb, 0x00, + 0x00, 0x00, 0xff, // FIXME + 0xff, 0xa5, 0x00 // FIXME + }; + + g_system->getPaletteManager()->setPalette(palette, 0, 6); + + _console = new Console(this); + _display = new Display(); + _parser = new Parser(*this, *_display); + + runGame(); + + return Common::kNoError; +} + +Common::String AdlEngine::readString(Common::ReadStream &stream, byte until) { + Common::String str; + + while (1) { + byte b = stream.readByte(); + + if (stream.eos() || stream.err() || b == until) + break; + + str += b; + }; + + return str; +} + +void AdlEngine::printStrings(Common::SeekableReadStream &stream, int count) { + while (1) { + Common::String str = readString(stream); + _display->printString(str); + + if (--count == 0) + break; + + stream.seek(3, SEEK_CUR); + }; +} + +AdlEngine *AdlEngine::create(GameType type, OSystem *syst, const AdlGameDescription *gd) { + switch(type) { + case kGameTypeAdl1: + return AdlEngine_v1__create(syst, gd); + default: + error("Unknown GameType"); + } +} + +} // End of namespace Adl diff --git a/engines/adl/adl.h b/engines/adl/adl.h new file mode 100644 index 0000000000..d5a518faa7 --- /dev/null +++ b/engines/adl/adl.h @@ -0,0 +1,98 @@ +/* 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 ADL_ADL_H +#define ADL_ADL_H + +#include "common/random.h" +#include "engines/engine.h" +#include "gui/debugger.h" + +namespace Common { +class ReadStream; +class SeekableReadStream; +} + +namespace Adl { + +class Display; +class Parser; +class Console; +struct AdlGameDescription; + +enum GameType { + kGameTypeNone = 0, + kGameTypeAdl1 +}; + +Common::String asciiToApple(Common::String str); +Common::String appleToAscii(Common::String str); + +enum { + STR_COMMON_ENTERCMD, + STR_COMMON_VERBERR, + STR_COMMON_NOUNERR, + STR_CUSTOM_START +}; + +#define A2CHAR(C) ((C) | 0x80) + +class AdlEngine : public Engine { +public: + AdlEngine(OSystem *syst, const AdlGameDescription *gd); + virtual ~AdlEngine(); + + const AdlGameDescription *_gameDescription; + uint32 getFeatures() const; + const char *getGameId() const; + + static AdlEngine *create(GameType type, OSystem *syst, const AdlGameDescription *gd); + + Common::Error run(); + virtual Common::String getExeString(uint id) = 0; + +protected: + virtual void runGame() = 0; + Common::String readString(Common::ReadStream &stream, byte until = 0); + void printStrings(Common::SeekableReadStream &stream, int count = 1); + Display *_display; + Parser *_parser; + +private: + Console *_console; + + // We need random numbers + Common::RandomSource *_rnd; +}; + +// Example console class +class Console : public GUI::Debugger { +public: + Console(AdlEngine *vm) {} + virtual ~Console(void) {} +}; + +AdlEngine *AdlEngine_v1__create(OSystem *syst, const AdlGameDescription *gd); + +} // End of namespace Adl + +#endif diff --git a/engines/adl/adl_v1.cpp b/engines/adl/adl_v1.cpp new file mode 100644 index 0000000000..61671e5d7f --- /dev/null +++ b/engines/adl/adl_v1.cpp @@ -0,0 +1,690 @@ +/* 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.h" +#include "common/debug-channels.h" +#include "common/error.h" +#include "common/file.h" +#include "common/fs.h" +#include "common/system.h" +#include "common/events.h" +#include "common/stream.h" +#include "graphics/palette.h" + +#include "engines/util.h" + +#include "adl/adl_v1.h" +#include "adl/display.h" +#include "adl/parser.h" + +namespace Adl { + +static uint exeStrings[STR_MH_TOTAL] = { + 23484, 23375, 23438, 27658, 0x6c31, 27729, 27772, 0x5f1e +}; + +AdlEngine_v1::AdlEngine_v1(OSystem *syst, const AdlGameDescription *gd) : + AdlEngine(syst, gd), + _state(kIntro), + _room(1), + _steps(1), + _isDark(false) { + _variables.resize(20); +} + +void AdlEngine_v1::runIntro() { + Common::File file; + + if (!file.open("AUTO LOAD OBJ")) + error("Failed to open file"); + + file.seek(0x1003); + _display->setMode(Display::kModeHires); + _display->loadFrameBuffer(file); + _display->decodeFrameBuffer(); + _display->delay(4000); + + if (shouldQuit()) + return; + + _display->setMode(Display::kModeText); + + Common::File basic; + if (!basic.open("MYSTERY.HELLO")) + error("Failed to open file"); + + Common::String str; + + basic.seek(93); + str = readString(basic, '"'); + _display->printASCIIString(str + '\r'); + + basic.seek(299); + str = readString(basic, '"'); + _display->printASCIIString(str + "\r\r"); + + basic.seek(365); + str = readString(basic, '"'); + _display->printASCIIString(str + "\r\r"); + + basic.seek(601); + str = readString(basic, '"'); + _display->printASCIIString(str + '\r'); + + _display->inputKey(); + if (g_engine->shouldQuit()) + return; + + _display->setMode(Display::kModeMixed); + + file.seek(15); + str = readString(file); + + while (1) { + _display->printString(str); + Common::String s = _display->inputString(); + + if (g_engine->shouldQuit()) + break; + + if (s.empty()) + continue; + + if ((byte)s[0] == ('I' | 0x80)) + break; + else if ((byte)s[0] == ('G' | 0x80)) + return; + }; + + _display->setMode(Display::kModeText); + file.seek(102); + + const int pages[] = { 6, 6, 4, 5, 8, 7, 0 }; + + int page = 0; + while (pages[page] != 0) { + _display->home(); + printStrings(file, pages[page++]); + _display->inputString(); + + if (g_engine->shouldQuit()) + return; + + file.seek(9, SEEK_CUR); + } +} + +void AdlEngine_v1::drawPic(Common::ReadStream &stream, byte xOffset, byte yOffset) { + byte x, y; + bool bNewLine = false; + byte oldX = 0, oldY = 0; + while (1) { + x = stream.readByte(); + y = stream.readByte(); + + if (stream.err() || stream.eos()) + error("Failed to read picture"); + + if (x == 0xff && y == 0xff) + return; + + if (x == 0 && y == 0) { + bNewLine = true; + continue; + } + + x += xOffset; + y += yOffset; + + if (y > 160) + y = 160; + + if (bNewLine) { + _display->drawPixel(x, y, 0x7f); + bNewLine = false; + } else { + _display->drawLine(Common::Point(oldX, oldY), Common::Point(x, y), 0x7f); + } + + oldX = x; + oldY = y; + } +} + +void AdlEngine_v1::drawPic(byte pic, byte xOffset, byte yOffset) { + Common::File f; + Common::String name = Common::String::format("BLOCK%i", _pictures[pic].block); + + if (!f.open(name)) + error("Failed to open file"); + + f.seek(_pictures[pic].offset); + drawPic(f, xOffset, yOffset); +} + +void AdlEngine_v1::drawItems() { + Common::Array::const_iterator it; + + uint dropped = 0; + + for (it = _inventory.begin(); it != _inventory.end(); ++it) { + if (it->field2 != _room) + continue; + + if (it->field7 == 1) { + if (_rooms[_room].field8 == _rooms[_room].picture) { + const Common::Point &p = _itemOffsets[dropped]; + if (it->field4) + _display->drawRightAngles(_drawings[it->field3 - 1], Common::Point(p.x, p.y), 0, 1, 0x7f); + else + drawPic(it->field3, p.x, p.y); + ++dropped; + } + continue; + } + + Common::Array::const_iterator it2; + + for (it2 = it->field10.begin(); it2 != it->field10.end(); ++it2) { + if (*it2 == _rooms[_room].picture) { + if (it->field4) + _display->drawRightAngles(_drawings[it->field3 - 1], Common::Point(it->field5, it->field6), 0, 1, 0x7f); + else + drawPic(it->field3, it->field5, it->field6); + continue; + } + } + } +} + +void AdlEngine_v1::showRoom() { + if (!_isDark) { + drawPic(_rooms[_room].picture, 0, 0); + drawItems(); + } + + _display->decodeFrameBuffer(); + printMessage(_rooms[_room].description, false); +} + +Common::String AdlEngine_v1::getExeString(uint idx) { + return _exeStrings[idx]; +} + +void AdlEngine_v1::wordWrap(Common::String &str) { + uint end = 39; + + while (1) { + if (str.size() <= end) + return; + + while (str[end] != (char)A2CHAR(' ')) + --end; + + str.setChar((char)A2CHAR('\r'), end); + end += 40; + } +} + +void AdlEngine_v1::printMessage(uint idx, bool wait) { + // Hardcoded overrides that don't wait after printing + // Note: strings may differ slightly from the ones in MESSAGES + switch (idx) { + case 137: + _display->printString(_exeStrings[STR_MH_DIRERR]); + return; + case 127: + _display->printString(_exeStrings[STR_MH_DONTHAVEIT]); + return; + case 37: + _display->printString(_exeStrings[STR_MH_DONTUNDERSTAND]); + return; + case 7: + _display->printString(_exeStrings[STR_MH_GETTINGDARK]); + return; + } + + Common::String msg = _msgStrings[idx - 1]; + wordWrap(msg); + _display->printString(msg); + + if (wait) + _display->delay(14 * 166018 / 1000); +} + +void AdlEngine_v1::readCommands(Common::ReadStream &stream, Commands &commands) { + while (1) { + Command command; + command.room = stream.readByte(); + + if (command.room == 0xff) + return; + + command.verb = stream.readByte(); + command.noun = stream.readByte(); + + byte scriptSize = stream.readByte() - 6; + + command.numCond = stream.readByte(); + command.numAct = stream.readByte(); + + for (uint i = 0; i < scriptSize; ++i) + command.script.push_back(stream.readByte()); + + if (stream.eos() || stream.err()) + error("Failed to read commands"); + + commands.push_back(command); + } +} + +void AdlEngine_v1::takeItem(byte noun) { + Common::Array::iterator it; + + for (it = _inventory.begin(); it != _inventory.end(); ++it) { + if (it->field1 != noun || it->field2 != _room) + continue; + + if (it->field7 == 2) { + // It doesn't move + printMessage(151); + return; + } + + if (it->field7 == 1) { + it->field2 = 0xfe; + it->field7 = 1; + return; + } + + Common::Array::const_iterator it2; + for (it2 = it->field10.begin(); it->field10.end(); ++it2) { + if (*it2 == _rooms[_room].picture) { + it->field2 = 0xfe; + it->field7 = 1; + return; + } + } + } + + // Item not here + printMessage(152); +} + +void AdlEngine_v1::dropItem(byte noun) { + Common::Array::iterator it; + + for (it = _inventory.begin(); it != _inventory.end(); ++it) { + if (it->field1 != noun || it->field2 != 0xfe) + continue; + + it->field2 = _room; + it->field7 = 1; + return; + } + + // Don't understand + printMessage(37); +} + +void AdlEngine_v1::doActions(const Command &command, byte noun, byte offset) { + for (uint i = 0; i < command.numAct; ++i) { + switch (command.script[offset]) { + case 1: + _variables[command.script[offset + 2]] += command.script[offset + 1]; + offset += 3; + break; + case 2: + _variables[command.script[offset + 2]] -= command.script[offset + 1]; + offset += 3; + break; + case 3: + _variables[command.script[offset + 1]] = command.script[offset + 2]; + offset += 3; + break; + case 4: { + Common::Array::const_iterator it; + + for (it = _inventory.begin(); it != _inventory.end(); ++it) + if (it->field2 == 0xfe) + printMessage(it->field8); + + ++offset; + break; + } + case 5: + _inventory[command.script[offset + 1] - 1].field2 = command.script[offset + 2]; + offset += 3; + break; + case 6: + _rooms[_room].picture = _rooms[_room].field8; + _room = command.script[offset + 1]; + offset += 2; + break; + case 7: + _rooms[_room].picture = command.script[offset + 1]; + offset += 2; + break; + case 8: + _rooms[_room].field8 = _rooms[_room].picture = command.script[offset + 1]; + offset += 2; + break; + case 9: + printMessage(command.script[offset + 1]); + offset += 2; + break; + case 0xa: + _isDark = false; + ++offset; + break; + case 0xb: + _isDark = true; + ++offset; + break; + case 0xf: + warning("Save game not implemented"); + ++offset; + break; + case 0x10: + warning("Load game not implemented"); + ++offset; + break; + case 0x11: { + _display->printString(_exeStrings[STR_MH_PLAYAGAIN]); + Common::String input = _display->inputString(); + if (input.size() == 0 || input[0] != (char)A2CHAR('N')) { + warning("Restart game not implemented"); + return; + } + // Fall-through + } + case 0xd: + printMessage(140); + quitGame(); + return; + case 0x12: { + byte item = command.script[offset + 1] - 1; + _inventory[item].field2 = command.script[offset + 2]; + _inventory[item].field5 = command.script[offset + 3]; + _inventory[item].field6 = command.script[offset + 4]; + offset += 5; + break; + } + case 0x13: { + byte item = command.script[offset + 2] - 1; + _inventory[item].field3 = command.script[offset + 1]; + offset += 3; + break; + } + case 0x14: + _rooms[_room].picture = _rooms[_room].field8; + ++offset; + break; + case 0x15: + case 0x16: + case 0x17: + case 0x18: + case 0x19: + case 0x1a: { + byte room = _rooms[_room].connections[command.script[offset] - 0x15]; + + if (room == 0) { + printMessage(137); + return; + } + + _rooms[_room].picture = _rooms[_room].field8; + _room = room; + return; + } + case 0x1b: + takeItem(noun); + ++offset; + break; + case 0x1c: + dropItem(noun); + ++offset; + break; + case 0x1d: + _rooms[command.script[offset + 1]].field8 = _rooms[command.script[offset + 1]].picture = command.script[offset + 2]; + offset += 3; + break; + default: + error("Invalid action opcode %02x", command.script[offset]); + } + } +} + +bool AdlEngine_v1::checkCommand(const Command &command, byte verb, byte noun) { + if (command.room != 0xfe && command.room != _room) + return false; + + if (command.verb != 0xfe && command.verb != verb) + return false; + + if (command.noun != 0xfe && command.noun != noun) + return false; + + uint offset = 0; + for (uint i = 0; i < command.numCond; ++i) { + switch (command.script[offset]) { + case 3: + if (_inventory[command.script[offset + 1] - 1].field2 != command.script[offset + 2]) + return false; + offset += 3; + break; + case 5: + if (command.script[offset + 1] > _steps) + return false; + offset += 2; + break; + case 6: + if (_variables[command.script[offset + 1]] != command.script[offset + 2]) + return false; + offset += 3; + break; + case 9: + if (_rooms[_room].picture != command.script[offset + 1]) + return false; + offset += 2; + break; + case 10: + if (_inventory[command.script[offset + 1] - 1].field3 != command.script[offset + 2]) + return false; + offset += 3; + break; + default: + error("Invalid condition opcode %02x", command.script[offset]); + } + } + + doActions(command, noun, offset); + + return true; +} + +bool AdlEngine_v1::doOneCommand(const Commands &commands, byte verb, byte noun) { + Commands::const_iterator it; + + for (it = commands.begin(); it != commands.end(); ++it) { + if (checkCommand(*it, verb, noun)) { + debug("Found match: %i %i %i", it->room, it->verb, it->noun); + return true; + } + } + + return false; +} + +void AdlEngine_v1::doAllCommands(const Commands &commands, byte verb, byte noun) { + Commands::const_iterator it; + + for (it = commands.begin(); it != commands.end(); ++it) { + if (checkCommand(*it, verb, noun)) { + debug("Found match: %i %i %i", it->room, it->verb, it->noun); + } + } +} + +void AdlEngine_v1::clearScreen() { + _display->setMode(Display::kModeMixed); + _display->clear(0x00); +} + +void AdlEngine_v1::runGame() { + runIntro(); + _display->printASCIIString("\r"); + + Common::File f; + + if (!f.open("MESSAGES")) + error("Failed to open file"); + + while (!f.eos() && !f.err()) + _msgStrings.push_back(readString(f, A2CHAR('\r')) + (char)A2CHAR('\r')); + + f.close(); + + if (!f.open("ADVENTURE")) + error("Failed to open file"); + + // Load strings from executable + for (uint idx = 0; idx < STR_MH_TOTAL; ++idx) { + f.seek(exeStrings[idx]); + _exeStrings.push_back(readString(f)); + } + + // Load room data from executable + f.seek(1280); + for (uint i = 0; i < MH_ROOMS; ++i) { + struct Room room; + f.readByte(); + room.description = f.readByte(); + for (uint j = 0; j < 6; ++j) + room.connections[j] = f.readByte(); + room.field8 = f.readByte(); + room.picture = f.readByte(); + _rooms.push_back(room); + } + + // Load inventory data from executable + f.seek(0x100); + while (f.readByte() != 0xff) { + struct Item item; + item.field1 = f.readByte(); + item.field2 = f.readByte(); + item.field3 = f.readByte(); + item.field4 = f.readByte(); + item.field5 = f.readByte(); + item.field6 = f.readByte(); + item.field7 = f.readByte(); + item.field8 = f.readByte(); + + f.readByte(); + + byte size = f.readByte(); + + for (uint i = 0; i < size; ++i) + item.field10.push_back(f.readByte()); + + _inventory.push_back(item); + } + + // Load picture data from executable + f.seek(0x4b00); + for (uint i = 0; i < MH_PICS; ++i) { + struct Picture pic; + pic.block = f.readByte(); + pic.offset = f.readUint16LE(); + _pictures.push_back(pic); + } + + // Load commands from executable + f.seek(0x3D00); + readCommands(f, _roomCommands); + + f.seek(0x3C00); + readCommands(f, _globalCommands); + + // Load dropped item offsets + f.seek(0x68ff); + for (uint i = 0; i < MH_ITEM_OFFSETS; ++i) { + Common::Point p; + p.x = f.readByte(); + p.y = f.readByte(); + _itemOffsets.push_back(p); + } + + // Load right-angle drawings + f.seek(0x4f00); + uint16 drawingsTotal = f.readUint16LE(); + for (uint i = 0; i < drawingsTotal; ++i) { + f.seek(0x4f00 + 2 + i * 2); + uint16 offset = f.readUint16LE(); + f.seek(0x4f00 + offset); + + Common::Array drawing; + byte b = f.readByte(); + while (b != 0) { + drawing.push_back(b); + b = f.readByte(); + } + _drawings.push_back(drawing); + } + + // Title screen shown during loading + f.seek(0x1800); + _display->loadFrameBuffer(f); + _display->decodeFrameBuffer(); + _display->delay(2000); + + f.seek(0x3800); + _parser->loadVerbs(f); + + f.seek(0xf00); + _parser->loadNouns(f); + + while (1) { + uint verb = 0, noun = 0; + clearScreen(); + showRoom(); + _parser->getInput(verb, noun); + + if (!doOneCommand(_roomCommands, verb, noun)) + printMessage(37); + doAllCommands(_globalCommands, verb, noun); + + _steps++; + + if (shouldQuit()) + return; + } +} + +AdlEngine *AdlEngine_v1__create(OSystem *syst, const AdlGameDescription *gd) { + return new AdlEngine_v1(syst, gd); +} + +} // End of namespace Adl diff --git a/engines/adl/adl_v1.h b/engines/adl/adl_v1.h new file mode 100644 index 0000000000..b8f4c536a5 --- /dev/null +++ b/engines/adl/adl_v1.h @@ -0,0 +1,133 @@ +/* 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 ADL_ADL_V1_H +#define ADL_ADL_V1_H + +#include "adl/adl.h" + +namespace Common { +class ReadStream; +} + +namespace Adl { + +enum { + // Some of these are probably common + STR_MH_DIRERR = STR_CUSTOM_START, + STR_MH_DONTHAVEIT, + STR_MH_DONTUNDERSTAND, + STR_MH_GETTINGDARK, + STR_MH_PLAYAGAIN, + + STR_MH_TOTAL +}; + +class AdlEngine_v1 : public AdlEngine { +public: + AdlEngine_v1(OSystem *syst, const AdlGameDescription *gd); + Common::String getExeString(uint idx); + +protected: + void runGame(); + +private: + enum { + MH_ROOMS = 42, + MH_PICS = 98, + MH_ITEM_OFFSETS = 21 + }; + + enum State { + kIntro, + kIdle + }; + + struct Room { + byte description; + byte connections[6]; + byte field8; + byte picture; + }; + + struct Picture { + byte block; + uint16 offset; + }; + + struct Command { + byte room; + byte verb, noun; + byte numCond, numAct; + Common::Array script; + }; + + struct Item { + byte field1; + byte field2; + byte field3; + byte field4; + byte field5; + byte field6; + byte field7; + byte field8; + Common::Array field10; + }; + + typedef Common::List Commands; + + int _state; + + void runIntro(); + void drawPic(Common::ReadStream &stream, byte xOffset, byte yOffset); + void showRoom(); + void printMessage(uint idx, bool wait = true); + void wordWrap(Common::String &str); + void readCommands(Common::ReadStream &stream, Commands &commands); + bool checkCommand(const Command &command, byte verb, byte noun); + bool doOneCommand(const Commands &commands, byte verb, byte noun); + void doAllCommands(const Commands &commands, byte verb, byte noun); + void doActions(const Command &command, byte noun, byte offset); + void clearScreen(); + void takeItem(byte noun); + void dropItem(byte noun); + void drawItems(); + void drawPic(byte pic, byte xOffset, byte yOffset); + + Common::Array _exeStrings; + Common::Array _msgStrings; + Common::Array _rooms; + Common::Array _pictures; + Common::Array _inventory; + Common::Array _itemOffsets; + Common::Array > _drawings; + Commands _roomCommands; + Commands _globalCommands; + byte _room; + uint16 _steps; + Common::Array _variables; + bool _isDark; +}; + +} // End of namespace Adl + +#endif diff --git a/engines/adl/configure.engine b/engines/adl/configure.engine new file mode 100644 index 0000000000..844e2b8e6a --- /dev/null +++ b/engines/adl/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 adl "ADL" no diff --git a/engines/adl/detection.cpp b/engines/adl/detection.cpp new file mode 100644 index 0000000000..ba4e0104b9 --- /dev/null +++ b/engines/adl/detection.cpp @@ -0,0 +1,108 @@ +/* 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 "adl/adl.h" + +#include "common/config-manager.h" +#include "common/error.h" +#include "common/fs.h" + +#include "engines/advancedDetector.h" +#include "engines/metaengine.h" + +namespace Adl { + +struct AdlGameDescription { + ADGameDescription desc; + GameType gameType; +}; + +uint32 AdlEngine::getFeatures() const { + return _gameDescription->desc.flags; +} + +const char *AdlEngine::getGameId() const { + return _gameDescription->desc.gameid; +} + +const char *const directoryGlobs[] = { + "game", + "datafiles", + 0 +}; + +static const PlainGameDescriptor adlGames[] = { + // Games + {"hires1", "Hi-Res Adventure #1: Mystery House"}, + {0, 0} +}; + +static const AdlGameDescription gameDescriptions[] = { + + { // MD5 by waltervn + { + "hires1", 0, + { + {"ADVENTURE", 0, "22d9e63a11d69fa033ba1738715ad09a", 29952}, + {"AUTO LOAD OBJ", 0, "23bfccfe9fcff9b22cf6c41bde9078ac", 12291}, + {"MYSTERY.HELLO", 0, "2289b7fea300b506e902a4c597968369", 836}, + AD_LISTEND + }, + Common::EN_ANY, + Common::kPlatformApple2GS, // FIXME + ADGF_NO_FLAGS, + GUIO0() + }, + kGameTypeAdl1 + }, + {AD_TABLE_END_MARKER, kGameTypeNone} +}; + +class AdlMetaEngine : public AdvancedMetaEngine { +public: + AdlMetaEngine() : AdvancedMetaEngine(gameDescriptions, sizeof(AdlGameDescription), adlGames) { } + + const char *getName() const { + return "Hi-Res Adventure"; + } + + const char *getOriginalCopyright() const { + return "Copyright (C) Sierra On-Line"; + } + + bool createInstance(OSystem *syst, Engine **engine, const ADGameDescription *gd) const; +}; + +bool AdlMetaEngine::createInstance(OSystem *syst, Engine **engine, const ADGameDescription *gd) const { + if (gd) { + *engine = AdlEngine::create(((const AdlGameDescription *)gd)->gameType, syst, (const AdlGameDescription *)gd); + } + return gd != 0; +} + +} // End of namespace Adl + +#if PLUGIN_ENABLED_DYNAMIC(ADL) + REGISTER_PLUGIN_DYNAMIC(ADL, PLUGIN_TYPE_ENGINE, Adl::AdlMetaEngine); +#else + REGISTER_PLUGIN_STATIC(ADL, PLUGIN_TYPE_ENGINE, Adl::AdlMetaEngine); +#endif diff --git a/engines/adl/display.cpp b/engines/adl/display.cpp new file mode 100644 index 0000000000..02b8d51b7f --- /dev/null +++ b/engines/adl/display.cpp @@ -0,0 +1,611 @@ +/* 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 "adl/display.h" +#include "common/stream.h" +#include "common/rect.h" +#include "graphics/surface.h" +#include "common/system.h" +#include "common/str.h" +#include "common/events.h" +#include "common/rect.h" +#include "common/array.h" +#include "engines/engine.h" + +namespace Adl { + +static byte font[64][5] = { + { 0x7c, 0x82, 0xba, 0xb2, 0x9c }, { 0xf8, 0x24, 0x22, 0x24, 0xf8 }, // @A + { 0xfe, 0x92, 0x92, 0x92, 0x6c }, { 0x7c, 0x82, 0x82, 0x82, 0x44 }, // BC + { 0xfe, 0x82, 0x82, 0x82, 0x7c }, { 0xfe, 0x92, 0x92, 0x92, 0x82 }, // DE + { 0xfe, 0x12, 0x12, 0x12, 0x02 }, { 0x7c, 0x82, 0x82, 0xa2, 0xe2 }, // FG + { 0xfe, 0x10, 0x10, 0x10, 0xfe }, { 0x00, 0x82, 0xfe, 0x82, 0x00 }, // HI + { 0x40, 0x80, 0x80, 0x80, 0x7e }, { 0xfe, 0x10, 0x28, 0x44, 0x82 }, // JK + { 0xfe, 0x80, 0x80, 0x80, 0x80 }, { 0xfe, 0x04, 0x18, 0x04, 0xfe }, // LM + { 0xfe, 0x08, 0x10, 0x20, 0xfe }, { 0x7c, 0x82, 0x82, 0x82, 0x7c }, // NO + { 0xfe, 0x12, 0x12, 0x12, 0x0c }, { 0x7c, 0x82, 0xa2, 0x42, 0xbc }, // PQ + { 0xfe, 0x12, 0x32, 0x52, 0x8c }, { 0x4c, 0x92, 0x92, 0x92, 0x64 }, // RS + { 0x02, 0x02, 0xfe, 0x02, 0x02 }, { 0x7e, 0x80, 0x80, 0x80, 0x7e }, // TU + { 0x3e, 0x40, 0x80, 0x40, 0x3e }, { 0xfe, 0x40, 0x30, 0x40, 0xfe }, // VW + { 0xc6, 0x28, 0x10, 0x28, 0xc6 }, { 0x06, 0x08, 0xf0, 0x08, 0x06 }, // XY + { 0xc2, 0xa2, 0x92, 0x8a, 0x86 }, { 0xfe, 0xfe, 0x82, 0x82, 0x82 }, // Z[ + { 0x04, 0x08, 0x10, 0x20, 0x40 }, { 0x82, 0x82, 0x82, 0xfe, 0xfe }, // \] + { 0x20, 0x10, 0x08, 0x10, 0x20 }, { 0x80, 0x80, 0x80, 0x80, 0x80 }, // ^_ + { 0x00, 0x00, 0x00, 0x00, 0x00 }, { 0x00, 0x00, 0xbe, 0x00, 0x00 }, // ! + { 0x00, 0x0e, 0x00, 0x0e, 0x00 }, { 0x28, 0xfe, 0x28, 0xfe, 0x28 }, // "# + { 0x48, 0x54, 0xfe, 0x54, 0x24 }, { 0x46, 0x26, 0x10, 0xc8, 0xc4 }, // $% + { 0x6c, 0x92, 0xac, 0x40, 0xa0 }, { 0x00, 0x00, 0x0e, 0x00, 0x00 }, // &' + { 0x38, 0x44, 0x82, 0x00, 0x00 }, { 0x00, 0x00, 0x82, 0x44, 0x38 }, // () + { 0x44, 0x28, 0xfe, 0x28, 0x44 }, { 0x10, 0x10, 0x7c, 0x10, 0x10 }, // *+ + { 0x00, 0x80, 0x60, 0x00, 0x00 }, { 0x10, 0x10, 0x10, 0x10, 0x10 }, // ,- + { 0x00, 0x00, 0x80, 0x00, 0x00 }, { 0x40, 0x20, 0x10, 0x08, 0x04 }, // ./ + { 0x7c, 0xa2, 0x92, 0x8a, 0x7c }, { 0x00, 0x84, 0xfe, 0x80, 0x00 }, // 01 + { 0xc4, 0xa2, 0x92, 0x92, 0x8c }, { 0x42, 0x82, 0x92, 0x9a, 0x66 }, // 23 + { 0x30, 0x28, 0x24, 0xfe, 0x20 }, { 0x4e, 0x8a, 0x8a, 0x8a, 0x72 }, // 45 + { 0x78, 0x94, 0x92, 0x92, 0x62 }, { 0x02, 0xe2, 0x12, 0x0a, 0x06 }, // 67 + { 0x6c, 0x92, 0x92, 0x92, 0x6c }, { 0x8c, 0x92, 0x92, 0x52, 0x3c }, // 89 + { 0x00, 0x00, 0x28, 0x00, 0x00 }, { 0x00, 0x80, 0x68, 0x00, 0x00 }, // :; + { 0x10, 0x28, 0x44, 0x82, 0x00 }, { 0x28, 0x28, 0x28, 0x28, 0x28 }, // <= + { 0x00, 0x82, 0x44, 0x28, 0x10 }, { 0x04, 0x02, 0xb2, 0x0a, 0x04 } // >? +}; + +Display::Display() : + _scanlines(false), + _cursorPos(0), + _mode(kModeText) { + _frameBuf = new byte[kFrameBufSize]; + _frameBufSurface = new Graphics::Surface; + _frameBufSurface->create(kWidth * 2, kHeight * 2, Graphics::PixelFormat::createFormatCLUT8()); + + _textBuf = new byte[kTextBufSize]; + memset(_textBuf, ' ' | 0x80, kTextBufSize); + _textBufSurface = new Graphics::Surface; + _textBufSurface->create(kWidth * 2, kHeight * 2, Graphics::PixelFormat::createFormatCLUT8()); + + createFont(); + + struct PixelPos rel = getPixelPos(0, 191); + struct PixelPos absy; + for (int i = 191; i >= 0; --i) { + absy = getPixelPos(0, i); + if (absy.rowAddr != rel.rowAddr) + debug("%i: %04x %04x", i, absy.rowAddr, rel.rowAddr); + moveY(rel, false); + } + absy = getPixelPos(0, 191); + if (absy.rowAddr != rel.rowAddr) + debug("%i: %04x %04x", 191, absy.rowAddr, rel.rowAddr); + + rel = getPixelPos(0, 0); + for (int i = 0; i < 192; ++i) { + absy = getPixelPos(0, i); + if (absy.rowAddr != rel.rowAddr) + debug("%i: %04x %04x", i, absy.rowAddr, rel.rowAddr); + moveY(rel, true); + } + absy = getPixelPos(0, 0); + if (absy.rowAddr != rel.rowAddr) + debug("%i: %04x %04x", 191, absy.rowAddr, rel.rowAddr); +} + +Display::~Display() { + delete[] _frameBuf; + _frameBufSurface->free(); + delete _frameBufSurface; + + delete[] _textBuf; + _textBufSurface->free(); + delete _textBufSurface; + + _font->free(); + delete _font; +} + +void Display::loadFrameBuffer(Common::ReadStream &stream) { + stream.read(_frameBuf, kFrameBufSize); +} + +void Display::decodeScanline(byte *dst, int pitch, byte *src) { + // TODO: shift secondPal by half a pixel + + bool prevOn = false; + + for (uint j = 0; j < 39; ++j) { + bool secondPal = src[j] & 0x80; + byte cur = src[j]; + byte next = 0; + if (j != 39) + next = src[j + 1]; + + for (uint k = 0; k < 7; ++k) { + bool curOn = cur & (1 << k); + bool nextOn; + + if (k != 6) + nextOn = cur & (1 << (k + 1)); + else + nextOn = next & 1; + + byte color; + if (curOn == prevOn || curOn == nextOn) + color = curOn ? 1 : 0; + else { + if (secondPal) + color = (curOn == ((j + k) % 2) ? 5 : 4); + else + color = (curOn == ((j + k) % 2) ? 3 : 2); + } + + dst[0] = color; + dst[1] = color; + + if (!_scanlines) { + dst[pitch] = color; + dst[pitch + 1] = color; + } + + dst += 2; + prevOn = curOn; + } + } +} + +Display::PixelPos Display::getPixelPos(byte x, byte y) { + PixelPos pixelPos; + + // FIXME: check X, Y range + + byte offsetL = y & 0xc0; + offsetL |= offsetL >> 2; + byte offsetH = y; + y <<= 2; + offsetH <<= 1; + offsetH |= y >> 7; + y <<= 1; + offsetH <<= 1; + offsetH |= y >> 7; + y <<= 1; + offsetL >>= 1; + offsetL |= y & 0x80; + y <<= 1; + offsetH = offsetH & 0x1f; + pixelPos.rowAddr = (offsetH << 8) | offsetL; + pixelPos.byteOffset = x / 7; + pixelPos.bitMask = 0x80 | (1 << x % 7); + + return pixelPos; +} + +byte Display::getPixelColor(byte offset, byte color) { + if (offset & 1) { + byte c = color << 1; + if (c >= 0x40 && c < 0xc0) + return color ^ 0x7f; + } + + return color; +} + +void Display::decodeFrameBuffer() { + byte *src = _frameBuf; + int pitch = _frameBufSurface->pitch; + for (int j = 0; j < 8; ++j) { + for (int i = 0; i < 8; ++i) { + byte *dst = (byte *)_frameBufSurface->getPixels() + pitch * 2 * (i * 8 + j); + decodeScanline(dst, pitch, src); + src += 40; + dst += pitch * 2 * 64; + decodeScanline(dst, pitch, src); + src += 40; + dst += pitch * 2 * 64; + decodeScanline(dst, pitch, src); + src += 48; + dst += pitch * 2 * 64; + } + } +} + +void Display::drawPixel(byte x, byte y, byte color) { + PixelPos p = getPixelPos(x, y); + byte c = getPixelColor(p.byteOffset, color); + byte *b = _frameBuf + p.rowAddr + p.byteOffset; + c ^= *b; + c &= p.bitMask; + c ^= *b; + *b = c; +} + +void Display::moveX(PixelPos &p, byte &color, bool left) { + if (left) { + byte bit = p.bitMask; + bool b = bit & 1; + bit >>= 1; + if (!b) { + bit ^= 0xc0; + p.bitMask = bit; + return; + } + --p.byteOffset; + if (p.byteOffset & 0x80) + p.byteOffset = 39; + p.bitMask = 0xc0; + } else { + byte bit = p.bitMask; + bit <<= 1; + bit ^= 0x80; + if (bit & 0x80) { + p.bitMask = bit; + return; + } + p.bitMask = 0x81; + ++p.byteOffset; + if (p.byteOffset == 40) + p.byteOffset = 0; + } + + color = getPixelColor(p.byteOffset, color); +} + +void Display::moveY(PixelPos &p, bool down) { + if (!down) { + if (p.rowAddr & 0x1c00) + p.rowAddr -= 0x400; + else if (p.rowAddr & 0x380) + p.rowAddr += 0x1b80; + else { + p.rowAddr += 0x1f58; + if (!(p.rowAddr & 0x80)) + p.rowAddr += 0x78; // Wrap around + } + } else { + p.rowAddr += 0x400; + if (p.rowAddr & 0x1c00) + return; + else if ((p.rowAddr & 0x380) != 0x380) + p.rowAddr -= 0x1f80; + else { + p.rowAddr -= 0x2358; + if ((p.rowAddr & 0x78) == 0x78) + p.rowAddr -= 0x78; // Wrap around + } + } +} + +void Display::drawNextPixel(Display::PixelPos &p, byte &color, byte bits, byte quadrant) { + if (bits & 4) { + byte b = (_frameBuf[p.rowAddr + p.byteOffset] ^ color) & p.bitMask; + _frameBuf[p.rowAddr + p.byteOffset] ^= b; + } + + bits += quadrant; + + if (bits & 1) + moveX(p, color, bits & 2); + else + moveY(p, bits & 2); +} + +void Display::drawRightAngles(Common::Array &rightAngles, Common::Point p, byte rotation, byte scaling, byte color) { + const byte stepping[] = { + 0xff, 0xfe, 0xfa, 0xf4, 0xec, 0xe1, 0xd4, 0xc5, + 0xb4, 0xa1, 0x8d, 0x78, 0x61, 0x49, 0x31, 0x18, + 0xff + }; + + PixelPos pos = getPixelPos(p.x, p.y); + byte c = getPixelColor(pos.byteOffset, color); + + byte quadrant = rotation >> 4; + rotation &= 0xf; + byte xStep = stepping[rotation]; + byte yStep = stepping[(rotation ^ 0xf) + 1] + 1; + + for (uint i = 0; i < rightAngles.size(); ++i) { + byte b = rightAngles[i]; + + do { + byte xFrac = 0x80; + byte yFrac = 0x80; + for (uint j = 0; j < scaling; ++j) { + if (xFrac + xStep + 1 > 255) + drawNextPixel(pos, c, b, quadrant); + xFrac += xStep + 1; + if (yFrac + yStep > 255) + drawNextPixel(pos, c, b, quadrant + 1); + yFrac += yStep; + } + b >>= 3; + } while (b != 0); + } +} + +void Display::drawLine(Common::Point p1, Common::Point p2, byte color) { + PixelPos p = getPixelPos(p1.x, p1.y); + byte c = getPixelColor(p.byteOffset, color); + + int16 deltaX = p2.x - p1.x; + byte dir = deltaX >> 8; + + if (deltaX < 0) + deltaX = -deltaX; + + int16 err = deltaX; + + int16 deltaY = p2.y - p1.y - 1; + dir >>= 1; + if (deltaY >= 0) { + deltaY = -deltaY - 2; + dir |= 0x80; + } + + int16 steps = deltaY - deltaX; + + err += deltaY + 1; + + while (1) { + byte *b = _frameBuf + p.rowAddr + p.byteOffset; + byte d = *b; + d ^= c; + d &= p.bitMask; + d ^= *b; + *b = d; + + if (++steps == 0) + return; + + if (err < 0) { + moveY(p, dir & 0x80); + err += deltaX; + } else { + moveX(p, c, dir & 0x40); + err += deltaY + 1; + } + } +} + +void Display::clear(byte color) { + for (uint i = 0; i < kFrameBufSize; ++i) + _frameBuf[i] = getPixelColor(i & 1, color); +} + +void Display::updateTextSurface() { + for (uint row = 0; row < 24; ++row) + for (uint col = 0; col < 40; ++col) { + char c = _textBuf[row * 40 + col]; + + Common::Rect r(7 * 2, 8 * 2); + r.translate(((c & 0x3f) % 16) * 7 * 2, (c & 0x3f) / 16 * 8 * 2); + + if (!(c & 0x80)) { + if (!(c & 0x40) || ((g_system->getMillis() / 270) & 1)) + r.translate(0, 4 * 8 * 2); + } + + _textBufSurface->copyRectToSurface(*_font, col * 7 * 2, row * 8 * 2, r); + } +} + +void Display::printString(const Common::String &str) { + Common::String::const_iterator it; + for (it = str.begin(); it != str.end(); ++it) { + byte b = *it; + + if (b == ('\r' | 0x80)) + _cursorPos = (_cursorPos / 40 + 1) * 40; + else if (b < 0x80 || b >= 0xa0) + _textBuf[_cursorPos++] = b; + + if (_cursorPos == kTextBufSize) { + memmove(_textBuf, _textBuf + 40, kTextBufSize - 40); + memset(_textBuf + kTextBufSize - 40, ' ' | 0x80, 40); + _cursorPos -= 40; + } + } + + updateTextSurface(); +} + +void Display::printASCIIString(const Common::String &str) { + Common::String aStr; + + Common::String::const_iterator it; + for (it = str.begin(); it != str.end(); ++it) + aStr += *it | 0x80; + + printString(aStr); +} + +void Display::drawChar(byte c, int x, int y) { + byte *buf = (byte *)_font->getPixels() + y * _font->pitch + x; + + for (uint row = 0; row < 8; ++row) { + for (uint col = 1; col < 6; ++col) + if (font[c][col - 1] & (1 << row)) { + buf[col * 2] = 1; + buf[col * 2 + 1] = 1; + + if (!_scanlines) { + buf[_font->pitch + col * 2] = 1; + buf[_font->pitch + col * 2 + 1] = 1; + } + } + + buf += 2 * _font->pitch; + } +} + +void Display::createFont() { + _font = new Graphics::Surface; + _font->create(16 * 7 * 2, 4 * 8 * 2 * 2, Graphics::PixelFormat::createFormatCLUT8()); + + for (uint i = 0; i < 4; ++i) + for (uint j = 0; j < 16; ++j) + drawChar(i * 16 + j, j * 7 * 2, i * 8 * 2); + + // Create inverted font + byte *buf = (byte *)_font->getPixels(); + byte *bufInv = buf + (_font->h / 2) * _font->pitch; + + for (uint row = 0; row < _font->h / 2; ++row) { + if (!_scanlines || !(row & 1)) + for (uint col = 0; col < _font->w; ++col) + bufInv[col] = buf[col] ? 0 : 1; + + buf += _font->pitch; + bufInv += _font->pitch; + } +} + +void Display::updateScreen() { + if (_mode == kModeText) { + g_system->copyRectToScreen(_textBufSurface->getPixels(), _textBufSurface->pitch, 0, 0, _textBufSurface->w, _textBufSurface->h); + } else if (_mode == kModeHires) { + g_system->copyRectToScreen(_frameBufSurface->getPixels(), _frameBufSurface->pitch, 0, 0, _frameBufSurface->w, _frameBufSurface->h); + } else { + g_system->copyRectToScreen(_frameBufSurface->getPixels(), _frameBufSurface->pitch, 0, 0, _frameBufSurface->w, _frameBufSurface->h - 4 * 8 * 2); + g_system->copyRectToScreen(_textBufSurface->getBasePtr(0, _textBufSurface->h - 4 * 8 * 2), _textBufSurface->pitch, 0, _textBufSurface->h - 4 * 8 * 2, _textBufSurface->w, 4 * 8 * 2); + } +} + +Common::String Display::inputString(byte prompt) { + Common::String s; + + if (prompt > 0) + printString(Common::String(prompt)); + + while (1) { + byte b = inputKey(); + + if (g_engine->shouldQuit()) + return 0; + + if (b == 0) + continue; + + if (b == ('\r' | 0x80)) { + s += b; + printString(Common::String(b)); + return s; + } + + if (b < 0xa0) { + switch (b) { + case Common::KEYCODE_BACKSPACE | 0x80: + if (!s.empty()) { + --_cursorPos; + _textBuf[_cursorPos] = ' ' | 0x80; + s.deleteLastChar(); + } + break; + }; + } else { + s += b; + printString(Common::String(b)); + } + } +} + +byte Display::convertKey(uint16 ascii) { + ascii = toupper(ascii); + + if (ascii >= 0x80) + return 0; + + ascii |= 0x80; + + if (ascii >= 0x80 && ascii <= 0xe0) + return ascii; + + return 0; +} + +byte Display::inputKey() { + Common::EventManager *ev = g_system->getEventManager(); + + byte orgChar = _textBuf[_cursorPos]; + _textBuf[_cursorPos] = (orgChar & 0x3f) | 0x40; + + byte key = 0; + + while (!g_engine->shouldQuit() && key == 0) { + Common::Event event; + if (ev->pollEvent(event)) { + if (event.type != Common::EVENT_KEYDOWN) + continue; + + if (event.kbd.flags & Common::KBD_CTRL) { + if (event.kbd.keycode == Common::KEYCODE_q) + g_engine->quitGame(); + continue; + } + + switch (event.kbd.keycode) { + case Common::KEYCODE_BACKSPACE: + case Common::KEYCODE_RETURN: + key = convertKey(event.kbd.keycode); + break; + default: + if (event.kbd.ascii >= 0x20 && event.kbd.ascii < 0x80) + key = convertKey(event.kbd.ascii); + }; + } + + updateTextSurface(); + updateScreen(); + g_system->updateScreen(); + g_system->delayMillis(16); + } + + _textBuf[_cursorPos] = orgChar; + return key; +} + +void Display::delay(uint32 ms) { + Common::EventManager *ev = g_system->getEventManager(); + + uint32 start = g_system->getMillis(); + + while (!g_engine->shouldQuit() && g_system->getMillis() - start < ms) { + Common::Event event; + if (ev->pollEvent(event)) { + if (event.type == Common::EVENT_KEYDOWN && (event.kbd.flags & Common::KBD_CTRL)) { + switch(event.kbd.keycode) { + case Common::KEYCODE_q: + g_engine->quitGame(); + break; + default: + break; + } + } + } + updateScreen(); + g_system->updateScreen(); + g_system->delayMillis(16); + } +} + +void Display::home() { + memset(_textBuf, ' ' | 0x80, kTextBufSize); + _cursorPos = 0; +} + +} // End of namespace Adl diff --git a/engines/adl/display.h b/engines/adl/display.h new file mode 100644 index 0000000000..eabf340573 --- /dev/null +++ b/engines/adl/display.h @@ -0,0 +1,103 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#ifndef ADL_DISPLAY_H +#define ADL_DISPLAY_H + +#include +#include + +namespace Common { +class ReadStream; +class String; +class Point; +} + +namespace Graphics { +class Surface; +} + +namespace Adl { + +class Display { +public: + enum Mode { + kModeHires, + kModeText, + kModeMixed + }; + + Display(); + ~Display(); + void loadFrameBuffer(Common::ReadStream &stream); + void decodeFrameBuffer(); + void printString(const Common::String &str); + void printASCIIString(const Common::String &str); + void updateScreen(); + Common::String inputString(byte prompt = 0); + void delay(uint32 ms); + void setMode(Mode mode) { _mode = mode; } + byte inputKey(); + void home(); + void drawPixel(byte x, byte y, byte color); + void drawLine(Common::Point p1, Common::Point p2, byte color); + void clear(byte color); + void drawRightAngles(Common::Array &rightAngles, Common::Point p, byte rotation, byte scaling, byte color); + +private: + enum { + kWidth = 280, + kHeight = 192, + kFrameBufSize = 0x2000, + kTextBufSize = 40 * 24 + }; + + struct PixelPos { + uint16 rowAddr; + byte byteOffset; + byte bitMask; + }; + + void decodeScanline(byte *dst, int pitch, byte *src); + PixelPos getPixelPos(byte x, byte y); + byte getPixelColor(byte x, byte color); + void drawChar(byte c, int x, int y); + void createFont(); + void updateTextSurface(); + byte convertKey(uint16 ascii); + void moveX(PixelPos &p, byte &color, bool left); + void moveY(PixelPos &p, bool down); + void drawNextPixel(Display::PixelPos &p, byte &color, byte bits, byte quadrant); + + bool _scanlines; + byte *_frameBuf; + byte *_textBuf; + Graphics::Surface *_frameBufSurface; + Graphics::Surface *_textBufSurface; + Graphics::Surface *_font; + int _cursorPos; + Mode _mode; +}; + +} // End of namespace Adl + +#endif diff --git a/engines/adl/module.mk b/engines/adl/module.mk new file mode 100644 index 0000000000..8f86eeec68 --- /dev/null +++ b/engines/adl/module.mk @@ -0,0 +1,19 @@ +MODULE := engines/adl + +MODULE_OBJS := \ + detection.o \ + display.o \ + adl.o \ + adl_v1.o \ + parser.o + +MODULE_DIRS += \ + engines/adl + +# This module can be built as a plugin +ifeq ($(ENABLE_ADL), DYNAMIC_PLUGIN) +PLUGIN := 1 +endif + +# Include common rules +include $(srcdir)/rules.mk diff --git a/engines/adl/parser.cpp b/engines/adl/parser.cpp new file mode 100644 index 0000000000..cdbaf3ba6c --- /dev/null +++ b/engines/adl/parser.cpp @@ -0,0 +1,172 @@ +/* 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 "adl/adl.h" +#include "adl/parser.h" +#include "adl/display.h" + +#include "engines/engine.h" + +#include "common/str.h" +#include "common/stream.h" +#include "common/debug.h" +#include "common/textconsole.h" + +namespace Adl { + +Parser::Parser(AdlEngine &engine, Display &display) : + _engine(engine), + _display(display) { + +} + +void Parser::loadWords(Common::ReadStream &stream, WordMap &map) { + uint index = 0; + + while (1) { + ++index; + + byte buf[kWordSize]; + + if (stream.read(buf, kWordSize) < kWordSize) + error("Error reading word list"); + + Common::String word((char *)buf, kWordSize); + + if (!map.contains(word)) + map[word] = index; + + byte synonyms = stream.readByte(); + + if (stream.err() || stream.eos()) + error("Error reading word list"); + + if (synonyms == 0xff) + break; + + for (uint i = 0; i < synonyms; ++i) { + if (stream.read((char *)buf, kWordSize) < kWordSize) + error("Error reading word list"); + + word = Common::String((char *)buf, kWordSize); + + if (!map.contains(word)) + map[word] = index; + } + } +} + +Common::String Parser::getLine() { + // Original engine uses a global here, which isn't reset between + // calls and may not match actual mode + bool textMode = false; + + while (1) { + Common::String line = _display.inputString(A2CHAR('?')); + + if (g_engine->shouldQuit()) + return ""; + + if ((byte)line[0] == ('\r' | 0x80)) { + textMode = !textMode; + _display.setMode(textMode ? Display::kModeText : Display::kModeMixed); + continue; + } + + // Remove the return + line.deleteLastChar(); + return line; + } +} + +Common::String Parser::getWord(const Common::String &line, uint &index) { + Common::String str; + + for (uint i = 0; i < 8; ++i) + str += (char)(A2CHAR(' ')); + + int copied = 0; + + // Skip initial whitespace + while (1) { + if (index == line.size()) + return str; + if (line[index] != (char)(A2CHAR(' '))) + break; + ++index; + } + + // Copy up to 8 characters + while (1) { + if (copied < 8) + str.setChar(line[index], copied++); + + index++; + + if (index == line.size() || line[index] == (char)(A2CHAR(' '))) + return str; + } +} + +void Parser::getInput(uint &verb, uint &noun) { + while (1) { + _display.printString(_engine.getExeString(STR_COMMON_ENTERCMD)); + Common::String line = getLine(); + + if (g_engine->shouldQuit()) + return; + + uint index = 0; + Common::String verbStr = getWord(line, index); + debug("Verb: \"%s\"", appleToAscii(verbStr).c_str()); + + if (!_verbs.contains(verbStr)) { + Common::String err = _engine.getExeString(STR_COMMON_VERBERR); + for (uint i = 0; i < verbStr.size(); ++i) + err.setChar(verbStr[i], i + 19); + _display.printString(err); + continue; + } + + verb = _verbs[verbStr]; + debug("Verb ID: %i", verb); + + Common::String nounStr = getWord(line, index); + debug("Noun: \"%s\"", appleToAscii(nounStr).c_str()); + + if (!_nouns.contains(nounStr)) { + Common::String err = _engine.getExeString(STR_COMMON_NOUNERR); + for (uint i = 0; i < verbStr.size(); ++i) + err.setChar(verbStr[i], i + 19); + for (uint i = 0; i < nounStr.size(); ++i) + err.setChar(nounStr[i], i + 30); + _display.printString(err); + continue; + } + + noun = _nouns[nounStr]; + debug("Noun ID: %i", noun); + return; + } +} + +} // End of namespace Adl diff --git a/engines/adl/parser.h b/engines/adl/parser.h new file mode 100644 index 0000000000..3c191d90f6 --- /dev/null +++ b/engines/adl/parser.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 ADL_PARSER_H +#define ADL_PARSER_H + +#include "common/types.h" +#include "common/hashmap.h" +#include "common/hash-str.h" + +namespace Common { +class ReadStream; +class String; +} + +namespace Adl { + +class Display; + +class Parser { +public: + Parser(AdlEngine &engine, Display &display); + + void loadVerbs(Common::ReadStream &stream) { loadWords(stream, _verbs); } + void loadNouns(Common::ReadStream &stream) { loadWords(stream, _nouns); } + void getInput(uint &verb, uint &noun); + +private: + enum { + kWordSize = 8 + }; + + typedef Common::HashMap WordMap; + + void loadWords(Common::ReadStream &stream, WordMap &map); + Common::String getLine(); + Common::String getWord(const Common::String &line, uint &index); + + AdlEngine &_engine; + Display &_display; + WordMap _verbs; + WordMap _nouns; +}; + +} // End of namespace Adl + +#endif -- cgit v1.2.3 From 87e2c4c1a933cbfb8cb03e36531503f0d1122053 Mon Sep 17 00:00:00 2001 From: Walter van Niftrik Date: Sat, 27 Feb 2016 10:46:37 +0100 Subject: ADL: Rename game type --- engines/adl/adl.cpp | 2 +- engines/adl/adl.h | 2 +- engines/adl/detection.cpp | 33 ++++++--------------------------- 3 files changed, 8 insertions(+), 29 deletions(-) (limited to 'engines') diff --git a/engines/adl/adl.cpp b/engines/adl/adl.cpp index be3d8d7151..b96ecc8b97 100644 --- a/engines/adl/adl.cpp +++ b/engines/adl/adl.cpp @@ -145,7 +145,7 @@ void AdlEngine::printStrings(Common::SeekableReadStream &stream, int count) { AdlEngine *AdlEngine::create(GameType type, OSystem *syst, const AdlGameDescription *gd) { switch(type) { - case kGameTypeAdl1: + case kGameTypeHires1: return AdlEngine_v1__create(syst, gd); default: error("Unknown GameType"); diff --git a/engines/adl/adl.h b/engines/adl/adl.h index d5a518faa7..e945a45ec8 100644 --- a/engines/adl/adl.h +++ b/engines/adl/adl.h @@ -41,7 +41,7 @@ struct AdlGameDescription; enum GameType { kGameTypeNone = 0, - kGameTypeAdl1 + kGameTypeHires1 }; Common::String asciiToApple(Common::String str); diff --git a/engines/adl/detection.cpp b/engines/adl/detection.cpp index ba4e0104b9..9fadb9d3d7 100644 --- a/engines/adl/detection.cpp +++ b/engines/adl/detection.cpp @@ -20,14 +20,9 @@ * */ -#include "adl/adl.h" - -#include "common/config-manager.h" -#include "common/error.h" -#include "common/fs.h" - #include "engines/advancedDetector.h" -#include "engines/metaengine.h" + +#include "adl/adl.h" namespace Adl { @@ -36,22 +31,7 @@ struct AdlGameDescription { GameType gameType; }; -uint32 AdlEngine::getFeatures() const { - return _gameDescription->desc.flags; -} - -const char *AdlEngine::getGameId() const { - return _gameDescription->desc.gameid; -} - -const char *const directoryGlobs[] = { - "game", - "datafiles", - 0 -}; - static const PlainGameDescriptor adlGames[] = { - // Games {"hires1", "Hi-Res Adventure #1: Mystery House"}, {0, 0} }; @@ -72,7 +52,7 @@ static const AdlGameDescription gameDescriptions[] = { ADGF_NO_FLAGS, GUIO0() }, - kGameTypeAdl1 + kGameTypeHires1 }, {AD_TABLE_END_MARKER, kGameTypeNone} }; @@ -82,7 +62,7 @@ public: AdlMetaEngine() : AdvancedMetaEngine(gameDescriptions, sizeof(AdlGameDescription), adlGames) { } const char *getName() const { - return "Hi-Res Adventure"; + return "ADL"; } const char *getOriginalCopyright() const { @@ -93,10 +73,9 @@ public: }; bool AdlMetaEngine::createInstance(OSystem *syst, Engine **engine, const ADGameDescription *gd) const { - if (gd) { + if (gd) *engine = AdlEngine::create(((const AdlGameDescription *)gd)->gameType, syst, (const AdlGameDescription *)gd); - } - return gd != 0; + return gd != nullptr; } } // End of namespace Adl -- cgit v1.2.3 From 9717aa956197480a608622a2e294fa8302258a0e Mon Sep 17 00:00:00 2001 From: Walter van Niftrik Date: Sat, 27 Feb 2016 13:35:49 +0100 Subject: ADL: Clean-up string handling --- engines/adl/adl.cpp | 48 +++--------------------------------------------- engines/adl/adl.h | 36 ++++++++++++++++++++++++++++++++---- engines/adl/adl_v1.cpp | 22 ++++++++-------------- engines/adl/display.cpp | 2 +- engines/adl/display.h | 4 +++- engines/adl/parser.cpp | 12 ++++-------- 6 files changed, 51 insertions(+), 73 deletions(-) (limited to 'engines') diff --git a/engines/adl/adl.cpp b/engines/adl/adl.cpp index b96ecc8b97..9925e04286 100644 --- a/engines/adl/adl.cpp +++ b/engines/adl/adl.cpp @@ -20,77 +20,35 @@ * */ - #include "common/scummsys.h" - +#include "common/scummsys.h" #include "common/config-manager.h" #include "common/debug.h" -#include "common/debug-channels.h" #include "common/error.h" #include "common/file.h" -#include "common/fs.h" #include "common/system.h" #include "common/events.h" #include "common/stream.h" -#include "graphics/palette.h" #include "engines/util.h" +#include "graphics/palette.h" + #include "adl/adl.h" #include "adl/display.h" #include "adl/parser.h" namespace Adl { -Common::String asciiToApple(Common::String str) { - Common::String ret(str); - Common::String::iterator it; - - for (it = ret.begin(); it != ret.end(); ++it) - *it = *it | 0x80; - - return ret; -} - -Common::String appleToAscii(Common::String str) { - Common::String ret(str); - Common::String::iterator it; - - for (it = ret.begin(); it != ret.end(); ++it) - *it = *it & 0x7f; - - return ret; -} - AdlEngine::AdlEngine(OSystem *syst, const AdlGameDescription *gd) : Engine(syst), _gameDescription(gd), _console(nullptr), _display(nullptr) { - // Put your engine in a sane state, but do nothing big yet; - // in particular, do not load data from files; rather, if you - // need to do such things, do them from run(). - - // Do not initialize graphics here - // Do not initialize audio devices here - - // However this is the place to specify all default directories - const Common::FSNode gameDataDir(ConfMan.get("path")); - SearchMan.addSubDirectoryMatching(gameDataDir, "sound"); - - // Don't forget to register your random source - _rnd = new Common::RandomSource("adl"); - - debug("AdlEngine::AdlEngine"); } AdlEngine::~AdlEngine() { - debug("AdlEngine::~AdlEngine"); - - delete _rnd; delete _console; delete _display; - - DebugMan.clearAllDebugChannels(); } Common::Error AdlEngine::run() { diff --git a/engines/adl/adl.h b/engines/adl/adl.h index e945a45ec8..954c61335d 100644 --- a/engines/adl/adl.h +++ b/engines/adl/adl.h @@ -44,9 +44,6 @@ enum GameType { kGameTypeHires1 }; -Common::String asciiToApple(Common::String str); -Common::String appleToAscii(Common::String str); - enum { STR_COMMON_ENTERCMD, STR_COMMON_VERBERR, @@ -54,7 +51,38 @@ enum { STR_CUSTOM_START }; -#define A2CHAR(C) ((C) | 0x80) +struct Room { + byte description; + byte connections[6]; + byte field8; + byte picture; +}; + +struct Picture { + byte block; + uint16 offset; +}; + +struct Command { + byte room; + byte verb, noun; + byte numCond, numAct; + Common::Array script; +}; + +struct Item { + byte field1; + byte field2; + byte field3; + byte field4; + byte field5; + byte field6; + byte field7; + byte field8; + Common::Array field10; +}; + +typedef Common::List Commands; class AdlEngine : public Engine { public: diff --git a/engines/adl/adl_v1.cpp b/engines/adl/adl_v1.cpp index 61671e5d7f..42182390dd 100644 --- a/engines/adl/adl_v1.cpp +++ b/engines/adl/adl_v1.cpp @@ -240,10 +240,10 @@ void AdlEngine_v1::wordWrap(Common::String &str) { if (str.size() <= end) return; - while (str[end] != (char)A2CHAR(' ')) + while (str[end] != APPLECHAR(' ')) --end; - str.setChar((char)A2CHAR('\r'), end); + str.setChar(APPLECHAR('\r'), end); end += 40; } } @@ -414,7 +414,7 @@ void AdlEngine_v1::doActions(const Command &command, byte noun, byte offset) { case 0x11: { _display->printString(_exeStrings[STR_MH_PLAYAGAIN]); Common::String input = _display->inputString(); - if (input.size() == 0 || input[0] != (char)A2CHAR('N')) { + if (input.size() == 0 || input[0] != APPLECHAR('N')) { warning("Restart game not implemented"); return; } @@ -528,12 +528,9 @@ bool AdlEngine_v1::checkCommand(const Command &command, byte verb, byte noun) { bool AdlEngine_v1::doOneCommand(const Commands &commands, byte verb, byte noun) { Commands::const_iterator it; - for (it = commands.begin(); it != commands.end(); ++it) { - if (checkCommand(*it, verb, noun)) { - debug("Found match: %i %i %i", it->room, it->verb, it->noun); + for (it = commands.begin(); it != commands.end(); ++it) + if (checkCommand(*it, verb, noun)) return true; - } - } return false; } @@ -541,11 +538,8 @@ bool AdlEngine_v1::doOneCommand(const Commands &commands, byte verb, byte noun) void AdlEngine_v1::doAllCommands(const Commands &commands, byte verb, byte noun) { Commands::const_iterator it; - for (it = commands.begin(); it != commands.end(); ++it) { - if (checkCommand(*it, verb, noun)) { - debug("Found match: %i %i %i", it->room, it->verb, it->noun); - } - } + for (it = commands.begin(); it != commands.end(); ++it) + checkCommand(*it, verb, noun); } void AdlEngine_v1::clearScreen() { @@ -563,7 +557,7 @@ void AdlEngine_v1::runGame() { error("Failed to open file"); while (!f.eos() && !f.err()) - _msgStrings.push_back(readString(f, A2CHAR('\r')) + (char)A2CHAR('\r')); + _msgStrings.push_back(readString(f, APPLECHAR('\r')) + APPLECHAR('\r')); f.close(); diff --git a/engines/adl/display.cpp b/engines/adl/display.cpp index 02b8d51b7f..47b1533582 100644 --- a/engines/adl/display.cpp +++ b/engines/adl/display.cpp @@ -429,7 +429,7 @@ void Display::printASCIIString(const Common::String &str) { Common::String::const_iterator it; for (it = str.begin(); it != str.end(); ++it) - aStr += *it | 0x80; + aStr += APPLECHAR(*it); printString(aStr); } diff --git a/engines/adl/display.h b/engines/adl/display.h index eabf340573..62294d3e55 100644 --- a/engines/adl/display.h +++ b/engines/adl/display.h @@ -37,7 +37,9 @@ class Surface; } namespace Adl { - + +#define APPLECHAR(C) ((char)((C) | 0x80)) + class Display { public: enum Mode { diff --git a/engines/adl/parser.cpp b/engines/adl/parser.cpp index cdbaf3ba6c..1611fc7f54 100644 --- a/engines/adl/parser.cpp +++ b/engines/adl/parser.cpp @@ -81,7 +81,7 @@ Common::String Parser::getLine() { bool textMode = false; while (1) { - Common::String line = _display.inputString(A2CHAR('?')); + Common::String line = _display.inputString(APPLECHAR('?')); if (g_engine->shouldQuit()) return ""; @@ -102,7 +102,7 @@ Common::String Parser::getWord(const Common::String &line, uint &index) { Common::String str; for (uint i = 0; i < 8; ++i) - str += (char)(A2CHAR(' ')); + str += APPLECHAR(' '); int copied = 0; @@ -110,7 +110,7 @@ Common::String Parser::getWord(const Common::String &line, uint &index) { while (1) { if (index == line.size()) return str; - if (line[index] != (char)(A2CHAR(' '))) + if (line[index] != APPLECHAR(' ')) break; ++index; } @@ -122,7 +122,7 @@ Common::String Parser::getWord(const Common::String &line, uint &index) { index++; - if (index == line.size() || line[index] == (char)(A2CHAR(' '))) + if (index == line.size() || line[index] == APPLECHAR(' ')) return str; } } @@ -137,7 +137,6 @@ void Parser::getInput(uint &verb, uint &noun) { uint index = 0; Common::String verbStr = getWord(line, index); - debug("Verb: \"%s\"", appleToAscii(verbStr).c_str()); if (!_verbs.contains(verbStr)) { Common::String err = _engine.getExeString(STR_COMMON_VERBERR); @@ -148,10 +147,8 @@ void Parser::getInput(uint &verb, uint &noun) { } verb = _verbs[verbStr]; - debug("Verb ID: %i", verb); Common::String nounStr = getWord(line, index); - debug("Noun: \"%s\"", appleToAscii(nounStr).c_str()); if (!_nouns.contains(nounStr)) { Common::String err = _engine.getExeString(STR_COMMON_NOUNERR); @@ -164,7 +161,6 @@ void Parser::getInput(uint &verb, uint &noun) { } noun = _nouns[nounStr]; - debug("Noun ID: %i", noun); return; } } -- cgit v1.2.3 From 183fe8b217c09df4deef3e31d5c01531bb532c50 Mon Sep 17 00:00:00 2001 From: Walter van Niftrik Date: Sat, 27 Feb 2016 13:54:47 +0100 Subject: ADL: Move members into base class --- engines/adl/adl.cpp | 10 ++++++---- engines/adl/adl.h | 23 +++++++++++++++++----- engines/adl/adl_v1.cpp | 6 +----- engines/adl/adl_v1.h | 52 -------------------------------------------------- 4 files changed, 25 insertions(+), 66 deletions(-) (limited to 'engines') diff --git a/engines/adl/adl.cpp b/engines/adl/adl.cpp index 9925e04286..8042a9a557 100644 --- a/engines/adl/adl.cpp +++ b/engines/adl/adl.cpp @@ -42,12 +42,15 @@ namespace Adl { AdlEngine::AdlEngine(OSystem *syst, const AdlGameDescription *gd) : Engine(syst), _gameDescription(gd), - _console(nullptr), - _display(nullptr) { + _display(nullptr), + _parser(nullptr), + _room(1), + _steps(0), + _isDark(false) { } AdlEngine::~AdlEngine() { - delete _console; + delete _parser; delete _display; } @@ -65,7 +68,6 @@ Common::Error AdlEngine::run() { g_system->getPaletteManager()->setPalette(palette, 0, 6); - _console = new Console(this); _display = new Display(); _parser = new Parser(*this, *_display); diff --git a/engines/adl/adl.h b/engines/adl/adl.h index 954c61335d..55ba0fcdec 100644 --- a/engines/adl/adl.h +++ b/engines/adl/adl.h @@ -24,7 +24,10 @@ #define ADL_ADL_H #include "common/random.h" +#include "common/rect.h" + #include "engines/engine.h" + #include "gui/debugger.h" namespace Common { @@ -102,14 +105,24 @@ protected: virtual void runGame() = 0; Common::String readString(Common::ReadStream &stream, byte until = 0); void printStrings(Common::SeekableReadStream &stream, int count = 1); + Display *_display; Parser *_parser; -private: - Console *_console; - - // We need random numbers - Common::RandomSource *_rnd; + Common::Array _msgStrings; + Common::Array _pictures; + Common::Array _inventory; + Common::Array _itemOffsets; + Common::Array > _drawings; + Commands _roomCommands; + Commands _globalCommands; + + // Game state + Common::Array _rooms; + byte _room; + uint16 _steps; + Common::Array _variables; + bool _isDark; }; // Example console class diff --git a/engines/adl/adl_v1.cpp b/engines/adl/adl_v1.cpp index 42182390dd..28aa895b3c 100644 --- a/engines/adl/adl_v1.cpp +++ b/engines/adl/adl_v1.cpp @@ -46,11 +46,7 @@ static uint exeStrings[STR_MH_TOTAL] = { }; AdlEngine_v1::AdlEngine_v1(OSystem *syst, const AdlGameDescription *gd) : - AdlEngine(syst, gd), - _state(kIntro), - _room(1), - _steps(1), - _isDark(false) { + AdlEngine(syst, gd) { _variables.resize(20); } diff --git a/engines/adl/adl_v1.h b/engines/adl/adl_v1.h index b8f4c536a5..c1e28bcb04 100644 --- a/engines/adl/adl_v1.h +++ b/engines/adl/adl_v1.h @@ -57,46 +57,6 @@ private: MH_ITEM_OFFSETS = 21 }; - enum State { - kIntro, - kIdle - }; - - struct Room { - byte description; - byte connections[6]; - byte field8; - byte picture; - }; - - struct Picture { - byte block; - uint16 offset; - }; - - struct Command { - byte room; - byte verb, noun; - byte numCond, numAct; - Common::Array script; - }; - - struct Item { - byte field1; - byte field2; - byte field3; - byte field4; - byte field5; - byte field6; - byte field7; - byte field8; - Common::Array field10; - }; - - typedef Common::List Commands; - - int _state; - void runIntro(); void drawPic(Common::ReadStream &stream, byte xOffset, byte yOffset); void showRoom(); @@ -114,18 +74,6 @@ private: void drawPic(byte pic, byte xOffset, byte yOffset); Common::Array _exeStrings; - Common::Array _msgStrings; - Common::Array _rooms; - Common::Array _pictures; - Common::Array _inventory; - Common::Array _itemOffsets; - Common::Array > _drawings; - Commands _roomCommands; - Commands _globalCommands; - byte _room; - uint16 _steps; - Common::Array _variables; - bool _isDark; }; } // End of namespace Adl -- cgit v1.2.3 From d30cfa24fad35a668d0006f67b9d39901f0757a9 Mon Sep 17 00:00:00 2001 From: Walter van Niftrik Date: Sat, 27 Feb 2016 13:57:52 +0100 Subject: ADL: Remove dead code --- engines/adl/adl.h | 7 ------- 1 file changed, 7 deletions(-) (limited to 'engines') diff --git a/engines/adl/adl.h b/engines/adl/adl.h index 55ba0fcdec..cc20edf22c 100644 --- a/engines/adl/adl.h +++ b/engines/adl/adl.h @@ -125,13 +125,6 @@ protected: bool _isDark; }; -// Example console class -class Console : public GUI::Debugger { -public: - Console(AdlEngine *vm) {} - virtual ~Console(void) {} -}; - AdlEngine *AdlEngine_v1__create(OSystem *syst, const AdlGameDescription *gd); } // End of namespace Adl -- cgit v1.2.3 From 43a37e94dd466887eabdeb589bdc54ca4cec6c41 Mon Sep 17 00:00:00 2001 From: Walter van Niftrik Date: Sat, 27 Feb 2016 15:03:24 +0100 Subject: ADL: Rename AdlEngine_v1 to HiRes1Engine --- engines/adl/adl.cpp | 2 +- engines/adl/adl.h | 2 +- engines/adl/adl_v1.cpp | 40 ++++++++++++++++++++-------------------- engines/adl/adl_v1.h | 4 ++-- 4 files changed, 24 insertions(+), 24 deletions(-) (limited to 'engines') diff --git a/engines/adl/adl.cpp b/engines/adl/adl.cpp index 8042a9a557..3ee72e8255 100644 --- a/engines/adl/adl.cpp +++ b/engines/adl/adl.cpp @@ -106,7 +106,7 @@ void AdlEngine::printStrings(Common::SeekableReadStream &stream, int count) { AdlEngine *AdlEngine::create(GameType type, OSystem *syst, const AdlGameDescription *gd) { switch(type) { case kGameTypeHires1: - return AdlEngine_v1__create(syst, gd); + return HiRes1Engine__create(syst, gd); default: error("Unknown GameType"); } diff --git a/engines/adl/adl.h b/engines/adl/adl.h index cc20edf22c..5252916c2f 100644 --- a/engines/adl/adl.h +++ b/engines/adl/adl.h @@ -125,7 +125,7 @@ protected: bool _isDark; }; -AdlEngine *AdlEngine_v1__create(OSystem *syst, const AdlGameDescription *gd); +AdlEngine *HiRes1Engine__create(OSystem *syst, const AdlGameDescription *gd); } // End of namespace Adl diff --git a/engines/adl/adl_v1.cpp b/engines/adl/adl_v1.cpp index 28aa895b3c..566a46779c 100644 --- a/engines/adl/adl_v1.cpp +++ b/engines/adl/adl_v1.cpp @@ -45,12 +45,12 @@ static uint exeStrings[STR_MH_TOTAL] = { 23484, 23375, 23438, 27658, 0x6c31, 27729, 27772, 0x5f1e }; -AdlEngine_v1::AdlEngine_v1(OSystem *syst, const AdlGameDescription *gd) : +HiRes1Engine::HiRes1Engine(OSystem *syst, const AdlGameDescription *gd) : AdlEngine(syst, gd) { _variables.resize(20); } -void AdlEngine_v1::runIntro() { +void HiRes1Engine::runIntro() { Common::File file; if (!file.open("AUTO LOAD OBJ")) @@ -132,7 +132,7 @@ void AdlEngine_v1::runIntro() { } } -void AdlEngine_v1::drawPic(Common::ReadStream &stream, byte xOffset, byte yOffset) { +void HiRes1Engine::drawPic(Common::ReadStream &stream, byte xOffset, byte yOffset) { byte x, y; bool bNewLine = false; byte oldX = 0, oldY = 0; @@ -169,7 +169,7 @@ void AdlEngine_v1::drawPic(Common::ReadStream &stream, byte xOffset, byte yOffse } } -void AdlEngine_v1::drawPic(byte pic, byte xOffset, byte yOffset) { +void HiRes1Engine::drawPic(byte pic, byte xOffset, byte yOffset) { Common::File f; Common::String name = Common::String::format("BLOCK%i", _pictures[pic].block); @@ -180,7 +180,7 @@ void AdlEngine_v1::drawPic(byte pic, byte xOffset, byte yOffset) { drawPic(f, xOffset, yOffset); } -void AdlEngine_v1::drawItems() { +void HiRes1Engine::drawItems() { Common::Array::const_iterator it; uint dropped = 0; @@ -215,7 +215,7 @@ void AdlEngine_v1::drawItems() { } } -void AdlEngine_v1::showRoom() { +void HiRes1Engine::showRoom() { if (!_isDark) { drawPic(_rooms[_room].picture, 0, 0); drawItems(); @@ -225,11 +225,11 @@ void AdlEngine_v1::showRoom() { printMessage(_rooms[_room].description, false); } -Common::String AdlEngine_v1::getExeString(uint idx) { +Common::String HiRes1Engine::getExeString(uint idx) { return _exeStrings[idx]; } -void AdlEngine_v1::wordWrap(Common::String &str) { +void HiRes1Engine::wordWrap(Common::String &str) { uint end = 39; while (1) { @@ -244,7 +244,7 @@ void AdlEngine_v1::wordWrap(Common::String &str) { } } -void AdlEngine_v1::printMessage(uint idx, bool wait) { +void HiRes1Engine::printMessage(uint idx, bool wait) { // Hardcoded overrides that don't wait after printing // Note: strings may differ slightly from the ones in MESSAGES switch (idx) { @@ -270,7 +270,7 @@ void AdlEngine_v1::printMessage(uint idx, bool wait) { _display->delay(14 * 166018 / 1000); } -void AdlEngine_v1::readCommands(Common::ReadStream &stream, Commands &commands) { +void HiRes1Engine::readCommands(Common::ReadStream &stream, Commands &commands) { while (1) { Command command; command.room = stream.readByte(); @@ -296,7 +296,7 @@ void AdlEngine_v1::readCommands(Common::ReadStream &stream, Commands &commands) } } -void AdlEngine_v1::takeItem(byte noun) { +void HiRes1Engine::takeItem(byte noun) { Common::Array::iterator it; for (it = _inventory.begin(); it != _inventory.end(); ++it) { @@ -329,7 +329,7 @@ void AdlEngine_v1::takeItem(byte noun) { printMessage(152); } -void AdlEngine_v1::dropItem(byte noun) { +void HiRes1Engine::dropItem(byte noun) { Common::Array::iterator it; for (it = _inventory.begin(); it != _inventory.end(); ++it) { @@ -345,7 +345,7 @@ void AdlEngine_v1::dropItem(byte noun) { printMessage(37); } -void AdlEngine_v1::doActions(const Command &command, byte noun, byte offset) { +void HiRes1Engine::doActions(const Command &command, byte noun, byte offset) { for (uint i = 0; i < command.numAct; ++i) { switch (command.script[offset]) { case 1: @@ -473,7 +473,7 @@ void AdlEngine_v1::doActions(const Command &command, byte noun, byte offset) { } } -bool AdlEngine_v1::checkCommand(const Command &command, byte verb, byte noun) { +bool HiRes1Engine::checkCommand(const Command &command, byte verb, byte noun) { if (command.room != 0xfe && command.room != _room) return false; @@ -521,7 +521,7 @@ bool AdlEngine_v1::checkCommand(const Command &command, byte verb, byte noun) { return true; } -bool AdlEngine_v1::doOneCommand(const Commands &commands, byte verb, byte noun) { +bool HiRes1Engine::doOneCommand(const Commands &commands, byte verb, byte noun) { Commands::const_iterator it; for (it = commands.begin(); it != commands.end(); ++it) @@ -531,19 +531,19 @@ bool AdlEngine_v1::doOneCommand(const Commands &commands, byte verb, byte noun) return false; } -void AdlEngine_v1::doAllCommands(const Commands &commands, byte verb, byte noun) { +void HiRes1Engine::doAllCommands(const Commands &commands, byte verb, byte noun) { Commands::const_iterator it; for (it = commands.begin(); it != commands.end(); ++it) checkCommand(*it, verb, noun); } -void AdlEngine_v1::clearScreen() { +void HiRes1Engine::clearScreen() { _display->setMode(Display::kModeMixed); _display->clear(0x00); } -void AdlEngine_v1::runGame() { +void HiRes1Engine::runGame() { runIntro(); _display->printASCIIString("\r"); @@ -673,8 +673,8 @@ void AdlEngine_v1::runGame() { } } -AdlEngine *AdlEngine_v1__create(OSystem *syst, const AdlGameDescription *gd) { - return new AdlEngine_v1(syst, gd); +AdlEngine *HiRes1Engine__create(OSystem *syst, const AdlGameDescription *gd) { + return new HiRes1Engine(syst, gd); } } // End of namespace Adl diff --git a/engines/adl/adl_v1.h b/engines/adl/adl_v1.h index c1e28bcb04..e9e274cc58 100644 --- a/engines/adl/adl_v1.h +++ b/engines/adl/adl_v1.h @@ -42,9 +42,9 @@ enum { STR_MH_TOTAL }; -class AdlEngine_v1 : public AdlEngine { +class HiRes1Engine : public AdlEngine { public: - AdlEngine_v1(OSystem *syst, const AdlGameDescription *gd); + HiRes1Engine(OSystem *syst, const AdlGameDescription *gd); Common::String getExeString(uint idx); protected: -- cgit v1.2.3 From 1e17a23879c6e81a09e2ad80d0ae7a1c0cc10732 Mon Sep 17 00:00:00 2001 From: Walter van Niftrik Date: Sat, 27 Feb 2016 15:05:06 +0100 Subject: ADL: Rename adl_v1.cpp/h to hires1.cpp/h --- engines/adl/adl_v1.cpp | 680 ------------------------------------------------- engines/adl/adl_v1.h | 81 ------ engines/adl/hires1.cpp | 680 +++++++++++++++++++++++++++++++++++++++++++++++++ engines/adl/hires1.h | 81 ++++++ engines/adl/module.mk | 4 +- 5 files changed, 763 insertions(+), 763 deletions(-) delete mode 100644 engines/adl/adl_v1.cpp delete mode 100644 engines/adl/adl_v1.h create mode 100644 engines/adl/hires1.cpp create mode 100644 engines/adl/hires1.h (limited to 'engines') diff --git a/engines/adl/adl_v1.cpp b/engines/adl/adl_v1.cpp deleted file mode 100644 index 566a46779c..0000000000 --- a/engines/adl/adl_v1.cpp +++ /dev/null @@ -1,680 +0,0 @@ -/* ScummVM - Graphic Adventure Engine - * - * ScummVM is the legal property of its developers, whose names - * are too numerous to list here. Please refer to the COPYRIGHT - * file distributed with this source distribution. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - */ - -#include "common/scummsys.h" - -#include "common/config-manager.h" -#include "common/debug.h" -#include "common/debug-channels.h" -#include "common/error.h" -#include "common/file.h" -#include "common/fs.h" -#include "common/system.h" -#include "common/events.h" -#include "common/stream.h" -#include "graphics/palette.h" - -#include "engines/util.h" - -#include "adl/adl_v1.h" -#include "adl/display.h" -#include "adl/parser.h" - -namespace Adl { - -static uint exeStrings[STR_MH_TOTAL] = { - 23484, 23375, 23438, 27658, 0x6c31, 27729, 27772, 0x5f1e -}; - -HiRes1Engine::HiRes1Engine(OSystem *syst, const AdlGameDescription *gd) : - AdlEngine(syst, gd) { - _variables.resize(20); -} - -void HiRes1Engine::runIntro() { - Common::File file; - - if (!file.open("AUTO LOAD OBJ")) - error("Failed to open file"); - - file.seek(0x1003); - _display->setMode(Display::kModeHires); - _display->loadFrameBuffer(file); - _display->decodeFrameBuffer(); - _display->delay(4000); - - if (shouldQuit()) - return; - - _display->setMode(Display::kModeText); - - Common::File basic; - if (!basic.open("MYSTERY.HELLO")) - error("Failed to open file"); - - Common::String str; - - basic.seek(93); - str = readString(basic, '"'); - _display->printASCIIString(str + '\r'); - - basic.seek(299); - str = readString(basic, '"'); - _display->printASCIIString(str + "\r\r"); - - basic.seek(365); - str = readString(basic, '"'); - _display->printASCIIString(str + "\r\r"); - - basic.seek(601); - str = readString(basic, '"'); - _display->printASCIIString(str + '\r'); - - _display->inputKey(); - if (g_engine->shouldQuit()) - return; - - _display->setMode(Display::kModeMixed); - - file.seek(15); - str = readString(file); - - while (1) { - _display->printString(str); - Common::String s = _display->inputString(); - - if (g_engine->shouldQuit()) - break; - - if (s.empty()) - continue; - - if ((byte)s[0] == ('I' | 0x80)) - break; - else if ((byte)s[0] == ('G' | 0x80)) - return; - }; - - _display->setMode(Display::kModeText); - file.seek(102); - - const int pages[] = { 6, 6, 4, 5, 8, 7, 0 }; - - int page = 0; - while (pages[page] != 0) { - _display->home(); - printStrings(file, pages[page++]); - _display->inputString(); - - if (g_engine->shouldQuit()) - return; - - file.seek(9, SEEK_CUR); - } -} - -void HiRes1Engine::drawPic(Common::ReadStream &stream, byte xOffset, byte yOffset) { - byte x, y; - bool bNewLine = false; - byte oldX = 0, oldY = 0; - while (1) { - x = stream.readByte(); - y = stream.readByte(); - - if (stream.err() || stream.eos()) - error("Failed to read picture"); - - if (x == 0xff && y == 0xff) - return; - - if (x == 0 && y == 0) { - bNewLine = true; - continue; - } - - x += xOffset; - y += yOffset; - - if (y > 160) - y = 160; - - if (bNewLine) { - _display->drawPixel(x, y, 0x7f); - bNewLine = false; - } else { - _display->drawLine(Common::Point(oldX, oldY), Common::Point(x, y), 0x7f); - } - - oldX = x; - oldY = y; - } -} - -void HiRes1Engine::drawPic(byte pic, byte xOffset, byte yOffset) { - Common::File f; - Common::String name = Common::String::format("BLOCK%i", _pictures[pic].block); - - if (!f.open(name)) - error("Failed to open file"); - - f.seek(_pictures[pic].offset); - drawPic(f, xOffset, yOffset); -} - -void HiRes1Engine::drawItems() { - Common::Array::const_iterator it; - - uint dropped = 0; - - for (it = _inventory.begin(); it != _inventory.end(); ++it) { - if (it->field2 != _room) - continue; - - if (it->field7 == 1) { - if (_rooms[_room].field8 == _rooms[_room].picture) { - const Common::Point &p = _itemOffsets[dropped]; - if (it->field4) - _display->drawRightAngles(_drawings[it->field3 - 1], Common::Point(p.x, p.y), 0, 1, 0x7f); - else - drawPic(it->field3, p.x, p.y); - ++dropped; - } - continue; - } - - Common::Array::const_iterator it2; - - for (it2 = it->field10.begin(); it2 != it->field10.end(); ++it2) { - if (*it2 == _rooms[_room].picture) { - if (it->field4) - _display->drawRightAngles(_drawings[it->field3 - 1], Common::Point(it->field5, it->field6), 0, 1, 0x7f); - else - drawPic(it->field3, it->field5, it->field6); - continue; - } - } - } -} - -void HiRes1Engine::showRoom() { - if (!_isDark) { - drawPic(_rooms[_room].picture, 0, 0); - drawItems(); - } - - _display->decodeFrameBuffer(); - printMessage(_rooms[_room].description, false); -} - -Common::String HiRes1Engine::getExeString(uint idx) { - return _exeStrings[idx]; -} - -void HiRes1Engine::wordWrap(Common::String &str) { - uint end = 39; - - while (1) { - if (str.size() <= end) - return; - - while (str[end] != APPLECHAR(' ')) - --end; - - str.setChar(APPLECHAR('\r'), end); - end += 40; - } -} - -void HiRes1Engine::printMessage(uint idx, bool wait) { - // Hardcoded overrides that don't wait after printing - // Note: strings may differ slightly from the ones in MESSAGES - switch (idx) { - case 137: - _display->printString(_exeStrings[STR_MH_DIRERR]); - return; - case 127: - _display->printString(_exeStrings[STR_MH_DONTHAVEIT]); - return; - case 37: - _display->printString(_exeStrings[STR_MH_DONTUNDERSTAND]); - return; - case 7: - _display->printString(_exeStrings[STR_MH_GETTINGDARK]); - return; - } - - Common::String msg = _msgStrings[idx - 1]; - wordWrap(msg); - _display->printString(msg); - - if (wait) - _display->delay(14 * 166018 / 1000); -} - -void HiRes1Engine::readCommands(Common::ReadStream &stream, Commands &commands) { - while (1) { - Command command; - command.room = stream.readByte(); - - if (command.room == 0xff) - return; - - command.verb = stream.readByte(); - command.noun = stream.readByte(); - - byte scriptSize = stream.readByte() - 6; - - command.numCond = stream.readByte(); - command.numAct = stream.readByte(); - - for (uint i = 0; i < scriptSize; ++i) - command.script.push_back(stream.readByte()); - - if (stream.eos() || stream.err()) - error("Failed to read commands"); - - commands.push_back(command); - } -} - -void HiRes1Engine::takeItem(byte noun) { - Common::Array::iterator it; - - for (it = _inventory.begin(); it != _inventory.end(); ++it) { - if (it->field1 != noun || it->field2 != _room) - continue; - - if (it->field7 == 2) { - // It doesn't move - printMessage(151); - return; - } - - if (it->field7 == 1) { - it->field2 = 0xfe; - it->field7 = 1; - return; - } - - Common::Array::const_iterator it2; - for (it2 = it->field10.begin(); it->field10.end(); ++it2) { - if (*it2 == _rooms[_room].picture) { - it->field2 = 0xfe; - it->field7 = 1; - return; - } - } - } - - // Item not here - printMessage(152); -} - -void HiRes1Engine::dropItem(byte noun) { - Common::Array::iterator it; - - for (it = _inventory.begin(); it != _inventory.end(); ++it) { - if (it->field1 != noun || it->field2 != 0xfe) - continue; - - it->field2 = _room; - it->field7 = 1; - return; - } - - // Don't understand - printMessage(37); -} - -void HiRes1Engine::doActions(const Command &command, byte noun, byte offset) { - for (uint i = 0; i < command.numAct; ++i) { - switch (command.script[offset]) { - case 1: - _variables[command.script[offset + 2]] += command.script[offset + 1]; - offset += 3; - break; - case 2: - _variables[command.script[offset + 2]] -= command.script[offset + 1]; - offset += 3; - break; - case 3: - _variables[command.script[offset + 1]] = command.script[offset + 2]; - offset += 3; - break; - case 4: { - Common::Array::const_iterator it; - - for (it = _inventory.begin(); it != _inventory.end(); ++it) - if (it->field2 == 0xfe) - printMessage(it->field8); - - ++offset; - break; - } - case 5: - _inventory[command.script[offset + 1] - 1].field2 = command.script[offset + 2]; - offset += 3; - break; - case 6: - _rooms[_room].picture = _rooms[_room].field8; - _room = command.script[offset + 1]; - offset += 2; - break; - case 7: - _rooms[_room].picture = command.script[offset + 1]; - offset += 2; - break; - case 8: - _rooms[_room].field8 = _rooms[_room].picture = command.script[offset + 1]; - offset += 2; - break; - case 9: - printMessage(command.script[offset + 1]); - offset += 2; - break; - case 0xa: - _isDark = false; - ++offset; - break; - case 0xb: - _isDark = true; - ++offset; - break; - case 0xf: - warning("Save game not implemented"); - ++offset; - break; - case 0x10: - warning("Load game not implemented"); - ++offset; - break; - case 0x11: { - _display->printString(_exeStrings[STR_MH_PLAYAGAIN]); - Common::String input = _display->inputString(); - if (input.size() == 0 || input[0] != APPLECHAR('N')) { - warning("Restart game not implemented"); - return; - } - // Fall-through - } - case 0xd: - printMessage(140); - quitGame(); - return; - case 0x12: { - byte item = command.script[offset + 1] - 1; - _inventory[item].field2 = command.script[offset + 2]; - _inventory[item].field5 = command.script[offset + 3]; - _inventory[item].field6 = command.script[offset + 4]; - offset += 5; - break; - } - case 0x13: { - byte item = command.script[offset + 2] - 1; - _inventory[item].field3 = command.script[offset + 1]; - offset += 3; - break; - } - case 0x14: - _rooms[_room].picture = _rooms[_room].field8; - ++offset; - break; - case 0x15: - case 0x16: - case 0x17: - case 0x18: - case 0x19: - case 0x1a: { - byte room = _rooms[_room].connections[command.script[offset] - 0x15]; - - if (room == 0) { - printMessage(137); - return; - } - - _rooms[_room].picture = _rooms[_room].field8; - _room = room; - return; - } - case 0x1b: - takeItem(noun); - ++offset; - break; - case 0x1c: - dropItem(noun); - ++offset; - break; - case 0x1d: - _rooms[command.script[offset + 1]].field8 = _rooms[command.script[offset + 1]].picture = command.script[offset + 2]; - offset += 3; - break; - default: - error("Invalid action opcode %02x", command.script[offset]); - } - } -} - -bool HiRes1Engine::checkCommand(const Command &command, byte verb, byte noun) { - if (command.room != 0xfe && command.room != _room) - return false; - - if (command.verb != 0xfe && command.verb != verb) - return false; - - if (command.noun != 0xfe && command.noun != noun) - return false; - - uint offset = 0; - for (uint i = 0; i < command.numCond; ++i) { - switch (command.script[offset]) { - case 3: - if (_inventory[command.script[offset + 1] - 1].field2 != command.script[offset + 2]) - return false; - offset += 3; - break; - case 5: - if (command.script[offset + 1] > _steps) - return false; - offset += 2; - break; - case 6: - if (_variables[command.script[offset + 1]] != command.script[offset + 2]) - return false; - offset += 3; - break; - case 9: - if (_rooms[_room].picture != command.script[offset + 1]) - return false; - offset += 2; - break; - case 10: - if (_inventory[command.script[offset + 1] - 1].field3 != command.script[offset + 2]) - return false; - offset += 3; - break; - default: - error("Invalid condition opcode %02x", command.script[offset]); - } - } - - doActions(command, noun, offset); - - return true; -} - -bool HiRes1Engine::doOneCommand(const Commands &commands, byte verb, byte noun) { - Commands::const_iterator it; - - for (it = commands.begin(); it != commands.end(); ++it) - if (checkCommand(*it, verb, noun)) - return true; - - return false; -} - -void HiRes1Engine::doAllCommands(const Commands &commands, byte verb, byte noun) { - Commands::const_iterator it; - - for (it = commands.begin(); it != commands.end(); ++it) - checkCommand(*it, verb, noun); -} - -void HiRes1Engine::clearScreen() { - _display->setMode(Display::kModeMixed); - _display->clear(0x00); -} - -void HiRes1Engine::runGame() { - runIntro(); - _display->printASCIIString("\r"); - - Common::File f; - - if (!f.open("MESSAGES")) - error("Failed to open file"); - - while (!f.eos() && !f.err()) - _msgStrings.push_back(readString(f, APPLECHAR('\r')) + APPLECHAR('\r')); - - f.close(); - - if (!f.open("ADVENTURE")) - error("Failed to open file"); - - // Load strings from executable - for (uint idx = 0; idx < STR_MH_TOTAL; ++idx) { - f.seek(exeStrings[idx]); - _exeStrings.push_back(readString(f)); - } - - // Load room data from executable - f.seek(1280); - for (uint i = 0; i < MH_ROOMS; ++i) { - struct Room room; - f.readByte(); - room.description = f.readByte(); - for (uint j = 0; j < 6; ++j) - room.connections[j] = f.readByte(); - room.field8 = f.readByte(); - room.picture = f.readByte(); - _rooms.push_back(room); - } - - // Load inventory data from executable - f.seek(0x100); - while (f.readByte() != 0xff) { - struct Item item; - item.field1 = f.readByte(); - item.field2 = f.readByte(); - item.field3 = f.readByte(); - item.field4 = f.readByte(); - item.field5 = f.readByte(); - item.field6 = f.readByte(); - item.field7 = f.readByte(); - item.field8 = f.readByte(); - - f.readByte(); - - byte size = f.readByte(); - - for (uint i = 0; i < size; ++i) - item.field10.push_back(f.readByte()); - - _inventory.push_back(item); - } - - // Load picture data from executable - f.seek(0x4b00); - for (uint i = 0; i < MH_PICS; ++i) { - struct Picture pic; - pic.block = f.readByte(); - pic.offset = f.readUint16LE(); - _pictures.push_back(pic); - } - - // Load commands from executable - f.seek(0x3D00); - readCommands(f, _roomCommands); - - f.seek(0x3C00); - readCommands(f, _globalCommands); - - // Load dropped item offsets - f.seek(0x68ff); - for (uint i = 0; i < MH_ITEM_OFFSETS; ++i) { - Common::Point p; - p.x = f.readByte(); - p.y = f.readByte(); - _itemOffsets.push_back(p); - } - - // Load right-angle drawings - f.seek(0x4f00); - uint16 drawingsTotal = f.readUint16LE(); - for (uint i = 0; i < drawingsTotal; ++i) { - f.seek(0x4f00 + 2 + i * 2); - uint16 offset = f.readUint16LE(); - f.seek(0x4f00 + offset); - - Common::Array drawing; - byte b = f.readByte(); - while (b != 0) { - drawing.push_back(b); - b = f.readByte(); - } - _drawings.push_back(drawing); - } - - // Title screen shown during loading - f.seek(0x1800); - _display->loadFrameBuffer(f); - _display->decodeFrameBuffer(); - _display->delay(2000); - - f.seek(0x3800); - _parser->loadVerbs(f); - - f.seek(0xf00); - _parser->loadNouns(f); - - while (1) { - uint verb = 0, noun = 0; - clearScreen(); - showRoom(); - _parser->getInput(verb, noun); - - if (!doOneCommand(_roomCommands, verb, noun)) - printMessage(37); - doAllCommands(_globalCommands, verb, noun); - - _steps++; - - if (shouldQuit()) - return; - } -} - -AdlEngine *HiRes1Engine__create(OSystem *syst, const AdlGameDescription *gd) { - return new HiRes1Engine(syst, gd); -} - -} // End of namespace Adl diff --git a/engines/adl/adl_v1.h b/engines/adl/adl_v1.h deleted file mode 100644 index e9e274cc58..0000000000 --- a/engines/adl/adl_v1.h +++ /dev/null @@ -1,81 +0,0 @@ -/* ScummVM - Graphic Adventure Engine - * - * ScummVM is the legal property of its developers, whose names - * are too numerous to list here. Please refer to the COPYRIGHT - * file distributed with this source distribution. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - */ - -#ifndef ADL_ADL_V1_H -#define ADL_ADL_V1_H - -#include "adl/adl.h" - -namespace Common { -class ReadStream; -} - -namespace Adl { - -enum { - // Some of these are probably common - STR_MH_DIRERR = STR_CUSTOM_START, - STR_MH_DONTHAVEIT, - STR_MH_DONTUNDERSTAND, - STR_MH_GETTINGDARK, - STR_MH_PLAYAGAIN, - - STR_MH_TOTAL -}; - -class HiRes1Engine : public AdlEngine { -public: - HiRes1Engine(OSystem *syst, const AdlGameDescription *gd); - Common::String getExeString(uint idx); - -protected: - void runGame(); - -private: - enum { - MH_ROOMS = 42, - MH_PICS = 98, - MH_ITEM_OFFSETS = 21 - }; - - void runIntro(); - void drawPic(Common::ReadStream &stream, byte xOffset, byte yOffset); - void showRoom(); - void printMessage(uint idx, bool wait = true); - void wordWrap(Common::String &str); - void readCommands(Common::ReadStream &stream, Commands &commands); - bool checkCommand(const Command &command, byte verb, byte noun); - bool doOneCommand(const Commands &commands, byte verb, byte noun); - void doAllCommands(const Commands &commands, byte verb, byte noun); - void doActions(const Command &command, byte noun, byte offset); - void clearScreen(); - void takeItem(byte noun); - void dropItem(byte noun); - void drawItems(); - void drawPic(byte pic, byte xOffset, byte yOffset); - - Common::Array _exeStrings; -}; - -} // End of namespace Adl - -#endif diff --git a/engines/adl/hires1.cpp b/engines/adl/hires1.cpp new file mode 100644 index 0000000000..28aa13568d --- /dev/null +++ b/engines/adl/hires1.cpp @@ -0,0 +1,680 @@ +/* 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.h" +#include "common/debug-channels.h" +#include "common/error.h" +#include "common/file.h" +#include "common/fs.h" +#include "common/system.h" +#include "common/events.h" +#include "common/stream.h" +#include "graphics/palette.h" + +#include "engines/util.h" + +#include "adl/hires1.h" +#include "adl/display.h" +#include "adl/parser.h" + +namespace Adl { + +static uint exeStrings[STR_MH_TOTAL] = { + 23484, 23375, 23438, 27658, 0x6c31, 27729, 27772, 0x5f1e +}; + +HiRes1Engine::HiRes1Engine(OSystem *syst, const AdlGameDescription *gd) : + AdlEngine(syst, gd) { + _variables.resize(20); +} + +void HiRes1Engine::runIntro() { + Common::File file; + + if (!file.open("AUTO LOAD OBJ")) + error("Failed to open file"); + + file.seek(0x1003); + _display->setMode(Display::kModeHires); + _display->loadFrameBuffer(file); + _display->decodeFrameBuffer(); + _display->delay(4000); + + if (shouldQuit()) + return; + + _display->setMode(Display::kModeText); + + Common::File basic; + if (!basic.open("MYSTERY.HELLO")) + error("Failed to open file"); + + Common::String str; + + basic.seek(93); + str = readString(basic, '"'); + _display->printASCIIString(str + '\r'); + + basic.seek(299); + str = readString(basic, '"'); + _display->printASCIIString(str + "\r\r"); + + basic.seek(365); + str = readString(basic, '"'); + _display->printASCIIString(str + "\r\r"); + + basic.seek(601); + str = readString(basic, '"'); + _display->printASCIIString(str + '\r'); + + _display->inputKey(); + if (g_engine->shouldQuit()) + return; + + _display->setMode(Display::kModeMixed); + + file.seek(15); + str = readString(file); + + while (1) { + _display->printString(str); + Common::String s = _display->inputString(); + + if (g_engine->shouldQuit()) + break; + + if (s.empty()) + continue; + + if ((byte)s[0] == ('I' | 0x80)) + break; + else if ((byte)s[0] == ('G' | 0x80)) + return; + }; + + _display->setMode(Display::kModeText); + file.seek(102); + + const int pages[] = { 6, 6, 4, 5, 8, 7, 0 }; + + int page = 0; + while (pages[page] != 0) { + _display->home(); + printStrings(file, pages[page++]); + _display->inputString(); + + if (g_engine->shouldQuit()) + return; + + file.seek(9, SEEK_CUR); + } +} + +void HiRes1Engine::drawPic(Common::ReadStream &stream, byte xOffset, byte yOffset) { + byte x, y; + bool bNewLine = false; + byte oldX = 0, oldY = 0; + while (1) { + x = stream.readByte(); + y = stream.readByte(); + + if (stream.err() || stream.eos()) + error("Failed to read picture"); + + if (x == 0xff && y == 0xff) + return; + + if (x == 0 && y == 0) { + bNewLine = true; + continue; + } + + x += xOffset; + y += yOffset; + + if (y > 160) + y = 160; + + if (bNewLine) { + _display->drawPixel(x, y, 0x7f); + bNewLine = false; + } else { + _display->drawLine(Common::Point(oldX, oldY), Common::Point(x, y), 0x7f); + } + + oldX = x; + oldY = y; + } +} + +void HiRes1Engine::drawPic(byte pic, byte xOffset, byte yOffset) { + Common::File f; + Common::String name = Common::String::format("BLOCK%i", _pictures[pic].block); + + if (!f.open(name)) + error("Failed to open file"); + + f.seek(_pictures[pic].offset); + drawPic(f, xOffset, yOffset); +} + +void HiRes1Engine::drawItems() { + Common::Array::const_iterator it; + + uint dropped = 0; + + for (it = _inventory.begin(); it != _inventory.end(); ++it) { + if (it->field2 != _room) + continue; + + if (it->field7 == 1) { + if (_rooms[_room].field8 == _rooms[_room].picture) { + const Common::Point &p = _itemOffsets[dropped]; + if (it->field4) + _display->drawRightAngles(_drawings[it->field3 - 1], Common::Point(p.x, p.y), 0, 1, 0x7f); + else + drawPic(it->field3, p.x, p.y); + ++dropped; + } + continue; + } + + Common::Array::const_iterator it2; + + for (it2 = it->field10.begin(); it2 != it->field10.end(); ++it2) { + if (*it2 == _rooms[_room].picture) { + if (it->field4) + _display->drawRightAngles(_drawings[it->field3 - 1], Common::Point(it->field5, it->field6), 0, 1, 0x7f); + else + drawPic(it->field3, it->field5, it->field6); + continue; + } + } + } +} + +void HiRes1Engine::showRoom() { + if (!_isDark) { + drawPic(_rooms[_room].picture, 0, 0); + drawItems(); + } + + _display->decodeFrameBuffer(); + printMessage(_rooms[_room].description, false); +} + +Common::String HiRes1Engine::getExeString(uint idx) { + return _exeStrings[idx]; +} + +void HiRes1Engine::wordWrap(Common::String &str) { + uint end = 39; + + while (1) { + if (str.size() <= end) + return; + + while (str[end] != APPLECHAR(' ')) + --end; + + str.setChar(APPLECHAR('\r'), end); + end += 40; + } +} + +void HiRes1Engine::printMessage(uint idx, bool wait) { + // Hardcoded overrides that don't wait after printing + // Note: strings may differ slightly from the ones in MESSAGES + switch (idx) { + case 137: + _display->printString(_exeStrings[STR_MH_DIRERR]); + return; + case 127: + _display->printString(_exeStrings[STR_MH_DONTHAVEIT]); + return; + case 37: + _display->printString(_exeStrings[STR_MH_DONTUNDERSTAND]); + return; + case 7: + _display->printString(_exeStrings[STR_MH_GETTINGDARK]); + return; + } + + Common::String msg = _msgStrings[idx - 1]; + wordWrap(msg); + _display->printString(msg); + + if (wait) + _display->delay(14 * 166018 / 1000); +} + +void HiRes1Engine::readCommands(Common::ReadStream &stream, Commands &commands) { + while (1) { + Command command; + command.room = stream.readByte(); + + if (command.room == 0xff) + return; + + command.verb = stream.readByte(); + command.noun = stream.readByte(); + + byte scriptSize = stream.readByte() - 6; + + command.numCond = stream.readByte(); + command.numAct = stream.readByte(); + + for (uint i = 0; i < scriptSize; ++i) + command.script.push_back(stream.readByte()); + + if (stream.eos() || stream.err()) + error("Failed to read commands"); + + commands.push_back(command); + } +} + +void HiRes1Engine::takeItem(byte noun) { + Common::Array::iterator it; + + for (it = _inventory.begin(); it != _inventory.end(); ++it) { + if (it->field1 != noun || it->field2 != _room) + continue; + + if (it->field7 == 2) { + // It doesn't move + printMessage(151); + return; + } + + if (it->field7 == 1) { + it->field2 = 0xfe; + it->field7 = 1; + return; + } + + Common::Array::const_iterator it2; + for (it2 = it->field10.begin(); it->field10.end(); ++it2) { + if (*it2 == _rooms[_room].picture) { + it->field2 = 0xfe; + it->field7 = 1; + return; + } + } + } + + // Item not here + printMessage(152); +} + +void HiRes1Engine::dropItem(byte noun) { + Common::Array::iterator it; + + for (it = _inventory.begin(); it != _inventory.end(); ++it) { + if (it->field1 != noun || it->field2 != 0xfe) + continue; + + it->field2 = _room; + it->field7 = 1; + return; + } + + // Don't understand + printMessage(37); +} + +void HiRes1Engine::doActions(const Command &command, byte noun, byte offset) { + for (uint i = 0; i < command.numAct; ++i) { + switch (command.script[offset]) { + case 1: + _variables[command.script[offset + 2]] += command.script[offset + 1]; + offset += 3; + break; + case 2: + _variables[command.script[offset + 2]] -= command.script[offset + 1]; + offset += 3; + break; + case 3: + _variables[command.script[offset + 1]] = command.script[offset + 2]; + offset += 3; + break; + case 4: { + Common::Array::const_iterator it; + + for (it = _inventory.begin(); it != _inventory.end(); ++it) + if (it->field2 == 0xfe) + printMessage(it->field8); + + ++offset; + break; + } + case 5: + _inventory[command.script[offset + 1] - 1].field2 = command.script[offset + 2]; + offset += 3; + break; + case 6: + _rooms[_room].picture = _rooms[_room].field8; + _room = command.script[offset + 1]; + offset += 2; + break; + case 7: + _rooms[_room].picture = command.script[offset + 1]; + offset += 2; + break; + case 8: + _rooms[_room].field8 = _rooms[_room].picture = command.script[offset + 1]; + offset += 2; + break; + case 9: + printMessage(command.script[offset + 1]); + offset += 2; + break; + case 0xa: + _isDark = false; + ++offset; + break; + case 0xb: + _isDark = true; + ++offset; + break; + case 0xf: + warning("Save game not implemented"); + ++offset; + break; + case 0x10: + warning("Load game not implemented"); + ++offset; + break; + case 0x11: { + _display->printString(_exeStrings[STR_MH_PLAYAGAIN]); + Common::String input = _display->inputString(); + if (input.size() == 0 || input[0] != APPLECHAR('N')) { + warning("Restart game not implemented"); + return; + } + // Fall-through + } + case 0xd: + printMessage(140); + quitGame(); + return; + case 0x12: { + byte item = command.script[offset + 1] - 1; + _inventory[item].field2 = command.script[offset + 2]; + _inventory[item].field5 = command.script[offset + 3]; + _inventory[item].field6 = command.script[offset + 4]; + offset += 5; + break; + } + case 0x13: { + byte item = command.script[offset + 2] - 1; + _inventory[item].field3 = command.script[offset + 1]; + offset += 3; + break; + } + case 0x14: + _rooms[_room].picture = _rooms[_room].field8; + ++offset; + break; + case 0x15: + case 0x16: + case 0x17: + case 0x18: + case 0x19: + case 0x1a: { + byte room = _rooms[_room].connections[command.script[offset] - 0x15]; + + if (room == 0) { + printMessage(137); + return; + } + + _rooms[_room].picture = _rooms[_room].field8; + _room = room; + return; + } + case 0x1b: + takeItem(noun); + ++offset; + break; + case 0x1c: + dropItem(noun); + ++offset; + break; + case 0x1d: + _rooms[command.script[offset + 1]].field8 = _rooms[command.script[offset + 1]].picture = command.script[offset + 2]; + offset += 3; + break; + default: + error("Invalid action opcode %02x", command.script[offset]); + } + } +} + +bool HiRes1Engine::checkCommand(const Command &command, byte verb, byte noun) { + if (command.room != 0xfe && command.room != _room) + return false; + + if (command.verb != 0xfe && command.verb != verb) + return false; + + if (command.noun != 0xfe && command.noun != noun) + return false; + + uint offset = 0; + for (uint i = 0; i < command.numCond; ++i) { + switch (command.script[offset]) { + case 3: + if (_inventory[command.script[offset + 1] - 1].field2 != command.script[offset + 2]) + return false; + offset += 3; + break; + case 5: + if (command.script[offset + 1] > _steps) + return false; + offset += 2; + break; + case 6: + if (_variables[command.script[offset + 1]] != command.script[offset + 2]) + return false; + offset += 3; + break; + case 9: + if (_rooms[_room].picture != command.script[offset + 1]) + return false; + offset += 2; + break; + case 10: + if (_inventory[command.script[offset + 1] - 1].field3 != command.script[offset + 2]) + return false; + offset += 3; + break; + default: + error("Invalid condition opcode %02x", command.script[offset]); + } + } + + doActions(command, noun, offset); + + return true; +} + +bool HiRes1Engine::doOneCommand(const Commands &commands, byte verb, byte noun) { + Commands::const_iterator it; + + for (it = commands.begin(); it != commands.end(); ++it) + if (checkCommand(*it, verb, noun)) + return true; + + return false; +} + +void HiRes1Engine::doAllCommands(const Commands &commands, byte verb, byte noun) { + Commands::const_iterator it; + + for (it = commands.begin(); it != commands.end(); ++it) + checkCommand(*it, verb, noun); +} + +void HiRes1Engine::clearScreen() { + _display->setMode(Display::kModeMixed); + _display->clear(0x00); +} + +void HiRes1Engine::runGame() { + runIntro(); + _display->printASCIIString("\r"); + + Common::File f; + + if (!f.open("MESSAGES")) + error("Failed to open file"); + + while (!f.eos() && !f.err()) + _msgStrings.push_back(readString(f, APPLECHAR('\r')) + APPLECHAR('\r')); + + f.close(); + + if (!f.open("ADVENTURE")) + error("Failed to open file"); + + // Load strings from executable + for (uint idx = 0; idx < STR_MH_TOTAL; ++idx) { + f.seek(exeStrings[idx]); + _exeStrings.push_back(readString(f)); + } + + // Load room data from executable + f.seek(1280); + for (uint i = 0; i < MH_ROOMS; ++i) { + struct Room room; + f.readByte(); + room.description = f.readByte(); + for (uint j = 0; j < 6; ++j) + room.connections[j] = f.readByte(); + room.field8 = f.readByte(); + room.picture = f.readByte(); + _rooms.push_back(room); + } + + // Load inventory data from executable + f.seek(0x100); + while (f.readByte() != 0xff) { + struct Item item; + item.field1 = f.readByte(); + item.field2 = f.readByte(); + item.field3 = f.readByte(); + item.field4 = f.readByte(); + item.field5 = f.readByte(); + item.field6 = f.readByte(); + item.field7 = f.readByte(); + item.field8 = f.readByte(); + + f.readByte(); + + byte size = f.readByte(); + + for (uint i = 0; i < size; ++i) + item.field10.push_back(f.readByte()); + + _inventory.push_back(item); + } + + // Load picture data from executable + f.seek(0x4b00); + for (uint i = 0; i < MH_PICS; ++i) { + struct Picture pic; + pic.block = f.readByte(); + pic.offset = f.readUint16LE(); + _pictures.push_back(pic); + } + + // Load commands from executable + f.seek(0x3D00); + readCommands(f, _roomCommands); + + f.seek(0x3C00); + readCommands(f, _globalCommands); + + // Load dropped item offsets + f.seek(0x68ff); + for (uint i = 0; i < MH_ITEM_OFFSETS; ++i) { + Common::Point p; + p.x = f.readByte(); + p.y = f.readByte(); + _itemOffsets.push_back(p); + } + + // Load right-angle drawings + f.seek(0x4f00); + uint16 drawingsTotal = f.readUint16LE(); + for (uint i = 0; i < drawingsTotal; ++i) { + f.seek(0x4f00 + 2 + i * 2); + uint16 offset = f.readUint16LE(); + f.seek(0x4f00 + offset); + + Common::Array drawing; + byte b = f.readByte(); + while (b != 0) { + drawing.push_back(b); + b = f.readByte(); + } + _drawings.push_back(drawing); + } + + // Title screen shown during loading + f.seek(0x1800); + _display->loadFrameBuffer(f); + _display->decodeFrameBuffer(); + _display->delay(2000); + + f.seek(0x3800); + _parser->loadVerbs(f); + + f.seek(0xf00); + _parser->loadNouns(f); + + while (1) { + uint verb = 0, noun = 0; + clearScreen(); + showRoom(); + _parser->getInput(verb, noun); + + if (!doOneCommand(_roomCommands, verb, noun)) + printMessage(37); + doAllCommands(_globalCommands, verb, noun); + + _steps++; + + if (shouldQuit()) + return; + } +} + +AdlEngine *HiRes1Engine__create(OSystem *syst, const AdlGameDescription *gd) { + return new HiRes1Engine(syst, gd); +} + +} // End of namespace Adl diff --git a/engines/adl/hires1.h b/engines/adl/hires1.h new file mode 100644 index 0000000000..e9e274cc58 --- /dev/null +++ b/engines/adl/hires1.h @@ -0,0 +1,81 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#ifndef ADL_ADL_V1_H +#define ADL_ADL_V1_H + +#include "adl/adl.h" + +namespace Common { +class ReadStream; +} + +namespace Adl { + +enum { + // Some of these are probably common + STR_MH_DIRERR = STR_CUSTOM_START, + STR_MH_DONTHAVEIT, + STR_MH_DONTUNDERSTAND, + STR_MH_GETTINGDARK, + STR_MH_PLAYAGAIN, + + STR_MH_TOTAL +}; + +class HiRes1Engine : public AdlEngine { +public: + HiRes1Engine(OSystem *syst, const AdlGameDescription *gd); + Common::String getExeString(uint idx); + +protected: + void runGame(); + +private: + enum { + MH_ROOMS = 42, + MH_PICS = 98, + MH_ITEM_OFFSETS = 21 + }; + + void runIntro(); + void drawPic(Common::ReadStream &stream, byte xOffset, byte yOffset); + void showRoom(); + void printMessage(uint idx, bool wait = true); + void wordWrap(Common::String &str); + void readCommands(Common::ReadStream &stream, Commands &commands); + bool checkCommand(const Command &command, byte verb, byte noun); + bool doOneCommand(const Commands &commands, byte verb, byte noun); + void doAllCommands(const Commands &commands, byte verb, byte noun); + void doActions(const Command &command, byte noun, byte offset); + void clearScreen(); + void takeItem(byte noun); + void dropItem(byte noun); + void drawItems(); + void drawPic(byte pic, byte xOffset, byte yOffset); + + Common::Array _exeStrings; +}; + +} // End of namespace Adl + +#endif diff --git a/engines/adl/module.mk b/engines/adl/module.mk index 8f86eeec68..012b027b48 100644 --- a/engines/adl/module.mk +++ b/engines/adl/module.mk @@ -1,10 +1,10 @@ MODULE := engines/adl MODULE_OBJS := \ + adl.o \ detection.o \ display.o \ - adl.o \ - adl_v1.o \ + hires1.o \ parser.o MODULE_DIRS += \ -- cgit v1.2.3 From 6a1dd071978f8ef48cb980d736877f1944a9a78f Mon Sep 17 00:00:00 2001 From: Walter van Niftrik Date: Sun, 28 Feb 2016 13:24:41 +0100 Subject: ADL: Move more functionality into base class --- engines/adl/adl.cpp | 303 +++++++++++++++++++++++++++++++++++++ engines/adl/adl.h | 46 +++++- engines/adl/hires1.cpp | 395 +++++++++---------------------------------------- engines/adl/hires1.h | 25 +--- engines/adl/parser.cpp | 6 +- 5 files changed, 420 insertions(+), 355 deletions(-) (limited to 'engines') diff --git a/engines/adl/adl.cpp b/engines/adl/adl.cpp index 3ee72e8255..2c11290919 100644 --- a/engines/adl/adl.cpp +++ b/engines/adl/adl.cpp @@ -103,6 +103,309 @@ void AdlEngine::printStrings(Common::SeekableReadStream &stream, int count) { }; } +Common::String AdlEngine::getEngineString(int str) { + return _strings[str]; +} + +void AdlEngine::wordWrap(Common::String &str) { + uint end = 39; + + while (1) { + if (str.size() <= end) + return; + + while (str[end] != APPLECHAR(' ')) + --end; + + str.setChar(APPLECHAR('\r'), end); + end += 40; + } +} + +void AdlEngine::printMessage(uint idx, bool wait) { + Common::String msg = _messages[idx - 1]; + wordWrap(msg); + _display->printString(msg); + + if (wait) + _display->delay(14 * 166018 / 1000); +} + +void AdlEngine::printEngineMessage(EngineMessage msg) { + printMessage(getEngineMessage(msg)); +} + +void AdlEngine::readCommands(Common::ReadStream &stream, Commands &commands) { + while (1) { + Command command; + command.room = stream.readByte(); + + if (command.room == 0xff) + return; + + command.verb = stream.readByte(); + command.noun = stream.readByte(); + + byte scriptSize = stream.readByte() - 6; + + command.numCond = stream.readByte(); + command.numAct = stream.readByte(); + + for (uint i = 0; i < scriptSize; ++i) + command.script.push_back(stream.readByte()); + + if (stream.eos() || stream.err()) + error("Failed to read commands"); + + commands.push_back(command); + } +} + +void AdlEngine::takeItem(byte noun) { + Common::Array::iterator it; + + for (it = _inventory.begin(); it != _inventory.end(); ++it) { + if (it->field1 != noun || it->field2 != _room) + continue; + + if (it->field7 == 2) { + printEngineMessage(IDI_MSG_ITEM_DOESNT_MOVE); + return; + } + + if (it->field7 == 1) { + it->field2 = 0xfe; + it->field7 = 1; + return; + } + + Common::Array::const_iterator it2; + for (it2 = it->field10.begin(); it->field10.end(); ++it2) { + if (*it2 == _rooms[_room].picture) { + it->field2 = 0xfe; + it->field7 = 1; + return; + } + } + } + + printEngineMessage(IDI_MSG_ITEM_NOT_HERE); +} + +void AdlEngine::dropItem(byte noun) { + Common::Array::iterator it; + + for (it = _inventory.begin(); it != _inventory.end(); ++it) { + if (it->field1 != noun || it->field2 != 0xfe) + continue; + + it->field2 = _room; + it->field7 = 1; + return; + } + + // Don't understand + printEngineMessage(IDI_MSG_DONT_UNDERSTAND); +} + +void AdlEngine::doActions(const Command &command, byte noun, byte offset) { + for (uint i = 0; i < command.numAct; ++i) { + switch (command.script[offset]) { + case 1: + _variables[command.script[offset + 2]] += command.script[offset + 1]; + offset += 3; + break; + case 2: + _variables[command.script[offset + 2]] -= command.script[offset + 1]; + offset += 3; + break; + case 3: + _variables[command.script[offset + 1]] = command.script[offset + 2]; + offset += 3; + break; + case 4: { + Common::Array::const_iterator it; + + for (it = _inventory.begin(); it != _inventory.end(); ++it) + if (it->field2 == 0xfe) + printMessage(it->field8); + + ++offset; + break; + } + case 5: + _inventory[command.script[offset + 1] - 1].field2 = command.script[offset + 2]; + offset += 3; + break; + case 6: + _rooms[_room].picture = _rooms[_room].field8; + _room = command.script[offset + 1]; + offset += 2; + break; + case 7: + _rooms[_room].picture = command.script[offset + 1]; + offset += 2; + break; + case 8: + _rooms[_room].field8 = _rooms[_room].picture = command.script[offset + 1]; + offset += 2; + break; + case 9: + printMessage(command.script[offset + 1]); + offset += 2; + break; + case 0xa: + _isDark = false; + ++offset; + break; + case 0xb: + _isDark = true; + ++offset; + break; + case 0xf: + warning("Save game not implemented"); + ++offset; + break; + case 0x10: + warning("Load game not implemented"); + ++offset; + break; + case 0x11: { + _display->printString(_strings[IDI_STR_PLAY_AGAIN]); + Common::String input = _display->inputString(); + if (input.size() == 0 || input[0] != APPLECHAR('N')) { + warning("Restart game not implemented"); + return; + } + // Fall-through + } + case 0xd: + printEngineMessage(IDI_MSG_THANKS_FOR_PLAYING); + quitGame(); + return; + case 0x12: { + byte item = command.script[offset + 1] - 1; + _inventory[item].field2 = command.script[offset + 2]; + _inventory[item].field5 = command.script[offset + 3]; + _inventory[item].field6 = command.script[offset + 4]; + offset += 5; + break; + } + case 0x13: { + byte item = command.script[offset + 2] - 1; + _inventory[item].field3 = command.script[offset + 1]; + offset += 3; + break; + } + case 0x14: + _rooms[_room].picture = _rooms[_room].field8; + ++offset; + break; + case 0x15: + case 0x16: + case 0x17: + case 0x18: + case 0x19: + case 0x1a: { + byte room = _rooms[_room].connections[command.script[offset] - 0x15]; + + if (room == 0) { + printEngineMessage(IDI_MSG_CANT_GO_THERE); + return; + } + + _rooms[_room].picture = _rooms[_room].field8; + _room = room; + return; + } + case 0x1b: + takeItem(noun); + ++offset; + break; + case 0x1c: + dropItem(noun); + ++offset; + break; + case 0x1d: + _rooms[command.script[offset + 1]].field8 = _rooms[command.script[offset + 1]].picture = command.script[offset + 2]; + offset += 3; + break; + default: + error("Invalid action opcode %02x", command.script[offset]); + } + } +} + +bool AdlEngine::checkCommand(const Command &command, byte verb, byte noun) { + if (command.room != 0xfe && command.room != _room) + return false; + + if (command.verb != 0xfe && command.verb != verb) + return false; + + if (command.noun != 0xfe && command.noun != noun) + return false; + + uint offset = 0; + for (uint i = 0; i < command.numCond; ++i) { + switch (command.script[offset]) { + case 3: + if (_inventory[command.script[offset + 1] - 1].field2 != command.script[offset + 2]) + return false; + offset += 3; + break; + case 5: + if (command.script[offset + 1] > _steps) + return false; + offset += 2; + break; + case 6: + if (_variables[command.script[offset + 1]] != command.script[offset + 2]) + return false; + offset += 3; + break; + case 9: + if (_rooms[_room].picture != command.script[offset + 1]) + return false; + offset += 2; + break; + case 10: + if (_inventory[command.script[offset + 1] - 1].field3 != command.script[offset + 2]) + return false; + offset += 3; + break; + default: + error("Invalid condition opcode %02x", command.script[offset]); + } + } + + doActions(command, noun, offset); + + return true; +} + +bool AdlEngine::doOneCommand(const Commands &commands, byte verb, byte noun) { + Commands::const_iterator it; + + for (it = commands.begin(); it != commands.end(); ++it) + if (checkCommand(*it, verb, noun)) + return true; + + return false; +} + +void AdlEngine::doAllCommands(const Commands &commands, byte verb, byte noun) { + Commands::const_iterator it; + + for (it = commands.begin(); it != commands.end(); ++it) + checkCommand(*it, verb, noun); +} + +void AdlEngine::clearScreen() { + _display->setMode(Display::kModeMixed); + _display->clear(0x00); +} + AdlEngine *AdlEngine::create(GameType type, OSystem *syst, const AdlGameDescription *gd) { switch(type) { case kGameTypeHires1: diff --git a/engines/adl/adl.h b/engines/adl/adl.h index 5252916c2f..beb915ca9f 100644 --- a/engines/adl/adl.h +++ b/engines/adl/adl.h @@ -42,16 +42,33 @@ class Parser; class Console; struct AdlGameDescription; +struct StringOffset { + int stringIdx; + uint offset; +}; + enum GameType { kGameTypeNone = 0, kGameTypeHires1 }; -enum { - STR_COMMON_ENTERCMD, - STR_COMMON_VERBERR, - STR_COMMON_NOUNERR, - STR_CUSTOM_START +// Messages used outside of scripts +enum EngineMessage { + IDI_MSG_CANT_GO_THERE, + IDI_MSG_DONT_UNDERSTAND, + IDI_MSG_ITEM_DOESNT_MOVE, + IDI_MSG_ITEM_NOT_HERE, + IDI_MSG_THANKS_FOR_PLAYING +}; + +// Strings embedded in the executable +enum EngineString { + IDI_STR_ENTER_COMMAND, + IDI_STR_VERB_ERROR, + IDI_STR_NOUN_ERROR, + IDI_STR_PLAY_AGAIN, + + IDI_STR_TOTAL }; struct Room { @@ -99,17 +116,29 @@ public: static AdlEngine *create(GameType type, OSystem *syst, const AdlGameDescription *gd); Common::Error run(); - virtual Common::String getExeString(uint id) = 0; + virtual Common::String getEngineString(int str); protected: virtual void runGame() = 0; + virtual uint getEngineMessage(EngineMessage msg) = 0; Common::String readString(Common::ReadStream &stream, byte until = 0); void printStrings(Common::SeekableReadStream &stream, int count = 1); + virtual void printMessage(uint idx, bool wait = true); + void wordWrap(Common::String &str); + void readCommands(Common::ReadStream &stream, Commands &commands); + bool checkCommand(const Command &command, byte verb, byte noun); + bool doOneCommand(const Commands &commands, byte verb, byte noun); + void doAllCommands(const Commands &commands, byte verb, byte noun); + void doActions(const Command &command, byte noun, byte offset); + void clearScreen(); + void takeItem(byte noun); + void dropItem(byte noun); Display *_display; Parser *_parser; - Common::Array _msgStrings; + Common::Array _strings; + Common::Array _messages; Common::Array _pictures; Common::Array _inventory; Common::Array _itemOffsets; @@ -123,6 +152,9 @@ protected: uint16 _steps; Common::Array _variables; bool _isDark; + +private: + void printEngineMessage(EngineMessage); }; AdlEngine *HiRes1Engine__create(OSystem *syst, const AdlGameDescription *gd); diff --git a/engines/adl/hires1.cpp b/engines/adl/hires1.cpp index 28aa13568d..7d52d2ab05 100644 --- a/engines/adl/hires1.cpp +++ b/engines/adl/hires1.cpp @@ -41,8 +41,34 @@ namespace Adl { -static uint exeStrings[STR_MH_TOTAL] = { - 23484, 23375, 23438, 27658, 0x6c31, 27729, 27772, 0x5f1e +// Messages used outside of scripts +#define IDI_HR1_MSG_CANT_GO_THERE 137 +#define IDI_HR1_MSG_DONT_UNDERSTAND 37 +#define IDI_HR1_MSG_ITEM_DOESNT_MOVE 151 +#define IDI_HR1_MSG_ITEM_NOT_HERE 152 +#define IDI_HR1_MSG_THANKS_FOR_PLAYING 140 +#define IDI_HR1_MSG_DONT_HAVE_IT 127 +#define IDI_HR1_MSG_GETTING_DARK 7 + +// Strings embedded in the executable +enum { + IDI_HR1_STR_CANT_GO_THERE = IDI_STR_TOTAL, + IDI_HR1_STR_DONT_HAVE_IT, + IDI_HR1_STR_DONT_UNDERSTAND, + IDI_HR1_STR_GETTING_DARK, + + IDI_HR1_STR_TOTAL +}; + +static const StringOffset stringOffsets[] = { + { IDI_STR_ENTER_COMMAND, 0x5bbc }, + { IDI_STR_VERB_ERROR, 0x5b4f }, + { IDI_STR_NOUN_ERROR, 0x5b8e }, + { IDI_STR_PLAY_AGAIN, 0x5f1e }, + { IDI_HR1_STR_CANT_GO_THERE, 0x6c0a }, + { IDI_HR1_STR_DONT_HAVE_IT, 0x6c31 }, + { IDI_HR1_STR_DONT_UNDERSTAND, 0x6c51 }, + { IDI_HR1_STR_GETTING_DARK, 0x6c7c } }; HiRes1Engine::HiRes1Engine(OSystem *syst, const AdlGameDescription *gd) : @@ -225,324 +251,6 @@ void HiRes1Engine::showRoom() { printMessage(_rooms[_room].description, false); } -Common::String HiRes1Engine::getExeString(uint idx) { - return _exeStrings[idx]; -} - -void HiRes1Engine::wordWrap(Common::String &str) { - uint end = 39; - - while (1) { - if (str.size() <= end) - return; - - while (str[end] != APPLECHAR(' ')) - --end; - - str.setChar(APPLECHAR('\r'), end); - end += 40; - } -} - -void HiRes1Engine::printMessage(uint idx, bool wait) { - // Hardcoded overrides that don't wait after printing - // Note: strings may differ slightly from the ones in MESSAGES - switch (idx) { - case 137: - _display->printString(_exeStrings[STR_MH_DIRERR]); - return; - case 127: - _display->printString(_exeStrings[STR_MH_DONTHAVEIT]); - return; - case 37: - _display->printString(_exeStrings[STR_MH_DONTUNDERSTAND]); - return; - case 7: - _display->printString(_exeStrings[STR_MH_GETTINGDARK]); - return; - } - - Common::String msg = _msgStrings[idx - 1]; - wordWrap(msg); - _display->printString(msg); - - if (wait) - _display->delay(14 * 166018 / 1000); -} - -void HiRes1Engine::readCommands(Common::ReadStream &stream, Commands &commands) { - while (1) { - Command command; - command.room = stream.readByte(); - - if (command.room == 0xff) - return; - - command.verb = stream.readByte(); - command.noun = stream.readByte(); - - byte scriptSize = stream.readByte() - 6; - - command.numCond = stream.readByte(); - command.numAct = stream.readByte(); - - for (uint i = 0; i < scriptSize; ++i) - command.script.push_back(stream.readByte()); - - if (stream.eos() || stream.err()) - error("Failed to read commands"); - - commands.push_back(command); - } -} - -void HiRes1Engine::takeItem(byte noun) { - Common::Array::iterator it; - - for (it = _inventory.begin(); it != _inventory.end(); ++it) { - if (it->field1 != noun || it->field2 != _room) - continue; - - if (it->field7 == 2) { - // It doesn't move - printMessage(151); - return; - } - - if (it->field7 == 1) { - it->field2 = 0xfe; - it->field7 = 1; - return; - } - - Common::Array::const_iterator it2; - for (it2 = it->field10.begin(); it->field10.end(); ++it2) { - if (*it2 == _rooms[_room].picture) { - it->field2 = 0xfe; - it->field7 = 1; - return; - } - } - } - - // Item not here - printMessage(152); -} - -void HiRes1Engine::dropItem(byte noun) { - Common::Array::iterator it; - - for (it = _inventory.begin(); it != _inventory.end(); ++it) { - if (it->field1 != noun || it->field2 != 0xfe) - continue; - - it->field2 = _room; - it->field7 = 1; - return; - } - - // Don't understand - printMessage(37); -} - -void HiRes1Engine::doActions(const Command &command, byte noun, byte offset) { - for (uint i = 0; i < command.numAct; ++i) { - switch (command.script[offset]) { - case 1: - _variables[command.script[offset + 2]] += command.script[offset + 1]; - offset += 3; - break; - case 2: - _variables[command.script[offset + 2]] -= command.script[offset + 1]; - offset += 3; - break; - case 3: - _variables[command.script[offset + 1]] = command.script[offset + 2]; - offset += 3; - break; - case 4: { - Common::Array::const_iterator it; - - for (it = _inventory.begin(); it != _inventory.end(); ++it) - if (it->field2 == 0xfe) - printMessage(it->field8); - - ++offset; - break; - } - case 5: - _inventory[command.script[offset + 1] - 1].field2 = command.script[offset + 2]; - offset += 3; - break; - case 6: - _rooms[_room].picture = _rooms[_room].field8; - _room = command.script[offset + 1]; - offset += 2; - break; - case 7: - _rooms[_room].picture = command.script[offset + 1]; - offset += 2; - break; - case 8: - _rooms[_room].field8 = _rooms[_room].picture = command.script[offset + 1]; - offset += 2; - break; - case 9: - printMessage(command.script[offset + 1]); - offset += 2; - break; - case 0xa: - _isDark = false; - ++offset; - break; - case 0xb: - _isDark = true; - ++offset; - break; - case 0xf: - warning("Save game not implemented"); - ++offset; - break; - case 0x10: - warning("Load game not implemented"); - ++offset; - break; - case 0x11: { - _display->printString(_exeStrings[STR_MH_PLAYAGAIN]); - Common::String input = _display->inputString(); - if (input.size() == 0 || input[0] != APPLECHAR('N')) { - warning("Restart game not implemented"); - return; - } - // Fall-through - } - case 0xd: - printMessage(140); - quitGame(); - return; - case 0x12: { - byte item = command.script[offset + 1] - 1; - _inventory[item].field2 = command.script[offset + 2]; - _inventory[item].field5 = command.script[offset + 3]; - _inventory[item].field6 = command.script[offset + 4]; - offset += 5; - break; - } - case 0x13: { - byte item = command.script[offset + 2] - 1; - _inventory[item].field3 = command.script[offset + 1]; - offset += 3; - break; - } - case 0x14: - _rooms[_room].picture = _rooms[_room].field8; - ++offset; - break; - case 0x15: - case 0x16: - case 0x17: - case 0x18: - case 0x19: - case 0x1a: { - byte room = _rooms[_room].connections[command.script[offset] - 0x15]; - - if (room == 0) { - printMessage(137); - return; - } - - _rooms[_room].picture = _rooms[_room].field8; - _room = room; - return; - } - case 0x1b: - takeItem(noun); - ++offset; - break; - case 0x1c: - dropItem(noun); - ++offset; - break; - case 0x1d: - _rooms[command.script[offset + 1]].field8 = _rooms[command.script[offset + 1]].picture = command.script[offset + 2]; - offset += 3; - break; - default: - error("Invalid action opcode %02x", command.script[offset]); - } - } -} - -bool HiRes1Engine::checkCommand(const Command &command, byte verb, byte noun) { - if (command.room != 0xfe && command.room != _room) - return false; - - if (command.verb != 0xfe && command.verb != verb) - return false; - - if (command.noun != 0xfe && command.noun != noun) - return false; - - uint offset = 0; - for (uint i = 0; i < command.numCond; ++i) { - switch (command.script[offset]) { - case 3: - if (_inventory[command.script[offset + 1] - 1].field2 != command.script[offset + 2]) - return false; - offset += 3; - break; - case 5: - if (command.script[offset + 1] > _steps) - return false; - offset += 2; - break; - case 6: - if (_variables[command.script[offset + 1]] != command.script[offset + 2]) - return false; - offset += 3; - break; - case 9: - if (_rooms[_room].picture != command.script[offset + 1]) - return false; - offset += 2; - break; - case 10: - if (_inventory[command.script[offset + 1] - 1].field3 != command.script[offset + 2]) - return false; - offset += 3; - break; - default: - error("Invalid condition opcode %02x", command.script[offset]); - } - } - - doActions(command, noun, offset); - - return true; -} - -bool HiRes1Engine::doOneCommand(const Commands &commands, byte verb, byte noun) { - Commands::const_iterator it; - - for (it = commands.begin(); it != commands.end(); ++it) - if (checkCommand(*it, verb, noun)) - return true; - - return false; -} - -void HiRes1Engine::doAllCommands(const Commands &commands, byte verb, byte noun) { - Commands::const_iterator it; - - for (it = commands.begin(); it != commands.end(); ++it) - checkCommand(*it, verb, noun); -} - -void HiRes1Engine::clearScreen() { - _display->setMode(Display::kModeMixed); - _display->clear(0x00); -} - void HiRes1Engine::runGame() { runIntro(); _display->printASCIIString("\r"); @@ -553,7 +261,7 @@ void HiRes1Engine::runGame() { error("Failed to open file"); while (!f.eos() && !f.err()) - _msgStrings.push_back(readString(f, APPLECHAR('\r')) + APPLECHAR('\r')); + _messages.push_back(readString(f, APPLECHAR('\r')) + APPLECHAR('\r')); f.close(); @@ -561,9 +269,10 @@ void HiRes1Engine::runGame() { error("Failed to open file"); // Load strings from executable - for (uint idx = 0; idx < STR_MH_TOTAL; ++idx) { - f.seek(exeStrings[idx]); - _exeStrings.push_back(readString(f)); + _strings.resize(IDI_HR1_STR_TOTAL); + for (uint idx = 0; idx < IDI_HR1_STR_TOTAL; ++idx) { + f.seek(stringOffsets[idx].offset); + _strings[stringOffsets[idx].stringIdx] = readString(f); } // Load room data from executable @@ -673,6 +382,44 @@ void HiRes1Engine::runGame() { } } +void HiRes1Engine::printMessage(uint idx, bool wait) { + // Hardcoded overrides that don't wait after printing + // Note: strings may differ slightly from the ones in MESSAGES + switch (idx) { + case 137: + _display->printString(_strings[IDI_HR1_STR_CANT_GO_THERE]); + return; + case 127: + _display->printString(_strings[IDI_HR1_STR_DONT_HAVE_IT]); + return; + case 37: + _display->printString(_strings[IDI_HR1_STR_DONT_UNDERSTAND]); + return; + case 7: + _display->printString(_strings[IDI_HR1_STR_GETTING_DARK]); + return; + } + + AdlEngine::printMessage(idx, wait); +} + +uint HiRes1Engine::getEngineMessage(EngineMessage msg) { + switch (msg) { + case IDI_MSG_CANT_GO_THERE: + return IDI_HR1_MSG_CANT_GO_THERE; + case IDI_MSG_DONT_UNDERSTAND: + return IDI_HR1_MSG_DONT_UNDERSTAND; + case IDI_MSG_ITEM_DOESNT_MOVE: + return IDI_HR1_MSG_ITEM_DOESNT_MOVE; + case IDI_MSG_ITEM_NOT_HERE: + return IDI_HR1_MSG_ITEM_NOT_HERE; + case IDI_MSG_THANKS_FOR_PLAYING: + return IDI_HR1_MSG_THANKS_FOR_PLAYING; + default: + error("Cannot find engine message %i", msg); + } +} + AdlEngine *HiRes1Engine__create(OSystem *syst, const AdlGameDescription *gd) { return new HiRes1Engine(syst, gd); } diff --git a/engines/adl/hires1.h b/engines/adl/hires1.h index e9e274cc58..19aa55ee9f 100644 --- a/engines/adl/hires1.h +++ b/engines/adl/hires1.h @@ -32,20 +32,12 @@ class ReadStream; namespace Adl { enum { - // Some of these are probably common - STR_MH_DIRERR = STR_CUSTOM_START, - STR_MH_DONTHAVEIT, - STR_MH_DONTUNDERSTAND, - STR_MH_GETTINGDARK, - STR_MH_PLAYAGAIN, - - STR_MH_TOTAL + IDI_HR1_MSG_ }; class HiRes1Engine : public AdlEngine { public: HiRes1Engine(OSystem *syst, const AdlGameDescription *gd); - Common::String getExeString(uint idx); protected: void runGame(); @@ -57,23 +49,14 @@ private: MH_ITEM_OFFSETS = 21 }; + void printMessage(uint idx, bool wait = true); + uint getEngineMessage(EngineMessage msg); + void runIntro(); void drawPic(Common::ReadStream &stream, byte xOffset, byte yOffset); void showRoom(); - void printMessage(uint idx, bool wait = true); - void wordWrap(Common::String &str); - void readCommands(Common::ReadStream &stream, Commands &commands); - bool checkCommand(const Command &command, byte verb, byte noun); - bool doOneCommand(const Commands &commands, byte verb, byte noun); - void doAllCommands(const Commands &commands, byte verb, byte noun); - void doActions(const Command &command, byte noun, byte offset); - void clearScreen(); - void takeItem(byte noun); - void dropItem(byte noun); void drawItems(); void drawPic(byte pic, byte xOffset, byte yOffset); - - Common::Array _exeStrings; }; } // End of namespace Adl diff --git a/engines/adl/parser.cpp b/engines/adl/parser.cpp index 1611fc7f54..a697301664 100644 --- a/engines/adl/parser.cpp +++ b/engines/adl/parser.cpp @@ -129,7 +129,7 @@ Common::String Parser::getWord(const Common::String &line, uint &index) { void Parser::getInput(uint &verb, uint &noun) { while (1) { - _display.printString(_engine.getExeString(STR_COMMON_ENTERCMD)); + _display.printString(_engine.getEngineString(IDI_STR_ENTER_COMMAND)); Common::String line = getLine(); if (g_engine->shouldQuit()) @@ -139,7 +139,7 @@ void Parser::getInput(uint &verb, uint &noun) { Common::String verbStr = getWord(line, index); if (!_verbs.contains(verbStr)) { - Common::String err = _engine.getExeString(STR_COMMON_VERBERR); + Common::String err = _engine.getEngineString(IDI_STR_VERB_ERROR); for (uint i = 0; i < verbStr.size(); ++i) err.setChar(verbStr[i], i + 19); _display.printString(err); @@ -151,7 +151,7 @@ void Parser::getInput(uint &verb, uint &noun) { Common::String nounStr = getWord(line, index); if (!_nouns.contains(nounStr)) { - Common::String err = _engine.getExeString(STR_COMMON_NOUNERR); + Common::String err = _engine.getEngineString(IDI_STR_NOUN_ERROR); for (uint i = 0; i < verbStr.size(); ++i) err.setChar(verbStr[i], i + 19); for (uint i = 0; i < nounStr.size(); ++i) -- cgit v1.2.3 From ce97d0a26e51ff1253ae3268f09673f0aa31f4a7 Mon Sep 17 00:00:00 2001 From: Walter van Niftrik Date: Sun, 28 Feb 2016 13:43:28 +0100 Subject: ADL: Use #defines instead of literals --- engines/adl/hires1.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'engines') diff --git a/engines/adl/hires1.cpp b/engines/adl/hires1.cpp index 7d52d2ab05..65aa66532e 100644 --- a/engines/adl/hires1.cpp +++ b/engines/adl/hires1.cpp @@ -386,16 +386,16 @@ void HiRes1Engine::printMessage(uint idx, bool wait) { // Hardcoded overrides that don't wait after printing // Note: strings may differ slightly from the ones in MESSAGES switch (idx) { - case 137: + case IDI_HR1_MSG_CANT_GO_THERE: _display->printString(_strings[IDI_HR1_STR_CANT_GO_THERE]); return; - case 127: + case IDI_HR1_MSG_DONT_HAVE_IT: _display->printString(_strings[IDI_HR1_STR_DONT_HAVE_IT]); return; - case 37: + case IDI_MSG_DONT_UNDERSTAND: _display->printString(_strings[IDI_HR1_STR_DONT_UNDERSTAND]); return; - case 7: + case IDI_HR1_MSG_GETTING_DARK: _display->printString(_strings[IDI_HR1_STR_GETTING_DARK]); return; } -- cgit v1.2.3 From f9c9f2ac9de984aed7fb2438899aff33104ab3b8 Mon Sep 17 00:00:00 2001 From: Walter van Niftrik Date: Sun, 28 Feb 2016 14:24:04 +0100 Subject: ADL: Rename Item struct fields --- engines/adl/adl.cpp | 45 ++++++++++++++++++++++----------------------- engines/adl/adl.h | 25 ++++++++++++++++--------- engines/adl/hires1.cpp | 36 ++++++++++++++++++------------------ 3 files changed, 56 insertions(+), 50 deletions(-) (limited to 'engines') diff --git a/engines/adl/adl.cpp b/engines/adl/adl.cpp index 2c11290919..3ce6d709f8 100644 --- a/engines/adl/adl.cpp +++ b/engines/adl/adl.cpp @@ -165,25 +165,24 @@ void AdlEngine::takeItem(byte noun) { Common::Array::iterator it; for (it = _inventory.begin(); it != _inventory.end(); ++it) { - if (it->field1 != noun || it->field2 != _room) + if (it->noun != noun || it->room != _room) continue; - if (it->field7 == 2) { + if (it->state == IDI_ITEM_DOESNT_MOVE) { printEngineMessage(IDI_MSG_ITEM_DOESNT_MOVE); return; } - if (it->field7 == 1) { - it->field2 = 0xfe; - it->field7 = 1; + if (it->state == IDI_ITEM_MOVED) { + it->room = IDI_NONE; return; } Common::Array::const_iterator it2; - for (it2 = it->field10.begin(); it->field10.end(); ++it2) { + for (it2 = it->roomPictures.begin(); it->roomPictures.end(); ++it2) { if (*it2 == _rooms[_room].picture) { - it->field2 = 0xfe; - it->field7 = 1; + it->room = IDI_NONE; + it->state = IDI_ITEM_MOVED; return; } } @@ -196,11 +195,11 @@ void AdlEngine::dropItem(byte noun) { Common::Array::iterator it; for (it = _inventory.begin(); it != _inventory.end(); ++it) { - if (it->field1 != noun || it->field2 != 0xfe) + if (it->noun != noun || it->room != IDI_NONE) continue; - it->field2 = _room; - it->field7 = 1; + it->room = _room; + it->state = IDI_ITEM_MOVED; return; } @@ -227,14 +226,14 @@ void AdlEngine::doActions(const Command &command, byte noun, byte offset) { Common::Array::const_iterator it; for (it = _inventory.begin(); it != _inventory.end(); ++it) - if (it->field2 == 0xfe) - printMessage(it->field8); + if (it->room == IDI_NONE) + printMessage(it->description); ++offset; break; } case 5: - _inventory[command.script[offset + 1] - 1].field2 = command.script[offset + 2]; + _inventory[command.script[offset + 1] - 1].room = command.script[offset + 2]; offset += 3; break; case 6: @@ -285,15 +284,15 @@ void AdlEngine::doActions(const Command &command, byte noun, byte offset) { return; case 0x12: { byte item = command.script[offset + 1] - 1; - _inventory[item].field2 = command.script[offset + 2]; - _inventory[item].field5 = command.script[offset + 3]; - _inventory[item].field6 = command.script[offset + 4]; + _inventory[item].room = command.script[offset + 2]; + _inventory[item].position.x = command.script[offset + 3]; + _inventory[item].position.y = command.script[offset + 4]; offset += 5; break; } case 0x13: { byte item = command.script[offset + 2] - 1; - _inventory[item].field3 = command.script[offset + 1]; + _inventory[item].picture = command.script[offset + 1]; offset += 3; break; } @@ -337,20 +336,20 @@ void AdlEngine::doActions(const Command &command, byte noun, byte offset) { } bool AdlEngine::checkCommand(const Command &command, byte verb, byte noun) { - if (command.room != 0xfe && command.room != _room) + if (command.room != IDI_NONE && command.room != _room) return false; - if (command.verb != 0xfe && command.verb != verb) + if (command.verb != IDI_NONE && command.verb != verb) return false; - if (command.noun != 0xfe && command.noun != noun) + if (command.noun != IDI_NONE && command.noun != noun) return false; uint offset = 0; for (uint i = 0; i < command.numCond; ++i) { switch (command.script[offset]) { case 3: - if (_inventory[command.script[offset + 1] - 1].field2 != command.script[offset + 2]) + if (_inventory[command.script[offset + 1] - 1].room != command.script[offset + 2]) return false; offset += 3; break; @@ -370,7 +369,7 @@ bool AdlEngine::checkCommand(const Command &command, byte verb, byte noun) { offset += 2; break; case 10: - if (_inventory[command.script[offset + 1] - 1].field3 != command.script[offset + 2]) + if (_inventory[command.script[offset + 1] - 1].picture != command.script[offset + 2]) return false; offset += 3; break; diff --git a/engines/adl/adl.h b/engines/adl/adl.h index beb915ca9f..987a962b4f 100644 --- a/engines/adl/adl.h +++ b/engines/adl/adl.h @@ -90,16 +90,23 @@ struct Command { Common::Array script; }; +enum { + IDI_ITEM_NOT_MOVED, + IDI_ITEM_MOVED, + IDI_ITEM_DOESNT_MOVE +}; + +#define IDI_NONE 0xfe + struct Item { - byte field1; - byte field2; - byte field3; - byte field4; - byte field5; - byte field6; - byte field7; - byte field8; - Common::Array field10; + byte noun; + byte room; + byte picture; + bool isDrawing; + Common::Point position; + int state; + byte description; + Common::Array roomPictures; }; typedef Common::List Commands; diff --git a/engines/adl/hires1.cpp b/engines/adl/hires1.cpp index 65aa66532e..a078340f2f 100644 --- a/engines/adl/hires1.cpp +++ b/engines/adl/hires1.cpp @@ -212,16 +212,16 @@ void HiRes1Engine::drawItems() { uint dropped = 0; for (it = _inventory.begin(); it != _inventory.end(); ++it) { - if (it->field2 != _room) + if (it->room != _room) continue; - if (it->field7 == 1) { + if (it->state == IDI_ITEM_MOVED) { if (_rooms[_room].field8 == _rooms[_room].picture) { const Common::Point &p = _itemOffsets[dropped]; - if (it->field4) - _display->drawRightAngles(_drawings[it->field3 - 1], Common::Point(p.x, p.y), 0, 1, 0x7f); + if (it->isDrawing) + _display->drawRightAngles(_drawings[it->picture - 1], Common::Point(p.x, p.y), 0, 1, 0x7f); else - drawPic(it->field3, p.x, p.y); + drawPic(it->picture, p.x, p.y); ++dropped; } continue; @@ -229,12 +229,12 @@ void HiRes1Engine::drawItems() { Common::Array::const_iterator it2; - for (it2 = it->field10.begin(); it2 != it->field10.end(); ++it2) { + for (it2 = it->roomPictures.begin(); it2 != it->roomPictures.end(); ++it2) { if (*it2 == _rooms[_room].picture) { - if (it->field4) - _display->drawRightAngles(_drawings[it->field3 - 1], Common::Point(it->field5, it->field6), 0, 1, 0x7f); + if (it->isDrawing) + _display->drawRightAngles(_drawings[it->picture - 1], it->position, 0, 1, 0x7f); else - drawPic(it->field3, it->field5, it->field6); + drawPic(it->picture, it->position.x, it->position.y); continue; } } @@ -292,21 +292,21 @@ void HiRes1Engine::runGame() { f.seek(0x100); while (f.readByte() != 0xff) { struct Item item; - item.field1 = f.readByte(); - item.field2 = f.readByte(); - item.field3 = f.readByte(); - item.field4 = f.readByte(); - item.field5 = f.readByte(); - item.field6 = f.readByte(); - item.field7 = f.readByte(); - item.field8 = f.readByte(); + item.noun = f.readByte(); + item.room = f.readByte(); + item.picture = f.readByte(); + item.isDrawing = f.readByte(); + item.position.x = f.readByte(); + item.position.y = f.readByte(); + item.state = f.readByte(); + item.description = f.readByte(); f.readByte(); byte size = f.readByte(); for (uint i = 0; i < size; ++i) - item.field10.push_back(f.readByte()); + item.roomPictures.push_back(f.readByte()); _inventory.push_back(item); } -- cgit v1.2.3 From 8f9d4b96530a8b30ec2208aa217d6b339e4e94b7 Mon Sep 17 00:00:00 2001 From: Walter van Niftrik Date: Sun, 28 Feb 2016 14:48:36 +0100 Subject: ADL: Use #defines instead of literals --- engines/adl/adl.h | 10 +++++----- engines/adl/hires1.cpp | 25 ++++++++++++++++++------- 2 files changed, 23 insertions(+), 12 deletions(-) (limited to 'engines') diff --git a/engines/adl/adl.h b/engines/adl/adl.h index 987a962b4f..4c8180eeab 100644 --- a/engines/adl/adl.h +++ b/engines/adl/adl.h @@ -42,16 +42,16 @@ class Parser; class Console; struct AdlGameDescription; -struct StringOffset { - int stringIdx; - uint offset; -}; - enum GameType { kGameTypeNone = 0, kGameTypeHires1 }; +struct StringOffset { + int stringIdx; + uint offset; +}; + // Messages used outside of scripts enum EngineMessage { IDI_MSG_CANT_GO_THERE, diff --git a/engines/adl/hires1.cpp b/engines/adl/hires1.cpp index a078340f2f..a5dbb894e2 100644 --- a/engines/adl/hires1.cpp +++ b/engines/adl/hires1.cpp @@ -60,6 +60,7 @@ enum { IDI_HR1_STR_TOTAL }; +// Offsets for strings inside executable static const StringOffset stringOffsets[] = { { IDI_STR_ENTER_COMMAND, 0x5bbc }, { IDI_STR_VERB_ERROR, 0x5b4f }, @@ -71,6 +72,16 @@ static const StringOffset stringOffsets[] = { { IDI_HR1_STR_GETTING_DARK, 0x6c7c } }; +#define IDI_HR1_OFS_PD_TEXT_0 0x5d +#define IDI_HR1_OFS_PD_TEXT_1 0x12b +#define IDI_HR1_OFS_PD_TEXT_2 0x16d +#define IDI_HR1_OFS_PD_TEXT_3 0x259 + +#define IDI_HR1_OFS_INTRO_TEXT 0x66 +#define IDI_HR1_OFS_GAME_OR_HELP 0xf + +#define IDI_HR1_OFS_LOGO_0 0x1003 + HiRes1Engine::HiRes1Engine(OSystem *syst, const AdlGameDescription *gd) : AdlEngine(syst, gd) { _variables.resize(20); @@ -82,7 +93,7 @@ void HiRes1Engine::runIntro() { if (!file.open("AUTO LOAD OBJ")) error("Failed to open file"); - file.seek(0x1003); + file.seek(IDI_HR1_OFS_LOGO_0); _display->setMode(Display::kModeHires); _display->loadFrameBuffer(file); _display->decodeFrameBuffer(); @@ -99,19 +110,19 @@ void HiRes1Engine::runIntro() { Common::String str; - basic.seek(93); + basic.seek(IDI_HR1_OFS_PD_TEXT_0); str = readString(basic, '"'); _display->printASCIIString(str + '\r'); - basic.seek(299); + basic.seek(IDI_HR1_OFS_PD_TEXT_1); str = readString(basic, '"'); _display->printASCIIString(str + "\r\r"); - basic.seek(365); + basic.seek(IDI_HR1_OFS_PD_TEXT_2); str = readString(basic, '"'); _display->printASCIIString(str + "\r\r"); - basic.seek(601); + basic.seek(IDI_HR1_OFS_PD_TEXT_3); str = readString(basic, '"'); _display->printASCIIString(str + '\r'); @@ -121,7 +132,7 @@ void HiRes1Engine::runIntro() { _display->setMode(Display::kModeMixed); - file.seek(15); + file.seek(IDI_HR1_OFS_GAME_OR_HELP); str = readString(file); while (1) { @@ -141,7 +152,7 @@ void HiRes1Engine::runIntro() { }; _display->setMode(Display::kModeText); - file.seek(102); + file.seek(IDI_HR1_OFS_INTRO_TEXT); const int pages[] = { 6, 6, 4, 5, 8, 7, 0 }; -- cgit v1.2.3 From 2104a5095d9d338a05cdf1e3a8e8b7f680b15f46 Mon Sep 17 00:00:00 2001 From: Walter van Niftrik Date: Sun, 28 Feb 2016 15:18:00 +0100 Subject: ADL: Rename Room struct fields --- engines/adl/adl.cpp | 16 ++++++++-------- engines/adl/adl.h | 2 +- engines/adl/hires1.cpp | 20 ++++++++++---------- 3 files changed, 19 insertions(+), 19 deletions(-) (limited to 'engines') diff --git a/engines/adl/adl.cpp b/engines/adl/adl.cpp index 3ce6d709f8..6109004f8a 100644 --- a/engines/adl/adl.cpp +++ b/engines/adl/adl.cpp @@ -180,7 +180,7 @@ void AdlEngine::takeItem(byte noun) { Common::Array::const_iterator it2; for (it2 = it->roomPictures.begin(); it->roomPictures.end(); ++it2) { - if (*it2 == _rooms[_room].picture) { + if (*it2 == _rooms[_room].curPicture) { it->room = IDI_NONE; it->state = IDI_ITEM_MOVED; return; @@ -237,16 +237,16 @@ void AdlEngine::doActions(const Command &command, byte noun, byte offset) { offset += 3; break; case 6: - _rooms[_room].picture = _rooms[_room].field8; + _rooms[_room].curPicture = _rooms[_room].picture; _room = command.script[offset + 1]; offset += 2; break; case 7: - _rooms[_room].picture = command.script[offset + 1]; + _rooms[_room].curPicture = command.script[offset + 1]; offset += 2; break; case 8: - _rooms[_room].field8 = _rooms[_room].picture = command.script[offset + 1]; + _rooms[_room].picture = _rooms[_room].curPicture = command.script[offset + 1]; offset += 2; break; case 9: @@ -297,7 +297,7 @@ void AdlEngine::doActions(const Command &command, byte noun, byte offset) { break; } case 0x14: - _rooms[_room].picture = _rooms[_room].field8; + _rooms[_room].curPicture = _rooms[_room].picture; ++offset; break; case 0x15: @@ -313,7 +313,7 @@ void AdlEngine::doActions(const Command &command, byte noun, byte offset) { return; } - _rooms[_room].picture = _rooms[_room].field8; + _rooms[_room].curPicture = _rooms[_room].picture; _room = room; return; } @@ -326,7 +326,7 @@ void AdlEngine::doActions(const Command &command, byte noun, byte offset) { ++offset; break; case 0x1d: - _rooms[command.script[offset + 1]].field8 = _rooms[command.script[offset + 1]].picture = command.script[offset + 2]; + _rooms[command.script[offset + 1]].picture = _rooms[command.script[offset + 1]].curPicture = command.script[offset + 2]; offset += 3; break; default: @@ -364,7 +364,7 @@ bool AdlEngine::checkCommand(const Command &command, byte verb, byte noun) { offset += 3; break; case 9: - if (_rooms[_room].picture != command.script[offset + 1]) + if (_rooms[_room].curPicture != command.script[offset + 1]) return false; offset += 2; break; diff --git a/engines/adl/adl.h b/engines/adl/adl.h index 4c8180eeab..fffe61eadf 100644 --- a/engines/adl/adl.h +++ b/engines/adl/adl.h @@ -74,8 +74,8 @@ enum EngineString { struct Room { byte description; byte connections[6]; - byte field8; byte picture; + byte curPicture; }; struct Picture { diff --git a/engines/adl/hires1.cpp b/engines/adl/hires1.cpp index a5dbb894e2..730f229198 100644 --- a/engines/adl/hires1.cpp +++ b/engines/adl/hires1.cpp @@ -42,13 +42,13 @@ namespace Adl { // Messages used outside of scripts -#define IDI_HR1_MSG_CANT_GO_THERE 137 -#define IDI_HR1_MSG_DONT_UNDERSTAND 37 -#define IDI_HR1_MSG_ITEM_DOESNT_MOVE 151 -#define IDI_HR1_MSG_ITEM_NOT_HERE 152 +#define IDI_HR1_MSG_CANT_GO_THERE 137 +#define IDI_HR1_MSG_DONT_UNDERSTAND 37 +#define IDI_HR1_MSG_ITEM_DOESNT_MOVE 151 +#define IDI_HR1_MSG_ITEM_NOT_HERE 152 #define IDI_HR1_MSG_THANKS_FOR_PLAYING 140 -#define IDI_HR1_MSG_DONT_HAVE_IT 127 -#define IDI_HR1_MSG_GETTING_DARK 7 +#define IDI_HR1_MSG_DONT_HAVE_IT 127 +#define IDI_HR1_MSG_GETTING_DARK 7 // Strings embedded in the executable enum { @@ -227,7 +227,7 @@ void HiRes1Engine::drawItems() { continue; if (it->state == IDI_ITEM_MOVED) { - if (_rooms[_room].field8 == _rooms[_room].picture) { + if (_rooms[_room].picture == _rooms[_room].curPicture) { const Common::Point &p = _itemOffsets[dropped]; if (it->isDrawing) _display->drawRightAngles(_drawings[it->picture - 1], Common::Point(p.x, p.y), 0, 1, 0x7f); @@ -241,7 +241,7 @@ void HiRes1Engine::drawItems() { Common::Array::const_iterator it2; for (it2 = it->roomPictures.begin(); it2 != it->roomPictures.end(); ++it2) { - if (*it2 == _rooms[_room].picture) { + if (*it2 == _rooms[_room].curPicture) { if (it->isDrawing) _display->drawRightAngles(_drawings[it->picture - 1], it->position, 0, 1, 0x7f); else @@ -254,7 +254,7 @@ void HiRes1Engine::drawItems() { void HiRes1Engine::showRoom() { if (!_isDark) { - drawPic(_rooms[_room].picture, 0, 0); + drawPic(_rooms[_room].curPicture, 0, 0); drawItems(); } @@ -294,8 +294,8 @@ void HiRes1Engine::runGame() { room.description = f.readByte(); for (uint j = 0; j < 6; ++j) room.connections[j] = f.readByte(); - room.field8 = f.readByte(); room.picture = f.readByte(); + room.curPicture = f.readByte(); _rooms.push_back(room); } -- cgit v1.2.3 From 00d87cca9007ef69314b00eec5bffd6b9a9f2e72 Mon Sep 17 00:00:00 2001 From: Walter van Niftrik Date: Sun, 28 Feb 2016 15:56:17 +0100 Subject: ADL: Add more #defines for literals --- engines/adl/adl.cpp | 64 ++++++++++++++++++++++++++--------------------------- engines/adl/adl.h | 36 ++++++++++++++++++++++++++++++ 2 files changed, 68 insertions(+), 32 deletions(-) (limited to 'engines') diff --git a/engines/adl/adl.cpp b/engines/adl/adl.cpp index 6109004f8a..af71bba5c9 100644 --- a/engines/adl/adl.cpp +++ b/engines/adl/adl.cpp @@ -210,19 +210,19 @@ void AdlEngine::dropItem(byte noun) { void AdlEngine::doActions(const Command &command, byte noun, byte offset) { for (uint i = 0; i < command.numAct; ++i) { switch (command.script[offset]) { - case 1: + case IDO_ACT_VAR_ADD: _variables[command.script[offset + 2]] += command.script[offset + 1]; offset += 3; break; - case 2: + case IDO_ACT_VAR_SUB: _variables[command.script[offset + 2]] -= command.script[offset + 1]; offset += 3; break; - case 3: + case IDO_ACT_VAR_SET: _variables[command.script[offset + 1]] = command.script[offset + 2]; offset += 3; break; - case 4: { + case IDO_ACT_LIST_ITEMS: { Common::Array::const_iterator it; for (it = _inventory.begin(); it != _inventory.end(); ++it) @@ -232,44 +232,44 @@ void AdlEngine::doActions(const Command &command, byte noun, byte offset) { ++offset; break; } - case 5: + case IDO_ACT_MOVE_ITEM: _inventory[command.script[offset + 1] - 1].room = command.script[offset + 2]; offset += 3; break; - case 6: + case IDO_ACT_SET_ROOM: _rooms[_room].curPicture = _rooms[_room].picture; _room = command.script[offset + 1]; offset += 2; break; - case 7: + case IDO_ACT_SET_CUR_PIC: _rooms[_room].curPicture = command.script[offset + 1]; offset += 2; break; - case 8: + case IDO_ACT_SET_PIC: _rooms[_room].picture = _rooms[_room].curPicture = command.script[offset + 1]; offset += 2; break; - case 9: + case IDO_ACT_PRINT_MSG: printMessage(command.script[offset + 1]); offset += 2; break; - case 0xa: + case IDO_ACT_SET_LIGHT: _isDark = false; ++offset; break; - case 0xb: + case IDO_ACT_SET_DARK: _isDark = true; ++offset; break; - case 0xf: + case IDO_ACT_SAVE: warning("Save game not implemented"); ++offset; break; - case 0x10: + case IDO_ACT_LOAD: warning("Load game not implemented"); ++offset; break; - case 0x11: { + case IDO_ACT_RESTART: { _display->printString(_strings[IDI_STR_PLAY_AGAIN]); Common::String input = _display->inputString(); if (input.size() == 0 || input[0] != APPLECHAR('N')) { @@ -278,11 +278,11 @@ void AdlEngine::doActions(const Command &command, byte noun, byte offset) { } // Fall-through } - case 0xd: + case IDO_ACT_QUIT: printEngineMessage(IDI_MSG_THANKS_FOR_PLAYING); quitGame(); return; - case 0x12: { + case IDO_ACT_SET_ITEM_POS: { byte item = command.script[offset + 1] - 1; _inventory[item].room = command.script[offset + 2]; _inventory[item].position.x = command.script[offset + 3]; @@ -290,22 +290,22 @@ void AdlEngine::doActions(const Command &command, byte noun, byte offset) { offset += 5; break; } - case 0x13: { + case IDO_ACT_SET_ITEM_PIC: { byte item = command.script[offset + 2] - 1; _inventory[item].picture = command.script[offset + 1]; offset += 3; break; } - case 0x14: + case IDO_ACT_RESET_PIC: _rooms[_room].curPicture = _rooms[_room].picture; ++offset; break; - case 0x15: - case 0x16: - case 0x17: - case 0x18: - case 0x19: - case 0x1a: { + case IDO_ACT_GO_NORTH: + case IDO_ACT_GO_SOUTH: + case IDO_ACT_GO_EAST: + case IDO_ACT_GO_WEST: + case IDO_ACT_GO_UP: + case IDO_ACT_GO_DOWN: { byte room = _rooms[_room].connections[command.script[offset] - 0x15]; if (room == 0) { @@ -317,15 +317,15 @@ void AdlEngine::doActions(const Command &command, byte noun, byte offset) { _room = room; return; } - case 0x1b: + case IDO_ACT_TAKE_ITEM: takeItem(noun); ++offset; break; - case 0x1c: + case IDO_ACT_DROP_ITEM: dropItem(noun); ++offset; break; - case 0x1d: + case IDO_ACT_SET_ROOM_PIC: _rooms[command.script[offset + 1]].picture = _rooms[command.script[offset + 1]].curPicture = command.script[offset + 2]; offset += 3; break; @@ -348,27 +348,27 @@ bool AdlEngine::checkCommand(const Command &command, byte verb, byte noun) { uint offset = 0; for (uint i = 0; i < command.numCond; ++i) { switch (command.script[offset]) { - case 3: + case IDO_CND_ITEM_IN_ROOM: if (_inventory[command.script[offset + 1] - 1].room != command.script[offset + 2]) return false; offset += 3; break; - case 5: + case IDO_CND_STEPS_GE: if (command.script[offset + 1] > _steps) return false; offset += 2; break; - case 6: + case IDO_CND_VAR_EQ: if (_variables[command.script[offset + 1]] != command.script[offset + 2]) return false; offset += 3; break; - case 9: + case IDO_CND_CUR_PIC_EQ: if (_rooms[_room].curPicture != command.script[offset + 1]) return false; offset += 2; break; - case 10: + case IDO_CND_ITEM_PIC_EQ: if (_inventory[command.script[offset + 1] - 1].picture != command.script[offset + 2]) return false; offset += 3; diff --git a/engines/adl/adl.h b/engines/adl/adl.h index fffe61eadf..e78d9ae6fd 100644 --- a/engines/adl/adl.h +++ b/engines/adl/adl.h @@ -71,6 +71,42 @@ enum EngineString { IDI_STR_TOTAL }; +// Conditional opcodes +#define IDO_CND_ITEM_IN_ROOM 0x03 +#define IDO_CND_STEPS_GE 0x05 +#define IDO_CND_VAR_EQ 0x06 +#define IDO_CND_CUR_PIC_EQ 0x09 +#define IDO_CND_ITEM_PIC_EQ 0x0a + +// Action opcodes +#define IDO_ACT_VAR_ADD 0x01 +#define IDO_ACT_VAR_SUB 0x02 +#define IDO_ACT_VAR_SET 0x03 +#define IDO_ACT_LIST_ITEMS 0x04 +#define IDO_ACT_MOVE_ITEM 0x05 +#define IDO_ACT_SET_ROOM 0x06 +#define IDO_ACT_SET_CUR_PIC 0x07 +#define IDO_ACT_SET_PIC 0x08 +#define IDO_ACT_PRINT_MSG 0x09 +#define IDO_ACT_SET_LIGHT 0x0a +#define IDO_ACT_SET_DARK 0x0b +#define IDO_ACT_QUIT 0x0d +#define IDO_ACT_SAVE 0x0f +#define IDO_ACT_LOAD 0x10 +#define IDO_ACT_RESTART 0x11 +#define IDO_ACT_SET_ITEM_POS 0x12 +#define IDO_ACT_SET_ITEM_PIC 0x13 +#define IDO_ACT_RESET_PIC 0x14 +#define IDO_ACT_GO_NORTH 0x15 +#define IDO_ACT_GO_SOUTH 0x16 +#define IDO_ACT_GO_EAST 0x17 +#define IDO_ACT_GO_WEST 0x18 +#define IDO_ACT_GO_UP 0x19 +#define IDO_ACT_GO_DOWN 0x1a +#define IDO_ACT_TAKE_ITEM 0x1b +#define IDO_ACT_DROP_ITEM 0x1c +#define IDO_ACT_SET_ROOM_PIC 0x1d + struct Room { byte description; byte connections[6]; -- cgit v1.2.3 From ede25c19bcedb802f3b0a7a1a5dc20238277012c Mon Sep 17 00:00:00 2001 From: Walter van Niftrik Date: Sun, 28 Feb 2016 16:21:46 +0100 Subject: ADL: Rename some #defines and variables for clarity --- engines/adl/adl.cpp | 55 +++++++++++++++++++++++++------------------------- engines/adl/adl.h | 2 +- engines/adl/hires1.cpp | 26 ++++++++++++------------ 3 files changed, 41 insertions(+), 42 deletions(-) (limited to 'engines') diff --git a/engines/adl/adl.cpp b/engines/adl/adl.cpp index af71bba5c9..eaffbb5a8b 100644 --- a/engines/adl/adl.cpp +++ b/engines/adl/adl.cpp @@ -162,27 +162,27 @@ void AdlEngine::readCommands(Common::ReadStream &stream, Commands &commands) { } void AdlEngine::takeItem(byte noun) { - Common::Array::iterator it; + Common::Array::iterator item; - for (it = _inventory.begin(); it != _inventory.end(); ++it) { - if (it->noun != noun || it->room != _room) + for (item = _inventory.begin(); item != _inventory.end(); ++item) { + if (item->noun != noun || item->room != _room) continue; - if (it->state == IDI_ITEM_DOESNT_MOVE) { + if (item->state == IDI_ITEM_DOESNT_MOVE) { printEngineMessage(IDI_MSG_ITEM_DOESNT_MOVE); return; } - if (it->state == IDI_ITEM_MOVED) { - it->room = IDI_NONE; + if (item->state == IDI_ITEM_MOVED) { + item->room = IDI_NONE; return; } - Common::Array::const_iterator it2; - for (it2 = it->roomPictures.begin(); it->roomPictures.end(); ++it2) { - if (*it2 == _rooms[_room].curPicture) { - it->room = IDI_NONE; - it->state = IDI_ITEM_MOVED; + Common::Array::const_iterator pic; + for (pic = item->roomPictures.begin(); item->roomPictures.end(); ++pic) { + if (*pic == _rooms[_room].curPicture) { + item->room = IDI_NONE; + item->state = IDI_ITEM_MOVED; return; } } @@ -192,18 +192,17 @@ void AdlEngine::takeItem(byte noun) { } void AdlEngine::dropItem(byte noun) { - Common::Array::iterator it; + Common::Array::iterator item; - for (it = _inventory.begin(); it != _inventory.end(); ++it) { - if (it->noun != noun || it->room != IDI_NONE) + for (item = _inventory.begin(); item != _inventory.end(); ++item) { + if (item->noun != noun || item->room != IDI_NONE) continue; - it->room = _room; - it->state = IDI_ITEM_MOVED; + item->room = _room; + item->state = IDI_ITEM_MOVED; return; } - // Don't understand printEngineMessage(IDI_MSG_DONT_UNDERSTAND); } @@ -223,11 +222,11 @@ void AdlEngine::doActions(const Command &command, byte noun, byte offset) { offset += 3; break; case IDO_ACT_LIST_ITEMS: { - Common::Array::const_iterator it; + Common::Array::const_iterator item; - for (it = _inventory.begin(); it != _inventory.end(); ++it) - if (it->room == IDI_NONE) - printMessage(it->description); + for (item = _inventory.begin(); item != _inventory.end(); ++item) + if (item->room == IDI_NONE) + printMessage(item->description); ++offset; break; @@ -282,7 +281,7 @@ void AdlEngine::doActions(const Command &command, byte noun, byte offset) { printEngineMessage(IDI_MSG_THANKS_FOR_PLAYING); quitGame(); return; - case IDO_ACT_SET_ITEM_POS: { + case IDO_ACT_PLACE_ITEM: { byte item = command.script[offset + 1] - 1; _inventory[item].room = command.script[offset + 2]; _inventory[item].position.x = command.script[offset + 3]; @@ -384,20 +383,20 @@ bool AdlEngine::checkCommand(const Command &command, byte verb, byte noun) { } bool AdlEngine::doOneCommand(const Commands &commands, byte verb, byte noun) { - Commands::const_iterator it; + Commands::const_iterator cmd; - for (it = commands.begin(); it != commands.end(); ++it) - if (checkCommand(*it, verb, noun)) + for (cmd = commands.begin(); cmd != commands.end(); ++cmd) + if (checkCommand(*cmd, verb, noun)) return true; return false; } void AdlEngine::doAllCommands(const Commands &commands, byte verb, byte noun) { - Commands::const_iterator it; + Commands::const_iterator cmd; - for (it = commands.begin(); it != commands.end(); ++it) - checkCommand(*it, verb, noun); + for (cmd = commands.begin(); cmd != commands.end(); ++cmd) + checkCommand(*cmd, verb, noun); } void AdlEngine::clearScreen() { diff --git a/engines/adl/adl.h b/engines/adl/adl.h index e78d9ae6fd..02207d951e 100644 --- a/engines/adl/adl.h +++ b/engines/adl/adl.h @@ -94,7 +94,7 @@ enum EngineString { #define IDO_ACT_SAVE 0x0f #define IDO_ACT_LOAD 0x10 #define IDO_ACT_RESTART 0x11 -#define IDO_ACT_SET_ITEM_POS 0x12 +#define IDO_ACT_PLACE_ITEM 0x12 #define IDO_ACT_SET_ITEM_PIC 0x13 #define IDO_ACT_RESET_PIC 0x14 #define IDO_ACT_GO_NORTH 0x15 diff --git a/engines/adl/hires1.cpp b/engines/adl/hires1.cpp index 730f229198..dde8ed0fc7 100644 --- a/engines/adl/hires1.cpp +++ b/engines/adl/hires1.cpp @@ -218,34 +218,34 @@ void HiRes1Engine::drawPic(byte pic, byte xOffset, byte yOffset) { } void HiRes1Engine::drawItems() { - Common::Array::const_iterator it; + Common::Array::const_iterator item; uint dropped = 0; - for (it = _inventory.begin(); it != _inventory.end(); ++it) { - if (it->room != _room) + for (item = _inventory.begin(); item != _inventory.end(); ++item) { + if (item->room != _room) continue; - if (it->state == IDI_ITEM_MOVED) { + if (item->state == IDI_ITEM_MOVED) { if (_rooms[_room].picture == _rooms[_room].curPicture) { const Common::Point &p = _itemOffsets[dropped]; - if (it->isDrawing) - _display->drawRightAngles(_drawings[it->picture - 1], Common::Point(p.x, p.y), 0, 1, 0x7f); + if (item->isDrawing) + _display->drawRightAngles(_drawings[item->picture - 1], Common::Point(p.x, p.y), 0, 1, 0x7f); else - drawPic(it->picture, p.x, p.y); + drawPic(item->picture, p.x, p.y); ++dropped; } continue; } - Common::Array::const_iterator it2; + Common::Array::const_iterator pic; - for (it2 = it->roomPictures.begin(); it2 != it->roomPictures.end(); ++it2) { - if (*it2 == _rooms[_room].curPicture) { - if (it->isDrawing) - _display->drawRightAngles(_drawings[it->picture - 1], it->position, 0, 1, 0x7f); + for (pic = item->roomPictures.begin(); pic != item->roomPictures.end(); ++pic) { + if (*pic == _rooms[_room].curPicture) { + if (item->isDrawing) + _display->drawRightAngles(_drawings[item->picture - 1], item->position, 0, 1, 0x7f); else - drawPic(it->picture, it->position.x, it->position.y); + drawPic(item->picture, item->position.x, item->position.y); continue; } } -- cgit v1.2.3 From 24c478c5ecd61d42a1456a7b8cbecec70e24cd1a Mon Sep 17 00:00:00 2001 From: Walter van Niftrik Date: Sun, 28 Feb 2016 16:36:28 +0100 Subject: ADL: Add ARG #define to improve readability --- engines/adl/adl.cpp | 54 ++++++++++++++++++++++++++--------------------------- 1 file changed, 27 insertions(+), 27 deletions(-) (limited to 'engines') diff --git a/engines/adl/adl.cpp b/engines/adl/adl.cpp index eaffbb5a8b..c46b74799a 100644 --- a/engines/adl/adl.cpp +++ b/engines/adl/adl.cpp @@ -206,19 +206,21 @@ void AdlEngine::dropItem(byte noun) { printEngineMessage(IDI_MSG_DONT_UNDERSTAND); } +#define ARG(N) (command.script[offset + N]) + void AdlEngine::doActions(const Command &command, byte noun, byte offset) { for (uint i = 0; i < command.numAct; ++i) { - switch (command.script[offset]) { + switch (ARG(0)) { case IDO_ACT_VAR_ADD: - _variables[command.script[offset + 2]] += command.script[offset + 1]; + _variables[ARG(2)] += ARG(1); offset += 3; break; case IDO_ACT_VAR_SUB: - _variables[command.script[offset + 2]] -= command.script[offset + 1]; + _variables[ARG(2)] -= ARG(1); offset += 3; break; case IDO_ACT_VAR_SET: - _variables[command.script[offset + 1]] = command.script[offset + 2]; + _variables[ARG(1)] = ARG(2); offset += 3; break; case IDO_ACT_LIST_ITEMS: { @@ -232,24 +234,24 @@ void AdlEngine::doActions(const Command &command, byte noun, byte offset) { break; } case IDO_ACT_MOVE_ITEM: - _inventory[command.script[offset + 1] - 1].room = command.script[offset + 2]; + _inventory[ARG(1) - 1].room = ARG(2); offset += 3; break; case IDO_ACT_SET_ROOM: _rooms[_room].curPicture = _rooms[_room].picture; - _room = command.script[offset + 1]; + _room = ARG(1); offset += 2; break; case IDO_ACT_SET_CUR_PIC: - _rooms[_room].curPicture = command.script[offset + 1]; + _rooms[_room].curPicture = ARG(1); offset += 2; break; case IDO_ACT_SET_PIC: - _rooms[_room].picture = _rooms[_room].curPicture = command.script[offset + 1]; + _rooms[_room].picture = _rooms[_room].curPicture = ARG(1); offset += 2; break; case IDO_ACT_PRINT_MSG: - printMessage(command.script[offset + 1]); + printMessage(ARG(1)); offset += 2; break; case IDO_ACT_SET_LIGHT: @@ -281,20 +283,16 @@ void AdlEngine::doActions(const Command &command, byte noun, byte offset) { printEngineMessage(IDI_MSG_THANKS_FOR_PLAYING); quitGame(); return; - case IDO_ACT_PLACE_ITEM: { - byte item = command.script[offset + 1] - 1; - _inventory[item].room = command.script[offset + 2]; - _inventory[item].position.x = command.script[offset + 3]; - _inventory[item].position.y = command.script[offset + 4]; + case IDO_ACT_PLACE_ITEM: + _inventory[ARG(1) - 1].room = ARG(2); + _inventory[ARG(1) - 1].position.x = ARG(3); + _inventory[ARG(1) - 1].position.y = ARG(4); offset += 5; break; - } - case IDO_ACT_SET_ITEM_PIC: { - byte item = command.script[offset + 2] - 1; - _inventory[item].picture = command.script[offset + 1]; + case IDO_ACT_SET_ITEM_PIC: + _inventory[ARG(2) - 1].picture = ARG(1); offset += 3; break; - } case IDO_ACT_RESET_PIC: _rooms[_room].curPicture = _rooms[_room].picture; ++offset; @@ -305,7 +303,7 @@ void AdlEngine::doActions(const Command &command, byte noun, byte offset) { case IDO_ACT_GO_WEST: case IDO_ACT_GO_UP: case IDO_ACT_GO_DOWN: { - byte room = _rooms[_room].connections[command.script[offset] - 0x15]; + byte room = _rooms[_room].connections[ARG(0) - 0x15]; if (room == 0) { printEngineMessage(IDI_MSG_CANT_GO_THERE); @@ -325,11 +323,11 @@ void AdlEngine::doActions(const Command &command, byte noun, byte offset) { ++offset; break; case IDO_ACT_SET_ROOM_PIC: - _rooms[command.script[offset + 1]].picture = _rooms[command.script[offset + 1]].curPicture = command.script[offset + 2]; + _rooms[ARG(1)].picture = _rooms[ARG(1)].curPicture = ARG(2); offset += 3; break; default: - error("Invalid action opcode %02x", command.script[offset]); + error("Invalid action opcode %02x", ARG(0)); } } } @@ -348,27 +346,27 @@ bool AdlEngine::checkCommand(const Command &command, byte verb, byte noun) { for (uint i = 0; i < command.numCond; ++i) { switch (command.script[offset]) { case IDO_CND_ITEM_IN_ROOM: - if (_inventory[command.script[offset + 1] - 1].room != command.script[offset + 2]) + if (_inventory[ARG(1) - 1].room != ARG(2)) return false; offset += 3; break; case IDO_CND_STEPS_GE: - if (command.script[offset + 1] > _steps) + if (ARG(1) > _steps) return false; offset += 2; break; case IDO_CND_VAR_EQ: - if (_variables[command.script[offset + 1]] != command.script[offset + 2]) + if (_variables[ARG(1)] != ARG(2)) return false; offset += 3; break; case IDO_CND_CUR_PIC_EQ: - if (_rooms[_room].curPicture != command.script[offset + 1]) + if (_rooms[_room].curPicture != ARG(1)) return false; offset += 2; break; case IDO_CND_ITEM_PIC_EQ: - if (_inventory[command.script[offset + 1] - 1].picture != command.script[offset + 2]) + if (_inventory[ARG(1) - 1].picture != ARG(2)) return false; offset += 3; break; @@ -382,6 +380,8 @@ bool AdlEngine::checkCommand(const Command &command, byte verb, byte noun) { return true; } +#undef ARG + bool AdlEngine::doOneCommand(const Commands &commands, byte verb, byte noun) { Commands::const_iterator cmd; -- cgit v1.2.3 From 34cb2f4c53280d5b1f10ded5951d0ca5c0bf754d Mon Sep 17 00:00:00 2001 From: Walter van Niftrik Date: Sun, 28 Feb 2016 17:12:00 +0100 Subject: ADL: Move functionality into base class --- engines/adl/adl.cpp | 47 +++++++++++++++++++++++++++++++++++++++++- engines/adl/adl.h | 3 +++ engines/adl/hires1.cpp | 55 +++++--------------------------------------------- engines/adl/hires1.h | 5 ++--- 4 files changed, 56 insertions(+), 54 deletions(-) (limited to 'engines') diff --git a/engines/adl/adl.cpp b/engines/adl/adl.cpp index c46b74799a..9676924f34 100644 --- a/engines/adl/adl.cpp +++ b/engines/adl/adl.cpp @@ -206,7 +206,7 @@ void AdlEngine::dropItem(byte noun) { printEngineMessage(IDI_MSG_DONT_UNDERSTAND); } -#define ARG(N) (command.script[offset + N]) +#define ARG(N) (command.script[offset + (N)]) void AdlEngine::doActions(const Command &command, byte noun, byte offset) { for (uint i = 0; i < command.numAct; ++i) { @@ -404,6 +404,51 @@ void AdlEngine::clearScreen() { _display->clear(0x00); } +void AdlEngine::drawItems() { + Common::Array::const_iterator item; + + uint dropped = 0; + + for (item = _inventory.begin(); item != _inventory.end(); ++item) { + if (item->room != _room) + continue; + + if (item->state == IDI_ITEM_MOVED) { + if (_rooms[_room].picture == _rooms[_room].curPicture) { + const Common::Point &p = _itemOffsets[dropped]; + if (item->isDrawing) + _display->drawRightAngles(_drawings[item->picture - 1], p, 0, 1, 0x7f); + else + drawPic(item->picture, p); + ++dropped; + } + continue; + } + + Common::Array::const_iterator pic; + + for (pic = item->roomPictures.begin(); pic != item->roomPictures.end(); ++pic) { + if (*pic == _rooms[_room].curPicture) { + if (item->isDrawing) + _display->drawRightAngles(_drawings[item->picture - 1], item->position, 0, 1, 0x7f); + else + drawPic(item->picture, item->position); + continue; + } + } + } +} + +void AdlEngine::showRoom() { + if (!_isDark) { + drawPic(_rooms[_room].curPicture); + drawItems(); + } + + _display->decodeFrameBuffer(); + printMessage(_rooms[_room].description, false); +} + AdlEngine *AdlEngine::create(GameType type, OSystem *syst, const AdlGameDescription *gd) { switch(type) { case kGameTypeHires1: diff --git a/engines/adl/adl.h b/engines/adl/adl.h index 02207d951e..a030059ec0 100644 --- a/engines/adl/adl.h +++ b/engines/adl/adl.h @@ -174,6 +174,9 @@ protected: void doAllCommands(const Commands &commands, byte verb, byte noun); void doActions(const Command &command, byte noun, byte offset); void clearScreen(); + virtual void drawPic(byte pic, Common::Point pos = Common::Point()) = 0; + void drawItems(); + void showRoom(); void takeItem(byte noun); void dropItem(byte noun); diff --git a/engines/adl/hires1.cpp b/engines/adl/hires1.cpp index dde8ed0fc7..64ae81fbeb 100644 --- a/engines/adl/hires1.cpp +++ b/engines/adl/hires1.cpp @@ -169,7 +169,7 @@ void HiRes1Engine::runIntro() { } } -void HiRes1Engine::drawPic(Common::ReadStream &stream, byte xOffset, byte yOffset) { +void HiRes1Engine::drawPic(Common::ReadStream &stream, Common::Point pos) { byte x, y; bool bNewLine = false; byte oldX = 0, oldY = 0; @@ -188,8 +188,8 @@ void HiRes1Engine::drawPic(Common::ReadStream &stream, byte xOffset, byte yOffse continue; } - x += xOffset; - y += yOffset; + x += pos.x; + y += pos.y; if (y > 160) y = 160; @@ -206,7 +206,7 @@ void HiRes1Engine::drawPic(Common::ReadStream &stream, byte xOffset, byte yOffse } } -void HiRes1Engine::drawPic(byte pic, byte xOffset, byte yOffset) { +void HiRes1Engine::drawPic(byte pic, Common::Point pos) { Common::File f; Common::String name = Common::String::format("BLOCK%i", _pictures[pic].block); @@ -214,52 +214,7 @@ void HiRes1Engine::drawPic(byte pic, byte xOffset, byte yOffset) { error("Failed to open file"); f.seek(_pictures[pic].offset); - drawPic(f, xOffset, yOffset); -} - -void HiRes1Engine::drawItems() { - Common::Array::const_iterator item; - - uint dropped = 0; - - for (item = _inventory.begin(); item != _inventory.end(); ++item) { - if (item->room != _room) - continue; - - if (item->state == IDI_ITEM_MOVED) { - if (_rooms[_room].picture == _rooms[_room].curPicture) { - const Common::Point &p = _itemOffsets[dropped]; - if (item->isDrawing) - _display->drawRightAngles(_drawings[item->picture - 1], Common::Point(p.x, p.y), 0, 1, 0x7f); - else - drawPic(item->picture, p.x, p.y); - ++dropped; - } - continue; - } - - Common::Array::const_iterator pic; - - for (pic = item->roomPictures.begin(); pic != item->roomPictures.end(); ++pic) { - if (*pic == _rooms[_room].curPicture) { - if (item->isDrawing) - _display->drawRightAngles(_drawings[item->picture - 1], item->position, 0, 1, 0x7f); - else - drawPic(item->picture, item->position.x, item->position.y); - continue; - } - } - } -} - -void HiRes1Engine::showRoom() { - if (!_isDark) { - drawPic(_rooms[_room].curPicture, 0, 0); - drawItems(); - } - - _display->decodeFrameBuffer(); - printMessage(_rooms[_room].description, false); + drawPic(f, pos); } void HiRes1Engine::runGame() { diff --git a/engines/adl/hires1.h b/engines/adl/hires1.h index 19aa55ee9f..4bd0a87034 100644 --- a/engines/adl/hires1.h +++ b/engines/adl/hires1.h @@ -53,10 +53,9 @@ private: uint getEngineMessage(EngineMessage msg); void runIntro(); - void drawPic(Common::ReadStream &stream, byte xOffset, byte yOffset); - void showRoom(); + void drawPic(Common::ReadStream &stream, Common::Point pos); void drawItems(); - void drawPic(byte pic, byte xOffset, byte yOffset); + void drawPic(byte pic, Common::Point pos); }; } // End of namespace Adl -- cgit v1.2.3 From 1abaf60cf04c5bc2bf8a3fb37aa8dd83816a7771 Mon Sep 17 00:00:00 2001 From: Walter van Niftrik Date: Sun, 28 Feb 2016 17:21:09 +0100 Subject: ADL: Rename rightAngles to lineArt --- engines/adl/adl.cpp | 8 ++++---- engines/adl/adl.h | 4 ++-- engines/adl/display.cpp | 6 +++--- engines/adl/display.h | 2 +- engines/adl/hires1.cpp | 14 +++++++------- 5 files changed, 17 insertions(+), 17 deletions(-) (limited to 'engines') diff --git a/engines/adl/adl.cpp b/engines/adl/adl.cpp index 9676924f34..d93b771406 100644 --- a/engines/adl/adl.cpp +++ b/engines/adl/adl.cpp @@ -416,8 +416,8 @@ void AdlEngine::drawItems() { if (item->state == IDI_ITEM_MOVED) { if (_rooms[_room].picture == _rooms[_room].curPicture) { const Common::Point &p = _itemOffsets[dropped]; - if (item->isDrawing) - _display->drawRightAngles(_drawings[item->picture - 1], p, 0, 1, 0x7f); + if (item->isLineArt) + _display->drawLineArt(_lineArt[item->picture - 1], p); else drawPic(item->picture, p); ++dropped; @@ -429,8 +429,8 @@ void AdlEngine::drawItems() { for (pic = item->roomPictures.begin(); pic != item->roomPictures.end(); ++pic) { if (*pic == _rooms[_room].curPicture) { - if (item->isDrawing) - _display->drawRightAngles(_drawings[item->picture - 1], item->position, 0, 1, 0x7f); + if (item->isLineArt) + _display->drawLineArt(_lineArt[item->picture - 1], item->position); else drawPic(item->picture, item->position); continue; diff --git a/engines/adl/adl.h b/engines/adl/adl.h index a030059ec0..5335211cea 100644 --- a/engines/adl/adl.h +++ b/engines/adl/adl.h @@ -138,7 +138,7 @@ struct Item { byte noun; byte room; byte picture; - bool isDrawing; + bool isLineArt; Common::Point position; int state; byte description; @@ -188,7 +188,7 @@ protected: Common::Array _pictures; Common::Array _inventory; Common::Array _itemOffsets; - Common::Array > _drawings; + Common::Array > _lineArt; Commands _roomCommands; Commands _globalCommands; diff --git a/engines/adl/display.cpp b/engines/adl/display.cpp index 47b1533582..8ea0a7bcba 100644 --- a/engines/adl/display.cpp +++ b/engines/adl/display.cpp @@ -304,7 +304,7 @@ void Display::drawNextPixel(Display::PixelPos &p, byte &color, byte bits, byte q moveY(p, bits & 2); } -void Display::drawRightAngles(Common::Array &rightAngles, Common::Point p, byte rotation, byte scaling, byte color) { +void Display::drawLineArt(const Common::Array &lineArt, Common::Point p, byte rotation, byte scaling, byte color) { const byte stepping[] = { 0xff, 0xfe, 0xfa, 0xf4, 0xec, 0xe1, 0xd4, 0xc5, 0xb4, 0xa1, 0x8d, 0x78, 0x61, 0x49, 0x31, 0x18, @@ -319,8 +319,8 @@ void Display::drawRightAngles(Common::Array &rightAngles, Common::Point p, byte xStep = stepping[rotation]; byte yStep = stepping[(rotation ^ 0xf) + 1] + 1; - for (uint i = 0; i < rightAngles.size(); ++i) { - byte b = rightAngles[i]; + for (uint i = 0; i < lineArt.size(); ++i) { + byte b = lineArt[i]; do { byte xFrac = 0x80; diff --git a/engines/adl/display.h b/engines/adl/display.h index 62294d3e55..229446f447 100644 --- a/engines/adl/display.h +++ b/engines/adl/display.h @@ -63,7 +63,7 @@ public: void drawPixel(byte x, byte y, byte color); void drawLine(Common::Point p1, Common::Point p2, byte color); void clear(byte color); - void drawRightAngles(Common::Array &rightAngles, Common::Point p, byte rotation, byte scaling, byte color); + void drawLineArt(const Common::Array &lineArt, Common::Point p, byte rotation = 0, byte scaling = 1, byte color = 0x7f); private: enum { diff --git a/engines/adl/hires1.cpp b/engines/adl/hires1.cpp index 64ae81fbeb..9163875f37 100644 --- a/engines/adl/hires1.cpp +++ b/engines/adl/hires1.cpp @@ -261,7 +261,7 @@ void HiRes1Engine::runGame() { item.noun = f.readByte(); item.room = f.readByte(); item.picture = f.readByte(); - item.isDrawing = f.readByte(); + item.isLineArt = f.readByte(); item.position.x = f.readByte(); item.position.y = f.readByte(); item.state = f.readByte(); @@ -302,21 +302,21 @@ void HiRes1Engine::runGame() { _itemOffsets.push_back(p); } - // Load right-angle drawings + // Load right-angle line art f.seek(0x4f00); - uint16 drawingsTotal = f.readUint16LE(); - for (uint i = 0; i < drawingsTotal; ++i) { + uint16 lineArtTotal = f.readUint16LE(); + for (uint i = 0; i < lineArtTotal; ++i) { f.seek(0x4f00 + 2 + i * 2); uint16 offset = f.readUint16LE(); f.seek(0x4f00 + offset); - Common::Array drawing; + Common::Array lineArt; byte b = f.readByte(); while (b != 0) { - drawing.push_back(b); + lineArt.push_back(b); b = f.readByte(); } - _drawings.push_back(drawing); + _lineArt.push_back(lineArt); } // Title screen shown during loading -- cgit v1.2.3 From dc2e5e09ba045474284521e8db4ff7e40b0fe68a Mon Sep 17 00:00:00 2001 From: Walter van Niftrik Date: Sun, 28 Feb 2016 21:01:01 +0100 Subject: ADL: Put state-related members in _state struct --- engines/adl/adl.cpp | 83 ++++++++++++++++++++++++-------------------------- engines/adl/adl.h | 21 ++++++++----- engines/adl/hires1.cpp | 63 ++++++++++++++++++++++++-------------- engines/adl/hires1.h | 1 + 4 files changed, 95 insertions(+), 73 deletions(-) (limited to 'engines') diff --git a/engines/adl/adl.cpp b/engines/adl/adl.cpp index d93b771406..e395c8266f 100644 --- a/engines/adl/adl.cpp +++ b/engines/adl/adl.cpp @@ -43,10 +43,7 @@ AdlEngine::AdlEngine(OSystem *syst, const AdlGameDescription *gd) : Engine(syst), _gameDescription(gd), _display(nullptr), - _parser(nullptr), - _room(1), - _steps(0), - _isDark(false) { + _parser(nullptr) { } AdlEngine::~AdlEngine() { @@ -164,8 +161,8 @@ void AdlEngine::readCommands(Common::ReadStream &stream, Commands &commands) { void AdlEngine::takeItem(byte noun) { Common::Array::iterator item; - for (item = _inventory.begin(); item != _inventory.end(); ++item) { - if (item->noun != noun || item->room != _room) + for (item = _state.items.begin(); item != _state.items.end(); ++item) { + if (item->noun != noun || item->room != _state.room) continue; if (item->state == IDI_ITEM_DOESNT_MOVE) { @@ -180,7 +177,7 @@ void AdlEngine::takeItem(byte noun) { Common::Array::const_iterator pic; for (pic = item->roomPictures.begin(); item->roomPictures.end(); ++pic) { - if (*pic == _rooms[_room].curPicture) { + if (*pic == _state.rooms[_state.room].curPicture) { item->room = IDI_NONE; item->state = IDI_ITEM_MOVED; return; @@ -194,11 +191,11 @@ void AdlEngine::takeItem(byte noun) { void AdlEngine::dropItem(byte noun) { Common::Array::iterator item; - for (item = _inventory.begin(); item != _inventory.end(); ++item) { + for (item = _state.items.begin(); item != _state.items.end(); ++item) { if (item->noun != noun || item->room != IDI_NONE) continue; - item->room = _room; + item->room = _state.room; item->state = IDI_ITEM_MOVED; return; } @@ -212,21 +209,21 @@ void AdlEngine::doActions(const Command &command, byte noun, byte offset) { for (uint i = 0; i < command.numAct; ++i) { switch (ARG(0)) { case IDO_ACT_VAR_ADD: - _variables[ARG(2)] += ARG(1); + _state.vars[ARG(2)] += ARG(1); offset += 3; break; case IDO_ACT_VAR_SUB: - _variables[ARG(2)] -= ARG(1); + _state.vars[ARG(2)] -= ARG(1); offset += 3; break; case IDO_ACT_VAR_SET: - _variables[ARG(1)] = ARG(2); + _state.vars[ARG(1)] = ARG(2); offset += 3; break; case IDO_ACT_LIST_ITEMS: { Common::Array::const_iterator item; - for (item = _inventory.begin(); item != _inventory.end(); ++item) + for (item = _state.items.begin(); item != _state.items.end(); ++item) if (item->room == IDI_NONE) printMessage(item->description); @@ -234,20 +231,20 @@ void AdlEngine::doActions(const Command &command, byte noun, byte offset) { break; } case IDO_ACT_MOVE_ITEM: - _inventory[ARG(1) - 1].room = ARG(2); + _state.items[ARG(1) - 1].room = ARG(2); offset += 3; break; case IDO_ACT_SET_ROOM: - _rooms[_room].curPicture = _rooms[_room].picture; - _room = ARG(1); + _state.rooms[_state.room].curPicture = _state.rooms[_state.room].picture; + _state.room = ARG(1); offset += 2; break; case IDO_ACT_SET_CUR_PIC: - _rooms[_room].curPicture = ARG(1); + _state.rooms[_state.room].curPicture = ARG(1); offset += 2; break; case IDO_ACT_SET_PIC: - _rooms[_room].picture = _rooms[_room].curPicture = ARG(1); + _state.rooms[_state.room].picture = _state.rooms[_state.room].curPicture = ARG(1); offset += 2; break; case IDO_ACT_PRINT_MSG: @@ -255,11 +252,11 @@ void AdlEngine::doActions(const Command &command, byte noun, byte offset) { offset += 2; break; case IDO_ACT_SET_LIGHT: - _isDark = false; + _state.isDark = false; ++offset; break; case IDO_ACT_SET_DARK: - _isDark = true; + _state.isDark = true; ++offset; break; case IDO_ACT_SAVE: @@ -284,17 +281,17 @@ void AdlEngine::doActions(const Command &command, byte noun, byte offset) { quitGame(); return; case IDO_ACT_PLACE_ITEM: - _inventory[ARG(1) - 1].room = ARG(2); - _inventory[ARG(1) - 1].position.x = ARG(3); - _inventory[ARG(1) - 1].position.y = ARG(4); + _state.items[ARG(1) - 1].room = ARG(2); + _state.items[ARG(1) - 1].position.x = ARG(3); + _state.items[ARG(1) - 1].position.y = ARG(4); offset += 5; break; case IDO_ACT_SET_ITEM_PIC: - _inventory[ARG(2) - 1].picture = ARG(1); + _state.items[ARG(2) - 1].picture = ARG(1); offset += 3; break; case IDO_ACT_RESET_PIC: - _rooms[_room].curPicture = _rooms[_room].picture; + _state.rooms[_state.room].curPicture = _state.rooms[_state.room].picture; ++offset; break; case IDO_ACT_GO_NORTH: @@ -303,15 +300,15 @@ void AdlEngine::doActions(const Command &command, byte noun, byte offset) { case IDO_ACT_GO_WEST: case IDO_ACT_GO_UP: case IDO_ACT_GO_DOWN: { - byte room = _rooms[_room].connections[ARG(0) - 0x15]; + byte room = _state.rooms[_state.room].connections[ARG(0) - 0x15]; if (room == 0) { printEngineMessage(IDI_MSG_CANT_GO_THERE); return; } - _rooms[_room].curPicture = _rooms[_room].picture; - _room = room; + _state.rooms[_state.room].curPicture = _state.rooms[_state.room].picture; + _state.room = room; return; } case IDO_ACT_TAKE_ITEM: @@ -323,7 +320,7 @@ void AdlEngine::doActions(const Command &command, byte noun, byte offset) { ++offset; break; case IDO_ACT_SET_ROOM_PIC: - _rooms[ARG(1)].picture = _rooms[ARG(1)].curPicture = ARG(2); + _state.rooms[ARG(1)].picture = _state.rooms[ARG(1)].curPicture = ARG(2); offset += 3; break; default: @@ -333,7 +330,7 @@ void AdlEngine::doActions(const Command &command, byte noun, byte offset) { } bool AdlEngine::checkCommand(const Command &command, byte verb, byte noun) { - if (command.room != IDI_NONE && command.room != _room) + if (command.room != IDI_NONE && command.room != _state.room) return false; if (command.verb != IDI_NONE && command.verb != verb) @@ -346,27 +343,27 @@ bool AdlEngine::checkCommand(const Command &command, byte verb, byte noun) { for (uint i = 0; i < command.numCond; ++i) { switch (command.script[offset]) { case IDO_CND_ITEM_IN_ROOM: - if (_inventory[ARG(1) - 1].room != ARG(2)) + if (_state.items[ARG(1) - 1].room != ARG(2)) return false; offset += 3; break; - case IDO_CND_STEPS_GE: - if (ARG(1) > _steps) + case IDO_CND_MOVES_GE: + if (ARG(1) > _state.moves) return false; offset += 2; break; case IDO_CND_VAR_EQ: - if (_variables[ARG(1)] != ARG(2)) + if (_state.vars[ARG(1)] != ARG(2)) return false; offset += 3; break; case IDO_CND_CUR_PIC_EQ: - if (_rooms[_room].curPicture != ARG(1)) + if (_state.rooms[_state.room].curPicture != ARG(1)) return false; offset += 2; break; case IDO_CND_ITEM_PIC_EQ: - if (_inventory[ARG(1) - 1].picture != ARG(2)) + if (_state.items[ARG(1) - 1].picture != ARG(2)) return false; offset += 3; break; @@ -409,12 +406,12 @@ void AdlEngine::drawItems() { uint dropped = 0; - for (item = _inventory.begin(); item != _inventory.end(); ++item) { - if (item->room != _room) + for (item = _state.items.begin(); item != _state.items.end(); ++item) { + if (item->room != _state.room) continue; if (item->state == IDI_ITEM_MOVED) { - if (_rooms[_room].picture == _rooms[_room].curPicture) { + if (_state.rooms[_state.room].picture == _state.rooms[_state.room].curPicture) { const Common::Point &p = _itemOffsets[dropped]; if (item->isLineArt) _display->drawLineArt(_lineArt[item->picture - 1], p); @@ -428,7 +425,7 @@ void AdlEngine::drawItems() { Common::Array::const_iterator pic; for (pic = item->roomPictures.begin(); pic != item->roomPictures.end(); ++pic) { - if (*pic == _rooms[_room].curPicture) { + if (*pic == _state.rooms[_state.room].curPicture) { if (item->isLineArt) _display->drawLineArt(_lineArt[item->picture - 1], item->position); else @@ -440,13 +437,13 @@ void AdlEngine::drawItems() { } void AdlEngine::showRoom() { - if (!_isDark) { - drawPic(_rooms[_room].curPicture); + if (!_state.isDark) { + drawPic(_state.rooms[_state.room].curPicture); drawItems(); } _display->decodeFrameBuffer(); - printMessage(_rooms[_room].description, false); + printMessage(_state.rooms[_state.room].description, false); } AdlEngine *AdlEngine::create(GameType type, OSystem *syst, const AdlGameDescription *gd) { diff --git a/engines/adl/adl.h b/engines/adl/adl.h index 5335211cea..d39e0e3638 100644 --- a/engines/adl/adl.h +++ b/engines/adl/adl.h @@ -73,7 +73,7 @@ enum EngineString { // Conditional opcodes #define IDO_CND_ITEM_IN_ROOM 0x03 -#define IDO_CND_STEPS_GE 0x05 +#define IDO_CND_MOVES_GE 0x05 #define IDO_CND_VAR_EQ 0x06 #define IDO_CND_CUR_PIC_EQ 0x09 #define IDO_CND_ITEM_PIC_EQ 0x0a @@ -145,6 +145,18 @@ struct Item { Common::Array roomPictures; }; +struct State { + Common::Array rooms; + Common::Array items; + Common::Array vars; + + byte room; + uint16 moves; + bool isDark; + + State() : room(1), moves(0), isDark(false) { } +}; + typedef Common::List Commands; class AdlEngine : public Engine { @@ -186,18 +198,13 @@ protected: Common::Array _strings; Common::Array _messages; Common::Array _pictures; - Common::Array _inventory; Common::Array _itemOffsets; Common::Array > _lineArt; Commands _roomCommands; Commands _globalCommands; // Game state - Common::Array _rooms; - byte _room; - uint16 _steps; - Common::Array _variables; - bool _isDark; + State _state; private: void printEngineMessage(EngineMessage); diff --git a/engines/adl/hires1.cpp b/engines/adl/hires1.cpp index 9163875f37..1316bf2d70 100644 --- a/engines/adl/hires1.cpp +++ b/engines/adl/hires1.cpp @@ -84,7 +84,6 @@ static const StringOffset stringOffsets[] = { HiRes1Engine::HiRes1Engine(OSystem *syst, const AdlGameDescription *gd) : AdlEngine(syst, gd) { - _variables.resize(20); } void HiRes1Engine::runIntro() { @@ -217,47 +216,38 @@ void HiRes1Engine::drawPic(byte pic, Common::Point pos) { drawPic(f, pos); } -void HiRes1Engine::runGame() { - runIntro(); - _display->printASCIIString("\r"); - +void HiRes1Engine::initState() { Common::File f; - if (!f.open("MESSAGES")) - error("Failed to open file"); + _state.room = 1; + _state.moves = 0; + _state.isDark = false; - while (!f.eos() && !f.err()) - _messages.push_back(readString(f, APPLECHAR('\r')) + APPLECHAR('\r')); - - f.close(); + _state.vars.clear(); + _state.vars.resize(20); if (!f.open("ADVENTURE")) error("Failed to open file"); - // Load strings from executable - _strings.resize(IDI_HR1_STR_TOTAL); - for (uint idx = 0; idx < IDI_HR1_STR_TOTAL; ++idx) { - f.seek(stringOffsets[idx].offset); - _strings[stringOffsets[idx].stringIdx] = readString(f); - } - // Load room data from executable + _state.rooms.clear(); f.seek(1280); for (uint i = 0; i < MH_ROOMS; ++i) { - struct Room room; + Room room; f.readByte(); room.description = f.readByte(); for (uint j = 0; j < 6; ++j) room.connections[j] = f.readByte(); room.picture = f.readByte(); room.curPicture = f.readByte(); - _rooms.push_back(room); + _state.rooms.push_back(room); } // Load inventory data from executable + _state.items.clear(); f.seek(0x100); while (f.readByte() != 0xff) { - struct Item item; + Item item; item.noun = f.readByte(); item.room = f.readByte(); item.picture = f.readByte(); @@ -274,7 +264,34 @@ void HiRes1Engine::runGame() { for (uint i = 0; i < size; ++i) item.roomPictures.push_back(f.readByte()); - _inventory.push_back(item); + _state.items.push_back(item); + } +} + +void HiRes1Engine::runGame() { + runIntro(); + _display->printASCIIString("\r"); + + Common::File f; + + if (!f.open("MESSAGES")) + error("Failed to open file"); + + while (!f.eos() && !f.err()) + _messages.push_back(readString(f, APPLECHAR('\r')) + APPLECHAR('\r')); + + f.close(); + + initState(); + + if (!f.open("ADVENTURE")) + error("Failed to open file"); + + // Load strings from executable + _strings.resize(IDI_HR1_STR_TOTAL); + for (uint idx = 0; idx < IDI_HR1_STR_TOTAL; ++idx) { + f.seek(stringOffsets[idx].offset); + _strings[stringOffsets[idx].stringIdx] = readString(f); } // Load picture data from executable @@ -341,7 +358,7 @@ void HiRes1Engine::runGame() { printMessage(37); doAllCommands(_globalCommands, verb, noun); - _steps++; + _state.moves++; if (shouldQuit()) return; diff --git a/engines/adl/hires1.h b/engines/adl/hires1.h index 4bd0a87034..5cc9f3ac98 100644 --- a/engines/adl/hires1.h +++ b/engines/adl/hires1.h @@ -52,6 +52,7 @@ private: void printMessage(uint idx, bool wait = true); uint getEngineMessage(EngineMessage msg); + void initState(); void runIntro(); void drawPic(Common::ReadStream &stream, Common::Point pos); void drawItems(); -- cgit v1.2.3 From 301b2fdc219ecc92cc81cc94d8e2904fc21cec6e Mon Sep 17 00:00:00 2001 From: Walter van Niftrik Date: Sun, 28 Feb 2016 21:04:21 +0100 Subject: ADL: Remove leftover debug code --- engines/adl/display.cpp | 23 ----------------------- 1 file changed, 23 deletions(-) (limited to 'engines') diff --git a/engines/adl/display.cpp b/engines/adl/display.cpp index 8ea0a7bcba..05e7c2e67c 100644 --- a/engines/adl/display.cpp +++ b/engines/adl/display.cpp @@ -82,29 +82,6 @@ Display::Display() : _textBufSurface->create(kWidth * 2, kHeight * 2, Graphics::PixelFormat::createFormatCLUT8()); createFont(); - - struct PixelPos rel = getPixelPos(0, 191); - struct PixelPos absy; - for (int i = 191; i >= 0; --i) { - absy = getPixelPos(0, i); - if (absy.rowAddr != rel.rowAddr) - debug("%i: %04x %04x", i, absy.rowAddr, rel.rowAddr); - moveY(rel, false); - } - absy = getPixelPos(0, 191); - if (absy.rowAddr != rel.rowAddr) - debug("%i: %04x %04x", 191, absy.rowAddr, rel.rowAddr); - - rel = getPixelPos(0, 0); - for (int i = 0; i < 192; ++i) { - absy = getPixelPos(0, i); - if (absy.rowAddr != rel.rowAddr) - debug("%i: %04x %04x", i, absy.rowAddr, rel.rowAddr); - moveY(rel, true); - } - absy = getPixelPos(0, 0); - if (absy.rowAddr != rel.rowAddr) - debug("%i: %04x %04x", 191, absy.rowAddr, rel.rowAddr); } Display::~Display() { -- cgit v1.2.3 From 727469d4a7ad9ba516538009efdac3834a6daccd Mon Sep 17 00:00:00 2001 From: Walter van Niftrik Date: Sun, 28 Feb 2016 21:44:23 +0100 Subject: ADL: Add restarting --- engines/adl/adl.cpp | 11 ++++++++--- engines/adl/adl.h | 3 +++ engines/adl/hires1.cpp | 23 ++++++++++++++++++++++- engines/adl/hires1.h | 1 + 4 files changed, 34 insertions(+), 4 deletions(-) (limited to 'engines') diff --git a/engines/adl/adl.cpp b/engines/adl/adl.cpp index e395c8266f..24a18d62ac 100644 --- a/engines/adl/adl.cpp +++ b/engines/adl/adl.cpp @@ -43,7 +43,8 @@ AdlEngine::AdlEngine(OSystem *syst, const AdlGameDescription *gd) : Engine(syst), _gameDescription(gd), _display(nullptr), - _parser(nullptr) { + _parser(nullptr), + _isRestarting(false) { } AdlEngine::~AdlEngine() { @@ -271,7 +272,8 @@ void AdlEngine::doActions(const Command &command, byte noun, byte offset) { _display->printString(_strings[IDI_STR_PLAY_AGAIN]); Common::String input = _display->inputString(); if (input.size() == 0 || input[0] != APPLECHAR('N')) { - warning("Restart game not implemented"); + _isRestarting = true; + restartGame(); return; } // Fall-through @@ -392,8 +394,11 @@ bool AdlEngine::doOneCommand(const Commands &commands, byte verb, byte noun) { void AdlEngine::doAllCommands(const Commands &commands, byte verb, byte noun) { Commands::const_iterator cmd; - for (cmd = commands.begin(); cmd != commands.end(); ++cmd) + for (cmd = commands.begin(); cmd != commands.end(); ++cmd) { checkCommand(*cmd, verb, noun); + if (_isRestarting) + return; + } } void AdlEngine::clearScreen() { diff --git a/engines/adl/adl.h b/engines/adl/adl.h index d39e0e3638..8b0aa45937 100644 --- a/engines/adl/adl.h +++ b/engines/adl/adl.h @@ -175,6 +175,8 @@ public: protected: virtual void runGame() = 0; + virtual void initState() = 0; + virtual void restartGame() = 0; virtual uint getEngineMessage(EngineMessage msg) = 0; Common::String readString(Common::ReadStream &stream, byte until = 0); void printStrings(Common::SeekableReadStream &stream, int count = 1); @@ -194,6 +196,7 @@ protected: Display *_display; Parser *_parser; + bool _isRestarting; Common::Array _strings; Common::Array _messages; diff --git a/engines/adl/hires1.cpp b/engines/adl/hires1.cpp index 1316bf2d70..4cf7b4599d 100644 --- a/engines/adl/hires1.cpp +++ b/engines/adl/hires1.cpp @@ -56,6 +56,7 @@ enum { IDI_HR1_STR_DONT_HAVE_IT, IDI_HR1_STR_DONT_UNDERSTAND, IDI_HR1_STR_GETTING_DARK, + IDI_HR1_STR_PRESS_RETURN, IDI_HR1_STR_TOTAL }; @@ -69,7 +70,8 @@ static const StringOffset stringOffsets[] = { { IDI_HR1_STR_CANT_GO_THERE, 0x6c0a }, { IDI_HR1_STR_DONT_HAVE_IT, 0x6c31 }, { IDI_HR1_STR_DONT_UNDERSTAND, 0x6c51 }, - { IDI_HR1_STR_GETTING_DARK, 0x6c7c } + { IDI_HR1_STR_GETTING_DARK, 0x6c7c }, + { IDI_HR1_STR_PRESS_RETURN, 0x5f68 } }; #define IDI_HR1_OFS_PD_TEXT_0 0x5d @@ -268,6 +270,13 @@ void HiRes1Engine::initState() { } } +void HiRes1Engine::restartGame() { + initState(); + _display->printString(_strings[IDI_HR1_STR_PRESS_RETURN]); + _display->inputString(); // Missing in the original + _display->printASCIIString("\r\r\r\r\r"); +} + void HiRes1Engine::runGame() { runIntro(); _display->printASCIIString("\r"); @@ -348,7 +357,12 @@ void HiRes1Engine::runGame() { f.seek(0xf00); _parser->loadNouns(f); + _display->printASCIIString("\r\r\r\r\r"); + while (1) { + if (_isRestarting) + _isRestarting = false; + uint verb = 0, noun = 0; clearScreen(); showRoom(); @@ -356,8 +370,15 @@ void HiRes1Engine::runGame() { if (!doOneCommand(_roomCommands, verb, noun)) printMessage(37); + + if (_isRestarting) + continue; + doAllCommands(_globalCommands, verb, noun); + if (_isRestarting) + continue; + _state.moves++; if (shouldQuit()) diff --git a/engines/adl/hires1.h b/engines/adl/hires1.h index 5cc9f3ac98..a378dc9423 100644 --- a/engines/adl/hires1.h +++ b/engines/adl/hires1.h @@ -49,6 +49,7 @@ private: MH_ITEM_OFFSETS = 21 }; + void restartGame(); void printMessage(uint idx, bool wait = true); uint getEngineMessage(EngineMessage msg); -- cgit v1.2.3 From e3d13d06ee32fa1cb3663c0e9c46f356f08b5c9b Mon Sep 17 00:00:00 2001 From: Walter van Niftrik Date: Mon, 29 Feb 2016 00:32:47 +0100 Subject: ADL: Add save game support --- engines/adl/adl.cpp | 118 ++++++++++++++++++++++++++++++++++++++++++++++++++- engines/adl/adl.h | 6 +++ engines/adl/hires1.h | 1 + 3 files changed, 123 insertions(+), 2 deletions(-) (limited to 'engines') diff --git a/engines/adl/adl.cpp b/engines/adl/adl.cpp index 24a18d62ac..9c86b3a022 100644 --- a/engines/adl/adl.cpp +++ b/engines/adl/adl.cpp @@ -28,6 +28,7 @@ #include "common/system.h" #include "common/events.h" #include "common/stream.h" +#include "common/savefile.h" #include "engines/util.h" @@ -261,18 +262,21 @@ void AdlEngine::doActions(const Command &command, byte noun, byte offset) { ++offset; break; case IDO_ACT_SAVE: - warning("Save game not implemented"); + saveState(0); ++offset; break; case IDO_ACT_LOAD: - warning("Load game not implemented"); + loadState(0); ++offset; + // Original engine continues processing here (?) break; case IDO_ACT_RESTART: { _display->printString(_strings[IDI_STR_PLAY_AGAIN]); Common::String input = _display->inputString(); if (input.size() == 0 || input[0] != APPLECHAR('N')) { _isRestarting = true; + _display->clear(0x00); + _display->decodeFrameBuffer(); restartGame(); return; } @@ -451,6 +455,116 @@ void AdlEngine::showRoom() { printMessage(_state.rooms[_state.room].description, false); } +bool AdlEngine::saveState(uint slot) { + Common::String fileName = Common::String::format("%s.s%02d", _targetName.c_str(), slot); + Common::OutSaveFile *outFile = getSaveFileManager()->openForSaving(fileName); + + if (!outFile) { + warning("Failed to open file '%s'", fileName.c_str()); + return false; + } + + outFile->writeUint32BE(getTag()); + outFile->writeByte(SAVEGAME_VERSION); + + outFile->writeByte(_state.room); + outFile->writeByte(_state.moves); + outFile->writeByte(_state.isDark); + + outFile->writeUint32BE(_state.rooms.size()); + for (uint i = 0; i < _state.rooms.size(); ++i) { + outFile->writeByte(_state.rooms[i].picture); + outFile->writeByte(_state.rooms[i].curPicture); + } + + outFile->writeUint32BE(_state.items.size()); + for (uint i = 0; i < _state.items.size(); ++i) { + outFile->writeByte(_state.items[i].room); + outFile->writeByte(_state.items[i].picture); + outFile->writeByte(_state.items[i].position.x); + outFile->writeByte(_state.items[i].position.y); + outFile->writeByte(_state.items[i].state); + } + + outFile->writeUint32BE(_state.vars.size()); + for (uint i = 0; i < _state.vars.size(); ++i) + outFile->writeByte(_state.vars[i]); + + outFile->finalize(); + + if (outFile->err()) { + delete outFile; + warning("Failed to save game '%s'", fileName.c_str()); + return false; + } + + delete outFile; + return true; +} + +bool AdlEngine::loadState(uint slot) { + Common::String fileName = Common::String::format("%s.s%02d", _targetName.c_str(), slot); + Common::InSaveFile *inFile = getSaveFileManager()->openForLoading(fileName); + + if (!inFile) { + warning("Failed to open file '%s'", fileName.c_str()); + return false; + } + + if (inFile->readUint32BE() != getTag()) { + warning("No header found in '%s'", fileName.c_str()); + delete inFile; + return false; + } + + byte saveVersion = inFile->readByte(); + if (saveVersion != SAVEGAME_VERSION) { + warning("Save game version %i not supported", saveVersion); + delete inFile; + return false; + } + + initState(); + + _state.room = inFile->readByte(); + _state.moves = inFile->readByte(); + _state.isDark = inFile->readByte(); + + uint32 size = inFile->readUint32BE(); + if (size != _state.rooms.size()) + error("Room count mismatch (expected %i; found %i)", _state.rooms.size(), size); + + for (uint i = 0; i < size; ++i) { + _state.rooms[i].picture = inFile->readByte(); + _state.rooms[i].curPicture = inFile->readByte(); + } + + size = inFile->readUint32BE(); + if (size != _state.items.size()) + error("Item count mismatch (expected %i; found %i)", _state.items.size(), size); + + for (uint i = 0; i < size; ++i) { + _state.items[i].room = inFile->readByte(); + _state.items[i].picture = inFile->readByte(); + _state.items[i].position.x = inFile->readByte(); + _state.items[i].position.y = inFile->readByte(); + _state.items[i].state = inFile->readByte(); + } + + size = inFile->readUint32BE(); + if (size != _state.vars.size()) + error("Variable count mismatch (expected %i; found %i)", _state.vars.size(), size); + + for (uint i = 0; i < size; ++i) + _state.vars[i] = inFile->readByte(); + + if (inFile->err() || inFile->eos()) + error("Failed to load game '%s'", fileName.c_str()); + + delete inFile; + return true; +} + AdlEngine *AdlEngine::create(GameType type, OSystem *syst, const AdlGameDescription *gd) { switch(type) { case kGameTypeHires1: diff --git a/engines/adl/adl.h b/engines/adl/adl.h index 8b0aa45937..abb62ee8b2 100644 --- a/engines/adl/adl.h +++ b/engines/adl/adl.h @@ -37,6 +37,8 @@ class SeekableReadStream; namespace Adl { +#define SAVEGAME_VERSION 0 + class Display; class Parser; class Console; @@ -178,6 +180,7 @@ protected: virtual void initState() = 0; virtual void restartGame() = 0; virtual uint getEngineMessage(EngineMessage msg) = 0; + virtual uint32 getTag() = 0; Common::String readString(Common::ReadStream &stream, byte until = 0); void printStrings(Common::SeekableReadStream &stream, int count = 1); virtual void printMessage(uint idx, bool wait = true); @@ -211,6 +214,9 @@ protected: private: void printEngineMessage(EngineMessage); + bool saveState(uint slot); + bool loadState(uint slot); + Common::String getTargetName() { return _targetName; } }; AdlEngine *HiRes1Engine__create(OSystem *syst, const AdlGameDescription *gd); diff --git a/engines/adl/hires1.h b/engines/adl/hires1.h index a378dc9423..ab26b2c87d 100644 --- a/engines/adl/hires1.h +++ b/engines/adl/hires1.h @@ -52,6 +52,7 @@ private: void restartGame(); void printMessage(uint idx, bool wait = true); uint getEngineMessage(EngineMessage msg); + uint32 getTag() { return MKTAG('H', 'R', 'A', '1'); } void initState(); void runIntro(); -- cgit v1.2.3 From e1fb5853576d8b0c05710ad70e22e10254467153 Mon Sep 17 00:00:00 2001 From: Walter van Niftrik Date: Mon, 29 Feb 2016 09:31:59 +0100 Subject: ADL: Use #define instead of literal --- engines/adl/adl.cpp | 2 +- engines/adl/hires1.cpp | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'engines') diff --git a/engines/adl/adl.cpp b/engines/adl/adl.cpp index 9c86b3a022..711e538f3b 100644 --- a/engines/adl/adl.cpp +++ b/engines/adl/adl.cpp @@ -306,7 +306,7 @@ void AdlEngine::doActions(const Command &command, byte noun, byte offset) { case IDO_ACT_GO_WEST: case IDO_ACT_GO_UP: case IDO_ACT_GO_DOWN: { - byte room = _state.rooms[_state.room].connections[ARG(0) - 0x15]; + byte room = _state.rooms[_state.room].connections[ARG(0) - IDO_ACT_GO_NORTH]; if (room == 0) { printEngineMessage(IDI_MSG_CANT_GO_THERE); diff --git a/engines/adl/hires1.cpp b/engines/adl/hires1.cpp index 4cf7b4599d..dac6d4c9cb 100644 --- a/engines/adl/hires1.cpp +++ b/engines/adl/hires1.cpp @@ -155,9 +155,9 @@ void HiRes1Engine::runIntro() { _display->setMode(Display::kModeText); file.seek(IDI_HR1_OFS_INTRO_TEXT); - const int pages[] = { 6, 6, 4, 5, 8, 7, 0 }; + const uint pages[] = { 6, 6, 4, 5, 8, 7, 0 }; - int page = 0; + uint page = 0; while (pages[page] != 0) { _display->home(); printStrings(file, pages[page++]); -- cgit v1.2.3 From 475eb0cc95c46be651d15de8eb1c0f42a2921c6a Mon Sep 17 00:00:00 2001 From: Walter van Niftrik Date: Mon, 29 Feb 2016 09:32:22 +0100 Subject: ADL: Fix bug in item taking --- engines/adl/adl.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'engines') diff --git a/engines/adl/adl.cpp b/engines/adl/adl.cpp index 711e538f3b..1847f7f32c 100644 --- a/engines/adl/adl.cpp +++ b/engines/adl/adl.cpp @@ -178,7 +178,7 @@ void AdlEngine::takeItem(byte noun) { } Common::Array::const_iterator pic; - for (pic = item->roomPictures.begin(); item->roomPictures.end(); ++pic) { + for (pic = item->roomPictures.begin(); pic != item->roomPictures.end(); ++pic) { if (*pic == _state.rooms[_state.room].curPicture) { item->room = IDI_NONE; item->state = IDI_ITEM_MOVED; -- cgit v1.2.3 From 9928e51bd73985f48c8378308a278fff433eaae1 Mon Sep 17 00:00:00 2001 From: Walter van Niftrik Date: Mon, 29 Feb 2016 11:54:57 +0100 Subject: ADL: Add functions to adjust for 1-based arrays --- engines/adl/adl.cpp | 75 +++++++++++++++++++++++++++++++++----------------- engines/adl/adl.h | 4 +++ engines/adl/hires1.cpp | 2 +- engines/adl/hires1.h | 2 +- 4 files changed, 56 insertions(+), 27 deletions(-) (limited to 'engines') diff --git a/engines/adl/adl.cpp b/engines/adl/adl.cpp index 1847f7f32c..be9067881f 100644 --- a/engines/adl/adl.cpp +++ b/engines/adl/adl.cpp @@ -179,7 +179,7 @@ void AdlEngine::takeItem(byte noun) { Common::Array::const_iterator pic; for (pic = item->roomPictures.begin(); pic != item->roomPictures.end(); ++pic) { - if (*pic == _state.rooms[_state.room].curPicture) { + if (*pic == curRoom().curPicture) { item->room = IDI_NONE; item->state = IDI_ITEM_MOVED; return; @@ -211,15 +211,15 @@ void AdlEngine::doActions(const Command &command, byte noun, byte offset) { for (uint i = 0; i < command.numAct; ++i) { switch (ARG(0)) { case IDO_ACT_VAR_ADD: - _state.vars[ARG(2)] += ARG(1); + var(ARG(2)) += ARG(1); offset += 3; break; case IDO_ACT_VAR_SUB: - _state.vars[ARG(2)] -= ARG(1); + var(ARG(2)) -= ARG(1); offset += 3; break; case IDO_ACT_VAR_SET: - _state.vars[ARG(1)] = ARG(2); + var(ARG(1)) = ARG(2); offset += 3; break; case IDO_ACT_LIST_ITEMS: { @@ -233,20 +233,20 @@ void AdlEngine::doActions(const Command &command, byte noun, byte offset) { break; } case IDO_ACT_MOVE_ITEM: - _state.items[ARG(1) - 1].room = ARG(2); + item(ARG(1)).room = ARG(2); offset += 3; break; case IDO_ACT_SET_ROOM: - _state.rooms[_state.room].curPicture = _state.rooms[_state.room].picture; + curRoom().curPicture = curRoom().picture; _state.room = ARG(1); offset += 2; break; case IDO_ACT_SET_CUR_PIC: - _state.rooms[_state.room].curPicture = ARG(1); + curRoom().curPicture = ARG(1); offset += 2; break; case IDO_ACT_SET_PIC: - _state.rooms[_state.room].picture = _state.rooms[_state.room].curPicture = ARG(1); + curRoom().picture = curRoom().curPicture = ARG(1); offset += 2; break; case IDO_ACT_PRINT_MSG: @@ -287,17 +287,17 @@ void AdlEngine::doActions(const Command &command, byte noun, byte offset) { quitGame(); return; case IDO_ACT_PLACE_ITEM: - _state.items[ARG(1) - 1].room = ARG(2); - _state.items[ARG(1) - 1].position.x = ARG(3); - _state.items[ARG(1) - 1].position.y = ARG(4); + item(ARG(1)).room = ARG(2); + item(ARG(1)).position.x = ARG(3); + item(ARG(1)).position.y = ARG(4); offset += 5; break; case IDO_ACT_SET_ITEM_PIC: - _state.items[ARG(2) - 1].picture = ARG(1); + item(ARG(2)).picture = ARG(1); offset += 3; break; case IDO_ACT_RESET_PIC: - _state.rooms[_state.room].curPicture = _state.rooms[_state.room].picture; + curRoom().curPicture = curRoom().picture; ++offset; break; case IDO_ACT_GO_NORTH: @@ -306,14 +306,14 @@ void AdlEngine::doActions(const Command &command, byte noun, byte offset) { case IDO_ACT_GO_WEST: case IDO_ACT_GO_UP: case IDO_ACT_GO_DOWN: { - byte room = _state.rooms[_state.room].connections[ARG(0) - IDO_ACT_GO_NORTH]; + byte room = curRoom().connections[ARG(0) - IDO_ACT_GO_NORTH]; if (room == 0) { printEngineMessage(IDI_MSG_CANT_GO_THERE); return; } - _state.rooms[_state.room].curPicture = _state.rooms[_state.room].picture; + curRoom().curPicture = curRoom().picture; _state.room = room; return; } @@ -326,7 +326,7 @@ void AdlEngine::doActions(const Command &command, byte noun, byte offset) { ++offset; break; case IDO_ACT_SET_ROOM_PIC: - _state.rooms[ARG(1)].picture = _state.rooms[ARG(1)].curPicture = ARG(2); + room(ARG(1)).picture = room(ARG(1)).curPicture = ARG(2); offset += 3; break; default: @@ -347,9 +347,9 @@ bool AdlEngine::checkCommand(const Command &command, byte verb, byte noun) { uint offset = 0; for (uint i = 0; i < command.numCond; ++i) { - switch (command.script[offset]) { + switch (ARG(0)) { case IDO_CND_ITEM_IN_ROOM: - if (_state.items[ARG(1) - 1].room != ARG(2)) + if (item(ARG(1)).room != ARG(2)) return false; offset += 3; break; @@ -359,17 +359,17 @@ bool AdlEngine::checkCommand(const Command &command, byte verb, byte noun) { offset += 2; break; case IDO_CND_VAR_EQ: - if (_state.vars[ARG(1)] != ARG(2)) + if (var(ARG(1)) != ARG(2)) return false; offset += 3; break; case IDO_CND_CUR_PIC_EQ: - if (_state.rooms[_state.room].curPicture != ARG(1)) + if (curRoom().curPicture != ARG(1)) return false; offset += 2; break; case IDO_CND_ITEM_PIC_EQ: - if (_state.items[ARG(1) - 1].picture != ARG(2)) + if (item(ARG(1)).picture != ARG(2)) return false; offset += 3; break; @@ -420,7 +420,7 @@ void AdlEngine::drawItems() { continue; if (item->state == IDI_ITEM_MOVED) { - if (_state.rooms[_state.room].picture == _state.rooms[_state.room].curPicture) { + if (curRoom().picture == curRoom().curPicture) { const Common::Point &p = _itemOffsets[dropped]; if (item->isLineArt) _display->drawLineArt(_lineArt[item->picture - 1], p); @@ -434,7 +434,7 @@ void AdlEngine::drawItems() { Common::Array::const_iterator pic; for (pic = item->roomPictures.begin(); pic != item->roomPictures.end(); ++pic) { - if (*pic == _state.rooms[_state.room].curPicture) { + if (*pic == curRoom().curPicture) { if (item->isLineArt) _display->drawLineArt(_lineArt[item->picture - 1], item->position); else @@ -447,12 +447,12 @@ void AdlEngine::drawItems() { void AdlEngine::showRoom() { if (!_state.isDark) { - drawPic(_state.rooms[_state.room].curPicture); + drawPic(curRoom().curPicture); drawItems(); } _display->decodeFrameBuffer(); - printMessage(_state.rooms[_state.room].description, false); + printMessage(curRoom().description, false); } bool AdlEngine::saveState(uint slot) { @@ -565,6 +565,31 @@ bool AdlEngine::loadState(uint slot) { return true; } +Room &AdlEngine::room(uint i) { + if (i < 1 || i > _state.rooms.size()) + error("Room %i out of range [1, %i]", i, _state.rooms.size()); + + return _state.rooms[i - 1]; +} + +Room &AdlEngine::curRoom() { + return room(_state.room); +} + +Item &AdlEngine::item(uint i) { + if (i < 1 || i > _state.items.size()) + error("Item %i out of range [1, %i]", i, _state.items.size()); + + return _state.items[i - 1]; +} + +byte &AdlEngine::var(uint i) { + if (i >= _state.vars.size()) + error("Variable %i out of range [0, %i]", i, _state.vars.size() - 1); + + return _state.vars[i]; +} + AdlEngine *AdlEngine::create(GameType type, OSystem *syst, const AdlGameDescription *gd) { switch(type) { case kGameTypeHires1: diff --git a/engines/adl/adl.h b/engines/adl/adl.h index abb62ee8b2..b7fd3dc410 100644 --- a/engines/adl/adl.h +++ b/engines/adl/adl.h @@ -196,6 +196,10 @@ protected: void showRoom(); void takeItem(byte noun); void dropItem(byte noun); + Room &room(uint i); + Room &curRoom(); + Item &item(uint i); + byte &var(uint i); Display *_display; Parser *_parser; diff --git a/engines/adl/hires1.cpp b/engines/adl/hires1.cpp index dac6d4c9cb..45a011ad63 100644 --- a/engines/adl/hires1.cpp +++ b/engines/adl/hires1.cpp @@ -233,7 +233,7 @@ void HiRes1Engine::initState() { // Load room data from executable _state.rooms.clear(); - f.seek(1280); + f.seek(0x50a); for (uint i = 0; i < MH_ROOMS; ++i) { Room room; f.readByte(); diff --git a/engines/adl/hires1.h b/engines/adl/hires1.h index ab26b2c87d..247625cba7 100644 --- a/engines/adl/hires1.h +++ b/engines/adl/hires1.h @@ -44,7 +44,7 @@ protected: private: enum { - MH_ROOMS = 42, + MH_ROOMS = 41, MH_PICS = 98, MH_ITEM_OFFSETS = 21 }; -- cgit v1.2.3 From ba54955bffec15ed95aa1ca1ec955aecaa315478 Mon Sep 17 00:00:00 2001 From: Walter van Niftrik Date: Mon, 29 Feb 2016 16:50:24 +0100 Subject: ADL: Add loading from launcher --- engines/adl/adl.cpp | 30 +++++++++++++++++++++--- engines/adl/adl.h | 5 ++-- engines/adl/detection.cpp | 57 ++++++++++++++++++++++++++++++++++++++++++++ engines/adl/display.cpp | 4 ++++ engines/adl/display.h | 1 + engines/adl/hires1.cpp | 60 ++++++++++++++++++++++++++++------------------- engines/adl/hires1.h | 1 - 7 files changed, 128 insertions(+), 30 deletions(-) (limited to 'engines') diff --git a/engines/adl/adl.cpp b/engines/adl/adl.cpp index be9067881f..ab05c40b69 100644 --- a/engines/adl/adl.cpp +++ b/engines/adl/adl.cpp @@ -70,6 +70,16 @@ Common::Error AdlEngine::run() { _display = new Display(); _parser = new Parser(*this, *_display); + int saveSlot = ConfMan.getInt("save_slot"); + if (saveSlot >= 0) { + if (!loadState(saveSlot)) + error("Failed to load save game from slot %i", saveSlot); + _display->setCursorPos(Common::Point(0, 23)); + } else { + runIntro(); + initState(); + } + runGame(); return Common::kNoError; @@ -455,7 +465,7 @@ void AdlEngine::showRoom() { printMessage(curRoom().description, false); } -bool AdlEngine::saveState(uint slot) { +bool AdlEngine::saveState(uint slot, const Common::String *description) { Common::String fileName = Common::String::format("%s.s%02d", _targetName.c_str(), slot); Common::OutSaveFile *outFile = getSaveFileManager()->openForSaving(fileName); @@ -464,9 +474,21 @@ bool AdlEngine::saveState(uint slot) { return false; } - outFile->writeUint32BE(getTag()); + outFile->writeUint32BE(MKTAG('A', 'D', 'L', ':')); outFile->writeByte(SAVEGAME_VERSION); + char name[SAVEGAME_NAME_LEN] = { }; + + if (description) + strncpy(name, description->c_str(), sizeof(name) - 1); + else { + Common::String defaultName("Save "); + defaultName += 'A' + slot; + strncpy(name, defaultName.c_str(), sizeof(name) - 1); + } + + outFile->write(name, sizeof(name)); + outFile->writeByte(_state.room); outFile->writeByte(_state.moves); outFile->writeByte(_state.isDark); @@ -511,7 +533,7 @@ bool AdlEngine::loadState(uint slot) { return false; } - if (inFile->readUint32BE() != getTag()) { + if (inFile->readUint32BE() != MKTAG('A', 'D', 'L', ':')) { warning("No header found in '%s'", fileName.c_str()); delete inFile; return false; @@ -526,6 +548,8 @@ bool AdlEngine::loadState(uint slot) { initState(); + inFile->seek(SAVEGAME_NAME_LEN, SEEK_CUR); + _state.room = inFile->readByte(); _state.moves = inFile->readByte(); _state.isDark = inFile->readByte(); diff --git a/engines/adl/adl.h b/engines/adl/adl.h index b7fd3dc410..9955b0d79a 100644 --- a/engines/adl/adl.h +++ b/engines/adl/adl.h @@ -38,6 +38,7 @@ class SeekableReadStream; namespace Adl { #define SAVEGAME_VERSION 0 +#define SAVEGAME_NAME_LEN 32 class Display; class Parser; @@ -176,11 +177,11 @@ public: virtual Common::String getEngineString(int str); protected: + virtual void runIntro() { } virtual void runGame() = 0; virtual void initState() = 0; virtual void restartGame() = 0; virtual uint getEngineMessage(EngineMessage msg) = 0; - virtual uint32 getTag() = 0; Common::String readString(Common::ReadStream &stream, byte until = 0); void printStrings(Common::SeekableReadStream &stream, int count = 1); virtual void printMessage(uint idx, bool wait = true); @@ -218,7 +219,7 @@ protected: private: void printEngineMessage(EngineMessage); - bool saveState(uint slot); + bool saveState(uint slot, const Common::String *description = nullptr); bool loadState(uint slot); Common::String getTargetName() { return _targetName; } }; diff --git a/engines/adl/detection.cpp b/engines/adl/detection.cpp index 9fadb9d3d7..5fe469d20f 100644 --- a/engines/adl/detection.cpp +++ b/engines/adl/detection.cpp @@ -20,6 +20,9 @@ * */ +#include "common/system.h" +#include "common/savefile.h" + #include "engines/advancedDetector.h" #include "adl/adl.h" @@ -69,9 +72,63 @@ public: return "Copyright (C) Sierra On-Line"; } + bool hasFeature(MetaEngineFeature f) const; + int getMaximumSaveSlot() const { return 15; } + SaveStateList listSaves(const char *target) const; + bool createInstance(OSystem *syst, Engine **engine, const ADGameDescription *gd) const; }; +bool AdlMetaEngine::hasFeature(MetaEngineFeature f) const { + switch(f) { + case kSupportsListSaves: + case kSupportsLoadingDuringStartup: + return true; + default: + return false; + } +} + +SaveStateList AdlMetaEngine::listSaves(const char *target) const { + Common::SaveFileManager *saveFileMan = g_system->getSavefileManager(); + Common::StringArray files = saveFileMan->listSavefiles(Common::String(target) + ".s##"); + + SaveStateList saveList; + for (uint i = 0; i < files.size(); ++i) { + const Common::String &fileName = files[i]; + Common::InSaveFile *inFile = saveFileMan->openForLoading(fileName); + if (!inFile) { + warning("Cannot open save file %s", fileName.c_str()); + continue; + } + + if (inFile->readUint32BE() != MKTAG('A', 'D', 'L', ':')) { + warning("No header found in '%s'", fileName.c_str()); + delete inFile; + continue; + } + + byte saveVersion = inFile->readByte(); + if (saveVersion != SAVEGAME_VERSION) { + warning("Save game version %i not supported in '%s'", saveVersion, fileName.c_str()); + delete inFile; + continue; + } + + char name[SAVEGAME_NAME_LEN] = { }; + inFile->read(name, sizeof(name) - 1); + delete inFile; + + int slotNum = atoi(fileName.c_str() + fileName.size() - 2); + SaveStateDescriptor sd(slotNum, name); + saveList.push_back(sd); + } + + // Sort saves based on slot number. + Common::sort(saveList.begin(), saveList.end(), SaveStateDescriptorSlotComparator()); + return saveList; +} + bool AdlMetaEngine::createInstance(OSystem *syst, Engine **engine, const ADGameDescription *gd) const { if (gd) *engine = AdlEngine::create(((const AdlGameDescription *)gd)->gameType, syst, (const AdlGameDescription *)gd); diff --git a/engines/adl/display.cpp b/engines/adl/display.cpp index 05e7c2e67c..ffb98c4a1b 100644 --- a/engines/adl/display.cpp +++ b/engines/adl/display.cpp @@ -585,4 +585,8 @@ void Display::home() { _cursorPos = 0; } +void Display::setCursorPos(Common::Point pos) { + _cursorPos = pos.y * 40 + pos.x; +} + } // End of namespace Adl diff --git a/engines/adl/display.h b/engines/adl/display.h index 229446f447..91d8b0ec97 100644 --- a/engines/adl/display.h +++ b/engines/adl/display.h @@ -64,6 +64,7 @@ public: void drawLine(Common::Point p1, Common::Point p2, byte color); void clear(byte color); void drawLineArt(const Common::Array &lineArt, Common::Point p, byte rotation = 0, byte scaling = 1, byte color = 0x7f); + void setCursorPos(Common::Point pos); private: enum { diff --git a/engines/adl/hires1.cpp b/engines/adl/hires1.cpp index 45a011ad63..ba6f19a8e4 100644 --- a/engines/adl/hires1.cpp +++ b/engines/adl/hires1.cpp @@ -136,6 +136,8 @@ void HiRes1Engine::runIntro() { file.seek(IDI_HR1_OFS_GAME_OR_HELP); str = readString(file); + bool instructions = false; + while (1) { _display->printString(str); Common::String s = _display->inputString(); @@ -146,28 +148,47 @@ void HiRes1Engine::runIntro() { if (s.empty()) continue; - if ((byte)s[0] == ('I' | 0x80)) + if (s[0] == APPLECHAR('I')) { + instructions = true; break; - else if ((byte)s[0] == ('G' | 0x80)) - return; + } else if (s[0] == APPLECHAR('G')) { + break; + } }; - _display->setMode(Display::kModeText); - file.seek(IDI_HR1_OFS_INTRO_TEXT); + if (instructions) { + _display->setMode(Display::kModeText); + file.seek(IDI_HR1_OFS_INTRO_TEXT); - const uint pages[] = { 6, 6, 4, 5, 8, 7, 0 }; + const uint pages[] = { 6, 6, 4, 5, 8, 7, 0 }; - uint page = 0; - while (pages[page] != 0) { - _display->home(); - printStrings(file, pages[page++]); - _display->inputString(); + uint page = 0; + while (pages[page] != 0) { + _display->home(); + printStrings(file, pages[page++]); + _display->inputString(); - if (g_engine->shouldQuit()) - return; + if (g_engine->shouldQuit()) + return; - file.seek(9, SEEK_CUR); + file.seek(9, SEEK_CUR); + } } + + _display->printASCIIString("\r"); + + file.close(); + + _display->setMode(Display::kModeMixed); + + if (!file.open("ADVENTURE")) + error("Failed to open file"); + + // Title screen shown during loading + file.seek(0x1800); + _display->loadFrameBuffer(file); + _display->decodeFrameBuffer(); + _display->delay(2000); } void HiRes1Engine::drawPic(Common::ReadStream &stream, Common::Point pos) { @@ -278,8 +299,7 @@ void HiRes1Engine::restartGame() { } void HiRes1Engine::runGame() { - runIntro(); - _display->printASCIIString("\r"); + _display->setMode(Display::kModeMixed); Common::File f; @@ -291,8 +311,6 @@ void HiRes1Engine::runGame() { f.close(); - initState(); - if (!f.open("ADVENTURE")) error("Failed to open file"); @@ -345,12 +363,6 @@ void HiRes1Engine::runGame() { _lineArt.push_back(lineArt); } - // Title screen shown during loading - f.seek(0x1800); - _display->loadFrameBuffer(f); - _display->decodeFrameBuffer(); - _display->delay(2000); - f.seek(0x3800); _parser->loadVerbs(f); diff --git a/engines/adl/hires1.h b/engines/adl/hires1.h index 247625cba7..897327cdbf 100644 --- a/engines/adl/hires1.h +++ b/engines/adl/hires1.h @@ -52,7 +52,6 @@ private: void restartGame(); void printMessage(uint idx, bool wait = true); uint getEngineMessage(EngineMessage msg); - uint32 getTag() { return MKTAG('H', 'R', 'A', '1'); } void initState(); void runIntro(); -- cgit v1.2.3 From 339d3bc86813b454447b02481f82b85c4c8be75b Mon Sep 17 00:00:00 2001 From: Walter van Niftrik Date: Tue, 1 Mar 2016 15:47:34 +0100 Subject: ADL: Move input code into AdlEngine --- engines/adl/adl.cpp | 261 ++++++++++++++++++++++++++++++++++++++++++++++-- engines/adl/adl.h | 20 ++++ engines/adl/display.cpp | 178 +++++++++------------------------ engines/adl/display.h | 20 ++-- engines/adl/hires1.cpp | 33 +++--- engines/adl/module.mk | 3 +- engines/adl/parser.cpp | 168 ------------------------------- engines/adl/parser.h | 66 ------------ 8 files changed, 349 insertions(+), 400 deletions(-) delete mode 100644 engines/adl/parser.cpp delete mode 100644 engines/adl/parser.h (limited to 'engines') diff --git a/engines/adl/adl.cpp b/engines/adl/adl.cpp index ab05c40b69..3c405b67b5 100644 --- a/engines/adl/adl.cpp +++ b/engines/adl/adl.cpp @@ -36,7 +36,6 @@ #include "adl/adl.h" #include "adl/display.h" -#include "adl/parser.h" namespace Adl { @@ -44,12 +43,10 @@ AdlEngine::AdlEngine(OSystem *syst, const AdlGameDescription *gd) : Engine(syst), _gameDescription(gd), _display(nullptr), - _parser(nullptr), _isRestarting(false) { } AdlEngine::~AdlEngine() { - delete _parser; delete _display; } @@ -68,7 +65,6 @@ Common::Error AdlEngine::run() { g_system->getPaletteManager()->setPalette(palette, 0, 6); _display = new Display(); - _parser = new Parser(*this, *_display); int saveSlot = ConfMan.getInt("save_slot"); if (saveSlot >= 0) { @@ -137,7 +133,7 @@ void AdlEngine::printMessage(uint idx, bool wait) { _display->printString(msg); if (wait) - _display->delay(14 * 166018 / 1000); + delay(14 * 166018 / 1000); } void AdlEngine::printEngineMessage(EngineMessage msg) { @@ -282,7 +278,7 @@ void AdlEngine::doActions(const Command &command, byte noun, byte offset) { break; case IDO_ACT_RESTART: { _display->printString(_strings[IDI_STR_PLAY_AGAIN]); - Common::String input = _display->inputString(); + Common::String input = inputString(); if (input.size() == 0 || input[0] != APPLECHAR('N')) { _isRestarting = true; _display->clear(0x00); @@ -614,6 +610,259 @@ byte &AdlEngine::var(uint i) { return _state.vars[i]; } +void AdlEngine::loadWords(Common::ReadStream &stream, WordMap &map) { + uint index = 0; + + while (1) { + ++index; + + byte buf[kWordSize]; + + if (stream.read(buf, kWordSize) < kWordSize) + error("Error reading word list"); + + Common::String word((char *)buf, kWordSize); + + if (!map.contains(word)) + map[word] = index; + + byte synonyms = stream.readByte(); + + if (stream.err() || stream.eos()) + error("Error reading word list"); + + if (synonyms == 0xff) + break; + + for (uint i = 0; i < synonyms; ++i) { + if (stream.read((char *)buf, kWordSize) < kWordSize) + error("Error reading word list"); + + word = Common::String((char *)buf, kWordSize); + + if (!map.contains(word)) + map[word] = index; + } + } +} + +Common::String AdlEngine::getLine() { + // Original engine uses a global here, which isn't reset between + // calls and may not match actual mode + bool textMode = false; + + while (1) { + Common::String line = inputString(APPLECHAR('?')); + + if (shouldQuit()) + return ""; + + if ((byte)line[0] == ('\r' | 0x80)) { + textMode = !textMode; + _display->setMode(textMode ? Display::kModeText : Display::kModeMixed); + continue; + } + + // Remove the return + line.deleteLastChar(); + return line; + } +} + +Common::String AdlEngine::getWord(const Common::String &line, uint &index) { + Common::String str; + + for (uint i = 0; i < 8; ++i) + str += APPLECHAR(' '); + + int copied = 0; + + // Skip initial whitespace + while (1) { + if (index == line.size()) + return str; + if (line[index] != APPLECHAR(' ')) + break; + ++index; + } + + // Copy up to 8 characters + while (1) { + if (copied < 8) + str.setChar(line[index], copied++); + + index++; + + if (index == line.size() || line[index] == APPLECHAR(' ')) + return str; + } +} + +void AdlEngine::getInput(uint &verb, uint &noun) { + while (1) { + _display->printString(getEngineString(IDI_STR_ENTER_COMMAND)); + Common::String line = getLine(); + + if (shouldQuit()) + return; + + uint index = 0; + Common::String verbStr = getWord(line, index); + + if (!_verbs.contains(verbStr)) { + Common::String err = getEngineString(IDI_STR_VERB_ERROR); + for (uint i = 0; i < verbStr.size(); ++i) + err.setChar(verbStr[i], i + 19); + _display->printString(err); + continue; + } + + verb = _verbs[verbStr]; + + Common::String nounStr = getWord(line, index); + + if (!_nouns.contains(nounStr)) { + Common::String err = getEngineString(IDI_STR_NOUN_ERROR); + for (uint i = 0; i < verbStr.size(); ++i) + err.setChar(verbStr[i], i + 19); + for (uint i = 0; i < nounStr.size(); ++i) + err.setChar(nounStr[i], i + 30); + _display->printString(err); + continue; + } + + noun = _nouns[nounStr]; + return; + } +} + +void AdlEngine::printASCIIString(const Common::String &str) { + Common::String aStr; + + Common::String::const_iterator it; + for (it = str.begin(); it != str.end(); ++it) + aStr += APPLECHAR(*it); + + _display->printString(aStr); +} + +Common::String AdlEngine::inputString(byte prompt) { + Common::String s; + + if (prompt > 0) + _display->printString(Common::String(prompt)); + + while (1) { + byte b = inputKey(); + + if (g_engine->shouldQuit()) + return 0; + + if (b == 0) + continue; + + if (b == ('\r' | 0x80)) { + s += b; + _display->printString(Common::String(b)); + return s; + } + + if (b < 0xa0) { + switch (b) { + case Common::KEYCODE_BACKSPACE | 0x80: + if (!s.empty()) { + _display->moveCursorBackward(); + _display->setCharAtCursor(APPLECHAR(' ')); + s.deleteLastChar(); + } + break; + }; + } else { + s += b; + _display->printString(Common::String(b)); + } + } +} + +byte AdlEngine::convertKey(uint16 ascii) { + ascii = toupper(ascii); + + if (ascii >= 0x80) + return 0; + + ascii |= 0x80; + + if (ascii >= 0x80 && ascii <= 0xe0) + return ascii; + + return 0; +} + +byte AdlEngine::inputKey() { + Common::EventManager *ev = g_system->getEventManager(); + + byte key = 0; + + _display->showCursor(true); + + while (!g_engine->shouldQuit() && key == 0) { + Common::Event event; + if (ev->pollEvent(event)) { + if (event.type != Common::EVENT_KEYDOWN) + continue; + + if (event.kbd.flags & Common::KBD_CTRL) { + if (event.kbd.keycode == Common::KEYCODE_q) + g_engine->quitGame(); + continue; + } + + switch (event.kbd.keycode) { + case Common::KEYCODE_BACKSPACE: + case Common::KEYCODE_RETURN: + key = convertKey(event.kbd.keycode); + break; + default: + if (event.kbd.ascii >= 0x20 && event.kbd.ascii < 0x80) + key = convertKey(event.kbd.ascii); + }; + } + + _display->updateTextSurface(); + _display->updateScreen(); + g_system->updateScreen(); + g_system->delayMillis(16); + } + + _display->showCursor(false); + + return key; +} + +void AdlEngine::delay(uint32 ms) { + Common::EventManager *ev = g_system->getEventManager(); + + uint32 start = g_system->getMillis(); + + while (!g_engine->shouldQuit() && g_system->getMillis() - start < ms) { + Common::Event event; + if (ev->pollEvent(event)) { + if (event.type == Common::EVENT_KEYDOWN && (event.kbd.flags & Common::KBD_CTRL)) { + switch(event.kbd.keycode) { + case Common::KEYCODE_q: + g_engine->quitGame(); + break; + default: + break; + } + } + } + _display->updateScreen(); + g_system->updateScreen(); + g_system->delayMillis(16); + } +} + AdlEngine *AdlEngine::create(GameType type, OSystem *syst, const AdlGameDescription *gd) { switch(type) { case kGameTypeHires1: diff --git a/engines/adl/adl.h b/engines/adl/adl.h index 9955b0d79a..a9ac79d9f0 100644 --- a/engines/adl/adl.h +++ b/engines/adl/adl.h @@ -177,6 +177,8 @@ public: virtual Common::String getEngineString(int str); protected: + typedef Common::HashMap WordMap; + virtual void runIntro() { } virtual void runGame() = 0; virtual void initState() = 0; @@ -201,6 +203,16 @@ protected: Room &curRoom(); Item &item(uint i); byte &var(uint i); + void loadVerbs(Common::ReadStream &stream) { loadWords(stream, _verbs); } + void loadNouns(Common::ReadStream &stream) { loadWords(stream, _nouns); } + void getInput(uint &verb, uint &noun); + void loadWords(Common::ReadStream &stream, WordMap &map); + Common::String getLine(); + Common::String getWord(const Common::String &line, uint &index); + void printASCIIString(const Common::String &str); + Common::String inputString(byte prompt = 0); + void delay(uint32 ms); + byte inputKey(); Display *_display; Parser *_parser; @@ -222,6 +234,14 @@ private: bool saveState(uint slot, const Common::String *description = nullptr); bool loadState(uint slot); Common::String getTargetName() { return _targetName; } + byte convertKey(uint16 ascii); + + enum { + kWordSize = 8 + }; + + WordMap _verbs; + WordMap _nouns; }; AdlEngine *HiRes1Engine__create(OSystem *syst, const AdlGameDescription *gd); diff --git a/engines/adl/display.cpp b/engines/adl/display.cpp index ffb98c4a1b..a6d94f6e13 100644 --- a/engines/adl/display.cpp +++ b/engines/adl/display.cpp @@ -71,7 +71,8 @@ static byte font[64][5] = { Display::Display() : _scanlines(false), _cursorPos(0), - _mode(kModeText) { + _mode(kModeText), + _showCursor(false) { _frameBuf = new byte[kFrameBufSize]; _frameBufSurface = new Graphics::Surface; _frameBufSurface->create(kWidth * 2, kHeight * 2, Graphics::PixelFormat::createFormatCLUT8()); @@ -367,8 +368,12 @@ void Display::clear(byte color) { void Display::updateTextSurface() { for (uint row = 0; row < 24; ++row) for (uint col = 0; col < 40; ++col) { + int charPos = row * 40 + col; char c = _textBuf[row * 40 + col]; + if (charPos == _cursorPos && _showCursor) + c = (c & 0x3f) | 0x40; + Common::Rect r(7 * 2, 8 * 2); r.translate(((c & 0x3f) % 16) * 7 * 2, (c & 0x3f) / 16 * 8 * 2); @@ -381,36 +386,6 @@ void Display::updateTextSurface() { } } -void Display::printString(const Common::String &str) { - Common::String::const_iterator it; - for (it = str.begin(); it != str.end(); ++it) { - byte b = *it; - - if (b == ('\r' | 0x80)) - _cursorPos = (_cursorPos / 40 + 1) * 40; - else if (b < 0x80 || b >= 0xa0) - _textBuf[_cursorPos++] = b; - - if (_cursorPos == kTextBufSize) { - memmove(_textBuf, _textBuf + 40, kTextBufSize - 40); - memset(_textBuf + kTextBufSize - 40, ' ' | 0x80, 40); - _cursorPos -= 40; - } - } - - updateTextSurface(); -} - -void Display::printASCIIString(const Common::String &str) { - Common::String aStr; - - Common::String::const_iterator it; - for (it = str.begin(); it != str.end(); ++it) - aStr += APPLECHAR(*it); - - printString(aStr); -} - void Display::drawChar(byte c, int x, int y) { byte *buf = (byte *)_font->getPixels() + y * _font->pitch + x; @@ -463,126 +438,63 @@ void Display::updateScreen() { } } -Common::String Display::inputString(byte prompt) { - Common::String s; - - if (prompt > 0) - printString(Common::String(prompt)); - - while (1) { - byte b = inputKey(); - - if (g_engine->shouldQuit()) - return 0; - - if (b == 0) - continue; - - if (b == ('\r' | 0x80)) { - s += b; - printString(Common::String(b)); - return s; - } - - if (b < 0xa0) { - switch (b) { - case Common::KEYCODE_BACKSPACE | 0x80: - if (!s.empty()) { - --_cursorPos; - _textBuf[_cursorPos] = ' ' | 0x80; - s.deleteLastChar(); - } - break; - }; - } else { - s += b; - printString(Common::String(b)); - } - } +void Display::home() { + memset(_textBuf, APPLECHAR(' '), kTextBufSize); + _cursorPos = 0; } -byte Display::convertKey(uint16 ascii) { - ascii = toupper(ascii); - - if (ascii >= 0x80) - return 0; +void Display::moveCursorForward() { + ++_cursorPos; - ascii |= 0x80; + if (_cursorPos >= kTextBufSize) + scrollUp(); +} - if (ascii >= 0x80 && ascii <= 0xe0) - return ascii; +void Display::moveCursorBackward() { + --_cursorPos; - return 0; + if (_cursorPos < 0) + _cursorPos = 0; } -byte Display::inputKey() { - Common::EventManager *ev = g_system->getEventManager(); +void Display::moveCursorTo(const Common::Point &pos) { + _cursorPos = pos.y * 40 + pos.x; - byte orgChar = _textBuf[_cursorPos]; - _textBuf[_cursorPos] = (orgChar & 0x3f) | 0x40; + if (_cursorPos >= kTextBufSize) + error("Cursor position (%i, %i) out of bounds", pos.x, pos.y); +} - byte key = 0; +void Display::setCharAtCursor(byte c) { + _textBuf[_cursorPos] = c; +} - while (!g_engine->shouldQuit() && key == 0) { - Common::Event event; - if (ev->pollEvent(event)) { - if (event.type != Common::EVENT_KEYDOWN) - continue; +void Display::scrollUp() { + memmove(_textBuf, _textBuf + 40, kTextBufSize - 40); + memset(_textBuf + kTextBufSize - 40, ' ' | 0x80, 40); + _cursorPos -= 40; +} - if (event.kbd.flags & Common::KBD_CTRL) { - if (event.kbd.keycode == Common::KEYCODE_q) - g_engine->quitGame(); - continue; - } +void Display::printString(const Common::String &str) { + Common::String::const_iterator c; + for (c = str.begin(); c != str.end(); ++c) { + byte b = *c; - switch (event.kbd.keycode) { - case Common::KEYCODE_BACKSPACE: - case Common::KEYCODE_RETURN: - key = convertKey(event.kbd.keycode); - break; - default: - if (event.kbd.ascii >= 0x20 && event.kbd.ascii < 0x80) - key = convertKey(event.kbd.ascii); - }; + if (*c == APPLECHAR('\r')) + _cursorPos = (_cursorPos / 40 + 1) * 40; + else if (b < 0x80 || b >= 0xa0) { + setCharAtCursor(b); + ++_cursorPos; } - updateTextSurface(); - updateScreen(); - g_system->updateScreen(); - g_system->delayMillis(16); + if (_cursorPos == kTextBufSize) + scrollUp(); } - _textBuf[_cursorPos] = orgChar; - return key; -} - -void Display::delay(uint32 ms) { - Common::EventManager *ev = g_system->getEventManager(); - - uint32 start = g_system->getMillis(); - - while (!g_engine->shouldQuit() && g_system->getMillis() - start < ms) { - Common::Event event; - if (ev->pollEvent(event)) { - if (event.type == Common::EVENT_KEYDOWN && (event.kbd.flags & Common::KBD_CTRL)) { - switch(event.kbd.keycode) { - case Common::KEYCODE_q: - g_engine->quitGame(); - break; - default: - break; - } - } - } - updateScreen(); - g_system->updateScreen(); - g_system->delayMillis(16); - } + updateTextSurface(); } -void Display::home() { - memset(_textBuf, ' ' | 0x80, kTextBufSize); - _cursorPos = 0; +void Display::showCursor(bool enable) { + _showCursor = enable; } void Display::setCursorPos(Common::Point pos) { diff --git a/engines/adl/display.h b/engines/adl/display.h index 91d8b0ec97..91ae447cfd 100644 --- a/engines/adl/display.h +++ b/engines/adl/display.h @@ -52,20 +52,23 @@ public: ~Display(); void loadFrameBuffer(Common::ReadStream &stream); void decodeFrameBuffer(); - void printString(const Common::String &str); - void printASCIIString(const Common::String &str); void updateScreen(); - Common::String inputString(byte prompt = 0); - void delay(uint32 ms); void setMode(Mode mode) { _mode = mode; } - byte inputKey(); - void home(); void drawPixel(byte x, byte y, byte color); void drawLine(Common::Point p1, Common::Point p2, byte color); void clear(byte color); void drawLineArt(const Common::Array &lineArt, Common::Point p, byte rotation = 0, byte scaling = 1, byte color = 0x7f); void setCursorPos(Common::Point pos); + void home(); + void moveCursorTo(const Common::Point &pos); + void moveCursorForward(); + void moveCursorBackward(); + void printString(const Common::String &str); + void setCharAtCursor(byte c); + void showCursor(bool enable); + void updateTextSurface(); + private: enum { kWidth = 280, @@ -85,12 +88,12 @@ private: byte getPixelColor(byte x, byte color); void drawChar(byte c, int x, int y); void createFont(); - void updateTextSurface(); - byte convertKey(uint16 ascii); void moveX(PixelPos &p, byte &color, bool left); void moveY(PixelPos &p, bool down); void drawNextPixel(Display::PixelPos &p, byte &color, byte bits, byte quadrant); + void scrollUp(); + bool _scanlines; byte *_frameBuf; byte *_textBuf; @@ -99,6 +102,7 @@ private: Graphics::Surface *_font; int _cursorPos; Mode _mode; + bool _showCursor; }; } // End of namespace Adl diff --git a/engines/adl/hires1.cpp b/engines/adl/hires1.cpp index ba6f19a8e4..591216698b 100644 --- a/engines/adl/hires1.cpp +++ b/engines/adl/hires1.cpp @@ -37,7 +37,6 @@ #include "adl/hires1.h" #include "adl/display.h" -#include "adl/parser.h" namespace Adl { @@ -98,7 +97,7 @@ void HiRes1Engine::runIntro() { _display->setMode(Display::kModeHires); _display->loadFrameBuffer(file); _display->decodeFrameBuffer(); - _display->delay(4000); + delay(4000); if (shouldQuit()) return; @@ -113,21 +112,21 @@ void HiRes1Engine::runIntro() { basic.seek(IDI_HR1_OFS_PD_TEXT_0); str = readString(basic, '"'); - _display->printASCIIString(str + '\r'); + printASCIIString(str + '\r'); basic.seek(IDI_HR1_OFS_PD_TEXT_1); str = readString(basic, '"'); - _display->printASCIIString(str + "\r\r"); + printASCIIString(str + "\r\r"); basic.seek(IDI_HR1_OFS_PD_TEXT_2); str = readString(basic, '"'); - _display->printASCIIString(str + "\r\r"); + printASCIIString(str + "\r\r"); basic.seek(IDI_HR1_OFS_PD_TEXT_3); str = readString(basic, '"'); - _display->printASCIIString(str + '\r'); + printASCIIString(str + '\r'); - _display->inputKey(); + inputKey(); if (g_engine->shouldQuit()) return; @@ -140,7 +139,7 @@ void HiRes1Engine::runIntro() { while (1) { _display->printString(str); - Common::String s = _display->inputString(); + Common::String s = inputString(); if (g_engine->shouldQuit()) break; @@ -166,7 +165,7 @@ void HiRes1Engine::runIntro() { while (pages[page] != 0) { _display->home(); printStrings(file, pages[page++]); - _display->inputString(); + inputString(); if (g_engine->shouldQuit()) return; @@ -175,7 +174,7 @@ void HiRes1Engine::runIntro() { } } - _display->printASCIIString("\r"); + printASCIIString("\r"); file.close(); @@ -188,7 +187,7 @@ void HiRes1Engine::runIntro() { file.seek(0x1800); _display->loadFrameBuffer(file); _display->decodeFrameBuffer(); - _display->delay(2000); + delay(2000); } void HiRes1Engine::drawPic(Common::ReadStream &stream, Common::Point pos) { @@ -294,8 +293,8 @@ void HiRes1Engine::initState() { void HiRes1Engine::restartGame() { initState(); _display->printString(_strings[IDI_HR1_STR_PRESS_RETURN]); - _display->inputString(); // Missing in the original - _display->printASCIIString("\r\r\r\r\r"); + inputString(); // Missing in the original + printASCIIString("\r\r\r\r\r"); } void HiRes1Engine::runGame() { @@ -364,12 +363,12 @@ void HiRes1Engine::runGame() { } f.seek(0x3800); - _parser->loadVerbs(f); + loadVerbs(f); f.seek(0xf00); - _parser->loadNouns(f); + loadNouns(f); - _display->printASCIIString("\r\r\r\r\r"); + printASCIIString("\r\r\r\r\r"); while (1) { if (_isRestarting) @@ -378,7 +377,7 @@ void HiRes1Engine::runGame() { uint verb = 0, noun = 0; clearScreen(); showRoom(); - _parser->getInput(verb, noun); + getInput(verb, noun); if (!doOneCommand(_roomCommands, verb, noun)) printMessage(37); diff --git a/engines/adl/module.mk b/engines/adl/module.mk index 012b027b48..6acd06f6de 100644 --- a/engines/adl/module.mk +++ b/engines/adl/module.mk @@ -4,8 +4,7 @@ MODULE_OBJS := \ adl.o \ detection.o \ display.o \ - hires1.o \ - parser.o + hires1.o MODULE_DIRS += \ engines/adl diff --git a/engines/adl/parser.cpp b/engines/adl/parser.cpp deleted file mode 100644 index a697301664..0000000000 --- a/engines/adl/parser.cpp +++ /dev/null @@ -1,168 +0,0 @@ -/* ScummVM - Graphic Adventure Engine - * - * ScummVM is the legal property of its developers, whose names - * are too numerous to list here. Please refer to the COPYRIGHT - * file distributed with this source distribution. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - */ - -#include "adl/adl.h" -#include "adl/parser.h" -#include "adl/display.h" - -#include "engines/engine.h" - -#include "common/str.h" -#include "common/stream.h" -#include "common/debug.h" -#include "common/textconsole.h" - -namespace Adl { - -Parser::Parser(AdlEngine &engine, Display &display) : - _engine(engine), - _display(display) { - -} - -void Parser::loadWords(Common::ReadStream &stream, WordMap &map) { - uint index = 0; - - while (1) { - ++index; - - byte buf[kWordSize]; - - if (stream.read(buf, kWordSize) < kWordSize) - error("Error reading word list"); - - Common::String word((char *)buf, kWordSize); - - if (!map.contains(word)) - map[word] = index; - - byte synonyms = stream.readByte(); - - if (stream.err() || stream.eos()) - error("Error reading word list"); - - if (synonyms == 0xff) - break; - - for (uint i = 0; i < synonyms; ++i) { - if (stream.read((char *)buf, kWordSize) < kWordSize) - error("Error reading word list"); - - word = Common::String((char *)buf, kWordSize); - - if (!map.contains(word)) - map[word] = index; - } - } -} - -Common::String Parser::getLine() { - // Original engine uses a global here, which isn't reset between - // calls and may not match actual mode - bool textMode = false; - - while (1) { - Common::String line = _display.inputString(APPLECHAR('?')); - - if (g_engine->shouldQuit()) - return ""; - - if ((byte)line[0] == ('\r' | 0x80)) { - textMode = !textMode; - _display.setMode(textMode ? Display::kModeText : Display::kModeMixed); - continue; - } - - // Remove the return - line.deleteLastChar(); - return line; - } -} - -Common::String Parser::getWord(const Common::String &line, uint &index) { - Common::String str; - - for (uint i = 0; i < 8; ++i) - str += APPLECHAR(' '); - - int copied = 0; - - // Skip initial whitespace - while (1) { - if (index == line.size()) - return str; - if (line[index] != APPLECHAR(' ')) - break; - ++index; - } - - // Copy up to 8 characters - while (1) { - if (copied < 8) - str.setChar(line[index], copied++); - - index++; - - if (index == line.size() || line[index] == APPLECHAR(' ')) - return str; - } -} - -void Parser::getInput(uint &verb, uint &noun) { - while (1) { - _display.printString(_engine.getEngineString(IDI_STR_ENTER_COMMAND)); - Common::String line = getLine(); - - if (g_engine->shouldQuit()) - return; - - uint index = 0; - Common::String verbStr = getWord(line, index); - - if (!_verbs.contains(verbStr)) { - Common::String err = _engine.getEngineString(IDI_STR_VERB_ERROR); - for (uint i = 0; i < verbStr.size(); ++i) - err.setChar(verbStr[i], i + 19); - _display.printString(err); - continue; - } - - verb = _verbs[verbStr]; - - Common::String nounStr = getWord(line, index); - - if (!_nouns.contains(nounStr)) { - Common::String err = _engine.getEngineString(IDI_STR_NOUN_ERROR); - for (uint i = 0; i < verbStr.size(); ++i) - err.setChar(verbStr[i], i + 19); - for (uint i = 0; i < nounStr.size(); ++i) - err.setChar(nounStr[i], i + 30); - _display.printString(err); - continue; - } - - noun = _nouns[nounStr]; - return; - } -} - -} // End of namespace Adl diff --git a/engines/adl/parser.h b/engines/adl/parser.h deleted file mode 100644 index 3c191d90f6..0000000000 --- a/engines/adl/parser.h +++ /dev/null @@ -1,66 +0,0 @@ -/* ScummVM - Graphic Adventure Engine - * - * ScummVM is the legal property of its developers, whose names - * are too numerous to list here. Please refer to the COPYRIGHT - * file distributed with this source distribution. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - */ - -#ifndef ADL_PARSER_H -#define ADL_PARSER_H - -#include "common/types.h" -#include "common/hashmap.h" -#include "common/hash-str.h" - -namespace Common { -class ReadStream; -class String; -} - -namespace Adl { - -class Display; - -class Parser { -public: - Parser(AdlEngine &engine, Display &display); - - void loadVerbs(Common::ReadStream &stream) { loadWords(stream, _verbs); } - void loadNouns(Common::ReadStream &stream) { loadWords(stream, _nouns); } - void getInput(uint &verb, uint &noun); - -private: - enum { - kWordSize = 8 - }; - - typedef Common::HashMap WordMap; - - void loadWords(Common::ReadStream &stream, WordMap &map); - Common::String getLine(); - Common::String getWord(const Common::String &line, uint &index); - - AdlEngine &_engine; - Display &_display; - WordMap _verbs; - WordMap _nouns; -}; - -} // End of namespace Adl - -#endif -- cgit v1.2.3 From 93f5e36c9f9a75a2fa939408a76b0a2632c09425 Mon Sep 17 00:00:00 2001 From: Walter van Niftrik Date: Wed, 2 Mar 2016 11:38:01 +0100 Subject: ADL: Add GMM loading and saving --- engines/adl/adl.cpp | 105 +++++++++++++++++++++++++++++++++++++++++++------ engines/adl/adl.h | 12 ++++-- engines/adl/hires1.cpp | 50 ++++++++++++++++------- 3 files changed, 138 insertions(+), 29 deletions(-) (limited to 'engines') diff --git a/engines/adl/adl.cpp b/engines/adl/adl.cpp index 3c405b67b5..8ffb929e7a 100644 --- a/engines/adl/adl.cpp +++ b/engines/adl/adl.cpp @@ -43,13 +43,31 @@ AdlEngine::AdlEngine(OSystem *syst, const AdlGameDescription *gd) : Engine(syst), _gameDescription(gd), _display(nullptr), - _isRestarting(false) { + _isRestarting(false), + _isRestoring(false), + _saveVerb(0), + _saveNoun(0), + _restoreVerb(0), + _restoreNoun(0), + _canSaveNow(false), + _canRestoreNow(false) { } AdlEngine::~AdlEngine() { delete _display; } +bool AdlEngine::hasFeature(EngineFeature f) const { + switch (f) { + case kSupportsLoadingDuringRuntime: + case kSupportsSavingDuringRuntime: + case kSupportsRTL: + return true; + default: + return false; + } +} + Common::Error AdlEngine::run() { initGraphics(560, 384, true); @@ -71,6 +89,7 @@ Common::Error AdlEngine::run() { if (!loadState(saveSlot)) error("Failed to load save game from slot %i", saveSlot); _display->setCursorPos(Common::Point(0, 23)); + _isRestoring = true; } else { runIntro(); initState(); @@ -162,6 +181,16 @@ void AdlEngine::readCommands(Common::ReadStream &stream, Commands &commands) { if (stream.eos() || stream.err()) error("Failed to read commands"); + if (command.numCond == 0 && command.script[0] == IDO_ACT_SAVE) { + _saveVerb = command.verb; + _saveNoun = command.noun; + } + + if (command.numCond == 0 && command.script[0] == IDO_ACT_LOAD) { + _restoreVerb = command.verb; + _restoreNoun = command.noun; + } + commands.push_back(command); } } @@ -278,7 +307,15 @@ void AdlEngine::doActions(const Command &command, byte noun, byte offset) { break; case IDO_ACT_RESTART: { _display->printString(_strings[IDI_STR_PLAY_AGAIN]); + + // We allow restoring via GMM here + _canRestoreNow = true; Common::String input = inputString(); + _canRestoreNow = false; + + if (_isRestoring) + return; + if (input.size() == 0 || input[0] != APPLECHAR('N')) { _isRestarting = true; _display->clear(0x00); @@ -341,7 +378,7 @@ void AdlEngine::doActions(const Command &command, byte noun, byte offset) { } } -bool AdlEngine::checkCommand(const Command &command, byte verb, byte noun) { +bool AdlEngine::matchCommand(const Command &command, byte verb, byte noun, bool run) { if (command.room != IDI_NONE && command.room != _state.room) return false; @@ -384,7 +421,8 @@ bool AdlEngine::checkCommand(const Command &command, byte verb, byte noun) { } } - doActions(command, noun, offset); + if (run) + doActions(command, noun, offset); return true; } @@ -395,7 +433,7 @@ bool AdlEngine::doOneCommand(const Commands &commands, byte verb, byte noun) { Commands::const_iterator cmd; for (cmd = commands.begin(); cmd != commands.end(); ++cmd) - if (checkCommand(*cmd, verb, noun)) + if (matchCommand(*cmd, verb, noun)) return true; return false; @@ -403,14 +441,43 @@ bool AdlEngine::doOneCommand(const Commands &commands, byte verb, byte noun) { void AdlEngine::doAllCommands(const Commands &commands, byte verb, byte noun) { Commands::const_iterator cmd; + bool oldIsRestoring = _isRestoring; for (cmd = commands.begin(); cmd != commands.end(); ++cmd) { - checkCommand(*cmd, verb, noun); - if (_isRestarting) - return; + matchCommand(*cmd, verb, noun); + + // We assume no restarts happen in this command group. This + // simplifies enabling GMM savegame loading on the restart + // prompt. + if (_isRestarting || _isRestoring != oldIsRestoring) + error("Unexpected restart action encountered"); } } +bool AdlEngine::canSaveGameStateCurrently() { + if (!_canSaveNow) + return false; + + Commands::const_iterator cmd; + + // Here we check whether or not the game currently accepts the command + // "SAVE GAME". This prevents saving via the GMM in situations where + // it wouldn't otherwise be possible to do so. + for (cmd = _roomCommands.begin(); cmd != _roomCommands.end(); ++cmd) { + if (matchCommand(*cmd, _saveVerb, _saveNoun, false)) { + if (cmd->verb != _saveVerb || cmd->noun != _saveNoun) + return false; + return cmd->numCond == 0 && cmd->script[0] == IDO_ACT_SAVE; + } + } + + return false; +} + +bool AdlEngine::canLoadGameStateCurrently() { + return _canRestoreNow; +} + void AdlEngine::clearScreen() { _display->setMode(Display::kModeMixed); _display->clear(0x00); @@ -654,7 +721,7 @@ Common::String AdlEngine::getLine() { while (1) { Common::String line = inputString(APPLECHAR('?')); - if (shouldQuit()) + if (shouldQuit() || _isRestoring) return ""; if ((byte)line[0] == ('\r' | 0x80)) { @@ -703,7 +770,7 @@ void AdlEngine::getInput(uint &verb, uint &noun) { _display->printString(getEngineString(IDI_STR_ENTER_COMMAND)); Common::String line = getLine(); - if (shouldQuit()) + if (shouldQuit() || _isRestoring) return; uint index = 0; @@ -755,7 +822,7 @@ Common::String AdlEngine::inputString(byte prompt) { while (1) { byte b = inputKey(); - if (g_engine->shouldQuit()) + if (g_engine->shouldQuit() || _isRestoring) return 0; if (b == 0) @@ -805,7 +872,7 @@ byte AdlEngine::inputKey() { _display->showCursor(true); - while (!g_engine->shouldQuit() && key == 0) { + while (!g_engine->shouldQuit() && !_isRestoring && key == 0) { Common::Event event; if (ev->pollEvent(event)) { if (event.type != Common::EVENT_KEYDOWN) @@ -863,6 +930,22 @@ void AdlEngine::delay(uint32 ms) { } } +Common::Error AdlEngine::loadGameState(int slot) { + if (loadState(slot)) { + _isRestoring = true; + return Common::kNoError; + } + + return Common::kUnknownError; +} + +Common::Error AdlEngine::saveGameState(int slot, const Common::String &desc) { + if (saveState(slot, &desc)) + return Common::kNoError; + + return Common::kUnknownError; +} + AdlEngine *AdlEngine::create(GameType type, OSystem *syst, const AdlGameDescription *gd) { switch(type) { case kGameTypeHires1: diff --git a/engines/adl/adl.h b/engines/adl/adl.h index a9ac79d9f0..4d160f08b0 100644 --- a/engines/adl/adl.h +++ b/engines/adl/adl.h @@ -168,7 +168,7 @@ public: virtual ~AdlEngine(); const AdlGameDescription *_gameDescription; - uint32 getFeatures() const; + bool hasFeature(EngineFeature f) const; const char *getGameId() const; static AdlEngine *create(GameType type, OSystem *syst, const AdlGameDescription *gd); @@ -184,12 +184,14 @@ protected: virtual void initState() = 0; virtual void restartGame() = 0; virtual uint getEngineMessage(EngineMessage msg) = 0; + bool canSaveGameStateCurrently(); + bool canLoadGameStateCurrently(); Common::String readString(Common::ReadStream &stream, byte until = 0); void printStrings(Common::SeekableReadStream &stream, int count = 1); virtual void printMessage(uint idx, bool wait = true); void wordWrap(Common::String &str); void readCommands(Common::ReadStream &stream, Commands &commands); - bool checkCommand(const Command &command, byte verb, byte noun); + bool matchCommand(const Command &command, byte verb, byte noun, bool run = true); bool doOneCommand(const Commands &commands, byte verb, byte noun); void doAllCommands(const Commands &commands, byte verb, byte noun); void doActions(const Command &command, byte noun, byte offset); @@ -213,10 +215,14 @@ protected: Common::String inputString(byte prompt = 0); void delay(uint32 ms); byte inputKey(); + Common::Error loadGameState(int slot); + Common::Error saveGameState(int slot, const Common::String &desc); Display *_display; Parser *_parser; - bool _isRestarting; + bool _isRestarting, _isRestoring; + byte _saveVerb, _saveNoun, _restoreVerb, _restoreNoun; + bool _canSaveNow, _canRestoreNow; Common::Array _strings; Common::Array _messages; diff --git a/engines/adl/hires1.cpp b/engines/adl/hires1.cpp index 591216698b..db69a2d863 100644 --- a/engines/adl/hires1.cpp +++ b/engines/adl/hires1.cpp @@ -371,29 +371,49 @@ void HiRes1Engine::runGame() { printASCIIString("\r\r\r\r\r"); while (1) { - if (_isRestarting) - _isRestarting = false; - uint verb = 0, noun = 0; - clearScreen(); - showRoom(); - getInput(verb, noun); - if (!doOneCommand(_roomCommands, verb, noun)) - printMessage(37); + // When restoring from the launcher, we don't read + // input on the first iteration. This is needed to + // ensure that restoring from the launcher and + // restoring in-game brings us to the same game state. + // (Also see comment below.) + if (!_isRestoring) { + clearScreen(); + showRoom(); - if (_isRestarting) - continue; + _canSaveNow = _canRestoreNow = true; + getInput(verb, noun); + _canSaveNow = _canRestoreNow = false; - doAllCommands(_globalCommands, verb, noun); + if (shouldQuit()) + return; + + if (!doOneCommand(_roomCommands, verb, noun)) + printMessage(IDI_HR1_MSG_DONT_UNDERSTAND); + } - if (_isRestarting) + if (_isRestoring) { + // We restored from the GMM or launcher. As restoring + // with "RESTORE GAME" does not end command processing, + // we don't break it off here either. This essentially + // means that restoring a game will always run through + // the global commands and increase the move counter + // before the first user input. + printASCIIString("\r"); + _isRestoring = false; + verb = _restoreVerb; + noun = _restoreNoun; + } + + // Restarting does end command processing + if (_isRestarting) { + _isRestarting = false; continue; + } + doAllCommands(_globalCommands, verb, noun); _state.moves++; - - if (shouldQuit()) - return; } } -- cgit v1.2.3 From baa2410a1cbe34606cbb6c0939a800edb09dfc65 Mon Sep 17 00:00:00 2001 From: Walter van Niftrik Date: Wed, 2 Mar 2016 12:59:11 +0100 Subject: ADL: Fix "don't understand" parser response override --- engines/adl/hires1.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'engines') diff --git a/engines/adl/hires1.cpp b/engines/adl/hires1.cpp index db69a2d863..54351911fc 100644 --- a/engines/adl/hires1.cpp +++ b/engines/adl/hires1.cpp @@ -427,7 +427,7 @@ void HiRes1Engine::printMessage(uint idx, bool wait) { case IDI_HR1_MSG_DONT_HAVE_IT: _display->printString(_strings[IDI_HR1_STR_DONT_HAVE_IT]); return; - case IDI_MSG_DONT_UNDERSTAND: + case IDI_HR1_MSG_DONT_UNDERSTAND: _display->printString(_strings[IDI_HR1_STR_DONT_UNDERSTAND]); return; case IDI_HR1_MSG_GETTING_DARK: -- cgit v1.2.3 From 84a9f6ce95822efd2c2e0600daf2aeb27a841106 Mon Sep 17 00:00:00 2001 From: Walter van Niftrik Date: Wed, 2 Mar 2016 21:56:06 +0100 Subject: ADL: Add save game meta info support --- engines/adl/adl.cpp | 73 ++++++++++++++++++++++++++--------------------- engines/adl/adl.h | 2 -- engines/adl/detection.cpp | 70 ++++++++++++++++++++++++++++++++++++++++++++- 3 files changed, 110 insertions(+), 35 deletions(-) (limited to 'engines') diff --git a/engines/adl/adl.cpp b/engines/adl/adl.cpp index 8ffb929e7a..633705f2db 100644 --- a/engines/adl/adl.cpp +++ b/engines/adl/adl.cpp @@ -33,6 +33,7 @@ #include "engines/util.h" #include "graphics/palette.h" +#include "graphics/thumbnail.h" #include "adl/adl.h" #include "adl/display.h" @@ -86,7 +87,7 @@ Common::Error AdlEngine::run() { int saveSlot = ConfMan.getInt("save_slot"); if (saveSlot >= 0) { - if (!loadState(saveSlot)) + if (loadGameState(saveSlot).getCode() != Common::kNoError) error("Failed to load save game from slot %i", saveSlot); _display->setCursorPos(Common::Point(0, 23)); _isRestoring = true; @@ -297,11 +298,11 @@ void AdlEngine::doActions(const Command &command, byte noun, byte offset) { ++offset; break; case IDO_ACT_SAVE: - saveState(0); + saveGameState(0, ""); ++offset; break; case IDO_ACT_LOAD: - loadState(0); + loadGameState(0); ++offset; // Original engine continues processing here (?) break; @@ -528,13 +529,13 @@ void AdlEngine::showRoom() { printMessage(curRoom().description, false); } -bool AdlEngine::saveState(uint slot, const Common::String *description) { +Common::Error AdlEngine::saveGameState(int slot, const Common::String &desc) { Common::String fileName = Common::String::format("%s.s%02d", _targetName.c_str(), slot); Common::OutSaveFile *outFile = getSaveFileManager()->openForSaving(fileName); if (!outFile) { warning("Failed to open file '%s'", fileName.c_str()); - return false; + return Common::kUnknownError; } outFile->writeUint32BE(MKTAG('A', 'D', 'L', ':')); @@ -542,8 +543,8 @@ bool AdlEngine::saveState(uint slot, const Common::String *description) { char name[SAVEGAME_NAME_LEN] = { }; - if (description) - strncpy(name, description->c_str(), sizeof(name) - 1); + if (!desc.empty()) + strncpy(name, desc.c_str(), sizeof(name) - 1); else { Common::String defaultName("Save "); defaultName += 'A' + slot; @@ -552,6 +553,20 @@ bool AdlEngine::saveState(uint slot, const Common::String *description) { outFile->write(name, sizeof(name)); + TimeDate t; + g_system->getTimeAndDate(t); + + outFile->writeUint16BE(t.tm_year); + outFile->writeByte(t.tm_mon); + outFile->writeByte(t.tm_mday); + outFile->writeByte(t.tm_hour); + outFile->writeByte(t.tm_min); + + uint32 playTime = getTotalPlayTime(); + outFile->writeUint32BE(playTime); + + Graphics::saveThumbnail(*outFile); + outFile->writeByte(_state.room); outFile->writeByte(_state.moves); outFile->writeByte(_state.isDark); @@ -580,38 +595,45 @@ bool AdlEngine::saveState(uint slot, const Common::String *description) { if (outFile->err()) { delete outFile; warning("Failed to save game '%s'", fileName.c_str()); - return false; + return Common::kUnknownError; } delete outFile; - return true; + return Common::kNoError; } -bool AdlEngine::loadState(uint slot) { +Common::Error AdlEngine::loadGameState(int slot) { Common::String fileName = Common::String::format("%s.s%02d", _targetName.c_str(), slot); Common::InSaveFile *inFile = getSaveFileManager()->openForLoading(fileName); if (!inFile) { warning("Failed to open file '%s'", fileName.c_str()); - return false; + return Common::kUnknownError; } if (inFile->readUint32BE() != MKTAG('A', 'D', 'L', ':')) { warning("No header found in '%s'", fileName.c_str()); delete inFile; - return false; + return Common::kUnknownError; } byte saveVersion = inFile->readByte(); if (saveVersion != SAVEGAME_VERSION) { warning("Save game version %i not supported", saveVersion); delete inFile; - return false; + return Common::kUnknownError; } - initState(); - + // Skip description inFile->seek(SAVEGAME_NAME_LEN, SEEK_CUR); + // Skip save time + inFile->seek(6, SEEK_CUR); + + uint32 playTime = inFile->readUint32BE(); + + Graphics::skipThumbnail(*inFile); + + initState(); _state.room = inFile->readByte(); _state.moves = inFile->readByte(); @@ -649,7 +671,10 @@ bool AdlEngine::loadState(uint slot) { error("Failed to load game '%s'", fileName.c_str()); delete inFile; - return true; + + setTotalPlayTime(playTime); + + return Common::kNoError; } Room &AdlEngine::room(uint i) { @@ -930,22 +955,6 @@ void AdlEngine::delay(uint32 ms) { } } -Common::Error AdlEngine::loadGameState(int slot) { - if (loadState(slot)) { - _isRestoring = true; - return Common::kNoError; - } - - return Common::kUnknownError; -} - -Common::Error AdlEngine::saveGameState(int slot, const Common::String &desc) { - if (saveState(slot, &desc)) - return Common::kNoError; - - return Common::kUnknownError; -} - AdlEngine *AdlEngine::create(GameType type, OSystem *syst, const AdlGameDescription *gd) { switch(type) { case kGameTypeHires1: diff --git a/engines/adl/adl.h b/engines/adl/adl.h index 4d160f08b0..f8b2dca1b7 100644 --- a/engines/adl/adl.h +++ b/engines/adl/adl.h @@ -237,8 +237,6 @@ protected: private: void printEngineMessage(EngineMessage); - bool saveState(uint slot, const Common::String *description = nullptr); - bool loadState(uint slot); Common::String getTargetName() { return _targetName; } byte convertKey(uint16 ascii); diff --git a/engines/adl/detection.cpp b/engines/adl/detection.cpp index 5fe469d20f..27ce5939a3 100644 --- a/engines/adl/detection.cpp +++ b/engines/adl/detection.cpp @@ -23,6 +23,8 @@ #include "common/system.h" #include "common/savefile.h" +#include "graphics/thumbnail.h" + #include "engines/advancedDetector.h" #include "adl/adl.h" @@ -73,8 +75,10 @@ public: } bool hasFeature(MetaEngineFeature f) const; - int getMaximumSaveSlot() const { return 15; } + SaveStateDescriptor querySaveMetaInfos(const char *target, int slot) const; + int getMaximumSaveSlot() const { return 'O' - 'A'; } SaveStateList listSaves(const char *target) const; + void removeSaveState(const char *target, int slot) const; bool createInstance(OSystem *syst, Engine **engine, const ADGameDescription *gd) const; }; @@ -83,17 +87,76 @@ bool AdlMetaEngine::hasFeature(MetaEngineFeature f) const { switch(f) { case kSupportsListSaves: case kSupportsLoadingDuringStartup: + case kSupportsDeleteSave: + case kSavesSupportMetaInfo: + case kSavesSupportThumbnail: + case kSavesSupportCreationDate: + case kSavesSupportPlayTime: return true; default: return false; } } +SaveStateDescriptor AdlMetaEngine::querySaveMetaInfos(const char *target, int slot) const { + Common::String fileName = Common::String::format("%s.s%02d", target, slot); + Common::InSaveFile *inFile = g_system->getSavefileManager()->openForLoading(fileName); + + if (!inFile) + return SaveStateDescriptor(); + + if (inFile->readUint32BE() != MKTAG('A', 'D', 'L', ':')) { + delete inFile; + return SaveStateDescriptor(); + } + + byte saveVersion = inFile->readByte(); + if (saveVersion != SAVEGAME_VERSION) { + delete inFile; + return SaveStateDescriptor(); + } + + char name[SAVEGAME_NAME_LEN] = { }; + inFile->read(name, sizeof(name) - 1); + inFile->readByte(); + + if (inFile->eos() || inFile->err()) { + delete inFile; + return SaveStateDescriptor(); + } + + SaveStateDescriptor sd(slot, name); + + int year = inFile->readUint16BE(); + int month = inFile->readByte(); + int day = inFile->readByte(); + sd.setSaveDate(year + 1900, month + 1, day); + + int hour = inFile->readByte(); + int minutes = inFile->readByte(); + sd.setSaveTime(hour, minutes); + + uint32 playTime = inFile->readUint32BE(); + sd.setPlayTime(playTime); + + if (inFile->eos() || inFile->err()) { + delete inFile; + return SaveStateDescriptor(); + } + + Graphics::Surface *const thumbnail = Graphics::loadThumbnail(*inFile); + sd.setThumbnail(thumbnail); + + delete inFile; + return sd; +} + SaveStateList AdlMetaEngine::listSaves(const char *target) const { Common::SaveFileManager *saveFileMan = g_system->getSavefileManager(); Common::StringArray files = saveFileMan->listSavefiles(Common::String(target) + ".s##"); SaveStateList saveList; + for (uint i = 0; i < files.size(); ++i) { const Common::String &fileName = files[i]; Common::InSaveFile *inFile = saveFileMan->openForLoading(fileName); @@ -129,6 +192,11 @@ SaveStateList AdlMetaEngine::listSaves(const char *target) const { return saveList; } +void AdlMetaEngine::removeSaveState(const char *target, int slot) const { + Common::String fileName = Common::String::format("%s.s%02d", target, slot); + g_system->getSavefileManager()->removeSavefile(fileName); +} + bool AdlMetaEngine::createInstance(OSystem *syst, Engine **engine, const ADGameDescription *gd) const { if (gd) *engine = AdlEngine::create(((const AdlGameDescription *)gd)->gameType, syst, (const AdlGameDescription *)gd); -- cgit v1.2.3 From 912a31fa652c389b14e3d77998736813e3b621d0 Mon Sep 17 00:00:00 2001 From: Walter van Niftrik Date: Thu, 3 Mar 2016 13:43:26 +0100 Subject: ADL: Add monochrome and scanline rendering --- engines/adl/adl.cpp | 13 ------ engines/adl/detection.cpp | 32 +++++++++++++- engines/adl/display.cpp | 108 ++++++++++++++++++++++++++++++++++++++-------- engines/adl/display.h | 4 ++ 4 files changed, 124 insertions(+), 33 deletions(-) (limited to 'engines') diff --git a/engines/adl/adl.cpp b/engines/adl/adl.cpp index 633705f2db..15a6c32018 100644 --- a/engines/adl/adl.cpp +++ b/engines/adl/adl.cpp @@ -70,19 +70,6 @@ bool AdlEngine::hasFeature(EngineFeature f) const { } Common::Error AdlEngine::run() { - initGraphics(560, 384, true); - - byte palette[6 * 3] = { - 0x00, 0x00, 0x00, - 0xff, 0xff, 0xff, - 0xc7, 0x34, 0xff, - 0x38, 0xcb, 0x00, - 0x00, 0x00, 0xff, // FIXME - 0xff, 0xa5, 0x00 // FIXME - }; - - g_system->getPaletteManager()->setPalette(palette, 0, 6); - _display = new Display(); int saveSlot = ConfMan.getInt("save_slot"); diff --git a/engines/adl/detection.cpp b/engines/adl/detection.cpp index 27ce5939a3..e556e1258a 100644 --- a/engines/adl/detection.cpp +++ b/engines/adl/detection.cpp @@ -22,6 +22,7 @@ #include "common/system.h" #include "common/savefile.h" +#include "common/translation.h" #include "graphics/thumbnail.h" @@ -31,6 +32,33 @@ namespace Adl { +#define GAMEOPTION_COLOR GUIO_GAMEOPTIONS1 +#define GAMEOPTION_SCANLINES GUIO_GAMEOPTIONS2 + +static const ADExtraGuiOptionsMap optionsList[] = { + { + GAMEOPTION_COLOR, + { + _s("Color mode"), + _s("Use color graphics"), + "color", + false + } + }, + + { + GAMEOPTION_SCANLINES, + { + _s("Scanlines"), + _s("Show scanlines"), + "scanlines", + false + } + }, + + AD_EXTRA_GUI_OPTIONS_TERMINATOR +}; + struct AdlGameDescription { ADGameDescription desc; GameType gameType; @@ -55,7 +83,7 @@ static const AdlGameDescription gameDescriptions[] = { Common::EN_ANY, Common::kPlatformApple2GS, // FIXME ADGF_NO_FLAGS, - GUIO0() + GUIO2(GAMEOPTION_COLOR, GAMEOPTION_SCANLINES) }, kGameTypeHires1 }, @@ -64,7 +92,7 @@ static const AdlGameDescription gameDescriptions[] = { class AdlMetaEngine : public AdvancedMetaEngine { public: - AdlMetaEngine() : AdvancedMetaEngine(gameDescriptions, sizeof(AdlGameDescription), adlGames) { } + AdlMetaEngine() : AdvancedMetaEngine(gameDescriptions, sizeof(AdlGameDescription), adlGames, optionsList) { } const char *getName() const { return "ADL"; diff --git a/engines/adl/display.cpp b/engines/adl/display.cpp index a6d94f6e13..ade05ab06d 100644 --- a/engines/adl/display.cpp +++ b/engines/adl/display.cpp @@ -29,11 +29,14 @@ #include "common/events.h" #include "common/rect.h" #include "common/array.h" +#include "common/config-manager.h" #include "engines/engine.h" +#include "engines/util.h" +#include "graphics/palette.h" namespace Adl { -static byte font[64][5] = { +static const byte font[64][5] = { { 0x7c, 0x82, 0xba, 0xb2, 0x9c }, { 0xf8, 0x24, 0x22, 0x24, 0xf8 }, // @A { 0xfe, 0x92, 0x92, 0x92, 0x6c }, { 0x7c, 0x82, 0x82, 0x82, 0x44 }, // BC { 0xfe, 0x82, 0x82, 0x82, 0x7c }, { 0xfe, 0x92, 0x92, 0x92, 0x82 }, // DE @@ -69,10 +72,17 @@ static byte font[64][5] = { }; Display::Display() : - _scanlines(false), _cursorPos(0), _mode(kModeText), _showCursor(false) { + + initGraphics(560, 384, true); + + _monochrome = !ConfMan.getBool("color"); + _scanlines = ConfMan.getBool("scanlines"); + + setPalette(_scanlines, _monochrome); + _frameBuf = new byte[kFrameBufSize]; _frameBufSurface = new Graphics::Surface; _frameBufSurface->create(kWidth * 2, kHeight * 2, Graphics::PixelFormat::createFormatCLUT8()); @@ -98,11 +108,37 @@ Display::~Display() { delete _font; } +void Display::setPalette(bool scanlines, bool monochrome) { + const byte colorPal[6 * 3] = { + 0x00, 0x00, 0x00, + 0xff, 0xff, 0xff, + 0xc7, 0x34, 0xff, + 0x38, 0xcb, 0x00, + 0x0d, 0xa1, 0xff, + 0xf2, 0x5e, 0x00 + }; + + const byte monoPal[2 * 3] = { + 0x00, 0x00, 0x00, + 0x00, 0xc0, 0x01 + }; + + if (monochrome) { + g_system->getPaletteManager()->setPalette(monoPal, 0, 2); + if (!scanlines) + g_system->getPaletteManager()->setPalette(monoPal, 6, 2); + } else { + g_system->getPaletteManager()->setPalette(colorPal, 0, 6); + if (!scanlines) + g_system->getPaletteManager()->setPalette(colorPal, 6, 6); + } +} + void Display::loadFrameBuffer(Common::ReadStream &stream) { stream.read(_frameBuf, kFrameBufSize); } -void Display::decodeScanline(byte *dst, int pitch, byte *src) { +void Display::decodeScanlineColor(byte *dst, int pitch, byte *src) { // TODO: shift secondPal by half a pixel bool prevOn = false; @@ -135,11 +171,8 @@ void Display::decodeScanline(byte *dst, int pitch, byte *src) { dst[0] = color; dst[1] = color; - - if (!_scanlines) { - dst[pitch] = color; - dst[pitch + 1] = color; - } + dst[pitch] = color + 6; + dst[pitch + 1] = color + 6; dst += 2; prevOn = curOn; @@ -147,6 +180,33 @@ void Display::decodeScanline(byte *dst, int pitch, byte *src) { } } +void Display::decodeScanlineMono(byte *dst, int pitch, byte *src) { + // TODO: shift secondPal by half a pixel + + for (uint j = 0; j < 39; ++j) { + for (uint k = 0; k < 7; ++k) { + byte color = 0; + + if (src[j] & (1 << k)) + color = 1; + + dst[0] = color; + dst[1] = color; + dst[pitch] = color + 6; + dst[pitch + 1] = color + 6; + + dst += 2; + } + } +} + +void Display::decodeScanline(byte *dst, int pitch, byte *src) { + if (_monochrome) + decodeScanlineMono(dst, pitch, src); + else + decodeScanlineColor(dst, pitch, src); +} + Display::PixelPos Display::getPixelPos(byte x, byte y) { PixelPos pixelPos; @@ -390,16 +450,23 @@ void Display::drawChar(byte c, int x, int y) { byte *buf = (byte *)_font->getPixels() + y * _font->pitch + x; for (uint row = 0; row < 8; ++row) { - for (uint col = 1; col < 6; ++col) + if (row & 1) { + buf[_font->pitch] = 6; + buf[_font->pitch + 1] = 6; + buf[_font->pitch + 6 * 2] = 6; + buf[_font->pitch + 6 * 2 + 1] = 6; + } + for (uint col = 1; col < 6; ++col) { if (font[c][col - 1] & (1 << row)) { buf[col * 2] = 1; buf[col * 2 + 1] = 1; - - if (!_scanlines) { - buf[_font->pitch + col * 2] = 1; - buf[_font->pitch + col * 2 + 1] = 1; - } + buf[_font->pitch + col * 2] = 1 + 6; + buf[_font->pitch + col * 2 + 1] = 1 + 6; + } else { + buf[_font->pitch + col * 2] = 6; + buf[_font->pitch + col * 2 + 1] = 6; } + } buf += 2 * _font->pitch; } @@ -417,10 +484,15 @@ void Display::createFont() { byte *buf = (byte *)_font->getPixels(); byte *bufInv = buf + (_font->h / 2) * _font->pitch; - for (uint row = 0; row < _font->h / 2; ++row) { - if (!_scanlines || !(row & 1)) - for (uint col = 0; col < _font->w; ++col) - bufInv[col] = buf[col] ? 0 : 1; + for (uint row = 0; row < _font->h / 2; row += 2) { + for (uint col = 0; col < _font->w; ++col) + bufInv[col] = (buf[col] ? 0 : 1); + + buf += _font->pitch; + bufInv += _font->pitch; + + for (uint col = 0; col < _font->w; ++col) + bufInv[col] = (buf[col] == 7 ? 6 : 7); buf += _font->pitch; bufInv += _font->pitch; diff --git a/engines/adl/display.h b/engines/adl/display.h index 91ae447cfd..21cc599b89 100644 --- a/engines/adl/display.h +++ b/engines/adl/display.h @@ -50,6 +50,7 @@ public: Display(); ~Display(); + void setPalette(bool monochrome, bool scanlines); void loadFrameBuffer(Common::ReadStream &stream); void decodeFrameBuffer(); void updateScreen(); @@ -84,6 +85,8 @@ private: }; void decodeScanline(byte *dst, int pitch, byte *src); + void decodeScanlineColor(byte *dst, int pitch, byte *src); + void decodeScanlineMono(byte *dst, int pitch, byte *src); PixelPos getPixelPos(byte x, byte y); byte getPixelColor(byte x, byte color); void drawChar(byte c, int x, int y); @@ -103,6 +106,7 @@ private: int _cursorPos; Mode _mode; bool _showCursor; + bool _monochrome; }; } // End of namespace Adl -- cgit v1.2.3 From b30fb417acb29dee415a784f15f63772a010b4d3 Mon Sep 17 00:00:00 2001 From: Walter van Niftrik Date: Thu, 3 Mar 2016 14:05:19 +0100 Subject: ADL: Disable scanlines when saving thumbnail --- engines/adl/adl.cpp | 2 +- engines/adl/display.cpp | 51 ++++++++++++++++++++++++++++++++++++++----------- engines/adl/display.h | 6 +++++- 3 files changed, 46 insertions(+), 13 deletions(-) (limited to 'engines') diff --git a/engines/adl/adl.cpp b/engines/adl/adl.cpp index 15a6c32018..083fde9690 100644 --- a/engines/adl/adl.cpp +++ b/engines/adl/adl.cpp @@ -552,7 +552,7 @@ Common::Error AdlEngine::saveGameState(int slot, const Common::String &desc) { uint32 playTime = getTotalPlayTime(); outFile->writeUint32BE(playTime); - Graphics::saveThumbnail(*outFile); + _display->saveThumbnail(*outFile); outFile->writeByte(_state.room); outFile->writeByte(_state.moves); diff --git a/engines/adl/display.cpp b/engines/adl/display.cpp index ade05ab06d..6a7cc6900b 100644 --- a/engines/adl/display.cpp +++ b/engines/adl/display.cpp @@ -33,6 +33,7 @@ #include "engines/engine.h" #include "engines/util.h" #include "graphics/palette.h" +#include "graphics/thumbnail.h" namespace Adl { @@ -81,7 +82,12 @@ Display::Display() : _monochrome = !ConfMan.getBool("color"); _scanlines = ConfMan.getBool("scanlines"); - setPalette(_scanlines, _monochrome); + if (_monochrome) + setMonoPalette(); + else + setColorPalette(); + + enableScanlines(_scanlines); _frameBuf = new byte[kFrameBufSize]; _frameBufSurface = new Graphics::Surface; @@ -108,7 +114,34 @@ Display::~Display() { delete _font; } -void Display::setPalette(bool scanlines, bool monochrome) { +bool Display::saveThumbnail(Common::WriteStream &out) { + if (_scanlines) { + enableScanlines(false); + g_system->updateScreen(); + } + + bool retval = Graphics::saveThumbnail(out); + + if (_scanlines) { + enableScanlines(true); + g_system->updateScreen(); + } + + return retval; +} + +void Display::enableScanlines(bool enable) { + byte pal[6 * 3] = { }; + + if (enable) + g_system->getPaletteManager()->setPalette(pal, 6, 6); + else { + g_system->getPaletteManager()->grabPalette(pal, 0, 6); + g_system->getPaletteManager()->setPalette(pal, 6, 6); + } +} + +void Display::setColorPalette() { const byte colorPal[6 * 3] = { 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, @@ -118,20 +151,16 @@ void Display::setPalette(bool scanlines, bool monochrome) { 0xf2, 0x5e, 0x00 }; + g_system->getPaletteManager()->setPalette(colorPal, 0, 6); +} + +void Display::setMonoPalette() { const byte monoPal[2 * 3] = { 0x00, 0x00, 0x00, 0x00, 0xc0, 0x01 }; - if (monochrome) { - g_system->getPaletteManager()->setPalette(monoPal, 0, 2); - if (!scanlines) - g_system->getPaletteManager()->setPalette(monoPal, 6, 2); - } else { - g_system->getPaletteManager()->setPalette(colorPal, 0, 6); - if (!scanlines) - g_system->getPaletteManager()->setPalette(colorPal, 6, 6); - } + g_system->getPaletteManager()->setPalette(monoPal, 0, 2); } void Display::loadFrameBuffer(Common::ReadStream &stream) { diff --git a/engines/adl/display.h b/engines/adl/display.h index 21cc599b89..12e3ab90b9 100644 --- a/engines/adl/display.h +++ b/engines/adl/display.h @@ -28,6 +28,7 @@ namespace Common { class ReadStream; +class WriteStream; class String; class Point; } @@ -50,7 +51,9 @@ public: Display(); ~Display(); - void setPalette(bool monochrome, bool scanlines); + void enableScanlines(bool enable); + void setMonoPalette(); + void setColorPalette(); void loadFrameBuffer(Common::ReadStream &stream); void decodeFrameBuffer(); void updateScreen(); @@ -69,6 +72,7 @@ public: void setCharAtCursor(byte c); void showCursor(bool enable); void updateTextSurface(); + bool saveThumbnail(Common::WriteStream &out); private: enum { -- cgit v1.2.3 From d5cc42f1c233a45abb879818af503ec7b91c6f34 Mon Sep 17 00:00:00 2001 From: Walter van Niftrik Date: Thu, 3 Mar 2016 19:17:49 +0100 Subject: ADL: Make frame buffer linear --- engines/adl/adl.cpp | 48 +++++++++- engines/adl/adl.h | 2 + engines/adl/display.cpp | 241 ++++++++---------------------------------------- engines/adl/display.h | 10 +- engines/adl/hires1.cpp | 40 +++++++- engines/adl/hires1.h | 1 + 6 files changed, 125 insertions(+), 217 deletions(-) (limited to 'engines') diff --git a/engines/adl/adl.cpp b/engines/adl/adl.cpp index 083fde9690..90a9a0db06 100644 --- a/engines/adl/adl.cpp +++ b/engines/adl/adl.cpp @@ -484,7 +484,7 @@ void AdlEngine::drawItems() { if (curRoom().picture == curRoom().curPicture) { const Common::Point &p = _itemOffsets[dropped]; if (item->isLineArt) - _display->drawLineArt(_lineArt[item->picture - 1], p); + drawLineArt(_lineArt[item->picture - 1], p); else drawPic(item->picture, p); ++dropped; @@ -497,7 +497,7 @@ void AdlEngine::drawItems() { for (pic = item->roomPictures.begin(); pic != item->roomPictures.end(); ++pic) { if (*pic == curRoom().curPicture) { if (item->isLineArt) - _display->drawLineArt(_lineArt[item->picture - 1], item->position); + drawLineArt(_lineArt[item->picture - 1], item->position); else drawPic(item->picture, item->position); continue; @@ -942,6 +942,50 @@ void AdlEngine::delay(uint32 ms) { } } +void AdlEngine::drawNextPixel(Common::Point &p, byte color, byte bits, byte quadrant) { + if (bits & 4) { + _display->putPixel(p, color); + } + + bits += quadrant; + + if (bits & 1) + p.x += (bits & 2 ? -1 : 1); + else + p.y += (bits & 2 ? 1 : -1); +} + +void AdlEngine::drawLineArt(const Common::Array &lineArt, Common::Point p, byte rotation, byte scaling, byte color) { + const byte stepping[] = { + 0xff, 0xfe, 0xfa, 0xf4, 0xec, 0xe1, 0xd4, 0xc5, + 0xb4, 0xa1, 0x8d, 0x78, 0x61, 0x49, 0x31, 0x18, + 0xff + }; + + byte quadrant = rotation >> 4; + rotation &= 0xf; + byte xStep = stepping[rotation]; + byte yStep = stepping[(rotation ^ 0xf) + 1] + 1; + + for (uint i = 0; i < lineArt.size(); ++i) { + byte b = lineArt[i]; + + do { + byte xFrac = 0x80; + byte yFrac = 0x80; + for (uint j = 0; j < scaling; ++j) { + if (xFrac + xStep + 1 > 255) + drawNextPixel(p, color, b, quadrant); + xFrac += xStep + 1; + if (yFrac + yStep > 255) + drawNextPixel(p, color, b, quadrant + 1); + yFrac += yStep; + } + b >>= 3; + } while (b != 0); + } +} + AdlEngine *AdlEngine::create(GameType type, OSystem *syst, const AdlGameDescription *gd) { switch(type) { case kGameTypeHires1: diff --git a/engines/adl/adl.h b/engines/adl/adl.h index f8b2dca1b7..84b9214161 100644 --- a/engines/adl/adl.h +++ b/engines/adl/adl.h @@ -198,6 +198,8 @@ protected: void clearScreen(); virtual void drawPic(byte pic, Common::Point pos = Common::Point()) = 0; void drawItems(); + void drawNextPixel(Common::Point &p, byte color, byte bits, byte quadrant); + void drawLineArt(const Common::Array &lineArt, Common::Point p, byte rotation = 0, byte scaling = 1, byte color = 0x7f); void showRoom(); void takeItem(byte noun); void dropItem(byte noun); diff --git a/engines/adl/display.cpp b/engines/adl/display.cpp index 6a7cc6900b..90ca1b60db 100644 --- a/engines/adl/display.cpp +++ b/engines/adl/display.cpp @@ -89,7 +89,7 @@ Display::Display() : enableScanlines(_scanlines); - _frameBuf = new byte[kFrameBufSize]; + _frameBuf = new byte[kWidth * kHeight / 7]; _frameBufSurface = new Graphics::Surface; _frameBufSurface->create(kWidth * 2, kHeight * 2, Graphics::PixelFormat::createFormatCLUT8()); @@ -164,7 +164,19 @@ void Display::setMonoPalette() { } void Display::loadFrameBuffer(Common::ReadStream &stream) { - stream.read(_frameBuf, kFrameBufSize); + for (uint j = 0; j < 8; ++j) { + for (uint i = 0; i < 8; ++i) { + byte *dst = _frameBuf + kWidth / 7 * (i * 8 + j); + stream.read(dst, kWidth / 7); + dst += kWidth / 7 * 64; + stream.read(dst, kWidth / 7); + dst += kWidth / 7 * 64; + stream.read(dst, kWidth / 7); + stream.readUint32LE(); + stream.readUint32LE(); + dst += kWidth / 7 * 64; + } + } } void Display::decodeScanlineColor(byte *dst, int pitch, byte *src) { @@ -236,224 +248,45 @@ void Display::decodeScanline(byte *dst, int pitch, byte *src) { decodeScanlineColor(dst, pitch, src); } -Display::PixelPos Display::getPixelPos(byte x, byte y) { - PixelPos pixelPos; - - // FIXME: check X, Y range - - byte offsetL = y & 0xc0; - offsetL |= offsetL >> 2; - byte offsetH = y; - y <<= 2; - offsetH <<= 1; - offsetH |= y >> 7; - y <<= 1; - offsetH <<= 1; - offsetH |= y >> 7; - y <<= 1; - offsetL >>= 1; - offsetL |= y & 0x80; - y <<= 1; - offsetH = offsetH & 0x1f; - pixelPos.rowAddr = (offsetH << 8) | offsetL; - pixelPos.byteOffset = x / 7; - pixelPos.bitMask = 0x80 | (1 << x % 7); - - return pixelPos; -} - -byte Display::getPixelColor(byte offset, byte color) { - if (offset & 1) { - byte c = color << 1; - if (c >= 0x40 && c < 0xc0) - return color ^ 0x7f; - } - - return color; -} - void Display::decodeFrameBuffer() { byte *src = _frameBuf; - int pitch = _frameBufSurface->pitch; - for (int j = 0; j < 8; ++j) { - for (int i = 0; i < 8; ++i) { - byte *dst = (byte *)_frameBufSurface->getPixels() + pitch * 2 * (i * 8 + j); - decodeScanline(dst, pitch, src); - src += 40; - dst += pitch * 2 * 64; - decodeScanline(dst, pitch, src); - src += 40; - dst += pitch * 2 * 64; - decodeScanline(dst, pitch, src); - src += 48; - dst += pitch * 2 * 64; - } - } -} - -void Display::drawPixel(byte x, byte y, byte color) { - PixelPos p = getPixelPos(x, y); - byte c = getPixelColor(p.byteOffset, color); - byte *b = _frameBuf + p.rowAddr + p.byteOffset; - c ^= *b; - c &= p.bitMask; - c ^= *b; - *b = c; -} + byte *dst = (byte *)_frameBufSurface->getPixels(); -void Display::moveX(PixelPos &p, byte &color, bool left) { - if (left) { - byte bit = p.bitMask; - bool b = bit & 1; - bit >>= 1; - if (!b) { - bit ^= 0xc0; - p.bitMask = bit; - return; - } - --p.byteOffset; - if (p.byteOffset & 0x80) - p.byteOffset = 39; - p.bitMask = 0xc0; - } else { - byte bit = p.bitMask; - bit <<= 1; - bit ^= 0x80; - if (bit & 0x80) { - p.bitMask = bit; - return; - } - p.bitMask = 0x81; - ++p.byteOffset; - if (p.byteOffset == 40) - p.byteOffset = 0; + for (uint i = 0; i < kHeight; ++i) { + decodeScanline(dst, _frameBufSurface->pitch, src); + src += kWidth / 7; + dst += _frameBufSurface->pitch * 2; } - - color = getPixelColor(p.byteOffset, color); } -void Display::moveY(PixelPos &p, bool down) { - if (!down) { - if (p.rowAddr & 0x1c00) - p.rowAddr -= 0x400; - else if (p.rowAddr & 0x380) - p.rowAddr += 0x1b80; - else { - p.rowAddr += 0x1f58; - if (!(p.rowAddr & 0x80)) - p.rowAddr += 0x78; // Wrap around - } - } else { - p.rowAddr += 0x400; - if (p.rowAddr & 0x1c00) - return; - else if ((p.rowAddr & 0x380) != 0x380) - p.rowAddr -= 0x1f80; - else { - p.rowAddr -= 0x2358; - if ((p.rowAddr & 0x78) == 0x78) - p.rowAddr -= 0x78; // Wrap around - } - } -} +void Display::putPixel(Common::Point p, byte color) { + byte offset = p.x / 7; -void Display::drawNextPixel(Display::PixelPos &p, byte &color, byte bits, byte quadrant) { - if (bits & 4) { - byte b = (_frameBuf[p.rowAddr + p.byteOffset] ^ color) & p.bitMask; - _frameBuf[p.rowAddr + p.byteOffset] ^= b; + if (offset & 1) { + byte c = color << 1; + if (c >= 0x40 && c < 0xc0) + color ^= 0x7f; } - bits += quadrant; - - if (bits & 1) - moveX(p, color, bits & 2); - else - moveY(p, bits & 2); -} - -void Display::drawLineArt(const Common::Array &lineArt, Common::Point p, byte rotation, byte scaling, byte color) { - const byte stepping[] = { - 0xff, 0xfe, 0xfa, 0xf4, 0xec, 0xe1, 0xd4, 0xc5, - 0xb4, 0xa1, 0x8d, 0x78, 0x61, 0x49, 0x31, 0x18, - 0xff - }; - - PixelPos pos = getPixelPos(p.x, p.y); - byte c = getPixelColor(pos.byteOffset, color); - - byte quadrant = rotation >> 4; - rotation &= 0xf; - byte xStep = stepping[rotation]; - byte yStep = stepping[(rotation ^ 0xf) + 1] + 1; - - for (uint i = 0; i < lineArt.size(); ++i) { - byte b = lineArt[i]; - - do { - byte xFrac = 0x80; - byte yFrac = 0x80; - for (uint j = 0; j < scaling; ++j) { - if (xFrac + xStep + 1 > 255) - drawNextPixel(pos, c, b, quadrant); - xFrac += xStep + 1; - if (yFrac + yStep > 255) - drawNextPixel(pos, c, b, quadrant + 1); - yFrac += yStep; - } - b >>= 3; - } while (b != 0); - } + byte *b = _frameBuf + p.y * kWidth / 7 + offset; + color ^= *b; + color &= 1 << (p.x % 7); + *b ^= color; } -void Display::drawLine(Common::Point p1, Common::Point p2, byte color) { - PixelPos p = getPixelPos(p1.x, p1.y); - byte c = getPixelColor(p.byteOffset, color); - - int16 deltaX = p2.x - p1.x; - byte dir = deltaX >> 8; - - if (deltaX < 0) - deltaX = -deltaX; - - int16 err = deltaX; - - int16 deltaY = p2.y - p1.y - 1; - dir >>= 1; - if (deltaY >= 0) { - deltaY = -deltaY - 2; - dir |= 0x80; - } - - int16 steps = deltaY - deltaX; - - err += deltaY + 1; - - while (1) { - byte *b = _frameBuf + p.rowAddr + p.byteOffset; - byte d = *b; - d ^= c; - d &= p.bitMask; - d ^= *b; - *b = d; +void Display::clear(byte color) { + byte val = 0; - if (++steps == 0) - return; + byte c = color << 1; + if (c >= 0x40 && c < 0xc0) + val = 0x7f; - if (err < 0) { - moveY(p, dir & 0x80); - err += deltaX; - } else { - moveX(p, c, dir & 0x40); - err += deltaY + 1; - } + for (uint i = 0; i < kWidth / 7 * kHeight; ++i) { + _frameBuf[i] = color; + color ^= val; } } -void Display::clear(byte color) { - for (uint i = 0; i < kFrameBufSize; ++i) - _frameBuf[i] = getPixelColor(i & 1, color); -} - void Display::updateTextSurface() { for (uint row = 0; row < 24; ++row) for (uint col = 0; col < 40; ++col) { diff --git a/engines/adl/display.h b/engines/adl/display.h index 12e3ab90b9..0452b2768f 100644 --- a/engines/adl/display.h +++ b/engines/adl/display.h @@ -58,10 +58,8 @@ public: void decodeFrameBuffer(); void updateScreen(); void setMode(Mode mode) { _mode = mode; } - void drawPixel(byte x, byte y, byte color); - void drawLine(Common::Point p1, Common::Point p2, byte color); + void putPixel(Common::Point p1, byte color); void clear(byte color); - void drawLineArt(const Common::Array &lineArt, Common::Point p, byte rotation = 0, byte scaling = 1, byte color = 0x7f); void setCursorPos(Common::Point pos); void home(); @@ -78,7 +76,6 @@ private: enum { kWidth = 280, kHeight = 192, - kFrameBufSize = 0x2000, kTextBufSize = 40 * 24 }; @@ -91,13 +88,8 @@ private: void decodeScanline(byte *dst, int pitch, byte *src); void decodeScanlineColor(byte *dst, int pitch, byte *src); void decodeScanlineMono(byte *dst, int pitch, byte *src); - PixelPos getPixelPos(byte x, byte y); - byte getPixelColor(byte x, byte color); void drawChar(byte c, int x, int y); void createFont(); - void moveX(PixelPos &p, byte &color, bool left); - void moveY(PixelPos &p, bool down); - void drawNextPixel(Display::PixelPos &p, byte &color, byte bits, byte quadrant); void scrollUp(); diff --git a/engines/adl/hires1.cpp b/engines/adl/hires1.cpp index 54351911fc..04df01ecd4 100644 --- a/engines/adl/hires1.cpp +++ b/engines/adl/hires1.cpp @@ -216,10 +216,10 @@ void HiRes1Engine::drawPic(Common::ReadStream &stream, Common::Point pos) { y = 160; if (bNewLine) { - _display->drawPixel(x, y, 0x7f); + _display->putPixel(Common::Point(x, y), 0x7f); bNewLine = false; } else { - _display->drawLine(Common::Point(oldX, oldY), Common::Point(x, y), 0x7f); + drawLine(Common::Point(oldX, oldY), Common::Point(x, y), 0x7f); } oldX = x; @@ -455,6 +455,42 @@ uint HiRes1Engine::getEngineMessage(EngineMessage msg) { } } +void HiRes1Engine::drawLine(Common::Point p1, Common::Point p2, byte color) { + int16 deltaX = p2.x - p1.x; + byte dir = deltaX >> 8; + + if (deltaX < 0) + deltaX = -deltaX; + + int16 err = deltaX; + + int16 deltaY = p2.y - p1.y - 1; + dir >>= 1; + if (deltaY >= 0) { + deltaY = -deltaY - 2; + dir |= 0x80; + } + + int16 steps = deltaY - deltaX; + + err += deltaY + 1; + + while (1) { + _display->putPixel(p1, color); + + if (++steps == 0) + return; + + if (err < 0) { + p1.y += (dir & 0x80 ? 1 : -1); + err += deltaX; + } else { + p1.x += (dir & 0x40 ? -1 : 1); + err += deltaY + 1; + } + } +} + AdlEngine *HiRes1Engine__create(OSystem *syst, const AdlGameDescription *gd) { return new HiRes1Engine(syst, gd); } diff --git a/engines/adl/hires1.h b/engines/adl/hires1.h index 897327cdbf..cae5980102 100644 --- a/engines/adl/hires1.h +++ b/engines/adl/hires1.h @@ -57,6 +57,7 @@ private: void runIntro(); void drawPic(Common::ReadStream &stream, Common::Point pos); void drawItems(); + void drawLine(Common::Point p1, Common::Point p2, byte color); void drawPic(byte pic, Common::Point pos); }; -- cgit v1.2.3 From 4f7e5da4dad61f11553e5f51f00d33506b9ef342 Mon Sep 17 00:00:00 2001 From: Walter van Niftrik Date: Fri, 4 Mar 2016 16:12:11 +0100 Subject: ADL: Clean up Display class --- engines/adl/display.cpp | 364 ++++++++++++++++++++++++------------------------ engines/adl/display.h | 46 +++--- 2 files changed, 204 insertions(+), 206 deletions(-) (limited to 'engines') diff --git a/engines/adl/display.cpp b/engines/adl/display.cpp index 90ca1b60db..55166f4e30 100644 --- a/engines/adl/display.cpp +++ b/engines/adl/display.cpp @@ -20,23 +20,40 @@ * */ -#include "adl/display.h" #include "common/stream.h" #include "common/rect.h" -#include "graphics/surface.h" #include "common/system.h" #include "common/str.h" -#include "common/events.h" -#include "common/rect.h" -#include "common/array.h" #include "common/config-manager.h" -#include "engines/engine.h" -#include "engines/util.h" + +#include "graphics/surface.h" #include "graphics/palette.h" #include "graphics/thumbnail.h" +#include "engines/util.h" + +#include "adl/display.h" + namespace Adl { +#define DISPLAY_PITCH (DISPLAY_WIDTH / 7) + +#define COLOR_PALETTE_SIZE 6 +const byte colorPalette[COLOR_PALETTE_SIZE * 3] = { + 0x00, 0x00, 0x00, + 0xff, 0xff, 0xff, + 0xc7, 0x34, 0xff, + 0x38, 0xcb, 0x00, + 0x0d, 0xa1, 0xff, + 0xf2, 0x5e, 0x00 +}; + +#define MONO_PALETTE_SIZE 2 +const byte monoPalette[MONO_PALETTE_SIZE * 3] = { + 0x00, 0x00, 0x00, + 0x00, 0xc0, 0x01 +}; + static const byte font[64][5] = { { 0x7c, 0x82, 0xba, 0xb2, 0x9c }, { 0xf8, 0x24, 0x22, 0x24, 0xf8 }, // @A { 0xfe, 0x92, 0x92, 0x92, 0x6c }, { 0x7c, 0x82, 0x82, 0x82, 0x44 }, // BC @@ -73,8 +90,8 @@ static const byte font[64][5] = { }; Display::Display() : - _cursorPos(0), _mode(kModeText), + _cursorPos(0), _showCursor(false) { initGraphics(560, 384, true); @@ -83,20 +100,23 @@ Display::Display() : _scanlines = ConfMan.getBool("scanlines"); if (_monochrome) - setMonoPalette(); + g_system->getPaletteManager()->setPalette(monoPalette, 0, MONO_PALETTE_SIZE); else - setColorPalette(); + g_system->getPaletteManager()->setPalette(colorPalette, 0, COLOR_PALETTE_SIZE); enableScanlines(_scanlines); - _frameBuf = new byte[kWidth * kHeight / 7]; + _frameBuf = new byte[DISPLAY_PITCH * DISPLAY_HEIGHT]; _frameBufSurface = new Graphics::Surface; - _frameBufSurface->create(kWidth * 2, kHeight * 2, Graphics::PixelFormat::createFormatCLUT8()); + // We need 2x scaling to properly render the half-pixel shift + // of the second palette + _frameBufSurface->create(DISPLAY_WIDTH * 2, DISPLAY_HEIGHT * 2, Graphics::PixelFormat::createFormatCLUT8()); _textBuf = new byte[kTextBufSize]; - memset(_textBuf, ' ' | 0x80, kTextBufSize); + memset(_textBuf, APPLECHAR(' '), kTextBufSize); _textBufSurface = new Graphics::Surface; - _textBufSurface->create(kWidth * 2, kHeight * 2, Graphics::PixelFormat::createFormatCLUT8()); + // For ease of copying, also use 2x scaling here + _textBufSurface->create(DISPLAY_WIDTH * 2, DISPLAY_HEIGHT * 2, Graphics::PixelFormat::createFormatCLUT8()); createFont(); } @@ -114,6 +134,17 @@ Display::~Display() { delete _font; } +void Display::updateScreen() { + if (_mode == kModeText) { + g_system->copyRectToScreen(_textBufSurface->getPixels(), _textBufSurface->pitch, 0, 0, _textBufSurface->w, _textBufSurface->h); + } else if (_mode == kModeHires) { + g_system->copyRectToScreen(_frameBufSurface->getPixels(), _frameBufSurface->pitch, 0, 0, _frameBufSurface->w, _frameBufSurface->h); + } else { + g_system->copyRectToScreen(_frameBufSurface->getPixels(), _frameBufSurface->pitch, 0, 0, _frameBufSurface->w, _frameBufSurface->h - 4 * 8 * 2); + g_system->copyRectToScreen(_textBufSurface->getBasePtr(0, _textBufSurface->h - 4 * 8 * 2), _textBufSurface->pitch, 0, _textBufSurface->h - 4 * 8 * 2, _textBufSurface->w, 4 * 8 * 2); + } +} + bool Display::saveThumbnail(Common::WriteStream &out) { if (_scanlines) { enableScanlines(false); @@ -130,56 +161,153 @@ bool Display::saveThumbnail(Common::WriteStream &out) { return retval; } -void Display::enableScanlines(bool enable) { - byte pal[6 * 3] = { }; +void Display::loadFrameBuffer(Common::ReadStream &stream) { + for (uint j = 0; j < 8; ++j) { + for (uint i = 0; i < 8; ++i) { + byte *dst = _frameBuf + DISPLAY_PITCH * (i * 8 + j); + stream.read(dst, DISPLAY_PITCH); + dst += DISPLAY_PITCH * 64; + stream.read(dst, DISPLAY_PITCH); + dst += DISPLAY_PITCH * 64; + stream.read(dst, DISPLAY_PITCH); + stream.readUint32LE(); + stream.readUint32LE(); + dst += DISPLAY_PITCH * 64; + } + } +} - if (enable) - g_system->getPaletteManager()->setPalette(pal, 6, 6); - else { - g_system->getPaletteManager()->grabPalette(pal, 0, 6); - g_system->getPaletteManager()->setPalette(pal, 6, 6); +void Display::decodeFrameBuffer() { + byte *src = _frameBuf; + byte *dst = (byte *)_frameBufSurface->getPixels(); + + for (uint i = 0; i < DISPLAY_HEIGHT; ++i) { + decodeScanline(dst, _frameBufSurface->pitch, src); + src += DISPLAY_PITCH; + dst += _frameBufSurface->pitch * 2; } } -void Display::setColorPalette() { - const byte colorPal[6 * 3] = { - 0x00, 0x00, 0x00, - 0xff, 0xff, 0xff, - 0xc7, 0x34, 0xff, - 0x38, 0xcb, 0x00, - 0x0d, 0xa1, 0xff, - 0xf2, 0x5e, 0x00 - }; - - g_system->getPaletteManager()->setPalette(colorPal, 0, 6); +void Display::putPixel(Common::Point p, byte color) { + byte offset = p.x / 7; + + if (offset & 1) { + byte c = color << 1; + if (c >= 0x40 && c < 0xc0) + color ^= 0x7f; + } + + byte *b = _frameBuf + p.y * DISPLAY_PITCH + offset; + color ^= *b; + color &= 1 << (p.x % 7); + *b ^= color; } -void Display::setMonoPalette() { - const byte monoPal[2 * 3] = { - 0x00, 0x00, 0x00, - 0x00, 0xc0, 0x01 - }; +void Display::clear(byte color) { + byte val = 0; + + byte c = color << 1; + if (c >= 0x40 && c < 0xc0) + val = 0x7f; - g_system->getPaletteManager()->setPalette(monoPal, 0, 2); + for (uint i = 0; i < DISPLAY_PITCH * DISPLAY_HEIGHT; ++i) { + _frameBuf[i] = color; + color ^= val; + } } -void Display::loadFrameBuffer(Common::ReadStream &stream) { - for (uint j = 0; j < 8; ++j) { - for (uint i = 0; i < 8; ++i) { - byte *dst = _frameBuf + kWidth / 7 * (i * 8 + j); - stream.read(dst, kWidth / 7); - dst += kWidth / 7 * 64; - stream.read(dst, kWidth / 7); - dst += kWidth / 7 * 64; - stream.read(dst, kWidth / 7); - stream.readUint32LE(); - stream.readUint32LE(); - dst += kWidth / 7 * 64; +void Display::updateTextSurface() { + for (uint row = 0; row < 24; ++row) + for (uint col = 0; col < 40; ++col) { + int charPos = row * 40 + col; + char c = _textBuf[row * 40 + col]; + + if (charPos == _cursorPos && _showCursor) + c = (c & 0x3f) | 0x40; + + Common::Rect r(7 * 2, 8 * 2); + r.translate(((c & 0x3f) % 16) * 7 * 2, (c & 0x3f) / 16 * 8 * 2); + + if (!(c & 0x80)) { + if (!(c & 0x40) || ((g_system->getMillis() / 270) & 1)) + r.translate(0, 4 * 8 * 2); + } + + _textBufSurface->copyRectToSurface(*_font, col * 7 * 2, row * 8 * 2, r); + } +} + + +void Display::setCursorPos(Common::Point pos) { + _cursorPos = pos.y * 40 + pos.x; +} + + +void Display::home() { + memset(_textBuf, APPLECHAR(' '), kTextBufSize); + _cursorPos = 0; +} + +void Display::moveCursorForward() { + ++_cursorPos; + + if (_cursorPos >= kTextBufSize) + scrollUp(); +} + +void Display::moveCursorBackward() { + --_cursorPos; + + if (_cursorPos < 0) + _cursorPos = 0; +} + +void Display::moveCursorTo(const Common::Point &pos) { + _cursorPos = pos.y * 40 + pos.x; + + if (_cursorPos >= kTextBufSize) + error("Cursor position (%i, %i) out of bounds", pos.x, pos.y); +} + +void Display::printString(const Common::String &str) { + Common::String::const_iterator c; + for (c = str.begin(); c != str.end(); ++c) { + byte b = *c; + + if (*c == APPLECHAR('\r')) + _cursorPos = (_cursorPos / 40 + 1) * 40; + else if (b < 0x80 || b >= 0xa0) { + setCharAtCursor(b); + ++_cursorPos; } + + if (_cursorPos == kTextBufSize) + scrollUp(); } + + updateTextSurface(); } -void Display::decodeScanlineColor(byte *dst, int pitch, byte *src) { +void Display::setCharAtCursor(byte c) { + _textBuf[_cursorPos] = c; +} + +void Display::showCursor(bool enable) { + _showCursor = enable; +} + +void Display::enableScanlines(bool enable) { + byte pal[6 * 3] = { }; + + if (enable) + g_system->getPaletteManager()->setPalette(pal, 6, 6); + else { + g_system->getPaletteManager()->grabPalette(pal, 0, 6); + g_system->getPaletteManager()->setPalette(pal, 6, 6); + } +} + +void Display::decodeScanlineColor(byte *dst, int pitch, byte *src) const { // TODO: shift secondPal by half a pixel bool prevOn = false; @@ -221,7 +349,7 @@ void Display::decodeScanlineColor(byte *dst, int pitch, byte *src) { } } -void Display::decodeScanlineMono(byte *dst, int pitch, byte *src) { +void Display::decodeScanlineMono(byte *dst, int pitch, byte *src) const { // TODO: shift secondPal by half a pixel for (uint j = 0; j < 39; ++j) { @@ -241,73 +369,13 @@ void Display::decodeScanlineMono(byte *dst, int pitch, byte *src) { } } -void Display::decodeScanline(byte *dst, int pitch, byte *src) { +void Display::decodeScanline(byte *dst, int pitch, byte *src) const { if (_monochrome) decodeScanlineMono(dst, pitch, src); else decodeScanlineColor(dst, pitch, src); } -void Display::decodeFrameBuffer() { - byte *src = _frameBuf; - byte *dst = (byte *)_frameBufSurface->getPixels(); - - for (uint i = 0; i < kHeight; ++i) { - decodeScanline(dst, _frameBufSurface->pitch, src); - src += kWidth / 7; - dst += _frameBufSurface->pitch * 2; - } -} - -void Display::putPixel(Common::Point p, byte color) { - byte offset = p.x / 7; - - if (offset & 1) { - byte c = color << 1; - if (c >= 0x40 && c < 0xc0) - color ^= 0x7f; - } - - byte *b = _frameBuf + p.y * kWidth / 7 + offset; - color ^= *b; - color &= 1 << (p.x % 7); - *b ^= color; -} - -void Display::clear(byte color) { - byte val = 0; - - byte c = color << 1; - if (c >= 0x40 && c < 0xc0) - val = 0x7f; - - for (uint i = 0; i < kWidth / 7 * kHeight; ++i) { - _frameBuf[i] = color; - color ^= val; - } -} - -void Display::updateTextSurface() { - for (uint row = 0; row < 24; ++row) - for (uint col = 0; col < 40; ++col) { - int charPos = row * 40 + col; - char c = _textBuf[row * 40 + col]; - - if (charPos == _cursorPos && _showCursor) - c = (c & 0x3f) | 0x40; - - Common::Rect r(7 * 2, 8 * 2); - r.translate(((c & 0x3f) % 16) * 7 * 2, (c & 0x3f) / 16 * 8 * 2); - - if (!(c & 0x80)) { - if (!(c & 0x40) || ((g_system->getMillis() / 270) & 1)) - r.translate(0, 4 * 8 * 2); - } - - _textBufSurface->copyRectToSurface(*_font, col * 7 * 2, row * 8 * 2, r); - } -} - void Display::drawChar(byte c, int x, int y) { byte *buf = (byte *)_font->getPixels() + y * _font->pitch + x; @@ -361,78 +429,10 @@ void Display::createFont() { } } -void Display::updateScreen() { - if (_mode == kModeText) { - g_system->copyRectToScreen(_textBufSurface->getPixels(), _textBufSurface->pitch, 0, 0, _textBufSurface->w, _textBufSurface->h); - } else if (_mode == kModeHires) { - g_system->copyRectToScreen(_frameBufSurface->getPixels(), _frameBufSurface->pitch, 0, 0, _frameBufSurface->w, _frameBufSurface->h); - } else { - g_system->copyRectToScreen(_frameBufSurface->getPixels(), _frameBufSurface->pitch, 0, 0, _frameBufSurface->w, _frameBufSurface->h - 4 * 8 * 2); - g_system->copyRectToScreen(_textBufSurface->getBasePtr(0, _textBufSurface->h - 4 * 8 * 2), _textBufSurface->pitch, 0, _textBufSurface->h - 4 * 8 * 2, _textBufSurface->w, 4 * 8 * 2); - } -} - -void Display::home() { - memset(_textBuf, APPLECHAR(' '), kTextBufSize); - _cursorPos = 0; -} - -void Display::moveCursorForward() { - ++_cursorPos; - - if (_cursorPos >= kTextBufSize) - scrollUp(); -} - -void Display::moveCursorBackward() { - --_cursorPos; - - if (_cursorPos < 0) - _cursorPos = 0; -} - -void Display::moveCursorTo(const Common::Point &pos) { - _cursorPos = pos.y * 40 + pos.x; - - if (_cursorPos >= kTextBufSize) - error("Cursor position (%i, %i) out of bounds", pos.x, pos.y); -} - -void Display::setCharAtCursor(byte c) { - _textBuf[_cursorPos] = c; -} - void Display::scrollUp() { memmove(_textBuf, _textBuf + 40, kTextBufSize - 40); - memset(_textBuf + kTextBufSize - 40, ' ' | 0x80, 40); + memset(_textBuf + kTextBufSize - 40, APPLECHAR(' '), 40); _cursorPos -= 40; } -void Display::printString(const Common::String &str) { - Common::String::const_iterator c; - for (c = str.begin(); c != str.end(); ++c) { - byte b = *c; - - if (*c == APPLECHAR('\r')) - _cursorPos = (_cursorPos / 40 + 1) * 40; - else if (b < 0x80 || b >= 0xa0) { - setCharAtCursor(b); - ++_cursorPos; - } - - if (_cursorPos == kTextBufSize) - scrollUp(); - } - - updateTextSurface(); -} - -void Display::showCursor(bool enable) { - _showCursor = enable; -} - -void Display::setCursorPos(Common::Point pos) { - _cursorPos = pos.y * 40 + pos.x; -} - } // End of namespace Adl diff --git a/engines/adl/display.h b/engines/adl/display.h index 0452b2768f..70dc42df63 100644 --- a/engines/adl/display.h +++ b/engines/adl/display.h @@ -24,7 +24,6 @@ #define ADL_DISPLAY_H #include -#include namespace Common { class ReadStream; @@ -39,6 +38,9 @@ class Surface; namespace Adl { +#define DISPLAY_WIDTH 280 +#define DISPLAY_HEIGHT 192 + #define APPLECHAR(C) ((char)((C) | 0x80)) class Display { @@ -51,17 +53,20 @@ public: Display(); ~Display(); - void enableScanlines(bool enable); - void setMonoPalette(); - void setColorPalette(); + + void setMode(Mode mode) { _mode = mode; } + void updateScreen(); + bool saveThumbnail(Common::WriteStream &out); + + // Graphics void loadFrameBuffer(Common::ReadStream &stream); void decodeFrameBuffer(); - void updateScreen(); - void setMode(Mode mode) { _mode = mode; } void putPixel(Common::Point p1, byte color); void clear(byte color); - void setCursorPos(Common::Point pos); + // Text + void updateTextSurface(); + void setCursorPos(Common::Point pos); void home(); void moveCursorTo(const Common::Point &pos); void moveCursorForward(); @@ -69,40 +74,33 @@ public: void printString(const Common::String &str); void setCharAtCursor(byte c); void showCursor(bool enable); - void updateTextSurface(); - bool saveThumbnail(Common::WriteStream &out); private: enum { - kWidth = 280, - kHeight = 192, kTextBufSize = 40 * 24 }; - struct PixelPos { - uint16 rowAddr; - byte byteOffset; - byte bitMask; - }; + void enableScanlines(bool enable); + void decodeScanlineColor(byte *dst, int pitch, byte *src) const; + void decodeScanlineMono(byte *dst, int pitch, byte *src) const; + void decodeScanline(byte *dst, int pitch, byte *src) const; - void decodeScanline(byte *dst, int pitch, byte *src); - void decodeScanlineColor(byte *dst, int pitch, byte *src); - void decodeScanlineMono(byte *dst, int pitch, byte *src); void drawChar(byte c, int x, int y); void createFont(); - void scrollUp(); - bool _scanlines; + Mode _mode; + byte *_frameBuf; - byte *_textBuf; Graphics::Surface *_frameBufSurface; + bool _scanlines; + bool _monochrome; + + byte *_textBuf; Graphics::Surface *_textBufSurface; Graphics::Surface *_font; int _cursorPos; - Mode _mode; bool _showCursor; - bool _monochrome; }; } // End of namespace Adl -- cgit v1.2.3 From 115e4cab0d3bd18b0e189c7c304e32f122836f75 Mon Sep 17 00:00:00 2001 From: Walter van Niftrik Date: Fri, 4 Mar 2016 16:30:40 +0100 Subject: ADL: Fix restoring on restart prompt --- engines/adl/adl.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'engines') diff --git a/engines/adl/adl.cpp b/engines/adl/adl.cpp index 90a9a0db06..d2d8492a23 100644 --- a/engines/adl/adl.cpp +++ b/engines/adl/adl.cpp @@ -291,7 +291,11 @@ void AdlEngine::doActions(const Command &command, byte noun, byte offset) { case IDO_ACT_LOAD: loadGameState(0); ++offset; - // Original engine continues processing here (?) + // Original engine does not jump out of the loop, + // so we don't either. + // We reset the restore flag, as the restore game + // process is complete + _isRestoring = false; break; case IDO_ACT_RESTART: { _display->printString(_strings[IDI_STR_PLAY_AGAIN]); @@ -301,6 +305,7 @@ void AdlEngine::doActions(const Command &command, byte noun, byte offset) { Common::String input = inputString(); _canRestoreNow = false; + // If the user restored with the GMM, we break off the restart if (_isRestoring) return; @@ -661,6 +666,7 @@ Common::Error AdlEngine::loadGameState(int slot) { setTotalPlayTime(playTime); + _isRestoring = true; return Common::kNoError; } -- cgit v1.2.3 From ec14c397eec87ee66337a9f15c044b47fec8855d Mon Sep 17 00:00:00 2001 From: Walter van Niftrik Date: Fri, 4 Mar 2016 18:48:31 +0100 Subject: ADL: Clean up Display class --- engines/adl/adl.cpp | 6 +++--- engines/adl/display.cpp | 12 +++--------- engines/adl/display.h | 17 ++++++++--------- engines/adl/hires1.cpp | 12 ++++++------ 4 files changed, 20 insertions(+), 27 deletions(-) (limited to 'engines') diff --git a/engines/adl/adl.cpp b/engines/adl/adl.cpp index d2d8492a23..99267baa00 100644 --- a/engines/adl/adl.cpp +++ b/engines/adl/adl.cpp @@ -76,7 +76,7 @@ Common::Error AdlEngine::run() { if (saveSlot >= 0) { if (loadGameState(saveSlot).getCode() != Common::kNoError) error("Failed to load save game from slot %i", saveSlot); - _display->setCursorPos(Common::Point(0, 23)); + _display->moveCursorTo(Common::Point(0, 23)); _isRestoring = true; } else { runIntro(); @@ -472,7 +472,7 @@ bool AdlEngine::canLoadGameStateCurrently() { } void AdlEngine::clearScreen() { - _display->setMode(Display::kModeMixed); + _display->setMode(DISPLAY_MODE_MIXED); _display->clear(0x00); } @@ -744,7 +744,7 @@ Common::String AdlEngine::getLine() { if ((byte)line[0] == ('\r' | 0x80)) { textMode = !textMode; - _display->setMode(textMode ? Display::kModeText : Display::kModeMixed); + _display->setMode(textMode ? DISPLAY_MODE_TEXT : DISPLAY_MODE_MIXED); continue; } diff --git a/engines/adl/display.cpp b/engines/adl/display.cpp index 55166f4e30..a75b129dc8 100644 --- a/engines/adl/display.cpp +++ b/engines/adl/display.cpp @@ -90,7 +90,7 @@ static const byte font[64][5] = { }; Display::Display() : - _mode(kModeText), + _mode(DISPLAY_MODE_TEXT), _cursorPos(0), _showCursor(false) { @@ -135,9 +135,9 @@ Display::~Display() { } void Display::updateScreen() { - if (_mode == kModeText) { + if (_mode == DISPLAY_MODE_TEXT) { g_system->copyRectToScreen(_textBufSurface->getPixels(), _textBufSurface->pitch, 0, 0, _textBufSurface->w, _textBufSurface->h); - } else if (_mode == kModeHires) { + } else if (_mode == DISPLAY_MODE_HIRES) { g_system->copyRectToScreen(_frameBufSurface->getPixels(), _frameBufSurface->pitch, 0, 0, _frameBufSurface->w, _frameBufSurface->h); } else { g_system->copyRectToScreen(_frameBufSurface->getPixels(), _frameBufSurface->pitch, 0, 0, _frameBufSurface->w, _frameBufSurface->h - 4 * 8 * 2); @@ -237,12 +237,6 @@ void Display::updateTextSurface() { } } - -void Display::setCursorPos(Common::Point pos) { - _cursorPos = pos.y * 40 + pos.x; -} - - void Display::home() { memset(_textBuf, APPLECHAR(' '), kTextBufSize); _cursorPos = 0; diff --git a/engines/adl/display.h b/engines/adl/display.h index 70dc42df63..40151c1c6a 100644 --- a/engines/adl/display.h +++ b/engines/adl/display.h @@ -41,20 +41,20 @@ namespace Adl { #define DISPLAY_WIDTH 280 #define DISPLAY_HEIGHT 192 +enum DisplayMode { + DISPLAY_MODE_HIRES, + DISPLAY_MODE_TEXT, + DISPLAY_MODE_MIXED +}; + #define APPLECHAR(C) ((char)((C) | 0x80)) class Display { public: - enum Mode { - kModeHires, - kModeText, - kModeMixed - }; - Display(); ~Display(); - void setMode(Mode mode) { _mode = mode; } + void setMode(DisplayMode mode) { _mode = mode; } void updateScreen(); bool saveThumbnail(Common::WriteStream &out); @@ -66,7 +66,6 @@ public: // Text void updateTextSurface(); - void setCursorPos(Common::Point pos); void home(); void moveCursorTo(const Common::Point &pos); void moveCursorForward(); @@ -89,7 +88,7 @@ private: void createFont(); void scrollUp(); - Mode _mode; + DisplayMode _mode; byte *_frameBuf; Graphics::Surface *_frameBufSurface; diff --git a/engines/adl/hires1.cpp b/engines/adl/hires1.cpp index 04df01ecd4..6c369222b1 100644 --- a/engines/adl/hires1.cpp +++ b/engines/adl/hires1.cpp @@ -94,7 +94,7 @@ void HiRes1Engine::runIntro() { error("Failed to open file"); file.seek(IDI_HR1_OFS_LOGO_0); - _display->setMode(Display::kModeHires); + _display->setMode(DISPLAY_MODE_HIRES); _display->loadFrameBuffer(file); _display->decodeFrameBuffer(); delay(4000); @@ -102,7 +102,7 @@ void HiRes1Engine::runIntro() { if (shouldQuit()) return; - _display->setMode(Display::kModeText); + _display->setMode(DISPLAY_MODE_TEXT); Common::File basic; if (!basic.open("MYSTERY.HELLO")) @@ -130,7 +130,7 @@ void HiRes1Engine::runIntro() { if (g_engine->shouldQuit()) return; - _display->setMode(Display::kModeMixed); + _display->setMode(DISPLAY_MODE_MIXED); file.seek(IDI_HR1_OFS_GAME_OR_HELP); str = readString(file); @@ -156,7 +156,7 @@ void HiRes1Engine::runIntro() { }; if (instructions) { - _display->setMode(Display::kModeText); + _display->setMode(DISPLAY_MODE_TEXT); file.seek(IDI_HR1_OFS_INTRO_TEXT); const uint pages[] = { 6, 6, 4, 5, 8, 7, 0 }; @@ -178,7 +178,7 @@ void HiRes1Engine::runIntro() { file.close(); - _display->setMode(Display::kModeMixed); + _display->setMode(DISPLAY_MODE_MIXED); if (!file.open("ADVENTURE")) error("Failed to open file"); @@ -298,7 +298,7 @@ void HiRes1Engine::restartGame() { } void HiRes1Engine::runGame() { - _display->setMode(Display::kModeMixed); + _display->setMode(DISPLAY_MODE_MIXED); Common::File f; -- cgit v1.2.3 From e6d478ad150f7eb702f12c8d3a60bfcd416f2b2e Mon Sep 17 00:00:00 2001 From: Walter van Niftrik Date: Fri, 4 Mar 2016 20:06:16 +0100 Subject: ADL: Clean up Display class --- engines/adl/adl.cpp | 10 ++--- engines/adl/display.cpp | 114 +++++++++++++++++++++++++++++------------------- engines/adl/display.h | 9 ++-- engines/adl/hires1.cpp | 4 +- 4 files changed, 78 insertions(+), 59 deletions(-) (limited to 'engines') diff --git a/engines/adl/adl.cpp b/engines/adl/adl.cpp index 99267baa00..313b14681e 100644 --- a/engines/adl/adl.cpp +++ b/engines/adl/adl.cpp @@ -312,7 +312,7 @@ void AdlEngine::doActions(const Command &command, byte noun, byte offset) { if (input.size() == 0 || input[0] != APPLECHAR('N')) { _isRestarting = true; _display->clear(0x00); - _display->decodeFrameBuffer(); + _display->updateHiResScreen(); restartGame(); return; } @@ -515,9 +515,9 @@ void AdlEngine::showRoom() { if (!_state.isDark) { drawPic(curRoom().curPicture); drawItems(); + _display->updateHiResScreen(); } - _display->decodeFrameBuffer(); printMessage(curRoom().description, false); } @@ -913,9 +913,7 @@ byte AdlEngine::inputKey() { }; } - _display->updateTextSurface(); - _display->updateScreen(); - g_system->updateScreen(); + _display->updateTextScreen(); g_system->delayMillis(16); } @@ -942,8 +940,6 @@ void AdlEngine::delay(uint32 ms) { } } } - _display->updateScreen(); - g_system->updateScreen(); g_system->delayMillis(16); } } diff --git a/engines/adl/display.cpp b/engines/adl/display.cpp index a75b129dc8..05c96cfcda 100644 --- a/engines/adl/display.cpp +++ b/engines/adl/display.cpp @@ -36,10 +36,12 @@ namespace Adl { +// TODO: Implement partial screen updates + #define DISPLAY_PITCH (DISPLAY_WIDTH / 7) -#define COLOR_PALETTE_SIZE 6 -const byte colorPalette[COLOR_PALETTE_SIZE * 3] = { +#define COLOR_PALETTE_ENTRIES 6 +const byte colorPalette[COLOR_PALETTE_ENTRIES * 3] = { 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xc7, 0x34, 0xff, @@ -48,8 +50,8 @@ const byte colorPalette[COLOR_PALETTE_SIZE * 3] = { 0xf2, 0x5e, 0x00 }; -#define MONO_PALETTE_SIZE 2 -const byte monoPalette[MONO_PALETTE_SIZE * 3] = { +#define MONO_PALETTE_ENTRIES 2 +const byte monoPalette[MONO_PALETTE_ENTRIES * 3] = { 0x00, 0x00, 0x00, 0x00, 0xc0, 0x01 }; @@ -100,9 +102,9 @@ Display::Display() : _scanlines = ConfMan.getBool("scanlines"); if (_monochrome) - g_system->getPaletteManager()->setPalette(monoPalette, 0, MONO_PALETTE_SIZE); + g_system->getPaletteManager()->setPalette(monoPalette, 0, MONO_PALETTE_ENTRIES); else - g_system->getPaletteManager()->setPalette(colorPalette, 0, COLOR_PALETTE_SIZE); + g_system->getPaletteManager()->setPalette(colorPalette, 0, COLOR_PALETTE_ENTRIES); enableScanlines(_scanlines); @@ -134,15 +136,35 @@ Display::~Display() { delete _font; } -void Display::updateScreen() { - if (_mode == DISPLAY_MODE_TEXT) { +void Display::setMode(DisplayMode mode) { + _mode = mode; + + if (_mode == DISPLAY_MODE_TEXT || _mode == DISPLAY_MODE_MIXED) + updateTextScreen(); + if (_mode == DISPLAY_MODE_HIRES || _mode == DISPLAY_MODE_MIXED) + updateHiResScreen(); +} + +void Display::updateTextScreen() { + updateTextSurface(); + + if (_mode == DISPLAY_MODE_TEXT) g_system->copyRectToScreen(_textBufSurface->getPixels(), _textBufSurface->pitch, 0, 0, _textBufSurface->w, _textBufSurface->h); - } else if (_mode == DISPLAY_MODE_HIRES) { + else if (_mode == DISPLAY_MODE_MIXED) + g_system->copyRectToScreen(_textBufSurface->getBasePtr(0, _textBufSurface->h - 4 * 8 * 2), _textBufSurface->pitch, 0, _textBufSurface->h - 4 * 8 * 2, _textBufSurface->w, 4 * 8 * 2); + + g_system->updateScreen(); +} + +void Display::updateHiResScreen() { + updateHiResSurface(); + + if (_mode == DISPLAY_MODE_HIRES) g_system->copyRectToScreen(_frameBufSurface->getPixels(), _frameBufSurface->pitch, 0, 0, _frameBufSurface->w, _frameBufSurface->h); - } else { + else if (_mode == DISPLAY_MODE_MIXED) g_system->copyRectToScreen(_frameBufSurface->getPixels(), _frameBufSurface->pitch, 0, 0, _frameBufSurface->w, _frameBufSurface->h - 4 * 8 * 2); - g_system->copyRectToScreen(_textBufSurface->getBasePtr(0, _textBufSurface->h - 4 * 8 * 2), _textBufSurface->pitch, 0, _textBufSurface->h - 4 * 8 * 2, _textBufSurface->w, 4 * 8 * 2); - } + + g_system->updateScreen(); } bool Display::saveThumbnail(Common::WriteStream &out) { @@ -177,17 +199,6 @@ void Display::loadFrameBuffer(Common::ReadStream &stream) { } } -void Display::decodeFrameBuffer() { - byte *src = _frameBuf; - byte *dst = (byte *)_frameBufSurface->getPixels(); - - for (uint i = 0; i < DISPLAY_HEIGHT; ++i) { - decodeScanline(dst, _frameBufSurface->pitch, src); - src += DISPLAY_PITCH; - dst += _frameBufSurface->pitch * 2; - } -} - void Display::putPixel(Common::Point p, byte color) { byte offset = p.x / 7; @@ -216,27 +227,6 @@ void Display::clear(byte color) { } } -void Display::updateTextSurface() { - for (uint row = 0; row < 24; ++row) - for (uint col = 0; col < 40; ++col) { - int charPos = row * 40 + col; - char c = _textBuf[row * 40 + col]; - - if (charPos == _cursorPos && _showCursor) - c = (c & 0x3f) | 0x40; - - Common::Rect r(7 * 2, 8 * 2); - r.translate(((c & 0x3f) % 16) * 7 * 2, (c & 0x3f) / 16 * 8 * 2); - - if (!(c & 0x80)) { - if (!(c & 0x40) || ((g_system->getMillis() / 270) & 1)) - r.translate(0, 4 * 8 * 2); - } - - _textBufSurface->copyRectToSurface(*_font, col * 7 * 2, row * 8 * 2, r); - } -} - void Display::home() { memset(_textBuf, APPLECHAR(' '), kTextBufSize); _cursorPos = 0; @@ -279,7 +269,7 @@ void Display::printString(const Common::String &str) { scrollUp(); } - updateTextSurface(); + updateTextScreen(); } void Display::setCharAtCursor(byte c) { @@ -291,7 +281,7 @@ void Display::showCursor(bool enable) { } void Display::enableScanlines(bool enable) { - byte pal[6 * 3] = { }; + byte pal[COLOR_PALETTE_ENTRIES * 3] = { }; if (enable) g_system->getPaletteManager()->setPalette(pal, 6, 6); @@ -301,6 +291,17 @@ void Display::enableScanlines(bool enable) { } } +void Display::updateHiResSurface() { + byte *src = _frameBuf; + byte *dst = (byte *)_frameBufSurface->getPixels(); + + for (uint i = 0; i < DISPLAY_HEIGHT; ++i) { + decodeScanline(dst, _frameBufSurface->pitch, src); + src += DISPLAY_PITCH; + dst += _frameBufSurface->pitch * 2; + } +} + void Display::decodeScanlineColor(byte *dst, int pitch, byte *src) const { // TODO: shift secondPal by half a pixel @@ -370,6 +371,27 @@ void Display::decodeScanline(byte *dst, int pitch, byte *src) const { decodeScanlineColor(dst, pitch, src); } +void Display::updateTextSurface() { + for (uint row = 0; row < 24; ++row) + for (uint col = 0; col < 40; ++col) { + int charPos = row * 40 + col; + char c = _textBuf[row * 40 + col]; + + if (charPos == _cursorPos && _showCursor) + c = (c & 0x3f) | 0x40; + + Common::Rect r(7 * 2, 8 * 2); + r.translate(((c & 0x3f) % 16) * 7 * 2, (c & 0x3f) / 16 * 8 * 2); + + if (!(c & 0x80)) { + if (!(c & 0x40) || ((g_system->getMillis() / 270) & 1)) + r.translate(0, 4 * 8 * 2); + } + + _textBufSurface->copyRectToSurface(*_font, col * 7 * 2, row * 8 * 2, r); + } +} + void Display::drawChar(byte c, int x, int y) { byte *buf = (byte *)_font->getPixels() + y * _font->pitch + x; diff --git a/engines/adl/display.h b/engines/adl/display.h index 40151c1c6a..16b52bf9a3 100644 --- a/engines/adl/display.h +++ b/engines/adl/display.h @@ -54,18 +54,17 @@ public: Display(); ~Display(); - void setMode(DisplayMode mode) { _mode = mode; } - void updateScreen(); + void setMode(DisplayMode mode); + void updateTextScreen(); + void updateHiResScreen(); bool saveThumbnail(Common::WriteStream &out); // Graphics void loadFrameBuffer(Common::ReadStream &stream); - void decodeFrameBuffer(); void putPixel(Common::Point p1, byte color); void clear(byte color); // Text - void updateTextSurface(); void home(); void moveCursorTo(const Common::Point &pos); void moveCursorForward(); @@ -79,11 +78,13 @@ private: kTextBufSize = 40 * 24 }; + void updateHiResSurface(); void enableScanlines(bool enable); void decodeScanlineColor(byte *dst, int pitch, byte *src) const; void decodeScanlineMono(byte *dst, int pitch, byte *src) const; void decodeScanline(byte *dst, int pitch, byte *src) const; + void updateTextSurface(); void drawChar(byte c, int x, int y); void createFont(); void scrollUp(); diff --git a/engines/adl/hires1.cpp b/engines/adl/hires1.cpp index 6c369222b1..8b5b9220f7 100644 --- a/engines/adl/hires1.cpp +++ b/engines/adl/hires1.cpp @@ -96,7 +96,7 @@ void HiRes1Engine::runIntro() { file.seek(IDI_HR1_OFS_LOGO_0); _display->setMode(DISPLAY_MODE_HIRES); _display->loadFrameBuffer(file); - _display->decodeFrameBuffer(); + _display->updateHiResScreen(); delay(4000); if (shouldQuit()) @@ -186,7 +186,7 @@ void HiRes1Engine::runIntro() { // Title screen shown during loading file.seek(0x1800); _display->loadFrameBuffer(file); - _display->decodeFrameBuffer(); + _display->updateHiResScreen(); delay(2000); } -- cgit v1.2.3 From 6f9128983847d78a41da7cf2f16a1243c7c1fa28 Mon Sep 17 00:00:00 2001 From: Walter van Niftrik Date: Fri, 4 Mar 2016 22:35:12 +0100 Subject: ADL: Clean up Display class --- engines/adl/display.cpp | 14 +++++++------- engines/adl/display.h | 2 +- 2 files changed, 8 insertions(+), 8 deletions(-) (limited to 'engines') diff --git a/engines/adl/display.cpp b/engines/adl/display.cpp index 05c96cfcda..e8ea8211ce 100644 --- a/engines/adl/display.cpp +++ b/engines/adl/display.cpp @@ -106,7 +106,7 @@ Display::Display() : else g_system->getPaletteManager()->setPalette(colorPalette, 0, COLOR_PALETTE_ENTRIES); - enableScanlines(_scanlines); + showScanlines(_scanlines); _frameBuf = new byte[DISPLAY_PITCH * DISPLAY_HEIGHT]; _frameBufSurface = new Graphics::Surface; @@ -169,14 +169,14 @@ void Display::updateHiResScreen() { bool Display::saveThumbnail(Common::WriteStream &out) { if (_scanlines) { - enableScanlines(false); + showScanlines(false); g_system->updateScreen(); } bool retval = Graphics::saveThumbnail(out); if (_scanlines) { - enableScanlines(true); + showScanlines(true); g_system->updateScreen(); } @@ -280,14 +280,14 @@ void Display::showCursor(bool enable) { _showCursor = enable; } -void Display::enableScanlines(bool enable) { +void Display::showScanlines(bool enable) { byte pal[COLOR_PALETTE_ENTRIES * 3] = { }; if (enable) - g_system->getPaletteManager()->setPalette(pal, 6, 6); + g_system->getPaletteManager()->setPalette(pal, COLOR_PALETTE_ENTRIES, COLOR_PALETTE_ENTRIES); else { - g_system->getPaletteManager()->grabPalette(pal, 0, 6); - g_system->getPaletteManager()->setPalette(pal, 6, 6); + g_system->getPaletteManager()->grabPalette(pal, 0, COLOR_PALETTE_ENTRIES); + g_system->getPaletteManager()->setPalette(pal, COLOR_PALETTE_ENTRIES, COLOR_PALETTE_ENTRIES); } } diff --git a/engines/adl/display.h b/engines/adl/display.h index 16b52bf9a3..b93128f6a5 100644 --- a/engines/adl/display.h +++ b/engines/adl/display.h @@ -79,7 +79,7 @@ private: }; void updateHiResSurface(); - void enableScanlines(bool enable); + void showScanlines(bool enable); void decodeScanlineColor(byte *dst, int pitch, byte *src) const; void decodeScanlineMono(byte *dst, int pitch, byte *src) const; void decodeScanline(byte *dst, int pitch, byte *src) const; -- cgit v1.2.3 From f5430f961bd937755e85da17d24e8d3f22470545 Mon Sep 17 00:00:00 2001 From: Walter van Niftrik Date: Sat, 5 Mar 2016 08:10:43 +0100 Subject: ADL: Implement half-pixel shift in color mode --- engines/adl/display.cpp | 72 ++++++++++++++++++++++++++++++++----------------- 1 file changed, 48 insertions(+), 24 deletions(-) (limited to 'engines') diff --git a/engines/adl/display.cpp b/engines/adl/display.cpp index e8ea8211ce..678b8c8bcf 100644 --- a/engines/adl/display.cpp +++ b/engines/adl/display.cpp @@ -36,20 +36,23 @@ namespace Adl { -// TODO: Implement partial screen updates +// This implements the Apple II "Hi-Res" display mode #define DISPLAY_PITCH (DISPLAY_WIDTH / 7) -#define COLOR_PALETTE_ENTRIES 6 +#define COLOR_PALETTE_ENTRIES 8 const byte colorPalette[COLOR_PALETTE_ENTRIES * 3] = { 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xc7, 0x34, 0xff, 0x38, 0xcb, 0x00, + 0x00, 0x00, 0x00, + 0xff, 0xff, 0xff, 0x0d, 0xa1, 0xff, 0xf2, 0x5e, 0x00 }; +// Green monochrome palette #define MONO_PALETTE_ENTRIES 2 const byte monoPalette[MONO_PALETTE_ENTRIES * 3] = { 0x00, 0x00, 0x00, @@ -303,11 +306,12 @@ void Display::updateHiResSurface() { } void Display::decodeScanlineColor(byte *dst, int pitch, byte *src) const { - // TODO: shift secondPal by half a pixel - bool prevOn = false; - for (uint j = 0; j < 39; ++j) { + if (src[0] & 0x80) + dst++; + + for (uint j = 0; j < 40; ++j) { bool secondPal = src[j] & 0x80; byte cur = src[j]; byte next = 0; @@ -326,19 +330,39 @@ void Display::decodeScanlineColor(byte *dst, int pitch, byte *src) const { byte color; if (curOn == prevOn || curOn == nextOn) color = curOn ? 1 : 0; - else { - if (secondPal) - color = (curOn == ((j + k) % 2) ? 5 : 4); - else - color = (curOn == ((j + k) % 2) ? 3 : 2); - } + else + color = (curOn == ((j + k) % 2) ? 3 : 2); + + if (secondPal) + color |= 4; dst[0] = color; - dst[1] = color; - dst[pitch] = color + 6; - dst[pitch + 1] = color + 6; + dst[pitch] = color + COLOR_PALETTE_ENTRIES; + ++dst; + + if (k == 6) { + if (secondPal) { + if (next & 0x80) { + dst[0] = color; + dst[pitch] = color + COLOR_PALETTE_ENTRIES; + ++dst; + } + } else { + dst[0] = color; + dst[pitch] = color + COLOR_PALETTE_ENTRIES; + ++dst; + if (next & 0x80) { + dst[0] = color | 4; + dst[pitch] = (color | 4) + COLOR_PALETTE_ENTRIES; + ++dst; + } + } + } else { + dst[0] = color; + dst[pitch] = color + COLOR_PALETTE_ENTRIES; + ++dst; + } - dst += 2; prevOn = curOn; } } @@ -397,20 +421,20 @@ void Display::drawChar(byte c, int x, int y) { for (uint row = 0; row < 8; ++row) { if (row & 1) { - buf[_font->pitch] = 6; - buf[_font->pitch + 1] = 6; - buf[_font->pitch + 6 * 2] = 6; - buf[_font->pitch + 6 * 2 + 1] = 6; + buf[_font->pitch] = COLOR_PALETTE_ENTRIES; + buf[_font->pitch + 1] = COLOR_PALETTE_ENTRIES; + buf[_font->pitch + 6 * 2] = COLOR_PALETTE_ENTRIES; + buf[_font->pitch + 6 * 2 + 1] = COLOR_PALETTE_ENTRIES; } for (uint col = 1; col < 6; ++col) { if (font[c][col - 1] & (1 << row)) { buf[col * 2] = 1; buf[col * 2 + 1] = 1; - buf[_font->pitch + col * 2] = 1 + 6; - buf[_font->pitch + col * 2 + 1] = 1 + 6; + buf[_font->pitch + col * 2] = 1 + COLOR_PALETTE_ENTRIES; + buf[_font->pitch + col * 2 + 1] = 1 + COLOR_PALETTE_ENTRIES; } else { - buf[_font->pitch + col * 2] = 6; - buf[_font->pitch + col * 2 + 1] = 6; + buf[_font->pitch + col * 2] = COLOR_PALETTE_ENTRIES; + buf[_font->pitch + col * 2 + 1] = COLOR_PALETTE_ENTRIES; } } @@ -438,7 +462,7 @@ void Display::createFont() { bufInv += _font->pitch; for (uint col = 0; col < _font->w; ++col) - bufInv[col] = (buf[col] == 7 ? 6 : 7); + bufInv[col] = (buf[col] == COLOR_PALETTE_ENTRIES + 1 ? COLOR_PALETTE_ENTRIES : COLOR_PALETTE_ENTRIES + 1); buf += _font->pitch; bufInv += _font->pitch; -- cgit v1.2.3 From 50d6e6938a60b323e1a1fbe2559e175492625cba Mon Sep 17 00:00:00 2001 From: Walter van Niftrik Date: Sat, 5 Mar 2016 12:34:48 +0100 Subject: ADL: Refactor graphics code --- engines/adl/display.cpp | 155 ++++++++++++++++++++++++++---------------------- 1 file changed, 84 insertions(+), 71 deletions(-) (limited to 'engines') diff --git a/engines/adl/display.cpp b/engines/adl/display.cpp index 678b8c8bcf..2a24b65a18 100644 --- a/engines/adl/display.cpp +++ b/engines/adl/display.cpp @@ -52,6 +52,12 @@ const byte colorPalette[COLOR_PALETTE_ENTRIES * 3] = { 0xf2, 0x5e, 0x00 }; +// Corresponding color in second palette +#define PAL2(X) ((X) | 0x04) + +// Alternate color for odd pixel rows (for scanlines) +#define ALTCOL(X) ((X) | 0x08) + // Green monochrome palette #define MONO_PALETTE_ENTRIES 2 const byte monoPalette[MONO_PALETTE_ENTRIES * 3] = { @@ -294,6 +300,17 @@ void Display::showScanlines(bool enable) { } } +static void copyEvenSurfaceRows(Graphics::Surface &surf) { + byte *src = (byte *)surf.getPixels(); + + for (uint y = 0; y < surf.h / 2; ++y) { + byte *dst = src + surf.pitch; + for (uint x = 0; x < surf.w; ++x) + dst[x] = ALTCOL(src[x]); + src += surf.pitch * 2; + } +} + void Display::updateHiResSurface() { byte *src = _frameBuf; byte *dst = (byte *)_frameBufSurface->getPixels(); @@ -303,68 +320,78 @@ void Display::updateHiResSurface() { src += DISPLAY_PITCH; dst += _frameBufSurface->pitch * 2; } + + copyEvenSurfaceRows(*_frameBufSurface); } -void Display::decodeScanlineColor(byte *dst, int pitch, byte *src) const { - bool prevOn = false; +static inline byte processColorBits(uint16 &bits, bool &odd, bool secondPal) { + byte color = 0; + + switch (bits & 0x7) { + case 0x3: // 011 (white) + case 0x6: // 110 + case 0x7: // 111 + color = 1; + break; + case 0x2: // 010 (color) + color = 2 + odd; + break; + case 0x5: // 101 (color) + color = 2 + !odd; + } - if (src[0] & 0x80) - dst++; + if (secondPal) + color = PAL2(color); - for (uint j = 0; j < 40; ++j) { - bool secondPal = src[j] & 0x80; - byte cur = src[j]; - byte next = 0; - if (j != 39) - next = src[j + 1]; + odd = !odd; + bits >>= 1; - for (uint k = 0; k < 7; ++k) { - bool curOn = cur & (1 << k); - bool nextOn; + return color; +} - if (k != 6) - nextOn = cur & (1 << (k + 1)); - else - nextOn = next & 1; +void Display::decodeScanlineColor(byte *dst, int pitch, byte *src) const { + uint16 bits = (src[0] & 0x7f) << 1; + byte pal = src[0] >> 7; - byte color; - if (curOn == prevOn || curOn == nextOn) - color = curOn ? 1 : 0; - else - color = (curOn == ((j + k) % 2) ? 3 : 2); + if (pal != 0) + *dst++ = 0; - if (secondPal) - color |= 4; + bool odd = false; - dst[0] = color; - dst[pitch] = color + COLOR_PALETTE_ENTRIES; - ++dst; - - if (k == 6) { - if (secondPal) { - if (next & 0x80) { - dst[0] = color; - dst[pitch] = color + COLOR_PALETTE_ENTRIES; - ++dst; - } - } else { - dst[0] = color; - dst[pitch] = color + COLOR_PALETTE_ENTRIES; - ++dst; - if (next & 0x80) { - dst[0] = color | 4; - dst[pitch] = (color | 4) + COLOR_PALETTE_ENTRIES; - ++dst; - } - } - } else { - dst[0] = color; - dst[pitch] = color + COLOR_PALETTE_ENTRIES; - ++dst; - } + for (uint i = 0; i < 40; ++i) { + if (i != 39) { + bits |= (src[i + 1] & 0x7f) << 8; + pal |= (src[i + 1] >> 7) << 1; + } - prevOn = curOn; + // For the first 6 bits in the block we draw two pixels + for (uint j = 0; j < 6; ++j) { + byte color = processColorBits(bits, odd, pal & 1); + *dst++ = color; + *dst++ = color; } + + // Last bit of the block, draw one, two or three pixels + byte color = processColorBits(bits, odd, pal & 1); + + // Draw the first pixel + *dst++ = color; + + switch (pal) { + case 0x0: + case 0x3: + // If palette stays the same, draw a second pixel + *dst++ = color; + break; + case 0x2: + // If we're moving from first to second palette, + // draw a second pixel, and a third in the second + // palette. + *dst++ = color; + *dst++ = PAL2(color); + } + + pal >>= 1; } } @@ -420,21 +447,10 @@ void Display::drawChar(byte c, int x, int y) { byte *buf = (byte *)_font->getPixels() + y * _font->pitch + x; for (uint row = 0; row < 8; ++row) { - if (row & 1) { - buf[_font->pitch] = COLOR_PALETTE_ENTRIES; - buf[_font->pitch + 1] = COLOR_PALETTE_ENTRIES; - buf[_font->pitch + 6 * 2] = COLOR_PALETTE_ENTRIES; - buf[_font->pitch + 6 * 2 + 1] = COLOR_PALETTE_ENTRIES; - } for (uint col = 1; col < 6; ++col) { if (font[c][col - 1] & (1 << row)) { buf[col * 2] = 1; buf[col * 2 + 1] = 1; - buf[_font->pitch + col * 2] = 1 + COLOR_PALETTE_ENTRIES; - buf[_font->pitch + col * 2 + 1] = 1 + COLOR_PALETTE_ENTRIES; - } else { - buf[_font->pitch + col * 2] = COLOR_PALETTE_ENTRIES; - buf[_font->pitch + col * 2 + 1] = COLOR_PALETTE_ENTRIES; } } @@ -458,21 +474,18 @@ void Display::createFont() { for (uint col = 0; col < _font->w; ++col) bufInv[col] = (buf[col] ? 0 : 1); - buf += _font->pitch; - bufInv += _font->pitch; - - for (uint col = 0; col < _font->w; ++col) - bufInv[col] = (buf[col] == COLOR_PALETTE_ENTRIES + 1 ? COLOR_PALETTE_ENTRIES : COLOR_PALETTE_ENTRIES + 1); - - buf += _font->pitch; - bufInv += _font->pitch; + buf += _font->pitch * 2; + bufInv += _font->pitch * 2; } + + copyEvenSurfaceRows(*_font); } void Display::scrollUp() { memmove(_textBuf, _textBuf + 40, kTextBufSize - 40); memset(_textBuf + kTextBufSize - 40, APPLECHAR(' '), 40); - _cursorPos -= 40; + if (_cursorPos >= 40) + _cursorPos -= 40; } } // End of namespace Adl -- cgit v1.2.3 From d3bfdc36578f137352589b8efacc3f4eb24054aa Mon Sep 17 00:00:00 2001 From: Walter van Niftrik Date: Sat, 5 Mar 2016 16:30:23 +0100 Subject: ADL: Add more #defines to replace literals --- engines/adl/display.cpp | 57 +++++++++++++++++++++++++++---------------------- engines/adl/display.h | 4 ++-- 2 files changed, 33 insertions(+), 28 deletions(-) (limited to 'engines') diff --git a/engines/adl/display.cpp b/engines/adl/display.cpp index 2a24b65a18..6f72f91b32 100644 --- a/engines/adl/display.cpp +++ b/engines/adl/display.cpp @@ -39,6 +39,11 @@ namespace Adl { // This implements the Apple II "Hi-Res" display mode #define DISPLAY_PITCH (DISPLAY_WIDTH / 7) +#define DISPLAY_SIZE (DISPLAY_PITCH * DISPLAY_HEIGHT) + +#define TEXT_WIDTH 40 +#define TEXT_HEIGHT 24 +#define TEXT_BUF_SIZE (TEXT_WIDTH * TEXT_HEIGHT) #define COLOR_PALETTE_ENTRIES 8 const byte colorPalette[COLOR_PALETTE_ENTRIES * 3] = { @@ -117,14 +122,15 @@ Display::Display() : showScanlines(_scanlines); - _frameBuf = new byte[DISPLAY_PITCH * DISPLAY_HEIGHT]; + _frameBuf = new byte[DISPLAY_SIZE]; + memset(_frameBuf, 0, DISPLAY_SIZE); _frameBufSurface = new Graphics::Surface; // We need 2x scaling to properly render the half-pixel shift // of the second palette _frameBufSurface->create(DISPLAY_WIDTH * 2, DISPLAY_HEIGHT * 2, Graphics::PixelFormat::createFormatCLUT8()); - _textBuf = new byte[kTextBufSize]; - memset(_textBuf, APPLECHAR(' '), kTextBufSize); + _textBuf = new byte[TEXT_BUF_SIZE]; + memset(_textBuf, APPLECHAR(' '), TEXT_BUF_SIZE); _textBufSurface = new Graphics::Surface; // For ease of copying, also use 2x scaling here _textBufSurface->create(DISPLAY_WIDTH * 2, DISPLAY_HEIGHT * 2, Graphics::PixelFormat::createFormatCLUT8()); @@ -193,9 +199,9 @@ bool Display::saveThumbnail(Common::WriteStream &out) { } void Display::loadFrameBuffer(Common::ReadStream &stream) { + byte *dst = _frameBuf; for (uint j = 0; j < 8; ++j) { for (uint i = 0; i < 8; ++i) { - byte *dst = _frameBuf + DISPLAY_PITCH * (i * 8 + j); stream.read(dst, DISPLAY_PITCH); dst += DISPLAY_PITCH * 64; stream.read(dst, DISPLAY_PITCH); @@ -203,12 +209,13 @@ void Display::loadFrameBuffer(Common::ReadStream &stream) { stream.read(dst, DISPLAY_PITCH); stream.readUint32LE(); stream.readUint32LE(); - dst += DISPLAY_PITCH * 64; + dst -= DISPLAY_PITCH * 120; } + dst -= DISPLAY_PITCH * 63; } } -void Display::putPixel(Common::Point p, byte color) { +void Display::putPixel(const Common::Point &p, byte color) { byte offset = p.x / 7; if (offset & 1) { @@ -230,35 +237,33 @@ void Display::clear(byte color) { if (c >= 0x40 && c < 0xc0) val = 0x7f; - for (uint i = 0; i < DISPLAY_PITCH * DISPLAY_HEIGHT; ++i) { + for (uint i = 0; i < DISPLAY_SIZE; ++i) { _frameBuf[i] = color; color ^= val; } } void Display::home() { - memset(_textBuf, APPLECHAR(' '), kTextBufSize); + memset(_textBuf, APPLECHAR(' '), TEXT_BUF_SIZE); _cursorPos = 0; } void Display::moveCursorForward() { ++_cursorPos; - if (_cursorPos >= kTextBufSize) + if (_cursorPos >= TEXT_BUF_SIZE) scrollUp(); } void Display::moveCursorBackward() { - --_cursorPos; - - if (_cursorPos < 0) - _cursorPos = 0; + if (_cursorPos > 0) + --_cursorPos; } void Display::moveCursorTo(const Common::Point &pos) { - _cursorPos = pos.y * 40 + pos.x; + _cursorPos = pos.y * TEXT_WIDTH + pos.x; - if (_cursorPos >= kTextBufSize) + if (_cursorPos >= TEXT_BUF_SIZE) error("Cursor position (%i, %i) out of bounds", pos.x, pos.y); } @@ -268,13 +273,13 @@ void Display::printString(const Common::String &str) { byte b = *c; if (*c == APPLECHAR('\r')) - _cursorPos = (_cursorPos / 40 + 1) * 40; + _cursorPos = (_cursorPos / TEXT_WIDTH + 1) * TEXT_WIDTH; else if (b < 0x80 || b >= 0xa0) { setCharAtCursor(b); ++_cursorPos; } - if (_cursorPos == kTextBufSize) + if (_cursorPos == TEXT_BUF_SIZE) scrollUp(); } @@ -358,8 +363,8 @@ void Display::decodeScanlineColor(byte *dst, int pitch, byte *src) const { bool odd = false; - for (uint i = 0; i < 40; ++i) { - if (i != 39) { + for (uint i = 0; i < DISPLAY_PITCH; ++i) { + if (i != DISPLAY_PITCH - 1) { bits |= (src[i + 1] & 0x7f) << 8; pal |= (src[i + 1] >> 7) << 1; } @@ -424,9 +429,9 @@ void Display::decodeScanline(byte *dst, int pitch, byte *src) const { void Display::updateTextSurface() { for (uint row = 0; row < 24; ++row) - for (uint col = 0; col < 40; ++col) { - int charPos = row * 40 + col; - char c = _textBuf[row * 40 + col]; + for (uint col = 0; col < TEXT_WIDTH; ++col) { + uint charPos = row * TEXT_WIDTH + col; + char c = _textBuf[row * TEXT_WIDTH + col]; if (charPos == _cursorPos && _showCursor) c = (c & 0x3f) | 0x40; @@ -482,10 +487,10 @@ void Display::createFont() { } void Display::scrollUp() { - memmove(_textBuf, _textBuf + 40, kTextBufSize - 40); - memset(_textBuf + kTextBufSize - 40, APPLECHAR(' '), 40); - if (_cursorPos >= 40) - _cursorPos -= 40; + memmove(_textBuf, _textBuf + TEXT_WIDTH, TEXT_BUF_SIZE - TEXT_WIDTH); + memset(_textBuf + TEXT_BUF_SIZE - TEXT_WIDTH, APPLECHAR(' '), TEXT_WIDTH); + if (_cursorPos >= TEXT_WIDTH) + _cursorPos -= TEXT_WIDTH; } } // End of namespace Adl diff --git a/engines/adl/display.h b/engines/adl/display.h index b93128f6a5..102622e61f 100644 --- a/engines/adl/display.h +++ b/engines/adl/display.h @@ -61,7 +61,7 @@ public: // Graphics void loadFrameBuffer(Common::ReadStream &stream); - void putPixel(Common::Point p1, byte color); + void putPixel(const Common::Point &p, byte color); void clear(byte color); // Text @@ -99,7 +99,7 @@ private: byte *_textBuf; Graphics::Surface *_textBufSurface; Graphics::Surface *_font; - int _cursorPos; + uint _cursorPos; bool _showCursor; }; -- cgit v1.2.3 From b2d2f3405e0b36e92402b6c38bc2c406ea960147 Mon Sep 17 00:00:00 2001 From: Walter van Niftrik Date: Sat, 5 Mar 2016 16:34:39 +0100 Subject: ADL: Make palettes static --- engines/adl/display.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'engines') diff --git a/engines/adl/display.cpp b/engines/adl/display.cpp index 6f72f91b32..235e42bb73 100644 --- a/engines/adl/display.cpp +++ b/engines/adl/display.cpp @@ -46,7 +46,7 @@ namespace Adl { #define TEXT_BUF_SIZE (TEXT_WIDTH * TEXT_HEIGHT) #define COLOR_PALETTE_ENTRIES 8 -const byte colorPalette[COLOR_PALETTE_ENTRIES * 3] = { +static const byte colorPalette[COLOR_PALETTE_ENTRIES * 3] = { 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xc7, 0x34, 0xff, @@ -65,7 +65,7 @@ const byte colorPalette[COLOR_PALETTE_ENTRIES * 3] = { // Green monochrome palette #define MONO_PALETTE_ENTRIES 2 -const byte monoPalette[MONO_PALETTE_ENTRIES * 3] = { +static const byte monoPalette[MONO_PALETTE_ENTRIES * 3] = { 0x00, 0x00, 0x00, 0x00, 0xc0, 0x01 }; @@ -110,7 +110,7 @@ Display::Display() : _cursorPos(0), _showCursor(false) { - initGraphics(560, 384, true); + initGraphics(DISPLAY_WIDTH * 2, DISPLAY_HEIGHT * 2, true); _monochrome = !ConfMan.getBool("color"); _scanlines = ConfMan.getBool("scanlines"); -- cgit v1.2.3 From 165e333f4f3fbde90f83c6cd8fe587e89e7455d7 Mon Sep 17 00:00:00 2001 From: Walter van Niftrik Date: Sat, 5 Mar 2016 17:13:26 +0100 Subject: ADL: Implement half-pixel shift for monochrome --- engines/adl/display.cpp | 96 +++++++++++++++++++++++++++---------------------- engines/adl/display.h | 3 -- 2 files changed, 53 insertions(+), 46 deletions(-) (limited to 'engines') diff --git a/engines/adl/display.cpp b/engines/adl/display.cpp index 235e42bb73..cc51e4ae7e 100644 --- a/engines/adl/display.cpp +++ b/engines/adl/display.cpp @@ -305,31 +305,7 @@ void Display::showScanlines(bool enable) { } } -static void copyEvenSurfaceRows(Graphics::Surface &surf) { - byte *src = (byte *)surf.getPixels(); - - for (uint y = 0; y < surf.h / 2; ++y) { - byte *dst = src + surf.pitch; - for (uint x = 0; x < surf.w; ++x) - dst[x] = ALTCOL(src[x]); - src += surf.pitch * 2; - } -} - -void Display::updateHiResSurface() { - byte *src = _frameBuf; - byte *dst = (byte *)_frameBufSurface->getPixels(); - - for (uint i = 0; i < DISPLAY_HEIGHT; ++i) { - decodeScanline(dst, _frameBufSurface->pitch, src); - src += DISPLAY_PITCH; - dst += _frameBufSurface->pitch * 2; - } - - copyEvenSurfaceRows(*_frameBufSurface); -} - -static inline byte processColorBits(uint16 &bits, bool &odd, bool secondPal) { +static byte processColorBits(uint16 &bits, bool &odd, bool secondPal) { byte color = 0; switch (bits & 0x7) { @@ -354,7 +330,7 @@ static inline byte processColorBits(uint16 &bits, bool &odd, bool secondPal) { return color; } -void Display::decodeScanlineColor(byte *dst, int pitch, byte *src) const { +static void renderPixelRowColor(byte *dst, byte *src) { uint16 bits = (src[0] & 0x7f) << 1; byte pal = src[0] >> 7; @@ -400,31 +376,65 @@ void Display::decodeScanlineColor(byte *dst, int pitch, byte *src) const { } } -void Display::decodeScanlineMono(byte *dst, int pitch, byte *src) const { - // TODO: shift secondPal by half a pixel +static void renderPixelRowMono(byte *dst, byte *src) { + byte pal = src[0] >> 7; - for (uint j = 0; j < 39; ++j) { - for (uint k = 0; k < 7; ++k) { - byte color = 0; + if (pal != 0) + *dst++ = 0; + + for (uint i = 0; i < DISPLAY_PITCH; ++i) { + if (i != DISPLAY_PITCH - 1) + pal |= (src[i + 1] >> 7) << 1; + + for (uint j = 0; j < 6; ++j) { + bool color = src[i] & (1 << j); + *dst++ = color; + *dst++ = color; + } - if (src[j] & (1 << k)) - color = 1; + bool color = src[i] & (1 << 6); - dst[0] = color; - dst[1] = color; - dst[pitch] = color + 6; - dst[pitch + 1] = color + 6; + *dst++ = color; - dst += 2; + switch (pal) { + case 0x0: + case 0x3: + *dst++ = color; + break; + case 0x2: + *dst++ = color; + *dst++ = color; } + + pal >>= 1; } } -void Display::decodeScanline(byte *dst, int pitch, byte *src) const { - if (_monochrome) - decodeScanlineMono(dst, pitch, src); - else - decodeScanlineColor(dst, pitch, src); +static void copyEvenSurfaceRows(Graphics::Surface &surf) { + byte *src = (byte *)surf.getPixels(); + + for (uint y = 0; y < surf.h / 2; ++y) { + byte *dst = src + surf.pitch; + for (uint x = 0; x < surf.w; ++x) + dst[x] = ALTCOL(src[x]); + src += surf.pitch * 2; + } +} + +void Display::updateHiResSurface() { + byte *src = _frameBuf; + byte *dst = (byte *)_frameBufSurface->getPixels(); + + for (uint i = 0; i < DISPLAY_HEIGHT; ++i) { + if (_monochrome) + renderPixelRowMono(dst, src); + else + renderPixelRowColor(dst, src); + src += DISPLAY_PITCH; + dst += _frameBufSurface->pitch * 2; + } + + copyEvenSurfaceRows(*_frameBufSurface); } void Display::updateTextSurface() { diff --git a/engines/adl/display.h b/engines/adl/display.h index 102622e61f..8690659ef4 100644 --- a/engines/adl/display.h +++ b/engines/adl/display.h @@ -80,9 +80,6 @@ private: void updateHiResSurface(); void showScanlines(bool enable); - void decodeScanlineColor(byte *dst, int pitch, byte *src) const; - void decodeScanlineMono(byte *dst, int pitch, byte *src) const; - void decodeScanline(byte *dst, int pitch, byte *src) const; void updateTextSurface(); void drawChar(byte c, int x, int y); -- cgit v1.2.3 From 1e1a5d4f0761ba22257f59cfd70aeb53a47b0321 Mon Sep 17 00:00:00 2001 From: Walter van Niftrik Date: Sat, 5 Mar 2016 17:24:45 +0100 Subject: ADL: Fix darkness setting in a move too late --- engines/adl/adl.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'engines') diff --git a/engines/adl/adl.cpp b/engines/adl/adl.cpp index 313b14681e..c58f28ad31 100644 --- a/engines/adl/adl.cpp +++ b/engines/adl/adl.cpp @@ -515,9 +515,9 @@ void AdlEngine::showRoom() { if (!_state.isDark) { drawPic(curRoom().curPicture); drawItems(); - _display->updateHiResScreen(); } + _display->updateHiResScreen(); printMessage(curRoom().description, false); } -- cgit v1.2.3 From 6379fbc124b63221576206bed070fa2a91b99718 Mon Sep 17 00:00:00 2001 From: Walter van Niftrik Date: Sat, 5 Mar 2016 20:07:28 +0100 Subject: ADL: Add more #defines to replace literals --- engines/adl/display.h | 4 --- engines/adl/hires1.cpp | 66 ++++++++++++++++++++++++++++++++------------------ engines/adl/hires1.h | 14 ++--------- 3 files changed, 44 insertions(+), 40 deletions(-) (limited to 'engines') diff --git a/engines/adl/display.h b/engines/adl/display.h index 8690659ef4..ce8f86beba 100644 --- a/engines/adl/display.h +++ b/engines/adl/display.h @@ -74,10 +74,6 @@ public: void showCursor(bool enable); private: - enum { - kTextBufSize = 40 * 24 - }; - void updateHiResSurface(); void showScanlines(bool enable); diff --git a/engines/adl/hires1.cpp b/engines/adl/hires1.cpp index 8b5b9220f7..d3e4c3ef52 100644 --- a/engines/adl/hires1.cpp +++ b/engines/adl/hires1.cpp @@ -40,6 +40,11 @@ namespace Adl { +#define IDI_HR1_NUM_ROOMS 41 +#define IDI_HR1_NUM_PICS 98 +#define IDI_HR1_NUM_VARS 20 +#define IDI_HR1_NUM_ITEM_OFFSETS 21 + // Messages used outside of scripts #define IDI_HR1_MSG_CANT_GO_THERE 137 #define IDI_HR1_MSG_DONT_UNDERSTAND 37 @@ -73,15 +78,28 @@ static const StringOffset stringOffsets[] = { { IDI_HR1_STR_PRESS_RETURN, 0x5f68 } }; -#define IDI_HR1_OFS_PD_TEXT_0 0x5d -#define IDI_HR1_OFS_PD_TEXT_1 0x12b -#define IDI_HR1_OFS_PD_TEXT_2 0x16d -#define IDI_HR1_OFS_PD_TEXT_3 0x259 +#define IDI_HR1_OFS_PD_TEXT_0 0x005d +#define IDI_HR1_OFS_PD_TEXT_1 0x012b +#define IDI_HR1_OFS_PD_TEXT_2 0x016d +#define IDI_HR1_OFS_PD_TEXT_3 0x0259 + +#define IDI_HR1_OFS_INTRO_TEXT 0x0066 +#define IDI_HR1_OFS_GAME_OR_HELP 0x000f + +#define IDI_HR1_OFS_LOGO_0 0x1003 +#define IDI_HR1_OFS_LOGO_1 0x1800 + +#define IDI_HR1_OFS_ITEMS 0x0100 +#define IDI_HR1_OFS_ROOMS 0x050a +#define IDI_HR1_OFS_PICS 0x4b00 +#define IDI_HR1_OFS_CMDS_0 0x3c00 +#define IDI_HR1_OFS_CMDS_1 0x3d00 -#define IDI_HR1_OFS_INTRO_TEXT 0x66 -#define IDI_HR1_OFS_GAME_OR_HELP 0xf +#define IDI_HR1_OFS_ITEM_OFFSETS 0x68ff +#define IDI_HR1_OFS_LINE_ART 0x4f00 -#define IDI_HR1_OFS_LOGO_0 0x1003 +#define IDI_HR1_OFS_VERBS 0x3800 +#define IDI_HR1_OFS_NOUNS 0x0f00 HiRes1Engine::HiRes1Engine(OSystem *syst, const AdlGameDescription *gd) : AdlEngine(syst, gd) { @@ -184,7 +202,7 @@ void HiRes1Engine::runIntro() { error("Failed to open file"); // Title screen shown during loading - file.seek(0x1800); + file.seek(IDI_HR1_OFS_LOGO_1); _display->loadFrameBuffer(file); _display->updateHiResScreen(); delay(2000); @@ -246,15 +264,15 @@ void HiRes1Engine::initState() { _state.isDark = false; _state.vars.clear(); - _state.vars.resize(20); + _state.vars.resize(IDI_HR1_NUM_VARS); if (!f.open("ADVENTURE")) error("Failed to open file"); // Load room data from executable _state.rooms.clear(); - f.seek(0x50a); - for (uint i = 0; i < MH_ROOMS; ++i) { + f.seek(IDI_HR1_OFS_ROOMS); + for (uint i = 0; i < IDI_HR1_NUM_ROOMS; ++i) { Room room; f.readByte(); room.description = f.readByte(); @@ -265,9 +283,9 @@ void HiRes1Engine::initState() { _state.rooms.push_back(room); } - // Load inventory data from executable + // Load item data from executable _state.items.clear(); - f.seek(0x100); + f.seek(IDI_HR1_OFS_ITEMS); while (f.readByte() != 0xff) { Item item; item.noun = f.readByte(); @@ -321,8 +339,8 @@ void HiRes1Engine::runGame() { } // Load picture data from executable - f.seek(0x4b00); - for (uint i = 0; i < MH_PICS; ++i) { + f.seek(IDI_HR1_OFS_PICS); + for (uint i = 0; i < IDI_HR1_NUM_PICS; ++i) { struct Picture pic; pic.block = f.readByte(); pic.offset = f.readUint16LE(); @@ -330,15 +348,15 @@ void HiRes1Engine::runGame() { } // Load commands from executable - f.seek(0x3D00); + f.seek(IDI_HR1_OFS_CMDS_1); readCommands(f, _roomCommands); - f.seek(0x3C00); + f.seek(IDI_HR1_OFS_CMDS_0); readCommands(f, _globalCommands); // Load dropped item offsets - f.seek(0x68ff); - for (uint i = 0; i < MH_ITEM_OFFSETS; ++i) { + f.seek(IDI_HR1_OFS_ITEM_OFFSETS); + for (uint i = 0; i < IDI_HR1_NUM_ITEM_OFFSETS; ++i) { Common::Point p; p.x = f.readByte(); p.y = f.readByte(); @@ -346,12 +364,12 @@ void HiRes1Engine::runGame() { } // Load right-angle line art - f.seek(0x4f00); + f.seek(IDI_HR1_OFS_LINE_ART); uint16 lineArtTotal = f.readUint16LE(); for (uint i = 0; i < lineArtTotal; ++i) { - f.seek(0x4f00 + 2 + i * 2); + f.seek(IDI_HR1_OFS_LINE_ART + 2 + i * 2); uint16 offset = f.readUint16LE(); - f.seek(0x4f00 + offset); + f.seek(IDI_HR1_OFS_LINE_ART + offset); Common::Array lineArt; byte b = f.readByte(); @@ -362,10 +380,10 @@ void HiRes1Engine::runGame() { _lineArt.push_back(lineArt); } - f.seek(0x3800); + f.seek(IDI_HR1_OFS_VERBS); loadVerbs(f); - f.seek(0xf00); + f.seek(IDI_HR1_OFS_NOUNS); loadNouns(f); printASCIIString("\r\r\r\r\r"); diff --git a/engines/adl/hires1.h b/engines/adl/hires1.h index cae5980102..f5c6d5b3e4 100644 --- a/engines/adl/hires1.h +++ b/engines/adl/hires1.h @@ -20,8 +20,8 @@ * */ -#ifndef ADL_ADL_V1_H -#define ADL_ADL_V1_H +#ifndef ADL_HIRES1_H +#define ADL_HIRES1_H #include "adl/adl.h" @@ -31,10 +31,6 @@ class ReadStream; namespace Adl { -enum { - IDI_HR1_MSG_ -}; - class HiRes1Engine : public AdlEngine { public: HiRes1Engine(OSystem *syst, const AdlGameDescription *gd); @@ -43,12 +39,6 @@ protected: void runGame(); private: - enum { - MH_ROOMS = 41, - MH_PICS = 98, - MH_ITEM_OFFSETS = 21 - }; - void restartGame(); void printMessage(uint idx, bool wait = true); uint getEngineMessage(EngineMessage msg); -- cgit v1.2.3 From f62c56e38475ccab0c94db949a14991e5423fc13 Mon Sep 17 00:00:00 2001 From: Walter van Niftrik Date: Sat, 5 Mar 2016 22:10:54 +0100 Subject: ADL: Clean up line drawing --- engines/adl/hires1.cpp | 48 ++++++++++++++++++++---------------------------- engines/adl/hires1.h | 4 ++-- 2 files changed, 22 insertions(+), 30 deletions(-) (limited to 'engines') diff --git a/engines/adl/hires1.cpp b/engines/adl/hires1.cpp index d3e4c3ef52..1345489315 100644 --- a/engines/adl/hires1.cpp +++ b/engines/adl/hires1.cpp @@ -20,20 +20,11 @@ * */ -#include "common/scummsys.h" - -#include "common/config-manager.h" +#include "common/system.h" #include "common/debug.h" -#include "common/debug-channels.h" #include "common/error.h" #include "common/file.h" -#include "common/fs.h" -#include "common/system.h" -#include "common/events.h" #include "common/stream.h" -#include "graphics/palette.h" - -#include "engines/util.h" #include "adl/hires1.h" #include "adl/display.h" @@ -208,7 +199,7 @@ void HiRes1Engine::runIntro() { delay(2000); } -void HiRes1Engine::drawPic(Common::ReadStream &stream, Common::Point pos) { +void HiRes1Engine::drawPic(Common::ReadStream &stream, const Common::Point &pos) { byte x, y; bool bNewLine = false; byte oldX = 0, oldY = 0; @@ -473,38 +464,39 @@ uint HiRes1Engine::getEngineMessage(EngineMessage msg) { } } -void HiRes1Engine::drawLine(Common::Point p1, Common::Point p2, byte color) { +void HiRes1Engine::drawLine(const Common::Point &p1, const Common::Point &p2, byte color) { int16 deltaX = p2.x - p1.x; - byte dir = deltaX >> 8; + int8 xStep = 1; - if (deltaX < 0) + if (deltaX < 0) { deltaX = -deltaX; + xStep = -1; + } - int16 err = deltaX; + int16 deltaY = p2.y - p1.y; + int8 yStep = -1; - int16 deltaY = p2.y - p1.y - 1; - dir >>= 1; - if (deltaY >= 0) { - deltaY = -deltaY - 2; - dir |= 0x80; + if (deltaY > 0) { + deltaY = -deltaY; + yStep = 1; } - int16 steps = deltaY - deltaX; - - err += deltaY + 1; + Common::Point p(p1); + int16 steps = deltaX - deltaY + 1; + int16 err = deltaX + deltaY; while (1) { - _display->putPixel(p1, color); + _display->putPixel(p, color); - if (++steps == 0) + if (--steps == 0) return; if (err < 0) { - p1.y += (dir & 0x80 ? 1 : -1); + p.y += yStep; err += deltaX; } else { - p1.x += (dir & 0x40 ? -1 : 1); - err += deltaY + 1; + p.x += xStep; + err += deltaY; } } } diff --git a/engines/adl/hires1.h b/engines/adl/hires1.h index f5c6d5b3e4..12c3c9461f 100644 --- a/engines/adl/hires1.h +++ b/engines/adl/hires1.h @@ -45,9 +45,9 @@ private: void initState(); void runIntro(); - void drawPic(Common::ReadStream &stream, Common::Point pos); + void drawPic(Common::ReadStream &stream, const Common::Point &pos); void drawItems(); - void drawLine(Common::Point p1, Common::Point p2, byte color); + void drawLine(const Common::Point &p1, const Common::Point &p2, byte color); void drawPic(byte pic, Common::Point pos); }; -- cgit v1.2.3 From af42795ffa9331a16c1c6fa819f5c3960fd3cfe1 Mon Sep 17 00:00:00 2001 From: Walter van Niftrik Date: Sun, 6 Mar 2016 11:58:21 +0100 Subject: ADL: Improve error messages --- engines/adl/adl.cpp | 5 ++++- engines/adl/display.cpp | 3 +++ engines/adl/hires1.cpp | 47 +++++++++++++++++++++++++++++------------------ engines/adl/hires1.h | 5 ++--- 4 files changed, 38 insertions(+), 22 deletions(-) (limited to 'engines') diff --git a/engines/adl/adl.cpp b/engines/adl/adl.cpp index c58f28ad31..c395fbb81b 100644 --- a/engines/adl/adl.cpp +++ b/engines/adl/adl.cpp @@ -94,7 +94,10 @@ Common::String AdlEngine::readString(Common::ReadStream &stream, byte until) { while (1) { byte b = stream.readByte(); - if (stream.eos() || stream.err() || b == until) + if (stream.eos() || stream.err()) + error("Error reading string"); + + if (b == until) break; str += b; diff --git a/engines/adl/display.cpp b/engines/adl/display.cpp index cc51e4ae7e..7af6f660fd 100644 --- a/engines/adl/display.cpp +++ b/engines/adl/display.cpp @@ -213,6 +213,9 @@ void Display::loadFrameBuffer(Common::ReadStream &stream) { } dst -= DISPLAY_PITCH * 63; } + + if (stream.eos() || stream.err()) + error("Failed to read frame buffer"); } void Display::putPixel(const Common::Point &p, byte color) { diff --git a/engines/adl/hires1.cpp b/engines/adl/hires1.cpp index 1345489315..91407808eb 100644 --- a/engines/adl/hires1.cpp +++ b/engines/adl/hires1.cpp @@ -31,10 +31,16 @@ namespace Adl { -#define IDI_HR1_NUM_ROOMS 41 -#define IDI_HR1_NUM_PICS 98 -#define IDI_HR1_NUM_VARS 20 -#define IDI_HR1_NUM_ITEM_OFFSETS 21 +#define IDS_HR1_EXE_0 "AUTO LOAD OBJ" +#define IDS_HR1_EXE_1 "ADVENTURE" +#define IDS_HR1_LOADER "MYSTERY.HELLO" +#define IDS_HR1_MESSAGES "MESSAGES" + +#define IDI_HR1_NUM_ROOMS 41 +#define IDI_HR1_NUM_PICS 98 +#define IDI_HR1_NUM_VARS 20 +#define IDI_HR1_NUM_ITEM_OFFSETS 21 +#define IDI_HR1_NUM_MESSAGES 167 // Messages used outside of scripts #define IDI_HR1_MSG_CANT_GO_THERE 137 @@ -99,8 +105,8 @@ HiRes1Engine::HiRes1Engine(OSystem *syst, const AdlGameDescription *gd) : void HiRes1Engine::runIntro() { Common::File file; - if (!file.open("AUTO LOAD OBJ")) - error("Failed to open file"); + if (!file.open(IDS_HR1_EXE_0)) + error("Failed to open file '" IDS_HR1_EXE_0 "'"); file.seek(IDI_HR1_OFS_LOGO_0); _display->setMode(DISPLAY_MODE_HIRES); @@ -114,8 +120,8 @@ void HiRes1Engine::runIntro() { _display->setMode(DISPLAY_MODE_TEXT); Common::File basic; - if (!basic.open("MYSTERY.HELLO")) - error("Failed to open file"); + if (!basic.open(IDS_HR1_LOADER)) + error("Failed to open file '" IDS_HR1_LOADER "'"); Common::String str; @@ -189,8 +195,8 @@ void HiRes1Engine::runIntro() { _display->setMode(DISPLAY_MODE_MIXED); - if (!file.open("ADVENTURE")) - error("Failed to open file"); + if (!file.open(IDS_HR1_EXE_1)) + error("Failed to open file '" IDS_HR1_EXE_1 "'"); // Title screen shown during loading file.seek(IDI_HR1_OFS_LOGO_1); @@ -241,7 +247,7 @@ void HiRes1Engine::drawPic(byte pic, Common::Point pos) { Common::String name = Common::String::format("BLOCK%i", _pictures[pic].block); if (!f.open(name)) - error("Failed to open file"); + error("Failed to open file '%s'", name.c_str()); f.seek(_pictures[pic].offset); drawPic(f, pos); @@ -257,8 +263,8 @@ void HiRes1Engine::initState() { _state.vars.clear(); _state.vars.resize(IDI_HR1_NUM_VARS); - if (!f.open("ADVENTURE")) - error("Failed to open file"); + if (!f.open(IDS_HR1_EXE_1)) + error("Failed to open file '" IDS_HR1_EXE_1 "'"); // Load room data from executable _state.rooms.clear(); @@ -311,16 +317,16 @@ void HiRes1Engine::runGame() { Common::File f; - if (!f.open("MESSAGES")) - error("Failed to open file"); + if (!f.open(IDS_HR1_MESSAGES)) + error("Failed to open file '" IDS_HR1_MESSAGES "'"); - while (!f.eos() && !f.err()) + for (uint i = 0; i < IDI_HR1_NUM_MESSAGES; ++i) _messages.push_back(readString(f, APPLECHAR('\r')) + APPLECHAR('\r')); f.close(); - if (!f.open("ADVENTURE")) - error("Failed to open file"); + if (!f.open(IDS_HR1_EXE_1)) + error("Failed to open file '" IDS_HR1_EXE_1 "'"); // Load strings from executable _strings.resize(IDI_HR1_STR_TOTAL); @@ -371,6 +377,9 @@ void HiRes1Engine::runGame() { _lineArt.push_back(lineArt); } + if (f.eos() || f.err()) + error("Failed to read game data from '" IDS_HR1_EXE_1 "'"); + f.seek(IDI_HR1_OFS_VERBS); loadVerbs(f); @@ -465,6 +474,8 @@ uint HiRes1Engine::getEngineMessage(EngineMessage msg) { } void HiRes1Engine::drawLine(const Common::Point &p1, const Common::Point &p2, byte color) { + // This draws a four-connected line + int16 deltaX = p2.x - p1.x; int8 xStep = 1; diff --git a/engines/adl/hires1.h b/engines/adl/hires1.h index 12c3c9461f..64cf8f35f7 100644 --- a/engines/adl/hires1.h +++ b/engines/adl/hires1.h @@ -27,6 +27,7 @@ namespace Common { class ReadStream; +class Point; } namespace Adl { @@ -35,9 +36,6 @@ class HiRes1Engine : public AdlEngine { public: HiRes1Engine(OSystem *syst, const AdlGameDescription *gd); -protected: - void runGame(); - private: void restartGame(); void printMessage(uint idx, bool wait = true); @@ -45,6 +43,7 @@ private: void initState(); void runIntro(); + void runGame(); void drawPic(Common::ReadStream &stream, const Common::Point &pos); void drawItems(); void drawLine(const Common::Point &p1, const Common::Point &p2, byte color); -- cgit v1.2.3 From a73dcdf224ae88c7bcf73d754781052835af4cd0 Mon Sep 17 00:00:00 2001 From: Walter van Niftrik Date: Sun, 6 Mar 2016 13:36:35 +0100 Subject: ADL: Move functionality into base class --- engines/adl/adl.cpp | 51 ++++++++++++++++++++++++++++++++++++++++++++++++- engines/adl/adl.h | 3 ++- engines/adl/hires1.cpp | 52 +------------------------------------------------- engines/adl/hires1.h | 2 +- 4 files changed, 54 insertions(+), 54 deletions(-) (limited to 'engines') diff --git a/engines/adl/adl.cpp b/engines/adl/adl.cpp index c395fbb81b..701f902ade 100644 --- a/engines/adl/adl.cpp +++ b/engines/adl/adl.cpp @@ -72,6 +72,8 @@ bool AdlEngine::hasFeature(EngineFeature f) const { Common::Error AdlEngine::run() { _display = new Display(); + loadData(); + int saveSlot = ConfMan.getInt("save_slot"); if (saveSlot >= 0) { if (loadGameState(saveSlot).getCode() != Common::kNoError) @@ -83,7 +85,54 @@ Common::Error AdlEngine::run() { initState(); } - runGame(); + _display->setMode(DISPLAY_MODE_MIXED); + printASCIIString("\r\r\r\r\r"); + + while (1) { + uint verb = 0, noun = 0; + + // When restoring from the launcher, we don't read + // input on the first iteration. This is needed to + // ensure that restoring from the launcher and + // restoring in-game brings us to the same game state. + // (Also see comment below.) + if (!_isRestoring) { + clearScreen(); + showRoom(); + + _canSaveNow = _canRestoreNow = true; + getInput(verb, noun); + _canSaveNow = _canRestoreNow = false; + + if (shouldQuit()) + break; + + if (!doOneCommand(_roomCommands, verb, noun)) + printEngineMessage(IDI_MSG_DONT_UNDERSTAND); + } + + if (_isRestoring) { + // We restored from the GMM or launcher. As restoring + // with "RESTORE GAME" does not end command processing, + // we don't break it off here either. This essentially + // means that restoring a game will always run through + // the global commands and increase the move counter + // before the first user input. + printASCIIString("\r"); + _isRestoring = false; + verb = _restoreVerb; + noun = _restoreNoun; + } + + // Restarting does end command processing + if (_isRestarting) { + _isRestarting = false; + continue; + } + + doAllCommands(_globalCommands, verb, noun); + _state.moves++; + } return Common::kNoError; } diff --git a/engines/adl/adl.h b/engines/adl/adl.h index 84b9214161..66a539547b 100644 --- a/engines/adl/adl.h +++ b/engines/adl/adl.h @@ -180,7 +180,8 @@ protected: typedef Common::HashMap WordMap; virtual void runIntro() { } - virtual void runGame() = 0; + virtual void loadData() = 0; + void runGame(); virtual void initState() = 0; virtual void restartGame() = 0; virtual uint getEngineMessage(EngineMessage msg) = 0; diff --git a/engines/adl/hires1.cpp b/engines/adl/hires1.cpp index 91407808eb..11d576b217 100644 --- a/engines/adl/hires1.cpp +++ b/engines/adl/hires1.cpp @@ -312,9 +312,7 @@ void HiRes1Engine::restartGame() { printASCIIString("\r\r\r\r\r"); } -void HiRes1Engine::runGame() { - _display->setMode(DISPLAY_MODE_MIXED); - +void HiRes1Engine::loadData() { Common::File f; if (!f.open(IDS_HR1_MESSAGES)) @@ -385,54 +383,6 @@ void HiRes1Engine::runGame() { f.seek(IDI_HR1_OFS_NOUNS); loadNouns(f); - - printASCIIString("\r\r\r\r\r"); - - while (1) { - uint verb = 0, noun = 0; - - // When restoring from the launcher, we don't read - // input on the first iteration. This is needed to - // ensure that restoring from the launcher and - // restoring in-game brings us to the same game state. - // (Also see comment below.) - if (!_isRestoring) { - clearScreen(); - showRoom(); - - _canSaveNow = _canRestoreNow = true; - getInput(verb, noun); - _canSaveNow = _canRestoreNow = false; - - if (shouldQuit()) - return; - - if (!doOneCommand(_roomCommands, verb, noun)) - printMessage(IDI_HR1_MSG_DONT_UNDERSTAND); - } - - if (_isRestoring) { - // We restored from the GMM or launcher. As restoring - // with "RESTORE GAME" does not end command processing, - // we don't break it off here either. This essentially - // means that restoring a game will always run through - // the global commands and increase the move counter - // before the first user input. - printASCIIString("\r"); - _isRestoring = false; - verb = _restoreVerb; - noun = _restoreNoun; - } - - // Restarting does end command processing - if (_isRestarting) { - _isRestarting = false; - continue; - } - - doAllCommands(_globalCommands, verb, noun); - _state.moves++; - } } void HiRes1Engine::printMessage(uint idx, bool wait) { diff --git a/engines/adl/hires1.h b/engines/adl/hires1.h index 64cf8f35f7..f72093a92a 100644 --- a/engines/adl/hires1.h +++ b/engines/adl/hires1.h @@ -43,7 +43,7 @@ private: void initState(); void runIntro(); - void runGame(); + void loadData(); void drawPic(Common::ReadStream &stream, const Common::Point &pos); void drawItems(); void drawLine(const Common::Point &p1, const Common::Point &p2, byte color); -- cgit v1.2.3 From 0ec3ab142244cbaf24f0f6c97a931d0d073d4f97 Mon Sep 17 00:00:00 2001 From: Walter van Niftrik Date: Sun, 6 Mar 2016 16:43:30 +0100 Subject: ADL: Fix const'ness --- engines/adl/adl.cpp | 87 ++++++++++++++++++++++++------------ engines/adl/adl.h | 117 ++++++++++++++++++++++++++----------------------- engines/adl/hires1.cpp | 8 ++-- engines/adl/hires1.h | 8 ++-- 4 files changed, 129 insertions(+), 91 deletions(-) (limited to 'engines') diff --git a/engines/adl/adl.cpp b/engines/adl/adl.cpp index 701f902ade..e0c0b3afae 100644 --- a/engines/adl/adl.cpp +++ b/engines/adl/adl.cpp @@ -137,7 +137,7 @@ Common::Error AdlEngine::run() { return Common::kNoError; } -Common::String AdlEngine::readString(Common::ReadStream &stream, byte until) { +Common::String AdlEngine::readString(Common::ReadStream &stream, byte until) const { Common::String str; while (1) { @@ -155,7 +155,7 @@ Common::String AdlEngine::readString(Common::ReadStream &stream, byte until) { return str; } -void AdlEngine::printStrings(Common::SeekableReadStream &stream, int count) { +void AdlEngine::printStrings(Common::SeekableReadStream &stream, int count) const { while (1) { Common::String str = readString(stream); _display->printString(str); @@ -167,11 +167,11 @@ void AdlEngine::printStrings(Common::SeekableReadStream &stream, int count) { }; } -Common::String AdlEngine::getEngineString(int str) { +Common::String AdlEngine::getEngineString(int str) const { return _strings[str]; } -void AdlEngine::wordWrap(Common::String &str) { +void AdlEngine::wordWrap(Common::String &str) const { uint end = 39; while (1) { @@ -186,7 +186,7 @@ void AdlEngine::wordWrap(Common::String &str) { } } -void AdlEngine::printMessage(uint idx, bool wait) { +void AdlEngine::printMessage(uint idx, bool wait) const { Common::String msg = _messages[idx - 1]; wordWrap(msg); _display->printString(msg); @@ -195,7 +195,7 @@ void AdlEngine::printMessage(uint idx, bool wait) { delay(14 * 166018 / 1000); } -void AdlEngine::printEngineMessage(EngineMessage msg) { +void AdlEngine::printEngineMessage(EngineMessage msg) const { printMessage(getEngineMessage(msg)); } @@ -423,7 +423,7 @@ void AdlEngine::doActions(const Command &command, byte noun, byte offset) { } } -bool AdlEngine::matchCommand(const Command &command, byte verb, byte noun, bool run) { +bool AdlEngine::matchCommand(const Command &command, byte verb, byte noun, uint *actions) const { if (command.room != IDI_NONE && command.room != _state.room) return false; @@ -466,8 +466,7 @@ bool AdlEngine::matchCommand(const Command &command, byte verb, byte noun, bool } } - if (run) - doActions(command, noun, offset); + *actions = offset; return true; } @@ -477,9 +476,13 @@ bool AdlEngine::matchCommand(const Command &command, byte verb, byte noun, bool bool AdlEngine::doOneCommand(const Commands &commands, byte verb, byte noun) { Commands::const_iterator cmd; - for (cmd = commands.begin(); cmd != commands.end(); ++cmd) - if (matchCommand(*cmd, verb, noun)) + for (cmd = commands.begin(); cmd != commands.end(); ++cmd) { + uint offset = 0; + if (matchCommand(*cmd, verb, noun, &offset)) { + doActions(*cmd, noun, offset); return true; + } + } return false; } @@ -489,7 +492,9 @@ void AdlEngine::doAllCommands(const Commands &commands, byte verb, byte noun) { bool oldIsRestoring = _isRestoring; for (cmd = commands.begin(); cmd != commands.end(); ++cmd) { - matchCommand(*cmd, verb, noun); + uint offset = 0; + if (matchCommand(*cmd, verb, noun, &offset)) + doActions(*cmd, noun, offset); // We assume no restarts happen in this command group. This // simplifies enabling GMM savegame loading on the restart @@ -499,7 +504,7 @@ void AdlEngine::doAllCommands(const Commands &commands, byte verb, byte noun) { } } -bool AdlEngine::canSaveGameStateCurrently() { +bool AdlEngine::canSaveGameStateCurrently() const { if (!_canSaveNow) return false; @@ -509,7 +514,7 @@ bool AdlEngine::canSaveGameStateCurrently() { // "SAVE GAME". This prevents saving via the GMM in situations where // it wouldn't otherwise be possible to do so. for (cmd = _roomCommands.begin(); cmd != _roomCommands.end(); ++cmd) { - if (matchCommand(*cmd, _saveVerb, _saveNoun, false)) { + if (matchCommand(*cmd, _saveVerb, _saveNoun)) { if (cmd->verb != _saveVerb || cmd->noun != _saveNoun) return false; return cmd->numCond == 0 && cmd->script[0] == IDO_ACT_SAVE; @@ -519,16 +524,16 @@ bool AdlEngine::canSaveGameStateCurrently() { return false; } -bool AdlEngine::canLoadGameStateCurrently() { +bool AdlEngine::canLoadGameStateCurrently() const { return _canRestoreNow; } -void AdlEngine::clearScreen() { +void AdlEngine::clearScreen() const { _display->setMode(DISPLAY_MODE_MIXED); _display->clear(0x00); } -void AdlEngine::drawItems() { +void AdlEngine::drawItems() const { Common::Array::const_iterator item; uint dropped = 0; @@ -563,7 +568,7 @@ void AdlEngine::drawItems() { } } -void AdlEngine::showRoom() { +void AdlEngine::showRoom() const { if (!_state.isDark) { drawPic(curRoom().curPicture); drawItems(); @@ -722,6 +727,13 @@ Common::Error AdlEngine::loadGameState(int slot) { return Common::kNoError; } +const Room &AdlEngine::room(uint i) const { + if (i < 1 || i > _state.rooms.size()) + error("Room %i out of range [1, %i]", i, _state.rooms.size()); + + return _state.rooms[i - 1]; +} + Room &AdlEngine::room(uint i) { if (i < 1 || i > _state.rooms.size()) error("Room %i out of range [1, %i]", i, _state.rooms.size()); @@ -729,10 +741,21 @@ Room &AdlEngine::room(uint i) { return _state.rooms[i - 1]; } +const Room &AdlEngine::curRoom() const { + return room(_state.room); +} + Room &AdlEngine::curRoom() { return room(_state.room); } +const Item &AdlEngine::item(uint i) const { + if (i < 1 || i > _state.items.size()) + error("Item %i out of range [1, %i]", i, _state.items.size()); + + return _state.items[i - 1]; +} + Item &AdlEngine::item(uint i) { if (i < 1 || i > _state.items.size()) error("Item %i out of range [1, %i]", i, _state.items.size()); @@ -740,6 +763,13 @@ Item &AdlEngine::item(uint i) { return _state.items[i - 1]; } +const byte &AdlEngine::var(uint i) const { + if (i >= _state.vars.size()) + error("Variable %i out of range [0, %i]", i, _state.vars.size() - 1); + + return _state.vars[i]; +} + byte &AdlEngine::var(uint i) { if (i >= _state.vars.size()) error("Variable %i out of range [0, %i]", i, _state.vars.size() - 1); @@ -783,7 +813,7 @@ void AdlEngine::loadWords(Common::ReadStream &stream, WordMap &map) { } } -Common::String AdlEngine::getLine() { +Common::String AdlEngine::getLine() const { // Original engine uses a global here, which isn't reset between // calls and may not match actual mode bool textMode = false; @@ -806,7 +836,7 @@ Common::String AdlEngine::getLine() { } } -Common::String AdlEngine::getWord(const Common::String &line, uint &index) { +Common::String AdlEngine::getWord(const Common::String &line, uint &index) const { Common::String str; for (uint i = 0; i < 8; ++i) @@ -873,7 +903,7 @@ void AdlEngine::getInput(uint &verb, uint &noun) { } } -void AdlEngine::printASCIIString(const Common::String &str) { +void AdlEngine::printASCIIString(const Common::String &str) const { Common::String aStr; Common::String::const_iterator it; @@ -883,7 +913,7 @@ void AdlEngine::printASCIIString(const Common::String &str) { _display->printString(aStr); } -Common::String AdlEngine::inputString(byte prompt) { +Common::String AdlEngine::inputString(byte prompt) const { Common::String s; if (prompt > 0) @@ -921,7 +951,7 @@ Common::String AdlEngine::inputString(byte prompt) { } } -byte AdlEngine::convertKey(uint16 ascii) { +byte AdlEngine::convertKey(uint16 ascii) const { ascii = toupper(ascii); if (ascii >= 0x80) @@ -935,7 +965,7 @@ byte AdlEngine::convertKey(uint16 ascii) { return 0; } -byte AdlEngine::inputKey() { +byte AdlEngine::inputKey() const { Common::EventManager *ev = g_system->getEventManager(); byte key = 0; @@ -974,7 +1004,7 @@ byte AdlEngine::inputKey() { return key; } -void AdlEngine::delay(uint32 ms) { +void AdlEngine::delay(uint32 ms) const { Common::EventManager *ev = g_system->getEventManager(); uint32 start = g_system->getMillis(); @@ -996,10 +1026,9 @@ void AdlEngine::delay(uint32 ms) { } } -void AdlEngine::drawNextPixel(Common::Point &p, byte color, byte bits, byte quadrant) { - if (bits & 4) { +void AdlEngine::drawNextPixel(Common::Point &p, byte color, byte bits, byte quadrant) const { + if (bits & 4) _display->putPixel(p, color); - } bits += quadrant; @@ -1009,7 +1038,7 @@ void AdlEngine::drawNextPixel(Common::Point &p, byte color, byte bits, byte quad p.y += (bits & 2 ? 1 : -1); } -void AdlEngine::drawLineArt(const Common::Array &lineArt, Common::Point p, byte rotation, byte scaling, byte color) { +void AdlEngine::drawLineArt(const Common::Array &lineArt, Common::Point p, byte rotation, byte scaling, byte color) const { const byte stepping[] = { 0xff, 0xfe, 0xfa, 0xf4, 0xec, 0xe1, 0xd4, 0xc5, 0xb4, 0xa1, 0x8d, 0x78, 0x61, 0x49, 0x31, 0x18, diff --git a/engines/adl/adl.h b/engines/adl/adl.h index 66a539547b..5afcb0f64d 100644 --- a/engines/adl/adl.h +++ b/engines/adl/adl.h @@ -161,71 +161,30 @@ struct State { }; typedef Common::List Commands; +typedef Common::HashMap WordMap; class AdlEngine : public Engine { public: - AdlEngine(OSystem *syst, const AdlGameDescription *gd); virtual ~AdlEngine(); - const AdlGameDescription *_gameDescription; - bool hasFeature(EngineFeature f) const; - const char *getGameId() const; - static AdlEngine *create(GameType type, OSystem *syst, const AdlGameDescription *gd); - Common::Error run(); - virtual Common::String getEngineString(int str); - protected: - typedef Common::HashMap WordMap; + AdlEngine(OSystem *syst, const AdlGameDescription *gd); - virtual void runIntro() { } - virtual void loadData() = 0; - void runGame(); - virtual void initState() = 0; - virtual void restartGame() = 0; - virtual uint getEngineMessage(EngineMessage msg) = 0; - bool canSaveGameStateCurrently(); - bool canLoadGameStateCurrently(); - Common::String readString(Common::ReadStream &stream, byte until = 0); - void printStrings(Common::SeekableReadStream &stream, int count = 1); - virtual void printMessage(uint idx, bool wait = true); - void wordWrap(Common::String &str); - void readCommands(Common::ReadStream &stream, Commands &commands); - bool matchCommand(const Command &command, byte verb, byte noun, bool run = true); - bool doOneCommand(const Commands &commands, byte verb, byte noun); - void doAllCommands(const Commands &commands, byte verb, byte noun); - void doActions(const Command &command, byte noun, byte offset); - void clearScreen(); - virtual void drawPic(byte pic, Common::Point pos = Common::Point()) = 0; - void drawItems(); - void drawNextPixel(Common::Point &p, byte color, byte bits, byte quadrant); - void drawLineArt(const Common::Array &lineArt, Common::Point p, byte rotation = 0, byte scaling = 1, byte color = 0x7f); - void showRoom(); - void takeItem(byte noun); - void dropItem(byte noun); - Room &room(uint i); - Room &curRoom(); - Item &item(uint i); - byte &var(uint i); + Common::String readString(Common::ReadStream &stream, byte until = 0) const; + void printStrings(Common::SeekableReadStream &stream, int count = 1) const; + void printMessage(uint idx, bool wait = true) const; + void printASCIIString(const Common::String &str) const; void loadVerbs(Common::ReadStream &stream) { loadWords(stream, _verbs); } void loadNouns(Common::ReadStream &stream) { loadWords(stream, _nouns); } - void getInput(uint &verb, uint &noun); - void loadWords(Common::ReadStream &stream, WordMap &map); - Common::String getLine(); - Common::String getWord(const Common::String &line, uint &index); - void printASCIIString(const Common::String &str); - Common::String inputString(byte prompt = 0); - void delay(uint32 ms); - byte inputKey(); - Common::Error loadGameState(int slot); - Common::Error saveGameState(int slot, const Common::String &desc); + void readCommands(Common::ReadStream &stream, Commands &commands); + Common::String inputString(byte prompt = 0) const; + void delay(uint32 ms) const; + byte inputKey() const; Display *_display; Parser *_parser; - bool _isRestarting, _isRestoring; - byte _saveVerb, _saveNoun, _restoreVerb, _restoreNoun; - bool _canSaveNow, _canRestoreNow; Common::Array _strings; Common::Array _messages; @@ -239,14 +198,64 @@ protected: State _state; private: - void printEngineMessage(EngineMessage); - Common::String getTargetName() { return _targetName; } - byte convertKey(uint16 ascii); + virtual void runIntro() { } + virtual void loadData() = 0; + virtual void initState() = 0; + virtual void restartGame() = 0; + virtual uint getEngineMessage(EngineMessage msg) const = 0; + virtual void drawPic(byte pic, Common::Point pos = Common::Point()) const = 0; + + // Engine + Common::Error run(); + bool hasFeature(EngineFeature f) const; + Common::Error loadGameState(int slot); + bool canLoadGameStateCurrently() const; + Common::Error saveGameState(int slot, const Common::String &desc); + bool canSaveGameStateCurrently() const; + + // Text output + Common::String getEngineString(int str) const; + void printEngineMessage(EngineMessage) const; + void wordWrap(Common::String &str) const; + + // Text input + void loadWords(Common::ReadStream &stream, WordMap &map); + byte convertKey(uint16 ascii) const; + Common::String getLine() const; + Common::String getWord(const Common::String &line, uint &index) const; + void getInput(uint &verb, uint &noun); + + // Graphics + void showRoom() const; + void clearScreen() const; + void drawItems() const; + void drawNextPixel(Common::Point &p, byte color, byte bits, byte quadrant) const; + void drawLineArt(const Common::Array &lineArt, Common::Point p, byte rotation = 0, byte scaling = 1, byte color = 0x7f) const; + + // Game state functions + const Room &room(uint i) const; + Room &room(uint i); + const Room &curRoom() const; + Room &curRoom(); + const Item &item(uint i) const; + Item &item(uint i); + const byte &var(uint i) const; + byte &var(uint i); + void takeItem(byte noun); + void dropItem(byte noun); + bool matchCommand(const Command &command, byte verb, byte noun, uint *actions = nullptr) const; + bool doOneCommand(const Commands &commands, byte verb, byte noun); + void doAllCommands(const Commands &commands, byte verb, byte noun); + void doActions(const Command &command, byte noun, byte offset); enum { kWordSize = 8 }; + const AdlGameDescription *_gameDescription; + bool _isRestarting, _isRestoring; + byte _saveVerb, _saveNoun, _restoreVerb, _restoreNoun; + bool _canSaveNow, _canRestoreNow; WordMap _verbs; WordMap _nouns; }; diff --git a/engines/adl/hires1.cpp b/engines/adl/hires1.cpp index 11d576b217..c7b62c144f 100644 --- a/engines/adl/hires1.cpp +++ b/engines/adl/hires1.cpp @@ -205,7 +205,7 @@ void HiRes1Engine::runIntro() { delay(2000); } -void HiRes1Engine::drawPic(Common::ReadStream &stream, const Common::Point &pos) { +void HiRes1Engine::drawPic(Common::ReadStream &stream, const Common::Point &pos) const { byte x, y; bool bNewLine = false; byte oldX = 0, oldY = 0; @@ -242,7 +242,7 @@ void HiRes1Engine::drawPic(Common::ReadStream &stream, const Common::Point &pos) } } -void HiRes1Engine::drawPic(byte pic, Common::Point pos) { +void HiRes1Engine::drawPic(byte pic, Common::Point pos) const { Common::File f; Common::String name = Common::String::format("BLOCK%i", _pictures[pic].block); @@ -406,7 +406,7 @@ void HiRes1Engine::printMessage(uint idx, bool wait) { AdlEngine::printMessage(idx, wait); } -uint HiRes1Engine::getEngineMessage(EngineMessage msg) { +uint HiRes1Engine::getEngineMessage(EngineMessage msg) const { switch (msg) { case IDI_MSG_CANT_GO_THERE: return IDI_HR1_MSG_CANT_GO_THERE; @@ -423,7 +423,7 @@ uint HiRes1Engine::getEngineMessage(EngineMessage msg) { } } -void HiRes1Engine::drawLine(const Common::Point &p1, const Common::Point &p2, byte color) { +void HiRes1Engine::drawLine(const Common::Point &p1, const Common::Point &p2, byte color) const { // This draws a four-connected line int16 deltaX = p2.x - p1.x; diff --git a/engines/adl/hires1.h b/engines/adl/hires1.h index f72093a92a..7446e10394 100644 --- a/engines/adl/hires1.h +++ b/engines/adl/hires1.h @@ -39,15 +39,15 @@ public: private: void restartGame(); void printMessage(uint idx, bool wait = true); - uint getEngineMessage(EngineMessage msg); + uint getEngineMessage(EngineMessage msg) const; void initState(); void runIntro(); void loadData(); - void drawPic(Common::ReadStream &stream, const Common::Point &pos); + void drawPic(Common::ReadStream &stream, const Common::Point &pos) const; void drawItems(); - void drawLine(const Common::Point &p1, const Common::Point &p2, byte color); - void drawPic(byte pic, Common::Point pos); + void drawLine(const Common::Point &p1, const Common::Point &p2, byte color) const; + void drawPic(byte pic, Common::Point pos) const; }; } // End of namespace Adl -- cgit v1.2.3 From 58e7c539096f6b37c40dd0afa13c7ed500037be8 Mon Sep 17 00:00:00 2001 From: Walter van Niftrik Date: Sun, 6 Mar 2016 19:34:14 +0100 Subject: ADL: Clean up AdlEngine class --- engines/adl/adl.cpp | 16 +++++++++------- engines/adl/adl.h | 26 ++++++++++++++------------ engines/adl/hires1.cpp | 4 ++-- 3 files changed, 25 insertions(+), 21 deletions(-) (limited to 'engines') diff --git a/engines/adl/adl.cpp b/engines/adl/adl.cpp index e0c0b3afae..442edb7b71 100644 --- a/engines/adl/adl.cpp +++ b/engines/adl/adl.cpp @@ -777,18 +777,18 @@ byte &AdlEngine::var(uint i) { return _state.vars[i]; } -void AdlEngine::loadWords(Common::ReadStream &stream, WordMap &map) { +void AdlEngine::loadWords(Common::ReadStream &stream, WordMap &map) const { uint index = 0; while (1) { ++index; - byte buf[kWordSize]; + byte buf[IDI_WORD_SIZE]; - if (stream.read(buf, kWordSize) < kWordSize) + if (stream.read(buf, IDI_WORD_SIZE) < IDI_WORD_SIZE) error("Error reading word list"); - Common::String word((char *)buf, kWordSize); + Common::String word((char *)buf, IDI_WORD_SIZE); if (!map.contains(word)) map[word] = index; @@ -802,10 +802,10 @@ void AdlEngine::loadWords(Common::ReadStream &stream, WordMap &map) { break; for (uint i = 0; i < synonyms; ++i) { - if (stream.read((char *)buf, kWordSize) < kWordSize) + if (stream.read((char *)buf, IDI_WORD_SIZE) < IDI_WORD_SIZE) error("Error reading word list"); - word = Common::String((char *)buf, kWordSize); + word = Common::String((char *)buf, IDI_WORD_SIZE); if (!map.contains(word)) map[word] = index; @@ -1038,7 +1038,7 @@ void AdlEngine::drawNextPixel(Common::Point &p, byte color, byte bits, byte quad p.y += (bits & 2 ? 1 : -1); } -void AdlEngine::drawLineArt(const Common::Array &lineArt, Common::Point p, byte rotation, byte scaling, byte color) const { +void AdlEngine::drawLineArt(const Common::Array &lineArt, const Common::Point &pos, byte rotation, byte scaling, byte color) const { const byte stepping[] = { 0xff, 0xfe, 0xfa, 0xf4, 0xec, 0xe1, 0xd4, 0xc5, 0xb4, 0xa1, 0x8d, 0x78, 0x61, 0x49, 0x31, 0x18, @@ -1050,6 +1050,8 @@ void AdlEngine::drawLineArt(const Common::Array &lineArt, Common::Point p, byte xStep = stepping[rotation]; byte yStep = stepping[(rotation ^ 0xf) + 1] + 1; + Common::Point p(pos); + for (uint i = 0; i < lineArt.size(); ++i) { byte b = lineArt[i]; diff --git a/engines/adl/adl.h b/engines/adl/adl.h index 5afcb0f64d..6d5ab429ef 100644 --- a/engines/adl/adl.h +++ b/engines/adl/adl.h @@ -28,8 +28,6 @@ #include "engines/engine.h" -#include "gui/debugger.h" - namespace Common { class ReadStream; class SeekableReadStream; @@ -110,6 +108,8 @@ enum EngineString { #define IDO_ACT_DROP_ITEM 0x1c #define IDO_ACT_SET_ROOM_PIC 0x1d +#define IDI_WORD_SIZE 8 + struct Room { byte description; byte connections[6]; @@ -176,24 +176,33 @@ protected: void printStrings(Common::SeekableReadStream &stream, int count = 1) const; void printMessage(uint idx, bool wait = true) const; void printASCIIString(const Common::String &str) const; - void loadVerbs(Common::ReadStream &stream) { loadWords(stream, _verbs); } - void loadNouns(Common::ReadStream &stream) { loadWords(stream, _nouns); } void readCommands(Common::ReadStream &stream, Commands &commands); Common::String inputString(byte prompt = 0) const; void delay(uint32 ms) const; byte inputKey() const; + void loadWords(Common::ReadStream &stream, WordMap &map) const; Display *_display; Parser *_parser; + // Strings inside executable Common::Array _strings; + // Message strings in data file Common::Array _messages; + // Picture data Common::Array _pictures; + // Dropped item screen offsets Common::Array _itemOffsets; + // Drawings consisting of horizontal and vertical lines only, but + // supporting scaling and rotation Common::Array > _lineArt; + // lists Commands _roomCommands; Commands _globalCommands; + WordMap _verbs; + WordMap _nouns; + // Game state State _state; @@ -219,7 +228,6 @@ private: void wordWrap(Common::String &str) const; // Text input - void loadWords(Common::ReadStream &stream, WordMap &map); byte convertKey(uint16 ascii) const; Common::String getLine() const; Common::String getWord(const Common::String &line, uint &index) const; @@ -230,7 +238,7 @@ private: void clearScreen() const; void drawItems() const; void drawNextPixel(Common::Point &p, byte color, byte bits, byte quadrant) const; - void drawLineArt(const Common::Array &lineArt, Common::Point p, byte rotation = 0, byte scaling = 1, byte color = 0x7f) const; + void drawLineArt(const Common::Array &lineArt, const Common::Point &pos, byte rotation = 0, byte scaling = 1, byte color = 0x7f) const; // Game state functions const Room &room(uint i) const; @@ -248,16 +256,10 @@ private: void doAllCommands(const Commands &commands, byte verb, byte noun); void doActions(const Command &command, byte noun, byte offset); - enum { - kWordSize = 8 - }; - const AdlGameDescription *_gameDescription; bool _isRestarting, _isRestoring; byte _saveVerb, _saveNoun, _restoreVerb, _restoreNoun; bool _canSaveNow, _canRestoreNow; - WordMap _verbs; - WordMap _nouns; }; AdlEngine *HiRes1Engine__create(OSystem *syst, const AdlGameDescription *gd); diff --git a/engines/adl/hires1.cpp b/engines/adl/hires1.cpp index c7b62c144f..314434d850 100644 --- a/engines/adl/hires1.cpp +++ b/engines/adl/hires1.cpp @@ -379,10 +379,10 @@ void HiRes1Engine::loadData() { error("Failed to read game data from '" IDS_HR1_EXE_1 "'"); f.seek(IDI_HR1_OFS_VERBS); - loadVerbs(f); + loadWords(f, _verbs); f.seek(IDI_HR1_OFS_NOUNS); - loadNouns(f); + loadWords(f, _nouns); } void HiRes1Engine::printMessage(uint idx, bool wait) { -- cgit v1.2.3 From 07d0997befe416c56e38b831031b81a30e63925a Mon Sep 17 00:00:00 2001 From: Walter van Niftrik Date: Sun, 6 Mar 2016 21:59:55 +0100 Subject: ADL: Clean up AdlMetaEngine --- engines/adl/adl.cpp | 10 +--------- engines/adl/adl.h | 11 ----------- engines/adl/detection.cpp | 35 +++++++++++++++++++++-------------- engines/adl/detection.h | 45 +++++++++++++++++++++++++++++++++++++++++++++ engines/adl/hires1.cpp | 6 +----- engines/adl/hires1.h | 2 +- 6 files changed, 69 insertions(+), 40 deletions(-) create mode 100644 engines/adl/detection.h (limited to 'engines') diff --git a/engines/adl/adl.cpp b/engines/adl/adl.cpp index 442edb7b71..8884015d93 100644 --- a/engines/adl/adl.cpp +++ b/engines/adl/adl.cpp @@ -37,6 +37,7 @@ #include "adl/adl.h" #include "adl/display.h" +#include "adl/detection.h" namespace Adl { @@ -1071,13 +1072,4 @@ void AdlEngine::drawLineArt(const Common::Array &lineArt, const Common::Po } } -AdlEngine *AdlEngine::create(GameType type, OSystem *syst, const AdlGameDescription *gd) { - switch(type) { - case kGameTypeHires1: - return HiRes1Engine__create(syst, gd); - default: - error("Unknown GameType"); - } -} - } // End of namespace Adl diff --git a/engines/adl/adl.h b/engines/adl/adl.h index 6d5ab429ef..6f9b24d83f 100644 --- a/engines/adl/adl.h +++ b/engines/adl/adl.h @@ -34,20 +34,11 @@ class SeekableReadStream; } namespace Adl { - -#define SAVEGAME_VERSION 0 -#define SAVEGAME_NAME_LEN 32 - class Display; class Parser; class Console; struct AdlGameDescription; -enum GameType { - kGameTypeNone = 0, - kGameTypeHires1 -}; - struct StringOffset { int stringIdx; uint offset; @@ -167,8 +158,6 @@ class AdlEngine : public Engine { public: virtual ~AdlEngine(); - static AdlEngine *create(GameType type, OSystem *syst, const AdlGameDescription *gd); - protected: AdlEngine(OSystem *syst, const AdlGameDescription *gd); diff --git a/engines/adl/detection.cpp b/engines/adl/detection.cpp index e556e1258a..d96d94c66f 100644 --- a/engines/adl/detection.cpp +++ b/engines/adl/detection.cpp @@ -28,7 +28,7 @@ #include "engines/advancedDetector.h" -#include "adl/adl.h" +#include "adl/detection.h" namespace Adl { @@ -59,18 +59,12 @@ static const ADExtraGuiOptionsMap optionsList[] = { AD_EXTRA_GUI_OPTIONS_TERMINATOR }; -struct AdlGameDescription { - ADGameDescription desc; - GameType gameType; -}; - static const PlainGameDescriptor adlGames[] = { {"hires1", "Hi-Res Adventure #1: Mystery House"}, {0, 0} }; static const AdlGameDescription gameDescriptions[] = { - { // MD5 by waltervn { "hires1", 0, @@ -85,9 +79,9 @@ static const AdlGameDescription gameDescriptions[] = { ADGF_NO_FLAGS, GUIO2(GAMEOPTION_COLOR, GAMEOPTION_SCANLINES) }, - kGameTypeHires1 + GAME_TYPE_HIRES1 }, - {AD_TABLE_END_MARKER, kGameTypeNone} + { AD_TABLE_END_MARKER, GAME_TYPE_NONE } }; class AdlMetaEngine : public AdvancedMetaEngine { @@ -189,7 +183,7 @@ SaveStateList AdlMetaEngine::listSaves(const char *target) const { const Common::String &fileName = files[i]; Common::InSaveFile *inFile = saveFileMan->openForLoading(fileName); if (!inFile) { - warning("Cannot open save file %s", fileName.c_str()); + warning("Cannot open save file '%s'", fileName.c_str()); continue; } @@ -201,7 +195,7 @@ SaveStateList AdlMetaEngine::listSaves(const char *target) const { byte saveVersion = inFile->readByte(); if (saveVersion != SAVEGAME_VERSION) { - warning("Save game version %i not supported in '%s'", saveVersion, fileName.c_str()); + warning("Unsupported save game version %i found in '%s'", saveVersion, fileName.c_str()); delete inFile; continue; } @@ -225,10 +219,23 @@ void AdlMetaEngine::removeSaveState(const char *target, int slot) const { g_system->getSavefileManager()->removeSavefile(fileName); } +Engine *HiRes1Engine_create(OSystem *syst, const AdlGameDescription *gd); + bool AdlMetaEngine::createInstance(OSystem *syst, Engine **engine, const ADGameDescription *gd) const { - if (gd) - *engine = AdlEngine::create(((const AdlGameDescription *)gd)->gameType, syst, (const AdlGameDescription *)gd); - return gd != nullptr; + if (!gd) + return false; + + const AdlGameDescription *adlGd = (const AdlGameDescription *)gd; + + switch (adlGd->gameType) { + case GAME_TYPE_HIRES1: + *engine = HiRes1Engine_create(syst, adlGd); + break; + default: + error("Unknown GameType"); + } + + return true; } } // End of namespace Adl diff --git a/engines/adl/detection.h b/engines/adl/detection.h new file mode 100644 index 0000000000..c646aeb5b9 --- /dev/null +++ b/engines/adl/detection.h @@ -0,0 +1,45 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#ifndef ADL_DETECTION_H +#define ADL_DETECTION_H + +#include "engines/advancedDetector.h" + +namespace Adl { + +#define SAVEGAME_VERSION 0 +#define SAVEGAME_NAME_LEN 32 + +enum GameType { + GAME_TYPE_NONE, + GAME_TYPE_HIRES1 +}; + +struct AdlGameDescription { + ADGameDescription desc; + GameType gameType; +}; + +} // End of namespace Adl + +#endif diff --git a/engines/adl/hires1.cpp b/engines/adl/hires1.cpp index 314434d850..ad023087d1 100644 --- a/engines/adl/hires1.cpp +++ b/engines/adl/hires1.cpp @@ -98,10 +98,6 @@ static const StringOffset stringOffsets[] = { #define IDI_HR1_OFS_VERBS 0x3800 #define IDI_HR1_OFS_NOUNS 0x0f00 -HiRes1Engine::HiRes1Engine(OSystem *syst, const AdlGameDescription *gd) : - AdlEngine(syst, gd) { -} - void HiRes1Engine::runIntro() { Common::File file; @@ -462,7 +458,7 @@ void HiRes1Engine::drawLine(const Common::Point &p1, const Common::Point &p2, by } } -AdlEngine *HiRes1Engine__create(OSystem *syst, const AdlGameDescription *gd) { +Engine *HiRes1Engine_create(OSystem *syst, const AdlGameDescription *gd) { return new HiRes1Engine(syst, gd); } diff --git a/engines/adl/hires1.h b/engines/adl/hires1.h index 7446e10394..540e613eb9 100644 --- a/engines/adl/hires1.h +++ b/engines/adl/hires1.h @@ -34,7 +34,7 @@ namespace Adl { class HiRes1Engine : public AdlEngine { public: - HiRes1Engine(OSystem *syst, const AdlGameDescription *gd); + HiRes1Engine(OSystem *syst, const AdlGameDescription *gd) : AdlEngine(syst, gd) { } private: void restartGame(); -- cgit v1.2.3 From ac79cb081c2e7a137f2196b14e1fb2b7b4099c7f Mon Sep 17 00:00:00 2001 From: Walter van Niftrik Date: Sun, 6 Mar 2016 22:50:17 +0100 Subject: ADL: Move #defines into header file --- engines/adl/adl.cpp | 12 --------- engines/adl/adl.h | 12 +++++---- engines/adl/hires1.cpp | 69 ++++++++------------------------------------------ engines/adl/hires1.h | 68 ++++++++++++++++++++++++++++++++++++++++++++----- 4 files changed, 79 insertions(+), 82 deletions(-) (limited to 'engines') diff --git a/engines/adl/adl.cpp b/engines/adl/adl.cpp index 8884015d93..af379c085c 100644 --- a/engines/adl/adl.cpp +++ b/engines/adl/adl.cpp @@ -156,18 +156,6 @@ Common::String AdlEngine::readString(Common::ReadStream &stream, byte until) con return str; } -void AdlEngine::printStrings(Common::SeekableReadStream &stream, int count) const { - while (1) { - Common::String str = readString(stream); - _display->printString(str); - - if (--count == 0) - break; - - stream.seek(3, SEEK_CUR); - }; -} - Common::String AdlEngine::getEngineString(int str) const { return _strings[str]; } diff --git a/engines/adl/adl.h b/engines/adl/adl.h index 6f9b24d83f..591b918e43 100644 --- a/engines/adl/adl.h +++ b/engines/adl/adl.h @@ -162,14 +162,16 @@ protected: AdlEngine(OSystem *syst, const AdlGameDescription *gd); Common::String readString(Common::ReadStream &stream, byte until = 0) const; - void printStrings(Common::SeekableReadStream &stream, int count = 1) const; - void printMessage(uint idx, bool wait = true) const; + + virtual void printMessage(uint idx, bool wait = true) const; void printASCIIString(const Common::String &str) const; - void readCommands(Common::ReadStream &stream, Commands &commands); - Common::String inputString(byte prompt = 0) const; void delay(uint32 ms) const; + + Common::String inputString(byte prompt = 0) const; byte inputKey() const; + void loadWords(Common::ReadStream &stream, WordMap &map) const; + void readCommands(Common::ReadStream &stream, Commands &commands); Display *_display; Parser *_parser; @@ -196,7 +198,7 @@ protected: State _state; private: - virtual void runIntro() { } + virtual void runIntro() const { } virtual void loadData() = 0; virtual void initState() = 0; virtual void restartGame() = 0; diff --git a/engines/adl/hires1.cpp b/engines/adl/hires1.cpp index ad023087d1..754ee3043c 100644 --- a/engines/adl/hires1.cpp +++ b/engines/adl/hires1.cpp @@ -31,37 +31,6 @@ namespace Adl { -#define IDS_HR1_EXE_0 "AUTO LOAD OBJ" -#define IDS_HR1_EXE_1 "ADVENTURE" -#define IDS_HR1_LOADER "MYSTERY.HELLO" -#define IDS_HR1_MESSAGES "MESSAGES" - -#define IDI_HR1_NUM_ROOMS 41 -#define IDI_HR1_NUM_PICS 98 -#define IDI_HR1_NUM_VARS 20 -#define IDI_HR1_NUM_ITEM_OFFSETS 21 -#define IDI_HR1_NUM_MESSAGES 167 - -// Messages used outside of scripts -#define IDI_HR1_MSG_CANT_GO_THERE 137 -#define IDI_HR1_MSG_DONT_UNDERSTAND 37 -#define IDI_HR1_MSG_ITEM_DOESNT_MOVE 151 -#define IDI_HR1_MSG_ITEM_NOT_HERE 152 -#define IDI_HR1_MSG_THANKS_FOR_PLAYING 140 -#define IDI_HR1_MSG_DONT_HAVE_IT 127 -#define IDI_HR1_MSG_GETTING_DARK 7 - -// Strings embedded in the executable -enum { - IDI_HR1_STR_CANT_GO_THERE = IDI_STR_TOTAL, - IDI_HR1_STR_DONT_HAVE_IT, - IDI_HR1_STR_DONT_UNDERSTAND, - IDI_HR1_STR_GETTING_DARK, - IDI_HR1_STR_PRESS_RETURN, - - IDI_HR1_STR_TOTAL -}; - // Offsets for strings inside executable static const StringOffset stringOffsets[] = { { IDI_STR_ENTER_COMMAND, 0x5bbc }, @@ -75,30 +44,7 @@ static const StringOffset stringOffsets[] = { { IDI_HR1_STR_PRESS_RETURN, 0x5f68 } }; -#define IDI_HR1_OFS_PD_TEXT_0 0x005d -#define IDI_HR1_OFS_PD_TEXT_1 0x012b -#define IDI_HR1_OFS_PD_TEXT_2 0x016d -#define IDI_HR1_OFS_PD_TEXT_3 0x0259 - -#define IDI_HR1_OFS_INTRO_TEXT 0x0066 -#define IDI_HR1_OFS_GAME_OR_HELP 0x000f - -#define IDI_HR1_OFS_LOGO_0 0x1003 -#define IDI_HR1_OFS_LOGO_1 0x1800 - -#define IDI_HR1_OFS_ITEMS 0x0100 -#define IDI_HR1_OFS_ROOMS 0x050a -#define IDI_HR1_OFS_PICS 0x4b00 -#define IDI_HR1_OFS_CMDS_0 0x3c00 -#define IDI_HR1_OFS_CMDS_1 0x3d00 - -#define IDI_HR1_OFS_ITEM_OFFSETS 0x68ff -#define IDI_HR1_OFS_LINE_ART 0x4f00 - -#define IDI_HR1_OFS_VERBS 0x3800 -#define IDI_HR1_OFS_NOUNS 0x0f00 - -void HiRes1Engine::runIntro() { +void HiRes1Engine::runIntro() const { Common::File file; if (!file.open(IDS_HR1_EXE_0)) @@ -175,13 +121,20 @@ void HiRes1Engine::runIntro() { uint page = 0; while (pages[page] != 0) { _display->home(); - printStrings(file, pages[page++]); + + uint count = pages[page++]; + for (uint i = 0; i < count; ++i) { + str = readString(file); + _display->printString(str); + file.seek(3, SEEK_CUR); + } + inputString(); if (g_engine->shouldQuit()) return; - file.seek(9, SEEK_CUR); + file.seek(6, SEEK_CUR); } } @@ -381,7 +334,7 @@ void HiRes1Engine::loadData() { loadWords(f, _nouns); } -void HiRes1Engine::printMessage(uint idx, bool wait) { +void HiRes1Engine::printMessage(uint idx, bool wait) const { // Hardcoded overrides that don't wait after printing // Note: strings may differ slightly from the ones in MESSAGES switch (idx) { diff --git a/engines/adl/hires1.h b/engines/adl/hires1.h index 540e613eb9..a19e9c07d2 100644 --- a/engines/adl/hires1.h +++ b/engines/adl/hires1.h @@ -32,22 +32,76 @@ class Point; namespace Adl { +#define IDS_HR1_EXE_0 "AUTO LOAD OBJ" +#define IDS_HR1_EXE_1 "ADVENTURE" +#define IDS_HR1_LOADER "MYSTERY.HELLO" +#define IDS_HR1_MESSAGES "MESSAGES" + +#define IDI_HR1_NUM_ROOMS 41 +#define IDI_HR1_NUM_PICS 98 +#define IDI_HR1_NUM_VARS 20 +#define IDI_HR1_NUM_ITEM_OFFSETS 21 +#define IDI_HR1_NUM_MESSAGES 167 + +// Messages used outside of scripts +#define IDI_HR1_MSG_CANT_GO_THERE 137 +#define IDI_HR1_MSG_DONT_UNDERSTAND 37 +#define IDI_HR1_MSG_ITEM_DOESNT_MOVE 151 +#define IDI_HR1_MSG_ITEM_NOT_HERE 152 +#define IDI_HR1_MSG_THANKS_FOR_PLAYING 140 +#define IDI_HR1_MSG_DONT_HAVE_IT 127 +#define IDI_HR1_MSG_GETTING_DARK 7 + +// Strings embedded in the executable +enum { + IDI_HR1_STR_CANT_GO_THERE = IDI_STR_TOTAL, + IDI_HR1_STR_DONT_HAVE_IT, + IDI_HR1_STR_DONT_UNDERSTAND, + IDI_HR1_STR_GETTING_DARK, + IDI_HR1_STR_PRESS_RETURN, + + IDI_HR1_STR_TOTAL +}; + +#define IDI_HR1_OFS_PD_TEXT_0 0x005d +#define IDI_HR1_OFS_PD_TEXT_1 0x012b +#define IDI_HR1_OFS_PD_TEXT_2 0x016d +#define IDI_HR1_OFS_PD_TEXT_3 0x0259 + +#define IDI_HR1_OFS_INTRO_TEXT 0x0066 +#define IDI_HR1_OFS_GAME_OR_HELP 0x000f + +#define IDI_HR1_OFS_LOGO_0 0x1003 +#define IDI_HR1_OFS_LOGO_1 0x1800 + +#define IDI_HR1_OFS_ITEMS 0x0100 +#define IDI_HR1_OFS_ROOMS 0x050a +#define IDI_HR1_OFS_PICS 0x4b00 +#define IDI_HR1_OFS_CMDS_0 0x3c00 +#define IDI_HR1_OFS_CMDS_1 0x3d00 + +#define IDI_HR1_OFS_ITEM_OFFSETS 0x68ff +#define IDI_HR1_OFS_LINE_ART 0x4f00 + +#define IDI_HR1_OFS_VERBS 0x3800 +#define IDI_HR1_OFS_NOUNS 0x0f00 + class HiRes1Engine : public AdlEngine { public: HiRes1Engine(OSystem *syst, const AdlGameDescription *gd) : AdlEngine(syst, gd) { } private: + // AdlEngine + void runIntro() const; + void loadData(); + void initState(); void restartGame(); - void printMessage(uint idx, bool wait = true); uint getEngineMessage(EngineMessage msg) const; + void drawPic(byte pic, Common::Point pos) const; + void printMessage(uint idx, bool wait = true) const; - void initState(); - void runIntro(); - void loadData(); - void drawPic(Common::ReadStream &stream, const Common::Point &pos) const; - void drawItems(); void drawLine(const Common::Point &p1, const Common::Point &p2, byte color) const; - void drawPic(byte pic, Common::Point pos) const; + void drawPic(Common::ReadStream &stream, const Common::Point &pos) const; }; } // End of namespace Adl -- cgit v1.2.3 From fd8a5f419f0855babb99f716e526fc20e50882d6 Mon Sep 17 00:00:00 2001 From: Walter van Niftrik Date: Mon, 7 Mar 2016 15:19:26 +0100 Subject: ADL: Refactor string handling --- engines/adl/adl.cpp | 29 +++++++--------- engines/adl/adl.h | 42 ++++++++++------------- engines/adl/hires1.cpp | 92 +++++++++++++++++++------------------------------- engines/adl/hires1.h | 24 +++++++------ 4 files changed, 79 insertions(+), 108 deletions(-) (limited to 'engines') diff --git a/engines/adl/adl.cpp b/engines/adl/adl.cpp index af379c085c..f466f80b24 100644 --- a/engines/adl/adl.cpp +++ b/engines/adl/adl.cpp @@ -109,7 +109,7 @@ Common::Error AdlEngine::run() { break; if (!doOneCommand(_roomCommands, verb, noun)) - printEngineMessage(IDI_MSG_DONT_UNDERSTAND); + printMessage(_messageIds.dontUnderstand); } if (_isRestoring) { @@ -156,8 +156,9 @@ Common::String AdlEngine::readString(Common::ReadStream &stream, byte until) con return str; } -Common::String AdlEngine::getEngineString(int str) const { - return _strings[str]; +Common::String AdlEngine::readStringAt(Common::SeekableReadStream &stream, uint offset, byte until) const { + stream.seek(offset); + return readString(stream, until); } void AdlEngine::wordWrap(Common::String &str) const { @@ -184,10 +185,6 @@ void AdlEngine::printMessage(uint idx, bool wait) const { delay(14 * 166018 / 1000); } -void AdlEngine::printEngineMessage(EngineMessage msg) const { - printMessage(getEngineMessage(msg)); -} - void AdlEngine::readCommands(Common::ReadStream &stream, Commands &commands) { while (1) { Command command; @@ -232,7 +229,7 @@ void AdlEngine::takeItem(byte noun) { continue; if (item->state == IDI_ITEM_DOESNT_MOVE) { - printEngineMessage(IDI_MSG_ITEM_DOESNT_MOVE); + printMessage(_messageIds.itemDoesntMove); return; } @@ -251,7 +248,7 @@ void AdlEngine::takeItem(byte noun) { } } - printEngineMessage(IDI_MSG_ITEM_NOT_HERE); + printMessage(_messageIds.itemNotHere); } void AdlEngine::dropItem(byte noun) { @@ -266,7 +263,7 @@ void AdlEngine::dropItem(byte noun) { return; } - printEngineMessage(IDI_MSG_DONT_UNDERSTAND); + printMessage(_messageIds.dontUnderstand); } #define ARG(N) (command.script[offset + (N)]) @@ -339,7 +336,7 @@ void AdlEngine::doActions(const Command &command, byte noun, byte offset) { _isRestoring = false; break; case IDO_ACT_RESTART: { - _display->printString(_strings[IDI_STR_PLAY_AGAIN]); + _display->printString(_strings.playAgain); // We allow restoring via GMM here _canRestoreNow = true; @@ -360,7 +357,7 @@ void AdlEngine::doActions(const Command &command, byte noun, byte offset) { // Fall-through } case IDO_ACT_QUIT: - printEngineMessage(IDI_MSG_THANKS_FOR_PLAYING); + printMessage(_messageIds.thanksForPlaying); quitGame(); return; case IDO_ACT_PLACE_ITEM: @@ -386,7 +383,7 @@ void AdlEngine::doActions(const Command &command, byte noun, byte offset) { byte room = curRoom().connections[ARG(0) - IDO_ACT_GO_NORTH]; if (room == 0) { - printEngineMessage(IDI_MSG_CANT_GO_THERE); + printMessage(_messageIds.cantGoThere); return; } @@ -856,7 +853,7 @@ Common::String AdlEngine::getWord(const Common::String &line, uint &index) const void AdlEngine::getInput(uint &verb, uint &noun) { while (1) { - _display->printString(getEngineString(IDI_STR_ENTER_COMMAND)); + _display->printString(_strings.enterCommand); Common::String line = getLine(); if (shouldQuit() || _isRestoring) @@ -866,7 +863,7 @@ void AdlEngine::getInput(uint &verb, uint &noun) { Common::String verbStr = getWord(line, index); if (!_verbs.contains(verbStr)) { - Common::String err = getEngineString(IDI_STR_VERB_ERROR); + Common::String err = _strings.verbError; for (uint i = 0; i < verbStr.size(); ++i) err.setChar(verbStr[i], i + 19); _display->printString(err); @@ -878,7 +875,7 @@ void AdlEngine::getInput(uint &verb, uint &noun) { Common::String nounStr = getWord(line, index); if (!_nouns.contains(nounStr)) { - Common::String err = getEngineString(IDI_STR_NOUN_ERROR); + Common::String err = _strings.nounError; for (uint i = 0; i < verbStr.size(); ++i) err.setChar(verbStr[i], i + 19); for (uint i = 0; i < nounStr.size(); ++i) diff --git a/engines/adl/adl.h b/engines/adl/adl.h index 591b918e43..303f1972c0 100644 --- a/engines/adl/adl.h +++ b/engines/adl/adl.h @@ -44,25 +44,6 @@ struct StringOffset { uint offset; }; -// Messages used outside of scripts -enum EngineMessage { - IDI_MSG_CANT_GO_THERE, - IDI_MSG_DONT_UNDERSTAND, - IDI_MSG_ITEM_DOESNT_MOVE, - IDI_MSG_ITEM_NOT_HERE, - IDI_MSG_THANKS_FOR_PLAYING -}; - -// Strings embedded in the executable -enum EngineString { - IDI_STR_ENTER_COMMAND, - IDI_STR_VERB_ERROR, - IDI_STR_NOUN_ERROR, - IDI_STR_PLAY_AGAIN, - - IDI_STR_TOTAL -}; - // Conditional opcodes #define IDO_CND_ITEM_IN_ROOM 0x03 #define IDO_CND_MOVES_GE 0x05 @@ -162,6 +143,7 @@ protected: AdlEngine(OSystem *syst, const AdlGameDescription *gd); Common::String readString(Common::ReadStream &stream, byte until = 0) const; + Common::String readStringAt(Common::SeekableReadStream &stream, uint offset, byte until = 0) const; virtual void printMessage(uint idx, bool wait = true) const; void printASCIIString(const Common::String &str) const; @@ -176,8 +158,6 @@ protected: Display *_display; Parser *_parser; - // Strings inside executable - Common::Array _strings; // Message strings in data file Common::Array _messages; // Picture data @@ -194,6 +174,23 @@ protected: WordMap _verbs; WordMap _nouns; + struct { + Common::String enterCommand; + Common::String dontHaveIt; + Common::String gettingDark; + Common::String verbError; + Common::String nounError; + Common::String playAgain; + } _strings; + + struct { + uint cantGoThere; + uint dontUnderstand; + uint itemDoesntMove; + uint itemNotHere; + uint thanksForPlaying; + } _messageIds; + // Game state State _state; @@ -202,7 +199,6 @@ private: virtual void loadData() = 0; virtual void initState() = 0; virtual void restartGame() = 0; - virtual uint getEngineMessage(EngineMessage msg) const = 0; virtual void drawPic(byte pic, Common::Point pos = Common::Point()) const = 0; // Engine @@ -214,8 +210,6 @@ private: bool canSaveGameStateCurrently() const; // Text output - Common::String getEngineString(int str) const; - void printEngineMessage(EngineMessage) const; void wordWrap(Common::String &str) const; // Text input diff --git a/engines/adl/hires1.cpp b/engines/adl/hires1.cpp index 754ee3043c..80ea094fa8 100644 --- a/engines/adl/hires1.cpp +++ b/engines/adl/hires1.cpp @@ -31,19 +31,6 @@ namespace Adl { -// Offsets for strings inside executable -static const StringOffset stringOffsets[] = { - { IDI_STR_ENTER_COMMAND, 0x5bbc }, - { IDI_STR_VERB_ERROR, 0x5b4f }, - { IDI_STR_NOUN_ERROR, 0x5b8e }, - { IDI_STR_PLAY_AGAIN, 0x5f1e }, - { IDI_HR1_STR_CANT_GO_THERE, 0x6c0a }, - { IDI_HR1_STR_DONT_HAVE_IT, 0x6c31 }, - { IDI_HR1_STR_DONT_UNDERSTAND, 0x6c51 }, - { IDI_HR1_STR_GETTING_DARK, 0x6c7c }, - { IDI_HR1_STR_PRESS_RETURN, 0x5f68 } -}; - void HiRes1Engine::runIntro() const { Common::File file; @@ -67,20 +54,16 @@ void HiRes1Engine::runIntro() const { Common::String str; - basic.seek(IDI_HR1_OFS_PD_TEXT_0); - str = readString(basic, '"'); + str = readStringAt(basic, IDI_HR1_OFS_PD_TEXT_0, '"'); printASCIIString(str + '\r'); - basic.seek(IDI_HR1_OFS_PD_TEXT_1); - str = readString(basic, '"'); + str = readStringAt(basic, IDI_HR1_OFS_PD_TEXT_1, '"'); printASCIIString(str + "\r\r"); - basic.seek(IDI_HR1_OFS_PD_TEXT_2); - str = readString(basic, '"'); + str = readStringAt(basic, IDI_HR1_OFS_PD_TEXT_2, '"'); printASCIIString(str + "\r\r"); - basic.seek(IDI_HR1_OFS_PD_TEXT_3); - str = readString(basic, '"'); + str = readStringAt(basic, IDI_HR1_OFS_PD_TEXT_3, '"'); printASCIIString(str + '\r'); inputKey(); @@ -89,8 +72,7 @@ void HiRes1Engine::runIntro() const { _display->setMode(DISPLAY_MODE_MIXED); - file.seek(IDI_HR1_OFS_GAME_OR_HELP); - str = readString(file); + str = readStringAt(file, IDI_HR1_OFS_GAME_OR_HELP); bool instructions = false; @@ -256,7 +238,7 @@ void HiRes1Engine::initState() { void HiRes1Engine::restartGame() { initState(); - _display->printString(_strings[IDI_HR1_STR_PRESS_RETURN]); + _display->printString(_gameStrings.pressReturn); inputString(); // Missing in the original printASCIIString("\r\r\r\r\r"); } @@ -275,12 +257,27 @@ void HiRes1Engine::loadData() { if (!f.open(IDS_HR1_EXE_1)) error("Failed to open file '" IDS_HR1_EXE_1 "'"); - // Load strings from executable - _strings.resize(IDI_HR1_STR_TOTAL); - for (uint idx = 0; idx < IDI_HR1_STR_TOTAL; ++idx) { - f.seek(stringOffsets[idx].offset); - _strings[stringOffsets[idx].stringIdx] = readString(f); - } + // Some messages have overrides inside the executable + _messages[IDI_HR1_MSG_CANT_GO_THERE - 1] = readStringAt(f, IDI_HR1_OFS_STR_CANT_GO_THERE); + _messages[IDI_HR1_MSG_DONT_HAVE_IT - 1] = readStringAt(f, IDI_HR1_OFS_STR_DONT_HAVE_IT); + _messages[IDI_HR1_MSG_DONT_UNDERSTAND - 1] = readStringAt(f, IDI_HR1_OFS_STR_DONT_UNDERSTAND); + _messages[IDI_HR1_MSG_GETTING_DARK - 1] = readStringAt(f, IDI_HR1_OFS_STR_GETTING_DARK); + + // Load other strings from executable + _strings.enterCommand = readStringAt(f, IDI_HR1_OFS_STR_ENTER_COMMAND); + _strings.dontHaveIt = readStringAt(f, IDI_HR1_OFS_STR_DONT_HAVE_IT); + _strings.gettingDark = readStringAt(f, IDI_HR1_OFS_STR_GETTING_DARK); + _strings.verbError = readStringAt(f, IDI_HR1_OFS_STR_VERB_ERROR); + _strings.nounError = readStringAt(f, IDI_HR1_OFS_STR_NOUN_ERROR); + _strings.playAgain = readStringAt(f, IDI_HR1_OFS_STR_PLAY_AGAIN); + _gameStrings.pressReturn = readStringAt(f, IDI_HR1_OFS_STR_PRESS_RETURN); + + // Set message IDs + _messageIds.cantGoThere = IDI_HR1_MSG_CANT_GO_THERE; + _messageIds.dontUnderstand = IDI_HR1_MSG_DONT_UNDERSTAND; + _messageIds.itemDoesntMove = IDI_HR1_MSG_ITEM_DOESNT_MOVE; + _messageIds.itemNotHere = IDI_HR1_MSG_ITEM_NOT_HERE; + _messageIds.thanksForPlaying = IDI_HR1_MSG_THANKS_FOR_PLAYING; // Load picture data from executable f.seek(IDI_HR1_OFS_PICS); @@ -335,43 +332,24 @@ void HiRes1Engine::loadData() { } void HiRes1Engine::printMessage(uint idx, bool wait) const { - // Hardcoded overrides that don't wait after printing - // Note: strings may differ slightly from the ones in MESSAGES + // Messages with hardcoded overrides don't delay after printing. + // It's unclear if this is a bug or not. In some cases the result + // is that these strings will scroll past the four-line text window + // before the user gets a chance to read them. + // NOTE: later games seem to wait for a key when the text window + // overflows and don't use delays. It might be better to use + // that system for this game as well. switch (idx) { case IDI_HR1_MSG_CANT_GO_THERE: - _display->printString(_strings[IDI_HR1_STR_CANT_GO_THERE]); - return; case IDI_HR1_MSG_DONT_HAVE_IT: - _display->printString(_strings[IDI_HR1_STR_DONT_HAVE_IT]); - return; case IDI_HR1_MSG_DONT_UNDERSTAND: - _display->printString(_strings[IDI_HR1_STR_DONT_UNDERSTAND]); - return; case IDI_HR1_MSG_GETTING_DARK: - _display->printString(_strings[IDI_HR1_STR_GETTING_DARK]); - return; + wait = false; } AdlEngine::printMessage(idx, wait); } -uint HiRes1Engine::getEngineMessage(EngineMessage msg) const { - switch (msg) { - case IDI_MSG_CANT_GO_THERE: - return IDI_HR1_MSG_CANT_GO_THERE; - case IDI_MSG_DONT_UNDERSTAND: - return IDI_HR1_MSG_DONT_UNDERSTAND; - case IDI_MSG_ITEM_DOESNT_MOVE: - return IDI_HR1_MSG_ITEM_DOESNT_MOVE; - case IDI_MSG_ITEM_NOT_HERE: - return IDI_HR1_MSG_ITEM_NOT_HERE; - case IDI_MSG_THANKS_FOR_PLAYING: - return IDI_HR1_MSG_THANKS_FOR_PLAYING; - default: - error("Cannot find engine message %i", msg); - } -} - void HiRes1Engine::drawLine(const Common::Point &p1, const Common::Point &p2, byte color) const { // This draws a four-connected line diff --git a/engines/adl/hires1.h b/engines/adl/hires1.h index a19e9c07d2..b7c7f41e12 100644 --- a/engines/adl/hires1.h +++ b/engines/adl/hires1.h @@ -52,16 +52,15 @@ namespace Adl { #define IDI_HR1_MSG_DONT_HAVE_IT 127 #define IDI_HR1_MSG_GETTING_DARK 7 -// Strings embedded in the executable -enum { - IDI_HR1_STR_CANT_GO_THERE = IDI_STR_TOTAL, - IDI_HR1_STR_DONT_HAVE_IT, - IDI_HR1_STR_DONT_UNDERSTAND, - IDI_HR1_STR_GETTING_DARK, - IDI_HR1_STR_PRESS_RETURN, - - IDI_HR1_STR_TOTAL -}; +#define IDI_HR1_OFS_STR_ENTER_COMMAND 0x5bbc +#define IDI_HR1_OFS_STR_VERB_ERROR 0x5b4f +#define IDI_HR1_OFS_STR_NOUN_ERROR 0x5b8e +#define IDI_HR1_OFS_STR_PLAY_AGAIN 0x5f1e +#define IDI_HR1_OFS_STR_CANT_GO_THERE 0x6c0a +#define IDI_HR1_OFS_STR_DONT_HAVE_IT 0x6c31 +#define IDI_HR1_OFS_STR_DONT_UNDERSTAND 0x6c51 +#define IDI_HR1_OFS_STR_GETTING_DARK 0x6c7c +#define IDI_HR1_OFS_STR_PRESS_RETURN 0x5f68 #define IDI_HR1_OFS_PD_TEXT_0 0x005d #define IDI_HR1_OFS_PD_TEXT_1 0x012b @@ -96,12 +95,15 @@ private: void loadData(); void initState(); void restartGame(); - uint getEngineMessage(EngineMessage msg) const; void drawPic(byte pic, Common::Point pos) const; void printMessage(uint idx, bool wait = true) const; void drawLine(const Common::Point &p1, const Common::Point &p2, byte color) const; void drawPic(Common::ReadStream &stream, const Common::Point &pos) const; + + struct { + Common::String pressReturn; + } _gameStrings; }; } // End of namespace Adl -- cgit v1.2.3 From 86d58534e7138c7b58995e1f730c8531ca2d4273 Mon Sep 17 00:00:00 2001 From: Walter van Niftrik Date: Mon, 7 Mar 2016 15:26:01 +0100 Subject: ADL: Move ASCII print function into Display class --- engines/adl/adl.cpp | 14 ++------------ engines/adl/adl.h | 1 - engines/adl/display.cpp | 10 ++++++++++ engines/adl/display.h | 1 + engines/adl/hires1.cpp | 12 ++++++------ 5 files changed, 19 insertions(+), 19 deletions(-) (limited to 'engines') diff --git a/engines/adl/adl.cpp b/engines/adl/adl.cpp index f466f80b24..5b43a6cd31 100644 --- a/engines/adl/adl.cpp +++ b/engines/adl/adl.cpp @@ -87,7 +87,7 @@ Common::Error AdlEngine::run() { } _display->setMode(DISPLAY_MODE_MIXED); - printASCIIString("\r\r\r\r\r"); + _display->printAsciiString("\r\r\r\r\r"); while (1) { uint verb = 0, noun = 0; @@ -119,7 +119,7 @@ Common::Error AdlEngine::run() { // means that restoring a game will always run through // the global commands and increase the move counter // before the first user input. - printASCIIString("\r"); + _display->printAsciiString("\r"); _isRestoring = false; verb = _restoreVerb; noun = _restoreNoun; @@ -889,16 +889,6 @@ void AdlEngine::getInput(uint &verb, uint &noun) { } } -void AdlEngine::printASCIIString(const Common::String &str) const { - Common::String aStr; - - Common::String::const_iterator it; - for (it = str.begin(); it != str.end(); ++it) - aStr += APPLECHAR(*it); - - _display->printString(aStr); -} - Common::String AdlEngine::inputString(byte prompt) const { Common::String s; diff --git a/engines/adl/adl.h b/engines/adl/adl.h index 303f1972c0..b1d5b7c0b3 100644 --- a/engines/adl/adl.h +++ b/engines/adl/adl.h @@ -146,7 +146,6 @@ protected: Common::String readStringAt(Common::SeekableReadStream &stream, uint offset, byte until = 0) const; virtual void printMessage(uint idx, bool wait = true) const; - void printASCIIString(const Common::String &str) const; void delay(uint32 ms) const; Common::String inputString(byte prompt = 0) const; diff --git a/engines/adl/display.cpp b/engines/adl/display.cpp index 7af6f660fd..d48296e9ee 100644 --- a/engines/adl/display.cpp +++ b/engines/adl/display.cpp @@ -289,6 +289,16 @@ void Display::printString(const Common::String &str) { updateTextScreen(); } +void Display::printAsciiString(const Common::String &str) { + Common::String aStr; + + Common::String::const_iterator it; + for (it = str.begin(); it != str.end(); ++it) + aStr += APPLECHAR(*it); + + printString(aStr); +} + void Display::setCharAtCursor(byte c) { _textBuf[_cursorPos] = c; } diff --git a/engines/adl/display.h b/engines/adl/display.h index ce8f86beba..e61477da84 100644 --- a/engines/adl/display.h +++ b/engines/adl/display.h @@ -70,6 +70,7 @@ public: void moveCursorForward(); void moveCursorBackward(); void printString(const Common::String &str); + void printAsciiString(const Common::String &str); void setCharAtCursor(byte c); void showCursor(bool enable); diff --git a/engines/adl/hires1.cpp b/engines/adl/hires1.cpp index 80ea094fa8..95f02899a2 100644 --- a/engines/adl/hires1.cpp +++ b/engines/adl/hires1.cpp @@ -55,16 +55,16 @@ void HiRes1Engine::runIntro() const { Common::String str; str = readStringAt(basic, IDI_HR1_OFS_PD_TEXT_0, '"'); - printASCIIString(str + '\r'); + _display->printAsciiString(str + '\r'); str = readStringAt(basic, IDI_HR1_OFS_PD_TEXT_1, '"'); - printASCIIString(str + "\r\r"); + _display->printAsciiString(str + "\r\r"); str = readStringAt(basic, IDI_HR1_OFS_PD_TEXT_2, '"'); - printASCIIString(str + "\r\r"); + _display->printAsciiString(str + "\r\r"); str = readStringAt(basic, IDI_HR1_OFS_PD_TEXT_3, '"'); - printASCIIString(str + '\r'); + _display->printAsciiString(str + '\r'); inputKey(); if (g_engine->shouldQuit()) @@ -120,7 +120,7 @@ void HiRes1Engine::runIntro() const { } } - printASCIIString("\r"); + _display->printAsciiString("\r"); file.close(); @@ -240,7 +240,7 @@ void HiRes1Engine::restartGame() { initState(); _display->printString(_gameStrings.pressReturn); inputString(); // Missing in the original - printASCIIString("\r\r\r\r\r"); + _display->printAsciiString("\r\r\r\r\r"); } void HiRes1Engine::loadData() { -- cgit v1.2.3 From 63adab81edc8f44d4b4387352e0869e3042c2a13 Mon Sep 17 00:00:00 2001 From: Walter van Niftrik Date: Mon, 7 Mar 2016 20:43:37 +0100 Subject: ADL: Clean up HiRes1Engine class --- engines/adl/adl.cpp | 1398 ++++++++++++++++++++++++------------------------ engines/adl/adl.h | 14 +- engines/adl/hires1.cpp | 214 ++++---- engines/adl/hires1.h | 2 + 4 files changed, 812 insertions(+), 816 deletions(-) (limited to 'engines') diff --git a/engines/adl/adl.cpp b/engines/adl/adl.cpp index 5b43a6cd31..dd4f4068d1 100644 --- a/engines/adl/adl.cpp +++ b/engines/adl/adl.cpp @@ -41,10 +41,14 @@ namespace Adl { +AdlEngine::~AdlEngine() { + delete _display; +} + AdlEngine::AdlEngine(OSystem *syst, const AdlGameDescription *gd) : Engine(syst), - _gameDescription(gd), _display(nullptr), + _gameDescription(gd), _isRestarting(false), _isRestoring(false), _saveVerb(0), @@ -55,18 +59,206 @@ AdlEngine::AdlEngine(OSystem *syst, const AdlGameDescription *gd) : _canRestoreNow(false) { } -AdlEngine::~AdlEngine() { - delete _display; +Common::String AdlEngine::readString(Common::ReadStream &stream, byte until) const { + Common::String str; + + while (1) { + byte b = stream.readByte(); + + if (stream.eos() || stream.err()) + error("Error reading string"); + + if (b == until) + break; + + str += b; + }; + + return str; } -bool AdlEngine::hasFeature(EngineFeature f) const { - switch (f) { - case kSupportsLoadingDuringRuntime: - case kSupportsSavingDuringRuntime: - case kSupportsRTL: - return true; - default: - return false; +Common::String AdlEngine::readStringAt(Common::SeekableReadStream &stream, uint offset, byte until) const { + stream.seek(offset); + return readString(stream, until); +} + +void AdlEngine::printMessage(uint idx, bool wait) const { + Common::String msg = _messages[idx - 1]; + wordWrap(msg); + _display->printString(msg); + + if (wait) + delay(14 * 166018 / 1000); +} + +void AdlEngine::delay(uint32 ms) const { + Common::EventManager *ev = g_system->getEventManager(); + + uint32 start = g_system->getMillis(); + + while (!g_engine->shouldQuit() && g_system->getMillis() - start < ms) { + Common::Event event; + if (ev->pollEvent(event)) { + if (event.type == Common::EVENT_KEYDOWN && (event.kbd.flags & Common::KBD_CTRL)) { + switch(event.kbd.keycode) { + case Common::KEYCODE_q: + g_engine->quitGame(); + break; + default: + break; + } + } + } + g_system->delayMillis(16); + } +} + +Common::String AdlEngine::inputString(byte prompt) const { + Common::String s; + + if (prompt > 0) + _display->printString(Common::String(prompt)); + + while (1) { + byte b = inputKey(); + + if (g_engine->shouldQuit() || _isRestoring) + return 0; + + if (b == 0) + continue; + + if (b == ('\r' | 0x80)) { + s += b; + _display->printString(Common::String(b)); + return s; + } + + if (b < 0xa0) { + switch (b) { + case Common::KEYCODE_BACKSPACE | 0x80: + if (!s.empty()) { + _display->moveCursorBackward(); + _display->setCharAtCursor(APPLECHAR(' ')); + s.deleteLastChar(); + } + break; + }; + } else { + s += b; + _display->printString(Common::String(b)); + } + } +} + +byte AdlEngine::inputKey() const { + Common::EventManager *ev = g_system->getEventManager(); + + byte key = 0; + + _display->showCursor(true); + + while (!g_engine->shouldQuit() && !_isRestoring && key == 0) { + Common::Event event; + if (ev->pollEvent(event)) { + if (event.type != Common::EVENT_KEYDOWN) + continue; + + if (event.kbd.flags & Common::KBD_CTRL) { + if (event.kbd.keycode == Common::KEYCODE_q) + g_engine->quitGame(); + continue; + } + + switch (event.kbd.keycode) { + case Common::KEYCODE_BACKSPACE: + case Common::KEYCODE_RETURN: + key = convertKey(event.kbd.keycode); + break; + default: + if (event.kbd.ascii >= 0x20 && event.kbd.ascii < 0x80) + key = convertKey(event.kbd.ascii); + }; + } + + _display->updateTextScreen(); + g_system->delayMillis(16); + } + + _display->showCursor(false); + + return key; +} + +void AdlEngine::loadWords(Common::ReadStream &stream, WordMap &map) const { + uint index = 0; + + while (1) { + ++index; + + byte buf[IDI_WORD_SIZE]; + + if (stream.read(buf, IDI_WORD_SIZE) < IDI_WORD_SIZE) + error("Error reading word list"); + + Common::String word((char *)buf, IDI_WORD_SIZE); + + if (!map.contains(word)) + map[word] = index; + + byte synonyms = stream.readByte(); + + if (stream.err() || stream.eos()) + error("Error reading word list"); + + if (synonyms == 0xff) + break; + + for (uint i = 0; i < synonyms; ++i) { + if (stream.read((char *)buf, IDI_WORD_SIZE) < IDI_WORD_SIZE) + error("Error reading word list"); + + word = Common::String((char *)buf, IDI_WORD_SIZE); + + if (!map.contains(word)) + map[word] = index; + } + } +} + +void AdlEngine::readCommands(Common::ReadStream &stream, Commands &commands) { + while (1) { + Command command; + command.room = stream.readByte(); + + if (command.room == 0xff) + return; + + command.verb = stream.readByte(); + command.noun = stream.readByte(); + + byte scriptSize = stream.readByte() - 6; + + command.numCond = stream.readByte(); + command.numAct = stream.readByte(); + + for (uint i = 0; i < scriptSize; ++i) + command.script.push_back(stream.readByte()); + + if (stream.eos() || stream.err()) + error("Failed to read commands"); + + if (command.numCond == 0 && command.script[0] == IDO_ACT_SAVE) { + _saveVerb = command.verb; + _saveNoun = command.noun; + } + + if (command.numCond == 0 && command.script[0] == IDO_ACT_LOAD) { + _restoreVerb = command.verb; + _restoreNoun = command.noun; + } + + commands.push_back(command); } } @@ -138,380 +330,317 @@ Common::Error AdlEngine::run() { return Common::kNoError; } -Common::String AdlEngine::readString(Common::ReadStream &stream, byte until) const { - Common::String str; - - while (1) { - byte b = stream.readByte(); +bool AdlEngine::hasFeature(EngineFeature f) const { + switch (f) { + case kSupportsLoadingDuringRuntime: + case kSupportsSavingDuringRuntime: + case kSupportsRTL: + return true; + default: + return false; + } +} - if (stream.eos() || stream.err()) - error("Error reading string"); +Common::Error AdlEngine::loadGameState(int slot) { + Common::String fileName = Common::String::format("%s.s%02d", _targetName.c_str(), slot); + Common::InSaveFile *inFile = getSaveFileManager()->openForLoading(fileName); - if (b == until) - break; + if (!inFile) { + warning("Failed to open file '%s'", fileName.c_str()); + return Common::kUnknownError; + } - str += b; - }; + if (inFile->readUint32BE() != MKTAG('A', 'D', 'L', ':')) { + warning("No header found in '%s'", fileName.c_str()); + delete inFile; + return Common::kUnknownError; + } - return str; -} + byte saveVersion = inFile->readByte(); + if (saveVersion != SAVEGAME_VERSION) { + warning("Save game version %i not supported", saveVersion); + delete inFile; + return Common::kUnknownError; + } -Common::String AdlEngine::readStringAt(Common::SeekableReadStream &stream, uint offset, byte until) const { - stream.seek(offset); - return readString(stream, until); -} + // Skip description + inFile->seek(SAVEGAME_NAME_LEN, SEEK_CUR); + // Skip save time + inFile->seek(6, SEEK_CUR); -void AdlEngine::wordWrap(Common::String &str) const { - uint end = 39; + uint32 playTime = inFile->readUint32BE(); - while (1) { - if (str.size() <= end) - return; + Graphics::skipThumbnail(*inFile); - while (str[end] != APPLECHAR(' ')) - --end; + initState(); - str.setChar(APPLECHAR('\r'), end); - end += 40; + _state.room = inFile->readByte(); + _state.moves = inFile->readByte(); + _state.isDark = inFile->readByte(); + + uint32 size = inFile->readUint32BE(); + if (size != _state.rooms.size()) + error("Room count mismatch (expected %i; found %i)", _state.rooms.size(), size); + + for (uint i = 0; i < size; ++i) { + _state.rooms[i].picture = inFile->readByte(); + _state.rooms[i].curPicture = inFile->readByte(); } -} -void AdlEngine::printMessage(uint idx, bool wait) const { - Common::String msg = _messages[idx - 1]; - wordWrap(msg); - _display->printString(msg); + size = inFile->readUint32BE(); + if (size != _state.items.size()) + error("Item count mismatch (expected %i; found %i)", _state.items.size(), size); - if (wait) - delay(14 * 166018 / 1000); + for (uint i = 0; i < size; ++i) { + _state.items[i].room = inFile->readByte(); + _state.items[i].picture = inFile->readByte(); + _state.items[i].position.x = inFile->readByte(); + _state.items[i].position.y = inFile->readByte(); + _state.items[i].state = inFile->readByte(); + } + + size = inFile->readUint32BE(); + if (size != _state.vars.size()) + error("Variable count mismatch (expected %i; found %i)", _state.vars.size(), size); + + for (uint i = 0; i < size; ++i) + _state.vars[i] = inFile->readByte(); + + if (inFile->err() || inFile->eos()) + error("Failed to load game '%s'", fileName.c_str()); + + delete inFile; + + setTotalPlayTime(playTime); + + _isRestoring = true; + return Common::kNoError; } -void AdlEngine::readCommands(Common::ReadStream &stream, Commands &commands) { - while (1) { - Command command; - command.room = stream.readByte(); +bool AdlEngine::canLoadGameStateCurrently() const { + return _canRestoreNow; +} - if (command.room == 0xff) - return; +Common::Error AdlEngine::saveGameState(int slot, const Common::String &desc) { + Common::String fileName = Common::String::format("%s.s%02d", _targetName.c_str(), slot); + Common::OutSaveFile *outFile = getSaveFileManager()->openForSaving(fileName); - command.verb = stream.readByte(); - command.noun = stream.readByte(); + if (!outFile) { + warning("Failed to open file '%s'", fileName.c_str()); + return Common::kUnknownError; + } - byte scriptSize = stream.readByte() - 6; + outFile->writeUint32BE(MKTAG('A', 'D', 'L', ':')); + outFile->writeByte(SAVEGAME_VERSION); - command.numCond = stream.readByte(); - command.numAct = stream.readByte(); + char name[SAVEGAME_NAME_LEN] = { }; - for (uint i = 0; i < scriptSize; ++i) - command.script.push_back(stream.readByte()); + if (!desc.empty()) + strncpy(name, desc.c_str(), sizeof(name) - 1); + else { + Common::String defaultName("Save "); + defaultName += 'A' + slot; + strncpy(name, defaultName.c_str(), sizeof(name) - 1); + } - if (stream.eos() || stream.err()) - error("Failed to read commands"); + outFile->write(name, sizeof(name)); - if (command.numCond == 0 && command.script[0] == IDO_ACT_SAVE) { - _saveVerb = command.verb; - _saveNoun = command.noun; - } + TimeDate t; + g_system->getTimeAndDate(t); - if (command.numCond == 0 && command.script[0] == IDO_ACT_LOAD) { - _restoreVerb = command.verb; - _restoreNoun = command.noun; - } + outFile->writeUint16BE(t.tm_year); + outFile->writeByte(t.tm_mon); + outFile->writeByte(t.tm_mday); + outFile->writeByte(t.tm_hour); + outFile->writeByte(t.tm_min); - commands.push_back(command); + uint32 playTime = getTotalPlayTime(); + outFile->writeUint32BE(playTime); + + _display->saveThumbnail(*outFile); + + outFile->writeByte(_state.room); + outFile->writeByte(_state.moves); + outFile->writeByte(_state.isDark); + + outFile->writeUint32BE(_state.rooms.size()); + for (uint i = 0; i < _state.rooms.size(); ++i) { + outFile->writeByte(_state.rooms[i].picture); + outFile->writeByte(_state.rooms[i].curPicture); } -} -void AdlEngine::takeItem(byte noun) { - Common::Array::iterator item; + outFile->writeUint32BE(_state.items.size()); + for (uint i = 0; i < _state.items.size(); ++i) { + outFile->writeByte(_state.items[i].room); + outFile->writeByte(_state.items[i].picture); + outFile->writeByte(_state.items[i].position.x); + outFile->writeByte(_state.items[i].position.y); + outFile->writeByte(_state.items[i].state); + } - for (item = _state.items.begin(); item != _state.items.end(); ++item) { - if (item->noun != noun || item->room != _state.room) - continue; + outFile->writeUint32BE(_state.vars.size()); + for (uint i = 0; i < _state.vars.size(); ++i) + outFile->writeByte(_state.vars[i]); - if (item->state == IDI_ITEM_DOESNT_MOVE) { - printMessage(_messageIds.itemDoesntMove); - return; - } + outFile->finalize(); - if (item->state == IDI_ITEM_MOVED) { - item->room = IDI_NONE; - return; - } + if (outFile->err()) { + delete outFile; + warning("Failed to save game '%s'", fileName.c_str()); + return Common::kUnknownError; + } - Common::Array::const_iterator pic; - for (pic = item->roomPictures.begin(); pic != item->roomPictures.end(); ++pic) { - if (*pic == curRoom().curPicture) { - item->room = IDI_NONE; - item->state = IDI_ITEM_MOVED; - return; - } + delete outFile; + return Common::kNoError; +} + +bool AdlEngine::canSaveGameStateCurrently() const { + if (!_canSaveNow) + return false; + + Commands::const_iterator cmd; + + // Here we check whether or not the game currently accepts the command + // "SAVE GAME". This prevents saving via the GMM in situations where + // it wouldn't otherwise be possible to do so. + for (cmd = _roomCommands.begin(); cmd != _roomCommands.end(); ++cmd) { + if (matchCommand(*cmd, _saveVerb, _saveNoun)) { + if (cmd->verb != _saveVerb || cmd->noun != _saveNoun) + return false; + return cmd->numCond == 0 && cmd->script[0] == IDO_ACT_SAVE; } } - printMessage(_messageIds.itemNotHere); + return false; } -void AdlEngine::dropItem(byte noun) { - Common::Array::iterator item; +void AdlEngine::wordWrap(Common::String &str) const { + uint end = 39; - for (item = _state.items.begin(); item != _state.items.end(); ++item) { - if (item->noun != noun || item->room != IDI_NONE) - continue; + while (1) { + if (str.size() <= end) + return; - item->room = _state.room; - item->state = IDI_ITEM_MOVED; - return; + while (str[end] != APPLECHAR(' ')) + --end; + + str.setChar(APPLECHAR('\r'), end); + end += 40; } +} - printMessage(_messageIds.dontUnderstand); +byte AdlEngine::convertKey(uint16 ascii) const { + ascii = toupper(ascii); + + if (ascii >= 0x80) + return 0; + + ascii |= 0x80; + + if (ascii >= 0x80 && ascii <= 0xe0) + return ascii; + + return 0; } -#define ARG(N) (command.script[offset + (N)]) +Common::String AdlEngine::getLine() const { + // Original engine uses a global here, which isn't reset between + // calls and may not match actual mode + bool textMode = false; -void AdlEngine::doActions(const Command &command, byte noun, byte offset) { - for (uint i = 0; i < command.numAct; ++i) { - switch (ARG(0)) { - case IDO_ACT_VAR_ADD: - var(ARG(2)) += ARG(1); - offset += 3; - break; - case IDO_ACT_VAR_SUB: - var(ARG(2)) -= ARG(1); - offset += 3; - break; - case IDO_ACT_VAR_SET: - var(ARG(1)) = ARG(2); - offset += 3; - break; - case IDO_ACT_LIST_ITEMS: { - Common::Array::const_iterator item; + while (1) { + Common::String line = inputString(APPLECHAR('?')); - for (item = _state.items.begin(); item != _state.items.end(); ++item) - if (item->room == IDI_NONE) - printMessage(item->description); + if (shouldQuit() || _isRestoring) + return ""; - ++offset; - break; + if ((byte)line[0] == ('\r' | 0x80)) { + textMode = !textMode; + _display->setMode(textMode ? DISPLAY_MODE_TEXT : DISPLAY_MODE_MIXED); + continue; } - case IDO_ACT_MOVE_ITEM: - item(ARG(1)).room = ARG(2); - offset += 3; - break; - case IDO_ACT_SET_ROOM: - curRoom().curPicture = curRoom().picture; - _state.room = ARG(1); - offset += 2; - break; - case IDO_ACT_SET_CUR_PIC: - curRoom().curPicture = ARG(1); - offset += 2; - break; - case IDO_ACT_SET_PIC: - curRoom().picture = curRoom().curPicture = ARG(1); - offset += 2; - break; - case IDO_ACT_PRINT_MSG: - printMessage(ARG(1)); - offset += 2; - break; - case IDO_ACT_SET_LIGHT: - _state.isDark = false; - ++offset; - break; - case IDO_ACT_SET_DARK: - _state.isDark = true; - ++offset; - break; - case IDO_ACT_SAVE: - saveGameState(0, ""); - ++offset; - break; - case IDO_ACT_LOAD: - loadGameState(0); - ++offset; - // Original engine does not jump out of the loop, - // so we don't either. - // We reset the restore flag, as the restore game - // process is complete - _isRestoring = false; - break; - case IDO_ACT_RESTART: { - _display->printString(_strings.playAgain); - - // We allow restoring via GMM here - _canRestoreNow = true; - Common::String input = inputString(); - _canRestoreNow = false; - - // If the user restored with the GMM, we break off the restart - if (_isRestoring) - return; - - if (input.size() == 0 || input[0] != APPLECHAR('N')) { - _isRestarting = true; - _display->clear(0x00); - _display->updateHiResScreen(); - restartGame(); - return; - } - // Fall-through - } - case IDO_ACT_QUIT: - printMessage(_messageIds.thanksForPlaying); - quitGame(); - return; - case IDO_ACT_PLACE_ITEM: - item(ARG(1)).room = ARG(2); - item(ARG(1)).position.x = ARG(3); - item(ARG(1)).position.y = ARG(4); - offset += 5; - break; - case IDO_ACT_SET_ITEM_PIC: - item(ARG(2)).picture = ARG(1); - offset += 3; - break; - case IDO_ACT_RESET_PIC: - curRoom().curPicture = curRoom().picture; - ++offset; - break; - case IDO_ACT_GO_NORTH: - case IDO_ACT_GO_SOUTH: - case IDO_ACT_GO_EAST: - case IDO_ACT_GO_WEST: - case IDO_ACT_GO_UP: - case IDO_ACT_GO_DOWN: { - byte room = curRoom().connections[ARG(0) - IDO_ACT_GO_NORTH]; - - if (room == 0) { - printMessage(_messageIds.cantGoThere); - return; - } - curRoom().curPicture = curRoom().picture; - _state.room = room; - return; - } - case IDO_ACT_TAKE_ITEM: - takeItem(noun); - ++offset; - break; - case IDO_ACT_DROP_ITEM: - dropItem(noun); - ++offset; - break; - case IDO_ACT_SET_ROOM_PIC: - room(ARG(1)).picture = room(ARG(1)).curPicture = ARG(2); - offset += 3; - break; - default: - error("Invalid action opcode %02x", ARG(0)); - } + // Remove the return + line.deleteLastChar(); + return line; } } -bool AdlEngine::matchCommand(const Command &command, byte verb, byte noun, uint *actions) const { - if (command.room != IDI_NONE && command.room != _state.room) - return false; +Common::String AdlEngine::getWord(const Common::String &line, uint &index) const { + Common::String str; - if (command.verb != IDI_NONE && command.verb != verb) - return false; + for (uint i = 0; i < 8; ++i) + str += APPLECHAR(' '); - if (command.noun != IDI_NONE && command.noun != noun) - return false; + int copied = 0; - uint offset = 0; - for (uint i = 0; i < command.numCond; ++i) { - switch (ARG(0)) { - case IDO_CND_ITEM_IN_ROOM: - if (item(ARG(1)).room != ARG(2)) - return false; - offset += 3; - break; - case IDO_CND_MOVES_GE: - if (ARG(1) > _state.moves) - return false; - offset += 2; - break; - case IDO_CND_VAR_EQ: - if (var(ARG(1)) != ARG(2)) - return false; - offset += 3; - break; - case IDO_CND_CUR_PIC_EQ: - if (curRoom().curPicture != ARG(1)) - return false; - offset += 2; - break; - case IDO_CND_ITEM_PIC_EQ: - if (item(ARG(1)).picture != ARG(2)) - return false; - offset += 3; + // Skip initial whitespace + while (1) { + if (index == line.size()) + return str; + if (line[index] != APPLECHAR(' ')) break; - default: - error("Invalid condition opcode %02x", command.script[offset]); - } + ++index; } - *actions = offset; + // Copy up to 8 characters + while (1) { + if (copied < 8) + str.setChar(line[index], copied++); - return true; + index++; + + if (index == line.size() || line[index] == APPLECHAR(' ')) + return str; + } } -#undef ARG +void AdlEngine::getInput(uint &verb, uint &noun) { + while (1) { + _display->printString(_strings.enterCommand); + Common::String line = getLine(); -bool AdlEngine::doOneCommand(const Commands &commands, byte verb, byte noun) { - Commands::const_iterator cmd; + if (shouldQuit() || _isRestoring) + return; - for (cmd = commands.begin(); cmd != commands.end(); ++cmd) { - uint offset = 0; - if (matchCommand(*cmd, verb, noun, &offset)) { - doActions(*cmd, noun, offset); - return true; + uint index = 0; + Common::String verbStr = getWord(line, index); + + if (!_verbs.contains(verbStr)) { + Common::String err = _strings.verbError; + for (uint i = 0; i < verbStr.size(); ++i) + err.setChar(verbStr[i], i + 19); + _display->printString(err); + continue; } - } - return false; -} + verb = _verbs[verbStr]; -void AdlEngine::doAllCommands(const Commands &commands, byte verb, byte noun) { - Commands::const_iterator cmd; - bool oldIsRestoring = _isRestoring; + Common::String nounStr = getWord(line, index); - for (cmd = commands.begin(); cmd != commands.end(); ++cmd) { - uint offset = 0; - if (matchCommand(*cmd, verb, noun, &offset)) - doActions(*cmd, noun, offset); + if (!_nouns.contains(nounStr)) { + Common::String err = _strings.nounError; + for (uint i = 0; i < verbStr.size(); ++i) + err.setChar(verbStr[i], i + 19); + for (uint i = 0; i < nounStr.size(); ++i) + err.setChar(nounStr[i], i + 30); + _display->printString(err); + continue; + } - // We assume no restarts happen in this command group. This - // simplifies enabling GMM savegame loading on the restart - // prompt. - if (_isRestarting || _isRestoring != oldIsRestoring) - error("Unexpected restart action encountered"); + noun = _nouns[nounStr]; + return; } } -bool AdlEngine::canSaveGameStateCurrently() const { - if (!_canSaveNow) - return false; - - Commands::const_iterator cmd; - - // Here we check whether or not the game currently accepts the command - // "SAVE GAME". This prevents saving via the GMM in situations where - // it wouldn't otherwise be possible to do so. - for (cmd = _roomCommands.begin(); cmd != _roomCommands.end(); ++cmd) { - if (matchCommand(*cmd, _saveVerb, _saveNoun)) { - if (cmd->verb != _saveVerb || cmd->noun != _saveNoun) - return false; - return cmd->numCond == 0 && cmd->script[0] == IDO_ACT_SAVE; - } +void AdlEngine::showRoom() const { + if (!_state.isDark) { + drawPic(curRoom().curPicture); + drawItems(); } - return false; -} - -bool AdlEngine::canLoadGameStateCurrently() const { - return _canRestoreNow; + _display->updateHiResScreen(); + printMessage(curRoom().description, false); } void AdlEngine::clearScreen() const { @@ -554,163 +683,49 @@ void AdlEngine::drawItems() const { } } -void AdlEngine::showRoom() const { - if (!_state.isDark) { - drawPic(curRoom().curPicture); - drawItems(); - } - - _display->updateHiResScreen(); - printMessage(curRoom().description, false); -} - -Common::Error AdlEngine::saveGameState(int slot, const Common::String &desc) { - Common::String fileName = Common::String::format("%s.s%02d", _targetName.c_str(), slot); - Common::OutSaveFile *outFile = getSaveFileManager()->openForSaving(fileName); - - if (!outFile) { - warning("Failed to open file '%s'", fileName.c_str()); - return Common::kUnknownError; - } - - outFile->writeUint32BE(MKTAG('A', 'D', 'L', ':')); - outFile->writeByte(SAVEGAME_VERSION); - - char name[SAVEGAME_NAME_LEN] = { }; - - if (!desc.empty()) - strncpy(name, desc.c_str(), sizeof(name) - 1); - else { - Common::String defaultName("Save "); - defaultName += 'A' + slot; - strncpy(name, defaultName.c_str(), sizeof(name) - 1); - } - - outFile->write(name, sizeof(name)); - - TimeDate t; - g_system->getTimeAndDate(t); - - outFile->writeUint16BE(t.tm_year); - outFile->writeByte(t.tm_mon); - outFile->writeByte(t.tm_mday); - outFile->writeByte(t.tm_hour); - outFile->writeByte(t.tm_min); - - uint32 playTime = getTotalPlayTime(); - outFile->writeUint32BE(playTime); - - _display->saveThumbnail(*outFile); - - outFile->writeByte(_state.room); - outFile->writeByte(_state.moves); - outFile->writeByte(_state.isDark); - - outFile->writeUint32BE(_state.rooms.size()); - for (uint i = 0; i < _state.rooms.size(); ++i) { - outFile->writeByte(_state.rooms[i].picture); - outFile->writeByte(_state.rooms[i].curPicture); - } - - outFile->writeUint32BE(_state.items.size()); - for (uint i = 0; i < _state.items.size(); ++i) { - outFile->writeByte(_state.items[i].room); - outFile->writeByte(_state.items[i].picture); - outFile->writeByte(_state.items[i].position.x); - outFile->writeByte(_state.items[i].position.y); - outFile->writeByte(_state.items[i].state); - } - - outFile->writeUint32BE(_state.vars.size()); - for (uint i = 0; i < _state.vars.size(); ++i) - outFile->writeByte(_state.vars[i]); - - outFile->finalize(); +void AdlEngine::drawNextPixel(Common::Point &p, byte color, byte bits, byte quadrant) const { + if (bits & 4) + _display->putPixel(p, color); - if (outFile->err()) { - delete outFile; - warning("Failed to save game '%s'", fileName.c_str()); - return Common::kUnknownError; - } + bits += quadrant; - delete outFile; - return Common::kNoError; + if (bits & 1) + p.x += (bits & 2 ? -1 : 1); + else + p.y += (bits & 2 ? 1 : -1); } -Common::Error AdlEngine::loadGameState(int slot) { - Common::String fileName = Common::String::format("%s.s%02d", _targetName.c_str(), slot); - Common::InSaveFile *inFile = getSaveFileManager()->openForLoading(fileName); - - if (!inFile) { - warning("Failed to open file '%s'", fileName.c_str()); - return Common::kUnknownError; - } - - if (inFile->readUint32BE() != MKTAG('A', 'D', 'L', ':')) { - warning("No header found in '%s'", fileName.c_str()); - delete inFile; - return Common::kUnknownError; - } - - byte saveVersion = inFile->readByte(); - if (saveVersion != SAVEGAME_VERSION) { - warning("Save game version %i not supported", saveVersion); - delete inFile; - return Common::kUnknownError; - } - - // Skip description - inFile->seek(SAVEGAME_NAME_LEN, SEEK_CUR); - // Skip save time - inFile->seek(6, SEEK_CUR); - - uint32 playTime = inFile->readUint32BE(); - - Graphics::skipThumbnail(*inFile); - - initState(); - - _state.room = inFile->readByte(); - _state.moves = inFile->readByte(); - _state.isDark = inFile->readByte(); +void AdlEngine::drawLineArt(const Common::Array &lineArt, const Common::Point &pos, byte rotation, byte scaling, byte color) const { + const byte stepping[] = { + 0xff, 0xfe, 0xfa, 0xf4, 0xec, 0xe1, 0xd4, 0xc5, + 0xb4, 0xa1, 0x8d, 0x78, 0x61, 0x49, 0x31, 0x18, + 0xff + }; - uint32 size = inFile->readUint32BE(); - if (size != _state.rooms.size()) - error("Room count mismatch (expected %i; found %i)", _state.rooms.size(), size); + byte quadrant = rotation >> 4; + rotation &= 0xf; + byte xStep = stepping[rotation]; + byte yStep = stepping[(rotation ^ 0xf) + 1] + 1; - for (uint i = 0; i < size; ++i) { - _state.rooms[i].picture = inFile->readByte(); - _state.rooms[i].curPicture = inFile->readByte(); - } + Common::Point p(pos); - size = inFile->readUint32BE(); - if (size != _state.items.size()) - error("Item count mismatch (expected %i; found %i)", _state.items.size(), size); + for (uint i = 0; i < lineArt.size(); ++i) { + byte b = lineArt[i]; - for (uint i = 0; i < size; ++i) { - _state.items[i].room = inFile->readByte(); - _state.items[i].picture = inFile->readByte(); - _state.items[i].position.x = inFile->readByte(); - _state.items[i].position.y = inFile->readByte(); - _state.items[i].state = inFile->readByte(); + do { + byte xFrac = 0x80; + byte yFrac = 0x80; + for (uint j = 0; j < scaling; ++j) { + if (xFrac + xStep + 1 > 255) + drawNextPixel(p, color, b, quadrant); + xFrac += xStep + 1; + if (yFrac + yStep > 255) + drawNextPixel(p, color, b, quadrant + 1); + yFrac += yStep; + } + b >>= 3; + } while (b != 0); } - - size = inFile->readUint32BE(); - if (size != _state.vars.size()) - error("Variable count mismatch (expected %i; found %i)", _state.vars.size(), size); - - for (uint i = 0; i < size; ++i) - _state.vars[i] = inFile->readByte(); - - if (inFile->err() || inFile->eos()) - error("Failed to load game '%s'", fileName.c_str()); - - delete inFile; - - setTotalPlayTime(playTime); - - _isRestoring = true; - return Common::kNoError; } const Room &AdlEngine::room(uint i) const { @@ -763,287 +778,272 @@ byte &AdlEngine::var(uint i) { return _state.vars[i]; } -void AdlEngine::loadWords(Common::ReadStream &stream, WordMap &map) const { - uint index = 0; - - while (1) { - ++index; - - byte buf[IDI_WORD_SIZE]; - - if (stream.read(buf, IDI_WORD_SIZE) < IDI_WORD_SIZE) - error("Error reading word list"); - - Common::String word((char *)buf, IDI_WORD_SIZE); - - if (!map.contains(word)) - map[word] = index; - - byte synonyms = stream.readByte(); - - if (stream.err() || stream.eos()) - error("Error reading word list"); +void AdlEngine::takeItem(byte noun) { + Common::Array::iterator item; - if (synonyms == 0xff) - break; + for (item = _state.items.begin(); item != _state.items.end(); ++item) { + if (item->noun != noun || item->room != _state.room) + continue; - for (uint i = 0; i < synonyms; ++i) { - if (stream.read((char *)buf, IDI_WORD_SIZE) < IDI_WORD_SIZE) - error("Error reading word list"); + if (item->state == IDI_ITEM_DOESNT_MOVE) { + printMessage(_messageIds.itemDoesntMove); + return; + } - word = Common::String((char *)buf, IDI_WORD_SIZE); + if (item->state == IDI_ITEM_MOVED) { + item->room = IDI_NONE; + return; + } - if (!map.contains(word)) - map[word] = index; + Common::Array::const_iterator pic; + for (pic = item->roomPictures.begin(); pic != item->roomPictures.end(); ++pic) { + if (*pic == curRoom().curPicture) { + item->room = IDI_NONE; + item->state = IDI_ITEM_MOVED; + return; + } } } -} -Common::String AdlEngine::getLine() const { - // Original engine uses a global here, which isn't reset between - // calls and may not match actual mode - bool textMode = false; - - while (1) { - Common::String line = inputString(APPLECHAR('?')); + printMessage(_messageIds.itemNotHere); +} - if (shouldQuit() || _isRestoring) - return ""; +void AdlEngine::dropItem(byte noun) { + Common::Array::iterator item; - if ((byte)line[0] == ('\r' | 0x80)) { - textMode = !textMode; - _display->setMode(textMode ? DISPLAY_MODE_TEXT : DISPLAY_MODE_MIXED); + for (item = _state.items.begin(); item != _state.items.end(); ++item) { + if (item->noun != noun || item->room != IDI_NONE) continue; - } - // Remove the return - line.deleteLastChar(); - return line; + item->room = _state.room; + item->state = IDI_ITEM_MOVED; + return; } + + printMessage(_messageIds.dontUnderstand); } -Common::String AdlEngine::getWord(const Common::String &line, uint &index) const { - Common::String str; +#define ARG(N) (command.script[offset + (N)]) - for (uint i = 0; i < 8; ++i) - str += APPLECHAR(' '); +bool AdlEngine::matchCommand(const Command &command, byte verb, byte noun, uint *actions) const { + if (command.room != IDI_NONE && command.room != _state.room) + return false; - int copied = 0; + if (command.verb != IDI_NONE && command.verb != verb) + return false; - // Skip initial whitespace - while (1) { - if (index == line.size()) - return str; - if (line[index] != APPLECHAR(' ')) + if (command.noun != IDI_NONE && command.noun != noun) + return false; + + uint offset = 0; + for (uint i = 0; i < command.numCond; ++i) { + switch (ARG(0)) { + case IDO_CND_ITEM_IN_ROOM: + if (item(ARG(1)).room != ARG(2)) + return false; + offset += 3; break; - ++index; + case IDO_CND_MOVES_GE: + if (ARG(1) > _state.moves) + return false; + offset += 2; + break; + case IDO_CND_VAR_EQ: + if (var(ARG(1)) != ARG(2)) + return false; + offset += 3; + break; + case IDO_CND_CUR_PIC_EQ: + if (curRoom().curPicture != ARG(1)) + return false; + offset += 2; + break; + case IDO_CND_ITEM_PIC_EQ: + if (item(ARG(1)).picture != ARG(2)) + return false; + offset += 3; + break; + default: + error("Invalid condition opcode %02x", command.script[offset]); + } } - // Copy up to 8 characters - while (1) { - if (copied < 8) - str.setChar(line[index], copied++); - - index++; + *actions = offset; - if (index == line.size() || line[index] == APPLECHAR(' ')) - return str; - } + return true; } -void AdlEngine::getInput(uint &verb, uint &noun) { - while (1) { - _display->printString(_strings.enterCommand); - Common::String line = getLine(); - - if (shouldQuit() || _isRestoring) - return; - - uint index = 0; - Common::String verbStr = getWord(line, index); - - if (!_verbs.contains(verbStr)) { - Common::String err = _strings.verbError; - for (uint i = 0; i < verbStr.size(); ++i) - err.setChar(verbStr[i], i + 19); - _display->printString(err); - continue; - } - - verb = _verbs[verbStr]; +void AdlEngine::doActions(const Command &command, byte noun, byte offset) { + for (uint i = 0; i < command.numAct; ++i) { + switch (ARG(0)) { + case IDO_ACT_VAR_ADD: + var(ARG(2)) += ARG(1); + offset += 3; + break; + case IDO_ACT_VAR_SUB: + var(ARG(2)) -= ARG(1); + offset += 3; + break; + case IDO_ACT_VAR_SET: + var(ARG(1)) = ARG(2); + offset += 3; + break; + case IDO_ACT_LIST_ITEMS: { + Common::Array::const_iterator item; - Common::String nounStr = getWord(line, index); + for (item = _state.items.begin(); item != _state.items.end(); ++item) + if (item->room == IDI_NONE) + printMessage(item->description); - if (!_nouns.contains(nounStr)) { - Common::String err = _strings.nounError; - for (uint i = 0; i < verbStr.size(); ++i) - err.setChar(verbStr[i], i + 19); - for (uint i = 0; i < nounStr.size(); ++i) - err.setChar(nounStr[i], i + 30); - _display->printString(err); - continue; + ++offset; + break; } + case IDO_ACT_MOVE_ITEM: + item(ARG(1)).room = ARG(2); + offset += 3; + break; + case IDO_ACT_SET_ROOM: + curRoom().curPicture = curRoom().picture; + _state.room = ARG(1); + offset += 2; + break; + case IDO_ACT_SET_CUR_PIC: + curRoom().curPicture = ARG(1); + offset += 2; + break; + case IDO_ACT_SET_PIC: + curRoom().picture = curRoom().curPicture = ARG(1); + offset += 2; + break; + case IDO_ACT_PRINT_MSG: + printMessage(ARG(1)); + offset += 2; + break; + case IDO_ACT_SET_LIGHT: + _state.isDark = false; + ++offset; + break; + case IDO_ACT_SET_DARK: + _state.isDark = true; + ++offset; + break; + case IDO_ACT_SAVE: + saveGameState(0, ""); + ++offset; + break; + case IDO_ACT_LOAD: + loadGameState(0); + ++offset; + // Original engine does not jump out of the loop, + // so we don't either. + // We reset the restore flag, as the restore game + // process is complete + _isRestoring = false; + break; + case IDO_ACT_RESTART: { + _display->printString(_strings.playAgain); - noun = _nouns[nounStr]; - return; - } -} - -Common::String AdlEngine::inputString(byte prompt) const { - Common::String s; - - if (prompt > 0) - _display->printString(Common::String(prompt)); - - while (1) { - byte b = inputKey(); - - if (g_engine->shouldQuit() || _isRestoring) - return 0; - - if (b == 0) - continue; + // We allow restoring via GMM here + _canRestoreNow = true; + Common::String input = inputString(); + _canRestoreNow = false; - if (b == ('\r' | 0x80)) { - s += b; - _display->printString(Common::String(b)); - return s; - } + // If the user restored with the GMM, we break off the restart + if (_isRestoring) + return; - if (b < 0xa0) { - switch (b) { - case Common::KEYCODE_BACKSPACE | 0x80: - if (!s.empty()) { - _display->moveCursorBackward(); - _display->setCharAtCursor(APPLECHAR(' ')); - s.deleteLastChar(); - } - break; - }; - } else { - s += b; - _display->printString(Common::String(b)); + if (input.size() == 0 || input[0] != APPLECHAR('N')) { + _isRestarting = true; + _display->clear(0x00); + _display->updateHiResScreen(); + restartGame(); + return; + } + // Fall-through } - } -} - -byte AdlEngine::convertKey(uint16 ascii) const { - ascii = toupper(ascii); - - if (ascii >= 0x80) - return 0; - - ascii |= 0x80; - - if (ascii >= 0x80 && ascii <= 0xe0) - return ascii; - - return 0; -} - -byte AdlEngine::inputKey() const { - Common::EventManager *ev = g_system->getEventManager(); - - byte key = 0; - - _display->showCursor(true); - - while (!g_engine->shouldQuit() && !_isRestoring && key == 0) { - Common::Event event; - if (ev->pollEvent(event)) { - if (event.type != Common::EVENT_KEYDOWN) - continue; + case IDO_ACT_QUIT: + printMessage(_messageIds.thanksForPlaying); + quitGame(); + return; + case IDO_ACT_PLACE_ITEM: + item(ARG(1)).room = ARG(2); + item(ARG(1)).position.x = ARG(3); + item(ARG(1)).position.y = ARG(4); + offset += 5; + break; + case IDO_ACT_SET_ITEM_PIC: + item(ARG(2)).picture = ARG(1); + offset += 3; + break; + case IDO_ACT_RESET_PIC: + curRoom().curPicture = curRoom().picture; + ++offset; + break; + case IDO_ACT_GO_NORTH: + case IDO_ACT_GO_SOUTH: + case IDO_ACT_GO_EAST: + case IDO_ACT_GO_WEST: + case IDO_ACT_GO_UP: + case IDO_ACT_GO_DOWN: { + byte room = curRoom().connections[ARG(0) - IDO_ACT_GO_NORTH]; - if (event.kbd.flags & Common::KBD_CTRL) { - if (event.kbd.keycode == Common::KEYCODE_q) - g_engine->quitGame(); - continue; + if (room == 0) { + printMessage(_messageIds.cantGoThere); + return; } - switch (event.kbd.keycode) { - case Common::KEYCODE_BACKSPACE: - case Common::KEYCODE_RETURN: - key = convertKey(event.kbd.keycode); - break; - default: - if (event.kbd.ascii >= 0x20 && event.kbd.ascii < 0x80) - key = convertKey(event.kbd.ascii); - }; + curRoom().curPicture = curRoom().picture; + _state.room = room; + return; + } + case IDO_ACT_TAKE_ITEM: + takeItem(noun); + ++offset; + break; + case IDO_ACT_DROP_ITEM: + dropItem(noun); + ++offset; + break; + case IDO_ACT_SET_ROOM_PIC: + room(ARG(1)).picture = room(ARG(1)).curPicture = ARG(2); + offset += 3; + break; + default: + error("Invalid action opcode %02x", ARG(0)); } - - _display->updateTextScreen(); - g_system->delayMillis(16); } - - _display->showCursor(false); - - return key; } -void AdlEngine::delay(uint32 ms) const { - Common::EventManager *ev = g_system->getEventManager(); +#undef ARG - uint32 start = g_system->getMillis(); +bool AdlEngine::doOneCommand(const Commands &commands, byte verb, byte noun) { + Commands::const_iterator cmd; - while (!g_engine->shouldQuit() && g_system->getMillis() - start < ms) { - Common::Event event; - if (ev->pollEvent(event)) { - if (event.type == Common::EVENT_KEYDOWN && (event.kbd.flags & Common::KBD_CTRL)) { - switch(event.kbd.keycode) { - case Common::KEYCODE_q: - g_engine->quitGame(); - break; - default: - break; - } - } + for (cmd = commands.begin(); cmd != commands.end(); ++cmd) { + uint offset = 0; + if (matchCommand(*cmd, verb, noun, &offset)) { + doActions(*cmd, noun, offset); + return true; } - g_system->delayMillis(16); } -} -void AdlEngine::drawNextPixel(Common::Point &p, byte color, byte bits, byte quadrant) const { - if (bits & 4) - _display->putPixel(p, color); - - bits += quadrant; - - if (bits & 1) - p.x += (bits & 2 ? -1 : 1); - else - p.y += (bits & 2 ? 1 : -1); + return false; } -void AdlEngine::drawLineArt(const Common::Array &lineArt, const Common::Point &pos, byte rotation, byte scaling, byte color) const { - const byte stepping[] = { - 0xff, 0xfe, 0xfa, 0xf4, 0xec, 0xe1, 0xd4, 0xc5, - 0xb4, 0xa1, 0x8d, 0x78, 0x61, 0x49, 0x31, 0x18, - 0xff - }; - - byte quadrant = rotation >> 4; - rotation &= 0xf; - byte xStep = stepping[rotation]; - byte yStep = stepping[(rotation ^ 0xf) + 1] + 1; - - Common::Point p(pos); +void AdlEngine::doAllCommands(const Commands &commands, byte verb, byte noun) { + Commands::const_iterator cmd; + bool oldIsRestoring = _isRestoring; - for (uint i = 0; i < lineArt.size(); ++i) { - byte b = lineArt[i]; + for (cmd = commands.begin(); cmd != commands.end(); ++cmd) { + uint offset = 0; + if (matchCommand(*cmd, verb, noun, &offset)) + doActions(*cmd, noun, offset); - do { - byte xFrac = 0x80; - byte yFrac = 0x80; - for (uint j = 0; j < scaling; ++j) { - if (xFrac + xStep + 1 > 255) - drawNextPixel(p, color, b, quadrant); - xFrac += xStep + 1; - if (yFrac + yStep > 255) - drawNextPixel(p, color, b, quadrant + 1); - yFrac += yStep; - } - b >>= 3; - } while (b != 0); + // We assume no restarts happen in this command group. This + // simplifies enabling GMM savegame loading on the restart + // prompt. + if (_isRestarting || _isRestoring != oldIsRestoring) + error("Unexpected restart action encountered"); } } diff --git a/engines/adl/adl.h b/engines/adl/adl.h index b1d5b7c0b3..a230f0f03b 100644 --- a/engines/adl/adl.h +++ b/engines/adl/adl.h @@ -23,8 +23,9 @@ #ifndef ADL_ADL_H #define ADL_ADL_H -#include "common/random.h" +#include "common/array.h" #include "common/rect.h" +#include "common/str.h" #include "engines/engine.h" @@ -34,16 +35,10 @@ class SeekableReadStream; } namespace Adl { + class Display; -class Parser; -class Console; struct AdlGameDescription; -struct StringOffset { - int stringIdx; - uint offset; -}; - // Conditional opcodes #define IDO_CND_ITEM_IN_ROOM 0x03 #define IDO_CND_MOVES_GE 0x05 @@ -155,7 +150,6 @@ protected: void readCommands(Common::ReadStream &stream, Commands &commands); Display *_display; - Parser *_parser; // Message strings in data file Common::Array _messages; @@ -236,9 +230,9 @@ private: void takeItem(byte noun); void dropItem(byte noun); bool matchCommand(const Command &command, byte verb, byte noun, uint *actions = nullptr) const; + void doActions(const Command &command, byte noun, byte offset); bool doOneCommand(const Commands &commands, byte verb, byte noun); void doAllCommands(const Commands &commands, byte verb, byte noun); - void doActions(const Command &command, byte noun, byte offset); const AdlGameDescription *_gameDescription; bool _isRestarting, _isRestoring; diff --git a/engines/adl/hires1.cpp b/engines/adl/hires1.cpp index 95f02899a2..6e1e31df9f 100644 --- a/engines/adl/hires1.cpp +++ b/engines/adl/hires1.cpp @@ -136,113 +136,6 @@ void HiRes1Engine::runIntro() const { delay(2000); } -void HiRes1Engine::drawPic(Common::ReadStream &stream, const Common::Point &pos) const { - byte x, y; - bool bNewLine = false; - byte oldX = 0, oldY = 0; - while (1) { - x = stream.readByte(); - y = stream.readByte(); - - if (stream.err() || stream.eos()) - error("Failed to read picture"); - - if (x == 0xff && y == 0xff) - return; - - if (x == 0 && y == 0) { - bNewLine = true; - continue; - } - - x += pos.x; - y += pos.y; - - if (y > 160) - y = 160; - - if (bNewLine) { - _display->putPixel(Common::Point(x, y), 0x7f); - bNewLine = false; - } else { - drawLine(Common::Point(oldX, oldY), Common::Point(x, y), 0x7f); - } - - oldX = x; - oldY = y; - } -} - -void HiRes1Engine::drawPic(byte pic, Common::Point pos) const { - Common::File f; - Common::String name = Common::String::format("BLOCK%i", _pictures[pic].block); - - if (!f.open(name)) - error("Failed to open file '%s'", name.c_str()); - - f.seek(_pictures[pic].offset); - drawPic(f, pos); -} - -void HiRes1Engine::initState() { - Common::File f; - - _state.room = 1; - _state.moves = 0; - _state.isDark = false; - - _state.vars.clear(); - _state.vars.resize(IDI_HR1_NUM_VARS); - - if (!f.open(IDS_HR1_EXE_1)) - error("Failed to open file '" IDS_HR1_EXE_1 "'"); - - // Load room data from executable - _state.rooms.clear(); - f.seek(IDI_HR1_OFS_ROOMS); - for (uint i = 0; i < IDI_HR1_NUM_ROOMS; ++i) { - Room room; - f.readByte(); - room.description = f.readByte(); - for (uint j = 0; j < 6; ++j) - room.connections[j] = f.readByte(); - room.picture = f.readByte(); - room.curPicture = f.readByte(); - _state.rooms.push_back(room); - } - - // Load item data from executable - _state.items.clear(); - f.seek(IDI_HR1_OFS_ITEMS); - while (f.readByte() != 0xff) { - Item item; - item.noun = f.readByte(); - item.room = f.readByte(); - item.picture = f.readByte(); - item.isLineArt = f.readByte(); - item.position.x = f.readByte(); - item.position.y = f.readByte(); - item.state = f.readByte(); - item.description = f.readByte(); - - f.readByte(); - - byte size = f.readByte(); - - for (uint i = 0; i < size; ++i) - item.roomPictures.push_back(f.readByte()); - - _state.items.push_back(item); - } -} - -void HiRes1Engine::restartGame() { - initState(); - _display->printString(_gameStrings.pressReturn); - inputString(); // Missing in the original - _display->printAsciiString("\r\r\r\r\r"); -} - void HiRes1Engine::loadData() { Common::File f; @@ -331,6 +224,76 @@ void HiRes1Engine::loadData() { loadWords(f, _nouns); } +void HiRes1Engine::initState() { + Common::File f; + + _state.room = 1; + _state.moves = 0; + _state.isDark = false; + + _state.vars.clear(); + _state.vars.resize(IDI_HR1_NUM_VARS); + + if (!f.open(IDS_HR1_EXE_1)) + error("Failed to open file '" IDS_HR1_EXE_1 "'"); + + // Load room data from executable + _state.rooms.clear(); + f.seek(IDI_HR1_OFS_ROOMS); + for (uint i = 0; i < IDI_HR1_NUM_ROOMS; ++i) { + Room room; + f.readByte(); + room.description = f.readByte(); + for (uint j = 0; j < 6; ++j) + room.connections[j] = f.readByte(); + room.picture = f.readByte(); + room.curPicture = f.readByte(); + _state.rooms.push_back(room); + } + + // Load item data from executable + _state.items.clear(); + f.seek(IDI_HR1_OFS_ITEMS); + while (f.readByte() != 0xff) { + Item item; + item.noun = f.readByte(); + item.room = f.readByte(); + item.picture = f.readByte(); + item.isLineArt = f.readByte(); + item.position.x = f.readByte(); + item.position.y = f.readByte(); + item.state = f.readByte(); + item.description = f.readByte(); + + f.readByte(); + + byte size = f.readByte(); + + for (uint i = 0; i < size; ++i) + item.roomPictures.push_back(f.readByte()); + + _state.items.push_back(item); + } +} + +void HiRes1Engine::restartGame() { + initState(); + _display->printString(_gameStrings.pressReturn); + inputString(); // Missing in the original + _display->printAsciiString("\r\r\r\r\r"); +} + +void HiRes1Engine::drawPic(byte pic, Common::Point pos) const { + Common::File f; + Common::String name = Common::String::format("BLOCK%i", _pictures[pic].block); + + if (!f.open(name)) + error("Failed to open file '%s'", name.c_str()); + + f.seek(_pictures[pic].offset); + drawPic(f, pos); +} + void HiRes1Engine::printMessage(uint idx, bool wait) const { // Messages with hardcoded overrides don't delay after printing. // It's unclear if this is a bug or not. In some cases the result @@ -389,6 +352,43 @@ void HiRes1Engine::drawLine(const Common::Point &p1, const Common::Point &p2, by } } +void HiRes1Engine::drawPic(Common::ReadStream &stream, const Common::Point &pos) const { + byte x, y; + bool bNewLine = false; + byte oldX = 0, oldY = 0; + while (1) { + x = stream.readByte(); + y = stream.readByte(); + + if (stream.err() || stream.eos()) + error("Failed to read picture"); + + if (x == 0xff && y == 0xff) + return; + + if (x == 0 && y == 0) { + bNewLine = true; + continue; + } + + x += pos.x; + y += pos.y; + + if (y > 160) + y = 160; + + if (bNewLine) { + _display->putPixel(Common::Point(x, y), 0x7f); + bNewLine = false; + } else { + drawLine(Common::Point(oldX, oldY), Common::Point(x, y), 0x7f); + } + + oldX = x; + oldY = y; + } +} + Engine *HiRes1Engine_create(OSystem *syst, const AdlGameDescription *gd) { return new HiRes1Engine(syst, gd); } diff --git a/engines/adl/hires1.h b/engines/adl/hires1.h index b7c7f41e12..d9d67c46e4 100644 --- a/engines/adl/hires1.h +++ b/engines/adl/hires1.h @@ -23,6 +23,8 @@ #ifndef ADL_HIRES1_H #define ADL_HIRES1_H +#include "common/str.h" + #include "adl/adl.h" namespace Common { -- cgit v1.2.3 From 57af92e0c11d578ba5361d07d569f0d480a9a29f Mon Sep 17 00:00:00 2001 From: Walter van Niftrik Date: Tue, 8 Mar 2016 00:18:19 +0100 Subject: ADL: Fix shadowing warning (GCC 4.8) --- engines/adl/adl.cpp | 70 ++++++++++++++++++++++++++--------------------------- engines/adl/adl.h | 16 ++++++------ 2 files changed, 43 insertions(+), 43 deletions(-) (limited to 'engines') diff --git a/engines/adl/adl.cpp b/engines/adl/adl.cpp index dd4f4068d1..92b74d20e9 100644 --- a/engines/adl/adl.cpp +++ b/engines/adl/adl.cpp @@ -635,12 +635,12 @@ void AdlEngine::getInput(uint &verb, uint &noun) { void AdlEngine::showRoom() const { if (!_state.isDark) { - drawPic(curRoom().curPicture); + drawPic(getCurRoom().curPicture); drawItems(); } _display->updateHiResScreen(); - printMessage(curRoom().description, false); + printMessage(getCurRoom().description, false); } void AdlEngine::clearScreen() const { @@ -658,7 +658,7 @@ void AdlEngine::drawItems() const { continue; if (item->state == IDI_ITEM_MOVED) { - if (curRoom().picture == curRoom().curPicture) { + if (getCurRoom().picture == getCurRoom().curPicture) { const Common::Point &p = _itemOffsets[dropped]; if (item->isLineArt) drawLineArt(_lineArt[item->picture - 1], p); @@ -672,7 +672,7 @@ void AdlEngine::drawItems() const { Common::Array::const_iterator pic; for (pic = item->roomPictures.begin(); pic != item->roomPictures.end(); ++pic) { - if (*pic == curRoom().curPicture) { + if (*pic == getCurRoom().curPicture) { if (item->isLineArt) drawLineArt(_lineArt[item->picture - 1], item->position); else @@ -728,54 +728,54 @@ void AdlEngine::drawLineArt(const Common::Array &lineArt, const Common::Po } } -const Room &AdlEngine::room(uint i) const { +const Room &AdlEngine::getRoom(uint i) const { if (i < 1 || i > _state.rooms.size()) error("Room %i out of range [1, %i]", i, _state.rooms.size()); return _state.rooms[i - 1]; } -Room &AdlEngine::room(uint i) { +Room &AdlEngine::getRoom(uint i) { if (i < 1 || i > _state.rooms.size()) error("Room %i out of range [1, %i]", i, _state.rooms.size()); return _state.rooms[i - 1]; } -const Room &AdlEngine::curRoom() const { - return room(_state.room); +const Room &AdlEngine::getCurRoom() const { + return getRoom(_state.room); } -Room &AdlEngine::curRoom() { - return room(_state.room); +Room &AdlEngine::getCurRoom() { + return getRoom(_state.room); } -const Item &AdlEngine::item(uint i) const { +const Item &AdlEngine::getItem(uint i) const { if (i < 1 || i > _state.items.size()) error("Item %i out of range [1, %i]", i, _state.items.size()); return _state.items[i - 1]; } -Item &AdlEngine::item(uint i) { +Item &AdlEngine::getItem(uint i) { if (i < 1 || i > _state.items.size()) error("Item %i out of range [1, %i]", i, _state.items.size()); return _state.items[i - 1]; } -const byte &AdlEngine::var(uint i) const { +byte AdlEngine::getVar(uint i) const { if (i >= _state.vars.size()) error("Variable %i out of range [0, %i]", i, _state.vars.size() - 1); return _state.vars[i]; } -byte &AdlEngine::var(uint i) { +void AdlEngine::setVar(uint i, byte value) { if (i >= _state.vars.size()) error("Variable %i out of range [0, %i]", i, _state.vars.size() - 1); - return _state.vars[i]; + _state.vars[i] = value; } void AdlEngine::takeItem(byte noun) { @@ -797,7 +797,7 @@ void AdlEngine::takeItem(byte noun) { Common::Array::const_iterator pic; for (pic = item->roomPictures.begin(); pic != item->roomPictures.end(); ++pic) { - if (*pic == curRoom().curPicture) { + if (*pic == getCurRoom().curPicture) { item->room = IDI_NONE; item->state = IDI_ITEM_MOVED; return; @@ -839,7 +839,7 @@ bool AdlEngine::matchCommand(const Command &command, byte verb, byte noun, uint for (uint i = 0; i < command.numCond; ++i) { switch (ARG(0)) { case IDO_CND_ITEM_IN_ROOM: - if (item(ARG(1)).room != ARG(2)) + if (getItem(ARG(1)).room != ARG(2)) return false; offset += 3; break; @@ -849,17 +849,17 @@ bool AdlEngine::matchCommand(const Command &command, byte verb, byte noun, uint offset += 2; break; case IDO_CND_VAR_EQ: - if (var(ARG(1)) != ARG(2)) + if (getVar(ARG(1)) != ARG(2)) return false; offset += 3; break; case IDO_CND_CUR_PIC_EQ: - if (curRoom().curPicture != ARG(1)) + if (getCurRoom().curPicture != ARG(1)) return false; offset += 2; break; case IDO_CND_ITEM_PIC_EQ: - if (item(ARG(1)).picture != ARG(2)) + if (getItem(ARG(1)).picture != ARG(2)) return false; offset += 3; break; @@ -877,15 +877,15 @@ void AdlEngine::doActions(const Command &command, byte noun, byte offset) { for (uint i = 0; i < command.numAct; ++i) { switch (ARG(0)) { case IDO_ACT_VAR_ADD: - var(ARG(2)) += ARG(1); + setVar(ARG(2), getVar(ARG(2) + ARG(1))); offset += 3; break; case IDO_ACT_VAR_SUB: - var(ARG(2)) -= ARG(1); + setVar(ARG(2), getVar(ARG(2)) - ARG(1)); offset += 3; break; case IDO_ACT_VAR_SET: - var(ARG(1)) = ARG(2); + setVar(ARG(1), ARG(2)); offset += 3; break; case IDO_ACT_LIST_ITEMS: { @@ -899,20 +899,20 @@ void AdlEngine::doActions(const Command &command, byte noun, byte offset) { break; } case IDO_ACT_MOVE_ITEM: - item(ARG(1)).room = ARG(2); + getItem(ARG(1)).room = ARG(2); offset += 3; break; case IDO_ACT_SET_ROOM: - curRoom().curPicture = curRoom().picture; + getCurRoom().curPicture = getCurRoom().picture; _state.room = ARG(1); offset += 2; break; case IDO_ACT_SET_CUR_PIC: - curRoom().curPicture = ARG(1); + getCurRoom().curPicture = ARG(1); offset += 2; break; case IDO_ACT_SET_PIC: - curRoom().picture = curRoom().curPicture = ARG(1); + getCurRoom().picture = getCurRoom().curPicture = ARG(1); offset += 2; break; case IDO_ACT_PRINT_MSG: @@ -966,17 +966,17 @@ void AdlEngine::doActions(const Command &command, byte noun, byte offset) { quitGame(); return; case IDO_ACT_PLACE_ITEM: - item(ARG(1)).room = ARG(2); - item(ARG(1)).position.x = ARG(3); - item(ARG(1)).position.y = ARG(4); + getItem(ARG(1)).room = ARG(2); + getItem(ARG(1)).position.x = ARG(3); + getItem(ARG(1)).position.y = ARG(4); offset += 5; break; case IDO_ACT_SET_ITEM_PIC: - item(ARG(2)).picture = ARG(1); + getItem(ARG(2)).picture = ARG(1); offset += 3; break; case IDO_ACT_RESET_PIC: - curRoom().curPicture = curRoom().picture; + getCurRoom().curPicture = getCurRoom().picture; ++offset; break; case IDO_ACT_GO_NORTH: @@ -985,14 +985,14 @@ void AdlEngine::doActions(const Command &command, byte noun, byte offset) { case IDO_ACT_GO_WEST: case IDO_ACT_GO_UP: case IDO_ACT_GO_DOWN: { - byte room = curRoom().connections[ARG(0) - IDO_ACT_GO_NORTH]; + byte room = getCurRoom().connections[ARG(0) - IDO_ACT_GO_NORTH]; if (room == 0) { printMessage(_messageIds.cantGoThere); return; } - curRoom().curPicture = curRoom().picture; + getCurRoom().curPicture = getCurRoom().picture; _state.room = room; return; } @@ -1005,7 +1005,7 @@ void AdlEngine::doActions(const Command &command, byte noun, byte offset) { ++offset; break; case IDO_ACT_SET_ROOM_PIC: - room(ARG(1)).picture = room(ARG(1)).curPicture = ARG(2); + getRoom(ARG(1)).picture = getRoom(ARG(1)).curPicture = ARG(2); offset += 3; break; default: diff --git a/engines/adl/adl.h b/engines/adl/adl.h index a230f0f03b..8064375843 100644 --- a/engines/adl/adl.h +++ b/engines/adl/adl.h @@ -219,14 +219,14 @@ private: void drawLineArt(const Common::Array &lineArt, const Common::Point &pos, byte rotation = 0, byte scaling = 1, byte color = 0x7f) const; // Game state functions - const Room &room(uint i) const; - Room &room(uint i); - const Room &curRoom() const; - Room &curRoom(); - const Item &item(uint i) const; - Item &item(uint i); - const byte &var(uint i) const; - byte &var(uint i); + const Room &getRoom(uint i) const; + Room &getRoom(uint i); + const Room &getCurRoom() const; + Room &getCurRoom(); + const Item &getItem(uint i) const; + Item &getItem(uint i); + byte getVar(uint i) const; + void setVar(uint i, byte value); void takeItem(byte noun); void dropItem(byte noun); bool matchCommand(const Command &command, byte verb, byte noun, uint *actions = nullptr) const; -- cgit v1.2.3 From d01da596ef596883847d6c3da2b714367e314a06 Mon Sep 17 00:00:00 2001 From: Walter van Niftrik Date: Tue, 8 Mar 2016 11:16:16 +0100 Subject: ADL: Add note about font --- engines/adl/display.cpp | 1 + 1 file changed, 1 insertion(+) (limited to 'engines') diff --git a/engines/adl/display.cpp b/engines/adl/display.cpp index d48296e9ee..6342504bc3 100644 --- a/engines/adl/display.cpp +++ b/engines/adl/display.cpp @@ -70,6 +70,7 @@ static const byte monoPalette[MONO_PALETTE_ENTRIES * 3] = { 0x00, 0xc0, 0x01 }; +// Uppercase-only Apple II font (manually created). static const byte font[64][5] = { { 0x7c, 0x82, 0xba, 0xb2, 0x9c }, { 0xf8, 0x24, 0x22, 0x24, 0xf8 }, // @A { 0xfe, 0x92, 0x92, 0x92, 0x6c }, { 0x7c, 0x82, 0x82, 0x82, 0x44 }, // BC -- cgit v1.2.3 From ac39224958f6433a98da53606ce57ec8b3f123ee Mon Sep 17 00:00:00 2001 From: Walter van Niftrik Date: Tue, 8 Mar 2016 11:04:08 +0100 Subject: ADL: Limit keyboard input to 256 characters --- engines/adl/adl.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'engines') diff --git a/engines/adl/adl.cpp b/engines/adl/adl.cpp index 92b74d20e9..e9401cbc4d 100644 --- a/engines/adl/adl.cpp +++ b/engines/adl/adl.cpp @@ -145,8 +145,10 @@ Common::String AdlEngine::inputString(byte prompt) const { break; }; } else { - s += b; - _display->printString(Common::String(b)); + if (s.size() < 255) { + s += b; + _display->printString(Common::String(b)); + } } } } -- cgit v1.2.3 From 9d65f901d08955a78841581a4c05b1139b3fb41a Mon Sep 17 00:00:00 2001 From: Walter van Niftrik Date: Tue, 8 Mar 2016 14:12:20 +0100 Subject: ADL: Clarify detection entry --- engines/adl/detection.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'engines') diff --git a/engines/adl/detection.cpp b/engines/adl/detection.cpp index d96d94c66f..1a8c5025e8 100644 --- a/engines/adl/detection.cpp +++ b/engines/adl/detection.cpp @@ -65,7 +65,7 @@ static const PlainGameDescriptor adlGames[] = { }; static const AdlGameDescription gameDescriptions[] = { - { // MD5 by waltervn + { // Hi-Res Adventure #1: Mystery House - Apple II - 1987 PD release { "hires1", 0, { -- cgit v1.2.3 From 349245d9b42dbe72f8aaa9c8a7a1fe09f60c9787 Mon Sep 17 00:00:00 2001 From: Walter van Niftrik Date: Tue, 8 Mar 2016 15:09:52 +0100 Subject: ADL: Fix regression in GMM saving/loading --- engines/adl/adl.cpp | 22 ++++++++++++---------- engines/adl/adl.h | 4 ++-- 2 files changed, 14 insertions(+), 12 deletions(-) (limited to 'engines') diff --git a/engines/adl/adl.cpp b/engines/adl/adl.cpp index e9401cbc4d..8e374fa8f6 100644 --- a/engines/adl/adl.cpp +++ b/engines/adl/adl.cpp @@ -302,8 +302,11 @@ Common::Error AdlEngine::run() { if (shouldQuit()) break; - if (!doOneCommand(_roomCommands, verb, noun)) - printMessage(_messageIds.dontUnderstand); + // If we just restored from the GMM, we skip this command + // set, as no command has been input by the user + if (!_isRestoring) + if (!doOneCommand(_roomCommands, verb, noun)) + printMessage(_messageIds.dontUnderstand); } if (_isRestoring) { @@ -419,7 +422,7 @@ Common::Error AdlEngine::loadGameState(int slot) { return Common::kNoError; } -bool AdlEngine::canLoadGameStateCurrently() const { +bool AdlEngine::canLoadGameStateCurrently() { return _canRestoreNow; } @@ -496,7 +499,7 @@ Common::Error AdlEngine::saveGameState(int slot, const Common::String &desc) { return Common::kNoError; } -bool AdlEngine::canSaveGameStateCurrently() const { +bool AdlEngine::canSaveGameStateCurrently() { if (!_canSaveNow) return false; @@ -506,11 +509,9 @@ bool AdlEngine::canSaveGameStateCurrently() const { // "SAVE GAME". This prevents saving via the GMM in situations where // it wouldn't otherwise be possible to do so. for (cmd = _roomCommands.begin(); cmd != _roomCommands.end(); ++cmd) { - if (matchCommand(*cmd, _saveVerb, _saveNoun)) { - if (cmd->verb != _saveVerb || cmd->noun != _saveNoun) - return false; - return cmd->numCond == 0 && cmd->script[0] == IDO_ACT_SAVE; - } + uint offset; + if (matchCommand(*cmd, _saveVerb, _saveNoun, &offset)) + return cmd->script[offset] == IDO_ACT_SAVE; } return false; @@ -870,7 +871,8 @@ bool AdlEngine::matchCommand(const Command &command, byte verb, byte noun, uint } } - *actions = offset; + if (actions) + *actions = offset; return true; } diff --git a/engines/adl/adl.h b/engines/adl/adl.h index 8064375843..4ea7566669 100644 --- a/engines/adl/adl.h +++ b/engines/adl/adl.h @@ -198,9 +198,9 @@ private: Common::Error run(); bool hasFeature(EngineFeature f) const; Common::Error loadGameState(int slot); - bool canLoadGameStateCurrently() const; + bool canLoadGameStateCurrently(); Common::Error saveGameState(int slot, const Common::String &desc); - bool canSaveGameStateCurrently() const; + bool canSaveGameStateCurrently(); // Text output void wordWrap(Common::String &str) const; -- cgit v1.2.3 From ce3af91ef865992fb744463f2bbb8dff8d0369cb Mon Sep 17 00:00:00 2001 From: Walter van Niftrik Date: Tue, 8 Mar 2016 16:30:28 +0100 Subject: ADL: Disable GMM restore on restart prompt At the end of the game a restart command is executed from the global command list. As we assumed that this would not occur, we disable restoring on the restart prompt, at least for now. --- engines/adl/adl.cpp | 16 ---------------- 1 file changed, 16 deletions(-) (limited to 'engines') diff --git a/engines/adl/adl.cpp b/engines/adl/adl.cpp index 8e374fa8f6..1ab74c3cf6 100644 --- a/engines/adl/adl.cpp +++ b/engines/adl/adl.cpp @@ -946,16 +946,7 @@ void AdlEngine::doActions(const Command &command, byte noun, byte offset) { break; case IDO_ACT_RESTART: { _display->printString(_strings.playAgain); - - // We allow restoring via GMM here - _canRestoreNow = true; Common::String input = inputString(); - _canRestoreNow = false; - - // If the user restored with the GMM, we break off the restart - if (_isRestoring) - return; - if (input.size() == 0 || input[0] != APPLECHAR('N')) { _isRestarting = true; _display->clear(0x00); @@ -1036,18 +1027,11 @@ bool AdlEngine::doOneCommand(const Commands &commands, byte verb, byte noun) { void AdlEngine::doAllCommands(const Commands &commands, byte verb, byte noun) { Commands::const_iterator cmd; - bool oldIsRestoring = _isRestoring; for (cmd = commands.begin(); cmd != commands.end(); ++cmd) { uint offset = 0; if (matchCommand(*cmd, verb, noun, &offset)) doActions(*cmd, noun, offset); - - // We assume no restarts happen in this command group. This - // simplifies enabling GMM savegame loading on the restart - // prompt. - if (_isRestarting || _isRestoring != oldIsRestoring) - error("Unexpected restart action encountered"); } } -- cgit v1.2.3