diff options
Diffstat (limited to 'engines/scumm')
-rw-r--r-- | engines/scumm/object.cpp | 61 | ||||
-rw-r--r-- | engines/scumm/saveload.cpp | 9 | ||||
-rw-r--r-- | engines/scumm/saveload.h | 2 | ||||
-rw-r--r-- | engines/scumm/script.cpp | 2 | ||||
-rw-r--r-- | engines/scumm/script_v0.cpp | 134 | ||||
-rw-r--r-- | engines/scumm/scumm.cpp | 12 | ||||
-rw-r--r-- | engines/scumm/scumm.h | 5 | ||||
-rw-r--r-- | engines/scumm/scumm_v0.h | 30 | ||||
-rw-r--r-- | engines/scumm/scumm_v2.h | 2 | ||||
-rw-r--r-- | engines/scumm/vars.cpp | 4 | ||||
-rw-r--r-- | engines/scumm/verbs.cpp | 471 |
11 files changed, 640 insertions, 92 deletions
diff --git a/engines/scumm/object.cpp b/engines/scumm/object.cpp index f29be071e0..084d1242c6 100644 --- a/engines/scumm/object.cpp +++ b/engines/scumm/object.cpp @@ -181,7 +181,11 @@ void ScummEngine::clearOwnerOf(int obj) { // Alternatively, scan the inventory to see if the object is in there... for (i = 0; i < _numInventory; i++) { if (_inventory[i] == obj) { - assert(WIO_INVENTORY == whereIsObject(obj)); + if (_game.version == 0) + assert(WIO_INVENTORY == whereIsObjectInventory(obj)); + else + assert(WIO_INVENTORY == whereIsObject(obj)); + // Found the object! Nuke it from the inventory. _res->nukeResource(rtInventory, i); _inventory[i] = 0; @@ -286,7 +290,7 @@ int ScummEngine::getState(int obj) { // it. Fortunately this does not prevent frustrated players from // blowing up the mansion, should they feel the urge to. - if (_game.id == GID_MANIAC && (obj == 182 || obj == 193)) + if (_game.id == GID_MANIAC && _game.version != 0 && (obj == 182 || obj == 193)) _objectStateTable[obj] |= kObjectState_08; } @@ -317,6 +321,15 @@ int ScummEngine::getObjectIndex(int object) const { return -1; } +int ScummEngine::whereIsObjectInventory(int object) { + int res = 0; + _v0ObjectInInventory = true; + res = whereIsObject(object); + _v0ObjectInInventory = false; + + return res; +} + int ScummEngine::whereIsObject(int object) const { int i; @@ -326,7 +339,7 @@ int ScummEngine::whereIsObject(int object) const { if (object < 1) return WIO_NOT_FOUND; - if (_objectOwnerTable[object] != OF_OWNER_ROOM) { + if ((_objectOwnerTable[object] != OF_OWNER_ROOM && _game.version != 0) || _v0ObjectInInventory) { for (i = 0; i < _numInventory; i++) if (_inventory[i] == object) return WIO_INVENTORY; @@ -334,7 +347,7 @@ int ScummEngine::whereIsObject(int object) const { } for (i = (_numLocalObjects-1); i > 0; i--) - if (_objs[i].obj_nr == object) { + if ((_objs[i].obj_nr == object && !_v0ObjectIndex) || (_v0ObjectIndex && i == object)) { if (_objs[i].fl_object_index) return WIO_FLOBJECT; return WIO_ROOM; @@ -379,7 +392,7 @@ int ScummEngine::getObjectOrActorXY(int object, int &x, int &y) { * Returns X, Y and direction in angles */ void ScummEngine::getObjectXYPos(int object, int &x, int &y, int &dir) { - int idx = getObjectIndex(object); + int idx = (_v0ObjectIndex) ? object : getObjectIndex(object); assert(idx >= 0); ObjectData &od = _objs[idx]; int state; @@ -434,7 +447,7 @@ void ScummEngine::getObjectXYPos(int object, int &x, int &y, int &dir) { dir = oldDirToNewDir(od.actordir & 3); } -static int getDist(int x, int y, int x2, int y2) { +int ScummEngine::getDist(int x, int y, int x2, int y2) { int a = ABS(y - y2); int b = ABS(x - x2); return MAX(a, b); @@ -475,6 +488,14 @@ int ScummEngine::getObjActToObjActDist(int a, int b) { return getDist(x, y, x2, y2); } +int ScummEngine_v0::findObjectIndex(int x, int y) { + int objIdx; + _v0ObjectIndex = true; + objIdx = findObject(x, y); + _v0ObjectIndex = false; + return objIdx; +} + int ScummEngine::findObject(int x, int y) { int i, b; byte a; @@ -505,7 +526,10 @@ int ScummEngine::findObject(int x, int y) { #endif if (_objs[i].x_pos <= x && _objs[i].width + _objs[i].x_pos > x && _objs[i].y_pos <= y && _objs[i].height + _objs[i].y_pos > y) - return _objs[i].obj_nr; + if (_game.version == 0 && _v0ObjectIndex) + return i; + else + return _objs[i].obj_nr; break; } } while ((_objs[b].state & mask) == a); @@ -811,6 +835,9 @@ void ScummEngine_v3old::resetRoomObjects() { if (_dumpScripts) { char buf[32]; sprintf(buf, "roomobj-%d-", _roomResource); + if (_game.version == 0) + sprintf(buf + 11, "%d-", od->flags); + dumpResource(buf, od->obj_nr, room + od->OBCDoffset); } } @@ -1033,6 +1060,10 @@ void ScummEngine::updateObjectStates() { int i; ObjectData *od = &_objs[1]; for (i = 1; i < _numLocalObjects; i++, od++) { + // V0 MM, Room objects with Flag == 1 are objects with 'no-state' (room specific objects, non-pickup) + if (_game.version == 0 && od->flags == 1) + continue; + if (od->obj_nr > 0) od->state = getState(od->obj_nr); } @@ -1155,7 +1186,7 @@ const byte *ScummEngine::getObjOrActorName(int obj) { void ScummEngine::setObjectName(int obj) { int i; - if (obj < _numActors) + if (obj < _numActors && _game.version != 0) error("Can't set actor %d name with new-name-of", obj); for (i = 0; i < _numNewNames; i++) { @@ -1181,8 +1212,13 @@ void ScummEngine::setObjectName(int obj) { uint32 ScummEngine::getOBCDOffs(int object) const { int i; - if (_objectOwnerTable[object] != OF_OWNER_ROOM) + if (_objectOwnerTable[object] != OF_OWNER_ROOM && (_game.version != 0) || _v0ObjectInInventory) return 0; + + // V0 MM Return by Index + if (_v0ObjectIndex) + return _objs[object].OBCDoffset; + for (i = (_numLocalObjects-1); i > 0; i--) { if (_objs[i].obj_nr == object) { if (_objs[i].fl_object_index != 0) @@ -1194,17 +1230,20 @@ uint32 ScummEngine::getOBCDOffs(int object) const { } byte *ScummEngine::getOBCDFromObject(int obj) { + bool useInventory = _v0ObjectInInventory; int i; byte *ptr; - if (_objectOwnerTable[obj] != OF_OWNER_ROOM) { + _v0ObjectInInventory = false; + + if ((_objectOwnerTable[obj] != OF_OWNER_ROOM && (_game.version != 0)) || useInventory) { for (i = 0; i < _numInventory; i++) { if (_inventory[i] == obj) return getResourceAddress(rtInventory, i); } } else { for (i = (_numLocalObjects-1); i > 0; --i) { - if (_objs[i].obj_nr == obj) { + if ((_objs[i].obj_nr == obj && !_v0ObjectIndex) || (_v0ObjectIndex && i == obj)) { if (_objs[i].fl_object_index) { assert(_objs[i].OBCDoffset == 8); ptr = getResourceAddress(rtFlObject, _objs[i].fl_object_index); diff --git a/engines/scumm/saveload.cpp b/engines/scumm/saveload.cpp index 08c34dcfca..d906760243 100644 --- a/engines/scumm/saveload.cpp +++ b/engines/scumm/saveload.cpp @@ -1384,9 +1384,12 @@ void ScummEngine::saveOrLoad(Serializer *s) { void ScummEngine_v0::saveOrLoad(Serializer *s) { ScummEngine::saveOrLoad(s); - // TODO: Save additional variables - // _currentMode - // _currentLights + const SaveLoadEntry v0Entrys[] = { + MKLINE(ScummEngine_v0, _currentMode, sleByte, VER(78)), + MKLINE(ScummEngine_v0, _currentLights, sleByte, VER(78)), + MKEND() + }; + s->saveLoadEntries(this, v0Entrys); } void ScummEngine_v5::saveOrLoad(Serializer *s) { diff --git a/engines/scumm/saveload.h b/engines/scumm/saveload.h index 29184ad023..49bfe39b21 100644 --- a/engines/scumm/saveload.h +++ b/engines/scumm/saveload.h @@ -50,7 +50,7 @@ namespace Scumm { * only saves/loads those which are valid for the version of the savegame * which is being loaded/saved currently. */ -#define CURRENT_VER 77 +#define CURRENT_VER 78 /** * An auxillary macro, used to specify savegame versions. We use this instead diff --git a/engines/scumm/script.cpp b/engines/scumm/script.cpp index 4d9447bee5..ad9e0a92d1 100644 --- a/engines/scumm/script.cpp +++ b/engines/scumm/script.cpp @@ -133,6 +133,8 @@ void ScummEngine::runObjectScript(int object, int entry, bool freezeResistant, b initializeLocals(slot, vars); + // V0 Ensure we don't try and access objects via index inside the script + _v0ObjectIndex = false; runScriptNested(slot); } diff --git a/engines/scumm/script_v0.cpp b/engines/scumm/script_v0.cpp index 50c4a89e0a..873f2fa281 100644 --- a/engines/scumm/script_v0.cpp +++ b/engines/scumm/script_v0.cpp @@ -410,41 +410,43 @@ void ScummEngine_v0::decodeParseString() { actorTalk(buffer); } -void ScummEngine_v0::drawSentence() { - Common::Rect sentenceline; +void ScummEngine_v0::drawSentenceWord(int object, bool usePrep, bool objInInventory) { const byte *temp; int sentencePrep = 0; + + // If object not in inventory, we except an index + if (!objInInventory) + _v0ObjectIndex = true; + else + _v0ObjectInInventory = true; - if (!(_userState & 32)) - return; + temp = getObjOrActorName(object); - if (getResourceAddress(rtVerb, _activeVerb)) { - strcpy(_sentenceBuf, (char*)getResourceAddress(rtVerb, _activeVerb)); - } else { - return; + _v0ObjectInInventory = false; + _v0ObjectIndex = false; + + // Append the 'object-name' + if (temp) { + strcat(_sentenceBuf, " "); + strcat(_sentenceBuf, (const char*)temp); } - if (_activeObject > 0) { - temp = getObjOrActorName(_activeObject); - if (temp) { - strcat(_sentenceBuf, " "); - strcat(_sentenceBuf, (const char*)temp); - } + // Append the modifier? (With / On / To / In) + if (!usePrep) + return; - if (_verbs[_activeVerb].prep == 0xFF) { - byte *ptr = getOBCDFromObject(_activeObject); - assert(ptr); - sentencePrep = (*(ptr + 11) >> 5); - } else { - sentencePrep = _verbs[_activeVerb].prep; - } + if (_verbs[_activeVerb].prep == 0xFF) { + _v0ObjectInInventory = objInInventory; + sentencePrep = verbPrep(object); + } else { + sentencePrep = _verbs[_activeVerb].prep; } if (sentencePrep > 0 && sentencePrep <= 4) { // The prepositions, like the fonts, were hard code in the engine. Thus // we have to do that, too, and provde localized versions for all the // languages MM/Zak are available in. - const char *prepositions[][5] = { + static const char *prepositions[][5] = { { " ", " in", " with", " on", " to" }, // English { " ", " mit", " mit", " mit", " zu" }, // German { " ", " dans", " avec", " sur", " <" }, // French @@ -471,13 +473,65 @@ void ScummEngine_v0::drawSentence() { strcat(_sentenceBuf, prepositions[lang][sentencePrep]); } +} + +void ScummEngine_v0::drawSentence() { + Common::Rect sentenceline; + bool inventoryFirst = false; + + if (!(_userState & 32)) + return; + + // Current Verb, Walk/Use + if (getResourceAddress(rtVerb, _activeVerb)) { + strcpy(_sentenceBuf, (char*)getResourceAddress(rtVerb, _activeVerb)); + } else { + return; + } - if (_activeInventory > 0) { - temp = getObjOrActorName(_activeInventory); - if (temp) { - strcat(_sentenceBuf, " "); - strcat(_sentenceBuf, (const char*)temp); + // If using inventory first, draw it first + if (_activeInvExecute && _activeInventory) { + drawSentenceWord(_activeInventory, true, true); + } else { + // Not using inventory, use selected object + if (_activeObject) + drawSentenceWord(_activeObjectIndex, true, false); + else + inventoryFirst = true; + } + + + // Draw the inventory? + if (_activeInventory > 0 && _activeObject2 == 0) { + // Only if inventory isnt first (it will already be drawn by now) + if (!_activeInvExecute) { + drawSentenceWord(_activeInventory, inventoryFirst, true); + } else { + // Draw the active object, which could be inventory based, or room based + if (_activeObject && !_activeObjectIndex) { + drawSentenceWord(_activeObject, inventoryFirst, true); + } else // Room based + drawSentenceWord(_activeObjectIndex, inventoryFirst, false); } + + // Draw the 2nd active object + } else if (_activeObject2) { + + // 2nd Object is in inventory + if (_activeObject2Inv) { + _v0ObjectInInventory = true; + drawSentenceWord(_activeObject2, inventoryFirst, true); + } else { + drawSentenceWord(_activeObject2Index, inventoryFirst, false); + } + } + + // Draw the active actor + if (_activeActor) { + Actor *a = derefActor(_activeActor, ""); + + strcat(_sentenceBuf, " "); + strcat(_sentenceBuf, (const char*)a->getActorName()); } _string[2].charset = 1; @@ -664,6 +718,7 @@ void ScummEngine_v0::o_animateActor() { int act = getVarOrDirectByte(PARAM_1); int anim = getVarOrDirectByte(PARAM_2); int unk = fetchScriptByte(); + debug(0,"o_animateActor: unk %d", unk); ActorC64 *a = (ActorC64*) derefActor(act, "o_animateActor"); @@ -725,9 +780,9 @@ void ScummEngine_v0::o_pickupObject() { if (getObjectIndex(obj) == -1) return; - if (whereIsObject(obj) == WIO_INVENTORY) /* Don't take an */ + if (whereIsObjectInventory(_activeObject2) == WIO_INVENTORY) /* Don't take an */ return; /* object twice */ - + addObjectToInventory(obj, _roomResource); markObjectRectAsDirty(obj); putOwner(obj, VAR(VAR_EGO)); @@ -917,10 +972,25 @@ void ScummEngine_v0::o_setOwnerOf() { setOwnerOf(obj, owner); } -void ScummEngine_v0::resetSentence() { - _activeInventory = 0; - _activeObject = 0; +void ScummEngine_v0::resetSentence(bool walking) { _activeVerb = 13; + + if (!walking) { + _activeInventory = 0; + _activeObject = 0; + _activeObject2 = 0; + _activeObjectIndex = 0; + _activeObject2Index = 0; + } + + _verbExecuting = false; + _verbPickup = false; + + _activeActor = 0; + _activeInvExecute = false; + _activeObject2Inv = false; + _activeObjectObtained = false; + _activeObject2Obtained = false; } } // End of namespace Scumm diff --git a/engines/scumm/scumm.cpp b/engines/scumm/scumm.cpp index bdc2a4d387..3851cc7fb7 100644 --- a/engines/scumm/scumm.cpp +++ b/engines/scumm/scumm.cpp @@ -134,6 +134,8 @@ ScummEngine::ScummEngine(OSystem *syst, const DetectorResult &dr) // Init all vars + _v0ObjectIndex = false; + _v0ObjectInInventory = false; _imuse = NULL; _imuseDigital = NULL; _musicEngine = NULL; @@ -664,7 +666,17 @@ ScummEngine_v2::ScummEngine_v2(OSystem *syst, const DetectorResult &dr) ScummEngine_v0::ScummEngine_v0(OSystem *syst, const DetectorResult &dr) : ScummEngine_v2(syst, dr) { + _verbExecuting = false; + _verbPickup = false; _currentMode = 0; + + _activeObject2 = 0; + _activeObjectIndex = 0; + _activeObject2Index = 0; + _activeInvExecute = false; + _activeObject2Inv = false; + _activeObjectObtained = false; + _activeObject2Obtained = false; } ScummEngine_v6::ScummEngine_v6(OSystem *syst, const DetectorResult &dr) diff --git a/engines/scumm/scumm.h b/engines/scumm/scumm.h index 3d16bea2b1..753c5c2bca 100644 --- a/engines/scumm/scumm.h +++ b/engines/scumm/scumm.h @@ -565,6 +565,9 @@ protected: int32 *_scummVars; byte *_bitVars; + bool _v0ObjectIndex; // V0 Use object index, instead of object number + bool _v0ObjectInInventory; // V0 Use object number from inventory + /* Global resource tables */ int _numVariables, _numBitVariables, _numLocalObjects; int _numGlobalObjects, _numArray, _numVerbs, _numFlObject; @@ -858,12 +861,14 @@ protected: int getObjNewDir(int obj); int getObjectIndex(int object) const; int getObjectImageCount(int object); + int whereIsObjectInventory(int object); int whereIsObject(int object) const; int findObject(int x, int y); void findObjectInRoom(FindObjectInRoom *fo, byte findWhat, uint object, uint room); public: int getObjectOrActorXY(int object, int &x, int &y); // Used in actor.cpp, hence public protected: + int getDist(int x, int y, int x2, int y2); int getObjActToObjActDist(int a, int b); // Not sure how to handle const byte *getObjOrActorName(int obj); // these three.. void setObjectName(int obj); diff --git a/engines/scumm/scumm_v0.h b/engines/scumm/scumm_v0.h index ccca5df0d3..19260b6429 100644 --- a/engines/scumm/scumm_v0.h +++ b/engines/scumm/scumm_v0.h @@ -35,7 +35,20 @@ namespace Scumm { */ class ScummEngine_v0 : public ScummEngine_v2 { protected: - int _currentMode; + byte _currentMode; + bool _verbExecuting; // is a verb executing + bool _verbPickup; // are we picking up an object during a verb execute + + int _activeActor; // Actor Number + int _activeObject2; // 2nd Object Number + + bool _activeInvExecute; // is activeInventory first to be executed + bool _activeObject2Inv; // is activeobject2 in the inventory + bool _activeObjectObtained; // collected _activeobject? + bool _activeObject2Obtained; // collected _activeObject2? + + int _activeObjectIndex; + int _activeObject2Index; public: ScummEngine_v0(OSystem *syst, const DetectorResult &dr); @@ -53,12 +66,25 @@ protected: virtual void processInput(); + virtual void runObject(int obj, int entry); virtual void saveOrLoad(Serializer *s); + // V0 MM Verb commands + int verbPrep(int object); + bool verbMove(int object, int objectIndex, bool invObject); + bool verbMoveToActor(int actor); + bool verbObtain(int object, int objIndex); + bool verbExecutes(int object, bool inventory = false); + bool verbExec(); + + int findObjectIndex(int x, int y); + virtual void checkExecVerbs(); virtual void handleMouseOver(bool updateInventory); void resetVerbs(); void setNewKidVerbs(); + + void drawSentenceWord(int object, bool usePrep, bool objInInventory); void drawSentence(); void switchActor(int slot); @@ -68,7 +94,7 @@ protected: virtual int getActiveObject(); - virtual void resetSentence(); + virtual void resetSentence(bool walking = false); /* Version C64 script opcodes */ void o_stopCurrentScript(); diff --git a/engines/scumm/scumm_v2.h b/engines/scumm/scumm_v2.h index 338b5f6167..76176b9c53 100644 --- a/engines/scumm/scumm_v2.h +++ b/engines/scumm/scumm_v2.h @@ -100,7 +100,7 @@ protected: virtual void setBuiltinCursor(int index); - void runObject(int obj, int entry); + virtual void runObject(int obj, int entry); /* Version 2 script opcodes */ void o2_actorFromPos(); diff --git a/engines/scumm/vars.cpp b/engines/scumm/vars.cpp index 22487b43a3..98e088365e 100644 --- a/engines/scumm/vars.cpp +++ b/engines/scumm/vars.cpp @@ -538,9 +538,7 @@ void ScummEngine_v8::setupScummVars() { #endif void ScummEngine_v0::resetScummVars() { - _activeInventory = 0; - _activeObject = 0; - _activeVerb = 13; + resetSentence(); VAR(VAR_EGO) = 3; diff --git a/engines/scumm/verbs.cpp b/engines/scumm/verbs.cpp index 81b28ce563..87e1b3612f 100644 --- a/engines/scumm/verbs.cpp +++ b/engines/scumm/verbs.cpp @@ -155,6 +155,7 @@ void ScummEngine_v0::switchActor(int slot) { VAR(VAR_EGO) = VAR(97 + slot); actorFollowCamera(VAR(VAR_EGO)); resetVerbs(); + resetSentence(false); setUserState(247); } @@ -376,14 +377,8 @@ void ScummEngine_v2::checkV2Inventory(int x, int y) { if (object > 0) { if (_game.version == 0) { - if (_activeInventory != object) { _activeInventory = object; - } else if (_activeVerb != 3 && _activeVerb != 13) { - if (_activeObject) - runObject(_activeObject, _activeVerb); - else - runObject(_activeInventory, _activeVerb); - } + } else { runInputScript(kInventoryClickArea, object, 0); } @@ -425,7 +420,9 @@ void ScummEngine_v2::redrawV2Inventory() { _string[1].right = _mouseOverBoxesV2[i].rect.right - 1; _string[1].color = _mouseOverBoxesV2[i].color; + _v0ObjectInInventory = true; const byte *tmp = getObjOrActorName(obj); + _v0ObjectInInventory = false; assert(tmp); // Prevent inventory entries from overflowing by truncating the text @@ -666,6 +663,25 @@ void ScummEngine_v2::checkExecVerbs() { } } +void ScummEngine_v0::runObject(int obj, int entry) { + int prev = _v0ObjectInInventory; + + if (getVerbEntrypoint(obj, entry) != 0) { + _v0ObjectInInventory = prev; + runObjectScript(obj, entry, false, false, NULL); + } else if (entry != 13 && entry != 15) { + if (_activeVerb != 3) { + VAR(9) = entry; + runScript(3, 0, 0, 0); + + // For some reasons, certain objects don't have a "give" script + } else if (VAR(5) > 0 && VAR(5) < 8) { + if (_activeInventory) + setOwnerOf(_activeInventory, VAR(5)); + } + } +} + void ScummEngine_v2::runObject(int obj, int entry) { if (getVerbEntrypoint(obj, entry) != 0) { runObjectScript(obj, entry, false, false, NULL); @@ -679,10 +695,299 @@ void ScummEngine_v2::runObject(int obj, int entry) { _activeVerb = 13; } +bool ScummEngine_v0::verbMoveToActor(int actor) { + Actor *a = derefActor(VAR(VAR_EGO), "checkExecVerbs"); + Actor *a2 =derefActor(actor, "checkExecVerbs"); + + + if (!a->_moving) { + int dist = getDist(a->getRealPos().x, a->getRealPos().y, a2->getRealPos().x, a2->getRealPos().y); + + if (dist>5) + a->startWalkActor(a2->getRealPos().x, a2->getRealPos().y, 1); + else + return false; + + return true; + } + + return true; +} + +bool ScummEngine_v0::verbMove(int object, int objectIndex, bool invObject) { + int x, y, dir; + Actor *a = derefActor(VAR(VAR_EGO), "checkExecVerbs"); + + if (_currentMode != 3 && _currentMode != 2) + return false; + + if (a->_moving) + return true; + + _v0ObjectIndex = true; + getObjectXYPos(objectIndex, x, y, dir); + _v0ObjectIndex = false; + // Detect distance from target object + int dist = getDist(a->getRealPos().x, a->getRealPos().y, x, y); + + // FIXME: This should be changed once the walkbox problem is fixed + if (dist>0x5) { + a->startWalkActor(x, y, dir); + VAR(6) = x; + VAR(7) = y; + return true; + } else { + + // Finished walk, are we picking up the item? + if (_verbPickup) { + int oldActive = _activeObject, oldIndex = _activeObjectIndex; + _activeObject = object; + _activeObjectIndex = objectIndex; + + _v0ObjectIndex = true; + // Execute pickup + runObject(objectIndex, 14); + _v0ObjectIndex = false; + + _activeObject = oldActive; + _activeObjectIndex = oldIndex; + + // Finished picking up + _verbPickup = false; + } + } + + return false; +} + +bool ScummEngine_v0::verbObtain(int obj, int objIndex) { + bool didPickup = false; + + int prep, where = whereIsObjectInventory(obj); + + if (objIndex == 0) + return false; + + if (where != WIO_INVENTORY) { + _v0ObjectIndex = true; + prep = verbPrep(objIndex); + + if (prep == 1 || prep == 4) { + if (_activeVerb != 13 && _activeVerb != 14) { + _verbPickup = true; + didPickup = true; + } + } else { + _verbPickup = false; + } + + if (verbMove(obj, objIndex, false)) + return true; + + if (didPickup && (prep == 1 || prep == 4)) + if (_activeVerb != 13 && _activeVerb != 14) + _activeInventory = obj; + } + + return false; +} + +int ScummEngine_v0::verbPrep(int object) { + if (!_v0ObjectInInventory) + _v0ObjectIndex = true; + else + _v0ObjectIndex = false; + byte *ptr = getOBCDFromObject(object); + _v0ObjectIndex = false; + assert(ptr); + return (*(ptr + 11) >> 5); +} + +bool ScummEngine_v0::verbExecutes(int object, bool inventory) { + _v0ObjectInInventory = inventory; + int prep = verbPrep(object); + + if (prep == 2 || prep == 0) { + return true; + } + + return false; +} + +bool ScummEngine_v0::verbExec() { + int prep = 0; + int entry = (_currentMode != 0 && _currentMode != 1) ? _activeVerb : 15; + + if ((!_activeInvExecute && _activeObject && getObjectIndex(_activeObject) == -1)) { + resetSentence(); + return false; + } + + // Lets try walk to the object + if (_activeObject && _activeObjectIndex && !_activeObjectObtained && _currentMode != 0) { + prep = verbPrep(_activeObjectIndex); + + if (verbObtain(_activeObject, _activeObjectIndex)) + return true; + + _activeObjectObtained = true; + } + + if (_activeObject2 && _activeObject2Index && !_activeObject2Obtained && _currentMode != 0) { + prep = verbPrep(_activeObject2Index); + + _v0ObjectInInventory = false; + if (verbObtain(_activeObject2, _activeObject2Index)) + return true; + + if (prep != 1 && prep != 4) { + _activeInventory = _activeObject; + _activeObject = _activeObject2; + _activeObjectIndex = _activeObject2Index; + _activeObject2 = 0; + _activeObject2Index = 0; + } + + _activeObject2Obtained = true; + } + + // Give-To + if (_activeVerb == 3 && _activeInventory && _activeActor) { + // FIXME: Actors need to turn and face each other + // And walk to each other + // + if (verbMoveToActor(_activeActor)) + return true; + + _v0ObjectInInventory = true; + VAR(5) = _activeActor; + runObject(_activeInventory , 3); + _v0ObjectInInventory = false; + + resetSentence(); + return false; + } + + if (_activeActor) { + _v0ObjectIndex = true; + runObject(_activeActor, entry); + _v0ObjectIndex = false; + _verbExecuting = false; + + resetSentence(); + return false; + } + + // If we've finished walking (now near target), execute the action + if (_activeObject && _activeObjectIndex && verbPrep(_activeObjectIndex) == 2) { + _v0ObjectIndex = true; + runObject(_activeObjectIndex, entry); + _v0ObjectIndex = false; + _verbExecuting = false; + + if ((_currentMode == 3 || _currentMode == 2) && _activeVerb == 13) + return false; + + resetSentence(); + return false; + } + + // We acted on an inventory item + if (_activeInventory && verbExecutes(_activeInventory, true) && _activeVerb != 3) { + _v0ObjectInInventory = true; + runObject(_activeInventory, _activeVerb); + + _verbExecuting = false; + + if (_currentMode == 3 && _activeVerb == 13) { + resetSentence(true); + return false; + } + + resetSentence(); + return false; + } + + if (_activeObject) { + _v0ObjectIndex = true; + runObject(_activeObjectIndex, entry); + _v0ObjectIndex = false; + } else if (_activeInventory) { + if (verbExecutes(_activeInventory, true) == false) { + + if (_activeObject2 && verbExecutes(_activeObject2, true)) { + _v0ObjectInInventory = true; + + _activeObject = _activeInventory; + _activeInventory = _activeObject2; + + runObject(_activeObject, _activeVerb); + } else { + _v0ObjectInInventory = true; + runObject(_activeInventory, _activeVerb); + } + } else { + runObject(_activeInventory, _activeVerb); + _v0ObjectInInventory = true; + } + } + + _verbExecuting = false; + + if (_activeVerb == 13) { + resetSentence(true); + return false; + } + + resetSentence(); + + return false; +} + void ScummEngine_v0::checkExecVerbs() { Actor *a; VirtScreen *zone = findVirtScreen(_mouse.y); + // Is a verb currently executing + if (_verbExecuting) { + + // Check if mouse click + if (_mouseAndKeyboardStat & MBS_MOUSE_MASK) { + int over = findVerbAtPos(_mouse.x, _mouse.y); + int act = getActorFromPos(_virtualMouse.x, _virtualMouse.y); + int obj = findObject(_virtualMouse.x, _virtualMouse.y); + + if (over && over != _activeVerb) { + _activeVerb = over; + _verbExecuting = false; + return; + } + + if (!obj && !act && !over) { + resetSentence(false); + } else { + a = derefActor(VAR(VAR_EGO), "checkExecVerbs"); + a->stopActorMoving(); + } + } else { + if (_verbExecuting && !verbExec()) + return; + } + } + + // What-Is selected, any object we hover over is selected, on mouse press we set to WalkTo + if (_activeVerb == 15) { + int obj = findObject(_virtualMouse.x, _virtualMouse.y); + int objIdx = findObjectIndex(_virtualMouse.x, _virtualMouse.y); + _activeObject = obj; + _activeObjectIndex = objIdx; + + if ((_mouseAndKeyboardStat & MBS_MOUSE_MASK)) + _activeVerb = 13; // Walk-To + + return; + } + if (_userPut <= 0 || _mouseAndKeyboardStat == 0) return; @@ -693,61 +998,149 @@ void ScummEngine_v0::checkExecVerbs() { if (zone->number == kVerbVirtScreen && _mouse.y <= zone->topline + 8) { // TODO } else if (zone->number == kVerbVirtScreen && _mouse.y > zone->topline + 32) { + int prevInventory = _activeInventory; + // Click into V2 inventory checkV2Inventory(_mouse.x, _mouse.y); + if (!_activeInventory) + return; + + // Did we just change the selected inventory item? + if (prevInventory && prevInventory != _activeInventory && _activeInventory != _activeObject2) { + _activeObject = 0; + _activeInvExecute = true; + _activeObject2Inv = true; + _activeObject2 = _activeInventory; + _activeInventory = prevInventory; + return; + } + + // is the new selected inventory the same as the last selected?, reset to previous if it is + if (_activeInventory == _activeObject2) + _activeInventory = prevInventory; + + // Inventory Selected changed + if (prevInventory != _activeInventory) + if (!_activeObject2 || prevInventory != _activeObject2) + return; + + if (_activeVerb == 11 && !((!(_activeObject || _activeInventory)) || !_activeObject2)) + return; + } else { int over = findVerbAtPos(_mouse.x, _mouse.y); + int act = getActorFromPos(_virtualMouse.x, _virtualMouse.y); + int obj = findObject(_virtualMouse.x, _virtualMouse.y); + int objIdx = findObjectIndex(_virtualMouse.x, _virtualMouse.y); + + if ((_activeObject || _activeInventory) && act) { + obj = 0; + objIdx = 0; + } // Handle New Kid verb options - if (_activeVerb == 7) { + if (_activeVerb == 7 || over == 7) { + // Disable New-Kid (in the secret lab) + if (_currentMode == 2 || _currentMode == 0) + return; + + if (_activeVerb != 7) { + _activeVerb = over; + over = 0; + } + if (over) { _activeVerb = 13; switchActor(_verbs[over].verbid - 1); + return; } + + setNewKidVerbs(); + return; } + + // Clicked on nothing, walk here? + if (!over && !act && _activeVerb == 13 && !obj && _currentMode != 0) { + + // Clear all selected + resetSentence(); - if (over) { - _activeVerb = _verbs[over].verbid; - // Selected New Kid verb - if (_activeVerb == 7) - setNewKidVerbs(); + // 0xB31 + VAR(6) = _virtualMouse.x / V12_X_MULTIPLIER; + VAR(7) = _virtualMouse.y / V12_Y_MULTIPLIER; + if (zone->number == kMainVirtScreen) { + a = derefActor(VAR(VAR_EGO), "checkExecVerbs"); + a->stopActorMoving(); + a->startWalkActor(_virtualMouse.x / V12_X_MULTIPLIER, _virtualMouse.y / V12_Y_MULTIPLIER, -1); + } return; } - int act = getActorFromPos(_virtualMouse.x, _virtualMouse.y); - int obj = findObject(_virtualMouse.x, _virtualMouse.y); - if (act != 0 && _activeVerb == 3 && _activeInventory != 0) { - // Give inventory item to actor - VAR(5) = act; - runObject(_activeInventory, _activeVerb); - } else if (obj) { - if (_currentMode == 3 && _activeVerb != 13 && obj != _activeObject) { - _activeObject = obj; - return; - } + // No new verb, use previous + if (over == 0) + over = _activeVerb; - _activeObject = obj; - if (_currentMode == 3) { - int x, y, dir; - a = derefActor(VAR(VAR_EGO), "checkExecVerbs"); - getObjectXYPos(obj, x, y, dir); - a->startWalkActor(x, y, dir); + // No verb selected, use walk-to + if (!_activeVerb) + _activeVerb = over = 13; // Walk-To + + // New verb selected + if (_activeVerb != over) { + _activeVerb = over; + if (_activeVerb == 13) { + resetSentence(); } + return; + } - int entry = (_currentMode == 3) ? _activeVerb : 15; - runObject(_activeObject, entry); - } else if (zone->number == kMainVirtScreen) { - a = derefActor(VAR(VAR_EGO), "checkExecVerbs"); - a->startWalkActor(_virtualMouse.x / V12_X_MULTIPLIER, _virtualMouse.y / V12_Y_MULTIPLIER, -1); + // Only allowing targetting actors if its the GIVE/USE verb + if (_activeVerb == 3 || _activeVerb == 11) { + // Different actor selected? + if (act) { + if (_activeActor != act) { + _activeActor = act; + return; + } + } } - _activeInventory = 0; - _activeObject = 0; - _activeVerb = 13; + if (obj && obj != _activeObject) { + if (!_activeObject) + if (_activeInventory) + _activeInvExecute = true; + + // USE + if (_activeVerb == 11 || _activeVerb == 8) { + if (obj != _activeObject || obj != _activeObject2) { + if (!_activeObject || _activeInventory) { + _activeObject = obj; + _activeObjectIndex = objIdx; + return; + } else { + if (_activeObject2 != obj) { + _activeObject2 = obj; + _activeObject2Index = objIdx; + return; + } + } + } + } else { + _activeObject = obj; + _activeObjectIndex = objIdx; + + if (_activeVerb != 13) + return; + + //return; + } + } } - } + + _verbExecuting = true; + + } // mouse k/b action } void ScummEngine::verbMouseOver(int verb) { |