aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--engines/sherlock/objects.cpp40
-rw-r--r--engines/sherlock/objects.h8
-rw-r--r--engines/sherlock/people.h15
-rw-r--r--engines/sherlock/scene.cpp15
-rw-r--r--engines/sherlock/talk.cpp2
-rw-r--r--engines/sherlock/user_interface.cpp197
-rw-r--r--engines/sherlock/user_interface.h1
7 files changed, 254 insertions, 24 deletions
diff --git a/engines/sherlock/objects.cpp b/engines/sherlock/objects.cpp
index e4730ef207..dc57322bd4 100644
--- a/engines/sherlock/objects.cpp
+++ b/engines/sherlock/objects.cpp
@@ -248,7 +248,7 @@ void Sprite::checkSprite() {
case TALK:
case TALK_EVERY:
- _type = HIDDEN;
+ obj._type = HIDDEN;
obj.setFlagsAndToggles();
talk.talkTo(obj._use[0]._target);
break;
@@ -400,6 +400,36 @@ void Object::setVm(SherlockEngine *vm) {
_countCAnimFrames = false;
}
+Object::Object() {
+ _sequenceOffset = 0;
+ _sequences = nullptr;
+ _images = nullptr;
+ _imageFrame = nullptr;
+ _walkCount = 0;
+ _allow = 0;
+ _frameNumber = 0;
+ _sequenceNumber = 0;
+ _type = INVALID;
+ _pickup = 0;
+ _defaultCommand = 0;
+ _lookFlag = 0;
+ _pickupFlag = 0;
+ _requiredFlag = 0;
+ _status = 0;
+ _misc = 0;
+ _maxFrames = 0;
+ _flags = 0;
+ _lookFrames = 0;
+ _seqCounter = 0;
+ _lookFacing = 0;
+ _lookcAnim = 0;
+ _seqStack = 0;
+ _seqTo = 0;
+ _descOffset = 0;
+ _seqCounter2 = 0;
+ _seqSize = 0;
+}
+
/**
* Load the object data from the passed stream
*/
@@ -770,7 +800,7 @@ void Object::setObjSequence(int seq, bool wait) {
* @param messages Provides a lookup list of messages that can be printed
* @returns 0 if no codes are found, 1 if codes were found
*/
-int Object::checkNameForCodes(const Common::String &name, Common::StringArray *messages) {
+int Object::checkNameForCodes(const Common::String &name, const char *const messages[]) {
People &people = *_vm->_people;
Scene &scene = *_vm->_scene;
Screen &screen = *_vm->_screen;
@@ -851,15 +881,13 @@ int Object::checkNameForCodes(const Common::String &name, Common::StringArray *m
int messageNum = atoi(name.c_str() + 1);
ui._infoFlag++;
ui.clearInfo();
- screen.print(Common::Point(0, INFO_LINE + 1), INFO_FOREGROUND,
- (*messages)[messageNum].c_str());
+ screen.print(Common::Point(0, INFO_LINE + 1), INFO_FOREGROUND, messages[messageNum]);
ui._menuCounter = 25;
} else if (name.hasPrefix("@")) {
// Message attached to canimation
ui._infoFlag++;
ui.clearInfo();
- screen.print(Common::Point(0, INFO_LINE + 1), INFO_FOREGROUND,
- "%s", name.c_str() + 1);
+ screen.print(Common::Point(0, INFO_LINE + 1), INFO_FOREGROUND, name.c_str() + 1);
printed = true;
ui._menuCounter = 25;
}
diff --git a/engines/sherlock/objects.h b/engines/sherlock/objects.h
index 26ad1d3900..2c642b5a58 100644
--- a/engines/sherlock/objects.h
+++ b/engines/sherlock/objects.h
@@ -34,7 +34,7 @@ namespace Sherlock {
class SherlockEngine;
enum ObjectAllow {
- ALLOW_MOVEMENT = 1, ALLOW_OPEN = 2, ALLOW_CLOSE = 4
+ ALLOW_MOVE = 1, ALLOW_OPEN = 2, ALLOW_CLOSE = 4
};
enum SpriteType {
@@ -122,6 +122,8 @@ public:
int frameHeight() const { return _imageFrame ? _imageFrame->_frame.h : 0; }
};
+enum { REVERSE_DIRECTION = 0x80 };
+
struct ActionType {
int8 _cAnimNum;
uint8 _cAnimSpeed; // if high bit set, play in reverse
@@ -198,13 +200,15 @@ public:
ActionType _aMove;
UseType _use[4];
+ Object();
+
void synchronize(Common::SeekableReadStream &s);
void toggleHidden();
void checkObject(Object &o);
- int checkNameForCodes(const Common::String &name, Common::StringArray *messages);
+ int checkNameForCodes(const Common::String &name, const char *const messages[]);
void setFlagsAndToggles();
diff --git a/engines/sherlock/people.h b/engines/sherlock/people.h
index bec078d11e..ba870d041d 100644
--- a/engines/sherlock/people.h
+++ b/engines/sherlock/people.h
@@ -34,7 +34,8 @@ enum PeopleId {
PLAYER = 0,
AL = 0,
PEG = 1,
- MAX_PEOPLE = 66
+ NUM_OF_PEOPLE = 2, // Holmes and Watson
+ MAX_PEOPLE = 66 // Total of all NPCs
};
// Animation sequence identifiers for characters
@@ -62,7 +63,7 @@ public:
class People {
private:
SherlockEngine *_vm;
- Person _data[MAX_PEOPLE];
+ Person _data[NUM_OF_PEOPLE];
bool _walkLoaded;
int _oldWalkSequence;
int _srcZone, _destZone;
@@ -84,8 +85,14 @@ public:
People(SherlockEngine *vm);
~People();
- Person &operator[](PeopleId id) { return _data[id]; }
- Person &operator[](int idx) { return _data[idx]; }
+ Person &operator[](PeopleId id) {
+ assert(id < NUM_OF_PEOPLE);
+ return _data[id];
+ }
+ Person &operator[](int idx) {
+ assert(idx < NUM_OF_PEOPLE);
+ return _data[idx];
+ }
bool isHolmesActive() const { return _walkLoaded && _holmesOn; }
diff --git a/engines/sherlock/scene.cpp b/engines/sherlock/scene.cpp
index 3d5f566164..1cad2506e5 100644
--- a/engines/sherlock/scene.cpp
+++ b/engines/sherlock/scene.cpp
@@ -314,8 +314,8 @@ bool Scene::loadScene(const Common::String &filename) {
for (uint idx = 0; idx < _zones.size(); ++idx) {
_zones[idx].left = boundsStream->readSint16LE();
_zones[idx].top = boundsStream->readSint16LE();
- _zones[idx].setWidth(boundsStream->readSint16LE());
- _zones[idx].setHeight(boundsStream->readSint16LE());
+ _zones[idx].setWidth(boundsStream->readSint16LE() + 1);
+ _zones[idx].setHeight(boundsStream->readSint16LE() + 1);
boundsStream->skip(2); // Skip unused scene number field
}
@@ -925,20 +925,18 @@ int Scene::startCAnim(int cAnimNum, int playRate) {
rrmStream->seek(rrmStream->readUint32LE());
// Load the canimation into the cache
- Common::SeekableReadStream *imgStream = !_lzwMode ? rrmStream :
+ Common::SeekableReadStream *imgStream = !_lzwMode ? rrmStream->readStream(cAnim._size) :
decompressLZ(*rrmStream, cAnim._size);
res.addToCache(fname, *imgStream);
- if (_lzwMode)
- delete imgStream;
-
+ delete imgStream;
delete rrmStream;
}
// Now load the resource as an image
- cObj._maxFrames = cObj._images->size();
cObj._images = new ImageFile(fname);
cObj._imageFrame = &(*cObj._images)[0];
+ cObj._maxFrames = cObj._images->size();
int frames = 0;
if (playRate < 0) {
@@ -946,8 +944,7 @@ int Scene::startCAnim(int cAnimNum, int playRate) {
// Count number of frames
while (cObj._sequences[frames] && frames < MAX_FRAME)
++frames;
- }
- else {
+ } else {
// Forward direction
Object::_countCAnimFrames = true;
diff --git a/engines/sherlock/talk.cpp b/engines/sherlock/talk.cpp
index ec3f67bd84..281b6b4672 100644
--- a/engines/sherlock/talk.cpp
+++ b/engines/sherlock/talk.cpp
@@ -583,7 +583,7 @@ void Talk::loadTalkFile(const Common::String &filename) {
// Check for an existing person being talked to
_talkTo = -1;
- for (int idx = 0; idx < MAX_PEOPLE; ++idx) {
+ for (int idx = 0; idx < NUM_OF_PEOPLE; ++idx) {
if (!scumm_strnicmp(filename.c_str(), people[(PeopleId)idx]._portrait.c_str(), 4)) {
_talkTo = idx;
break;
diff --git a/engines/sherlock/user_interface.cpp b/engines/sherlock/user_interface.cpp
index 2b808a085a..ebbe00ffbc 100644
--- a/engines/sherlock/user_interface.cpp
+++ b/engines/sherlock/user_interface.cpp
@@ -58,6 +58,25 @@ const char INVENTORY_COMMANDS[9] = { "ELUG-+,." };
const char *const PRESS_KEY_FOR_MORE = "Press any Key for More.";
const char *const PRESS_KEY_TO_CONTINUE = "Press any Key to Continue.";
+const char *const MOPEN[] = {
+ "This cannot be opened", "It is already open", "It is locked", "Wait for Watson", " ", "."
+};
+const char *const MCLOSE[] = {
+ "This cannot be closed", "It is already closed", "The safe door is in the way"
+};
+const char *const MMOVE[] = {
+ "This cannot be moved", "It is bolted to the floor", "It is too heavy", "The other crate is in the way"
+};
+const char *const MPICK[] = {
+ "Nothing of interest here", "It is bolted down", "It is too big to carry", "It is too heavy",
+ "I think a girl would be more your type", "Those flowers belong to Penny", "She's far too young for you!",
+ "I think a girl would be more your type!", "Government property for official use only"
+};
+const char *const MUSE[] = {
+ "You can't do that", "It had no effect", "You can't reach it", "OK, the door looks bigger! Happy?",
+ "Doors don't smoke"
+};
+
/*----------------------------------------------------------------*/
UserInterface::UserInterface(SherlockEngine *vm) : _vm(vm) {
@@ -327,7 +346,7 @@ void UserInterface::handleInput() {
break;
case MOVE_MODE:
- doMiscControl(ALLOW_MOVEMENT);
+ doMiscControl(ALLOW_MOVE);
break;
case TALK_MODE:
@@ -1122,8 +1141,56 @@ void UserInterface::doMainControl() {
}
}
+/**
+ * Handles the input for the MOVE, OPEN, and CLOSE commands
+ */
void UserInterface::doMiscControl(int allowed) {
- // TODO
+ Events &events = *_vm->_events;
+ Scene &scene = *_vm->_scene;
+ Talk &talk = *_vm->_talk;
+
+ if (events._released) {
+ _temp = _bgFound;
+ if (_bgFound != -1) {
+ // Only allow pointing to objects, not people
+ if (_bgFound < 1000) {
+ events.clearEvents();
+ Object &obj = scene._bgShapes[_bgFound];
+
+ switch (allowed) {
+ case ALLOW_OPEN:
+ checkAction(obj._aOpen, MOPEN, _temp);
+ if (_menuMode && !talk._talkToAbort) {
+ _menuMode = STD_MODE;
+ restoreButton(OPEN_MODE - 1);
+ _key = _oldKey = -1;
+ }
+ break;
+
+ case ALLOW_CLOSE:
+ checkAction(obj._aClose, MCLOSE, _temp);
+ if (_menuMode != TALK_MODE && !talk._talkToAbort) {
+ _menuMode = STD_MODE;
+ restoreButton(CLOSE_MODE - 1);
+ _key = _oldKey = -1;
+ }
+ break;
+
+ case ALLOW_MOVE:
+ checkAction(obj._aMove, MMOVE, _temp);
+ if (_menuMode != TALK_MODE && !talk._talkToAbort) {
+ _menuMode = STD_MODE;
+ restoreButton(MOVE_MODE - 1);
+ _key = _oldKey = -1;
+ }
+ break;
+
+ default:
+ break;
+ }
+ }
+ }
+ }
}
void UserInterface::doPickControl() {
@@ -1503,5 +1570,131 @@ void UserInterface::checkUseAction(UseType &use, const Common::String &invName,
// TODO
}
+/**
+ * Called for OPEN, CLOSE, and MOVE actions are being done
+ */
+void UserInterface::checkAction(ActionType &action, const char *const messages[], int objNum) {
+ Events &events = *_vm->_events;
+ People &people = *_vm->_people;
+ Scene &scene = *_vm->_scene;
+ Screen &screen = *_vm->_screen;
+ Talk &talk = *_vm->_talk;
+ bool printed = false;
+ bool doCAnim = true;
+ int cAnimNum;
+ Common::Point pt(-1, -1);
+ int dir = -1;
+
+ if (objNum >= 1000)
+ // Ignore actions done on characters
+ return;
+ Object &obj = scene._bgShapes[objNum];
+
+ if (action._cAnimNum == 0)
+ // Really a 10
+ cAnimNum = 9;
+ else
+ cAnimNum = action._cAnimNum - 1;
+ CAnim &anim = scene._cAnim[cAnimNum];
+
+ if (action._cAnimNum != 99) {
+ if (action._cAnimSpeed & REVERSE_DIRECTION) {
+ pt = anim._teleportPos;
+ dir = anim._teleportDir;
+ } else {
+ pt = anim._goto;
+ dir = anim._gotoDir;
+ }
+ }
+
+ if (action._cAnimSpeed) {
+ // Has a value, so do action
+ // Show wait cursor whilst walking to object and doing action
+ events.setCursor(WAIT);
+
+ for (int nameIdx = 0; nameIdx < 4; ++nameIdx) {
+ if (action._names[nameIdx].hasPrefix("*") && toupper(action._names[nameIdx][1]) == 'W') {
+ if (obj.checkNameForCodes(Common::String(action._names[nameIdx].c_str() + 2), messages)) {
+ if (!talk._talkToAbort)
+ printed = true;
+ }
+ }
+ }
+
+ for (int nameIdx = 0; nameIdx < 4; ++nameIdx) {
+ if (action._names[nameIdx].hasPrefix("*")) {
+ char ch = toupper(action._names[nameIdx][1]);
+
+ if (ch == 'T' || ch == 'B') {
+ printed = true;
+ if (pt.x != -1)
+ // Holmes needs to walk to object before the action is done
+ people.walkToCoords(pt, dir);
+
+ if (!talk._talkToAbort) {
+ // Ensure Holmes is on the exact intended location
+ people[AL]._position = pt;
+ people[AL]._sequenceNumber = dir;
+ people.gotoStand(people[AL]);
+
+ talk.talkTo(action._names[nameIdx] + 2);
+ if (ch == 'T')
+ doCAnim = false;
+ }
+ }
+ }
+ }
+
+ if (doCAnim && !talk._talkToAbort) {
+ if (pt.x != -1)
+ // Holmes needs to walk to object before the action is done
+ people.walkToCoords(pt, dir);
+ }
+
+ for (int nameIdx = 0; nameIdx < 4; ++nameIdx) {
+ if (action._names[nameIdx].hasPrefix("*") && toupper(action._names[nameIdx][1]) == 'F') {
+ if (obj.checkNameForCodes(action._names[nameIdx].c_str() + 2, messages)) {
+ if (!talk._talkToAbort)
+ printed = true;
+ }
+ }
+ }
+
+ if (doCAnim && !talk._talkToAbort && action._cAnimNum != 99)
+ scene.startCAnim(cAnimNum, action._cAnimSpeed);
+
+ if (!talk._talkToAbort) {
+ for (int nameIdx = 0; nameIdx < 4 && !talk._talkToAbort; ++nameIdx) {
+ if (obj.checkNameForCodes(action._names[nameIdx], messages)) {
+ if (!talk._talkToAbort)
+ printed = true;
+ }
+ }
+
+ // Unless we're leaving the scene, print a "Done" message unless the printed flag has been set
+ if (scene._goToScene != 1 && !printed && !talk._talkToAbort) {
+ _infoFlag = true;
+ clearInfo();
+ screen.print(Common::Point(0, INFO_LINE + 1), INFO_FOREGROUND, messages[action._cAnimNum]);
+
+ // Set how long to show the message
+ _menuCounter = 30;
+ }
+ }
+ } else {
+ // Invalid action, to print error message
+ _infoFlag = true;
+ clearInfo();
+ screen.print(Common::Point(0, INFO_LINE + 1), INFO_FOREGROUND, messages[action._cAnimNum]);
+ _infoFlag = true;
+
+ // Set how long to show the message
+ _menuCounter = 30;
+ }
+
+ // Reset cursor back to arrow
+ events.setCursor(ARROW);
+}
+
} // End of namespace Sherlock
diff --git a/engines/sherlock/user_interface.h b/engines/sherlock/user_interface.h
index f80fe48b2d..9b104465cf 100644
--- a/engines/sherlock/user_interface.h
+++ b/engines/sherlock/user_interface.h
@@ -117,6 +117,7 @@ private:
void checkUseAction(UseType &use, const Common::String &invName, const Common::String &msg,
int objNum, int giveMode);
+ void checkAction(ActionType &action, const char *const messages[], int objNum);
public:
MenuMode _menuMode;
int _menuCounter;