diff options
Diffstat (limited to 'engines/director/score.cpp')
-rw-r--r-- | engines/director/score.cpp | 849 |
1 files changed, 849 insertions, 0 deletions
diff --git a/engines/director/score.cpp b/engines/director/score.cpp new file mode 100644 index 0000000000..8a252a26ed --- /dev/null +++ b/engines/director/score.cpp @@ -0,0 +1,849 @@ +/* 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 "common/config-manager.h" +#include "common/events.h" + +#include "engines/util.h" +#include "graphics/font.h" +#include "graphics/palette.h" + +#include "director/score.h" +#include "director/frame.h" +#include "director/resource.h" +#include "director/sound.h" +#include "director/sprite.h" +#include "director/lingo/lingo.h" + +namespace Director { + +static byte defaultPalette[768] = { + 0, 0, 0, 17, 17, 17, 34, 34, 34, 68, 68, 68, 85, 85, 85, 119, + 119, 119, 136, 136, 136, 170, 170, 170, 187, 187, 187, 221, 221, 221, 238, 238, + 238, 0, 0, 17, 0, 0, 34, 0, 0, 68, 0, 0, 85, 0, 0, 119, + 0, 0, 136, 0, 0, 170, 0, 0, 187, 0, 0, 221, 0, 0, 238, 0, + 17, 0, 0, 34, 0, 0, 68, 0, 0, 85, 0, 0, 119, 0, 0, 136, + 0, 0, 170, 0, 0, 187, 0, 0, 221, 0, 0, 238, 0, 17, 0, 0, + 34, 0, 0, 68, 0, 0, 85, 0, 0, 119, 0, 0, 136, 0, 0, 170, + 0, 0, 187, 0, 0, 221, 0, 0, 238, 0, 0, 0, 0, 51, 0, 0, + 102, 0, 0, 153, 0, 0, 204, 0, 0, 255, 0, 51, 0, 0, 51, 51, + 0, 51, 102, 0, 51, 153, 0, 51, 204, 0, 51, 255, 0, 102, 0, 0, + 102, 51, 0, 102, 102, 0, 102, 153, 0, 102, 204, 0, 102, 255, 0, 153, + 0, 0, 153, 51, 0, 153, 102, 0, 153, 153, 0, 153, 204, 0, 153, 255, + 0, 204, 0, 0, 204, 51, 0, 204, 102, 0, 204, 153, 0, 204, 204, 0, + 204, 255, 0, 255, 0, 0, 255, 51, 0, 255, 102, 0, 255, 153, 0, 255, + 204, 0, 255, 255, 51, 0, 0, 51, 0, 51, 51, 0, 102, 51, 0, 153, + 51, 0, 204, 51, 0, 255, 51, 51, 0, 51, 51, 51, 51, 51, 102, 51, + 51, 153, 51, 51, 204, 51, 51, 255, 51, 102, 0, 51, 102, 51, 51, 102, + 102, 51, 102, 153, 51, 102, 204, 51, 102, 255, 51, 153, 0, 51, 153, 51, + 51, 153, 102, 51, 153, 153, 51, 153, 204, 51, 153, 255, 51, 204, 0, 51, + 204, 51, 51, 204, 102, 51, 204, 153, 51, 204, 204, 51, 204, 255, 51, 255, + 0, 51, 255, 51, 51, 255, 102, 51, 255, 153, 51, 255, 204, 51, 255, 255, + 102, 0, 0, 102, 0, 51, 102, 0, 102, 102, 0, 153, 102, 0, 204, 102, + 0, 255, 102, 51, 0, 102, 51, 51, 102, 51, 102, 102, 51, 153, 102, 51, + 204, 102, 51, 255, 102, 102, 0, 102, 102, 51, 102, 102, 102, 102, 102, 153, + 102, 102, 204, 102, 102, 255, 102, 153, 0, 102, 153, 51, 102, 153, 102, 102, + 153, 153, 102, 153, 204, 102, 153, 255, 102, 204, 0, 102, 204, 51, 102, 204, + 102, 102, 204, 153, 102, 204, 204, 102, 204, 255, 102, 255, 0, 102, 255, 51, + 102, 255, 102, 102, 255, 153, 102, 255, 204, 102, 255, 255, 153, 0, 0, 153, + 0, 51, 153, 0, 102, 153, 0, 153, 153, 0, 204, 153, 0, 255, 153, 51, + 0, 153, 51, 51, 153, 51, 102, 153, 51, 153, 153, 51, 204, 153, 51, 255, + 153, 102, 0, 153, 102, 51, 153, 102, 102, 153, 102, 153, 153, 102, 204, 153, + 102, 255, 153, 153, 0, 153, 153, 51, 153, 153, 102, 153, 153, 153, 153, 153, + 204, 153, 153, 255, 153, 204, 0, 153, 204, 51, 153, 204, 102, 153, 204, 153, + 153, 204, 204, 153, 204, 255, 153, 255, 0, 153, 255, 51, 153, 255, 102, 153, + 255, 153, 153, 255, 204, 153, 255, 255, 204, 0, 0, 204, 0, 51, 204, 0, + 102, 204, 0, 153, 204, 0, 204, 204, 0, 255, 204, 51, 0, 204, 51, 51, + 204, 51, 102, 204, 51, 153, 204, 51, 204, 204, 51, 255, 204, 102, 0, 204, + 102, 51, 204, 102, 102, 204, 102, 153, 204, 102, 204, 204, 102, 255, 204, 153, + 0, 204, 153, 51, 204, 153, 102, 204, 153, 153, 204, 153, 204, 204, 153, 255, + 204, 204, 0, 204, 204, 51, 204, 204, 102, 204, 204, 153, 204, 204, 204, 204, + 204, 255, 204, 255, 0, 204, 255, 51, 204, 255, 102, 204, 255, 153, 204, 255, + 204, 204, 255, 255, 255, 0, 0, 255, 0, 51, 255, 0, 102, 255, 0, 153, + 255, 0, 204, 255, 0, 255, 255, 51, 0, 255, 51, 51, 255, 51, 102, 255, + 51, 153, 255, 51, 204, 255, 51, 255, 255, 102, 0, 255, 102, 51, 255, 102, + 102, 255, 102, 153, 255, 102, 204, 255, 102, 255, 255, 153, 0, 255, 153, 51, + 255, 153, 102, 255, 153, 153, 255, 153, 204, 255, 153, 255, 255, 204, 0, 255, + 204, 51, 255, 204, 102, 255, 204, 153, 255, 204, 204, 255, 204, 255, 255, 255, + 0, 255, 255, 51, 255, 255, 102, 255, 255, 153, 255, 255, 204, 255, 255, 255 }; + +Score::Score(DirectorEngine *vm) { + _vm = vm; + _surface = new Graphics::ManagedSurface; + _trailSurface = new Graphics::ManagedSurface; + _movieArchive = _vm->getMainArchive(); + _lingo = _vm->getLingo(); + _soundManager = _vm->getSoundManager(); + _lingo->processEvent(kEventPrepareMovie, 0); + _movieScriptCount = 0; + _labels = NULL; + _font = NULL; + + _versionMinor = _versionMajor = 0; + _currentFrameRate = 20; + _castArrayStart = _castArrayEnd = 0; + _currentFrame = 0; + _nextFrameTime = 0; + _flags = 0; + _stopPlay = false; + _stageColor = 0; + + if (_movieArchive->hasResource(MKTAG('M','C','N','M'), 0)) { + _macName = _movieArchive->getName(MKTAG('M','C','N','M'), 0).c_str(); + } + + if (_movieArchive->hasResource(MKTAG('V','W','L','B'), 1024)) { + loadLabels(*_movieArchive->getResource(MKTAG('V','W','L','B'), 1024)); + } +} + +void Score::loadArchive() { + Common::Array<uint16> clutList = _movieArchive->getResourceIDList(MKTAG('C','L','U','T')); + + if (clutList.size() > 1) + warning("More than one palette was found (%d)", clutList.size()); + + if (clutList.size() == 0) { + warning("CLUT resource not found, using default Mac palette"); + g_system->getPaletteManager()->setPalette(defaultPalette, 0, 256); + _vm->setPalette(defaultPalette, 256); + } else { + Common::SeekableSubReadStreamEndian *pal = _movieArchive->getResource(MKTAG('C', 'L', 'U', 'T'), clutList[0]); + + loadPalette(*pal); + g_system->getPaletteManager()->setPalette(_vm->getPalette(), 0, _vm->getPaletteColorCount()); + } + + assert(_movieArchive->hasResource(MKTAG('V','W','S','C'), 1024)); + assert(_movieArchive->hasResource(MKTAG('V','W','C','F'), 1024)); + + loadFrames(*_movieArchive->getResource(MKTAG('V','W','S','C'), 1024)); + loadConfig(*_movieArchive->getResource(MKTAG('V','W','C','F'), 1024)); + + if (_vm->getVersion() < 4) { + assert(_movieArchive->hasResource(MKTAG('V','W','C','R'), 1024)); + loadCastData(*_movieArchive->getResource(MKTAG('V','W','C','R'), 1024)); + } + + if (_movieArchive->hasResource(MKTAG('V','W','A','C'), 1024)) { + loadActions(*_movieArchive->getResource(MKTAG('V','W','A','C'), 1024)); + } + + if (_movieArchive->hasResource(MKTAG('V','W','F','I'), 1024)) { + loadFileInfo(*_movieArchive->getResource(MKTAG('V','W','F','I'), 1024)); + } + + if (_movieArchive->hasResource(MKTAG('V','W','F','M'), 1024)) { + loadFontMap(*_movieArchive->getResource(MKTAG('V','W','F','M'), 1024)); + } + + Common::Array<uint16> vwci = _movieArchive->getResourceIDList(MKTAG('V','W','C','I')); + + if (vwci.size() > 0) { + Common::Array<uint16>::iterator iterator; + + for (iterator = vwci.begin(); iterator != vwci.end(); ++iterator) + loadCastInfo(*_movieArchive->getResource(MKTAG('V','W','C','I'), *iterator), *iterator); + } + + Common::Array<uint16> stxt = _movieArchive->getResourceIDList(MKTAG('S','T','X','T')); + + if (stxt.size() > 0) { + loadScriptText(*_movieArchive->getResource(MKTAG('S','T','X','T'), *stxt.begin())); + } +} + +Score::~Score() { + if (_surface) + _surface->free(); + + if (_trailSurface) + _trailSurface->free(); + + delete _surface; + delete _trailSurface; + + if (_movieArchive) + _movieArchive->close(); + + delete _font; + delete _labels; +} + +void Score::loadPalette(Common::SeekableSubReadStreamEndian &stream) { + uint16 steps = stream.size() / 6; + uint16 index = (steps * 3) - 1; + uint16 _paletteColorCount = steps; + byte *_palette = new byte[index + 1]; + + for (uint8 i = 0; i < steps; i++) { + _palette[index - 2] = stream.readByte(); + stream.readByte(); + + _palette[index - 1] = stream.readByte(); + stream.readByte(); + + _palette[index] = stream.readByte(); + stream.readByte(); + index -= 3; + } + _vm->setPalette(_palette, _paletteColorCount); +} + +void Score::loadFrames(Common::SeekableSubReadStreamEndian &stream) { + uint32 size = stream.readUint32(); + size -= 4; + + if (_vm->getVersion() > 3) { + stream.skip(16); + //Unknown, some bytes - constant (refer to contuinity). + } + + uint16 channelSize; + uint16 channelOffset; + + Frame *initial = new Frame(_vm); + _frames.push_back(initial); + + while (size != 0) { + uint16 frameSize = stream.readUint16(); + size -= frameSize; + frameSize -= 2; + Frame *frame = new Frame(*_frames.back()); + + while (frameSize != 0) { + if (_vm->getVersion() < 4) { + channelSize = stream.readByte() * 2; + channelOffset = stream.readByte() * 2; + frameSize -= channelSize + 2; + } else { + channelSize = stream.readByte(); + channelOffset = stream.readByte(); + frameSize -= channelSize + 4; + } + frame->readChannel(stream, channelOffset, channelSize); + + } + + _frames.push_back(frame); + } + + //remove initial frame + _frames.remove_at(0); +} + +void Score::loadConfig(Common::SeekableSubReadStreamEndian &stream) { + /*uint16 unk1 = */ stream.readUint16(); + /*ver1 = */ stream.readUint16(); + _movieRect = Score::readRect(stream); + + _castArrayStart = stream.readUint16(); + _castArrayEnd = stream.readUint16(); + _currentFrameRate = stream.readByte(); + stream.skip(9); + _stageColor = stream.readUint16(); +} + +void Score::readVersion(uint32 rid) { + _versionMinor = rid & 0xffff; + _versionMajor = rid >> 16; + + debug("Version: %d.%d", _versionMajor, _versionMinor); +} + +void Score::loadCastData(Common::SeekableSubReadStreamEndian &stream) { + for (uint16 id = _castArrayStart; id <= _castArrayEnd; id++) { + byte size = stream.readByte(); + if (size == 0) + continue; + + uint8 castType = stream.readByte(); + + switch (castType) { + case kCastBitmap: + _casts[id] = new BitmapCast(stream); + _casts[id]->type = kCastBitmap; + break; + case kCastText: + _casts[id] = new TextCast(stream); + _casts[id]->type = kCastText; + break; + case kCastShape: + _casts[id] = new ShapeCast(stream); + _casts[id]->type = kCastShape; + break; + case kCastButton: + _casts[id] = new ButtonCast(stream); + _casts[id]->type = kCastButton; + break; + default: + warning("Unhandled cast type: %d", castType); + stream.skip(size - 1); + break; + } + } + + //Set cast pointers to sprites + for (uint16 i = 0; i < _frames.size(); i++) { + for (uint16 j = 0; j < _frames[i]->_sprites.size(); j++) { + byte castId = _frames[i]->_sprites[j]->_castId; + + if (_casts.contains(castId)) + _frames[i]->_sprites[j]->_cast = _casts.find(castId)->_value; + } + } +} + +void Score::loadLabels(Common::SeekableSubReadStreamEndian &stream) { + _labels = new Common::SortedArray<Label *>(compareLabels); + uint16 count = stream.readUint16() + 1; + uint16 offset = count * 4 + 2; + + uint16 frame = stream.readUint16(); + uint16 stringPos = stream.readUint16() + offset; + + for (uint16 i = 0; i < count; i++) { + uint16 nextFrame = stream.readUint16(); + uint16 nextStringPos = stream.readUint16() + offset; + uint16 streamPos = stream.pos(); + + stream.seek(stringPos); + Common::String label; + for (uint16 j = stringPos; j < nextStringPos; j++) { + label += stream.readByte(); + } + _labels->insert(new Label(label, frame)); + stream.seek(streamPos); + + frame = nextFrame; + stringPos = nextStringPos; + } + + Common::SortedArray<Label *>::iterator j; + + for (j = _labels->begin(); j != _labels->end(); ++j) { + debug("Frame %d, Label %s", (*j)->number, (*j)->name.c_str()); + } +} + +int Score::compareLabels(const void *a, const void *b) { + return ((const Label *)a)->number - ((const Label *)b)->number; +} + +void Score::loadActions(Common::SeekableSubReadStreamEndian &stream) { + uint16 count = stream.readUint16() + 1; + uint16 offset = count * 4 + 2; + + byte id = stream.readByte(); + /*byte subId = */ stream.readByte(); //I couldn't find how it used in continuity (except print). Frame actionId = 1 byte. + uint16 stringPos = stream.readUint16() + offset; + + for (uint16 i = 0; i < count; i++) { + uint16 nextId = stream.readByte(); + /*byte subId = */ stream.readByte(); + uint16 nextStringPos = stream.readUint16() + offset; + uint16 streamPos = stream.pos(); + + stream.seek(stringPos); + + for (uint16 j = stringPos; j < nextStringPos; j++) { + byte ch = stream.readByte(); + if (ch == 0x0d) { + ch = '\n'; + } + _actions[id] += ch; + } + + stream.seek(streamPos); + + id = nextId; + stringPos = nextStringPos; + + if (stringPos == stream.size()) + break; + } + + Common::HashMap<uint16, Common::String>::iterator j; + + if (ConfMan.getBool("dump_scripts")) + for (j = _actions.begin(); j != _actions.end(); ++j) { + if (!j->_value.empty()) + dumpScript(j->_value.c_str(), kFrameScript, j->_key); + } + + for (j = _actions.begin(); j != _actions.end(); ++j) + if (!j->_value.empty()) + _lingo->addCode(j->_value.c_str(), kFrameScript, j->_key); +} + +void Score::loadScriptText(Common::SeekableSubReadStreamEndian &stream) { + /*uint32 unk1 = */ stream.readUint32(); + uint32 strLen = stream.readUint32(); + /*uin32 dataLen = */ stream.readUint32(); + Common::String script; + + for (uint32 i = 0; i < strLen; i++) { + byte ch = stream.readByte(); + + if (ch == 0x0d) { + //in old Mac systems \r was the code for end-of-line instead. + ch = '\n'; + } + script += ch; + } + + if (!script.empty() && ConfMan.getBool("dump_scripts")) + dumpScript(script.c_str(), kMovieScript, _movieScriptCount); + + if (!script.empty()) + _lingo->addCode(script.c_str(), kMovieScript, _movieScriptCount); + + _movieScriptCount++; +} + +void Score::setStartToLabel(Common::String label) { + if (!_labels) { + warning("setStartToLabel: No labels set"); + return; + } + + Common::SortedArray<Label *>::iterator i; + + for (i = _labels->begin(); i != _labels->end(); ++i) { + if ((*i)->name == label) { + _currentFrame = (*i)->number; + return; + } + } + warning("Label %s not found", label.c_str()); +} + +void Score::dumpScript(const char *script, ScriptType type, uint16 id) { + Common::DumpFile out; + Common::String typeName; + char buf[256]; + + switch (type) { + case kNoneScript: + error("Incorrect dumpScript() call"); + case kFrameScript: + typeName = "frame"; + break; + case kMovieScript: + typeName = "movie"; + break; + case kSpriteScript: + typeName = "sprite"; + break; + } + + sprintf(buf, "./dumps/%s-%s-%d.txt", _macName.c_str(), typeName.c_str(), id); + + if (!out.open(buf)) { + warning("Can not open dump file %s", buf); + return; + } + + out.write(script, strlen(script)); + + out.flush(); + out.close(); +} + +void Score::loadCastInfo(Common::SeekableSubReadStreamEndian &stream, uint16 id) { + uint32 entryType = 0; + Common::Array<Common::String> castStrings = loadStrings(stream, entryType); + CastInfo *ci = new CastInfo(); + + ci->script = castStrings[0]; + + if (!ci->script.empty() && ConfMan.getBool("dump_scripts")) + dumpScript(ci->script.c_str(), kSpriteScript, id); + + if (!ci->script.empty()) + _lingo->addCode(ci->script.c_str(), kSpriteScript, id); + + ci->name = getString(castStrings[1]); + ci->directory = getString(castStrings[2]); + ci->fileName = getString(castStrings[3]); + ci->type = castStrings[4]; + + _castsInfo[id] = ci; +} + +void Score::gotoloop() { + //This command has the playback head contonuously return to the first marker to to the left and then loop back. + //If no marker are to the left of the playback head, the playback head continues to the right. + Common::SortedArray<Label *>::iterator i; + + for (i = _labels->begin(); i != _labels->end(); ++i) { + if ((*i)->name == _currentLabel) { + _currentFrame = (*i)->number; + return; + } + } +} + +void Score::gotonext() { + Common::SortedArray<Label *>::iterator i; + + for (i = _labels->begin(); i != _labels->end(); ++i) { + if ((*i)->name == _currentLabel) { + if (i != _labels->end()) { + //return to the first marker to to the right + ++i; + _currentFrame = (*i)->number; + return; + } else { + //if no markers are to the right of the playback head, + //the playback head goes to the first marker to the left + _currentFrame = (*i)->number; + return; + } + } + } + //If there are not markers to the left, + //the playback head goes to frame 1, (Director frame array start from 1, engine from 0) + _currentFrame = 0; +} + +void Score::gotoprevious() { + //One label + if (_labels->begin() == _labels->end()) { + _currentFrame = (*_labels->begin())->number; + return; + } + + Common::SortedArray<Label *>::iterator previous = _labels->begin(); + Common::SortedArray<Label *>::iterator i = previous++; + + for (i = _labels->begin(); i != _labels->end(); ++i, ++previous) { + if ((*i)->name == _currentLabel) { + _currentFrame = (*previous)->number; + return; + } else { + _currentFrame = (*i)->number; + return; + } + } + _currentFrame = 0; +} + +Common::String Score::getString(Common::String str) { + if (str.size() == 0) { + return str; + } + + uint8 f = static_cast<uint8>(str.firstChar()); + + if (f == 0) { + return ""; + } + + str.deleteChar(0); + + if (str.lastChar() == '\x00') { + str.deleteLastChar(); + } + + return str; +} + +void Score::loadFileInfo(Common::SeekableSubReadStreamEndian &stream) { + Common::Array<Common::String> fileInfoStrings = loadStrings(stream, _flags); + _script = fileInfoStrings[0]; + + if (!_script.empty() && ConfMan.getBool("dump_scripts")) + dumpScript(_script.c_str(), kMovieScript, _movieScriptCount); + + if (!_script.empty()) + _lingo->addCode(_script.c_str(), kMovieScript, _movieScriptCount); + + _movieScriptCount++; + _changedBy = fileInfoStrings[1]; + _createdBy = fileInfoStrings[2]; + _directory = fileInfoStrings[3]; +} + +Common::Array<Common::String> Score::loadStrings(Common::SeekableSubReadStreamEndian &stream, uint32 &entryType, bool hasHeader) { + Common::Array<Common::String> strings; + uint32 offset = 0; + + if (hasHeader) { + offset = stream.readUint32(); + /*uint32 unk1 = */ stream.readUint32(); + /*uint32 unk2 = */ stream.readUint32(); + entryType = stream.readUint32(); + stream.seek(offset); + } + + uint16 count = stream.readUint16(); + offset += (count + 1) * 4 + 2; //positions info + uint16 count + uint32 startPos = stream.readUint32() + offset; + + for (uint16 i = 0; i < count; i++) { + Common::String entryString; + uint32 nextPos = stream.readUint32() + offset; + uint32 streamPos = stream.pos(); + + stream.seek(startPos); + + while (startPos != nextPos) { + entryString += stream.readByte(); + ++startPos; + } + + strings.push_back(entryString); + + stream.seek(streamPos); + startPos = nextPos; + } + + return strings; +} + +void Score::loadFontMap(Common::SeekableSubReadStreamEndian &stream) { + uint16 count = stream.readUint16(); + uint32 offset = (count * 2) + 2; + uint16 currentRawPosition = offset; + + for (uint16 i = 0; i < count; i++) { + uint16 id = stream.readUint16(); + uint32 positionInfo = stream.pos(); + + stream.seek(currentRawPosition); + + uint16 size = stream.readByte(); + Common::String font; + + for (uint16 k = 0; k < size; k++) { + font += stream.readByte(); + } + + _fontMap[id] = font; + debug(3, "Fontmap. ID %d Font %s", id, font.c_str()); + currentRawPosition = stream.pos(); + stream.seek(positionInfo); + } +} + +BitmapCast::BitmapCast(Common::SeekableSubReadStreamEndian &stream) { + flags = stream.readByte(); + someFlaggyThing = stream.readUint16(); + initialRect = Score::readRect(stream); + boundingRect = Score::readRect(stream); + regY = stream.readUint16(); + regX = stream.readUint16(); + unk1 = unk2 = 0; + + if (someFlaggyThing & 0x8000) { + unk1 = stream.readUint16(); + unk2 = stream.readUint16(); + } + modified = 0; +} + +TextCast::TextCast(Common::SeekableSubReadStreamEndian &stream) { + /*byte flags =*/ stream.readByte(); + borderSize = static_cast<SizeType>(stream.readByte()); + gutterSize = static_cast<SizeType>(stream.readByte()); + boxShadow = static_cast<SizeType>(stream.readByte()); + textType = static_cast<TextType>(stream.readByte()); + textAlign = static_cast<TextAlignType>(stream.readUint16()); + stream.skip(6); //palinfo + + int t = stream.readUint32(); + assert(t == 0); // So far we saw only 0 here + + initialRect = Score::readRect(stream); + textShadow = static_cast<SizeType>(stream.readByte()); + byte flags = stream.readByte(); + if (flags & 0x1) + textFlags.push_back(kTextFlagEditable); + if (flags & 0x2) + textFlags.push_back(kTextFlagAutoTab); + if (flags & 0x4) + textFlags.push_back(kTextFlagDoNotWrap); + + //TODO: FIXME: guesswork + fontId = stream.readByte(); + fontSize = stream.readByte(); + + modified = 0; +} + +ShapeCast::ShapeCast(Common::SeekableSubReadStreamEndian &stream) { + /*byte flags = */ stream.readByte(); + /*unk1 = */ stream.readByte(); + shapeType = static_cast<ShapeType>(stream.readByte()); + initialRect = Score::readRect(stream); + pattern = stream.readUint16BE(); + fgCol = stream.readByte(); + bgCol = stream.readByte(); + fillType = stream.readByte(); + lineThickness = stream.readByte(); + lineDirection = stream.readByte(); + modified = 0; +} + +Common::Rect Score::readRect(Common::SeekableSubReadStreamEndian &stream) { + Common::Rect *rect = new Common::Rect(); + rect->top = stream.readUint16(); + rect->left = stream.readUint16(); + rect->bottom = stream.readUint16(); + rect->right = stream.readUint16(); + + return *rect; +} + +void Score::startLoop() { + initGraphics(_movieRect.width(), _movieRect.height(), true); + + _surface->create(_movieRect.width(), _movieRect.height()); + _trailSurface->create(_movieRect.width(), _movieRect.height()); + + if (_stageColor == 0) + _trailSurface->clear(_vm->getPaletteColorCount() - 1); + else + _trailSurface->clear(_stageColor); + + _currentFrame = 0; + _stopPlay = false; + _nextFrameTime = 0; + + _lingo->processEvent(kEventStartMovie, 0); + _frames[_currentFrame]->prepareFrame(this); + + while (!_stopPlay && _currentFrame < _frames.size() - 2) { + debugC(1, kDebugImages, "Current frame: %d", _currentFrame); + update(); + processEvents(); + } +} + +void Score::update() { + if (g_system->getMillis() < _nextFrameTime) + return; + + _surface->clear(); + _surface->copyFrom(*_trailSurface); + + //Enter and exit from previous frame (Director 4) + _lingo->processEvent(kEventEnterFrame, _frames[_currentFrame]->_actionId); + _lingo->processEvent(kEventExitFrame, _frames[_currentFrame]->_actionId); + //TODO Director 6 - another order + + + //TODO Director 6 step: send beginSprite event to any sprites whose span begin in the upcoming frame + //for (uint16 i = 0; i < CHANNEL_COUNT; i++) { + // if (_frames[_currentFrame]->_sprites[i]->_enabled) + // _lingo->processEvent(kEventBeginSprite, i); + //} + + //TODO Director 6 step: send prepareFrame event to all sprites and the script channel in upcoming frame + //_lingo->processEvent(kEventPrepareFrame, _currentFrame); + _currentFrame++; + + Common::SortedArray<Label *>::iterator i; + for (i = _labels->begin(); i != _labels->end(); ++i) { + if ((*i)->number == _currentFrame) { + _currentLabel = (*i)->name; + } + } + + _frames[_currentFrame]->prepareFrame(this); + //Stage is drawn between the prepareFrame and enterFrame events (Lingo in a Nutshell) + + byte tempo = _frames[_currentFrame]->_tempo; + + if (tempo) { + if (tempo > 161) { + //Delay + _nextFrameTime = g_system->getMillis() + (256 - tempo) * 1000; + + return; + } else if (tempo <= 60) { + //FPS + _nextFrameTime = g_system->getMillis() + (float)tempo / 60 * 1000; + _currentFrameRate = tempo; + } else if (tempo >= 136) { + //TODO Wait for channel tempo - 135 + } else if (tempo == 128) { + //TODO Wait for Click/Key + } else if (tempo == 135) { + //Wait for sound channel 1 + while (_soundManager->isChannelActive(1)) { + processEvents(); + } + } else if (tempo == 134) { + //Wait for sound channel 2 + while (_soundManager->isChannelActive(2)) { + processEvents(); + } + } + } + _nextFrameTime = g_system->getMillis() + (float)_currentFrameRate / 60 * 1000; +} + +void Score::processEvents() { + if (_currentFrame > 0) + _lingo->processEvent(kEventIdle, _currentFrame - 1); + + Common::Event event; + + int endTime = g_system->getMillis() + 200; + + while (g_system->getMillis() < endTime) { + while (g_system->getEventManager()->pollEvent(event)) { + if (event.type == Common::EVENT_QUIT) + _stopPlay = true; + + if (event.type == Common::EVENT_LBUTTONDOWN) { + Common::Point pos = g_system->getEventManager()->getMousePos(); + + //TODO there is dont send frame id + _lingo->processEvent(kEventMouseDown, _frames[_currentFrame]->getSpriteIDFromPos(pos)); + } + + if (event.type == Common::EVENT_LBUTTONUP) { + Common::Point pos = g_system->getEventManager()->getMousePos(); + + _lingo->processEvent(kEventMouseUp, _frames[_currentFrame]->getSpriteIDFromPos(pos)); + } + } + + g_system->updateScreen(); + g_system->delayMillis(10); + } +} + +Sprite *Score::getSpriteById(uint16 id) { + if (_frames[_currentFrame]->_sprites[id]) { + return _frames[_currentFrame]->_sprites[id]; + } else { + warning("Sprite on frame %d width id %d not found", _currentFrame, id); + return nullptr; + } +} + +} //End of namespace Director |