From 84784add6811aa1b285b70e139d0bdf9738c858c Mon Sep 17 00:00:00 2001 From: Kamil Zbróg Date: Mon, 28 Oct 2013 00:06:21 +0000 Subject: PRINCE: midi music player added. mob and object lists added --- engines/prince/debugger.cpp | 27 +++++++ engines/prince/debugger.h | 2 + engines/prince/font.cpp | 20 +++-- engines/prince/graphics.cpp | 15 ++-- engines/prince/graphics.h | 1 - engines/prince/mhwanh.h | 3 +- engines/prince/mob.cpp | 63 +++++++++++++++ engines/prince/mob.h | 48 +++++++++++ engines/prince/module.mk | 3 + engines/prince/object.cpp | 77 ++++++++++++++++++ engines/prince/object.h | 47 +++++++++++ engines/prince/prince.cpp | 193 +++++++++++++++++++++++++++++++++++++++++--- engines/prince/prince.h | 12 +++ engines/prince/script.cpp | 173 ++++++++++++++++++++++++++++++++------- engines/prince/sound.cpp | 160 ++++++++++++++++++++++++++++++++++++ engines/prince/sound.h | 73 +++++++++++++++++ 16 files changed, 864 insertions(+), 53 deletions(-) create mode 100644 engines/prince/mob.cpp create mode 100644 engines/prince/mob.h create mode 100644 engines/prince/object.cpp create mode 100644 engines/prince/object.h create mode 100644 engines/prince/sound.cpp create mode 100644 engines/prince/sound.h diff --git a/engines/prince/debugger.cpp b/engines/prince/debugger.cpp index 5da11acd88..817e4fb2b5 100644 --- a/engines/prince/debugger.cpp +++ b/engines/prince/debugger.cpp @@ -31,6 +31,8 @@ Debugger::Debugger(PrinceEngine *vm) : GUI::Debugger(), _vm(vm) { DCmd_Register("getflag", WRAP_METHOD(Debugger, Cmd_GetFlag)); DCmd_Register("clearflag", WRAP_METHOD(Debugger, Cmd_ClearFlag)); DCmd_Register("viewflc", WRAP_METHOD(Debugger, Cmd_ViewFlc)); + DCmd_Register("initroom", WRAP_METHOD(Debugger, Cmd_InitRoom)); + DCmd_Register("changecursor", WRAP_METHOD(Debugger, Cmd_ChangeCursor)); } static int strToInt(const char *s) { @@ -108,4 +110,29 @@ bool Debugger::Cmd_ViewFlc(int argc, const char **argv) { _vm->loadAnim(flagNum); return true; } + +bool Debugger::Cmd_InitRoom(int argc, const char **argv) { + // Check for a flag to clear + if (argc != 2) { + DebugPrintf("Usage: %s \n", argv[0]); + return true; + } + + int flagNum = strToInt(argv[1]); + _vm->loadLocation(flagNum); + return true; +} + +bool Debugger::Cmd_ChangeCursor(int argc, const char **argv) { + // Check for a flag to clear + if (argc != 2) { + DebugPrintf("Usage: %s \n", argv[0]); + return true; + } + + int flagNum = strToInt(argv[1]); + _vm->changeCursor(flagNum); + return true; +} + } diff --git a/engines/prince/debugger.h b/engines/prince/debugger.h index c5a8be60c6..dabcd970ea 100644 --- a/engines/prince/debugger.h +++ b/engines/prince/debugger.h @@ -40,6 +40,8 @@ private: bool Cmd_GetFlag(int argc, const char **argv); bool Cmd_ClearFlag(int argc, const char **argv); bool Cmd_ViewFlc(int argc, const char **argv); + bool Cmd_InitRoom(int argc, const char **argv); + bool Cmd_ChangeCursor(int argc, const char **argv); PrinceEngine *_vm; }; diff --git a/engines/prince/font.cpp b/engines/prince/font.cpp index 8c72f1b912..aac790dfe0 100644 --- a/engines/prince/font.cpp +++ b/engines/prince/font.cpp @@ -46,7 +46,6 @@ bool Font::load(Common::SeekableReadStream &stream) { } int Font::getFontHeight() const { - debug("Font::getFontHeight %d", _fontData[5]); return _fontData[5]; } @@ -70,15 +69,20 @@ int Font::getCharWidth(byte chr) const { return getChrData(chr)._width; } -void Font::drawChar(Graphics::Surface *dst, byte chr, int x, int y, uint32 color) const { +void Font::drawChar(Graphics::Surface *dst, byte chr, int posX, int posY, uint32 color) const { const ChrData chrData = getChrData(chr); - const byte *src = chrData._pixels; - byte *target = (byte *)dst->getBasePtr(x, y); - for (int i = 0; i < chrData._height; i++) { - memcpy(target, src, chrData._width); - src += chrData._width; - target += dst->pitch; + for (int y = 0; y < chrData._height; ++y) { + for (int x = 0; x < chrData._width; ++x) { + byte d = chrData._pixels[x + (chrData._width * y)]; + if (d == 0) d = 255; + else if (d == 1) d = 0; + else if (d == 2) d = color; + else if (d == 3) d = 0; + if (d != 255) { + *(byte*)dst->getBasePtr(posX + x, posY + y) = d; + } + } } } diff --git a/engines/prince/graphics.cpp b/engines/prince/graphics.cpp index 74b46aad4c..94cab7bb37 100644 --- a/engines/prince/graphics.cpp +++ b/engines/prince/graphics.cpp @@ -40,6 +40,7 @@ void GraphicsMan::update() { _vm->_system->copyRectToScreen((byte*)_frontScreen->getBasePtr(0,0), 640, 0, 0, 640, 480); _vm->_system->updateScreen(); + _changed = false; } } @@ -53,15 +54,19 @@ void GraphicsMan::change() { void GraphicsMan::draw(const Graphics::Surface *s) { - for (uint y = 0; y < 480; y++) - memcpy((byte*)_frontScreen->getBasePtr(0, y), (byte*)s->getBasePtr(0, y), 640); - change(); + uint16 w = MIN(_frontScreen->w, s->w); + for (uint y = 0; y < s->h; y++) { + if (y < _frontScreen->h) { + memcpy((byte*)_frontScreen->getBasePtr(0, y), (byte*)s->getBasePtr(0, y), w); + } + } + change(); } void GraphicsMan::drawTransparent(const Graphics::Surface *s) { - for (uint y = 0; y < 480; ++y) { - for (uint x = 0; x < 640; ++x) { + for (uint y = 0; y < s->h; ++y) { + for (uint x = 0; x < s->w; ++x) { byte pixel = *((byte*)s->getBasePtr(x,y)); if (pixel != 255) { *((byte*)_frontScreen->getBasePtr(x, y)) = pixel; diff --git a/engines/prince/graphics.h b/engines/prince/graphics.h index 0f12c734c6..0e29c5c97a 100644 --- a/engines/prince/graphics.h +++ b/engines/prince/graphics.h @@ -53,7 +53,6 @@ private: PrinceEngine *_vm; bool _changed; - byte _palette[3 * 256]; }; } diff --git a/engines/prince/mhwanh.h b/engines/prince/mhwanh.h index 21822759e8..24472da7a5 100644 --- a/engines/prince/mhwanh.h +++ b/engines/prince/mhwanh.h @@ -28,8 +28,7 @@ namespace Prince { -class MhwanhDecoder : public Graphics::ImageDecoder -{ +class MhwanhDecoder : public Graphics::ImageDecoder { public: MhwanhDecoder(); virtual ~MhwanhDecoder(); diff --git a/engines/prince/mob.cpp b/engines/prince/mob.cpp new file mode 100644 index 0000000000..caf44fef12 --- /dev/null +++ b/engines/prince/mob.cpp @@ -0,0 +1,63 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#include "prince/mob.h" + +#include "common/stream.h" + +namespace Prince { + +bool Mob::loadFromStream(Common::SeekableReadStream &stream) { + int32 pos = stream.pos(); + + uint16 visible = stream.readUint16LE(); + + if (visible == 0xFFFF) + return false; + + _visible = visible; + _type = stream.readUint16LE(); + _rect.left = stream.readUint16LE(); + _rect.top = stream.readUint16LE(); + _rect.right = stream.readUint16LE(); + _rect.bottom = stream.readUint16LE(); + + stream.skip(6 * sizeof(uint16)); + uint32 nameOffset = stream.readUint32LE(); + uint32 examTextOffset = stream.readUint32LE(); + + byte c; + stream.seek(nameOffset); + _name.clear(); + while ((c = stream.readByte())) + _name += c; + + stream.seek(examTextOffset); + _examText.clear(); + while ((c = stream.readByte())) + _examText += c; + stream.seek(pos + 32); + + return true; +} + +} diff --git a/engines/prince/mob.h b/engines/prince/mob.h new file mode 100644 index 0000000000..5b2a6f9d6e --- /dev/null +++ b/engines/prince/mob.h @@ -0,0 +1,48 @@ +/* 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/rect.h" +#include "common/str.h" + +namespace Common { + class SeekableReadStream; +} + +namespace Prince { + +class Mob { +public: + Mob() {} + + bool loadFromStream(Common::SeekableReadStream &stream); + + + bool _visible; + uint16 _type; + Common::Rect _rect; + Common::String _name; + Common::String _examText; +}; + +} + diff --git a/engines/prince/module.mk b/engines/prince/module.mk index a177e670ed..6b519d4d57 100644 --- a/engines/prince/module.mk +++ b/engines/prince/module.mk @@ -7,6 +7,9 @@ MODULE_OBJS = \ mhwanh.o \ detection.o \ font.o \ + mob.o \ + object.o \ + sound.o \ prince.o # This module can be built as a plugin diff --git a/engines/prince/object.cpp b/engines/prince/object.cpp new file mode 100644 index 0000000000..72d4f1103a --- /dev/null +++ b/engines/prince/object.cpp @@ -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. + * + */ + +#include "common/archive.h" +#include "common/debug-channels.h" +#include "common/debug.h" +#include "common/stream.h" + + +#include "graphics/surface.h" + +#include "prince/object.h" + +namespace Prince { + +Object::Object() : _surface(NULL) { +} + +void Object::loadSurface(Common::SeekableReadStream &stream) { + stream.skip(4); + + _surface = new Graphics::Surface(); + _surface->create(stream.readUint16LE(), stream.readUint16LE(), Graphics::PixelFormat::createFormatCLUT8()); + for (int h = 0; h < _surface->h; ++h) { + stream.read(_surface->getBasePtr(0, h), _surface->w); + } + +} + +bool Object::loadFromStream(Common::SeekableReadStream &stream) { + + int32 pos = stream.pos(); + uint16 x = stream.readUint16LE(); + if (x == 0xFFFF) + return false; + _x = x; + _y = stream.readUint16LE(); + + const Common::String obStreamName = Common::String::format("OB%02d", stream.readUint16LE()); + Common::SeekableReadStream *obStream = SearchMan.createReadStreamForMember(obStreamName); + if (!obStream) { + error("Can't load %s", obStreamName.c_str()); + return false; + } + + loadSurface(*obStream); + delete obStream; + + _z = stream.readUint16LE(); + + stream.seek(pos + 16); + + debug("Object x %d, y %d, z %d", _x, _y, _z); + + return true; +} + +} diff --git a/engines/prince/object.h b/engines/prince/object.h new file mode 100644 index 0000000000..3a8859c196 --- /dev/null +++ b/engines/prince/object.h @@ -0,0 +1,47 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#ifndef PRINCE_OBJECT_H +#define PRINCE_OBJECT_H + +#include "graphics/decoders/image_decoder.h" +#include "graphics/surface.h" + +namespace Prince { + +class Object { +public: + Object(); + + bool loadFromStream(Common::SeekableReadStream &stream); + Graphics::Surface *getSurface() const { return _surface; } + +private: + void loadSurface(Common::SeekableReadStream &stream); + + Graphics::Surface *_surface; + uint16 _x, _y, _z; +}; + +} + +#endif diff --git a/engines/prince/prince.cpp b/engines/prince/prince.cpp index 4fb2082baf..a9f243ce11 100644 --- a/engines/prince/prince.cpp +++ b/engines/prince/prince.cpp @@ -47,17 +47,46 @@ #include "prince/graphics.h" #include "prince/script.h" #include "prince/debugger.h" +#include "prince/object.h" +#include "prince/mob.h" +#include "prince/sound.h" #include "video/flic_decoder.h" namespace Prince { +Graphics::Surface *loadCursor(const char *curName) +{ + Common::SeekableReadStream *curStream = SearchMan.createReadStreamForMember(curName); + if (!curStream) { + error("Can't load %s", curName); + return NULL; + } + + curStream->skip(4); + uint16 w = curStream->readUint16LE(); + uint16 h = curStream->readUint16LE(); + + debug("Loading cursor %s, w %d, h %d", curName, w, h); + + Graphics::Surface *curSurface = new Graphics::Surface(); + curSurface->create(w, h, Graphics::PixelFormat::createFormatCLUT8()); + for (int ih = 0; ih < h; ++ih) { + curStream->read(curSurface->getBasePtr(0, ih), w); + } + + delete curStream; + return curSurface; +} + + + PrinceEngine::PrinceEngine(OSystem *syst, const PrinceGameDescription *gameDesc) : Engine(syst), _gameDescription(gameDesc), _graph(NULL), _script(NULL), - _locationNr(0), _debugger(NULL) { + _locationNr(0), _debugger(NULL), _objectList(NULL), _mobList(NULL), _midiPlayer(NULL) { _rnd = new Common::RandomSource("prince"); _debugger = new Debugger(this); - + _midiPlayer = new MusicPlayer(this); } PrinceEngine::~PrinceEngine() { @@ -65,6 +94,9 @@ PrinceEngine::~PrinceEngine() { delete _rnd; delete _debugger; + delete _cur1; + delete _cur2; + delete _midiPlayer; } GUI::Debugger *PrinceEngine::getDebugger() { @@ -108,23 +140,59 @@ Common::Error PrinceEngine::run() { delete skryptStream; - Common::SeekableReadStream *logoStrema = SearchMan.createReadStreamForMember("logo.raw"); - if (logoStrema) + + _cur1 = loadCursor("mouse1.cur"); + _cur2 = loadCursor("mouse2.cur"); + + Common::SeekableReadStream *logoStream = SearchMan.createReadStreamForMember("logo.raw"); + if (logoStream) { MhwanhDecoder logo; - logo.loadStream(*logoStrema); + logo.loadStream(*logoStream); _graph->setPalette(logo.getPalette()); _graph->draw(logo.getSurface()); _graph->update(); _system->delayMillis(700); } - delete logoStrema; + delete logoStream; mainLoop(); return Common::kNoError; } +class MobList { +public: + bool loadFromStream(Common::SeekableReadStream &stream); + + Common::Array _mobList; +}; + +bool MobList::loadFromStream(Common::SeekableReadStream &stream) +{ + Mob mob; + while (mob.loadFromStream(stream)) + _mobList.push_back(mob); + + return true; +} + +class ObjectList { +public: + bool loadFromStream(Common::SeekableReadStream &stream); + + Common::Array _objList; +}; + +bool ObjectList::loadFromStream(Common::SeekableReadStream &stream) +{ + Object obj; + while (obj.loadFromStream(stream)) + _objList.push_back(obj); + + return true; +} + bool PrinceEngine::loadLocation(uint16 locationNr) { debug("PrinceEngine::loadLocation %d", locationNr); const Common::FSNode gameDataDir(ConfMan.get("path")); @@ -145,14 +213,75 @@ bool PrinceEngine::loadLocation(uint16 locationNr) { if(_roomBmp.loadStream(*room)) { debug("Room bitmap loaded"); - _system->getPaletteManager()->setPalette(_roomBmp.getPalette(), 0, 256); } delete room; + delete _mobList; + _mobList = NULL; + + Common::SeekableReadStream *mobListStream = SearchMan.createReadStreamForMember("mob.lst"); + if (!mobListStream) { + error("Can't read mob.lst"); + return false; + } + + _mobList = new MobList(); + _mobList->loadFromStream(*mobListStream); + + delete mobListStream; + + delete _objectList; + _objectList = NULL; + + Common::SeekableReadStream *objListStream = SearchMan.createReadStreamForMember("obj.lst"); + if (!objListStream) { + error("Can't read obj.lst"); + return false; + } + + _objectList = new ObjectList(); + _objectList->loadFromStream(*objListStream); + delete objListStream; + + const char *musName = MusicPlayer::_musTable[MusicPlayer::_musRoomTable[locationNr]]; + _midiPlayer->loadMidi(musName); + return true; } +void PrinceEngine::changeCursor(uint16 curId) +{ + Graphics::Surface *curSurface = NULL; + + uint16 hotspotX = 0; + uint16 hotspotY = 0; + + switch(curId) { + case 0: + CursorMan.showMouse(false); + return; + case 1: + curSurface = _cur1; + break; + case 2: + curSurface = _cur2; + hotspotX = curSurface->w >> 1; + hotspotY = curSurface->h >> 1; + break; + } + + CursorMan.replaceCursorPalette(_roomBmp.getPalette(), 0, 255); + CursorMan.replaceCursor( + curSurface->getBasePtr(0, 0), + curSurface->w, curSurface->h, + hotspotX, hotspotY, + 255, false, + &curSurface->format + ); + CursorMan.showMouse(true); +} + bool PrinceEngine::playNextFrame() { const Graphics::Surface *s = _flicPlayer.decodeNextFrame(); if (s) { @@ -193,9 +322,46 @@ void PrinceEngine::keyHandler(Common::Event event) { } } +void PrinceEngine::hotspot() { + Common::Point mousepos = _system->getEventManager()->getMousePos(); + + Common::Array::iterator it = _mobList->_mobList.begin(); + for (; it != _mobList->_mobList.end(); ++it) { + if (it->_visible) + continue; + if (it->_rect.contains(mousepos)) { + uint16 textW = 0; + for (int i = 0; i < it->_name.size(); ++i) + textW += _font.getCharWidth(it->_name[i]); + + uint16 x = mousepos.x - textW/2; + if (x > _graph->_frontScreen->w) + x = 0; + + if (x + textW > _graph->_frontScreen->w) + x = _graph->_frontScreen->w - textW; + + _font.drawString( + _graph->_frontScreen, + it->_name, + x, + mousepos.y - _font.getFontHeight(), + _graph->_frontScreen->w, + 216 + ); + break; + } + } +} + void PrinceEngine::mainLoop() { + loadLocation(1); + changeCursor(1); + CursorMan.showMouse(true); + while (!shouldQuit()) { + _debugger->onFrame(); Common::Event event; Common::EventManager *eventMan = _system->getEventManager(); while (eventMan->pollEvent(event)) { @@ -223,13 +389,22 @@ void PrinceEngine::mainLoop() { if (shouldQuit()) return; - _script->step(); + //_script->step(); - if (_roomBmp.getSurface()) + if (_roomBmp.getSurface()) { + _graph->setPalette(_roomBmp.getPalette()); _graph->draw(_roomBmp.getSurface()); + } playNextFrame(); + //debug("Cursor visible %d", CursorMan.isVisible()); + + //if (_objectList) + // _graph->drawTransparent(_objectList->getSurface()); + + hotspot(); + _graph->update(); _system->delayMillis(40); diff --git a/engines/prince/prince.h b/engines/prince/prince.h index b289c75553..6340733255 100644 --- a/engines/prince/prince.h +++ b/engines/prince/prince.h @@ -53,6 +53,9 @@ class PrinceEngine; class GraphicsMan; class Script; class Debugger; +class ObjectList; +class MobList; +class MusicPlayer; class PrinceEngine : public Engine { protected: @@ -77,19 +80,28 @@ public: virtual GUI::Debugger *getDebugger(); + void changeCursor(uint16 curId); + private: bool playNextFrame(); void keyHandler(Common::Event event); + void hotspot(); Common::RandomSource *_rnd; Graphics::BitmapDecoder _roomBmp; uint16 _locationNr; MhwanhDecoder _walizkaBmp; + Graphics::Surface *_cur1; + Graphics::Surface *_cur2; + Debugger *_debugger; GraphicsMan *_graph; Script *_script; Font _font; + ObjectList *_objectList; + MobList *_mobList; + MusicPlayer *_midiPlayer; void mainLoop(); diff --git a/engines/prince/script.cpp b/engines/prince/script.cpp index d790d6d9c3..e2360debc8 100644 --- a/engines/prince/script.cpp +++ b/engines/prince/script.cpp @@ -206,24 +206,48 @@ void Script::O_REMBACKANIM() { debugScript("O_REMBACKANIM roomId %d, slot %d", roomId, slot); } -void Script::O_CHECKBACKANIMFRAME() {} +void Script::O_CHECKBACKANIMFRAME() { + uint16 slotId = readScript16bits(); + uint16 frameId = readScript16bits(); -void Script::O_FREEALLSAMPLES() {} + debugScript("O_CHECKBACKANIMFRAME slotId %d, frameId %d", slotId, frameId); +} -void Script::O_SETMUSIC() {} +void Script::O_FREEALLSAMPLES() { + debugScript("O_FREEALLSAMPLES"); +} -void Script::O_STOPMUSIC() {} +void Script::O_SETMUSIC() { + uint16 musicId = readScript16bits(); -void Script::O__WAIT() {} + debugScript("O_SETMUSIC musicId %d", musicId); +} -void Script::O_UPDATEOFF() {} +void Script::O_STOPMUSIC() { + debugScript("O_STOPMUSIC"); +} -void Script::O_UPDATEON() {} +void Script::O__WAIT() { + uint16 pause = readScript16bits(); -void Script::O_UPDATE () {} + debugScript("O__WAIT pause %d", pause); +} -void Script::O_CLS() {} +void Script::O_UPDATEOFF() { + debugScript("O_UPDATEOFF"); +} +void Script::O_UPDATEON() { + debugScript("O_UPDATEON"); +} + +void Script::O_UPDATE () { + debugScript("O_UPDATE"); +} + +void Script::O_CLS() { + debugScript("O_CLS"); +} void Script::O__CALL() { int32 address = readScript32bits(); @@ -247,7 +271,10 @@ void Script::O_GO() { debugScript("O_GO 0x%04X", opPC); _currentInstruction += opPC - 4; } -void Script::O_BACKANIMUPDATEOFF() {} +void Script::O_BACKANIMUPDATEOFF() { + uint16 slotId = readScript32bits(); + debugScript("O_BACKANIMUPDATEOFF slotId %d", slotId); +} void Script::O_BACKANIMUPDATEON() { uint16 slot = readScript16bits(); @@ -258,26 +285,39 @@ void Script::O_CHANGECURSOR() { uint16 cursorId = readScript16bits(); debugScript("O_CHANGECURSOR %x", cursorId); } -void Script::O_CHANGEANIMTYPE() {} + +void Script::O_CHANGEANIMTYPE() { + // NOT IMPLEMENTED +} + void Script::O__SETFLAG() { uint16 flagId = readScript16bits(); uint16 value = readScript16bits(); + + if (value & 0x8000) { + value = _flags[value - 0x8000]; + } + debugScript("O__SETFLAG 0x%04X %d", flagId, value); - _flags[flagId-0x8000] = value; + _flags[flagId - 0x8000] = value; } void Script::O_COMPARE() { uint16 flagId = readScript16bits(); uint16 value = readScript16bits(); + + if (value & 0x8000) { + value = _flags[value - 0x8000]; + } + debugScript("O_COMPARE flagId 0x%04X, value %d", flagId, value); - _result = (_flags[flagId-0x8000] == value); + _result = (_flags[flagId - 0x8000] == value); } void Script::O_JUMPZ() { int32 offset = readScript32bits(); debugScript("O_JUMPZ offset 0x%04X", offset); - if (_result == 0) - { + if (! _result) { _currentInstruction += offset - 4; } } @@ -285,20 +325,26 @@ void Script::O_JUMPZ() { void Script::O_JUMPNZ() { int32 offset = readScript32bits(); debugScript("O_JUMPNZ offset 0x%04X", offset); - if (_result) - { + if (_result) { _currentInstruction += offset - 4; } } -void Script::O_EXIT() {} +void Script::O_EXIT() { + uint16 exitCode = readScript16bits(); + debugScript("O_EXIT exitCode %d", exitCode); +} void Script::O_ADDFLAG() { uint16 flagId = readScript16bits(); uint16 value = readScript16bits(); - _flags[flagId-0x8000] += value; - if (_flags[flagId-0x8000]) + if (value & 0x8000) { + value = _flags[value - 0x8000]; + } + + _flags[flagId - 0x8000] += value; + if (_flags[flagId - 0x8000]) _result = 1; else _result = 0; @@ -317,8 +363,12 @@ void Script::O_SUBFLAG() { uint16 flagId = readScript16bits(); uint16 value = readScript16bits(); - _flags[flagId-0x8000] -= value; - if (_flags[flagId-0x8000]) + if (value & 0x8000) { + value = _flags[value - 0x8000]; + } + + _flags[flagId - 0x8000] -= value; + if (_flags[flagId - 0x8000]) _result = 1; else _result = 0; @@ -332,17 +382,84 @@ void Script::O_SETSTRING() { debugScript("O_SETSTRING 0x%04X", offset); } -void Script::O_ANDFLAG() {} +void Script::O_ANDFLAG() { + uint16 flagId = readScript16bits(); + uint16 value = readScript16bits(); -void Script::O_GETMOBDATA() {} + debugScript("O_ANDFLAG flagId %d, value %d", flagId, value); -void Script::O_ORFLAG() {} + if (value & 0x8000) { + value = _flags[value - 0x8000]; + } -void Script::O_SETMOBDATA() {} + _flags[flagId - 0x8000] &= value; -void Script::O_XORFLAG() {} + if (_flags[flagId - 0x8000]) { + _result = 1; + } else { + _result = 0; + } +} -void Script::O_GETMOBTEXT() {} +void Script::O_GETMOBDATA() { + uint16 flagId = readScript16bits(); + uint16 mobId = readScript16bits(); + uint16 mobOffset = readScript16bits(); + + debugScript("O_GETMOBDATA flagId %d, modId %d, mobOffset %d", flagId, mobId, mobOffset); +} + +void Script::O_ORFLAG() { + uint16 flagId = readScript16bits(); + uint16 value = readScript16bits(); + + debugScript("O_ORFLAG flagId %d, value %d", flagId, value); + + if (value & 0x8000) { + value = _flags[value - 0x8000]; + } + + _flags[flagId - 0x8000] |= value; + + if (_flags[flagId - 0x8000]) { + _result = 1; + } else { + _result = 0; + } +} + +void Script::O_SETMOBDATA() { + uint16 mobId = readScript16bits(); + uint16 mobOffset = readScript16bits(); + uint16 value = readScript16bits(); + + debugScript("O_SETMOBDATA mobId %d, mobOffset %d, value %d", mobId, mobOffset, value); +} + +void Script::O_XORFLAG() { + uint16 flagId = readScript16bits(); + uint16 value = readScript16bits(); + + debugScript("O_XORFLAG flagId %d, value %d", flagId, value); + + if (value & 0x8000) { + value = _flags[value - 0x8000]; + } + + _flags[flagId - 0x8000] ^= value; + + if (_flags[flagId - 0x8000]) { + _result = 1; + } else { + _result = 0; + } +} + +void Script::O_GETMOBTEXT() { + uint16 value = readScript16bits(); + + debugScript("O_GETMOBTEXT value %d", value); +} void Script::O_MOVEHERO() { uint16 heroId = readScript16bits(); diff --git a/engines/prince/sound.cpp b/engines/prince/sound.cpp new file mode 100644 index 0000000000..2e2e53e664 --- /dev/null +++ b/engines/prince/sound.cpp @@ -0,0 +1,160 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +/* + * This code is based on original Soltys source code + * Copyright (c) 1994-1995 Janus B. Wisniewski and L.K. Avalon + */ + +#include "prince/prince.h" +#include "prince/sound.h" +#include "common/config-manager.h" +#include "common/memstream.h" +#include "common/archive.h" +#include "audio/decoders/raw.h" +#include "audio/audiostream.h" + +namespace Prince { + +const char * MusicPlayer::_musTable[] = { + "", + "Battlfld.mid", + "Cave.mid", + "Cemetery.mid", + "Credits.mid", + "Fjord.mid", + "Guitar.mid", + "Hell.mid", + "Jingle.mid", + "Main.mid", + "Night.mid", + "Reality.mid", + "Sunlord.mid", + "Tavern.mid", + "Temple.mid", + "Boruta.mid", + "Intro.mid" +}; + +const uint8 MusicPlayer::_musRoomTable[] = { + 0, + 3, + 9, + 9, + 9, + 13, + 9, + 9 +}; + + +MusicPlayer::MusicPlayer(PrinceEngine *vm) : _vm(vm) { + _data = NULL; + _isGM = false; + + MidiPlayer::createDriver(); + + int ret = _driver->open(); + if (ret == 0) { + if (_nativeMT32) + _driver->sendMT32Reset(); + else + _driver->sendGMReset(); + + // TODO: Load cmf.ins with the instrument table. It seems that an + // interface for such an operation is supported for AdLib. Maybe for + // this card, setting instruments is necessary. + + _driver->setTimerCallback(this, &timerCallback); + } +} + +MusicPlayer::~MusicPlayer() { + killMidi(); +} + +void MusicPlayer::killMidi() { + Audio::MidiPlayer::stop(); + + free(_data); + _data = NULL; +} + +void MusicPlayer::loadMidi(const char * name) { + Common::SeekableReadStream * stream = SearchMan.createReadStreamForMember(name); + if (!stream) + return; + + // Stop any currently playing MIDI file + killMidi(); + + // Read in the data for the file + _dataSize = stream->size(); + _data = (byte *)malloc(_dataSize); + stream->read(_data, _dataSize); + + // Start playing the music + sndMidiStart(); +} + +void MusicPlayer::sndMidiStart() { + _isGM = true; + + MidiParser *parser = MidiParser::createParser_SMF(); + if (parser->loadMusic(_data, _dataSize)) { + parser->setTrack(0); + parser->setMidiDriver(this); + parser->setTimerRate(_driver->getBaseTempo()); + parser->property(MidiParser::mpCenterPitchWheelOnUnload, 1); + + _parser = parser; + + syncVolume(); + + // Al the tracks are supposed to loop + _isLooping = true; + _isPlaying = true; + } +} + +void MusicPlayer::send(uint32 b) { + if ((b & 0xF0) == 0xC0 && !_isGM && !_nativeMT32) { + b = (b & 0xFFFF00FF) | MidiDriver::_mt32ToGm[(b >> 8) & 0xFF] << 8; + } + + Audio::MidiPlayer::send(b); +} + +void MusicPlayer::sendToChannel(byte channel, uint32 b) { + if (!_channelsTable[channel]) { + _channelsTable[channel] = (channel == 9) ? _driver->getPercussionChannel() : _driver->allocateChannel(); + // If a new channel is allocated during the playback, make sure + // its volume is correctly initialized. + if (_channelsTable[channel]) + _channelsTable[channel]->volume(_channelsVolume[channel] * _masterVolume / 255); + } + + if (_channelsTable[channel]) + _channelsTable[channel]->send(b); +} + +} // End of namespace CGE diff --git a/engines/prince/sound.h b/engines/prince/sound.h new file mode 100644 index 0000000000..779fe563f9 --- /dev/null +++ b/engines/prince/sound.h @@ -0,0 +1,73 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +/* + * This code is based on original Soltys source code + * Copyright (c) 1994-1995 Janus B. Wisniewski and L.K. Avalon + */ + +#ifndef PRINCE_SOUND_H +#define PRINCE_SOUND_H + +#include "audio/audiostream.h" +#include "audio/decoders/wave.h" +#include "audio/fmopl.h" +#include "audio/mididrv.h" +#include "audio/midiparser.h" +#include "audio/midiplayer.h" +#include "audio/mixer.h" +#include "common/memstream.h" + +namespace Prince { + +class PrinceEngine; + +class MusicPlayer: public Audio::MidiPlayer { +private: + PrinceEngine *_vm; + byte *_data; + int _dataSize; + bool _isGM; + + // Start MIDI File + void sndMidiStart(); + + // Stop MIDI File + void sndMidiStop(); +public: + MusicPlayer(PrinceEngine *vm); + ~MusicPlayer(); + + void loadMidi(const char *); + void killMidi(); + + virtual void send(uint32 b); + virtual void sendToChannel(byte channel, uint32 b); + + static const char * _musTable[]; + static const uint8 _musRoomTable[]; +}; + +} // End of namespace Prince + +#endif + -- cgit v1.2.3