Enhanced hotspot action so that the player will properly walk to a hotspot before performing an action

svn-id: r22209
This commit is contained in:
Paul Gilbert 2006-04-29 11:22:05 +00:00
parent 946d0582dc
commit 1192f0dfca
4 changed files with 527 additions and 189 deletions

View File

@ -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();

View File

@ -43,6 +43,7 @@ private:
void handleClick();
void handleRightClickMenu();
void handleLeftClick();
void doAction(Action action, uint16 hotspotId, uint16 usedId);
void playerChangeRoom();
public:

View File

@ -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
if (*currentFrame == *destFrame) {
// sub_184 and other stuff TODO
}
// Opening the door
h.setOccupied(false);
--*currentFrame;
if (*currentFrame == *destFrame) {
//TODO: Check against script val 88 and play sound
}
}
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

View File

@ -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 &currentActions() { 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<Hotspot *> HotspotList;