diff options
-rw-r--r-- | engines/supernova2/graphics.cpp | 276 | ||||
-rw-r--r-- | engines/supernova2/graphics.h | 87 | ||||
-rw-r--r-- | engines/supernova2/imageid.h | 33 | ||||
-rw-r--r-- | engines/supernova2/module.mk | 4 | ||||
-rw-r--r-- | engines/supernova2/ms2_def.h | 170 | ||||
-rw-r--r-- | engines/supernova2/resman.cpp | 405 | ||||
-rw-r--r-- | engines/supernova2/resman.h | 77 | ||||
-rw-r--r-- | engines/supernova2/rooms.cpp | 183 | ||||
-rw-r--r-- | engines/supernova2/rooms.h | 79 | ||||
-rw-r--r-- | engines/supernova2/screen.cpp | 621 | ||||
-rw-r--r-- | engines/supernova2/screen.h | 197 | ||||
-rw-r--r-- | engines/supernova2/screenstatic.cpp | 329 | ||||
-rw-r--r-- | engines/supernova2/state.cpp | 2 | ||||
-rw-r--r-- | engines/supernova2/state.h | 6 |
14 files changed, 2465 insertions, 4 deletions
diff --git a/engines/supernova2/graphics.cpp b/engines/supernova2/graphics.cpp new file mode 100644 index 0000000000..3ea310a936 --- /dev/null +++ b/engines/supernova2/graphics.cpp @@ -0,0 +1,276 @@ +/* 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/algorithm.h" +#include "common/file.h" +#include "common/stream.h" +#include "common/system.h" +#include "common/config-manager.h" +#include "graphics/palette.h" +#include "graphics/surface.h" + +#include "supernova2/graphics.h" +#include "supernova2/ms2_def.h" +#include "supernova2/screen.h" +#include "supernova2/supernova2.h" + +namespace Supernova2 { + +MS2Image::MS2Image() { + _palette = nullptr; + _encodedImage = nullptr; + _filenumber = -1; + _pitch = 0; + _numSections = 0; + _numClickFields = 0; + + for (int i = 0; i < kMaxSections; ++i) { + _section[i].x1 = 0; + _section[i].x2 = 0; + _section[i].y1 = 0; + _section[i].y2 = 0; + _section[i].next = 0; + _section[i].addressLow = 0xFFFF; + _section[i].addressHigh = 0xFF; + } + + for (int i = 0; i < kMaxClickFields; ++i) { + _clickField[i].x1 = 0; + _clickField[i].x2 = 0; + _clickField[i].y1 = 0; + _clickField[i].y2 = 0; + _clickField[i].next = 0; + } +} + +MS2Image::~MS2Image() { + destroy(); +} + +bool MS2Image::init(int filenumber) { + Common::File file; + if (!file.open(Common::String::format("ms2_data.%03d", filenumber))) { + warning("Image data file ms2_data.%03d could not be read!", filenumber); + return false; + } + + _filenumber = filenumber; + loadStream(file); + + return true; +} + +bool MS2Image::loadFromEngineDataFile() { + //TODO + /*Common::String name; + if (_filenumber == 1) + name = "IMG1"; + else if (_filenumber == 2) + name = "IMG2"; + else + return false; + + Common::String cur_lang = ConfMan.get("language"); + + // Note: we don't print any warning or errors here if we cannot find the file + // or the format is not as expected. We will get those warning when reading the + // strings anyway (actually the engine will even refuse to start). + Common::File f; + if (!f.open(SUPERNOVA_DAT)) + return false; + + char id[5], lang[5]; + id[4] = lang[4] = '\0'; + f.read(id, 3); + if (strncmp(id, "MSN", 3) != 0) + return false; + int version = f.readByte(); + if (version != SUPERNOVA_DAT_VERSION) + return false; + + while (!f.eos()) { + f.read(id, 4); + f.read(lang, 4); + uint32 size = f.readUint32LE(); + if (f.eos()) + break; + if (name == id && cur_lang == lang) { + return f.read(_encodedImage, size) == size; + } else + f.skip(size); + }*/ + + return false; +} + +bool MS2Image::loadStream(Common::SeekableReadStream &stream) { + destroy(); + + uint size = 0; + size = (stream.readUint16LE() + 0xF) >> 4; + size |= (stream.readUint16LE() & 0xF) << 12; + size += 0x70; // zus_paragraph + size *= 16; // a paragraph is 16 bytes + _encodedImage = new byte[size]; + + _palette = new byte[717]; + g_system->getPaletteManager()->grabPalette(_palette, 16, 239); + + byte pal_diff; + byte flag = stream.readByte(); + if (flag == 0) { + pal_diff = 0; + _palette[141] = 0xE0; + _palette[142] = 0xE0; + _palette[143] = 0xE0; + } else { + pal_diff = 1; + for (int i = flag * 3; i != 0; --i) { + _palette[717 - i] = stream.readByte() << 2; + } + } + + _numSections = stream.readByte(); + for (uint i = 0; i < kMaxSections; ++i) { + _section[i].addressHigh = 0xff; + _section[i].addressLow = 0xffff; + _section[i].x2 = 0; + _section[i].next = 0; + } + for (int i = 0; i < _numSections; ++i) { + _section[i].x1 = stream.readUint16LE(); + _section[i].x2 = stream.readUint16LE(); + _section[i].y1 = stream.readByte(); + _section[i].y2 = stream.readByte(); + _section[i].next = stream.readByte(); + _section[i].addressLow = stream.readUint16LE(); + _section[i].addressHigh = stream.readByte(); + } + + _numClickFields = stream.readByte(); + for (int i = 0; i < _numClickFields; ++i) { + _clickField[i].x1 = stream.readUint16LE(); + _clickField[i].x2 = stream.readUint16LE(); + _clickField[i].y1 = stream.readByte(); + _clickField[i].y2 = stream.readByte(); + _clickField[i].next = stream.readByte(); + } + for (int i = _numClickFields; i < kMaxClickFields; ++i) { + _clickField[i].x1 = 0; + _clickField[i].x2 = 0; + _clickField[i].y1 = 0; + _clickField[i].y2 = 0; + _clickField[i].next = 0; + } + + // Images may be in the engine data file. So first try to read + // it from there. + if (!loadFromEngineDataFile()) { + // Load the image from the stream + byte zwCodes[256] = {0}; + byte numRepeat = stream.readByte(); + byte numZw = stream.readByte(); + stream.read(zwCodes, numZw); + numZw += numRepeat; + + byte input = 0; + uint i = 0; + + while (stream.read(&input, 1)) { + if (input < numRepeat) { + ++input; + byte value = stream.readByte(); + for (--value; input > 0; --input) { + _encodedImage[i++] = value; + } + } else if (input < numZw) { + input = zwCodes[input - numRepeat]; + --input; + _encodedImage[i++] = input; + _encodedImage[i++] = input; + } else { + input -= pal_diff; + _encodedImage[i++] = input; + } + } + } + + loadSections(); + + return true; +} + +bool MS2Image::loadSections() { + bool isNewspaper = false; + int imageWidth = isNewspaper ? 640 : 320; + int imageHeight = isNewspaper ? 480 : 200; + _pitch = imageWidth; + + for (int section = 0; section < _numSections; ++section) { + Graphics::Surface *surface = new Graphics::Surface; + _sectionSurfaces.push_back(surface); + + if (isNewspaper) { + surface->create(imageWidth, imageHeight, g_system->getScreenFormat()); + byte *surfacePixels = static_cast<byte *>(surface->getPixels()); + for (int i = 0; i < imageWidth * imageHeight / 8; ++i) { + *surfacePixels++ = (_encodedImage[i] & 0x80) ? kColorWhite63 : kColorBlack; + *surfacePixels++ = (_encodedImage[i] & 0x40) ? kColorWhite63 : kColorBlack; + *surfacePixels++ = (_encodedImage[i] & 0x20) ? kColorWhite63 : kColorBlack; + *surfacePixels++ = (_encodedImage[i] & 0x10) ? kColorWhite63 : kColorBlack; + *surfacePixels++ = (_encodedImage[i] & 0x08) ? kColorWhite63 : kColorBlack; + *surfacePixels++ = (_encodedImage[i] & 0x04) ? kColorWhite63 : kColorBlack; + *surfacePixels++ = (_encodedImage[i] & 0x02) ? kColorWhite63 : kColorBlack; + *surfacePixels++ = (_encodedImage[i] & 0x01) ? kColorWhite63 : kColorBlack; + } + } else { + uint32 offset = (_section[section].addressHigh << 16) + _section[section].addressLow; + if (offset == kInvalidAddress || _section[section].x2 == 0) { + return false; + } + int width = _section[section].x2 - _section[section].x1 + 1; + int height = _section[section].y2 - _section[section].y1 + 1; + surface->create(width, height, g_system->getScreenFormat()); + byte *surfacePixels = static_cast<byte *>(surface->getPixels()); + Common::copy(_encodedImage + offset, _encodedImage + offset + width * height, surfacePixels); + } + } + + return true; +} + +void MS2Image::destroy() { + if (_palette) { + delete[] _palette; + _palette = nullptr; + } + if (_encodedImage) { + delete[] _encodedImage; + _encodedImage = nullptr; + } + for (Common::Array<Graphics::Surface *>::iterator it = _sectionSurfaces.begin(); + it != _sectionSurfaces.end(); ++it) { + (*it)->free(); + } +} + +} diff --git a/engines/supernova2/graphics.h b/engines/supernova2/graphics.h new file mode 100644 index 0000000000..4559900faa --- /dev/null +++ b/engines/supernova2/graphics.h @@ -0,0 +1,87 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#ifndef SUPERNOVA2_GRAPHICS_H +#define SUPERNOVA2_GRAPHICS_H + +#include "common/scummsys.h" +#include "image/image_decoder.h" + +namespace Common { +class SeekableReadStream; +} + +namespace Graphics { +struct Surface; +} + +namespace Supernova2 { + +class MS2Image : public Image::ImageDecoder { +public: + MS2Image(); + virtual ~MS2Image(); + + virtual void destroy(); + virtual bool loadStream(Common::SeekableReadStream &stream); + virtual const Graphics::Surface *getSurface() const { return _sectionSurfaces[0]; } + virtual const byte *getPalette() const { return _palette; } + + bool init(int filenumber); + + static const int kMaxSections = 50; + static const int kMaxClickFields = 80; + static const uint32 kInvalidAddress = 0x00FFFFFF; + + int _filenumber; + int _pitch; + int _numSections; + int _numClickFields; + Common::Array<Graphics::Surface *> _sectionSurfaces; + byte *_palette; + byte *_encodedImage; + + struct Section { + int16 x1; + int16 x2; + byte y1; + byte y2; + byte next; + uint16 addressLow; + byte addressHigh; + } _section[kMaxSections]; + + struct ClickField { + int16 x1; + int16 x2; + byte y1; + byte y2; + byte next; + } _clickField[kMaxClickFields]; + +private: + bool loadFromEngineDataFile(); + bool loadSections(); +}; + +} +#endif diff --git a/engines/supernova2/imageid.h b/engines/supernova2/imageid.h new file mode 100644 index 0000000000..6a284e0769 --- /dev/null +++ b/engines/supernova2/imageid.h @@ -0,0 +1,33 @@ +/* ScummVM - Graphic Adventure Engine +* +* ScummVM is the legal property of its developers, whose names +* are too numerous to list here. Please refer to the COPYRIGHT +* file distributed with this source distribution. +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public License +* as published by the Free Software Foundation; either version 2 +* of the License, or (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +* +*/ + +#ifndef SUPERNOVA2_IMAGEID_H +#define SUPERNOVA2_IMAGEID_H + +namespace Supernova2 { + +enum ImageId { +}; + +} + +#endif diff --git a/engines/supernova2/module.mk b/engines/supernova2/module.mk index 541008ee26..f62af5f1a7 100644 --- a/engines/supernova2/module.mk +++ b/engines/supernova2/module.mk @@ -3,6 +3,10 @@ MODULE := engines/supernova2 MODULE_OBJS := \ detection.o \ state.o \ + graphics.o \ + resman.o \ + rooms.o \ + screen.o \ console.o \ supernova2.o diff --git a/engines/supernova2/ms2_def.h b/engines/supernova2/ms2_def.h new file mode 100644 index 0000000000..49128500a4 --- /dev/null +++ b/engines/supernova2/ms2_def.h @@ -0,0 +1,170 @@ +/* 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 SUPERNOVA2_MS2_DEF_H +#define SUPERNOVA2_MS2_DEF_H + +#include "common/scummsys.h" + +namespace Supernova2 { + +const int kTextSpeed[] = {19, 14, 10, 7, 4}; +const int kMsecPerTick = 55; + +const int kMaxSection = 40; +const int kMaxDialog = 2; +const int kMaxObject = 25; +const int kMaxCarry = 30; + +const int kSleepAutosaveSlot = 999; + +const byte kShownFalse = 0; +const byte kShownTrue = 1; + +enum MessagePosition { + kMessageNormal, + kMessageLeft, + kMessageRight, + kMessageCenter, + kMessageTop +}; + +enum ObjectType { + NULLTYPE = 0, + TAKE = 1, + OPENABLE = 2, + OPENED = 4, + CLOSED = 8, + EXIT = 16, + PRESS = 32, + COMBINABLE = 64, + CARRIED = 128, + UNNECESSARY = 256, + WORN = 512, + TALK = 1024, + OCCUPIED = 2048, + CAUGHT = 4096 +}; +typedef uint16 ObjectTypes; + +enum Action { + ACTION_WALK, + ACTION_LOOK, + ACTION_TAKE, + ACTION_OPEN, + ACTION_CLOSE, + ACTION_PRESS, + ACTION_PULL, + ACTION_USE, + ACTION_TALK, + ACTION_GIVE +}; + +enum RoomId { + INTRO, OUTRO, + NULLROOM +}; + +enum ObjectId { + INVALIDOBJECT = -1, + NULLOBJECT = 0 +}; + +enum StringId { + kNoString = -1, kStringDefaultDescription +}; + +ObjectType operator|(ObjectType a, ObjectType b); +ObjectType operator&(ObjectType a, ObjectType b); +ObjectType operator^(ObjectType a, ObjectType b); +ObjectType &operator|=(ObjectType &a, ObjectType b); +ObjectType &operator&=(ObjectType &a, ObjectType b); +ObjectType &operator^=(ObjectType &a, ObjectType b); + +struct Object { + Object() + : _name(kNoString) + , _description(kStringDefaultDescription) + , _id(INVALIDOBJECT) + , _roomId(NULLROOM) + , _type(NULLTYPE) + , _click(0) + , _click2(0) + , _section(0) + , _exitRoom(NULLROOM) + , _direction(0) + {} + Object(byte roomId, StringId name, StringId description, ObjectId id, ObjectType type, + byte click, byte click2, byte section = 0, RoomId exitRoom = NULLROOM, byte direction = 0) + : _name(name) + , _description(description) + , _id(id) + , _roomId(roomId) + , _type(type) + , _click(click) + , _click2(click2) + , _section(section) + , _exitRoom(exitRoom) + , _direction(direction) + {} + + void resetProperty(ObjectType type = NULLTYPE) { + _type = type; + } + + void setProperty(ObjectType type) { + _type |= type; + } + + void disableProperty(ObjectType type) { + _type &= ~type; + } + + bool hasProperty(ObjectType type) const { + return _type & type; + } + + static bool combine(Object &obj1, Object &obj2, ObjectId id1, ObjectId id2) { + if (obj1.hasProperty(COMBINABLE)) + return (((obj1._id == id1) && (obj2._id == id2)) || + ((obj1._id == id2) && (obj2._id == id1))); + else + return false; + } + + byte _roomId; + StringId _name; + StringId _description; + ObjectId _id; + ObjectTypes _type; + byte _click; + byte _click2; + byte _section; + RoomId _exitRoom; + byte _direction; +}; + +#define ticksToMsec(x) (x * kMsecPerTick) + +} + +#endif // SUPERNOVA2_MS2_DEF_H diff --git a/engines/supernova2/resman.cpp b/engines/supernova2/resman.cpp new file mode 100644 index 0000000000..259d279eec --- /dev/null +++ b/engines/supernova2/resman.cpp @@ -0,0 +1,405 @@ +/* ScummVM - Graphic Adventure Engine +* +* ScummVM is the legal property of its developers, whose names +* are too numerous to list here. Please refer to the COPYRIGHT +* file distributed with this source distribution. +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public License +* as published by the Free Software Foundation; either version 2 +* of the License, or (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +* +*/ + +#include "audio/audiostream.h" +#include "audio/decoders/raw.h" +#include "audio/mixer.h" +#include "audio/mods/protracker.h" +#include "common/memstream.h" +#include "common/system.h" +#include "graphics/cursorman.h" +#include "graphics/palette.h" + +#include "supernova2/graphics.h" +#include "supernova2/resman.h" +#include "supernova2/screen.h" +#include "supernova2/supernova2.h" + +namespace Supernova2 { + +struct AudioInfo { + int _filenumber; + int _offsetStart; + int _offsetEnd; +}; + +//static Common::MemoryReadStream *convertToMod(const char *filename, int version = 1); + +/*static const AudioInfo audioInfo[kAudioNumSamples] = { + {44, 0, -1}, + {45, 0, -1}, + {46, 0, 2510}, + {46, 2510, 4020}, + {46, 4020, -1}, + {47, 0, 24010}, + {47, 24010, -1}, + {48, 0, 2510}, + {48, 2510, 10520}, + {48, 10520, 13530}, + {48, 13530, -1}, + {50, 0, 12786}, + {50, 12786, -1}, + {51, 0, -1}, + {53, 0, -1}, + {54, 0, 8010}, + {54, 8010, 24020}, + {54, 24020, 30030}, + {54, 30030, 31040}, + {54, 31040, -1} +};*/ + +static const byte mouseNormal[64] = { + 0xff,0x3f,0xff,0x1f,0xff,0x0f,0xff,0x07, + 0xff,0x03,0xff,0x01,0xff,0x00,0x7f,0x00, + 0x3f,0x00,0x1f,0x00,0x0f,0x00,0x0f,0x00, + 0xff,0x00,0x7f,0x18,0x7f,0x38,0x7f,0xfc, + + 0x00,0x00,0x00,0x40,0x00,0x60,0x00,0x70, + 0x00,0x78,0x00,0x7c,0x00,0x7e,0x00,0x7f, + 0x80,0x7f,0xc0,0x7f,0xe0,0x7f,0x00,0x7e, + 0x00,0x66,0x00,0x43,0x00,0x03,0x00,0x00 +}; + +static const byte mouseWait[64] = { + 0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x80, + 0x01,0x80,0x01,0x80,0x11,0x88,0x31,0x8c, + 0x31,0x8c,0x11,0x88,0x01,0x80,0x01,0x80, + 0x01,0x80,0x00,0x00,0x00,0x00,0x00,0x00, + + 0x00,0x00,0xfe,0x7f,0xf4,0x2f,0xf4,0x2f, + 0x14,0x28,0x24,0x24,0x44,0x22,0x84,0x21, + 0x84,0x21,0xc4,0x23,0xe4,0x27,0x74,0x2e, + 0x34,0x2c,0x14,0x28,0xfe,0x7f,0x00,0x00 +}; + + +ResourceManager::ResourceManager() + : _audioRate(11931) { + //initSoundFiles(); + initGraphics(); +} + +//TODO +/*void ResourceManager::initSoundFiles() { + // Sound + // Note: + // - samples start with a header of 6 bytes: 01 SS SS 00 AD 00 + // where SS SS (LE uint16) is the size of the sound sample + 2 + // - samples end with a footer of 4 bytes: 00 00 + // Skip those in the buffer + Common::File file; + + for (int i = 0; i < kAudioNumSamples; ++i) { + if (!file.open(Common::String::format("msn_data.%03d", audioInfo[i]._filenumber))) { + error("File %s could not be read!", file.getName()); + } + + int length = 0; + byte *buffer = nullptr; + + if (audioInfo[i]._offsetEnd == -1) { + file.seek(0, SEEK_END); + length = file.pos() - audioInfo[i]._offsetStart - 10; + } else { + length = audioInfo[i]._offsetEnd - audioInfo[i]._offsetStart - 10; + } + buffer = new byte[length]; + file.seek(audioInfo[i]._offsetStart + 6); + file.read(buffer, length); + file.close(); + + byte streamFlag = Audio::FLAG_UNSIGNED | Audio::FLAG_LITTLE_ENDIAN; + _soundSamples[i].reset(Audio::makeRawStream(buffer, length, _audioRate, + streamFlag, DisposeAfterUse::YES)); + } + + _musicIntroBuffer.reset(convertToMod("msn_data.052")); + _musicOutroBuffer.reset(convertToMod("msn_data.049")); +}*/ + +void ResourceManager::initGraphics() { + Screen::initPalette(); + initCursorGraphics(); + initImages(); +} + +void ResourceManager::initCursorGraphics() { + const uint16 *bufferNormal = reinterpret_cast<const uint16 *>(mouseNormal); + const uint16 *bufferWait = reinterpret_cast<const uint16 *>(mouseWait); + for (uint i = 0; i < sizeof(mouseNormal) / 4; ++i) { + for (uint bit = 0; bit < 16; ++bit) { + uint mask = 0x8000 >> bit; + uint bitIndex = i * 16 + bit; + + _cursorNormal[bitIndex] = (READ_LE_UINT16(bufferNormal + i) & mask) ? + kColorCursorTransparent : kColorBlack; + if (READ_LE_UINT16(bufferNormal + i + 16) & mask) + _cursorNormal[bitIndex] = kColorLightRed; + + _cursorWait[bitIndex] = (READ_LE_UINT16(bufferWait + i) & mask) ? + kColorCursorTransparent : kColorBlack; + if (READ_LE_UINT16(bufferWait + i + 16) & mask) + _cursorWait[bitIndex] = kColorLightRed; + } + } +} + +void ResourceManager::initImages() { + for (int i = 0; i < 44; ++i) { + if (!_images[i].init(i)) + error("Failed reading image file ms2_data.%03d", i); + } + if (!_images[44].init(55)) + error("Failed reading image file ms2_data.055"); +} + +//TODO +/*Audio::SeekableAudioStream *ResourceManager::getSoundStream(AudioId index) { + Audio::SeekableAudioStream *stream = _soundSamples[index].get(); + stream->rewind(); + + return stream; +} + +Audio::AudioStream *ResourceManager::getSoundStream(MusicId index) { + switch (index) { + case kMusicIntro: + _musicIntro.reset(Audio::makeProtrackerStream(_musicIntroBuffer.get())); + return _musicIntro.get(); + case kMusicOutro: + _musicOutro.reset(Audio::makeProtrackerStream(_musicOutroBuffer.get())); + return _musicOutro.get(); + default: + error("Invalid music constant in playAudio()"); + } +}*/ + +const MS2Image *ResourceManager::getImage(int filenumber) const { + if (filenumber < 44) + return &_images[filenumber]; + else if (filenumber == 55) + return &_images[44]; + else + return nullptr; +} + +const byte *ResourceManager::getImage(CursorId id) const { + switch (id) { + case kCursorNormal: + return _cursorNormal; + case kCursorWait: + return _cursorWait; + default: + return nullptr; + } +} + +//TODO +/* +static Common::MemoryReadStream *convertToMod(const char *filename, int version) { + // MSN format + struct { + uint16 seg; + uint16 start; + uint16 end; + uint16 loopStart; + uint16 loopEnd; + char volume; + char dummy[5]; + } instr2[22]; + int nbInstr2; // 22 for version1, 15 for version 2 + int16 songLength; + char arrangement[128]; + int16 patternNumber; + int32 note2[28][64][4]; + + nbInstr2 = ((version == 1) ? 22 : 15); + + Common::File msnFile; + msnFile.open(filename); + if (!msnFile.isOpen()) { + warning("Data file '%s' not found", msnFile.getName()); + return nullptr; + } + + for (int i = 0 ; i < nbInstr2 ; ++i) { + instr2[i].seg = msnFile.readUint16LE(); + instr2[i].start = msnFile.readUint16LE(); + instr2[i].end = msnFile.readUint16LE(); + instr2[i].loopStart = msnFile.readUint16LE(); + instr2[i].loopEnd = msnFile.readUint16LE(); + instr2[i].volume = msnFile.readByte(); + msnFile.read(instr2[i].dummy, 5); + } + songLength = msnFile.readSint16LE(); + msnFile.read(arrangement, 128); + patternNumber = msnFile.readSint16LE(); + for (int p = 0 ; p < patternNumber ; ++p) { + for (int n = 0 ; n < 64 ; ++n) { + for (int k = 0 ; k < 4 ; ++k) { + note2[p][n][k] = msnFile.readSint32LE(); + } + } + } + + // MOD format + struct { + char iname[22]; + uint16 length; + char finetune; + char volume; + uint16 loopStart; + uint16 loopLength; + } instr[31]; + int32 note[28][64][4]; + + // We can't recover some MOD effects since several of them are mapped to 0. + // Assume the MSN effect of value 0 is Arpeggio (MOD effect of value 0). + const char invConvEff[8] = {0, 1, 2, 3, 10, 12, 13 ,15}; + + // Reminder from convertToMsn + // 31 30 29 28 27 26 25 24 - 23 22 21 20 19 18 17 16 - 15 14 13 12 11 10 09 08 - 07 06 05 04 03 02 01 00 + // h h h h g g g g f f f f e e e e d d d d c c c c b b b b a a a a + // + // MSN: + // hhhh (4 bits) Cleared to 0 + // dddd c (5 bits) Sample index | after mapping through convInstr + // ccc (3 bits) Effect type | after mapping through convEff + // bbbb aaaa (8 bits) Effect value | unmodified + // gggg ffff eeee (12 bits) Sample period | unmodified + // + // MS2: + // hhhh (4 bits) Cleared to 0 + // dddd (4 bits) Sample index | after mapping through convInstr + // cccc (4 bits) Effect type | unmodified + // bbbb aaaa (8 bits) Effect value | unmodified + // gggg ffff eeee (12 bits) Sample period | transformed (0xE000 / p) - 256 + // + // MOD: + // hhhh dddd (8 bits) Sample index + // cccc (4 bits) Effect type for this channel/division + // bbbb aaaa (8 bits) Effect value + // gggg ffff eeee (12 bits) Sample period + + // Can we recover the instruments mapping? I don't think so as part of the original instrument index is cleared. + // And it doesn't really matter as long as we are consistent. + // However we need to make sure 31 (or 15 in MS2) is mapped to 0 in MOD. + // We just add 1 to all other values, and this means a 1 <-> 1 mapping for the instruments + for (int p = 0; p < patternNumber; ++p) { + for (int n = 0; n < 64; ++n) { + for (int k = 0; k < 4; ++k) { + int32* l = &(note[p][n][k]); + *l = note2[p][n][k]; + int32 i = 0; + if (nbInstr2 == 22) { // version 1 + i = ((*l & 0xF800) >> 11); + int32 e = ((*l & 0x0700) >> 8); + int32 e1 = invConvEff[e]; + *l &= 0x0FFF00FF; + *l |= (e1 << 8); + } else { // version 2 + int32 h = (*l >> 16); + i = ((*l & 0xF000) >> 12); + *l &= 0x00000FFF; + if (h) + h = 0xE000 / (h + 256); + *l |= (h << 16); + if (i == 15) + i = 31; + } + + // Add back index in note + if (i != 31) { + ++i; + *l |= ((i & 0x0F) << 12); + *l |= ((i & 0xF0) << 24); + } + } + } + } + + for (int i = 0; i < 31; ++i) { + // iname is not stored in the mod file. Just set it to 'instrument#' + // finetune is not stored either. Assume 0. + memset(instr[i].iname, 0, 22); + sprintf(instr[i].iname, "instrument%d", i+1); + instr[i].length = 0; + instr[i].finetune = 0; + instr[i].volume = 0; + instr[i].loopStart = 0; + instr[i].loopLength = 0; + + if (i < nbInstr2) { + instr[i].length = ((instr2[i].end - instr2[i].start) >> 1); + instr[i].loopStart = ((instr2[i].loopStart - instr2[i].start) >> 1); + instr[i].loopLength = (( instr2[i].loopEnd - instr2[i].loopStart) >> 1); + instr[i].volume = instr2[i].volume; + } + } + + // The ciaaSpeed is kind of useless and not present in the MSN file. + // Traditionally 0x78 in SoundTracker. Was used in NoiseTracker as a restart point. + // ProTracker uses 0x7F. FastTracker uses it as a restart point, whereas ScreamTracker 3 uses 0x7F like ProTracker. + // You can use this to roughly detect which tracker made a MOD, and detection gets more accurate for more obscure MOD types. + char ciaaSpeed = 0x7F; + + // The mark cannot be recovered either. Since we have 4 channels and 31 instrument it can be either ID='M.K.' or ID='4CHN'. + // Assume 'M.K.' + const char mark[4] = { 'M', '.', 'K', '.' }; + + Common::MemoryWriteStreamDynamic buffer(DisposeAfterUse::NO); + + buffer.write(msnFile.getName(), 19); + buffer.writeByte(0); + + for (int i = 0 ; i < 31 ; ++i) { + buffer.write(instr[i].iname, 22); + buffer.writeUint16BE(instr[i].length); + buffer.writeByte(instr[i].finetune); + buffer.writeByte(instr[i].volume); + buffer.writeUint16BE(instr[i].loopStart); + buffer.writeUint16BE(instr[i].loopLength); + } + buffer.writeByte((char)songLength); + buffer.writeByte(ciaaSpeed); + buffer.write(arrangement, 128); + buffer.write(mark, 4); + + for (int p = 0 ; p < patternNumber ; ++p) { + for (int n = 0 ; n < 64 ; ++n) { + for (int k = 0 ; k < 4 ; ++k) { +// buffer.writeUint32BE(*((uint32*)(note[p][n]+k))); + buffer.writeSint32BE(note[p][n][k]); + } + } + } + + uint nb; + char buf[4096]; + while ((nb = msnFile.read(buf, 4096)) > 0) + buffer.write(buf, nb); + + return new Common::MemoryReadStream(buffer.getData(), buffer.size(), DisposeAfterUse::YES); +} +*/ + +} diff --git a/engines/supernova2/resman.h b/engines/supernova2/resman.h new file mode 100644 index 0000000000..84289d2b7f --- /dev/null +++ b/engines/supernova2/resman.h @@ -0,0 +1,77 @@ +/* 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 SUPERNOVA2_RESOURCES_H +#define SUPERNOVA2_RESOURCES_H + +#include "audio/audiostream.h" +#include "common/ptr.h" + +#include "supernova2/graphics.h" +//#include "supernova/sound.h" + + +namespace Common { +class MemoryReadStream; +} + +namespace Supernova2 { + +class ResourceManager { +public: + enum CursorId { + kCursorNormal, + kCursorWait + }; + +public: + static const int kNumImageFiles = 45; + +public: + ResourceManager(); + + //Audio::SeekableAudioStream *getSoundStream(AudioId index); + //Audio::AudioStream *getSoundStream(MusicId index); + const MS2Image *getImage(int filenumber) const; + const byte *getImage(CursorId id) const; + +private: + void initSoundFiles(); + void initGraphics(); + void initCursorGraphics(); + void initImages(); + +private: + //Common::ScopedPtr<Audio::SeekableAudioStream> _soundSamples[kAudioNumSamples]; + //Common::ScopedPtr<Common::MemoryReadStream> _musicIntroBuffer; + //Common::ScopedPtr<Common::MemoryReadStream> _musicOutroBuffer; + //Common::ScopedPtr<Audio::AudioStream> _musicIntro; + //Common::ScopedPtr<Audio::AudioStream> _musicOutro; + int _audioRate; + MS2Image _images[kNumImageFiles]; + byte _cursorNormal[256]; + byte _cursorWait[256]; +}; + +} + +#endif diff --git a/engines/supernova2/rooms.cpp b/engines/supernova2/rooms.cpp new file mode 100644 index 0000000000..f7f76c0da2 --- /dev/null +++ b/engines/supernova2/rooms.cpp @@ -0,0 +1,183 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#include "common/system.h" +#include "graphics/palette.h" +#include "graphics/cursorman.h" + +#include "supernova2/screen.h" +#include "supernova2/supernova2.h" +#include "supernova2/state.h" +#include "supernova2/rooms.h" + +namespace Supernova2 { + +Room::Room() { + _seen = false; + _fileNumber = 0; + _id = NULLROOM; + _vm = nullptr; + _gm = nullptr; + + for (int i = 0; i < kMaxSection; ++i) + _shown[i] = kShownFalse; + for (int i = 0; i < kMaxDialog; ++i) + _sentenceRemoved[i] = 0; +} + +Room::~Room() { +} + +bool Room::serialize(Common::WriteStream *out) { + if (out->err()) + return false; + + out->writeSint32LE(_id); + for (int i = 0; i < kMaxSection; ++i) + out->writeByte(_shown[i]); + for (int i = 0; i < kMaxDialog ; ++i) + out->writeByte(_sentenceRemoved[i]); + + int numObjects = 0; + while ((numObjects < kMaxObject) && (_objectState[numObjects]._id != INVALIDOBJECT)) + ++numObjects; + out->writeSint32LE(numObjects); + + for (int i = 0; i < numObjects; ++i) { + out->writeSint32LE(_objectState[i]._name); + out->writeSint32LE(_objectState[i]._description); + out->writeByte(_objectState[i]._roomId); + out->writeSint32LE(_objectState[i]._id); + out->writeSint32LE(_objectState[i]._type); + out->writeByte(_objectState[i]._click); + out->writeByte(_objectState[i]._click2); + out->writeByte(_objectState[i]._section); + out->writeSint32LE(_objectState[i]._exitRoom); + out->writeByte(_objectState[i]._direction); + } + + out->writeByte(_seen); + + return !out->err(); +} + +bool Room::deserialize(Common::ReadStream *in, int version) { + if (in->err()) + return false; + + in->readSint32LE(); + + for (int i = 0; i < kMaxSection; ++i) + _shown[i] = in->readByte(); + + // Prior to version 3, _sentenceRemoved was part of _shown (the last two values) + // But on the other hand dialog was not implemented anyway, so we don't even try to + // recover it. + for (int i = 0; i < kMaxDialog ; ++i) + _sentenceRemoved[i] = version < 3 ? 0 : in->readByte(); + + int numObjects = in->readSint32LE(); + for (int i = 0; i < numObjects; ++i) { + _objectState[i]._name = static_cast<StringId>(in->readSint32LE()); + _objectState[i]._description = static_cast<StringId>(in->readSint32LE()); + _objectState[i]._roomId = in->readByte(); + _objectState[i]._id = static_cast<ObjectId>(in->readSint32LE()); + _objectState[i]._type = static_cast<ObjectType>(in->readSint32LE()); + _objectState[i]._click = in->readByte(); + _objectState[i]._click2 = in->readByte(); + _objectState[i]._section = in->readByte(); + _objectState[i]._exitRoom = static_cast<RoomId>(in->readSint32LE()); + _objectState[i]._direction = in->readByte(); + } + + _seen = in->readByte(); + + return !in->err(); +} + +bool Room::hasSeen() { + return _seen; +} +void Room::setRoomSeen(bool seen) { + _seen = seen; +} + +int Room::getFileNumber() const { + return _fileNumber; +} +RoomId Room::getId() const { + return _id; +} + +void Room::setSectionVisible(uint section, bool visible) { + _shown[section] = visible ? kShownTrue : kShownFalse; +} + +bool Room::isSectionVisible(uint index) const { + return _shown[index] == kShownTrue; +} + +void Room::removeSentence(int sentence, int number) { + if (number > 0) + _sentenceRemoved[number - 1] |= (1 << sentence); +} + +void Room::addSentence(int sentence, int number) { + if (number > 0) + _sentenceRemoved[number - 1] &= ~(1 << sentence); +} + +void Room::addAllSentences(int number) { + if (number > 0) + _sentenceRemoved[number - 1] = 0; +} + +bool Room::sentenceRemoved(int sentence, int number) { + if (number <= 0) + return false; + return (_sentenceRemoved[number - 1] & (1 << sentence)); +} + +bool Room::allSentencesRemoved(int maxSentence, int number) { + if (number <= 0) + return false; + for (int i = 0, flag = 1 ; i < maxSentence ; ++i, flag <<= 1) + if (!(_sentenceRemoved[number - 1] & flag)) + return false; + return true; +} + +Object *Room::getObject(uint index) { + return &_objectState[index]; +} + +void Room::animation() { +} + +void Room::onEntrance() { +} + +bool Room::interact(Action verb, Object &obj1, Object &obj2) { + return false; +} + +} diff --git a/engines/supernova2/rooms.h b/engines/supernova2/rooms.h new file mode 100644 index 0000000000..26113d0425 --- /dev/null +++ b/engines/supernova2/rooms.h @@ -0,0 +1,79 @@ +/* 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 SUPERNOVA2_ROOMS_H +#define SUPERNOVA2_ROOMS_H + +#include "common/str.h" + +#include "supernova2/ms2_def.h" + +namespace Common { +class ReadStream; +class WriteStream; +} + +namespace Supernova2 { + +class GameManager; +class Supernova2Engine; + +class Room { +public: + Room(); + + bool hasSeen(); + void setRoomSeen(bool seen); + int getFileNumber() const; + RoomId getId() const; + void setSectionVisible(uint section, bool visible); + bool isSectionVisible(uint index) const; + void removeSentence(int sentence, int number); + void addSentence(int sentence, int number); + void addAllSentences(int number); + bool sentenceRemoved(int sentence, int number); + bool allSentencesRemoved(int maxSentence, int number); + Object *getObject(uint index); + + virtual ~Room(); + virtual void animation(); + virtual void onEntrance(); + virtual bool interact(Action verb, Object &obj1, Object &obj2); + virtual bool serialize(Common::WriteStream *out); + virtual bool deserialize(Common::ReadStream *in, int version); + +protected: + int _fileNumber; + bool _shown[kMaxSection]; + byte _sentenceRemoved[kMaxDialog]; + Object _objectState[kMaxObject]; + RoomId _id; + Supernova2Engine *_vm; + GameManager *_gm; + +private: + bool _seen; +}; + + +} +#endif // SUPERNOVA2_ROOMS_H diff --git a/engines/supernova2/screen.cpp b/engines/supernova2/screen.cpp new file mode 100644 index 0000000000..47c9535b0b --- /dev/null +++ b/engines/supernova2/screen.cpp @@ -0,0 +1,621 @@ +/* ScummVM - Graphic Adventure Engine +* +* ScummVM is the legal property of its developers, whose names +* are too numerous to list here. Please refer to the COPYRIGHT +* file distributed with this source distribution. +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public License +* as published by the Free Software Foundation; either version 2 +* of the License, or (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +* +*/ + +#include "common/str.h" +#include "common/system.h" +#include "engines/util.h" +#include "graphics/cursorman.h" +#include "graphics/palette.h" +#include "graphics/surface.h" + +#include "supernova2/imageid.h" +#include "supernova2/resman.h" +#include "supernova2/state.h" +#include "supernova2/screen.h" +#include "supernova2/supernova2.h" + +#include "supernova2/screenstatic.cpp" + +namespace Supernova2 { + +ScreenBuffer::ScreenBuffer() + : _x(0) + , _y(0) + , _width(0) + , _height(0) + , _pixels(nullptr) { +} + +ScreenBufferStack::ScreenBufferStack() + : _last(_buffer) { +} + +void ScreenBufferStack::push(int x, int y, int width, int height) { + if (_last == ARRAYEND(_buffer)) + return; + + Graphics::Surface *screenSurface = g_system->lockScreen(); + + if (x < 0) { + width += x; + x = 0; + } + + if (x + width > screenSurface->w) + width = screenSurface->w - x; + + if (y < 0) { + height += y; + y = 0; + } + + if (y + height > screenSurface->h) + height = screenSurface->h - y; + + _last->_pixels = new byte[width * height]; + byte *pixels = _last->_pixels; + const byte *screen = static_cast<const byte *>(screenSurface->getBasePtr(x, y)); + for (int i = 0; i < height; ++i) { + Common::copy(screen, screen + width, pixels); + screen += screenSurface->pitch; + pixels += width; + } + g_system->unlockScreen(); + + _last->_x = x; + _last->_y = y; + _last->_width = width; + _last->_height = height; + + ++_last; +} + +void ScreenBufferStack::restore() { + if (_last == _buffer) + return; + + --_last; + g_system->lockScreen()->copyRectToSurface(_last->_pixels, _last->_width, _last->_x, + _last->_y, _last->_width, _last->_height); + g_system->unlockScreen(); + + delete[] _last->_pixels; +} + +Marquee::Marquee(Screen *screen, MarqueeId id, const char *text) + : _text(text) + , _textBegin(text) + , _delay(0) + , _color(kColorLightBlue) + , _loop(false) + , _screen(screen) { + if (id == kMarqueeIntro) { + _y = 191; + _loop = true; + } else if (id == kMarqueeOutro) { + _y = 1; + } + + _textWidth = Screen::textWidth(_text); + _x = kScreenWidth / 2 - _textWidth / 2; + _screen->_textCursorX = _x; + _screen->_textCursorY = _y; + _screen->_textColor = _color; +} + +void Marquee::clearText() { + _screen->renderBox(_x, _y - 1, _textWidth + 1, 9, kColorBlack); +} + +void Marquee::renderCharacter() { + if (_delay != 0) { + _delay--; + return; + } + + switch (*_text) { + case '\233': + if (_loop) { + _loop = false; + _text = _textBegin; + clearText(); + _textWidth = Screen::textWidth(_text); + _x = kScreenWidth / 2 - _textWidth / 2; + _screen->_textCursorX = _x; + } + break; + case '\0': + clearText(); + _text++; + _textWidth = Screen::textWidth(_text); + _x = kScreenWidth / 2 - _textWidth / 2; + _screen->_textCursorX = _x; + _color = kColorLightBlue; + _screen->_textColor = _color; + break; + case '^': + _color = kColorLightYellow; + _screen->_textColor = _color; + _text++; + break; + case '#': + _delay = 50; + _text++; + break; + default: + _screen->renderText((uint16)*_text++); + _delay = 1; + break; + } +} + +Screen::Screen(Supernova2Engine *vm, ResourceManager *resMan) + : _vm(vm) + , _resMan(resMan) + , _currentImage(nullptr) + , _viewportBrightness(255) + , _guiBrightness(255) + , _screenWidth(320) + , _screenHeight(200) + , _textColor(kColorBlack) + , _textCursorX(0) + , _textCursorY(0) + , _messageShown(false) { + + CursorMan.replaceCursor(_resMan->getImage(ResourceManager::kCursorNormal), + 16, 16, 0, 0, kColorCursorTransparent); + CursorMan.replaceCursorPalette(initVGAPalette, 0, 16); + CursorMan.showMouse(true); +} + +int Screen::getGuiBrightness() const { + return _guiBrightness; +} + +void Screen::setViewportBrightness(int brightness) { + _viewportBrightness = brightness; +} + +int Screen::getViewportBrightness() const { + return _viewportBrightness; +} + +void Screen::setGuiBrightness(int brightness) { + _guiBrightness = brightness; +} + +const MS2Image *Screen::getCurrentImage() const { + return _currentImage; +} + +const Screen::ImageInfo *Screen::getImageInfo(ImageId id) const { + return &imageInfo[(int)id]; +} + +bool Screen::isMessageShown() const { + return _messageShown; +} + +Common::Point Screen::getTextCursorPos() { + return Common::Point(_textCursorX, _textCursorY); +} + +void Screen::setTextCursorPos(int x, int y) { + _textCursorX = x; + _textCursorY = y; +} + +byte Screen::getTextCursorColor() { + return _textColor; +} + +void Screen::setTextCursorColor(byte color) { + _textColor = color; +} + +void Screen::renderMessage(StringId stringId, MessagePosition position, + Common::String var1, Common::String var2) { + Common::String text = _vm->getGameString(stringId); + + if (!var1.empty()) { + if (!var2.empty()) + text = Common::String::format(text.c_str(), var1.c_str(), var2.c_str()); + else + text = Common::String::format(text.c_str(), var1.c_str()); + } + + renderMessage(text, position); +} + +void Screen::renderMessage(const Common::String &text, MessagePosition position) { + if (!text.empty()) + renderMessage(text.c_str(), position); +} + +void Screen::renderText(const uint16 character) { + char text[2]; + text[0] = character & 0xFF; + text[1] = 0; + renderText(text, _textCursorX, _textCursorY, _textColor); +} + +void Screen::renderText(const char *text) { + renderText(text, _textCursorX, _textCursorY, _textColor); +} + +void Screen::renderText(StringId stringId) { + renderText(_vm->getGameString(stringId)); +} + +void Screen::renderText(const Common::String &text) { + if (!text.empty()) + renderText(text.c_str()); +} + +/*void Screen::renderText(const GuiElement &guiElement) { + renderText(guiElement.getText(), guiElement.getTextPos().x, + guiElement.getTextPos().y, guiElement.getTextColor()); +}*/ + +void Screen::renderText(const uint16 character, int x, int y, byte color) { + char text[2]; + text[0] = character & 0xFF; + text[1] = 0; + renderText(text, x, y, color); +} + +void Screen::renderText(const char *text, int x, int y, byte color) { + Graphics::Surface *screen = _vm->_system->lockScreen(); + byte *cursor = static_cast<byte *>(screen->getBasePtr(x, y)); + const byte *basePtr = cursor; + + byte c; + while ((c = *text++) != '\0') { + if (c < 32) { + continue; + } else if (c == 225) { + c = 128; + } + + for (uint i = 0; i < 5; ++i) { + if (font[c - 32][i] == 0xff) { + break; + } + + byte *ascentLine = cursor; + for (byte j = font[c - 32][i]; j != 0; j >>= 1) { + if (j & 1) { + *cursor = color; + } + cursor += kScreenWidth; + } + cursor = ++ascentLine; + } + ++cursor; + } + _vm->_system->unlockScreen(); + + uint numChars = cursor - basePtr; + uint absPosition = y * kScreenWidth + x + numChars; + _textCursorX = absPosition % kScreenWidth; + _textCursorY = absPosition / kScreenWidth; + _textColor = color; +} + +void Screen::renderText(const Common::String &text, int x, int y, byte color) { + if (!text.empty()) + renderText(text.c_str(), x, y, color); +} + +void Screen::renderText(StringId stringId, int x, int y, byte color) { + renderText(_vm->getGameString(stringId), x, y, color); +} + +void Screen::renderImageSection(const MS2Image *image, int section, bool invert) { + // Note: inverting means we are removing the section. So we should get the rect for that + // section but draw the background (section 0) instead. + if (section > image->_numSections - 1) + return; + + Common::Rect sectionRect(image->_section[section].x1, + image->_section[section].y1, + image->_section[section].x2 + 1, + image->_section[section].y2 + 1); + if (image->_filenumber == 1 || image->_filenumber == 2) { + sectionRect.setWidth(640); + sectionRect.setHeight(480); + if (_screenWidth != 640) { + _screenWidth = 640; + _screenHeight = 480; + initGraphics(_screenWidth, _screenHeight); + } + } else { + if (_screenWidth != 320) { + _screenWidth = 320; + _screenHeight = 200; + initGraphics(_screenWidth, _screenHeight); + } + } + + uint offset = 0; + int pitch = sectionRect.width(); + if (invert) { + pitch = image->_pitch; + offset = image->_section[section].y1 * pitch + + image->_section[section].x1; + section = 0; + } + + void *pixels = image->_sectionSurfaces[section]->getPixels(); + _vm->_system->copyRectToScreen(static_cast<const byte *>(pixels) + offset, + pitch, sectionRect.left, sectionRect.top, + sectionRect.width(), sectionRect.height()); +} + +void Screen::renderImage(ImageId id, bool removeImage) { + ImageInfo info = imageInfo[id]; + const MS2Image *image = _resMan->getImage(info.filenumber); + + if (_currentImage != image) + setCurrentImage(info.filenumber); + + do { + renderImageSection(image, info.section, removeImage); + info.section = image->_section[info.section].next; + } while (info.section != 0); +} + +void Screen::renderImage(int section) { + bool removeImage = false; + if (section > 128) { + removeImage = true; + section -= 128; + } + + if (!_currentImage || section >= kMaxSection) + return; + + do { + renderImageSection(_currentImage, section, removeImage); + section = _currentImage->_section[section].next; + } while (section != 0); +} + +bool Screen::setCurrentImage(int filenumber) { + _currentImage = _resMan->getImage(filenumber); + _vm->_system->getPaletteManager()->setPalette(_currentImage->getPalette(), 16, 239); + paletteBrightness(); + + return true; +} + +void Screen::saveScreen(int x, int y, int width, int height) { + _screenBuffer.push(x, y, width, height); +} + +/*void Screen::saveScreen(const GuiElement &guiElement) { + saveScreen(guiElement.left, guiElement.top, guiElement.width(), guiElement.height()); +}*/ + +void Screen::restoreScreen() { + _screenBuffer.restore(); +} + +void Screen::renderRoom(Room &room) { + if (room.getId() == INTRO) + return; + + if (setCurrentImage(room.getFileNumber())) { + for (int i = 0; i < _currentImage->_numSections; ++i) { + int section = i; + if (room.isSectionVisible(section)) { + do { + renderImageSection(_currentImage, section, false); + section = _currentImage->_section[section].next; + } while (section != 0); + } + } + } +} + +int Screen::textWidth(const uint16 key) { + char text[2]; + text[0] = key & 0xFF; + text[1] = 0; + return textWidth(text); +} + +int Screen::textWidth(const char *text) { + int charWidth = 0; + while (*text != '\0') { + byte c = *text++; + if (c < 32) { + continue; + } else if (c == 225) { + c = 35; + } + + for (uint i = 0; i < 5; ++i) { + if (font[c - 32][i] == 0xff) { + break; + } + ++charWidth; + } + ++charWidth; + } + + return charWidth; +} + +int Screen::textWidth(const Common::String &text) { + return Screen::textWidth(text.c_str()); +} + +void Screen::renderMessage(const char *text, MessagePosition position) { + Common::String t(text); + char *row[20]; + Common::String::iterator p = t.begin(); + uint numRows = 0; + int rowWidthMax = 0; + int x = 0; + int y = 0; + byte textColor = 0; + + while (*p != '\0') { + row[numRows] = p; + ++numRows; + while ((*p != '\0') && (*p != '|')) { + ++p; + } + if (*p == '|') { + *p = '\0'; + ++p; + } + } + for (uint i = 0; i < numRows; ++i) { + int rowWidth = textWidth(row[i]); + if (rowWidth > rowWidthMax) + rowWidthMax = rowWidth; + } + + switch (position) { + case kMessageNormal: + x = 160 - rowWidthMax / 2; + textColor = kColorWhite99; + break; + case kMessageTop: + x = 160 - rowWidthMax / 2; + textColor = kColorLightYellow; + break; + case kMessageCenter: + x = 160 - rowWidthMax / 2; + textColor = kColorLightRed; + break; + case kMessageLeft: + x = 3; + textColor = kColorLightYellow; + break; + case kMessageRight: + x = 317 - rowWidthMax; + textColor = kColorLightGreen; + break; + } + + if (position == kMessageNormal) { + y = 70 - ((numRows * 9) / 2); + } else if (position == kMessageTop) { + y = 5; + } else { + y = 142; + } + + int message_columns = x - 3; + int message_rows = y - 3; + int message_width = rowWidthMax + 6; + int message_height = numRows * 9 + 5; + saveScreen(message_columns, message_rows, message_width, message_height); + renderBox(message_columns, message_rows, message_width, message_height, kColorWhite35); + for (uint i = 0; i < numRows; ++i) { + renderText(row[i], x, y, textColor); + y += 9; + } + + _messageShown = true; +} + +void Screen::removeMessage() { + if (_messageShown) { + restoreScreen(); + _messageShown = false; + } +} + +void Screen::renderBox(int x, int y, int width, int height, byte color) { + Graphics::Surface *screen = _vm->_system->lockScreen(); + screen->fillRect(Common::Rect(x, y, x + width, y + height), color); + _vm->_system->unlockScreen(); +} + +/*void Screen::renderBox(const GuiElement &guiElement) { + renderBox(guiElement.left, guiElement.top, guiElement.width(), + guiElement.height(), guiElement.getBackgroundColor()); +}*/ + +void Screen::initPalette() { + g_system->getPaletteManager()->setPalette(initVGAPalette, 0, 256); +} + +void Screen::paletteBrightness() { + byte palette[768]; + + _vm->_system->getPaletteManager()->grabPalette(palette, 0, 255); + for (uint i = 0; i < 48; ++i) { + palette[i] = (initVGAPalette[i] * _guiBrightness) >> 8; + } + for (uint i = 0; i < 717; ++i) { + const byte *imagePalette; + if (_currentImage && _currentImage->getPalette()) { + imagePalette = _currentImage->getPalette(); + } else { + imagePalette = palette + 48; + } + palette[i + 48] = (imagePalette[i] * _viewportBrightness) >> 8; + } + _vm->_system->getPaletteManager()->setPalette(palette, 0, 255); +} + +void Screen::paletteFadeOut() { + while (_guiBrightness > 10) { + _guiBrightness -= 10; + if (_viewportBrightness > _guiBrightness) + _viewportBrightness = _guiBrightness; + paletteBrightness(); + _vm->_system->updateScreen(); + _vm->_system->delayMillis(_vm->_delay); + } + _guiBrightness = 0; + _viewportBrightness = 0; + paletteBrightness(); + _vm->_system->updateScreen(); +} + +void Screen::paletteFadeIn(int maxViewportBrightness) { + while (_guiBrightness < 245) { + if (_viewportBrightness < maxViewportBrightness) + _viewportBrightness += 10; + _guiBrightness += 10; + paletteBrightness(); + _vm->_system->updateScreen(); + _vm->_system->delayMillis(_vm->_delay); + } + _guiBrightness = 255; + _viewportBrightness = maxViewportBrightness; + paletteBrightness(); + _vm->_system->updateScreen(); +} + +void Screen::setColor63(byte value) { + byte color[3] = {value, value, value}; + _vm->_system->getPaletteManager()->setPalette(color, 63, 1); +} + +} diff --git a/engines/supernova2/screen.h b/engines/supernova2/screen.h new file mode 100644 index 0000000000..104874c754 --- /dev/null +++ b/engines/supernova2/screen.h @@ -0,0 +1,197 @@ +/* ScummVM - Graphic Adventure Engine +* +* ScummVM is the legal property of its developers, whose names +* are too numerous to list here. Please refer to the COPYRIGHT +* file distributed with this source distribution. +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public License +* as published by the Free Software Foundation; either version 2 +* of the License, or (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +* +*/ + +#ifndef SUPERNOVA2_SCREEN_H +#define SUPERNOVA2_SCREEN_H + +#include "common/array.h" +#include "common/rect.h" +#include "common/scummsys.h" + +#include "supernova2/imageid.h" +#include "supernova2/ms2_def.h" + +namespace Supernova2 { + +class Supernova2Engine; +class GameManager; +class ResourceManager; +//class GuiElement; +class Room; +class MS2Image; +class Screen; + +const int kScreenWidth = 320; +const int kScreenHeight = 200; +const int kFontWidth = 5; +const int kFontHeight = 8; + +enum Color { + kColorBlack = 0, + kColorWhite25 = 1, + kColorWhite35 = 2, + kColorWhite44 = 3, + kColorWhite99 = 4, + kColorDarkGreen = 5, + kColorGreen = 6, + kColorDarkRed = 7, + kColorRed = 8, + kColorDarkBlue = 9, + kColorBlue = 10, + kColorWhite63 = 11, + kColorLightBlue = 12, + kColorLightGreen = 13, + kColorLightYellow = 14, + kColorLightRed = 15, + kColorCursorTransparent = kColorWhite25 +}; + +class ScreenBuffer { + friend class ScreenBufferStack; + +public: + ScreenBuffer(); + +private: + byte *_pixels; + int _x; + int _y; + int _width; + int _height; +}; + +class ScreenBufferStack { +public: + ScreenBufferStack(); + + void push(int x, int y, int width, int height); + void restore(); + +private: + ScreenBuffer _buffer[8]; + ScreenBuffer *_last; +}; + +class Marquee { +public: + enum MarqueeId { + kMarqueeIntro, + kMarqueeOutro + }; + + Marquee(Screen *screen, MarqueeId id, const char *text); + + void renderCharacter(); + +private: + void clearText(); + + Screen *_screen; + const char *const _textBegin; + const char *_text; + bool _loop; + int _delay; + int _color; + int _x; + int _y; + int _textWidth; +}; + +class Screen { + friend class Marquee; + +public: + struct ImageInfo { + int filenumber; + int section; + }; + +public: + static void initPalette(); + static int textWidth(const uint16 key); + static int textWidth(const char *text); + static int textWidth(const Common::String &text); + +public: + Screen(Supernova2Engine *vm, ResourceManager *resMan); + + int getViewportBrightness() const; + void setViewportBrightness(int brightness); + int getGuiBrightness() const; + void setGuiBrightness(int brightness); + const MS2Image *getCurrentImage() const; + const ImageInfo *getImageInfo(ImageId id) const; + bool isMessageShown() const; + void paletteFadeIn(int maxViewportBrightness); + void paletteFadeOut(); + void paletteBrightness(); + void renderImage(ImageId id, bool removeImage = false); + void renderImage(int section); + bool setCurrentImage(int filenumber); + void saveScreen(int x, int y, int width, int height); + //void saveScreen(const GuiElement &guiElement); + void restoreScreen(); + void renderRoom(Room &room); + void renderMessage(const char *text, MessagePosition position = kMessageNormal); + void renderMessage(const Common::String &text, MessagePosition position = kMessageNormal); + void renderMessage(StringId stringId, MessagePosition position = kMessageNormal, + Common::String var1 = "", Common::String var2 = ""); + void removeMessage(); + void renderText(const uint16 character); + void renderText(const char *text); + void renderText(const Common::String &text); + void renderText(StringId stringId); + void renderText(const uint16 character, int x, int y, byte color); + void renderText(const char *text, int x, int y, byte color); + void renderText(const Common::String &text, int x, int y, byte color); + void renderText(StringId stringId, int x, int y, byte color); + //void renderText(const GuiElement &guiElement); + void renderBox(int x, int y, int width, int height, byte color); + //void renderBox(const GuiElement &guiElement); + void setColor63(byte value); + Common::Point getTextCursorPos(); + void setTextCursorPos(int x, int y); + byte getTextCursorColor(); + void setTextCursorColor(byte color); + void update(); + +private: + void renderImageSection(const MS2Image *image, int section, bool invert); + +private: + Supernova2Engine *_vm; + ResourceManager *_resMan; + const MS2Image *_currentImage; + ScreenBufferStack _screenBuffer; + int _screenWidth; + int _screenHeight; + int _textCursorX; + int _textCursorY; + int _textColor; + byte _viewportBrightness; + byte _guiBrightness; + bool _messageShown; +}; + +} + +#endif diff --git a/engines/supernova2/screenstatic.cpp b/engines/supernova2/screenstatic.cpp new file mode 100644 index 0000000000..9c26d58dd7 --- /dev/null +++ b/engines/supernova2/screenstatic.cpp @@ -0,0 +1,329 @@ +/* ScummVM - Graphic Adventure Engine +* +* ScummVM is the legal property of its developers, whose names +* are too numerous to list here. Please refer to the COPYRIGHT +* file distributed with this source distribution. +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public License +* as published by the Free Software Foundation; either version 2 +* of the License, or (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +* +*/ + +namespace Supernova2 { + +static const Screen::ImageInfo imageInfo[] = { + { 0, 0}, { 0, 1}, { 0, 2}, + { 1, 0}, + { 2, 0}, + { 3, 0}, { 3, 1}, { 3, 2}, { 3, 3}, { 3, 4}, { 3, 5}, + { 3, 6}, { 3, 7}, { 3, 8}, { 3, 9}, { 3, 10}, { 3, 11}, + { 4, 0}, { 4, 1}, { 4, 2}, { 4, 3}, + { 5, 0}, { 5, 1}, { 5, 2}, { 5, 3}, { 5, 4}, { 5, 5}, + { 5, 6}, { 5, 7}, { 5, 8}, { 5, 9}, + { 6, 0}, { 6, 1}, { 6, 2}, { 6, 3}, { 6, 4}, { 6, 5}, + { 6, 6}, { 6, 7}, { 6, 8}, { 6, 9}, { 6, 10}, { 6, 11}, + { 6, 12}, { 6, 13}, { 6, 14}, { 6, 15}, { 6, 16}, { 6, 17}, + { 6, 18}, { 6, 19}, { 6, 20}, { 6, 21}, + { 7, 0}, { 7, 1}, { 7, 2}, { 7, 3}, { 7, 4}, { 7, 5}, + { 7, 6}, { 7, 7}, { 7, 8}, { 7, 9}, { 7, 10}, { 7, 11}, + { 7, 12}, { 7, 13}, { 7, 14}, { 7, 15}, { 7, 16}, { 7, 17}, + { 7, 18}, { 7, 19}, { 7, 20}, { 7, 21}, { 7, 22}, + { 8, 0}, { 8, 1}, { 8, 2}, { 8, 3}, { 8, 4}, { 8, 5}, + { 8, 6}, { 8, 7}, { 8, 8}, { 8, 9}, { 8, 10}, { 8, 11}, + { 8, 12}, + { 9, 0}, { 9, 1}, { 9, 2}, { 9, 3}, { 9, 4}, { 9, 5}, + { 9, 6}, { 9, 7}, { 9, 8}, { 9, 9}, { 9, 10}, { 9, 11}, + { 9, 12}, { 9, 13}, { 9, 14}, { 9, 15}, { 9, 16}, { 9, 17}, + { 9, 18}, { 9, 19}, { 9, 20}, { 9, 21}, { 9, 22}, { 9, 23}, + {10, 0}, {10, 1}, {10, 2}, {10, 3}, {10, 4}, {10, 5}, + {10, 6}, {10, 7}, {10, 8}, {10, 9}, {10, 10}, {10, 11}, + {10, 12}, {10, 13}, {10, 14}, {10, 15}, {10, 16}, + {11, 0}, + {12, 0}, {12, 1}, {12, 2}, {12, 3}, + {13, 0}, {13, 1}, {13, 2}, {13, 3}, {13, 4}, {13, 5}, + {13, 6}, {13, 7}, {13, 8}, {13, 9}, {13, 10}, {13, 11}, + {13, 12}, {13, 13}, + {14, 0}, {14, 1}, {14, 2}, {14, 3}, {14, 4}, {14, 5}, + {14, 6}, {14, 7}, {14, 8}, {14, 9}, {14, 10}, {14, 11}, + {14, 12}, {14, 13}, {14, 14}, {14, 15}, {14, 16}, {14, 17}, + {14, 18}, {14, 19}, + {15, 0}, {15, 1}, {15, 2}, {15, 3}, {15, 4}, {15, 5}, + {16, 0}, {16, 1}, {16, 2}, {16, 3}, {16, 4}, {16, 5}, + {16, 6}, {16, 7}, {16, 8}, {16, 9}, {16, 10}, {16, 11}, + {16, 12}, {16, 13}, {16, 14}, {16, 15}, {16, 16}, {16, 17}, + {16, 18}, {16, 19}, {16, 20}, {16, 21}, {16, 22}, {16, 23}, + {16, 24}, {16, 25}, {16, 26}, {16, 27}, {16, 28}, {16, 29}, + {16, 30}, {16, 31}, {16, 32}, {16, 33}, + {17, 0}, {17, 1}, {17, 2}, {17, 3}, {17, 4}, {17, 5}, + {17, 6}, {17, 7}, {17, 8}, {17, 9}, {17, 10}, {17, 11}, + {17, 12}, {17, 13}, {17, 14}, {17, 15}, + {18, 0}, {18, 1}, {18, 2}, {18, 3}, {18, 4}, {18, 5}, + {18, 6}, {18, 7}, {18, 8}, {18, 9}, {18, 10}, {18, 11}, + {18, 12}, {18, 13}, {18, 14}, {18, 15}, {18, 16}, {18, 17}, + {18, 18}, {18, 19}, {18, 20}, {18, 21}, + {19, 0}, {19, 1}, {19, 2}, {19, 3}, {19, 4}, {19, 5}, + {19, 6}, {19, 7}, {19, 8}, {19, 9}, {19, 10}, {19, 11}, + {19, 12}, {19, 13}, {19, 14}, {19, 15}, {19, 16}, {19, 17}, + {19, 18}, {19, 19}, {19, 20}, {19, 21}, {19, 22}, {19, 23}, + {19, 24}, {19, 25}, {19, 26}, {19, 27}, {19, 28}, {19, 29}, + {19, 30}, {19, 31}, {19, 32}, {19, 33}, {19, 34}, {19, 35}, + {19, 36}, {19, 37}, {19, 38}, {19, 39}, {19, 40}, + {20, 0}, + {21, 0}, {21, 1}, {21, 2}, {21, 3}, {21, 4}, {21, 5}, + {21, 6}, {21, 7}, {21, 8}, {21, 9}, {21, 10}, {21, 11}, + {21, 12}, {21, 13}, {21, 14}, {21, 15}, {21, 16}, {21, 17}, + {21, 18}, {21, 19}, {21, 20}, {21, 21}, {21, 22}, {21, 23}, + {21, 24}, {21, 25}, {21, 26}, {21, 27}, {21, 28}, {21, 29}, + {21, 30}, {21, 31}, {21, 32}, {21, 33}, {21, 34}, {21, 35}, + {21, 36}, {21, 37}, {21, 38}, + {22, 0}, {22, 1}, {22, 2}, {22, 3}, {22, 4}, {22, 5}, + {22, 6}, {22, 7}, {22, 8}, {22, 9}, {22, 10}, {22, 11}, + {22, 12}, {22, 13}, {22, 14}, {22, 15}, {22, 16}, {22, 17}, + {22, 18}, + {23, 0}, + {24, 0}, {24, 1}, {24, 2}, {24, 3}, {24, 4}, {24, 5}, + {24, 6}, {24, 7}, {24, 8}, + {25, 0}, {25, 1}, {25, 2}, {25, 3}, {25, 4}, {25, 5}, + {25, 6}, {25, 7}, {25, 8}, {25, 9}, {25, 10}, {25, 11}, + {25, 12}, {25, 13}, {25, 14}, {25, 15}, {25, 16}, {25, 17}, + {25, 18}, + {26, 0}, + {27, 0}, + {28, 0}, {28, 1}, {28, 2}, {28, 3}, {28, 4}, {28, 5}, + {28, 6}, {28, 7}, {28, 8}, {28, 9}, {28, 10}, {28, 11}, + {28, 12}, {28, 13}, {28, 14}, {28, 15}, {28, 16}, {28, 17}, + {28, 18}, {28, 19}, {28, 20}, {28, 21}, {28, 22}, + {29, 0}, {29, 1}, {29, 2}, {29, 3}, {29, 4}, {29, 5}, + {29, 6}, {29, 7}, {29, 8}, {29, 9}, {29, 10}, {29, 11}, + {29, 12}, {29, 13}, + {30, 0}, {30, 1}, + {31, 0}, {31, 1}, {31, 2}, {31, 3}, {31, 4}, {31, 5}, + {31, 6}, + {32, 0}, {32, 1}, {32, 2}, {32, 3}, + {33, 0}, {33, 1}, {33, 2}, {33, 3}, {33, 4}, {33, 5}, + {34, 0}, {34, 1}, {34, 2}, {34, 3}, {34, 4}, {34, 5}, + {34, 6}, {34, 7}, {34, 8}, {34, 9}, {34, 10}, {34, 11}, + {34, 12}, {34, 13}, {34, 14}, {34, 15}, {34, 16}, {34, 17}, + {35, 0}, {35, 1}, {35, 2}, {35, 3}, {35, 4}, {35, 5}, + {35, 6}, {35, 7}, {35, 8}, {35, 9}, {35, 10}, {35, 11}, + {35, 12}, {35, 13}, {35, 14}, {35, 15}, {35, 16}, {35, 17}, + {35, 18}, {35, 19}, {35, 20}, {35, 21}, + {36, 0}, {36, 1}, {36, 2}, {36, 3}, {36, 4}, {36, 5}, + {37, 0}, {37, 1}, {37, 2}, {37, 3}, {37, 4}, {37, 5}, + {37, 6}, {37, 7}, {37, 8}, {37, 9}, {37, 10}, {37, 11}, + {37, 12}, {37, 13}, {37, 14}, {37, 15}, {37, 16}, {37, 17}, + {37, 18}, {37, 19}, {37, 20}, {37, 21}, {37, 22}, {37, 23}, + {37, 24}, {37, 25}, {37, 26}, + {38, 0}, {38, 1}, {38, 2}, {38, 3}, {38, 4}, {38, 5}, + {38, 6}, {38, 7}, {38, 8}, {38, 9}, {38, 10}, {38, 11}, + {38, 12}, + {39, 0}, + {40, 0}, {40, 1}, {40, 2}, {40, 3}, {40, 4}, {40, 5}, + {40, 6}, {40, 7}, + {41, 0}, {41, 1}, {41, 2}, {41, 3}, + {42, 0}, {42, 1}, {42, 2}, {42, 3}, {42, 4}, {42, 5}, + {42, 6}, {42, 7}, {42, 8}, {42, 9}, {42, 10}, {42, 11}, + {43, 0}, {43, 1}, {43, 2}, {43, 3}, {43, 4}, {43, 5}, + {43, 6}, {43, 7}, {43, 8}, {43, 9}, {43, 10}, {43, 11}, + {43, 12}, {43, 13}, {43, 14}, {43, 15}, {43, 16}, {43, 17}, + {43, 18}, {43, 19}, {43, 20}, {43, 21}, {43, 22}, {43, 23}, + {43, 24}, {43, 25}, {43, 26}, {43, 27}, {43, 28}, {43, 29}, + {43, 30}, {43, 31}, + {55, 0} +}; + +// Default palette +static const byte initVGAPalette[768] = { + 0x00, 0x00, 0x00, 0x40, 0x40, 0x40, 0x58, 0x58, 0x58, 0x70, 0x70, 0x70, 0xfc, 0xfc, 0xfc, 0x00, 0xd0, 0x00, + 0x00, 0xfc, 0x00, 0xd8, 0x00, 0x00, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0xb0, 0xa0, 0xa0, 0xa0, + 0x50, 0xc8, 0xfc, 0x28, 0xfc, 0x28, 0xf0, 0xf0, 0x00, 0xfc, 0x28, 0x28, 0x00, 0x00, 0x00, 0x14, 0x14, 0x14, + 0x20, 0x20, 0x20, 0x2c, 0x2c, 0x2c, 0x38, 0x38, 0x38, 0x44, 0x44, 0x44, 0x50, 0x50, 0x50, 0x60, 0x60, 0x60, + 0x70, 0x70, 0x70, 0x80, 0x80, 0x80, 0x90, 0x90, 0x90, 0xa0, 0xa0, 0xa0, 0xb4, 0xb4, 0xb4, 0xc8, 0xc8, 0xc8, + 0xe0, 0xe0, 0xe0, 0xfc, 0xfc, 0xfc, 0x00, 0x00, 0xfc, 0x40, 0x00, 0xfc, 0x7c, 0x00, 0xfc, 0xbc, 0x00, 0xfc, + 0xfc, 0x00, 0xfc, 0xfc, 0x00, 0xbc, 0xfc, 0x00, 0x7c, 0xfc, 0x00, 0x40, 0xfc, 0x00, 0x00, 0xfc, 0x40, 0x00, + 0xfc, 0x7c, 0x00, 0xfc, 0xbc, 0x00, 0xfc, 0xfc, 0x00, 0xbc, 0xfc, 0x00, 0x7c, 0xfc, 0x00, 0x40, 0xfc, 0x00, + 0x00, 0xfc, 0x00, 0x00, 0xfc, 0x40, 0x00, 0xfc, 0x7c, 0x00, 0xfc, 0xbc, 0x00, 0xfc, 0xfc, 0x00, 0xbc, 0xfc, + 0x00, 0x7c, 0xfc, 0x00, 0x40, 0xfc, 0x7c, 0x7c, 0xfc, 0x9c, 0x7c, 0xfc, 0xbc, 0x7c, 0xfc, 0xdc, 0x7c, 0xfc, + 0xfc, 0x7c, 0xfc, 0xfc, 0x7c, 0xdc, 0xfc, 0x7c, 0xbc, 0xfc, 0x7c, 0x9c, 0xfc, 0x7c, 0x7c, 0xfc, 0x9c, 0x7c, + 0xfc, 0xbc, 0x7c, 0xfc, 0xdc, 0x7c, 0xfc, 0xfc, 0x7c, 0xdc, 0xfc, 0x7c, 0xbc, 0xfc, 0x7c, 0x9c, 0xfc, 0x7c, + 0x7c, 0xfc, 0x7c, 0x7c, 0xfc, 0x9c, 0x7c, 0xfc, 0xbc, 0x7c, 0xfc, 0xdc, 0x7c, 0xfc, 0xfc, 0x7c, 0xdc, 0xfc, + 0x7c, 0xbc, 0xfc, 0x7c, 0x9c, 0xfc, 0xb4, 0xb4, 0xfc, 0xc4, 0xb4, 0xfc, 0xd8, 0xb4, 0xfc, 0xe8, 0xb4, 0xfc, + 0xfc, 0xb4, 0xfc, 0xfc, 0xb4, 0xe8, 0xfc, 0xb4, 0xd8, 0xfc, 0xb4, 0xc4, 0xfc, 0xb4, 0xb4, 0xfc, 0xc4, 0xb4, + 0xfc, 0xd8, 0xb4, 0xfc, 0xe8, 0xb4, 0xfc, 0xfc, 0xb4, 0xe8, 0xfc, 0xb4, 0xd8, 0xfc, 0xb4, 0xc4, 0xfc, 0xb4, + 0xb4, 0xfc, 0xb4, 0xb4, 0xfc, 0xc4, 0xb4, 0xfc, 0xd8, 0xb4, 0xfc, 0xe8, 0xb4, 0xfc, 0xfc, 0xb4, 0xe8, 0xfc, + 0xb4, 0xd8, 0xfc, 0xb4, 0xc4, 0xfc, 0x00, 0x00, 0x70, 0x1c, 0x00, 0x70, 0x38, 0x00, 0x70, 0x54, 0x00, 0x70, + 0x70, 0x00, 0x70, 0x70, 0x00, 0x54, 0x70, 0x00, 0x38, 0x70, 0x00, 0x1c, 0x70, 0x00, 0x00, 0x70, 0x1c, 0x00, + 0x70, 0x38, 0x00, 0x70, 0x54, 0x00, 0x70, 0x70, 0x00, 0x54, 0x70, 0x00, 0x38, 0x70, 0x00, 0x1c, 0x70, 0x00, + 0x00, 0x70, 0x00, 0x00, 0x70, 0x1c, 0x00, 0x70, 0x38, 0x00, 0x70, 0x54, 0x00, 0x70, 0x70, 0x00, 0x54, 0x70, + 0x00, 0x38, 0x70, 0x00, 0x1c, 0x70, 0x38, 0x38, 0x70, 0x44, 0x38, 0x70, 0x54, 0x38, 0x70, 0x60, 0x38, 0x70, + 0x70, 0x38, 0x70, 0x70, 0x38, 0x60, 0x70, 0x38, 0x54, 0x70, 0x38, 0x44, 0x70, 0x38, 0x38, 0x70, 0x44, 0x38, + 0x70, 0x54, 0x38, 0x70, 0x60, 0x38, 0x70, 0x70, 0x38, 0x60, 0x70, 0x38, 0x54, 0x70, 0x38, 0x44, 0x70, 0x38, + 0x38, 0x70, 0x38, 0x38, 0x70, 0x44, 0x38, 0x70, 0x54, 0x38, 0x70, 0x60, 0x38, 0x70, 0x70, 0x38, 0x60, 0x70, + 0x38, 0x54, 0x70, 0x38, 0x44, 0x70, 0x50, 0x50, 0x70, 0x58, 0x50, 0x70, 0x60, 0x50, 0x70, 0x68, 0x50, 0x70, + 0x70, 0x50, 0x70, 0x70, 0x50, 0x68, 0x70, 0x50, 0x60, 0x70, 0x50, 0x58, 0x70, 0x50, 0x50, 0x70, 0x58, 0x50, + 0x70, 0x60, 0x50, 0x70, 0x68, 0x50, 0x70, 0x70, 0x50, 0x68, 0x70, 0x50, 0x60, 0x70, 0x50, 0x58, 0x70, 0x50, + 0x50, 0x70, 0x50, 0x50, 0x70, 0x58, 0x50, 0x70, 0x60, 0x50, 0x70, 0x68, 0x50, 0x70, 0x70, 0x50, 0x68, 0x70, + 0x50, 0x60, 0x70, 0x50, 0x58, 0x70, 0x00, 0x00, 0x40, 0x10, 0x00, 0x40, 0x20, 0x00, 0x40, 0x30, 0x00, 0x40, + 0x40, 0x00, 0x40, 0x40, 0x00, 0x30, 0x40, 0x00, 0x20, 0x40, 0x00, 0x10, 0x40, 0x00, 0x00, 0x40, 0x10, 0x00, + 0x40, 0x20, 0x00, 0x40, 0x30, 0x00, 0x40, 0x40, 0x00, 0x30, 0x40, 0x00, 0x20, 0x40, 0x00, 0x10, 0x40, 0x00, + 0x00, 0x40, 0x00, 0x00, 0x40, 0x10, 0x00, 0x40, 0x20, 0x00, 0x40, 0x30, 0x00, 0x40, 0x40, 0x00, 0x30, 0x40, + 0x00, 0x20, 0x40, 0x00, 0x10, 0x40, 0x20, 0x20, 0x40, 0x28, 0x20, 0x40, 0x30, 0x20, 0x40, 0x38, 0x20, 0x40, + 0x40, 0x20, 0x40, 0x40, 0x20, 0x38, 0x40, 0x20, 0x30, 0x40, 0x20, 0x28, 0x40, 0x20, 0x20, 0x40, 0x28, 0x20, + 0x40, 0x30, 0x20, 0x40, 0x38, 0x20, 0x40, 0x40, 0x20, 0x38, 0x40, 0x20, 0x30, 0x40, 0x20, 0x28, 0x40, 0x20, + 0x20, 0x40, 0x20, 0x20, 0x40, 0x28, 0x20, 0x40, 0x30, 0x20, 0x40, 0x38, 0x20, 0x40, 0x40, 0x20, 0x38, 0x40, + 0x20, 0x30, 0x40, 0x20, 0x28, 0x40, 0x2c, 0x2c, 0x40, 0x30, 0x2c, 0x40, 0x34, 0x2c, 0x40, 0x3c, 0x2c, 0x40, + 0x40, 0x2c, 0x40, 0x40, 0x2c, 0x3c, 0x40, 0x2c, 0x34, 0x40, 0x2c, 0x30, 0x40, 0x2c, 0x2c, 0x40, 0x30, 0x2c, + 0x40, 0x34, 0x2c, 0x40, 0x3c, 0x2c, 0x40, 0x40, 0x2c, 0x3c, 0x40, 0x2c, 0x34, 0x40, 0x2c, 0x30, 0x40, 0x2c, + 0x2c, 0x40, 0x2c, 0x2c, 0x40, 0x30, 0x2c, 0x40, 0x34, 0x2c, 0x40, 0x3c, 0x2c, 0x40, 0x40, 0x2c, 0x3c, 0x40, + 0x2c, 0x34, 0x40, 0x2c, 0x30, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; + +static const byte font[][5] = { + {0x00,0x00,0x00,0xff,0x00}, + {0x5f,0xff,0x00,0x00,0x00}, + {0x03,0x00,0x03,0xff,0x00}, + {0x14,0x7f,0x14,0x7f,0x14}, + {0x24,0x2a,0x7f,0x2a,0x12}, + {0x61,0x10,0x08,0x04,0x43}, + {0x38,0x4e,0x59,0x26,0x50}, + {0x03,0xff,0x00,0x00,0x00}, + {0x3e,0x41,0xff,0x00,0x00}, + {0x41,0x3e,0xff,0x00,0x00}, + {0x10,0x54,0x38,0x54,0x10}, + {0x10,0x10,0x7c,0x10,0x10}, + {0x80,0x40,0xff,0x00,0x00}, + {0x10,0x10,0x10,0x10,0x10}, + {0x40,0xff,0x00,0x00,0x00}, + {0x60,0x10,0x08,0x04,0x03}, + + {0x3e,0x41,0x41,0x41,0x3e}, /* digits */ + {0x04,0x02,0x7f,0xff,0x00}, + {0x42,0x61,0x51,0x49,0x46}, + {0x22,0x41,0x49,0x49,0x36}, + {0x18,0x14,0x12,0x7f,0x10}, + {0x27,0x45,0x45,0x45,0x39}, + {0x3e,0x49,0x49,0x49,0x32}, + {0x01,0x61,0x19,0x07,0x01}, + {0x36,0x49,0x49,0x49,0x36}, + {0x26,0x49,0x49,0x49,0x3e}, + + {0x44,0xff,0x00,0x00,0x00}, + {0x80,0x44,0xff,0x00,0x00}, + {0x10,0x28,0x44,0xff,0x00}, + {0x28,0x28,0x28,0x28,0x28}, + {0x44,0x28,0x10,0xff,0x00}, + {0x02,0x01,0x51,0x09,0x06}, + {0x3e,0x41,0x5d,0x5d,0x1e}, + + {0x7c,0x12,0x11,0x12,0x7c}, /* uppercase letters*/ + {0x7f,0x49,0x49,0x49,0x36}, + {0x3e,0x41,0x41,0x41,0x22}, + {0x7f,0x41,0x41,0x22,0x1c}, + {0x7f,0x49,0x49,0x49,0xff}, + {0x7f,0x09,0x09,0x09,0xff}, + {0x3e,0x41,0x41,0x49,0x3a}, + {0x7f,0x08,0x08,0x08,0x7f}, + {0x41,0x7f,0x41,0xff,0x00}, + {0x20,0x40,0x40,0x3f,0xff}, + {0x7f,0x08,0x14,0x22,0x41}, + {0x7f,0x40,0x40,0x40,0xff}, + {0x7f,0x02,0x04,0x02,0x7f}, + {0x7f,0x02,0x0c,0x10,0x7f}, + {0x3e,0x41,0x41,0x41,0x3e}, + {0x7f,0x09,0x09,0x09,0x06}, + {0x3e,0x41,0x51,0x21,0x5e}, + {0x7f,0x09,0x19,0x29,0x46}, + {0x26,0x49,0x49,0x49,0x32}, + {0x01,0x01,0x7f,0x01,0x01}, + {0x3f,0x40,0x40,0x40,0x3f}, + {0x07,0x18,0x60,0x18,0x07}, + {0x1f,0x60,0x18,0x60,0x1f}, + {0x63,0x14,0x08,0x14,0x63}, + {0x03,0x04,0x78,0x04,0x03}, + {0x61,0x51,0x49,0x45,0x43}, + + {0x7f,0x41,0x41,0xff,0x00}, + {0x03,0x04,0x08,0x10,0x60}, + {0x41,0x41,0x7f,0xff,0x00}, + {0x02,0x01,0x02,0xff,0x00}, + {0x80,0x80,0x80,0x80,0x80}, + {0x01,0x02,0xff,0x00,0x00}, + + {0x38,0x44,0x44,0x44,0x7c}, /* lowercase letters */ + {0x7f,0x44,0x44,0x44,0x38}, + {0x38,0x44,0x44,0x44,0x44}, + {0x38,0x44,0x44,0x44,0x7f}, + {0x38,0x54,0x54,0x54,0x58}, + {0x04,0x7e,0x05,0x01,0xff}, + {0x98,0xa4,0xa4,0xa4,0x7c}, + {0x7f,0x04,0x04,0x04,0x78}, + {0x7d,0xff,0x00,0x00,0x00}, + {0x80,0x80,0x7d,0xff,0x00}, + {0x7f,0x10,0x28,0x44,0xff}, + {0x7f,0xff,0x00,0x00,0x00}, + {0x7c,0x04,0x7c,0x04,0x78}, + {0x7c,0x04,0x04,0x04,0x78}, + {0x38,0x44,0x44,0x44,0x38}, + {0xfc,0x24,0x24,0x24,0x18}, + {0x18,0x24,0x24,0x24,0xfc}, + {0x7c,0x08,0x04,0x04,0xff}, + {0x48,0x54,0x54,0x54,0x24}, + {0x04,0x3e,0x44,0x40,0xff}, + {0x7c,0x40,0x40,0x40,0x3c}, + {0x0c,0x30,0x40,0x30,0x0c}, + {0x3c,0x40,0x3c,0x40,0x3c}, + {0x44,0x28,0x10,0x28,0x44}, + {0x9c,0xa0,0xa0,0xa0,0x7c}, + {0x44,0x64,0x54,0x4c,0x44}, + + {0x08,0x36,0x41,0xff,0x00}, + {0x77,0xff,0x00,0x00,0x00}, + {0x41,0x36,0x08,0xff,0x00}, + {0x02,0x01,0x02,0x01,0xff}, + {0xff,0x00,0x00,0x00,0x00}, + + {0xfe,0x49,0x49,0x4e,0x30}, /* sharp S */ + + {0x7c,0x41,0x40,0x41,0x3c}, /* umlauts */ + + {0x04,0x06,0x7f,0x06,0x04}, /* arrows */ + {0x20,0x60,0xfe,0x60,0x20}, + + {0x38,0x45,0x44,0x45,0x7c}, /* umlauts */ + {0xff,0x00,0x00,0x00,0x00}, + {0xff,0x00,0x00,0x00,0x00}, + {0xff,0x00,0x00,0x00,0x00}, + {0xff,0x00,0x00,0x00,0x00}, + {0xff,0x00,0x00,0x00,0x00}, + {0xff,0x00,0x00,0x00,0x00}, + {0xff,0x00,0x00,0x00,0x00}, + {0xff,0x00,0x00,0x00,0x00}, + {0xff,0x00,0x00,0x00,0x00}, + {0x79,0x14,0x12,0x14,0x79}, + {0xff,0x00,0x00,0x00,0x00}, + {0xff,0x00,0x00,0x00,0x00}, + {0xff,0x00,0x00,0x00,0x00}, + {0xff,0x00,0x00,0x00,0x00}, + {0xff,0x00,0x00,0x00,0x00}, + {0x38,0x45,0x44,0x45,0x38}, + {0xff,0x00,0x00,0x00,0x00}, + {0xff,0x00,0x00,0x00,0x00}, + {0xff,0x00,0x00,0x00,0x00}, + {0xff,0x00,0x00,0x00,0x00}, + {0x3d,0x42,0x42,0x42,0x3d}, + {0x3d,0x40,0x40,0x40,0x3d}, +}; + +} diff --git a/engines/supernova2/state.cpp b/engines/supernova2/state.cpp index 357a166ca7..4dd24a5e82 100644 --- a/engines/supernova2/state.cpp +++ b/engines/supernova2/state.cpp @@ -25,7 +25,7 @@ #include "graphics/palette.h" #include "gui/message.h" -//#include "supernova2/screen.h" +#include "supernova2/screen.h" #include "supernova2/supernova2.h" #include "supernova2/state.h" diff --git a/engines/supernova2/state.h b/engines/supernova2/state.h index 5c8cec4832..7665d22807 100644 --- a/engines/supernova2/state.h +++ b/engines/supernova2/state.h @@ -26,8 +26,8 @@ #include "common/events.h" #include "common/rect.h" #include "common/keyboard.h" -//#include "supernova/rooms.h" -//#include "supernova/sound.h" +#include "supernova2/rooms.h" +//#include "supernova2/sound.h" namespace Supernova2 { @@ -71,4 +71,4 @@ private: } -#endif // SUPERNOVA_STATE_H +#endif // SUPERNOVA2_STATE_H |