From 5364b46d6ac2a0907d864ec1aa60cd4835f4d1dc Mon Sep 17 00:00:00 2001 From: Paul Gilbert Date: Sun, 14 Jun 2015 08:56:00 -0400 Subject: SHERLOCK: RT: Move checkObject from Object to BaseObject checkObject needs to be called in checkSprite now, which is in the Sprite class. So the method and a few others it depeends on have been moved into BaseObject --- engines/sherlock/objects.cpp | 1855 +++++++++++++++++++++--------------------- 1 file changed, 927 insertions(+), 928 deletions(-) (limited to 'engines/sherlock/objects.cpp') diff --git a/engines/sherlock/objects.cpp b/engines/sherlock/objects.cpp index 29c5d73ad9..df91995c35 100644 --- a/engines/sherlock/objects.cpp +++ b/engines/sherlock/objects.cpp @@ -70,10 +70,15 @@ static const AdjustWalk ADJUST_WALKS[NUM_ADJUSTED_WALKS] = { { "ITDOWNRG", 8, 0, 0 } }; -SherlockEngine *Sprite::_vm; +SherlockEngine *BaseObject::_vm; /*----------------------------------------------------------------*/ +void BaseObject::setVm(SherlockEngine *vm) { + _vm = vm; + _countCAnimFrames = false; +} + BaseObject::BaseObject() { _type = INVALID; _sequences = nullptr; @@ -156,1023 +161,1114 @@ bool BaseObject::hasAborts() const { return true; } -/*----------------------------------------------------------------*/ - -void Sprite::clear() { - _name = ""; - _description = ""; - _examine.clear(); - _pickUp = ""; - _walkSequences.clear(); - _sequences = nullptr; - _images = nullptr; - _imageFrame = nullptr; - _walkCount = 0; - _allow = 0; - _frameNumber = _sequenceNumber = 0; - _position.x = _position.y = 0; - _delta.x = _delta.y = 0; - _oldPosition.x = _oldPosition.y = 0; - _oldSize.x = _oldSize.y = 0; - _goto.x = _goto.y = 0; - _type = INVALID; - _pickUp.clear(); - _noShapeSize.x = _noShapeSize.y = 0; - _status = 0; - _misc = 0; - _altImages = nullptr; - _altSeq = 0; - Common::fill(&_stopFrames[0], &_stopFrames[8], (ImageFrame *)nullptr); -} - -void Sprite::setImageFrame() { - int frameNum = MAX(_frameNumber, 0); - int imageNumber = _walkSequences[_sequenceNumber][frameNum]; - - if (IS_SERRATED_SCALPEL) - imageNumber = imageNumber + _walkSequences[_sequenceNumber][0] - 2; - else if (imageNumber > _maxFrames) - imageNumber = 1; +void BaseObject::checkObject() { + Scene &scene = *_vm->_scene; + Sound &sound = *_vm->_sound; + Talk &talk = *_vm->_talk; + int checkFrame = _allow ? MAX_FRAME : FRAMES_END; + bool codeFound; - // Get the images to use - ImageFile *images = _altSeq ? _altImages : _images; - assert(images); + if (_seqTo) { + byte *ptr = &_sequences[_frameNumber]; + if (*ptr == _seqTo) { + // The sequence is completed + *ptr = _seqTo + SEQ_TO_CODE + 128; // Reset to normal + _seqTo = 0; + } else { + // Continue doing sequence + if (*ptr > _seqTo) + *ptr -= 1; + else + *ptr += 1; - if (_vm->getPlatform() == Common::kPlatform3DO) { - // only do this to the image-array with 110 entries - // map uses another image-array and this code - if (images->size() == 110) { - // 3DO has 110 animation frames inside walk.anim - // PC has 55 - // this adjusts the framenumber accordingly - // sort of HACK - imageNumber *= 2; + return; } - } else if (IS_ROSE_TATTOO) { - --imageNumber; } - // Set the frame pointer - _imageFrame = &(*images)[imageNumber]; -} - -void Sprite::checkSprite() { - Events &events = *_vm->_events; - People &people = *_vm->_people; - Scene &scene = *_vm->_scene; - Screen &screen = *_vm->_screen; - Talk &talk = *_vm->_talk; - Point32 pt; - Common::Rect objBounds; - Common::Point spritePt(_position.x / FIXED_INT_MULTIPLIER, _position.y / FIXED_INT_MULTIPLIER); - - if (_type != CHARACTER || (IS_SERRATED_SCALPEL && talk._talkCounter)) - return; - - pt = _walkCount ? _position + _delta : _position; - pt.x /= FIXED_INT_MULTIPLIER; - pt.y /= FIXED_INT_MULTIPLIER; + ++_frameNumber; - if (IS_ROSE_TATTOO) { - // TODO: Needs to be called - //checkObject(1001); + do { + // Check for end of sequence + codeFound = checkEndOfSequence(); - // For Rose Tattoo, we only do the further processing for Sherlock - if (this != &people[HOLMES]) - return; - } + if (_sequences[_frameNumber] >= 128 && _frameNumber < checkFrame) { + codeFound = true; + int v = _sequences[_frameNumber]; - for (uint idx = 0; idx < scene._bgShapes.size() && !talk._talkToAbort; ++idx) { - Object &obj = scene._bgShapes[idx]; - if (obj._aType <= PERSON || obj._type == INVALID || obj._type == HIDDEN) - continue; + // Check for a Talk or Listen Sequence + if (IS_ROSE_TATTOO && v == ALLOW_TALK_CODE) { + if (_gotoSeq) { + setObjTalkSequence(_gotoSeq); + } else { + ++_frameNumber; + } + } else if (IS_ROSE_TATTOO && (v == TALK_SEQ_CODE || v == TALK_LISTEN_CODE)) { + if (_talkSeq) + setObjTalkSequence(_talkSeq); + else + setObjSequence(0, false); + } else if (v >= GOTO_CODE) { + // Goto code found + v -= GOTO_CODE; + _seqCounter2 = _seqCounter; + _seqStack = _frameNumber + 1; + setObjSequence(v, false); + } else if (v >= SOUND_CODE && (v < (SOUND_CODE + 30))) { + codeFound = true; + ++_frameNumber; + v -= SOUND_CODE + (IS_SERRATED_SCALPEL ? 1 : 0); - if (obj._type == NO_SHAPE) { - objBounds = Common::Rect(obj._position.x, obj._position.y, - obj._position.x + obj._noShapeSize.x + 1, obj._position.y + obj._noShapeSize.y + 1); - } else { - int xp = obj._position.x + obj._imageFrame->_offset.x; - int yp = obj._position.y + obj._imageFrame->_offset.y; - objBounds = Common::Rect(xp, yp, - xp + obj._imageFrame->_frame.w + 1, yp + obj._imageFrame->_frame.h + 1); - } + if (sound._soundOn && !_countCAnimFrames) { + if (!scene._sounds[v]._name.empty() && sound._digitized) + sound.playLoadedSound(v, WAIT_RETURN_IMMEDIATELY); + } + } else if (v >= FLIP_CODE && v < (FLIP_CODE + 3)) { + // Flip code + codeFound = true; + ++_frameNumber; + v -= FLIP_CODE; - if (objBounds.contains(pt)) { - if (objBounds.contains(spritePt)) { - // Current point is already inside the the bounds, so impact occurred - // on a previous call. So simply do nothing until we're clear of the box - switch (obj._aType) { - case TALK_MOVE: - if (_walkCount) { - // Holmes is moving - obj._type = HIDDEN; - obj.setFlagsAndToggles(); - talk.talkTo(obj._use[0]._target); - } + // Alter the flipped status + switch (v) { + case 0: + // Clear the flag + _flags &= ~OBJ_FLIPPED; + break; + case 1: + // Set the flag + _flags |= OBJ_FLIPPED; + break; + case 2: + // Toggle the flag + _flags ^= OBJ_FLIPPED; break; + default: + break; + } + } else if (IS_ROSE_TATTOO && v == TELEPORT_CODE) { + _position.x = READ_LE_UINT16(&_sequences[_frameNumber + 1]); + _position.y = READ_LE_UINT16(&_sequences[_frameNumber + 3]); - case PAL_CHANGE: - case PAL_CHANGE2: - if (_walkCount) { - int palStart = atoi(obj._use[0]._names[0].c_str()) * 3; - int palLength = atoi(obj._use[0]._names[1].c_str()) * 3; - int templ = atoi(obj._use[0]._names[2].c_str()) * 3; - if (templ == 0) - templ = 100; + _frameNumber += 5; + } else if (IS_ROSE_TATTOO && v == CALL_TALK_CODE) { + Common::String filename; + for (int idx = 0; idx < 8; ++idx) { + if (_sequences[_frameNumber + 1 + idx] != 1) + filename += (char)_sequences[_frameNumber + 1 + idx]; + else + break; + } - // Ensure only valid palette change data found - if (palLength > 0) { - // Figure out how far into the shape Holmes is so that we - // can figure out what percentage of the original palette - // to set the current palette to - int palPercent = (pt.x - objBounds.left) * 100 / objBounds.width(); - palPercent = palPercent * templ / 100; - if (obj._aType == PAL_CHANGE) - // Invert percentage - palPercent = 100 - palPercent; + _frameNumber += 8; + talk.talkTo(filename); - for (int i = palStart; i < (palStart + palLength); ++i) - screen._sMap[i] = screen._cMap[i] * palPercent / 100; + } else if (IS_ROSE_TATTOO && v == HIDE_CODE) { + switch (_sequences[_frameNumber + 2]) { + case 1: + // Hide Object + if (scene._bgShapes[_sequences[_frameNumber + 1] - 1]._type != HIDDEN) + scene._bgShapes[_sequences[_frameNumber + 1] - 1].toggleHidden(); + break; - events.pollEvents(); - screen.setPalette(screen._sMap); - } - } + case 2: + // Activate Object + if (scene._bgShapes[_sequences[_frameNumber + 1] - 1]._type == HIDDEN) + scene._bgShapes[_sequences[_frameNumber + 1] - 1].toggleHidden(); break; - case TALK: - case TALK_EVERY: - obj._type = HIDDEN; - obj.setFlagsAndToggles(); - talk.talkTo(obj._use[0]._target); + case 3: + // Toggle Object + scene._bgShapes[_sequences[_frameNumber + 1] - 1].toggleHidden(); break; default: break; } + _frameNumber += 3; + } else { - // New impact just occurred - switch (obj._aType) { - case BLANK_ZONE: - // A blank zone masks out all other remaining zones underneath it. - // If this zone is hit, exit the outer loop so we do not check anymore - return; - - case SOLID: - case TALK: - // Stop walking - if (obj._aType == TALK) { - obj.setFlagsAndToggles(); - talk.talkTo(obj._use[0]._target); - } else { - gotoStand(); - } - break; + v -= 128; - case TALK_EVERY: - if (obj._aType == TALK_EVERY) { - obj._type = HIDDEN; - obj.setFlagsAndToggles(); - talk.talkTo(obj._use[0]._target); - } else { - gotoStand(); - } - break; + // 68-99 is a squence code + if (v > SEQ_TO_CODE) { + byte *p = &_sequences[_frameNumber]; + v -= SEQ_TO_CODE; // # from 1-32 + _seqTo = v; + *p = *(p - 1); - case FLAG_SET: - obj.setFlagsAndToggles(); - obj._type = HIDDEN; - break; + if (*p > 128) + // If the high bit is set, convert to a real frame + *p -= (byte)(SEQ_TO_CODE - 128); - case WALK_AROUND: - if (objBounds.contains(people[HOLMES]._walkTo.front())) { - // Reached zone - gotoStand(); - } else { - // Destination not within box, walk to best corner - Common::Point walkPos; + if (*p > _seqTo) + *p -= 1; + else + *p += 1; - if (spritePt.x >= objBounds.left && spritePt.x < objBounds.right) { - // Impact occurred due to vertical movement. Determine whether to - // travel to the left or right side - if (_delta.x > 0) - // Go to right side - walkPos.x = objBounds.right + CLEAR_DIST_X; - else if (_delta.x < 0) { - // Go to left side - walkPos.x = objBounds.left - CLEAR_DIST_X; - } else { - // Going straight up or down. So choose best side - if (spritePt.x >= (objBounds.left + objBounds.width() / 2)) - walkPos.x = objBounds.right + CLEAR_DIST_X; - else - walkPos.x = objBounds.left - CLEAR_DIST_X; - } + // Will be incremented below to return back to original value + --_frameNumber; + v = 0; - walkPos.y = (_delta.y >= 0) ? objBounds.top - CLEAR_DIST_Y : - objBounds.bottom + CLEAR_DIST_Y; - } else { - // Impact occurred due to horizontal movement - if (_delta.y > 0) - // Go to bottom of box - walkPos.y = objBounds.bottom + CLEAR_DIST_Y; - else if (_delta.y < 0) - // Go to top of box - walkPos.y = objBounds.top - CLEAR_DIST_Y; - else { - // Going straight horizontal, so choose best side - if (spritePt.y >= (objBounds.top + objBounds.height() / 2)) - walkPos.y = objBounds.bottom + CLEAR_DIST_Y; - else - walkPos.y = objBounds.top - CLEAR_DIST_Y; - } + } else if (IS_ROSE_TATTOO && v == 10) { + // Set delta for objects + _delta = Common::Point(READ_LE_UINT16(&_sequences[_frameNumber + 1]), + READ_LE_UINT16(&_sequences[_frameNumber + 3])); + _noShapeSize = Common::Point(0, 0); + _frameNumber += 4; - walkPos.x = (_delta.x >= 0) ? objBounds.left - CLEAR_DIST_X : - objBounds.right + CLEAR_DIST_X; - } + } else if (v == 10) { + // Set delta for objects + Common::Point pt(_sequences[_frameNumber + 1], _sequences[_frameNumber + 2]); + if (pt.x > 128) + pt.x = (pt.x - 128) * -1; + else + pt.x--; - walkPos.x += people[HOLMES]._imageFrame->_frame.w / 2; - people._walkDest = walkPos; - people[HOLMES]._walkTo.push(walkPos); - people[HOLMES].setWalking(); - } - break; + if (pt.y > 128) + pt.y = (pt.y - 128) * -1; + else + pt.y--; - case DELTA: - _position.x += 200; - break; + _delta = pt; + _frameNumber += 2; - default: - break; + } else if (v < USE_COUNT) { + for (int idx = 0; idx < NAMES_COUNT; ++idx) { + checkNameForCodes(_use[v]._names[idx], nullptr); + } + + if (_use[v]._useFlag) + _vm->setFlags(_use[v]._useFlag); } + + ++_frameNumber; } } - } + } while (codeFound); } -const Common::Rect Sprite::getOldBounds() const { - return Common::Rect(_oldPosition.x, _oldPosition.y, _oldPosition.x + _oldSize.x, _oldPosition.y + _oldSize.y); -} +bool BaseObject::checkEndOfSequence() { + Screen &screen = *_vm->_screen; + int checkFrame = _allow ? MAX_FRAME : FRAMES_END; + bool result = false; -void Sprite::setObjTalkSequence(int seq) { - assert(seq != -1 && _type == CHARACTER); + if (_type == REMOVE || _type == INVALID) + return false; - if (_seqTo) { - // reset to previous value - _walkSequences[_sequenceNumber]._sequences[_frameNumber] = _seqTo; - _seqTo = 0; + if (_sequences[_frameNumber] == 0 || _frameNumber >= checkFrame) { + result = true; + + if (_frameNumber >= (checkFrame - 1)) { + _frameNumber = START_FRAME; + } else { + // Determine next sequence to use + int seq = _sequences[_frameNumber + 1]; + + if (seq == 99) { + --_frameNumber; + screen._backBuffer1.transBlitFrom(*_imageFrame, _position); + screen._backBuffer2.transBlitFrom(*_imageFrame, _position); + _type = INVALID; + } else if (IS_ROSE_TATTOO && _talkSeq && seq == 0) { + setObjTalkSequence(_talkSeq); + } else { + setObjSequence(seq, false); + } + } + + if (_allow && _frameNumber == 0) { + // canimation just ended + if (_type != NO_SHAPE && _type != REMOVE) { + _type = REMOVE; + + if (!_countCAnimFrames) { + // Save details before shape is removed + _delta.x = _imageFrame->_frame.w; + _delta.y = _imageFrame->_frame.h; + _position += _imageFrame->_offset; + + // Free the images + delete _images; + _images = nullptr; + _imageFrame = nullptr; + } + } else { + _type = INVALID; + } + } } - _sequenceNumber = _gotoSeq; - _frameNumber = 0; - checkWalkGraphics(); + return result; } -void Sprite::checkWalkGraphics() { - People &people = *_vm->_people; +void BaseObject::setObjSequence(int seq, bool wait) { + Scene &scene = *_vm->_scene; + int checkFrame = _allow ? MAX_FRAME : FRAMES_END; - if (_images == nullptr) { - freeAltGraphics(); - return; - } + if (seq >= 128) { + // Loop the sequence until the count exceeded + seq -= 128; - Common::String filename = Common::String::format("%s.vgs", _walkSequences[_sequenceNumber]._vgsName.c_str()); + ++_seqCounter; + if (_seqCounter >= seq) { + // Go to next sequence + if (_seqStack) { + _frameNumber = _seqStack; + _seqStack = 0; + _seqCounter = _seqCounter2; + _seqCounter2 = 0; + if (_frameNumber >= checkFrame) + _frameNumber = START_FRAME; - // Set the adjust depending on if we have to fine tune the x position of this particular graphic - _adjust.x = _adjust.y = 0; + return; + } - for (int idx = 0; idx < NUM_ADJUSTED_WALKS; ++idx) { - if (!scumm_strnicmp(_walkSequences[_sequenceNumber]._vgsName.c_str(), ADJUST_WALKS[idx]._vgsName, - strlen(ADJUST_WALKS[idx]._vgsName))) { - if (_walkSequences[_sequenceNumber]._horizFlip) - _adjust.x = ADJUST_WALKS[idx]._flipXAdjust; + _frameNumber += 2; + if (_frameNumber >= checkFrame) + _frameNumber = 0; + + _seqCounter = 0; + if (_sequences[_frameNumber] == 0) + seq = _sequences[_frameNumber + 1]; else - _adjust.x = ADJUST_WALKS[idx]._xAdjust; + return; + } else { + // Find beginning of sequence + do { + --_frameNumber; + } while (_frameNumber > 0 && _sequences[_frameNumber] != 0); - _adjust.y = ADJUST_WALKS[idx]._yAdjust; - break; + if (_frameNumber != 0) + _frameNumber += 2; + + return; } + } else { + // Reset sequence counter + _seqCounter = 0; } - // See if we're already using Alternate Graphics - if (_altSeq) { - // See if the VGS file called for is different than the alternate graphics already loaded - if (!_walkSequences[_sequenceNumber]._vgsName.compareToIgnoreCase(_walkSequences[_altSeq - 1]._vgsName)) { - // Different AltGraphics, Free the old ones - freeAltGraphics(); + int idx = 0; + int seqCc = 0; + + while (seqCc < seq && idx < checkFrame) { + ++idx; + if (_sequences[idx] == 0) { + ++seqCc; + idx += 2; } } - // If there is no Alternate Sequence set, see if we need to load a new one - if (!_altSeq) { - int npcNum = -1; - // Find which NPC this is so we can check the name of the graphics loaded - for (int idx = 0; idx < MAX_CHARACTERS; ++idx) { - if (this == &people[idx]) { - npcNum = idx; - break; - } - } + if (idx >= checkFrame) + idx = 0; + _frameNumber = idx; - if (npcNum != -1) { - // See if the VGS file called for is different than the main graphics which are already loaded - if (!filename.compareToIgnoreCase(people[npcNum]._walkVGSName)) { - // See if this is one of the more used Walk Graphics stored in WALK.LIB - for (int idx = 0; idx < NUM_IN_WALK_LIB; ++idx) { - if (!scumm_stricmp(filename.c_str(), WALK_LIB_NAMES[idx])) { - people._useWalkLib = true; - break; - } - } - - _altImages = new ImageFile(filename); - people._useWalkLib = false; - - _altSeq = _sequenceNumber + 1; - } - } - } + if (wait) { + seqCc = idx; + while (_sequences[idx] != 0) + ++idx; - // If this is a different seqeunce from the current sequence, reset the appropriate variables - if (_sequences != &_walkSequences[_sequenceNumber]._sequences[0]) { - _seqTo = _seqCounter = _seqCounter2 = _seqStack = _startSeq = 0; - _sequences = &_walkSequences[_sequenceNumber]._sequences[0]; - _seqSize = _walkSequences[_sequenceNumber]._sequences.size(); + idx = idx - seqCc + 2; + for (; idx > 0; --idx) + scene.doBgAnim(); } - - setImageFrame(); } -void Sprite::freeAltGraphics() { - if (_altImages != nullptr) { - delete _altImages; - _altImages = nullptr; - } - - _altSeq = 0; -} +int BaseObject::checkNameForCodes(const Common::String &name, const char *const messages[]) { + People &people = *_vm->_people; + Scene &scene = *_vm->_scene; + Screen &screen = *_vm->_screen; + Talk &talk = *_vm->_talk; + UserInterface &ui = *_vm->_ui; + bool printed = false; -/*----------------------------------------------------------------*/ + scene.toggleObject(name); -void WalkSequence::load(Common::SeekableReadStream &s) { - char buffer[9]; - s.read(buffer, 9); - _vgsName = Common::String(buffer); - _horizFlip = s.readByte() != 0; + if (name.hasPrefix("*")) { + // A code was found + printed = true; + char ch = (name == "*") ? 0 : toupper(name[1]); - _sequences.resize(s.readUint16LE()); - s.skip(4); // Skip over pointer field of structure + switch (ch) { + case 'C': + talk.talkTo(name.c_str() + 2); + break; - s.read(&_sequences[0], _sequences.size()); -} + case 'T': + case 'B': + case 'F': + case 'W': + // Nothing: action was already done before canimation + break; -/*----------------------------------------------------------------*/ + case 'G': + case 'A': { + // G: Have object go somewhere + // A: Add onto existing co-ordinates + Common::String sx(name.c_str() + 2, name.c_str() + 5); + Common::String sy(name.c_str() + 6, name.c_str() + 9); -WalkSequences &WalkSequences::operator=(const WalkSequences &src) { - resize(src.size()); - for (uint idx = 0; idx < size(); ++idx) { - const WalkSequence &wSrc = src[idx]; - WalkSequence &wDest = (*this)[idx]; - wDest._horizFlip = wSrc._horizFlip; + if (ch == 'G') + _position = Common::Point(atoi(sx.c_str()), atoi(sy.c_str())); + else + _position += Common::Point(atoi(sx.c_str()), atoi(sy.c_str())); + break; + } - wDest._sequences.resize(wSrc._sequences.size()); - Common::copy(&wSrc._sequences[0], &wSrc._sequences[0] + wSrc._sequences.size(), &wDest._sequences[0]); - } + default: + if (ch >= '0' && ch <= '9') { + scene._goToScene = atoi(name.c_str() + 1); - return *this; -} + if (IS_SERRATED_SCALPEL && scene._goToScene < 97) { + Scalpel::ScalpelMap &map = *(Scalpel::ScalpelMap *)_vm->_map; + if (map[scene._goToScene].x) { + map._overPos.x = (map[scene._goToScene].x - 6) * FIXED_INT_MULTIPLIER; + map._overPos.y = (map[scene._goToScene].y + 9) * FIXED_INT_MULTIPLIER; + } + } -/*----------------------------------------------------------------*/ + const char *p; + if ((p = strchr(name.c_str(), ',')) != nullptr) { + ++p; -ActionType::ActionType() { - _cAnimNum = _cAnimSpeed = 0; -} + Common::String s(p, p + 3); + people._hSavedPos.x = atoi(s.c_str()); -void ActionType::load(Common::SeekableReadStream &s) { - char buffer[12]; + s = Common::String(p + 3, p + 6); + people._hSavedPos.y = atoi(s.c_str()); - _cAnimNum = s.readByte(); - _cAnimSpeed = s.readByte(); - if (_cAnimSpeed & 0x80) - _cAnimSpeed = -(_cAnimSpeed & 0x7f); + s = Common::String(p + 6, p + 9); + people._hSavedFacing = atoi(s.c_str()); + if (people._hSavedFacing == 0) + people._hSavedFacing = 10; + } else if ((p = strchr(name.c_str(), '/')) != nullptr) { + people._hSavedPos = Common::Point(1, 0); + people._hSavedFacing = 100 + atoi(p + 1); + } + } else { + scene._goToScene = 100; + } - for (int idx = 0; idx < NAMES_COUNT; ++idx) { - s.read(buffer, 12); - _names[idx] = Common::String(buffer); + people[HOLMES]._position = Point32(0, 0); + break; + } + } else if (name.hasPrefix("!")) { + // Message attached to canimation + int messageNum = atoi(name.c_str() + 1); + ui._infoFlag = true; + ui.clearInfo(); + screen.print(Common::Point(0, INFO_LINE + 1), INFO_FOREGROUND, "%s", messages[messageNum]); + ui._menuCounter = 25; + } else if (name.hasPrefix("@")) { + // Message attached to canimation + ui._infoFlag = true; + ui.clearInfo(); + screen.print(Common::Point(0, INFO_LINE + 1), INFO_FOREGROUND, "%s", name.c_str() + 1); + printed = true; + ui._menuCounter = 25; } + + return printed; } /*----------------------------------------------------------------*/ -UseType::UseType(): ActionType() { - _useFlag = 0; +void Sprite::clear() { + _name = ""; + _description = ""; + _examine.clear(); + _pickUp = ""; + _walkSequences.clear(); + _sequences = nullptr; + _images = nullptr; + _imageFrame = nullptr; + _walkCount = 0; + _allow = 0; + _frameNumber = _sequenceNumber = 0; + _position.x = _position.y = 0; + _delta.x = _delta.y = 0; + _oldPosition.x = _oldPosition.y = 0; + _oldSize.x = _oldSize.y = 0; + _goto.x = _goto.y = 0; + _type = INVALID; + _pickUp.clear(); + _noShapeSize.x = _noShapeSize.y = 0; + _status = 0; + _misc = 0; + _altImages = nullptr; + _altSeq = 0; + Common::fill(&_stopFrames[0], &_stopFrames[8], (ImageFrame *)nullptr); } -void UseType::load(Common::SeekableReadStream &s, bool isRoseTattoo) { - char buffer[12]; +void Sprite::setImageFrame() { + int frameNum = MAX(_frameNumber, 0); + int imageNumber = _walkSequences[_sequenceNumber][frameNum]; + + if (IS_SERRATED_SCALPEL) + imageNumber = imageNumber + _walkSequences[_sequenceNumber][0] - 2; + else if (imageNumber > _maxFrames) + imageNumber = 1; - if (isRoseTattoo) { - s.read(buffer, 12); - _verb = Common::String(buffer); - } + // Get the images to use + ImageFile *images = _altSeq ? _altImages : _images; + assert(images); - ActionType::load(s); + if (_vm->getPlatform() == Common::kPlatform3DO) { + // only do this to the image-array with 110 entries + // map uses another image-array and this code + if (images->size() == 110) { + // 3DO has 110 animation frames inside walk.anim + // PC has 55 + // this adjusts the framenumber accordingly + // sort of HACK + imageNumber *= 2; + } + } else if (IS_ROSE_TATTOO) { + --imageNumber; + } - _useFlag = s.readSint16LE(); + // Set the frame pointer + _imageFrame = &(*images)[imageNumber]; +} - if (!isRoseTattoo) - s.skip(6); +void Sprite::checkSprite() { + Events &events = *_vm->_events; + People &people = *_vm->_people; + Scene &scene = *_vm->_scene; + Screen &screen = *_vm->_screen; + Talk &talk = *_vm->_talk; + Point32 pt; + Common::Rect objBounds; + Common::Point spritePt(_position.x / FIXED_INT_MULTIPLIER, _position.y / FIXED_INT_MULTIPLIER); - s.read(buffer, 12); - _target = Common::String(buffer); -} + if (_type != CHARACTER || (IS_SERRATED_SCALPEL && talk._talkCounter)) + return; -void UseType::load3DO(Common::SeekableReadStream &s) { - char buffer[12]; + pt = _walkCount ? _position + _delta : _position; + pt.x /= FIXED_INT_MULTIPLIER; + pt.y /= FIXED_INT_MULTIPLIER; - _cAnimNum = s.readByte(); - _cAnimSpeed = s.readByte(); - if (_cAnimSpeed & 0x80) - _cAnimSpeed = -(_cAnimSpeed & 0x7f); + if (IS_ROSE_TATTOO) { + // TODO: Needs to be called + //checkObject(1001); - for (int idx = 0; idx < NAMES_COUNT; ++idx) { - s.read(buffer, 12); - _names[idx] = Common::String(buffer); + // For Rose Tattoo, we only do the further processing for Sherlock + if (this != &people[HOLMES]) + return; } - _useFlag = s.readSint16BE(); - - s.skip(6); + for (uint idx = 0; idx < scene._bgShapes.size() && !talk._talkToAbort; ++idx) { + Object &obj = scene._bgShapes[idx]; + if (obj._aType <= PERSON || obj._type == INVALID || obj._type == HIDDEN) + continue; - s.read(buffer, 12); - _target = Common::String(buffer); -} + if (obj._type == NO_SHAPE) { + objBounds = Common::Rect(obj._position.x, obj._position.y, + obj._position.x + obj._noShapeSize.x + 1, obj._position.y + obj._noShapeSize.y + 1); + } else { + int xp = obj._position.x + obj._imageFrame->_offset.x; + int yp = obj._position.y + obj._imageFrame->_offset.y; + objBounds = Common::Rect(xp, yp, + xp + obj._imageFrame->_frame.w + 1, yp + obj._imageFrame->_frame.h + 1); + } -/*----------------------------------------------------------------*/ + if (objBounds.contains(pt)) { + if (objBounds.contains(spritePt)) { + // Current point is already inside the the bounds, so impact occurred + // on a previous call. So simply do nothing until we're clear of the box + switch (obj._aType) { + case TALK_MOVE: + if (_walkCount) { + // Holmes is moving + obj._type = HIDDEN; + obj.setFlagsAndToggles(); + talk.talkTo(obj._use[0]._target); + } + break; -SherlockEngine *Object::_vm; -bool Object::_countCAnimFrames; + case PAL_CHANGE: + case PAL_CHANGE2: + if (_walkCount) { + int palStart = atoi(obj._use[0]._names[0].c_str()) * 3; + int palLength = atoi(obj._use[0]._names[1].c_str()) * 3; + int templ = atoi(obj._use[0]._names[2].c_str()) * 3; + if (templ == 0) + templ = 100; -void Object::setVm(SherlockEngine *vm) { - _vm = vm; - _countCAnimFrames = false; -} + // Ensure only valid palette change data found + if (palLength > 0) { + // Figure out how far into the shape Holmes is so that we + // can figure out what percentage of the original palette + // to set the current palette to + int palPercent = (pt.x - objBounds.left) * 100 / objBounds.width(); + palPercent = palPercent * templ / 100; + if (obj._aType == PAL_CHANGE) + // Invert percentage + palPercent = 100 - palPercent; -Object::Object(): BaseObject() { - _sequenceNumber = 0; - _sequenceOffset = 0; - _pickup = 0; - _defaultCommand = 0; - _pickupFlag = 0; -} + for (int i = palStart; i < (palStart + palLength); ++i) + screen._sMap[i] = screen._cMap[i] * palPercent / 100; -void Object::load(Common::SeekableReadStream &s, bool isRoseTattoo) { - char buffer[41]; - s.read(buffer, 12); - _name = Common::String(buffer); - s.read(buffer, 41); - _description = Common::String(buffer); + events.pollEvents(); + screen.setPalette(screen._sMap); + } + } + break; - _examine.clear(); - _sequences = nullptr; - _images = nullptr; - _imageFrame = nullptr; + case TALK: + case TALK_EVERY: + obj._type = HIDDEN; + obj.setFlagsAndToggles(); + talk.talkTo(obj._use[0]._target); + break; - s.skip(4); - _sequenceOffset = s.readUint16LE(); - s.seek(10, SEEK_CUR); + default: + break; + } + } else { + // New impact just occurred + switch (obj._aType) { + case BLANK_ZONE: + // A blank zone masks out all other remaining zones underneath it. + // If this zone is hit, exit the outer loop so we do not check anymore + return; - _walkCount = s.readByte(); - _allow = s.readByte(); - _frameNumber = s.readSint16LE(); - _sequenceNumber = s.readSint16LE(); - _position.x = s.readSint16LE(); - _position.y = s.readSint16LE(); - _delta.x = s.readSint16LE(); - _delta.y = s.readSint16LE(); - _type = (SpriteType)s.readUint16LE(); - _oldPosition.x = s.readSint16LE(); - _oldPosition.y = s.readSint16LE(); - _oldSize.x = s.readUint16LE(); - _oldSize.y = s.readUint16LE(); - - _goto.x = s.readSint16LE(); - _goto.y = s.readSint16LE(); - if (!isRoseTattoo) { - _goto.x = _goto.x * FIXED_INT_MULTIPLIER / 100; - _goto.y = _goto.y * FIXED_INT_MULTIPLIER / 100; - } + case SOLID: + case TALK: + // Stop walking + if (obj._aType == TALK) { + obj.setFlagsAndToggles(); + talk.talkTo(obj._use[0]._target); + } else { + gotoStand(); + } + break; - _pickup = isRoseTattoo ? 0 : s.readByte(); - _defaultCommand = isRoseTattoo ? 0 : s.readByte(); - _lookFlag = s.readSint16LE(); - _pickupFlag = isRoseTattoo ? 0 : s.readSint16LE(); - _requiredFlag = s.readSint16LE(); - _noShapeSize.x = s.readUint16LE(); - _noShapeSize.y = s.readUint16LE(); - _status = s.readUint16LE(); - _misc = s.readByte(); - _maxFrames = s.readUint16LE(); - _flags = s.readByte(); + case TALK_EVERY: + if (obj._aType == TALK_EVERY) { + obj._type = HIDDEN; + obj.setFlagsAndToggles(); + talk.talkTo(obj._use[0]._target); + } else { + gotoStand(); + } + break; - if (!isRoseTattoo) - _aOpen.load(s); + case FLAG_SET: + obj.setFlagsAndToggles(); + obj._type = HIDDEN; + break; - _aType = (AType)s.readByte(); - _lookFrames = s.readByte(); - _seqCounter = s.readByte(); - _lookPosition.x = s.readUint16LE() * FIXED_INT_MULTIPLIER / 100; - _lookPosition.y = (isRoseTattoo ? s.readSint16LE() : s.readByte()) * FIXED_INT_MULTIPLIER; - _lookFacing = s.readByte(); - _lookcAnim = s.readByte(); + case WALK_AROUND: + if (objBounds.contains(people[HOLMES]._walkTo.front())) { + // Reached zone + gotoStand(); + } else { + // Destination not within box, walk to best corner + Common::Point walkPos; - if (!isRoseTattoo) - _aClose.load(s); + if (spritePt.x >= objBounds.left && spritePt.x < objBounds.right) { + // Impact occurred due to vertical movement. Determine whether to + // travel to the left or right side + if (_delta.x > 0) + // Go to right side + walkPos.x = objBounds.right + CLEAR_DIST_X; + else if (_delta.x < 0) { + // Go to left side + walkPos.x = objBounds.left - CLEAR_DIST_X; + } else { + // Going straight up or down. So choose best side + if (spritePt.x >= (objBounds.left + objBounds.width() / 2)) + walkPos.x = objBounds.right + CLEAR_DIST_X; + else + walkPos.x = objBounds.left - CLEAR_DIST_X; + } - _seqStack = s.readByte(); - _seqTo = s.readByte(); - _descOffset = s.readUint16LE(); - _seqCounter2 = s.readByte(); - _seqSize = s.readUint16LE(); + walkPos.y = (_delta.y >= 0) ? objBounds.top - CLEAR_DIST_Y : + objBounds.bottom + CLEAR_DIST_Y; + } else { + // Impact occurred due to horizontal movement + if (_delta.y > 0) + // Go to bottom of box + walkPos.y = objBounds.bottom + CLEAR_DIST_Y; + else if (_delta.y < 0) + // Go to top of box + walkPos.y = objBounds.top - CLEAR_DIST_Y; + else { + // Going straight horizontal, so choose best side + if (spritePt.y >= (objBounds.top + objBounds.height() / 2)) + walkPos.y = objBounds.bottom + CLEAR_DIST_Y; + else + walkPos.y = objBounds.top - CLEAR_DIST_Y; + } - if (isRoseTattoo) { - for (int idx = 0; idx < 6; ++idx) - _use[idx].load(s, true); + walkPos.x = (_delta.x >= 0) ? objBounds.left - CLEAR_DIST_X : + objBounds.right + CLEAR_DIST_X; + } - _quickDraw = s.readByte(); - _scaleVal = s.readUint16LE(); - _requiredFlags1 = s.readSint16LE(); - _gotoSeq = s.readByte(); - _talkSeq = s.readByte(); - _restoreSlot = s.readByte(); - } else { - s.skip(1); - _aMove.load(s); - s.skip(8); + walkPos.x += people[HOLMES]._imageFrame->_frame.w / 2; + people._walkDest = walkPos; + people[HOLMES]._walkTo.push(walkPos); + people[HOLMES].setWalking(); + } + break; - for (int idx = 0; idx < 4; ++idx) - _use[idx].load(s, false); + case DELTA: + _position.x += 200; + break; + + default: + break; + } + } + } } - //warning("object %s, useAnim %d", _name.c_str(), _use[0]._cAnimNum); } -void Object::load3DO(Common::SeekableReadStream &s) { - int32 streamStartPos = s.pos(); - char buffer[41]; +const Common::Rect Sprite::getOldBounds() const { + return Common::Rect(_oldPosition.x, _oldPosition.y, _oldPosition.x + _oldSize.x, _oldPosition.y + _oldSize.y); +} - _examine.clear(); - _sequences = nullptr; - _images = nullptr; - _imageFrame = nullptr; +void Sprite::setObjTalkSequence(int seq) { + assert(seq != -1 && _type == CHARACTER); - // on 3DO all of this data is reordered!!! - // it seems that possibly the 3DO compiler reordered the global struct - // 3DO size for 1 object is 588 bytes - s.skip(4); - _sequenceOffset = s.readUint16LE(); // weird that this seems to be LE - s.seek(10, SEEK_CUR); + if (_seqTo) { + // reset to previous value + _walkSequences[_sequenceNumber]._sequences[_frameNumber] = _seqTo; + _seqTo = 0; + } + + _sequenceNumber = _gotoSeq; + _frameNumber = 0; + checkWalkGraphics(); +} + +void Sprite::checkWalkGraphics() { + People &people = *_vm->_people; + + if (_images == nullptr) { + freeAltGraphics(); + return; + } + + Common::String filename = Common::String::format("%s.vgs", _walkSequences[_sequenceNumber]._vgsName.c_str()); + + // Set the adjust depending on if we have to fine tune the x position of this particular graphic + _adjust.x = _adjust.y = 0; + + for (int idx = 0; idx < NUM_ADJUSTED_WALKS; ++idx) { + if (!scumm_strnicmp(_walkSequences[_sequenceNumber]._vgsName.c_str(), ADJUST_WALKS[idx]._vgsName, + strlen(ADJUST_WALKS[idx]._vgsName))) { + if (_walkSequences[_sequenceNumber]._horizFlip) + _adjust.x = ADJUST_WALKS[idx]._flipXAdjust; + else + _adjust.x = ADJUST_WALKS[idx]._xAdjust; + + _adjust.y = ADJUST_WALKS[idx]._yAdjust; + break; + } + } + + // See if we're already using Alternate Graphics + if (_altSeq) { + // See if the VGS file called for is different than the alternate graphics already loaded + if (!_walkSequences[_sequenceNumber]._vgsName.compareToIgnoreCase(_walkSequences[_altSeq - 1]._vgsName)) { + // Different AltGraphics, Free the old ones + freeAltGraphics(); + } + } + + // If there is no Alternate Sequence set, see if we need to load a new one + if (!_altSeq) { + int npcNum = -1; + // Find which NPC this is so we can check the name of the graphics loaded + for (int idx = 0; idx < MAX_CHARACTERS; ++idx) { + if (this == &people[idx]) { + npcNum = idx; + break; + } + } - // Offset 16 - _frameNumber = s.readSint16BE(); - _sequenceNumber = s.readSint16BE(); - _position.x = s.readSint16BE(); - _position.y = s.readSint16BE(); - _delta.x = s.readSint16BE(); - _delta.y = s.readSint16BE(); - _type = (SpriteType)s.readUint16BE(); - _oldPosition.x = s.readSint16BE(); - _oldPosition.y = s.readSint16BE(); - _oldSize.x = s.readUint16BE(); - _oldSize.y = s.readUint16BE(); - - _goto.x = s.readSint16BE(); - _goto.y = s.readSint16BE(); - _goto.x = _goto.x * FIXED_INT_MULTIPLIER / 100; - _goto.y = _goto.y * FIXED_INT_MULTIPLIER / 100; + if (npcNum != -1) { + // See if the VGS file called for is different than the main graphics which are already loaded + if (!filename.compareToIgnoreCase(people[npcNum]._walkVGSName)) { + // See if this is one of the more used Walk Graphics stored in WALK.LIB + for (int idx = 0; idx < NUM_IN_WALK_LIB; ++idx) { + if (!scumm_stricmp(filename.c_str(), WALK_LIB_NAMES[idx])) { + people._useWalkLib = true; + break; + } + } - // Offset 42 - warning("pos %d", s.pos()); + _altImages = new ImageFile(filename); + people._useWalkLib = false; - // Unverified - _lookFlag = s.readSint16BE(); - _pickupFlag = s.readSint16BE(); - _requiredFlag = s.readSint16BE(); - _noShapeSize.x = s.readUint16BE(); - _noShapeSize.y = s.readUint16BE(); - _status = s.readUint16BE(); - // Unverified END + _altSeq = _sequenceNumber + 1; + } + } + } - _maxFrames = s.readUint16BE(); - // offset 56 - _lookPosition.x = s.readUint16BE() * FIXED_INT_MULTIPLIER / 100; - // offset 58 - _descOffset = s.readUint16BE(); - _seqSize = s.readUint16BE(); + // If this is a different seqeunce from the current sequence, reset the appropriate variables + if (_sequences != &_walkSequences[_sequenceNumber]._sequences[0]) { + _seqTo = _seqCounter = _seqCounter2 = _seqStack = _startSeq = 0; + _sequences = &_walkSequences[_sequenceNumber]._sequences[0]; + _seqSize = _walkSequences[_sequenceNumber]._sequences.size(); + } - s.skip(2); // boundary filler + setImageFrame(); +} - // 288 bytes - for (int idx = 0; idx < 4; ++idx) { - _use[idx].load3DO(s); - s.skip(2); // Filler +void Sprite::freeAltGraphics() { + if (_altImages != nullptr) { + delete _altImages; + _altImages = nullptr; } - // 158 bytes - _aOpen.load(s); // 2 + 12*4 bytes = 50 bytes - s.skip(2); // Boundary filler - _aClose.load(s); - s.skip(2); // Filler - _aMove.load(s); - s.skip(2); // Filler + _altSeq = 0; +} - // offset 508 - // 3DO: name is at the end - s.read(buffer, 12); - _name = Common::String(buffer); - s.read(buffer, 41); - _description = Common::String(buffer); +/*----------------------------------------------------------------*/ - // Unverified - _walkCount = s.readByte(); - _allow = s.readByte(); - _pickup = s.readByte(); - _defaultCommand = s.readByte(); - // Unverified END +void WalkSequence::load(Common::SeekableReadStream &s) { + char buffer[9]; + s.read(buffer, 9); + _vgsName = Common::String(buffer); + _horizFlip = s.readByte() != 0; - // Probably those here?!?! - _misc = s.readByte(); - _flags = s.readByte(); + _sequences.resize(s.readUint16LE()); + s.skip(4); // Skip over pointer field of structure - // Unverified - _aType = (AType)s.readByte(); - _lookFrames = s.readByte(); - _seqCounter = s.readByte(); - // Unverified END + s.read(&_sequences[0], _sequences.size()); +} - _lookPosition.y = s.readByte() * FIXED_INT_MULTIPLIER; - _lookFacing = s.readByte(); +/*----------------------------------------------------------------*/ - // Unverified - _lookcAnim = s.readByte(); - _seqStack = s.readByte(); - _seqTo = s.readByte(); - _seqCounter2 = s.readByte(); - // Unverified END +WalkSequences &WalkSequences::operator=(const WalkSequences &src) { + resize(src.size()); + for (uint idx = 0; idx < size(); ++idx) { + const WalkSequence &wSrc = src[idx]; + WalkSequence &wDest = (*this)[idx]; + wDest._horizFlip = wSrc._horizFlip; - s.skip(12); // Unknown + wDest._sequences.resize(wSrc._sequences.size()); + Common::copy(&wSrc._sequences[0], &wSrc._sequences[0] + wSrc._sequences.size(), &wDest._sequences[0]); + } - //warning("object %s, offset %d", _name.c_str(), streamPos); - //warning("object %s, lookPosX %d, lookPosY %d", _name.c_str(), _lookPosition.x, _lookPosition.y); - //warning("object %s, defCmd %d", _name.c_str(), _defaultCommand); - int32 dataSize = s.pos() - streamStartPos; - assert(dataSize == 588); + return *this; } -void Object::toggleHidden() { - if (_type != HIDDEN && _type != HIDE_SHAPE && _type != INVALID) { - if (_seqTo != 0) - _sequences[_frameNumber] = _seqTo + SEQ_TO_CODE + 128; - _seqTo = 0; +/*----------------------------------------------------------------*/ - if (_images == nullptr || _images->size() == 0) - // No shape to erase, so flag as hidden - _type = HIDDEN; - else - // Otherwise, flag it to be hidden after it gets erased - _type = HIDE_SHAPE; - } else if (_type != INVALID) { - if (_seqTo != 0) - _sequences[_frameNumber] = _seqTo + SEQ_TO_CODE + 128; - _seqTo = 0; +ActionType::ActionType() { + _cAnimNum = _cAnimSpeed = 0; +} - _seqCounter = _seqCounter2 = 0; - _seqStack = 0; - _frameNumber = -1; +void ActionType::load(Common::SeekableReadStream &s) { + char buffer[12]; - if (_images == nullptr || _images->size() == 0) { - _type = NO_SHAPE; - } else { - _type = ACTIVE_BG_SHAPE; - int idx = _sequences[0]; - if (idx >= _maxFrames) - // Turn on: set up first frame - idx = 0; + _cAnimNum = s.readByte(); + _cAnimSpeed = s.readByte(); + if (_cAnimSpeed & 0x80) + _cAnimSpeed = -(_cAnimSpeed & 0x7f); - _imageFrame = &(*_images)[idx]; - } + for (int idx = 0; idx < NAMES_COUNT; ++idx) { + s.read(buffer, 12); + _names[idx] = Common::String(buffer); } } -void Object::checkObject() { - Scene &scene = *_vm->_scene; - Sound &sound = *_vm->_sound; - Talk &talk = *_vm->_talk; - int checkFrame = _allow ? MAX_FRAME : FRAMES_END; - bool codeFound; +/*----------------------------------------------------------------*/ - if (_seqTo) { - byte *ptr = &_sequences[_frameNumber]; - if (*ptr == _seqTo) { - // The sequence is completed - *ptr = _seqTo + SEQ_TO_CODE + 128; // Reset to normal - _seqTo = 0; - } else { - // Continue doing sequence - if (*ptr > _seqTo) - *ptr -= 1; - else - *ptr += 1; +UseType::UseType(): ActionType() { + _useFlag = 0; +} - return; - } +void UseType::load(Common::SeekableReadStream &s, bool isRoseTattoo) { + char buffer[12]; + + if (isRoseTattoo) { + s.read(buffer, 12); + _verb = Common::String(buffer); } - ++_frameNumber; + ActionType::load(s); - do { - // Check for end of sequence - codeFound = checkEndOfSequence(); + _useFlag = s.readSint16LE(); - if (_sequences[_frameNumber] >= 128 && _frameNumber < checkFrame) { - codeFound = true; - int v = _sequences[_frameNumber]; + if (!isRoseTattoo) + s.skip(6); - // Check for a Talk or Listen Sequence - if (IS_ROSE_TATTOO && v == ALLOW_TALK_CODE) { - if (_gotoSeq) { - setObjTalkSequence(_gotoSeq); - } else { - ++_frameNumber; - } - } else if (IS_ROSE_TATTOO && (v == TALK_SEQ_CODE || v == TALK_LISTEN_CODE)) { - if (_talkSeq) - setObjTalkSequence(_talkSeq); - else - setObjSequence(0, false); - } else if (v >= GOTO_CODE) { - // Goto code found - v -= GOTO_CODE; - _seqCounter2 = _seqCounter; - _seqStack = _frameNumber + 1; - setObjSequence(v, false); - } else if (v >= SOUND_CODE && (v < (SOUND_CODE + 30))) { - codeFound = true; - ++_frameNumber; - v -= SOUND_CODE + (IS_SERRATED_SCALPEL ? 1 : 0); + s.read(buffer, 12); + _target = Common::String(buffer); +} - if (sound._soundOn && !_countCAnimFrames) { - if (!scene._sounds[v]._name.empty() && sound._digitized) - sound.playLoadedSound(v, WAIT_RETURN_IMMEDIATELY); - } - } else if (v >= FLIP_CODE && v < (FLIP_CODE + 3)) { - // Flip code - codeFound = true; - ++_frameNumber; - v -= FLIP_CODE; +void UseType::load3DO(Common::SeekableReadStream &s) { + char buffer[12]; + + _cAnimNum = s.readByte(); + _cAnimSpeed = s.readByte(); + if (_cAnimSpeed & 0x80) + _cAnimSpeed = -(_cAnimSpeed & 0x7f); + + for (int idx = 0; idx < NAMES_COUNT; ++idx) { + s.read(buffer, 12); + _names[idx] = Common::String(buffer); + } - // Alter the flipped status - switch (v) { - case 0: - // Clear the flag - _flags &= ~OBJ_FLIPPED; - break; - case 1: - // Set the flag - _flags |= OBJ_FLIPPED; - break; - case 2: - // Toggle the flag - _flags ^= OBJ_FLIPPED; - break; - default: - break; - } - } else if (IS_ROSE_TATTOO && v == TELEPORT_CODE) { - _position.x = READ_LE_UINT16(&_sequences[_frameNumber + 1]); - _position.y = READ_LE_UINT16(&_sequences[_frameNumber + 3]); + _useFlag = s.readSint16BE(); - _frameNumber += 5; - } else if (IS_ROSE_TATTOO && v == CALL_TALK_CODE) { - Common::String filename; - for (int idx = 0; idx < 8; ++idx) { - if (_sequences[_frameNumber + 1 + idx] != 1) - filename += (char)_sequences[_frameNumber + 1 + idx]; - else - break; - } + s.skip(6); - _frameNumber += 8; - talk.talkTo(filename); + s.read(buffer, 12); + _target = Common::String(buffer); +} - } else if (IS_ROSE_TATTOO && v == HIDE_CODE) { - switch (_sequences[_frameNumber + 2]) { - case 1: - // Hide Object - if (scene._bgShapes[_sequences[_frameNumber + 1] - 1]._type != HIDDEN) - scene._bgShapes[_sequences[_frameNumber + 1] - 1].toggleHidden(); - break; +/*----------------------------------------------------------------*/ - case 2: - // Activate Object - if (scene._bgShapes[_sequences[_frameNumber + 1] - 1]._type == HIDDEN) - scene._bgShapes[_sequences[_frameNumber + 1] - 1].toggleHidden(); - break; +bool Object::_countCAnimFrames; - case 3: - // Toggle Object - scene._bgShapes[_sequences[_frameNumber + 1] - 1].toggleHidden(); - break; +Object::Object(): BaseObject() { + _sequenceNumber = 0; + _sequenceOffset = 0; + _pickup = 0; + _defaultCommand = 0; + _pickupFlag = 0; +} - default: - break; - } - _frameNumber += 3; - - } else { - v -= 128; +void Object::load(Common::SeekableReadStream &s, bool isRoseTattoo) { + char buffer[41]; + s.read(buffer, 12); + _name = Common::String(buffer); + s.read(buffer, 41); + _description = Common::String(buffer); - // 68-99 is a squence code - if (v > SEQ_TO_CODE) { - byte *p = &_sequences[_frameNumber]; - v -= SEQ_TO_CODE; // # from 1-32 - _seqTo = v; - *p = *(p - 1); + _examine.clear(); + _sequences = nullptr; + _images = nullptr; + _imageFrame = nullptr; - if (*p > 128) - // If the high bit is set, convert to a real frame - *p -= (byte)(SEQ_TO_CODE - 128); + s.skip(4); + _sequenceOffset = s.readUint16LE(); + s.seek(10, SEEK_CUR); - if (*p > _seqTo) - *p -= 1; - else - *p += 1; + _walkCount = s.readByte(); + _allow = s.readByte(); + _frameNumber = s.readSint16LE(); + _sequenceNumber = s.readSint16LE(); + _position.x = s.readSint16LE(); + _position.y = s.readSint16LE(); + _delta.x = s.readSint16LE(); + _delta.y = s.readSint16LE(); + _type = (SpriteType)s.readUint16LE(); + _oldPosition.x = s.readSint16LE(); + _oldPosition.y = s.readSint16LE(); + _oldSize.x = s.readUint16LE(); + _oldSize.y = s.readUint16LE(); + + _goto.x = s.readSint16LE(); + _goto.y = s.readSint16LE(); + if (!isRoseTattoo) { + _goto.x = _goto.x * FIXED_INT_MULTIPLIER / 100; + _goto.y = _goto.y * FIXED_INT_MULTIPLIER / 100; + } - // Will be incremented below to return back to original value - --_frameNumber; - v = 0; + _pickup = isRoseTattoo ? 0 : s.readByte(); + _defaultCommand = isRoseTattoo ? 0 : s.readByte(); + _lookFlag = s.readSint16LE(); + _pickupFlag = isRoseTattoo ? 0 : s.readSint16LE(); + _requiredFlag = s.readSint16LE(); + _noShapeSize.x = s.readUint16LE(); + _noShapeSize.y = s.readUint16LE(); + _status = s.readUint16LE(); + _misc = s.readByte(); + _maxFrames = s.readUint16LE(); + _flags = s.readByte(); - } else if (IS_ROSE_TATTOO && v == 10) { - // Set delta for objects - _delta = Common::Point(READ_LE_UINT16(&_sequences[_frameNumber + 1]), - READ_LE_UINT16(&_sequences[_frameNumber + 3])); - _noShapeSize = Common::Point(0, 0); - _frameNumber += 4; + if (!isRoseTattoo) + _aOpen.load(s); - } else if (v == 10) { - // Set delta for objects - Common::Point pt(_sequences[_frameNumber + 1], _sequences[_frameNumber + 2]); - if (pt.x > 128) - pt.x = (pt.x - 128) * -1; - else - pt.x--; + _aType = (AType)s.readByte(); + _lookFrames = s.readByte(); + _seqCounter = s.readByte(); + _lookPosition.x = s.readUint16LE() * FIXED_INT_MULTIPLIER / 100; + _lookPosition.y = (isRoseTattoo ? s.readSint16LE() : s.readByte()) * FIXED_INT_MULTIPLIER; + _lookFacing = s.readByte(); + _lookcAnim = s.readByte(); - if (pt.y > 128) - pt.y = (pt.y - 128) * -1; - else - pt.y--; + if (!isRoseTattoo) + _aClose.load(s); - _delta = pt; - _frameNumber += 2; + _seqStack = s.readByte(); + _seqTo = s.readByte(); + _descOffset = s.readUint16LE(); + _seqCounter2 = s.readByte(); + _seqSize = s.readUint16LE(); - } else if (v < USE_COUNT) { - for (int idx = 0; idx < NAMES_COUNT; ++idx) { - checkNameForCodes(_use[v]._names[idx], nullptr); - } + if (isRoseTattoo) { + for (int idx = 0; idx < 6; ++idx) + _use[idx].load(s, true); - if (_use[v]._useFlag) - _vm->setFlags(_use[v]._useFlag); - } + _quickDraw = s.readByte(); + _scaleVal = s.readUint16LE(); + _requiredFlags1 = s.readSint16LE(); + _gotoSeq = s.readByte(); + _talkSeq = s.readByte(); + _restoreSlot = s.readByte(); + } else { + s.skip(1); + _aMove.load(s); + s.skip(8); - ++_frameNumber; - } - } - } while (codeFound); + for (int idx = 0; idx < 4; ++idx) + _use[idx].load(s, false); + } + //warning("object %s, useAnim %d", _name.c_str(), _use[0]._cAnimNum); } -bool Object::checkEndOfSequence() { - Screen &screen = *_vm->_screen; - int checkFrame = _allow ? MAX_FRAME : FRAMES_END; - bool result = false; +void Object::load3DO(Common::SeekableReadStream &s) { + int32 streamStartPos = s.pos(); + char buffer[41]; - if (_type == REMOVE || _type == INVALID) - return false; + _examine.clear(); + _sequences = nullptr; + _images = nullptr; + _imageFrame = nullptr; - if (_sequences[_frameNumber] == 0 || _frameNumber >= checkFrame) { - result = true; + // on 3DO all of this data is reordered!!! + // it seems that possibly the 3DO compiler reordered the global struct + // 3DO size for 1 object is 588 bytes + s.skip(4); + _sequenceOffset = s.readUint16LE(); // weird that this seems to be LE + s.seek(10, SEEK_CUR); - if (_frameNumber >= (checkFrame - 1)) { - _frameNumber = START_FRAME; - } else { - // Determine next sequence to use - int seq = _sequences[_frameNumber + 1]; + // Offset 16 + _frameNumber = s.readSint16BE(); + _sequenceNumber = s.readSint16BE(); + _position.x = s.readSint16BE(); + _position.y = s.readSint16BE(); + _delta.x = s.readSint16BE(); + _delta.y = s.readSint16BE(); + _type = (SpriteType)s.readUint16BE(); + _oldPosition.x = s.readSint16BE(); + _oldPosition.y = s.readSint16BE(); + _oldSize.x = s.readUint16BE(); + _oldSize.y = s.readUint16BE(); + + _goto.x = s.readSint16BE(); + _goto.y = s.readSint16BE(); + _goto.x = _goto.x * FIXED_INT_MULTIPLIER / 100; + _goto.y = _goto.y * FIXED_INT_MULTIPLIER / 100; - if (seq == 99) { - --_frameNumber; - screen._backBuffer1.transBlitFrom(*_imageFrame, _position); - screen._backBuffer2.transBlitFrom(*_imageFrame, _position); - _type = INVALID; - } else if (IS_ROSE_TATTOO && _talkSeq && seq == 0) { - setObjTalkSequence(_talkSeq); - } else { - setObjSequence(seq, false); - } - } + // Offset 42 + warning("pos %d", s.pos()); + + // Unverified + _lookFlag = s.readSint16BE(); + _pickupFlag = s.readSint16BE(); + _requiredFlag = s.readSint16BE(); + _noShapeSize.x = s.readUint16BE(); + _noShapeSize.y = s.readUint16BE(); + _status = s.readUint16BE(); + // Unverified END - if (_allow && _frameNumber == 0) { - // canimation just ended - if (_type != NO_SHAPE && _type != REMOVE) { - _type = REMOVE; + _maxFrames = s.readUint16BE(); + // offset 56 + _lookPosition.x = s.readUint16BE() * FIXED_INT_MULTIPLIER / 100; + // offset 58 + _descOffset = s.readUint16BE(); + _seqSize = s.readUint16BE(); - if (!_countCAnimFrames) { - // Save details before shape is removed - _delta.x = _imageFrame->_frame.w; - _delta.y = _imageFrame->_frame.h; - _position += _imageFrame->_offset; + s.skip(2); // boundary filler - // Free the images - delete _images; - _images = nullptr; - _imageFrame = nullptr; - } - } else { - _type = INVALID; - } - } + // 288 bytes + for (int idx = 0; idx < 4; ++idx) { + _use[idx].load3DO(s); + s.skip(2); // Filler } - return result; -} + // 158 bytes + _aOpen.load(s); // 2 + 12*4 bytes = 50 bytes + s.skip(2); // Boundary filler + _aClose.load(s); + s.skip(2); // Filler + _aMove.load(s); + s.skip(2); // Filler -void Object::setObjSequence(int seq, bool wait) { - Scene &scene = *_vm->_scene; - int checkFrame = _allow ? MAX_FRAME : FRAMES_END; + // offset 508 + // 3DO: name is at the end + s.read(buffer, 12); + _name = Common::String(buffer); + s.read(buffer, 41); + _description = Common::String(buffer); - if (seq >= 128) { - // Loop the sequence until the count exceeded - seq -= 128; + // Unverified + _walkCount = s.readByte(); + _allow = s.readByte(); + _pickup = s.readByte(); + _defaultCommand = s.readByte(); + // Unverified END - ++_seqCounter; - if (_seqCounter >= seq) { - // Go to next sequence - if (_seqStack) { - _frameNumber = _seqStack; - _seqStack = 0; - _seqCounter = _seqCounter2; - _seqCounter2 = 0; - if (_frameNumber >= checkFrame) - _frameNumber = START_FRAME; + // Probably those here?!?! + _misc = s.readByte(); + _flags = s.readByte(); - return; - } + // Unverified + _aType = (AType)s.readByte(); + _lookFrames = s.readByte(); + _seqCounter = s.readByte(); + // Unverified END - _frameNumber += 2; - if (_frameNumber >= checkFrame) - _frameNumber = 0; + _lookPosition.y = s.readByte() * FIXED_INT_MULTIPLIER; + _lookFacing = s.readByte(); - _seqCounter = 0; - if (_sequences[_frameNumber] == 0) - seq = _sequences[_frameNumber + 1]; - else - return; - } else { - // Find beginning of sequence - do { - --_frameNumber; - } while (_frameNumber > 0 && _sequences[_frameNumber] != 0); + // Unverified + _lookcAnim = s.readByte(); + _seqStack = s.readByte(); + _seqTo = s.readByte(); + _seqCounter2 = s.readByte(); + // Unverified END - if (_frameNumber != 0) - _frameNumber += 2; + s.skip(12); // Unknown - return; - } - } else { - // Reset sequence counter - _seqCounter = 0; - } + //warning("object %s, offset %d", _name.c_str(), streamPos); + //warning("object %s, lookPosX %d, lookPosY %d", _name.c_str(), _lookPosition.x, _lookPosition.y); + //warning("object %s, defCmd %d", _name.c_str(), _defaultCommand); + int32 dataSize = s.pos() - streamStartPos; + assert(dataSize == 588); +} - int idx = 0; - int seqCc = 0; +void Object::toggleHidden() { + if (_type != HIDDEN && _type != HIDE_SHAPE && _type != INVALID) { + if (_seqTo != 0) + _sequences[_frameNumber] = _seqTo + SEQ_TO_CODE + 128; + _seqTo = 0; - while (seqCc < seq && idx < checkFrame) { - ++idx; - if (_sequences[idx] == 0) { - ++seqCc; - idx += 2; - } - } + if (_images == nullptr || _images->size() == 0) + // No shape to erase, so flag as hidden + _type = HIDDEN; + else + // Otherwise, flag it to be hidden after it gets erased + _type = HIDE_SHAPE; + } else if (_type != INVALID) { + if (_seqTo != 0) + _sequences[_frameNumber] = _seqTo + SEQ_TO_CODE + 128; + _seqTo = 0; - if (idx >= checkFrame) - idx = 0; - _frameNumber = idx; + _seqCounter = _seqCounter2 = 0; + _seqStack = 0; + _frameNumber = -1; - if (wait) { - seqCc = idx; - while (_sequences[idx] != 0) - ++idx; + if (_images == nullptr || _images->size() == 0) { + _type = NO_SHAPE; + } else { + _type = ACTIVE_BG_SHAPE; + int idx = _sequences[0]; + if (idx >= _maxFrames) + // Turn on: set up first frame + idx = 0; - idx = idx - seqCc + 2; - for (; idx > 0; --idx) - scene.doBgAnim(); + _imageFrame = &(*_images)[idx]; + } } } @@ -1244,103 +1340,6 @@ void Object::setObjTalkSequence(int seq) { } } -int Object::checkNameForCodes(const Common::String &name, const char *const messages[]) { - People &people = *_vm->_people; - Scene &scene = *_vm->_scene; - Screen &screen = *_vm->_screen; - Talk &talk = *_vm->_talk; - UserInterface &ui = *_vm->_ui; - bool printed = false; - - scene.toggleObject(name); - - if (name.hasPrefix("*")) { - // A code was found - printed = true; - char ch = (name == "*") ? 0 : toupper(name[1]); - - switch (ch) { - case 'C': - talk.talkTo(name.c_str() + 2); - break; - - case 'T': - case 'B': - case 'F': - case 'W': - // Nothing: action was already done before canimation - break; - - case 'G': - case 'A': { - // G: Have object go somewhere - // A: Add onto existing co-ordinates - Common::String sx(name.c_str() + 2, name.c_str() + 5); - Common::String sy(name.c_str() + 6, name.c_str() + 9); - - if (ch == 'G') - _position = Common::Point(atoi(sx.c_str()), atoi(sy.c_str())); - else - _position += Common::Point(atoi(sx.c_str()), atoi(sy.c_str())); - break; - } - - default: - if (ch >= '0' && ch <= '9') { - scene._goToScene = atoi(name.c_str() + 1); - - if (IS_SERRATED_SCALPEL && scene._goToScene < 97) { - Scalpel::ScalpelMap &map = *(Scalpel::ScalpelMap *)_vm->_map; - if (map[scene._goToScene].x) { - map._overPos.x = (map[scene._goToScene].x - 6) * FIXED_INT_MULTIPLIER; - map._overPos.y = (map[scene._goToScene].y + 9) * FIXED_INT_MULTIPLIER; - } - } - - const char *p; - if ((p = strchr(name.c_str(), ',')) != nullptr) { - ++p; - - Common::String s(p, p + 3); - people._hSavedPos.x = atoi(s.c_str()); - - s = Common::String(p + 3, p + 6); - people._hSavedPos.y = atoi(s.c_str()); - - s = Common::String(p + 6, p + 9); - people._hSavedFacing = atoi(s.c_str()); - if (people._hSavedFacing == 0) - people._hSavedFacing = 10; - } else if ((p = strchr(name.c_str(), '/')) != nullptr) { - people._hSavedPos = Common::Point(1, 0); - people._hSavedFacing = 100 + atoi(p + 1); - } - } else { - scene._goToScene = 100; - } - - people[HOLMES]._position = Point32(0, 0); - break; - } - } else if (name.hasPrefix("!")) { - // Message attached to canimation - int messageNum = atoi(name.c_str() + 1); - ui._infoFlag = true; - ui.clearInfo(); - screen.print(Common::Point(0, INFO_LINE + 1), INFO_FOREGROUND, "%s", messages[messageNum]); - ui._menuCounter = 25; - } else if (name.hasPrefix("@")) { - // Message attached to canimation - ui._infoFlag = true; - ui.clearInfo(); - screen.print(Common::Point(0, INFO_LINE + 1), INFO_FOREGROUND, "%s", name.c_str() + 1); - printed = true; - ui._menuCounter = 25; - } - - return printed; -} - void Object::setFlagsAndToggles() { Scene &scene = *_vm->_scene; Talk &talk = *_vm->_talk; -- cgit v1.2.3