aboutsummaryrefslogtreecommitdiff
path: root/engines/lure/hotspots.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'engines/lure/hotspots.cpp')
-rw-r--r--engines/lure/hotspots.cpp407
1 files changed, 279 insertions, 128 deletions
diff --git a/engines/lure/hotspots.cpp b/engines/lure/hotspots.cpp
index 2944091f4f..f3b1c01d3d 100644
--- a/engines/lure/hotspots.cpp
+++ b/engines/lure/hotspots.cpp
@@ -62,9 +62,8 @@ Hotspot::Hotspot(HotspotData *res): _pathFinder(this) {
_talkX = res->talkX;
_talkY = res->talkY;
_layer = res->layer;
- _sequenceOffset = res->sequenceOffset;
+ _hotspotScriptOffset = res->hotspotScriptOffset;
_tickCtr = res->tickTimeout;
- _actions = res->actions;
_colourOffset = res->colourOffset;
_override = resources.getHotspotOverride(res->hotspotId);
@@ -405,7 +404,7 @@ void Hotspot::setSize(uint16 newWidth, uint16 newHeight) {
}
bool Hotspot::executeScript() {
- if (_data->sequenceOffset == 0xffff)
+ if (_data->hotspotScriptOffset == 0xffff)
return false;
else
return HotspotScript::execute(this);
@@ -478,7 +477,8 @@ void Hotspot::setDirection(Direction dir) {
_charRectY = 0;
break;
default:
- break;
+ // No need to change
+ return;
}
setFrameNumber(newFrameNumber);
@@ -488,14 +488,26 @@ void Hotspot::setDirection(Direction dir) {
// Makes the character face the given hotspot
void Hotspot::faceHotspot(HotspotData *hotspot) {
+ Resources &res = Resources::getReference();
+ Room &room = Room::getReference();
+ Screen &screen = Screen::getReference();
+
if (hotspot->hotspotId >= START_NONVISUAL_HOTSPOT_ID) {
// Non visual hotspot
setDirection(hotspot->nonVisualDirection());
} else {
// Visual hotspot
- int xp = x() - hotspot->startX;
- int yp = y() + heightCopy() - (hotspot->startY + hotspot->heightCopy);
+ int xp, yp;
+
+ HotspotOverrideData *hsEntry = res.getHotspotOverride(hotspot->hotspotId);
+ if (hsEntry != NULL) {
+ xp = x() - hsEntry->xs;
+ yp = y() + heightCopy() - (hsEntry->ys + hotspot->heightCopy);
+ } else {
+ xp = x() - hotspot->startX;
+ yp = y() + heightCopy() - (hotspot->startY + hotspot->heightCopy);
+ }
if (ABS(yp) >= ABS(xp)) {
if (yp < 0) setDirection(DOWN);
@@ -507,8 +519,8 @@ void Hotspot::faceHotspot(HotspotData *hotspot) {
}
if (hotspotId() == PLAYER_ID) {
- Room::getReference().update();
- Screen::getReference().update();
+ room.update();
+ screen.update();
}
}
@@ -525,7 +537,6 @@ void Hotspot::setRandomDest() {
RoomData *roomData = res.getRoom(roomNumber());
Common::Rect &rect = roomData->walkBounds;
Common::RandomSource rnd;
- int tryCtr = 0;
int16 xp, yp;
if (_currentActions.isEmpty())
@@ -534,13 +545,15 @@ void Hotspot::setRandomDest() {
_currentActions.top().setAction(START_WALKING);
_walkFlag = true;
- while (tryCtr ++ <= 20) {
+ // Try up to 20 times to find an unoccupied destination
+ for (int tryCtr = 0; tryCtr < 20; ++tryCtr) {
xp = rect.left + rnd.getRandomNumber(rect.right - rect.left);
- yp = rect.left + rnd.getRandomNumber(rect.right - rect.left);
+ yp = rect.top + rnd.getRandomNumber(rect.bottom - rect.top);
setDestPosition(xp, yp);
setDestHotspot(0);
- if (!roomData->paths.isOccupied(xp, yp) && !roomData->paths.isOccupied(xp, yp))
+ // Check if three sequential blocks at chosen destination are unoccupied
+ if (!roomData->paths.isOccupied(xp, yp, 3))
break;
}
}
@@ -555,7 +568,7 @@ void Hotspot::setOccupied(bool occupiedFlag) {
int xp = x() >> 3;
int yp = (y() - 8 + heightCopy() - 4) >> 3;
- int widthVal = MAX((widthCopy() >> 3), 1);
+ int widthVal = MAX(widthCopy() >> 3, 1);
// Handle cropping for screen left
if (xp < 0) {
@@ -660,12 +673,15 @@ void Hotspot::converse(uint16 destCharacterId, uint16 messageId, bool standStill
// in case the destination is already in process of talking
HotspotData *hotspot = Resources::getReference().getHotspot(destCharacterId);
_data->talkCountdown += hotspot->talkCountdown;
+
+ _data->talkDestCharacterId = destCharacterId;
+ _data->talkGate = 0;
}
if (standStill) {
setDelayCtr(_data->talkCountdown);
_data->characterMode = CHARMODE_CONVERSING;
- //TODO: HS[3Eh]=use_hotspot_id, HS[40h]=active_hotspot_id
+ //TODO: HS[3Eh]=character_hotspot_id, HS[40h]=active_hotspot_id
}
}
@@ -766,7 +782,8 @@ void Hotspot::handleTalkDialog() {
// Talking is finish - stop talking and free voice animation
debugC(ERROR_DETAILED, kLureDebugAnimations, "Talk dialog close");
room.setTalkDialog(0, 0, 0, 0);
- res.setTalkingCharacter(0);
+ _data->talkDestCharacterId = 0;
+ _data->talkGate = 0;
}
debugC(ERROR_DETAILED, kLureDebugAnimations, "Talk handler method end");
@@ -817,7 +834,7 @@ HotspotPrecheckResult Hotspot::actionPrecheck(HotspotData *hotspot) {
if (actionCtr() >= 6) {
warning("actionCtr exceeded");
setActionCtr(0);
- converse(0, 0xD);
+ converse(NOONE_ID, 0xD);
return PC_EXCESS;
}
@@ -831,11 +848,12 @@ HotspotPrecheckResult Hotspot::actionPrecheck(HotspotData *hotspot) {
} else {
// loc_886
setActionCtr(0);
- converse(0, 0xE);
+ showMessage(14, NOONE_ID);
return PC_FAILED;
}
} else {
setActionCtr(1);
+
if ((hotspot->hotspotId >= FIRST_NONCHARACTER_ID) ||
((hotspot->actionHotspotId != _hotspotId) &&
(hotspot->characterMode == CHARMODE_WAIT_FOR_PLAYER))) {
@@ -844,15 +862,14 @@ HotspotPrecheckResult Hotspot::actionPrecheck(HotspotData *hotspot) {
return PC_WAIT;
} else if (hotspot->actionHotspotId != _hotspotId) {
- if (fields.getField(88) == 2) {
- // loc_882
- hotspot->v2b = 0x2A;
- hotspot->useHotspotId = _hotspotId;
- return PC_WAIT;
- } else {
- converse(NOONE_ID, 5);
+ if (fields.getField(82) != 2) {
+ showMessage(5, hotspot->hotspotId);
setDelayCtr(4);
}
+
+ hotspot->talkGate = 0x2A;
+ hotspot->talkDestCharacterId = _hotspotId;
+ return PC_WAIT;
}
}
@@ -1017,15 +1034,16 @@ bool Hotspot::doorCloseCheck(uint16 doorId) {
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;
- }
+ // Check to see if the character is intersecting the door area
+ int tempY = hsCurrent->y() + hsCurrent->heightCopy();
+ if ((hsCurrent->x() >= bounds.right) ||
+ (hsCurrent->x() + hsCurrent->widthCopy() <= bounds.left) ||
+ (tempY + hsCurrent->charRectY() < bounds.top) ||
+ (tempY - hsCurrent->yCorrection() - hsCurrent->charRectY() > bounds.bottom))
+ continue;
+
+ // At this point we know a character is blocking door, so return false
+ return false;
}
// No blocking characters, so return true that the door can be closed
@@ -1087,7 +1105,7 @@ void Hotspot::doAction(Action action, HotspotData *hotspot) {
&Hotspot::npcSetSupportOffset,
&Hotspot::npcSupportOffsetConditional,
&Hotspot::npcDispatchAction,
- &Hotspot::npcUnknown3,
+ &Hotspot::npcTalkNpcToNpc,
&Hotspot::npcPause,
&Hotspot::npcStartTalking,
&Hotspot::npcJumpAddress};
@@ -1350,7 +1368,7 @@ void Hotspot::doGive(HotspotData *hotspot) {
endAction();
if ((hotspot->hotspotId != PRISONER_ID) || (usedId != BOTTLE_HOTSPOT_ID))
- showMessage(7);
+ showMessage(7, hotspot->hotspotId);
uint16 sequenceOffset = res.getHotspotAction(hotspot->actionsOffset, GIVE);
@@ -1367,7 +1385,7 @@ void Hotspot::doGive(HotspotData *hotspot) {
} else if (sequenceOffset == 0) {
// Move item into character's inventory
HotspotData *usedItem = res.getHotspot(usedId);
- usedItem->roomNumber = hotspotId();
+ usedItem->roomNumber = hotspot->hotspotId;
} else if (sequenceOffset > 1) {
showMessage(result);
}
@@ -1381,7 +1399,7 @@ void Hotspot::doTalkTo(HotspotData *hotspot) {
fields.setField(USE_HOTSPOT_ID, hotspot->hotspotId);
if ((hotspot->hotspotId != SKORL_ID) && ((hotspot->roomNumber != 28) ||
- (hotspot->hotspotId != 0x3EB))) {
+ (hotspot->hotspotId != BLACKSMITH_ID))) {
HotspotPrecheckResult result = actionPrecheck(hotspot);
if (result == PC_WAIT) return;
@@ -1889,8 +1907,38 @@ void Hotspot::npcDispatchAction(HotspotData *hotspot) {
}
}
-void Hotspot::npcUnknown3(HotspotData *hotspot) {
- warning("npcUnknown3: Not yet implemented");
+void Hotspot::npcTalkNpcToNpc(HotspotData *hotspot) {
+ Resources &res = Resources::getReference();
+ ValueTableData &fields = res.fieldList();
+ CharacterScheduleEntry &entry = _currentActions.top().supportData();
+ fields.setField(ACTIVE_HOTSPOT_ID, hotspot->hotspotId);
+ fields.setField(USE_HOTSPOT_ID, hotspot->hotspotId);
+
+ HotspotPrecheckResult result = actionPrecheck(hotspot);
+ if (result == PC_WAIT) return;
+ else if (result != PC_EXECUTE) {
+ endAction();
+ return;
+ }
+
+ // If dest is already talking, keep exiting until they're free
+ if (hotspot->talkCountdown != 0)
+ return;
+
+ // Handle the source's talk message
+ if (entry.param(1) != 0) {
+ converse(hotspot->hotspotId, entry.param(1));
+ resource()->talkCountdown += entry.param(2);
+ resource()->delayCtr = entry.param(2);
+ }
+
+ // Handle the destination's response message
+ if (entry.param(3) != 0) {
+ Hotspot *destHotspot = res.getActiveHotspot(hotspot->hotspotId);
+ assert(destHotspot);
+ destHotspot->converse(this->hotspotId(), entry.param(3));
+ }
+
endAction();
}
@@ -1977,6 +2025,7 @@ void Hotspot::startTalk(HotspotData *charHotspot, uint16 id) {
// Signal the character that they're being talked to
charHotspot->talkDestCharacterId = _hotspotId;
_data->talkDestCharacterId = charHotspot->hotspotId;
+ _data->talkGate = 0;
// Set the active talk data
res.setTalkStartEntry(0);
@@ -1995,6 +2044,7 @@ void Hotspot::saveToStream(Common::WriteStream *stream) {
stream->writeSint16LE(_startY);
stream->writeSint16LE(_destX);
stream->writeSint16LE(_destY);
+ stream->writeUint16LE(_destHotspotId);
stream->writeUint16LE(_frameWidth);
stream->writeUint16LE(_height);
stream->writeUint16LE(_width);
@@ -2004,9 +2054,8 @@ void Hotspot::saveToStream(Common::WriteStream *stream) {
stream->writeUint16LE(_talkX);
stream->writeUint16LE(_talkY);
stream->writeByte(_layer);
- stream->writeUint16LE(_sequenceOffset);
+ stream->writeUint16LE(_hotspotScriptOffset);
stream->writeUint16LE(_tickCtr);
- stream->writeUint32LE(_actions);
stream->writeByte(_colourOffset);
stream->writeUint16LE(_animId);
stream->writeUint16LE(_frameNumber);
@@ -2031,6 +2080,7 @@ void Hotspot::loadFromStream(Common::ReadStream *stream) {
_startY = stream->readSint16LE();
_destX = stream->readSint16LE();
_destY = stream->readSint16LE();
+ _destHotspotId = stream->readUint16LE();
_frameWidth = stream->readUint16LE();
_height = stream->readUint16LE();
_width = stream->readUint16LE();
@@ -2040,9 +2090,8 @@ void Hotspot::loadFromStream(Common::ReadStream *stream) {
_talkX = stream->readUint16LE();
_talkY = stream->readUint16LE();
_layer = stream->readByte();
- _sequenceOffset = stream->readUint16LE();
+ _hotspotScriptOffset = stream->readUint16LE();
_tickCtr = stream->readUint16LE();
- _actions = stream->readUint32LE();
_colourOffset = stream->readByte();
setAnimation(stream->readUint16LE());
setFrameNumber(stream->readUint16LE());
@@ -2062,6 +2111,9 @@ void Hotspot::loadFromStream(Common::ReadStream *stream) {
HandlerMethodPtr HotspotTickHandlers::getHandler(uint16 procOffset) {
switch (procOffset) {
+ case 0:
+ case 0x41BD:
+ return defaultHandler;
case STANDARD_CHARACTER_TICK_PROC:
return standardCharacterAnimHandler;
case VOICE_TICK_PROC_ID:
@@ -2076,16 +2128,22 @@ HandlerMethodPtr HotspotTickHandlers::getHandler(uint16 procOffset) {
return followerAnimHandler;
case 0x7EFA:
return skorlAnimHandler;
- case 0x7F37:
+ case STANDARD_ANIM_2_TICK_PROC:
return standardAnimHandler2;
- case 0x7F3A:
+ case STANDARD_ANIM_TICK_PROC:
return standardAnimHandler;
+ case 0x7F54:
+ return sonicRatAnimHandler;
case 0x7F69:
return droppingTorchAnimHandler;
case 0x7FA1:
return playerSewerExitAnimHandler;
case 0x8009:
return fireAnimHandler;
+ case 0x80C6:
+ return sparkleAnimHandler;
+ case 0x813F:
+ return teaAnimHandler;
case 0x8180:
return goewinCaptiveAnimHandler;
case 0x81B3:
@@ -2095,17 +2153,23 @@ HandlerMethodPtr HotspotTickHandlers::getHandler(uint16 procOffset) {
case 0x820E:
return morkusAnimHandler;
case 0x8241:
- return headAnimHandler;
+ return grubAnimHandler;
case 0x82A0:
return barmanAnimHandler;
case 0x85ce:
return skorlGaurdAnimHandler;
+ case 0x862D:
+ return gargoyleAnimHandler;
+ case 0x86FA:
+ case 0x86FF:
+ return skullAnimHandler;
case 0x882A:
return rackSerfAnimHandler;
case TALK_TICK_PROC_ID:
return talkAnimHandler;
default:
- return defaultHandler;
+ error("Unknown tick proc %xh for hotspot", procOffset);
+// return defaultHandler;
}
}
@@ -2147,14 +2211,14 @@ void HotspotTickHandlers::standardCharacterAnimHandler(Hotspot &h) {
// Handle any active hotspot the character is using (for example, if the player is
// talking to a character, this stops them from moving for the duration)
- if (h.useHotspotId() != 0) {
- debugC(ERROR_DETAILED, kLureDebugAnimations, "Use Hotspot Id = %xh, v2b = %d",
- h.useHotspotId(), h.v2b());
- if (h.v2b() == 0x2A) {
- fields.setField(ACTIVE_HOTSPOT_ID, h.v2b());
- fields.setField(USE_HOTSPOT_ID, h.useHotspotId());
- Script::execute(h.script());
- h.setUseHotspotId(0);
+ if (h.resource()->talkDestCharacterId != 0) {
+ debugC(ERROR_DETAILED, kLureDebugAnimations, "Use Hotspot Id = %xh, talk_gate = %d",
+ h.resource()->talkDestCharacterId, h.talkGate());
+ if (h.talkGate() == 0x2A) {
+ fields.setField(ACTIVE_HOTSPOT_ID, h.talkGate());
+ fields.setField(USE_HOTSPOT_ID, h.resource()->talkDestCharacterId);
+ Script::execute(h.talkScript());
+ h.resource()->talkDestCharacterId = 0;
} else {
h.updateMovement();
return;
@@ -2265,6 +2329,7 @@ void HotspotTickHandlers::standardCharacterAnimHandler(Hotspot &h) {
debugC(ERROR_DETAILED, kLureDebugAnimations, "Hotspot standard character point 6");
CurrentAction action = actions.action();
+ PathFinderResult pfResult;
switch (action) {
case NO_ACTION:
@@ -2314,14 +2379,15 @@ void HotspotTickHandlers::standardCharacterAnimHandler(Hotspot &h) {
debugC(ERROR_DETAILED, kLureDebugAnimations, "Hotspot standard character processing path");
res.pausedList().scan(h);
- if (!pathFinder.process()) break;
+ pfResult = pathFinder.process();
+ if (pfResult == PF_UNFINISHED) break;
debugC(ERROR_DETAILED, kLureDebugAnimations,
- "pathFinder done: result = %d", pathFinder.result());
+ "pathFinder done: result = %d", pfResult);
// Post-processing checks
- if ((pathFinder.result() == PF_OK) ||
- ((h.destHotspotId() == 0) && (pathFinder.result() == PF_DEST_OCCUPIED))) {
+ if ((pfResult == PF_OK) ||
+ ((h.destHotspotId() == 0) && (pfResult == PF_DEST_OCCUPIED))) {
// Standard processing
debugC(ERROR_DETAILED, kLureDebugAnimations, "Standard result handling");
@@ -2581,6 +2647,7 @@ void HotspotTickHandlers::playerAnimHandler(Hotspot &h) {
}
CurrentAction action = actions.action();
+ PathFinderResult pfResult;
switch (action) {
case NO_ACTION:
@@ -2633,16 +2700,16 @@ void HotspotTickHandlers::playerAnimHandler(Hotspot &h) {
h.setCharacterMode(CHARMODE_NONE);
res.pausedList().scan(h);
- if (!pathFinder.process()) break;
+ pfResult = pathFinder.process();
+ if (pfResult == PF_UNFINISHED) break;
// Pathfinding is now complete
pathFinder.list(buffer);
debugC(ERROR_DETAILED, kLureDebugAnimations,
"Pathfind processing done; result=%d, walkFlag=%d\n%s",
- pathFinder.result(), h.walkFlag(), buffer);
+ pfResult, h.walkFlag(), buffer);
- if ((pathFinder.result() != PF_OK) &&
- (h.walkFlag() || (pathFinder.result() != PF_DEST_OCCUPIED))) {
+ if ((pfResult != PF_OK) && (h.walkFlag() || (pfResult != PF_DEST_OCCUPIED))) {
debugC(ERROR_DETAILED, kLureDebugAnimations, "Blocked state checking");
if (h.blockedState() == BS_FINAL) {
@@ -2681,11 +2748,10 @@ void HotspotTickHandlers::playerAnimHandler(Hotspot &h) {
// The character is currently moving
h.setOccupied(false);
- if ((h.destHotspotId() != 0) && (h.destHotspotId() != 0xffff)) {
- // Player is walking to a room exit hotspot
+ if (h.destHotspotId() != 0) {
RoomExitJoinData *joinRec = res.getExitJoin(h.destHotspotId());
- if (joinRec->blocked) {
- // Exit now blocked, so stop walking
+ if ((joinRec != NULL) && (joinRec->blocked)) {
+ // Player is walking to a blocked room exit, so stop walking
actions.pop();
h.setOccupied(true);
break;
@@ -2757,18 +2823,6 @@ void HotspotTickHandlers::followerAnimHandler(Hotspot &h) {
return;
}
- if (fields.wanderingCharsLoaded()) {
- // Start Ratpouch to sewer exit to meet player
- fields.wanderingCharsLoaded() = false;
- h.setBlockedFlag(false);
- CharacterScheduleEntry *newEntry = res.charSchedules().getEntry(RETURN_SUPPORT_ID);
- h.currentActions().addFront(DISPATCH_ACTION, newEntry, 7);
- h.setActionCtr(0);
-
- standardCharacterAnimHandler(h);
- return;
- }
-
// Handle any pause countdown
if (countdownCtr > 0) {
--countdownCtr;
@@ -2841,6 +2895,16 @@ void HotspotTickHandlers::skorlAnimHandler(Hotspot &h) {
standardCharacterAnimHandler(h);
}
+void HotspotTickHandlers::sonicRatAnimHandler(Hotspot &h) {
+ if (h.actionCtr() == 0) {
+ HotspotData *player = Resources::getReference().getHotspot(PLAYER_ID);
+ if (Support::charactersIntersecting(h.resource(), player))
+ h.setActionCtr(1);
+ } else {
+ standardAnimHandler(h);
+ }
+}
+
void HotspotTickHandlers::droppingTorchAnimHandler(Hotspot &h) {
if (h.frameCtr() > 0)
h.setFrameCtr(h.frameCtr() - 1);
@@ -2886,6 +2950,10 @@ void HotspotTickHandlers::playerSewerExitAnimHandler(Hotspot &h) {
ratpouchHotspot->setCharacterMode(CHARMODE_NONE);
ratpouchHotspot->setDelayCtr(0);
ratpouchHotspot->setActions(0x821C00);
+
+ // Ratpouch has previously been moved to room 8. Start him moving to room 7
+ ratpouchHotspot->currentActions().clear();
+ ratpouchHotspot->currentActions().addFront(DISPATCH_ACTION, 7);
}
}
@@ -2894,6 +2962,59 @@ void HotspotTickHandlers::fireAnimHandler(Hotspot &h) {
h.setOccupied(true);
}
+void HotspotTickHandlers::sparkleAnimHandler(Hotspot &h) {
+ Resources &res = Resources::getReference();
+ Hotspot *player = res.getActiveHotspot(PLAYER_ID);
+ ValueTableData &fields = res.fieldList();
+
+ h.setRoomNumber(player->roomNumber());
+ h.setPosition(player->x() - 14, player->y() - 10);
+ h.setActionCtr(h.actionCtr() + 1);
+ if (h.actionCtr() == 6) {
+ uint16 animId;
+ if ((fields.getField(11) == 2) || (fields.getField(28) != 0)) {
+ fields.setField(28, 0);
+ animId = PLAYER_ANIM_ID;
+ } else {
+ fields.setField(28, fields.getField(28) + 1);
+ animId = SELENA_ANIM_ID;
+ }
+
+ player->setAnimation(animId);
+ }
+
+ if (h.executeScript()) {
+ HotspotData *data = h.resource();
+ res.deactivateHotspot(&h);
+ data->roomNumber = 0x1A8;
+
+ if (fields.getField(28) != 0) {
+ Hotspot *ratpouch = res.getActiveHotspot(RATPOUCH_ID);
+ assert(ratpouch);
+ ratpouch->converse(NOONE_ID, 0x854, false);
+
+ uint16 dataId = res.getCharOffset(4);
+ CharacterScheduleEntry *entry = res.charSchedules().getEntry(dataId);
+
+ ratpouch->currentActions().addFront(DISPATCH_ACTION, entry, ratpouch->roomNumber());
+ ratpouch->setActionCtr(0);
+ }
+ }
+}
+
+void HotspotTickHandlers::teaAnimHandler(Hotspot &h) {
+ if (h.frameCtr() > 0) {
+ h.decrFrameCtr();
+ return;
+ }
+
+ if (h.executeScript()) {
+ // Signal that the tea is done
+ h.setHotspotScript(0xB82);
+ Resources::getReference().fieldList().setField(27, 1);
+ }
+}
+
void HotspotTickHandlers::goewinCaptiveAnimHandler(Hotspot &h) {
if (h.actionCtr() > 0) {
if (h.executeScript()) {
@@ -2916,14 +3037,14 @@ void HotspotTickHandlers::prisonerAnimHandler(Hotspot &h) {
if (h.actionCtr() != 0) {
if (h.executeScript() == 0) {
h.setActionCtr(0);
- h.setScript(0x3E0);
+ h.setHotspotScript(0x3E0);
}
return;
}
if ((fields.getField(PRISONER_DEAD) == 0) && (rnd.getRandomNumber(65536) >= 6)) {
h.setActionCtr(1);
- h.setScript(0x3F6);
+ h.setHotspotScript(0x3F6);
}
}
@@ -2947,7 +3068,7 @@ void HotspotTickHandlers::morkusAnimHandler(Hotspot &h) {
if (h.executeScript()) {
// Script is done - set new script to one of two alternates randomly
Common::RandomSource rnd;
- h.setScript(rnd.getRandomNumber(100) >= 50 ? 0x54 : 0);
+ h.setHotspotScript(rnd.getRandomNumber(100) >= 50 ? 0x54 : 0);
h.setFrameCtr(20 + rnd.getRandomNumber(63));
}
}
@@ -3073,10 +3194,13 @@ void HotspotTickHandlers::talkAnimHandler(Hotspot &h) {
selectedLine, descId);
// Get the response the destination character will say
- if (descId != TALK_MAGIC_ID)
+ if (descId != TALK_MAGIC_ID) {
// Set up to display the question and response in talk dialogs
h.converse(talkDestCharacter, descId, false);
- res.setTalkState(TALK_RESPOND_2);
+ res.setTalkState(TALK_RESPOND_2);
+ } else {
+ res.setTalkState(TALK_RESPOND_3);
+ }
break;
case TALK_RESPOND_2:
@@ -3088,6 +3212,8 @@ void HotspotTickHandlers::talkAnimHandler(Hotspot &h) {
if (res.getTalkingCharacter() != 0)
return;
+ case TALK_RESPOND_3:
+ // Respond
selectedLine = res.getTalkSelection();
entry = talkSelections[selectedLine-1];
@@ -3165,21 +3291,25 @@ void HotspotTickHandlers::talkAnimHandler(Hotspot &h) {
}
}
-void HotspotTickHandlers::headAnimHandler(Hotspot &h) {
+void HotspotTickHandlers::grubAnimHandler(Hotspot &h) {
Resources &res = Resources::getReference();
+ h.handleTalkDialog();
+
Hotspot *character = res.getActiveHotspot(PLAYER_ID);
uint16 frameNumber = 0;
if (character->y() < 79) {
- // TODO:
- //character = res.getActiveHotspot(RATPOUCH_ID);
- frameNumber = 1;
- } else {
- if (character->x() < 72) frameNumber = 0;
- else if (character->x() < 172) frameNumber = 1;
- else frameNumber = 2;
+ // If player is behind Grub, use Ratpouch if possible
+ Hotspot *ratpouch = res.getActiveHotspot(RATPOUCH_ID);
+ if ((ratpouch != NULL) && (ratpouch->roomNumber() == h.roomNumber()))
+ character = ratpouch;
}
+ if (character->x() < 72) frameNumber = 0;
+ else if (character->x() < 172) frameNumber = 1;
+ else frameNumber = 2;
+
+ h.setActionCtr(frameNumber);
h.setFrameNumber(frameNumber);
}
@@ -3221,7 +3351,7 @@ void HotspotTickHandlers::barmanAnimHandler(Hotspot &h) {
h.setFrameCtr(barEntry.currentCustomer->serveFlags);
barEntry.currentCustomer->serveFlags &= 0xf8;
- } else if (!h.useHotspotId() == 0) {
+ } else if (h.resource()->talkDestCharacterId == 0) {
// Player is not currently talking
// Clear entry from list
barEntry.currentCustomer->hotspotId = 0;
@@ -3244,7 +3374,6 @@ void HotspotTickHandlers::barmanAnimHandler(Hotspot &h) {
barEntry.currentCustomer = &barEntry.customers[index];
Hotspot *hotspot = res.getActiveHotspot(barEntry.customers[index].hotspotId);
assert(hotspot);
-//DEBUG/TODO: Reaching here too early, so servee's x can be outside the bar range
h.setSupportValue(hotspot->x()); // Save the position to move to
h.setFrameCtr(0x80); // Flag for movement
return;
@@ -3400,6 +3529,18 @@ void HotspotTickHandlers::skorlGaurdAnimHandler(Hotspot &h) {
h.setFrameNumber(h.actionCtr());
}
+void HotspotTickHandlers::gargoyleAnimHandler(Hotspot &h) {
+ h.handleTalkDialog();
+}
+
+void HotspotTickHandlers::skullAnimHandler(Hotspot &h) {
+ Resources &res = Resources::getReference();
+ RoomExitJoinData *joinRec = res.getExitJoin(
+ (h.hotspotId() == 0x42f) ? 0x272A : 0x272C);
+
+ h.setFrameNumber(joinRec->blocked ? 0 : 1);
+}
+
void HotspotTickHandlers::rackSerfAnimHandler(Hotspot &h) {
Resources &res = Resources::getReference();
@@ -3413,7 +3554,7 @@ void HotspotTickHandlers::rackSerfAnimHandler(Hotspot &h) {
switch (h.actionCtr()) {
case 1:
- h.setScript(RACK_SERF_SCRIPT_ID_1);
+ h.setHotspotScript(RACK_SERF_SCRIPT_ID_1);
h.setActionCtr(2);
break;
@@ -3423,7 +3564,7 @@ void HotspotTickHandlers::rackSerfAnimHandler(Hotspot &h) {
break;
case 3:
- h.setScript(RACK_SERF_SCRIPT_ID_2);
+ h.setHotspotScript(RACK_SERF_SCRIPT_ID_2);
h.setActionCtr(4);
h.setLayer(2);
@@ -3548,6 +3689,7 @@ int WalkingActionEntry::numSteps() {
PathFinder::PathFinder(Hotspot *h) {
_hotspot = h;
+ _inUse = false;
_list.clear();
_stepCtr = 0;
}
@@ -3562,12 +3704,13 @@ void PathFinder::clear() {
void PathFinder::reset(RoomPathsData &src) {
clear();
src.decompress(_layer, _hotspot->widthCopy());
+ _inUse = true;
}
// Does the next stage of processing to figure out a path to take to a given
// destination. Returns true if the path finding has been completed
-bool PathFinder::process() {
+PathFinderResult PathFinder::process() {
bool returnFlag = _inProgress;
// Check whether the pathfinding can be broken by the countdown counter
bool breakFlag = (PATHFIND_COUNTDOWN != 0);
@@ -3580,6 +3723,7 @@ bool PathFinder::process() {
uint16 numSteps = 0, savedSteps = 0;
bool altFlag;
uint16 *pCurrent;
+ PathFinderResult result = PF_UNFINISHED;
if (!_inProgress) {
// Following code only done during first call to method
@@ -3596,6 +3740,7 @@ bool PathFinder::process() {
add(LEFT, -_xDestPos);
_inProgress = false;
+ result = PF_OK;
goto final_step;
}
@@ -3609,7 +3754,7 @@ bool PathFinder::process() {
// Flag starting/ending cells
*_pSrc = 1;
_destOccupied = *_pDest != 0;
- _result = _destOccupied ? PF_DEST_OCCUPIED : PF_OK;
+ result = _destOccupied ? PF_DEST_OCCUPIED : PF_OK;
*_pDest = 0;
// Set up the current pointer, adjusting away from edges if necessary
@@ -3644,7 +3789,7 @@ bool PathFinder::process() {
if (!returnFlag) {
processCell(&_layer[(_yChangeStart + _yCtr * _yChangeInc) * DECODED_PATHS_WIDTH +
(_xChangeStart + _xCtr * _xChangeInc)]);
- if (breakFlag && (_countdownCtr <= 0)) return false;
+ if (breakFlag && (_countdownCtr <= 0)) return PF_UNFINISHED;
} else {
returnFlag = false;
}
@@ -3660,7 +3805,7 @@ bool PathFinder::process() {
// At least one cell populated, so go repeat loop
_cellPopulated = false;
} else {
- _result = PF_NO_PATH;
+ result = PF_PART_PATH;
scanFlag = true;
break;
}
@@ -3685,9 +3830,8 @@ bool PathFinder::process() {
scanLine(ROOM_PATHS_HEIGHT - _destY, DECODED_PATHS_WIDTH, pTemp, v);
if (pTemp == _pDest) {
- _result = PF_NO_WALK;
clear();
- return true;
+ return PF_NO_WALK;
}
_pDest = pTemp;
@@ -3703,6 +3847,9 @@ bool PathFinder::process() {
// walking steps in reverse order until source is reached
int stageCtr;
for (stageCtr = 0; stageCtr < 3; ++stageCtr) {
+ // Clear out any previously determined directions
+ clear();
+
altFlag = stageCtr == 1;
pCurrent = _pDest;
@@ -3764,14 +3911,11 @@ bool PathFinder::process() {
if ((stageCtr == 1) && (numSteps <= savedSteps))
// Less steps were needed, so break out
break;
-
- // Clear out any previously determined directions
- clear();
}
// Add a final move if necessary
- if (_result == PF_OK) {
+ if (result == PF_OK) {
if (_xDestPos < 0)
addBack(LEFT, -_xDestPos);
else if (_xDestPos > 0)
@@ -3782,7 +3926,7 @@ final_step:
if (_xPos < 0) add(RIGHT, -_xPos);
else if (_xPos > 0) add(LEFT, _xPos);
- return true;
+ return result;
}
void PathFinder::list(char *buffer) {
@@ -3905,39 +4049,45 @@ void PathFinder::initVars() {
if (_yDestCurrent >= (FULL_SCREEN_HEIGHT - MENUBAR_Y_SIZE))
_yDestCurrent = FULL_SCREEN_HEIGHT - MENUBAR_Y_SIZE - 1;
- _result = PF_OK;
-
// Subtract an amount from the countdown counter to compensate for
// the time spent decompressing the walkable areas set for the room
_countdownCtr -= 700;
}
void PathFinder::saveToStream(Common::WriteStream *stream) {
- // Note: current saving process only handles the PathFinder correctly
- // if all pathfinding is done in one go (ie. multiple calls pathfinding
- // isn't supported)
-
- ManagedList<WalkingActionEntry *>::iterator i;
- for (i = _list.begin(); i != _list.end(); ++i) {
- WalkingActionEntry *entry = *i;
- stream->writeByte(entry->direction());
- stream->writeSint16LE(entry->rawSteps());
+ stream->writeByte(_inUse);
+
+ if (_inUse) {
+ // Save the path finding plane
+ stream->write(_layer, sizeof(RoomPathsDecompressedData));
+
+ // Save any active step sequence
+ ManagedList<WalkingActionEntry *>::iterator i;
+ for (i = _list.begin(); i != _list.end(); ++i) {
+ WalkingActionEntry *entry = *i;
+ stream->writeByte(entry->direction());
+ stream->writeSint16LE(entry->rawSteps());
+ }
+ stream->writeByte(0xff);
+ stream->writeSint16LE(_stepCtr);
}
- stream->writeByte(0xff);
- stream->writeByte(_result);
- stream->writeSint16LE(_stepCtr);
}
void PathFinder::loadFromStream(Common::ReadStream *stream) {
_inProgress = false;
- _list.clear();
- uint8 direction;
- while ((direction = stream->readByte()) != 0xff) {
- int steps = stream->readSint16LE();
- _list.push_back(new WalkingActionEntry((Direction) direction, steps));
+ _inUse = stream->readByte() != 0;
+
+ if (_inUse) {
+ stream->read(_layer, sizeof(RoomPathsDecompressedData));
+
+ _list.clear();
+ uint8 direction;
+ while ((direction = stream->readByte()) != 0xff) {
+ int steps = stream->readSint16LE();
+ _list.push_back(new WalkingActionEntry((Direction) direction, steps));
+ }
+ _stepCtr = stream->readSint16LE();
}
- _result = (PathFinderResult)stream->readByte();
- _stepCtr = stream->readSint16LE();
}
// Current action entry class methods
@@ -3986,6 +4136,7 @@ void CurrentActionEntry::saveToStream(WriteStream *stream) {
if (_dynamicSupportData)
{
// Write out the dynamic data
+ stream->writeByte(supportData().action());
stream->writeSint16LE(supportData().numParams());
for (int index = 0; index < supportData().numParams(); ++index)
stream->writeUint16LE(supportData().param(index));