2015-03-19 23:31:28 -04:00
|
|
|
/* 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 "sherlock/objects.h"
|
2015-03-21 11:24:35 -04:00
|
|
|
#include "sherlock/sherlock.h"
|
|
|
|
#include "sherlock/people.h"
|
|
|
|
#include "sherlock/scene.h"
|
2015-03-21 13:01:45 -04:00
|
|
|
#include "common/util.h"
|
2015-03-19 23:31:28 -04:00
|
|
|
|
|
|
|
namespace Sherlock {
|
|
|
|
|
2015-03-21 13:01:45 -04:00
|
|
|
#define UPPER_LIMIT 0
|
|
|
|
#define LOWER_LIMIT CONTROLS_Y
|
|
|
|
#define LEFT_LIMIT 0
|
|
|
|
#define RIGHT_LIMIT SHERLOCK_SCREEN_WIDTH
|
|
|
|
|
2015-03-21 20:25:15 -04:00
|
|
|
// Distance to walk around WALK_AROUND boxes
|
|
|
|
#define CLEAR_DIST_X 5
|
|
|
|
#define CLEAR_DIST_Y 0
|
|
|
|
|
2015-03-21 11:24:35 -04:00
|
|
|
SherlockEngine *Sprite::_vm;
|
|
|
|
|
2015-03-19 23:31:28 -04:00
|
|
|
/**
|
|
|
|
* Reset the data for the sprite
|
|
|
|
*/
|
|
|
|
void Sprite::clear() {
|
|
|
|
_name = "";
|
|
|
|
_description = "";
|
|
|
|
_examine.clear();
|
|
|
|
_pickUp = "";
|
|
|
|
_sequences = nullptr;
|
|
|
|
_images = nullptr;
|
|
|
|
_imageFrame = nullptr;
|
|
|
|
_walkCount = 0;
|
|
|
|
_allow = 0;
|
|
|
|
_frameNumber = _sequenceNumber = 0;
|
|
|
|
_position.x = _position.y = 0;
|
2015-03-21 11:24:35 -04:00
|
|
|
_delta.x = _delta.y = 0;
|
2015-03-19 23:31:28 -04:00
|
|
|
_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;
|
|
|
|
_numFrames = 0;
|
|
|
|
}
|
|
|
|
|
2015-03-21 13:01:45 -04:00
|
|
|
/**
|
|
|
|
* Updates the image frame poiner for the sprite
|
|
|
|
*/
|
2015-03-20 22:01:52 -04:00
|
|
|
void Sprite::setImageFrame() {
|
2015-03-21 13:01:45 -04:00
|
|
|
int imageNumber = (*_sequences)[_sequenceNumber][_frameNumber] +
|
|
|
|
(*_sequences)[_sequenceNumber][0] - 2;
|
2015-03-20 22:01:52 -04:00
|
|
|
_imageFrame = &(*_images)[imageNumber];
|
|
|
|
}
|
|
|
|
|
2015-03-21 13:01:45 -04:00
|
|
|
/**
|
|
|
|
* This adjusts the sprites position, as well as it's animation sequence:
|
|
|
|
*/
|
2015-03-21 11:24:35 -04:00
|
|
|
void Sprite::adjustSprite() {
|
2015-03-21 13:01:45 -04:00
|
|
|
People &people = *_vm->_people;
|
|
|
|
Scene &scene = *_vm->_scene;
|
2015-03-21 20:25:15 -04:00
|
|
|
Talk &talk = *_vm->_talk;
|
2015-03-21 13:01:45 -04:00
|
|
|
|
|
|
|
if (_type == INVALID || (_type == CHARACTER && _vm->_animating))
|
|
|
|
return;
|
|
|
|
|
2015-03-21 20:25:15 -04:00
|
|
|
if (!talk._talkCounter && _type == CHARACTER && _walkCount) {
|
2015-03-21 13:01:45 -04:00
|
|
|
// Handle active movement for the sprite
|
|
|
|
_position += _delta;
|
|
|
|
--_walkCount;
|
|
|
|
|
|
|
|
if (!_walkCount) {
|
|
|
|
// If there any points left for the character to walk to along the
|
|
|
|
// route to a destination, then move to the next point
|
|
|
|
if (!people._walkTo.empty()) {
|
|
|
|
people._walkDest = people._walkTo.pop();
|
|
|
|
people.setWalking();
|
|
|
|
} else {
|
|
|
|
people.gotoStand(*this);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (_type == CHARACTER && !_vm->_onChessboard) {
|
|
|
|
if ((_position.y / 100) > LOWER_LIMIT) {
|
|
|
|
_position.y = LOWER_LIMIT * 100;
|
|
|
|
people.gotoStand(*this);
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((_position.y / 100) < UPPER_LIMIT) {
|
|
|
|
_position.y = UPPER_LIMIT * 100;
|
|
|
|
people.gotoStand(*this);
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((_position.x / 100) < LEFT_LIMIT) {
|
|
|
|
_position.x = LEFT_LIMIT * 100;
|
|
|
|
people.gotoStand(*this);
|
|
|
|
}
|
|
|
|
} else if (!_vm->_onChessboard) {
|
|
|
|
_position.y = CLIP((int)_position.y, UPPER_LIMIT, LOWER_LIMIT);
|
|
|
|
_position.x = CLIP((int)_position.x, LEFT_LIMIT, RIGHT_LIMIT);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!_vm->_onChessboard || (_vm->_slowChess = !_vm->_slowChess))
|
|
|
|
++_frameNumber;
|
|
|
|
|
|
|
|
if ((*_sequences)[_sequenceNumber][_frameNumber] == 0) {
|
|
|
|
switch (_sequenceNumber) {
|
|
|
|
case STOP_UP:
|
|
|
|
case STOP_DOWN:
|
|
|
|
case STOP_LEFT:
|
|
|
|
case STOP_RIGHT:
|
|
|
|
case STOP_UPRIGHT:
|
|
|
|
case STOP_UPLEFT:
|
|
|
|
case STOP_DOWNRIGHT:
|
|
|
|
case STOP_DOWNLEFT:
|
|
|
|
// We're in a stop sequence, so reset back to the last frame, so
|
|
|
|
// the character is shown as standing still
|
|
|
|
--_frameNumber;
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
// Move 1 past the first frame - we need to compensate, since we
|
|
|
|
// already passed the frame increment
|
|
|
|
_frameNumber = 1;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Update the _imageFrame to point to the new frame's image
|
|
|
|
setImageFrame();
|
|
|
|
|
|
|
|
// Check to see if character has entered an exit zone
|
|
|
|
if (!_walkCount && scene._walkedInScene && scene._goToRoom == -1) {
|
|
|
|
Common::Rect charRect(_position.x / 100 - 5, _position.y / 100 - 2,
|
|
|
|
_position.x / 100 + 5, _position.y / 100 + 2);
|
|
|
|
Exit *exit = scene.checkForExit(charRect);
|
|
|
|
|
|
|
|
if (exit) {
|
|
|
|
scene._hsavedPos = exit->_people;
|
|
|
|
scene._hsavedFs = exit->_peopleDir;
|
|
|
|
|
|
|
|
if (scene._hsavedFs > 100 && scene._hsavedPos.x < 1)
|
|
|
|
scene._hsavedPos.x = 100;
|
|
|
|
}
|
|
|
|
}
|
2015-03-21 09:20:39 -04:00
|
|
|
}
|
|
|
|
|
2015-03-21 20:25:15 -04:00
|
|
|
/**
|
|
|
|
* Checks the sprite's position to see if it's collided with any special objects
|
|
|
|
*/
|
|
|
|
void Sprite::checkSprite() {
|
|
|
|
Events &events = *_vm->_events;
|
|
|
|
People &people = *_vm->_people;
|
|
|
|
Scene &scene = *_vm->_scene;
|
|
|
|
Screen &screen = *_vm->_screen;
|
|
|
|
Talk &talk = *_vm->_talk;
|
|
|
|
Common::Point pt;
|
|
|
|
Common::Rect objBounds;
|
|
|
|
Common::Point spritePt(_position.x / 100, _position.y / 100);
|
|
|
|
|
|
|
|
if (!talk._talkCounter && _type == CHARACTER) {
|
|
|
|
pt = _walkCount ? _position + _delta : _position;
|
|
|
|
pt.x /= 100;
|
|
|
|
pt.y /= 100;
|
|
|
|
|
|
|
|
for (uint idx = 0; idx < scene._bgShapes.size() && !talk._talkToAbort; ++idx) {
|
|
|
|
Object &obj = scene._bgShapes[idx];
|
|
|
|
|
|
|
|
if (obj._aType > PERSON && _type != INVALID && _type != HIDDEN) {
|
|
|
|
if (_type == NO_SHAPE) {
|
|
|
|
objBounds = Common::Rect(_position.x, _position.y,
|
|
|
|
_position.x + _noShapeSize.x, _position.y + _noShapeSize.y);
|
|
|
|
} else {
|
|
|
|
int xp = _position.x + _imageFrame->_offset.x;
|
|
|
|
int yp = _position.y + _imageFrame->_offset.y;
|
|
|
|
objBounds = Common::Rect(xp, yp,
|
|
|
|
xp + _imageFrame->_frame.w, yp + _imageFrame->_frame.h);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
|
|
|
// 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;
|
|
|
|
|
|
|
|
for (int idx = palStart; idx < (palStart + palLength); ++idx)
|
|
|
|
screen._sMap[idx] = screen._cMap[idx] * palPercent / 100;
|
|
|
|
|
|
|
|
events.pollEvents();
|
|
|
|
screen.setPalette(screen._sMap);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case TALK:
|
|
|
|
case TALK_EVERY:
|
|
|
|
_type = HIDDEN;
|
|
|
|
obj.setFlagsAndToggles();
|
|
|
|
talk.talkTo(obj._use[0]._target);
|
|
|
|
break;
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
|
|
|
case SOLID:
|
|
|
|
case TALK:
|
|
|
|
// Stop walking
|
|
|
|
if (obj._aType == TALK) {
|
|
|
|
obj.setFlagsAndToggles();
|
|
|
|
talk.talkTo(obj._use[0]._target);
|
|
|
|
} else {
|
|
|
|
people.gotoStand(*this);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case TALK_EVERY:
|
|
|
|
if (obj._aType == TALK_EVERY) {
|
|
|
|
obj._type = HIDDEN;
|
|
|
|
obj.setFlagsAndToggles();
|
|
|
|
talk.talkTo(obj._use[0]._target);
|
|
|
|
} else {
|
|
|
|
people.gotoStand(*this);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case FLAG_SET:
|
|
|
|
obj.setFlagsAndToggles();
|
|
|
|
obj._type = HIDDEN;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case WALK_AROUND:
|
|
|
|
if (objBounds.contains(people._walkTo.top())) {
|
|
|
|
// Reached zone
|
|
|
|
people.gotoStand(*this);
|
|
|
|
} else {
|
|
|
|
// Destination not within box, walk to best corner
|
|
|
|
Common::Point walkPos;
|
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
walkPos.x = (_delta.x >= 0) ? objBounds.left - CLEAR_DIST_X :
|
|
|
|
objBounds.right + CLEAR_DIST_X;
|
|
|
|
}
|
|
|
|
|
|
|
|
walkPos.x += people[AL]._imageFrame->_frame.w / 2;
|
|
|
|
people._walkDest = walkPos;
|
|
|
|
people._walkTo.push(walkPos);
|
|
|
|
people.setWalking();
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case DELTA:
|
|
|
|
_position.x += 200;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-03-19 23:31:28 -04:00
|
|
|
/*----------------------------------------------------------------*/
|
|
|
|
|
|
|
|
void ActionType::synchronize(Common::SeekableReadStream &s) {
|
|
|
|
char buffer[12];
|
|
|
|
|
|
|
|
_cAnimNum = s.readByte();
|
|
|
|
_cAnimSpeed = s.readByte();
|
|
|
|
|
|
|
|
for (int idx = 0; idx < 4; ++idx) {
|
|
|
|
s.read(buffer, 12);
|
|
|
|
_names[idx] = Common::String(buffer);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*----------------------------------------------------------------*/
|
|
|
|
|
|
|
|
void UseType::synchronize(Common::SeekableReadStream &s) {
|
|
|
|
char buffer[12];
|
|
|
|
|
|
|
|
_cAnimNum = s.readByte();
|
|
|
|
_cAnimSpeed = s.readByte();
|
|
|
|
|
|
|
|
for (int idx = 0; idx < 4; ++idx) {
|
|
|
|
s.read(buffer, 12);
|
|
|
|
_names[idx] = Common::String(buffer);
|
|
|
|
}
|
|
|
|
|
|
|
|
_useFlag = s.readUint16LE();
|
|
|
|
_dFlag[0] = s.readUint16LE();
|
|
|
|
_lFlag[0] = s.readUint16LE();
|
|
|
|
_lFlag[1] = s.readUint16LE();
|
|
|
|
|
|
|
|
s.read(buffer, 12);
|
|
|
|
_target = Common::String(buffer);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*----------------------------------------------------------------*/
|
|
|
|
|
2015-03-21 18:18:12 -04:00
|
|
|
SherlockEngine *Object::_vm;
|
|
|
|
bool Object::_countCAnimFrames;
|
|
|
|
|
|
|
|
void Object::setVm(SherlockEngine *vm) {
|
|
|
|
_vm = vm;
|
|
|
|
_countCAnimFrames = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Load the object data from the passed stream
|
|
|
|
*/
|
2015-03-19 23:31:28 -04:00
|
|
|
void Object::synchronize(Common::SeekableReadStream &s) {
|
|
|
|
char buffer[50];
|
|
|
|
|
|
|
|
s.read(buffer, 12);
|
|
|
|
_name = Common::String(buffer);
|
|
|
|
s.read(buffer, 41);
|
|
|
|
_description = Common::String(buffer);
|
|
|
|
|
|
|
|
_examine.clear();
|
|
|
|
_sequences = nullptr;
|
|
|
|
_images = nullptr;
|
|
|
|
_imageFrame = nullptr;
|
2015-03-20 07:54:39 -04:00
|
|
|
|
|
|
|
s.skip(4);
|
|
|
|
_sequenceOffset = s.readUint32LE();
|
|
|
|
s.seek(8, SEEK_CUR);
|
2015-03-19 23:31:28 -04:00
|
|
|
|
|
|
|
_walkCount = s.readByte();
|
|
|
|
_allow = s.readByte();
|
|
|
|
_frameNumber = s.readSint16LE();
|
|
|
|
_sequenceNumber = s.readSint16LE();
|
|
|
|
_position.x = s.readSint16LE();
|
|
|
|
_position.y = s.readSint16LE();
|
2015-03-21 18:18:12 -04:00
|
|
|
_delta.x = s.readSint16LE();
|
|
|
|
_delta.y = s.readSint16LE();
|
2015-03-19 23:31:28 -04:00
|
|
|
_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();
|
|
|
|
|
|
|
|
_pickup = s.readByte();
|
|
|
|
_defaultCommand = s.readByte();
|
|
|
|
_lookFlag = s.readUint16LE();
|
|
|
|
_pickupFlag = s.readUint16LE();
|
|
|
|
_requiredFlag = s.readUint16LE();
|
|
|
|
_noShapeSize.x = s.readUint16LE();
|
|
|
|
_noShapeSize.y = s.readUint16LE();
|
|
|
|
_status = s.readUint16LE();
|
|
|
|
_misc = s.readByte();
|
|
|
|
_maxFrames = s.readUint16LE();
|
|
|
|
_flags = s.readByte();
|
|
|
|
_aOpen.synchronize(s);
|
2015-03-20 19:44:32 -04:00
|
|
|
_aType = (AType)s.readByte();
|
2015-03-19 23:31:28 -04:00
|
|
|
_lookFrames = s.readByte();
|
2015-03-20 07:54:39 -04:00
|
|
|
_seqCounter = s.readByte();
|
2015-03-19 23:31:28 -04:00
|
|
|
_lookPosition.x = s.readUint16LE();
|
|
|
|
_lookPosition.y = s.readByte();
|
|
|
|
_lookFacing = s.readByte();
|
|
|
|
_lookcAnim = s.readByte();
|
|
|
|
_aClose.synchronize(s);
|
|
|
|
_seqStack = s.readByte();
|
|
|
|
_seqTo = s.readByte();
|
2015-03-20 07:54:39 -04:00
|
|
|
_descOffset = s.readUint16LE();
|
2015-03-19 23:31:28 -04:00
|
|
|
_seqcounter2 = s.readByte();
|
|
|
|
_seqSize = s.readUint16LE();
|
|
|
|
s.skip(1);
|
|
|
|
_aMove.synchronize(s);
|
|
|
|
s.skip(8);
|
|
|
|
|
|
|
|
for (int idx = 0; idx < 4; ++idx)
|
|
|
|
_use[idx].synchronize(s);
|
|
|
|
}
|
|
|
|
|
2015-03-21 18:18:12 -04:00
|
|
|
/**
|
|
|
|
* Toggle the type of an object between hidden and active
|
|
|
|
*/
|
2015-03-20 19:44:32 -04:00
|
|
|
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;
|
|
|
|
|
|
|
|
_seqCounter = _seqcounter2 = 0;
|
|
|
|
_seqStack = 0;
|
|
|
|
_frameNumber = -1;
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
|
|
|
_imageFrame = &(*_images)[idx];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-03-21 18:18:12 -04:00
|
|
|
/**
|
|
|
|
* Check the state of the object
|
|
|
|
*/
|
|
|
|
void Object::checkObject(Object &o) {
|
|
|
|
Scene &scene = *_vm->_scene;
|
|
|
|
Sound &sound = *_vm->_sound;
|
|
|
|
int checkFrame = _allow ? MAX_FRAME : 32000;
|
|
|
|
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--;
|
|
|
|
else
|
|
|
|
*ptr++;
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
++_frameNumber;
|
|
|
|
|
|
|
|
do {
|
|
|
|
// Check for end of sequence
|
|
|
|
codeFound = checkEndOfSequence();
|
|
|
|
|
|
|
|
if (_sequences[_frameNumber] >= 128 && _frameNumber < checkFrame) {
|
|
|
|
codeFound = true;
|
|
|
|
int v = _sequences[_frameNumber];
|
|
|
|
|
|
|
|
if (v >= 228) {
|
|
|
|
// Goto code found
|
|
|
|
v -= 228;
|
|
|
|
_seqcounter2 = _seqCounter;
|
|
|
|
_seqStack = _frameNumber + 1;
|
|
|
|
setObjSequence(v, false);
|
|
|
|
} else if (v >= SOUND_CODE && (v <= (SOUND_CODE + 29))) {
|
|
|
|
codeFound = true;
|
|
|
|
++_frameNumber;
|
|
|
|
v -= SOUND_CODE;
|
|
|
|
|
|
|
|
if (sound._soundOn && !_countCAnimFrames) {
|
|
|
|
if (!scene._sounds[v - 1]._name.empty() && sound._digitized)
|
|
|
|
sound.playLoadedSound(v - 1, 0);
|
|
|
|
}
|
|
|
|
} else if (v >= FLIP_CODE && v <= (FLIP_CODE + 2)) {
|
|
|
|
// Flip code
|
|
|
|
codeFound = true;
|
|
|
|
++_frameNumber;
|
|
|
|
v -= FLIP_CODE;
|
|
|
|
|
|
|
|
// Alter the flipped status
|
|
|
|
switch (v) {
|
|
|
|
case 0:
|
|
|
|
// Clear the flag
|
|
|
|
_flags &= ~2;
|
|
|
|
break;
|
|
|
|
case 1:
|
|
|
|
// Set the flag
|
|
|
|
_flags |= 2;
|
|
|
|
break;
|
|
|
|
case 2:
|
|
|
|
// Toggle the flag
|
|
|
|
_flags ^= 2;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
v -= 128;
|
|
|
|
|
|
|
|
// 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);
|
|
|
|
|
|
|
|
if (*p > 128)
|
|
|
|
// If the high bit is set, convert to a real frame
|
|
|
|
*p -= (byte)(SEQ_TO_CODE - 128);
|
|
|
|
|
|
|
|
if (*p > _seqTo)
|
|
|
|
*p -= 1;
|
|
|
|
else
|
|
|
|
*p += 1;
|
|
|
|
|
|
|
|
// Will be incremented below to return back to original value
|
|
|
|
--_frameNumber;
|
|
|
|
v = 0;
|
|
|
|
} 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--;
|
|
|
|
|
|
|
|
if (pt.y > 128)
|
|
|
|
pt.y = (pt.y - 128) * -1;
|
|
|
|
else
|
|
|
|
pt.y;
|
|
|
|
|
|
|
|
_delta = pt;
|
|
|
|
_frameNumber += 2;
|
|
|
|
} else if (v < 4) {
|
|
|
|
for (int idx = 0; idx < 4; ++idx) {
|
|
|
|
o.checkNameForCodes(_use[v]._names[idx], nullptr);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (_use[v]._useFlag)
|
|
|
|
_vm->setFlags(_use[v]._useFlag);
|
|
|
|
}
|
|
|
|
|
|
|
|
++_frameNumber;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} while (codeFound);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Object::checkEndOfSequence() const {
|
|
|
|
// TODO
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Object::setObjSequence(int seq, bool wait) {
|
|
|
|
// TODO
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Checks for codes
|
|
|
|
* @param name The name to check for codes
|
|
|
|
* @param messages If provided, any messages to be returned
|
|
|
|
* @returns 0 if no codes are found, 1 if codes were found
|
|
|
|
*/
|
|
|
|
int Object::checkNameForCodes(const Common::String &name, Common::StringArray *messages) {
|
|
|
|
|
|
|
|
// TODO
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2015-03-21 20:25:15 -04:00
|
|
|
void Object::setFlagsAndToggles() {
|
|
|
|
// TODO
|
|
|
|
}
|
|
|
|
|
2015-03-20 07:54:39 -04:00
|
|
|
/*----------------------------------------------------------------*/
|
|
|
|
|
|
|
|
void CAnim::synchronize(Common::SeekableReadStream &s) {
|
|
|
|
char buffer[12];
|
|
|
|
s.read(buffer, 12);
|
|
|
|
_name = Common::String(buffer);
|
|
|
|
|
|
|
|
s.read(_sequences, 30);
|
|
|
|
_position.x = s.readSint16LE();
|
|
|
|
_position.y = s.readSint16LE();
|
|
|
|
_size = s.readUint32LE();
|
|
|
|
_type = (SpriteType)s.readUint16LE();
|
|
|
|
_flags = s.readByte();
|
|
|
|
_goto.x = s.readSint16LE();
|
|
|
|
_goto.y = s.readSint16LE();
|
2015-03-21 18:18:12 -04:00
|
|
|
_gotoDir = s.readSint16LE();
|
2015-03-20 07:54:39 -04:00
|
|
|
_teleportPos.x = s.readSint16LE();
|
|
|
|
_teleportPos.y = s.readSint16LE();
|
2015-03-21 18:18:12 -04:00
|
|
|
_teleportDir = s.readSint16LE();
|
2015-03-20 07:54:39 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
/*----------------------------------------------------------------*/
|
|
|
|
|
|
|
|
InvGraphicType::InvGraphicType() {
|
|
|
|
_images = nullptr;
|
|
|
|
_maxFrames = 0;
|
|
|
|
_filesize = 0;
|
|
|
|
}
|
|
|
|
|
2015-03-19 23:31:28 -04:00
|
|
|
} // End of namespace Sherlock
|