From 1192f0dfca144db2b6913ce8db950dce028d012c Mon Sep 17 00:00:00 2001 From: Paul Gilbert Date: Sat, 29 Apr 2006 11:22:05 +0000 Subject: Enhanced hotspot action so that the player will properly walk to a hotspot before performing an action svn-id: r22209 --- engines/lure/game.cpp | 58 ++--- engines/lure/game.h | 1 + engines/lure/hotspots.cpp | 609 ++++++++++++++++++++++++++++++++++------------ engines/lure/hotspots.h | 46 +++- 4 files changed, 526 insertions(+), 188 deletions(-) (limited to 'engines') diff --git a/engines/lure/game.cpp b/engines/lure/game.cpp index a760faac02..0b756694d0 100644 --- a/engines/lure/game.cpp +++ b/engines/lure/game.cpp @@ -281,12 +281,16 @@ void Game::handleClick() { fields.setField(NEW_ROOM_NUMBER, oldRoomNumber); fields.setField(OLD_ROOM_NUMBER, 0); } - } else if (res.getTalkState() != TALK_NONE) { + } else if ((room.cursorState() == CS_TALKING) || + (res.getTalkState() != TALK_NONE)) { // Currently talking, so let it's tick proc handle it } else if (mouse.y() < MENUBAR_Y_SIZE) { uint8 response = Menu::getReference().execute(); if (response != MENUITEM_NONE) handleMenuResponse(response); + } else if ((room.cursorState() == CS_SEQUENCE) || + (room.cursorState() == CS_UNKNOWN)) { + // No action necessary } else { if (mouse.lButton()) handleLeftClick(); @@ -303,7 +307,7 @@ void Game::handleRightClickMenu() { HotspotData *hotspot; Action action; uint32 actions; - uint16 itemId; + uint16 itemId = 0xffff; if (room.hotspotId() != 0) { // Get hotspot actions @@ -353,23 +357,9 @@ void Game::handleRightClickMenu() { } } - // Set fields used by the script interpreter - fields.setField(CHARACTER_HOTSPOT_ID, PLAYER_ID); - if (hotspot) { - fields.setField(ACTIVE_HOTSPOT_ID, hotspot->hotspotId); - if ((action != USE) && (action != GIVE)) { - fields.setField(USE_HOTSPOT_ID, 0xffff); - } - } - if (action != NONE) { - res.setCurrentAction(action); - room.update(); - Screen::getReference().update(); - player->doAction(action, hotspot); - - if (action != TALK_TO) - res.setCurrentAction(NONE); + player->stopWalking(); + doAction(action, (hotspot != NULL) ? hotspot->hotspotId : NULL, itemId); } } @@ -377,22 +367,17 @@ void Game::handleLeftClick() { Room &room = Room::getReference(); Mouse &mouse = Mouse::getReference(); Resources &res = Resources::getReference(); - ValueTableData &fields = res.fieldList(); Hotspot *player = res.getActiveHotspot(PLAYER_ID); + room.setCursorState(CS_NONE); + player->stopWalking(); + player->setDestHotspot(0); + player->setActionCtr(0); + if ((room.destRoomNumber() == 0) && (room.hotspotId() != 0)) { // Handle look at hotspot - HotspotData *hs = res.getHotspot(room.hotspotId()); + doAction(LOOK_AT, room.hotspotId(), 0xffff); - fields.setField(CHARACTER_HOTSPOT_ID, PLAYER_ID); - fields.setField(ACTIVE_HOTSPOT_ID, hs->hotspotId); - fields.setField(USE_HOTSPOT_ID, 0xffff); - - res.setCurrentAction(LOOK_AT); - room.update(); - Screen::getReference().update(); - player->doAction(LOOK_AT, hs); - res.setCurrentAction(NONE); } else if (room.destRoomNumber() != 0) { // Walk to another room RoomExitCoordinateData &exitData = @@ -406,6 +391,21 @@ void Game::handleLeftClick() { } } +void Game::doAction(Action action, uint16 hotspotId, uint16 usedId) { + Resources &res = Resources::getReference(); + Room &room = Room::getReference(); + ValueTableData &fields = res.fieldList(); + Hotspot *player = res.getActiveHotspot(PLAYER_ID); + + fields.setField(CHARACTER_HOTSPOT_ID, PLAYER_ID); + fields.setField(ACTIVE_HOTSPOT_ID, hotspotId); + fields.setField(USE_HOTSPOT_ID, usedId); + + res.setCurrentAction(action); + room.setCursorState(CS_ACTION); + player->setCurrentAction(DISPATCH_ACTION, action, hotspotId, usedId); +} + void Game::doShowCredits() { Events &events = Events::getReference(); Mouse &mouse = Mouse::getReference(); diff --git a/engines/lure/game.h b/engines/lure/game.h index 897b791087..658ad07f15 100644 --- a/engines/lure/game.h +++ b/engines/lure/game.h @@ -43,6 +43,7 @@ private: void handleClick(); void handleRightClickMenu(); void handleLeftClick(); + void doAction(Action action, uint16 hotspotId, uint16 usedId); void playerChangeRoom(); public: diff --git a/engines/lure/hotspots.cpp b/engines/lure/hotspots.cpp index 9499a8293f..c7faa092ad 100644 --- a/engines/lure/hotspots.cpp +++ b/engines/lure/hotspots.cpp @@ -68,8 +68,8 @@ Hotspot::Hotspot(HotspotData *res): _pathFinder(this) { _tickHandler = HotspotTickHandlers::getHandler(_data->tickProcOffset); _frameCtr = 0; _skipFlag = false; - _pathfindCovered = false; _charRectY = 0; + _actionCtr = 0; } // Special constructor used to create a voice hotspot @@ -300,10 +300,17 @@ void Hotspot::walkTo(int16 endPosX, int16 endPosY, uint16 destHotspot) { _destX = endPosX; _destY = endPosY; _destHotspotId = destHotspot; - _currentActions.clear(); setCurrentAction(START_WALKING); } +void Hotspot::stopWalking() { + // TODO: voiceCtr = 0 + _actionCtr = 0; + _currentActions.clear(); + Room::getReference().setCursorState(CS_NONE); + Resources::getReference().setCurrentAction(NONE); +} + void Hotspot::setDirection(Direction dir) { _direction = dir; @@ -334,7 +341,8 @@ void Hotspot::setDirection(Direction dir) { void Hotspot::faceHotspot(HotspotData *hotspot) { if (hotspot->hotspotId >= START_NONVISUAL_HOTSPOT_ID) { // Non visual hotspot - // TODO: + setDirection(hotspot->nonVisualDirection()); + } else { // Visual hotspot int xp = x() - hotspot->startX; @@ -344,23 +352,25 @@ void Hotspot::faceHotspot(HotspotData *hotspot) { if (yp < 0) setDirection(DOWN); else setDirection(UP); } else { - if (xp < 0) setDirection(LEFT); - else setDirection(RIGHT); + if (xp < 0) setDirection(RIGHT); + else setDirection(LEFT); } } + + if (hotspotId() == PLAYER_ID) { + Room::getReference().update(); + Screen::getReference().update(); + } } // Sets or clears the hotspot as occupying an area in it's room's pathfinding data void Hotspot::setOccupied(bool occupiedFlag) { - if (occupiedFlag == _pathfindCovered) return; - _pathfindCovered = occupiedFlag; - + int xp = x() >> 3; int yp = (y() - 8 + heightCopy() - 4) >> 3; int widthVal = MAX((widthCopy() >> 3), 1); // Handle cropping for screen left - int xp = (x() >> 3) - 16; if (xp < 0) { xp = -xp; widthVal -= xp; @@ -369,10 +379,9 @@ void Hotspot::setOccupied(bool occupiedFlag) { } // Handle cropping for screen right - int x2 = xp + widthVal; - if (x2 > ROOM_PATHS_WIDTH) { - ++x2; - widthVal -= x2; + int x2 = xp + widthVal - ROOM_PATHS_WIDTH - 1; + if (x2 >= 0) { + widthVal -= (x2 + 1); if (widthVal <= 0) return; } @@ -449,7 +458,7 @@ HotspotPrecheckResult Hotspot::actionPrecheck(HotspotData *hotspot) { (hotspot->hotspotId == 0x429)) { // TODO: figure out specific handling code actionPrecheck3(hotspot); - return PC_0; + return PC_EXECUTE; } else { return actionPrecheck2(hotspot); } @@ -460,24 +469,34 @@ HotspotPrecheckResult Hotspot::actionPrecheck2(HotspotData *hotspot) { if (hotspot->roomNumber != roomNumber()) { // Hotspot isn't in same room as character - if (frameNumber() != 0) { + if (_actionCtr == 0) Dialog::showMessage(0, hotspotId()); - setFrameNumber(0); - } - return PC_1; - } else if (frameNumber() != 0) { - // TODO: loc_883 - setFrameNumber(frameNumber() + 1); - if (frameNumber() >= 6) { + _actionCtr = 0; + return PC_NOT_IN_ROOM; + } else if (_actionCtr != 0) { + // loc_883 + ++_actionCtr; + + if (_actionCtr >= 6) { + warning("actionCtr exceeded"); + _actionCtr = 0; Dialog::showMessage(0xD, hotspotId()); - return PC_4; + return PC_EXCESS; } - if ((hotspot->hotspotId < 0x408)) { + if (hotspot->hotspotId < FIRST_NONCHARACTER_ID) { // TODO: Does other checks on HS[44] -> loc_886 - setFrameNumber(0); + _actionCtr = 0; Dialog::showMessage(0xE, hotspotId()); - return PC_2; + return PC_UNKNOWN; + } + } else { + _actionCtr = 1; + + if (hotspot->hotspotId < FIRST_NONCHARACTER_ID) { + // TODO: Extra Checks + Dialog::showMessage(5, hotspotId()); + return PC_INITIAL; } } @@ -485,60 +504,104 @@ HotspotPrecheckResult Hotspot::actionPrecheck2(HotspotData *hotspot) { return PC_INITIAL; } else { actionPrecheck3(hotspot); - return PC_0; + return PC_EXECUTE; } } void Hotspot::actionPrecheck3(HotspotData *hotspot) { - setFrameNumber(0); - if (hotspot->hotspotId < 0x408) { + _actionCtr = 0; + if (hotspot->hotspotId < FIRST_NONCHARACTER_ID) { // TODO: HS[44]=8, HS[42]=1E, HS[50]=ID } } -// Checks to see whether a character needs to walk to the given hotspot - bool Hotspot::characterWalkingCheck(HotspotData *hotspot) { - Resources &res = Resources::getReference(); - HotspotProximityList &list = res.proximityList(); - HotspotProximityList::iterator i; int16 xp, yp; - // Get default position - xp = hotspot->startX; - yp = hotspot->startY + hotspot->heightCopy - 4; + if ((hotspot->walkX == 0) && (hotspot->walkY == 0)) { + // The hotspot doesn't have any walk co-ordinates + xp = hotspot->startX; + yp = hotspot->startY + hotspot->heightCopy - 4; + } else { + xp = hotspot->walkX; + yp = hotspot->walkY & 0x7fff; + if ((hotspot->walkY & 0x8000) != 0) { + // Special handling for walking +// if (((xp >> 3) != (x() >> 3)) || +// ((((y() + heightCopy()) >> 3) - 1) != (yp >> 3))) { + if ((abs(xp - x()) > 8) || + (abs(yp - (y() + heightCopy())) > 8)) { + walkTo(xp, yp); + return true; + } else { + return false; + } + } + } - // Scan through the list for a proximity record - for (i = list.begin(); i != list.end(); ++i) { - HotspotProximityData *rec = *i; - if (rec->hotspotId != hotspot->hotspotId) continue; + // Default walking handling + // TODO: ANIM[27h] = 1 if hotspot has walk co-ordinates + if ((abs(x() - xp) >= 8) || + (abs(y() + heightCopy() - yp - 1) >= 19)) { + walkTo(xp, yp); + return true; + } - xp = (int16) rec->x; - yp = (int16) (rec->y & 0x7fff); + return false; +} - // If the high bit of the Y position is clear, use standard handling - // with the co-ordinates provided by the record - if ((rec->y & 0x8000) == 0) - break; - - // Special handling for if hi-bit of Y is set - if (((x() >> 3) != (xp >> 3)) || - ((((y() + heightCopy()) >> 3) - 1) != (yp >> 3))) { - walkTo(xp, yp); - return true; - } else { +bool Hotspot::doorCloseCheck(uint16 doorId) { + Resources &res = Resources::getReference(); + Hotspot *doorHotspot = res.getActiveHotspot(doorId); + if (!doorHotspot) { + warning("Hotspot %xh is not currently active", doorId); + return true; + } + + Rect bounds(doorHotspot->x(), doorHotspot->y() + doorHotspot->heightCopy() + - doorHotspot->yCorrection() - doorHotspot->charRectY(), + doorHotspot->x() + doorHotspot->widthCopy(), + doorHotspot->y() + doorHotspot->heightCopy() + doorHotspot->charRectY()); + + // Loop through active hotspots + HotspotList::iterator i; + HotspotList &lst = res.activeHotspots(); + for (i = lst.begin(); i != lst.end(); ++i) { + Hotspot *hsCurrent = *i; + + // Skip entry if it's the door or the character + if ((hsCurrent->hotspotId() == hotspotId()) || + (hsCurrent->hotspotId() == doorHotspot->hotspotId())) + continue; + + // Skip entry if it doesn't meet certain criteria + if ((hsCurrent->layer() == 0) || + (hsCurrent->roomNumber() != doorHotspot->roomNumber()) || + (hsCurrent->hotspotId() < PLAYER_ID) || + ((hsCurrent->hotspotId() >= 0x408) && (hsCurrent->hotspotId() < 0x2710))) + continue; + + // Also skip entry if special Id + if ((hsCurrent->hotspotId() == 0xfffe) || (hsCurrent->hotspotId() == 0xffff)) + continue; + + // Check the dimensions of the animation + if ((hsCurrent->x() < bounds.right) && + ((hsCurrent->x() + hsCurrent->widthCopy()) > bounds.left) && + ((hsCurrent->y() + hsCurrent->heightCopy() + hsCurrent->charRectY()) >= bounds.top) && + ((hsCurrent->y() + hsCurrent->heightCopy() - hsCurrent->charRectY() + - hsCurrent->yCorrection()) > bounds.bottom)) { + // Return false - the door can't be closed return false; } } - // Default handling - if ((abs(x() - xp) < 8) && (abs(y() + heightCopy() - 1 - yp) < 19)) - return false; - - walkTo(xp, yp); + // No blocking characters, so return true that the door can be closed return true; } +/*-------------------------------------------------------------------------*/ + void Hotspot::doAction(Action action, HotspotData *hotspot) { switch (action) { case GET: @@ -556,10 +619,10 @@ void Hotspot::doAction(Action action, HotspotData *hotspot) { doClose(hotspot); break; case LOCK: - doSimple(hotspot, LOCK); + doLockUnlock(hotspot); break; case UNLOCK: - doSimple(hotspot, UNLOCK); + doLockUnlock(hotspot); break; case USE: doUse(hotspot); @@ -580,13 +643,13 @@ void Hotspot::doAction(Action action, HotspotData *hotspot) { doLookAt(hotspot); break; case LOOK_THROUGH: - doSimple(hotspot, LOOK_THROUGH); + doLookThrough(hotspot); break; case ASK: doAsk(hotspot); break; case DRINK: - doDrink(); + doDrink(hotspot); break; case STATUS: doStatus(); @@ -595,7 +658,7 @@ void Hotspot::doAction(Action action, HotspotData *hotspot) { doBribe(hotspot); break; case EXAMINE: - doExamine(); + doExamine(hotspot); break; default: doSimple(hotspot, action); @@ -605,16 +668,16 @@ void Hotspot::doAction(Action action, HotspotData *hotspot) { void Hotspot::doGet(HotspotData *hotspot) { Resources &res = Resources::getReference(); - HotspotPrecheckResult result = actionPrecheck(hotspot); + if (result == PC_INITIAL) return; - else if (result != PC_0) { + else if (result !=PC_EXECUTE) { stopWalking(); return; } - stopWalking(); faceHotspot(hotspot); + stopWalking(); uint16 sequenceOffset = res.getHotspotAction(hotspot->actionsOffset, GET); if (sequenceOffset >= 0x8000) { @@ -645,14 +708,26 @@ void Hotspot::doGet(HotspotData *hotspot) { void Hotspot::doOperate(HotspotData *hotspot, Action action) { Resources &res = Resources::getReference(); + + HotspotPrecheckResult result = actionPrecheck(hotspot); + if (result == PC_INITIAL) return; + else if (result != PC_EXECUTE) { + stopWalking(); + return; + } + + _actionCtr = 0; + faceHotspot(hotspot); + stopWalking(); + uint16 sequenceOffset = res.getHotspotAction(hotspot->actionsOffset, action); if (sequenceOffset >= 0x8000) { Dialog::showMessage(sequenceOffset, hotspotId()); - } else if (sequenceOffset != 0) { - uint16 result = Script::execute(sequenceOffset); - if (result > 1) - Dialog::showMessage(result, hotspotId()); + } else { + sequenceOffset = Script::execute(sequenceOffset); + if (sequenceOffset > 1) + Dialog::showMessage(sequenceOffset, hotspotId()); } } @@ -665,33 +740,47 @@ void Hotspot::doOpen(HotspotData *hotspot) { if (!joinRec->blocked) { // Room exit is already open Dialog::showMessage(4, hotspotId()); - // TODO: jmp loc_1102 + stopWalking(); return; } } - // TODO: Call to sub_107 and checking the results, then sub_110 + HotspotPrecheckResult result = actionPrecheck(hotspot); + if (result == PC_INITIAL) return; + else if (result != PC_EXECUTE) { + stopWalking(); + return; + } + + faceHotspot(hotspot); + _actionCtr = 0; + stopWalking(); uint16 sequenceOffset = res.getHotspotAction(hotspot->actionsOffset, OPEN); + if (sequenceOffset >= 0x8000) { // Message to display Dialog::showMessage(sequenceOffset, hotspotId()); - } else if (sequenceOffset != 0) { - // Otherwise handle script - uint16 result = Script::execute(sequenceOffset); + return; + } - if (result == 0) { - joinRec = res.getExitJoin(hotspot->hotspotId); - if (joinRec->blocked) { - joinRec->blocked = 0; + if (sequenceOffset != 0) { + sequenceOffset = Script::execute(sequenceOffset); - if (hotspotId() != PLAYER_ID) { - // TODO: HS[44h]=3, HS[42h]W = 4 - } - } - } else if (result != 1) { - // TODO: Figure out: if Hotspot-rec[60h] != 0, then set = 4 - Dialog::showMessage(result, hotspotId()); + if (sequenceOffset == 1) return; + if (sequenceOffset != 0) { + // TODO: HS[60h] check + Dialog::showMessage(sequenceOffset, hotspotId()); + return; + } + } + + joinRec = res.getExitJoin(hotspot->hotspotId); + if (joinRec->blocked) { + joinRec->blocked = 0; + + if (hotspotId() != PLAYER_ID) { + // TODO: HS[44h]=3, HS[42h]W = 4 } } } @@ -705,12 +794,21 @@ void Hotspot::doClose(HotspotData *hotspot) { if (joinRec->blocked) { // Room exit is already closed/blocked Dialog::showMessage(3, hotspotId()); - // TODO: jmp sub_129 + stopWalking(); return; } } - // TODO: Call to sub_107 and checking the results, then sub_110 + HotspotPrecheckResult result = actionPrecheck(hotspot); + if (result == PC_INITIAL) return; + else if (result != PC_EXECUTE) { + stopWalking(); + return; + } + + faceHotspot(hotspot); + _actionCtr = 0; + stopWalking(); uint16 sequenceOffset = res.getHotspotAction(hotspot->actionsOffset, CLOSE); @@ -719,30 +817,55 @@ void Hotspot::doClose(HotspotData *hotspot) { Dialog::showMessage(sequenceOffset, hotspotId()); } else if (sequenceOffset != 0) { // Otherwise handle script - uint16 result = Script::execute(sequenceOffset); + sequenceOffset = Script::execute(sequenceOffset); - if (result != 0) { - Dialog::showMessage(result, hotspotId()); + if (sequenceOffset != 0) { + Dialog::showMessage(sequenceOffset, hotspotId()); + return; + } + } + + joinRec = res.getExitJoin(hotspot->hotspotId); + if (!joinRec->blocked) { + // Close the door + if (!doorCloseCheck(joinRec->hotspot1Id) || + !doorCloseCheck(joinRec->hotspot2Id)) { + // A character is preventing the door from closing + Dialog::showMessage(2, hotspotId()); } else { - joinRec = res.getExitJoin(hotspot->hotspotId); - if (!joinRec->blocked) { - // Close the door - // TODO: Decode sub_183 - does check to see if door is 'jammed', but - // a cursory inspection seems to indicate that the routine is more - // concerned with checking if any character is blocking the door -// if (!sub183(joinRec->0Dh) || !sub183(joinRec->0Fh)) { -// Dialog::showMessage(2, hotspotId()); -// } else { - joinRec->blocked = 1; -// } - } + // Flag the door as closed + joinRec->blocked = 1; } } } void Hotspot::doUse(HotspotData *hotspot) { Resources &res = Resources::getReference(); -// uint16 usedId = res.fieldList().getField(USE_HOTSPOT_ID); + uint16 usedId = _currentActions.top().usedId(); + HotspotData *usedHotspot = res.getHotspot(usedId); + ValueTableData &fields = res.fieldList(); + fields.setField(ACTIVE_HOTSPOT_ID, hotspot->hotspotId); + fields.setField(USE_HOTSPOT_ID, usedHotspot->hotspotId); + + if (usedHotspot->roomNumber != hotspotId()) { + // Item to be used is not in character's inventory - say "What???" + stopWalking(); + Dialog::showMessage(0xF, hotspotId()); + return; + } + + HotspotPrecheckResult result = actionPrecheck(hotspot); + if (result == PC_INITIAL) return; + else if (result != PC_EXECUTE) { + stopWalking(); + return; + } + + faceHotspot(hotspot); + stopWalking(); + + // TODO: If character=3E9h, HS[-1]=28h, HS[1Fh]=50h + uint16 sequenceOffset = res.getHotspotAction(hotspot->actionsOffset, USE); if (sequenceOffset >= 0x8000) { @@ -750,59 +873,97 @@ void Hotspot::doUse(HotspotData *hotspot) { } else if (sequenceOffset == 0) { Dialog::showMessage(17, hotspotId()); } else { - uint16 result = Script::execute(sequenceOffset); - if (result != 0) - Dialog::showMessage(result, hotspotId()); + sequenceOffset = Script::execute(sequenceOffset); + if (sequenceOffset != 0) + Dialog::showMessage(sequenceOffset, hotspotId()); } } void Hotspot::doGive(HotspotData *hotspot) { Resources &res = Resources::getReference(); - uint16 usedId = res.fieldList().getField(USE_HOTSPOT_ID); + uint16 usedId = _currentActions.top().usedId(); + HotspotData *usedHotspot = res.getHotspot(usedId); + ValueTableData &fields = res.fieldList(); + fields.setField(ACTIVE_HOTSPOT_ID, hotspot->hotspotId); + fields.setField(USE_HOTSPOT_ID, usedId); + + if (usedHotspot->roomNumber != hotspotId()) { + // Item to be used is not in character's inventory - say "What???" + stopWalking(); + Dialog::showMessage(0xF, hotspotId()); + return; + } + + HotspotPrecheckResult result = actionPrecheck(hotspot); + if (result == PC_INITIAL) return; + else if (result != PC_EXECUTE) { + stopWalking(); + return; + } + + faceHotspot(hotspot); + stopWalking(); + + if ((hotspotId() != 0x412) || (usedId != 0x2710)) + Dialog::showMessage(7, hotspotId()); + uint16 sequenceOffset = res.getHotspotAction(hotspot->actionsOffset, GIVE); if (sequenceOffset >= 0x8000) { Dialog::showMessage(sequenceOffset, hotspotId()); - } else { - uint16 result = Script::execute(sequenceOffset); - if (result == 0x3E7) { + } else if (sequenceOffset != 0) { + sequenceOffset = Script::execute(sequenceOffset); + if (sequenceOffset == NOONE_ID) { // TODO - } else if (result == 0) { + } else if (sequenceOffset == 0) { // Move item into character's inventory HotspotData *usedItem = res.getHotspot(usedId); usedItem->roomNumber = hotspotId(); - } else if (result > 1) { - // TODO + } else if (sequenceOffset > 1) { + Dialog::showMessage(result, hotspotId()); } } } void Hotspot::doTalkTo(HotspotData *hotspot) { - // TODO: still some work at start - if ((hotspot->hotspotId != 0x3EA) && ((hotspot->roomNumber != 28) || + Resources &res = Resources::getReference(); + uint16 usedId = _currentActions.top().usedId(); + ValueTableData &fields = res.fieldList(); + fields.setField(ACTIVE_HOTSPOT_ID, hotspot->hotspotId); + fields.setField(USE_HOTSPOT_ID, usedId); + + if ((hotspot->hotspotId != SKORL_ID) && ((hotspot->roomNumber != 28) || (hotspot->hotspotId != 0x3EB))) { - // sub_107 call and after check + + HotspotPrecheckResult result = actionPrecheck(hotspot); + if (result == PC_INITIAL) return; + else if (result != PC_EXECUTE) { + stopWalking(); + return; + } } - // Validate character is in player's room - since currently you can activate - // hotspots when you're not in the room - if (hotspot->roomNumber != hotspot->roomNumber) return; + faceHotspot(hotspot); + stopWalking(); - Resources &res = Resources::getReference(); uint16 sequenceOffset = res.getHotspotAction(hotspot->actionsOffset, TALK_TO); if (sequenceOffset >= 0x8000) { Dialog::showMessage(sequenceOffset, hotspotId()); - } else if (sequenceOffset == 0) { - startTalk(hotspot); - } else { + return; + } + + if (sequenceOffset != 0) { uint16 result = Script::execute(sequenceOffset); - if (result == 0) { - // Start talking with character - startTalk(hotspot); + if (result != 0) { + stopWalking(); + return; } } + + // Start talking with character + startTalk(hotspot); } void Hotspot::doTell(HotspotData *hotspot) { @@ -810,13 +971,74 @@ void Hotspot::doTell(HotspotData *hotspot) { } void Hotspot::doLook() { + stopWalking(); Dialog::show(Room::getReference().descId()); } +uint16 hotspotLookAtList[] = {0x411, 0x412, 0x41F, 0x420, 0x421, 0x422, 0x426, + 0x427, 0x428, 0x429, 0x436, 0x437, 0}; + void Hotspot::doLookAt(HotspotData *hotspot) { Resources &res = Resources::getReference(); uint16 sequenceOffset = res.getHotspotAction(hotspot->actionsOffset, LOOK_AT); - + + if (hotspot->hotspotId >= FIRST_NONCHARACTER_ID) { + // Check if the hotspot appears in the list of hotspots that don't + // need to be walked to before being looked at + uint16 *tempId = &hotspotLookAtList[0]; + while ((*tempId != 0) && (*tempId != hotspot->hotspotId)) ++tempId; + if (!*tempId) { + // Hotspot wasn't in the list + HotspotPrecheckResult result = actionPrecheck(hotspot); + if (result == PC_INITIAL) return; + else if (result != PC_EXECUTE) { + stopWalking(); + return; + } + } + } + + faceHotspot(hotspot); + _actionCtr = 0; + stopWalking(); + + if (sequenceOffset >= 0x8000) { + Dialog::showMessage(sequenceOffset, hotspotId()); + } else { + if (sequenceOffset != 0) + sequenceOffset = Script::execute(sequenceOffset); + + if (sequenceOffset == 0) { + uint16 descId = (hotspot->descId2 != 0) ? hotspot->descId2 : hotspot->descId; + Dialog::show(descId); + } + } +} + +void Hotspot::doLookThrough(HotspotData *hotspot) { + Resources &res = Resources::getReference(); + uint16 sequenceOffset = res.getHotspotAction(hotspot->actionsOffset, LOOK_THROUGH); + + if (hotspot->hotspotId >= FIRST_NONCHARACTER_ID) { + // Check if the hotspot appears in the list of hotspots that don't + // need to be walked to before being looked at + uint16 *tempId = &hotspotLookAtList[0]; + while ((*tempId != 0) && (*tempId != hotspot->hotspotId)) ++tempId; + if (!*tempId) { + // Hotspot wasn't in the list + HotspotPrecheckResult result = actionPrecheck(hotspot); + if (result == PC_INITIAL) return; + else if (result != PC_EXECUTE) { + stopWalking(); + return; + } + } + } + + faceHotspot(hotspot); + _actionCtr = 0; + stopWalking(); + if (sequenceOffset >= 0x8000) { Dialog::showMessage(sequenceOffset, hotspotId()); } else { @@ -834,10 +1056,19 @@ void Hotspot::doAsk(HotspotData *hotspot) { // TODO } -void Hotspot::doDrink() { +void Hotspot::doDrink(HotspotData *hotspot) { Resources &res = Resources::getReference(); - uint16 usedId = res.fieldList().getField(USE_HOTSPOT_ID); - HotspotData *hotspot = res.getHotspot(usedId); + ValueTableData &fields = res.fieldList(); + fields.setField(ACTIVE_HOTSPOT_ID, hotspot->hotspotId); + fields.setField(USE_HOTSPOT_ID, hotspot->hotspotId); + + // Make sure item is in character's inventory + if (hotspot->hotspotId != hotspotId()) { + Dialog::showMessage(0xF, hotspotId()); + return; + } + + stopWalking(); uint16 sequenceOffset = res.getHotspotAction(hotspot->actionsOffset, DRINK); if (sequenceOffset >= 0x8000) { @@ -864,6 +1095,10 @@ void Hotspot::doStatus() { StringData &strings = StringData::getReference(); Resources &resources = Resources::getReference(); Room &room = Room::getReference(); +warning("status0 %d %d", room.cursorState(), resources.getCurrentAction()); + + room.update(); + stopWalking(); strings.getString(room.roomNumber(), buffer, NULL, NULL); strcat(buffer, "\n\nYou are carrying "); @@ -880,7 +1115,7 @@ void Hotspot::doStatus() { strings.getString(rec->nameId, buffer + strlen(buffer), NULL, NULL); } } - +warning("status1 %d", room.cursorState()); // If there were no items, add in the word 'nothing' if (numItems == 0) strcat(buffer, "nothing."); @@ -895,25 +1130,67 @@ void Hotspot::doStatus() { Screen &screen = Screen::getReference(); Mouse &mouse = Mouse::getReference(); mouse.cursorOff(); - +warning("status2 %d", room.cursorState()); Surface *s = Surface::newDialog(INFO_DIALOG_WIDTH, buffer); s->copyToScreen(INFO_DIALOG_X, (FULL_SCREEN_HEIGHT-s->height())/2); - +warning("status3"); Events::getReference().waitForPress(); +warning("status4"); screen.update(); mouse.cursorOn(); } +uint16 bribe_hotspot_list[] = {0x421, 0x879, 0x3E9, 0x8C7, 0x429, 0x8D1, + 0x422, 0x8D4, 0x420, 0x8D6, 0x42B, 0x956, 0x3F2, 0xBE6, 0}; + void Hotspot::doBribe(HotspotData *hotspot) { - Dialog::show("Yet to do"); + Resources &res = Resources::getReference(); + ValueTableData &fields = res.fieldList(); + fields.setField(ACTIVE_HOTSPOT_ID, hotspot->hotspotId); + fields.setField(USE_HOTSPOT_ID, hotspot->hotspotId); + + HotspotPrecheckResult result = actionPrecheck(hotspot); + if (result == PC_INITIAL) return; + else if (result != PC_EXECUTE) { + stopWalking(); + return; + } + + uint16 *tempId = &bribe_hotspot_list[0]; + uint16 sequenceOffset = 0x14B; // Default sequence offset + while (*tempId != 0) { + if (*tempId++ == hotspotId()) { + sequenceOffset = *tempId; + if ((sequenceOffset & 0x8000) != 0) + sequenceOffset = Script::execute(sequenceOffset & 0x7fff); + break; + } + ++tempId; // Move over entry's sequence offset + } + + // TODO: call to talk_setup + faceHotspot(hotspot); + _actionCtr = 0; + stopWalking(); + + sequenceOffset = res.getHotspotAction(hotspot->actionsOffset, BRIBE); + if (sequenceOffset != 0) { + sequenceOffset = Script::execute(sequenceOffset); + if (sequenceOffset != 0) return; + } + + // TODO: handle character message display } -void Hotspot::doExamine() { +void Hotspot::doExamine(HotspotData *hotspot) { Resources &res = Resources::getReference(); - uint16 usedId = res.fieldList().getField(USE_HOTSPOT_ID); - HotspotData *hotspot = res.getHotspot(usedId); + ValueTableData &fields = res.fieldList(); + fields.setField(ACTIVE_HOTSPOT_ID, hotspot->hotspotId); + fields.setField(USE_HOTSPOT_ID, hotspot->hotspotId); + + stopWalking(); uint16 sequenceOffset = res.getHotspotAction(hotspot->actionsOffset, EXAMINE); - + if (sequenceOffset >= 0x8000) { Dialog::showMessage(sequenceOffset, hotspotId()); } else { @@ -926,6 +1203,33 @@ void Hotspot::doExamine() { } } +void Hotspot::doLockUnlock(HotspotData *hotspot) { + Action action = _currentActions.top().hotspotAction(); + Resources &res = Resources::getReference(); + ValueTableData &fields = res.fieldList(); + fields.setField(ACTIVE_HOTSPOT_ID, hotspot->hotspotId); + fields.setField(USE_HOTSPOT_ID, hotspot->hotspotId); + + HotspotPrecheckResult result = actionPrecheck(hotspot); + if (result == PC_INITIAL) return; + else if (result != PC_EXECUTE) { + stopWalking(); + return; + } + + faceHotspot(hotspot); + stopWalking(); + + uint16 sequenceOffset = res.getHotspotAction(hotspot->actionsOffset, action); + + if (sequenceOffset >= 0x8000) { + Dialog::showMessage(sequenceOffset, hotspotId()); + } else { + if (sequenceOffset != 0) + Script::execute(sequenceOffset); + } +} + void Hotspot::doSimple(HotspotData *hotspot, Action action) { Resources &res = Resources::getReference(); uint16 sequenceOffset = res.getHotspotAction(hotspot->actionsOffset, action); @@ -1016,18 +1320,21 @@ void HotspotTickHandlers::roomExitAnimHandler(Hotspot &h) { } if ((rec->blocked != 0) && (*currentFrame != *destFrame)) { - // sub_178 + // Closing the door + h.setOccupied(true); ++*currentFrame; - if (*currentFrame != *destFrame) { - // cx=1 => sub_184 + if (*currentFrame == *destFrame) { + // TODO: play closed door sound } } else if ((rec->blocked == 0) && (*currentFrame != 0)) { - // sub_179 + // Opening the door + h.setOccupied(false); + + --*currentFrame; if (*currentFrame == *destFrame) { - // sub_184 and other stuff TODO + //TODO: Check against script val 88 and play sound } - --*currentFrame; } h.setFrameNumber(*currentFrame); @@ -1073,9 +1380,7 @@ void HotspotTickHandlers::playerAnimHandler(Hotspot &h) { h.setDestHotspot(0); hsAction = actions.top().hotspotAction(); hotspotId = actions.top().hotspotId(); - actions.pop(); - - hotspot = res.getHotspot(hotspotId); + hotspot = (hotspotId == 0) ? NULL : res.getHotspot(hotspotId); h.doAction(hsAction, hotspot); break; @@ -1089,7 +1394,7 @@ void HotspotTickHandlers::playerAnimHandler(Hotspot &h) { case START_WALKING: // Start the player walking to the given destination - h.setOccupied(false); // clear pathfinding area + h.setOccupied(false); // Reset the path finder / walking sequence pathFinder.reset(paths); @@ -1131,7 +1436,7 @@ void HotspotTickHandlers::playerAnimHandler(Hotspot &h) { if (h.walkingStep()) { // Walking done - actions.pop(); + h.currentActions().pop(); } // Check for whether need to change room @@ -1741,7 +2046,7 @@ int Support::findIntersectingCharacters(Hotspot &h, uint16 *charList) { // Check for basic reasons to skip checking the animation if ((h.hotspotId() == hotspot.hotspotId()) || (hotspot.layer() == 0) || - (h.roomNumber() != hotspot.roomNumber()) || (h.hotspotId() >= 0x408) || + (h.roomNumber() != hotspot.roomNumber()) || (h.hotspotId() >= FIRST_NONCHARACTER_ID) || h.skipFlag()) continue; // TODO: See why si+ANIM_HOTSPOT_OFFSET compared aganst di+ANIM_VOICE_CTR diff --git a/engines/lure/hotspots.h b/engines/lure/hotspots.h index 01949d75ca..f53223c643 100644 --- a/engines/lure/hotspots.h +++ b/engines/lure/hotspots.h @@ -71,6 +71,7 @@ private: CurrentAction _action; Action _hotspotAction; uint16 _hotspotId; + uint16 _usedId; public: CurrentActionEntry(CurrentAction newAction) { _action = newAction; } CurrentActionEntry(CurrentAction newAction, Action hsAction, uint16 id) { @@ -78,10 +79,17 @@ public: _hotspotAction = hsAction; _hotspotId = id; } + CurrentActionEntry(CurrentAction newAction, Action hsAction, uint16 id, uint16 uId) { + _action = newAction; + _hotspotAction = hsAction; + _hotspotId = id; + _usedId = uId; + } CurrentAction action() { return _action; } Action hotspotAction() { return _hotspotAction; } uint16 hotspotId() { return _hotspotId; } + uint16 usedId() { return _usedId; } }; class CurrentActionStack { @@ -95,9 +103,21 @@ public: CurrentActionEntry &top() { return **_actions.begin(); } CurrentAction action() { return isEmpty() ? NO_ACTION : top().action(); } void pop() { _actions.erase(_actions.begin()); } - void add(CurrentAction newAction) { + void addBack(CurrentAction newAction) { _actions.push_back(new CurrentActionEntry(newAction)); } + void addBack(CurrentAction newAction, Action hsAction, uint16 id) { + _actions.push_back(new CurrentActionEntry(newAction, hsAction, id)); + } + void addFront(CurrentAction newAction) { + _actions.push_front(new CurrentActionEntry(newAction)); + } + void addFront(CurrentAction newAction, Action hsAction, uint16 id) { + _actions.push_front(new CurrentActionEntry(newAction, hsAction, id)); + } + void addFront(CurrentAction newAction, Action hsAction, uint16 id, uint16 usedId) { + _actions.push_front(new CurrentActionEntry(newAction, hsAction, id, usedId)); + } }; class WalkingActionEntry { @@ -156,7 +176,7 @@ public: int &stepCtr() { return _stepCtr; } }; -enum HotspotPrecheckResult {PC_0, PC_1, PC_2, PC_INITIAL, PC_4}; +enum HotspotPrecheckResult {PC_EXECUTE, PC_NOT_IN_ROOM, PC_UNKNOWN, PC_INITIAL, PC_EXCESS}; class Hotspot { private: @@ -183,12 +203,12 @@ private: bool _persistant; HotspotOverrideData *_override; bool _skipFlag; - bool _pathfindCovered; CurrentActionStack _currentActions; PathFinder _pathFinder; uint16 _frameCtr; + uint8 _actionCtr; int16 _destX, _destY; uint16 _destHotspotId; @@ -200,6 +220,7 @@ private: HotspotPrecheckResult actionPrecheck2(HotspotData *hotspot); void actionPrecheck3(HotspotData *hotspot); bool characterWalkingCheck(HotspotData *hotspot); + bool doorCloseCheck(uint16 doorId); // Action set void doGet(HotspotData *hotspot); @@ -213,11 +234,12 @@ private: void doTell(HotspotData *hotspot); void doLook(); void doLookAt(HotspotData *hotspot); + void doLookThrough(HotspotData *hotspot); void doAsk(HotspotData *hotspot); - void doDrink(); + void doDrink(HotspotData *hotspot); void doStatus(); void doBribe(HotspotData *hotspot); - void doExamine(); + void doExamine(HotspotData *hotspot); void doSimple(HotspotData *hotspot, Action action); public: Hotspot(HotspotData *res); @@ -283,7 +305,7 @@ public: // Walking void walkTo(int16 endPosX, int16 endPosY, uint16 destHotspot = 0); - void stopWalking() { _currentActions.clear(); } + void stopWalking(); void setDirection(Direction dir); void faceHotspot(HotspotData *hotspot); void setOccupied(bool occupiedFlag); @@ -291,12 +313,22 @@ public: // Actions void doAction(Action action, HotspotData *hotspot); - void setCurrentAction(CurrentAction currAction) { _currentActions.add(currAction); } + void setCurrentAction(CurrentAction currAction) { + _currentActions.addFront(currAction); + } + void setCurrentAction(CurrentAction currAction, Action hsAction, uint16 id) { + _currentActions.addFront(currAction, hsAction, id); + } + void setCurrentAction(CurrentAction currAction, Action hsAction, uint16 id, uint16 usedId) { + _currentActions.addFront(currAction, hsAction, id, usedId); + } CurrentActionStack ¤tActions() { return _currentActions; } PathFinder &pathFinder() { return _pathFinder; } uint16 frameCtr() { return _frameCtr; } void setFrameCtr(uint16 value) { _frameCtr = value; } void decrFrameCtr() { if (_frameCtr > 0) --_frameCtr; } + uint8 actionCtr() { return _actionCtr; } + void setActionCtr(uint8 v) { _actionCtr = v; } }; typedef ManagedList HotspotList; -- cgit v1.2.3