aboutsummaryrefslogtreecommitdiff
path: root/engines
diff options
context:
space:
mode:
authorPaul Gilbert2006-02-19 04:25:28 +0000
committerPaul Gilbert2006-02-19 04:25:28 +0000
commit9496df6f1bf48e16d70308ce7603f11c759e3df2 (patch)
tree4361ac1bed0bb467bcb3459028f62e7d0ad5083e /engines
parent9a653960c7fbab8b79702d8934888b48e05558e7 (diff)
downloadscummvm-rg350-9496df6f1bf48e16d70308ce7603f11c759e3df2.tar.gz
scummvm-rg350-9496df6f1bf48e16d70308ce7603f11c759e3df2.tar.bz2
scummvm-rg350-9496df6f1bf48e16d70308ce7603f11c759e3df2.zip
Added basic support for conversations, as well as reworking the Hotspot class to allowing for non-hotspot animations like the floating talk icon during conversations
svn-id: r20768
Diffstat (limited to 'engines')
-rw-r--r--engines/lure/hotspots.cpp349
-rw-r--r--engines/lure/hotspots.h80
2 files changed, 358 insertions, 71 deletions
diff --git a/engines/lure/hotspots.cpp b/engines/lure/hotspots.cpp
index e7df938d47..0721df22b7 100644
--- a/engines/lure/hotspots.cpp
+++ b/engines/lure/hotspots.cpp
@@ -40,33 +40,72 @@ Hotspot::Hotspot(HotspotData *res) {
_numFrames = 0;
_persistant = false;
+ _hotspotId = res->hotspotId;
+ _roomNumber = res->roomNumber;
_startX = res->startX;
_startY = res->startY;
_destX = res->startX;
_destY = res->startY;
_destHotspotId = 0;
- _width = res->width;
_height = res->height;
+ _width = res->width;
+ _heightCopy = res->heightCopy;
+ _widthCopy = res->widthCopy;
+ _talkX = res->talkX;
+ _talkY = res->talkY;
+ _layer = res->layer;
+ _sequenceOffset = res->sequenceOffset;
_tickCtr = res->tickTimeout;
+ _actions = res->actions;
+ _colourOffset = res->colourOffset;
+
+ _override = Resources::getReference().getHotspotOverride(res->hotspotId);
- // Check for a hotspot override
- HotspotOverrideData *hor = Resources::getReference().getHotspotOverride(res->hotspotId);
-
- if (hor) {
- _startX = hor->xs;
- _startY = hor->ys;
- if (hor->xe < hor->xs) _width = 0;
- else _width = hor->xe - hor->xs + 1;
- if (hor->ye < hor->ys) _height = 0;
- else _height = hor->ye - hor->ys + 1;
- }
-
if (_data->animRecordId != 0)
setAnimation(_data->animRecordId);
_tickHandler = HotspotTickHandlers::getHandler(_data->tickProcOffset);
}
+// Special constructor used to create a voice hotspot
+
+Hotspot::Hotspot(Hotspot *character, uint16 objType) {
+ _data = NULL;
+ _anim = NULL;
+ _frames = NULL;
+ _numFrames = 0;
+ _persistant = false;
+ _hotspotId = 0xffff;
+ _override = NULL;
+ _colourOffset = 0;
+ _destHotspotId = character->hotspotId();
+
+ switch (objType) {
+ case VOICE_ANIM_ID:
+ _roomNumber = character->roomNumber();
+ _destHotspotId = character->hotspotId();
+ _startX = character->x() + character->talkX() + 12;
+ _startY = character->y() + character->talkY() - 18;
+ _destX = _startX;
+ _destY = _startY;
+ _layer = 1;
+ _height = 18;
+ _width = 32;
+ _heightCopy = character->height() + 14;
+ _widthCopy = 24;
+ _layer = 2;
+
+ _tickHandler = HotspotTickHandlers::getHandler(VOICE_TICK_PROC_ID);
+ _tickCtr = 0;
+
+ setAnimation(VOICE_ANIM_ID);
+ break;
+
+ default:
+ break;
+ }
+}
+
Hotspot::~Hotspot() {
if (_frames) delete _frames;
}
@@ -104,7 +143,7 @@ void Hotspot::setAnimation(HotspotAnimData *newRecord) {
_numFrames = 1;
_frameNumber = 0;
_frames = new Surface(1, 1);
- _frames->data().memorySet(_data->colourOffset, 0, 1);
+ _frames->data().setBytes(_colourOffset, 0, 1);
return;
}
@@ -122,9 +161,9 @@ void Hotspot::setAnimation(HotspotAnimData *newRecord) {
_numFrames = *numEntries;
_frameNumber = 0;
- _frames = new Surface(_data->width * _numFrames, _data->height);
+ _frames = new Surface(_width * _numFrames, _height);
- _frames->data().memorySet(_data->colourOffset, 0, _frames->data().size());
+ _frames->data().setBytes(_colourOffset, 0, _frames->data().size());
byte *pSrc = dest->data() + 0x40;
byte *pDest;
@@ -134,12 +173,12 @@ void Hotspot::setAnimation(HotspotAnimData *newRecord) {
for (uint16 frameCtr = 0; frameCtr < _numFrames; ++frameCtr, ++headerEntry) {
// Copy over the frame, applying the colour offset to each nibble
- for (uint16 yPos = 0; yPos < _data->height; ++yPos) {
- pDest = mDest.data() + (yPos * _numFrames + frameCtr) * _data->width;
+ for (uint16 yPos = 0; yPos < _height; ++yPos) {
+ pDest = mDest.data() + (yPos * _numFrames + frameCtr) * _width;
- for (uint16 ctr = 0; ctr < _data->width / 2; ++ctr) {
- *pDest++ = _data->colourOffset + (*pSrc >> 4);
- *pDest++ = _data->colourOffset + (*pSrc & 0xf);
+ for (uint16 ctr = 0; ctr < _width / 2; ++ctr) {
+ *pDest++ = _colourOffset + (*pSrc >> 4);
+ *pDest++ = _colourOffset + (*pSrc & 0xf);
++pSrc;
}
}
@@ -150,16 +189,10 @@ void Hotspot::setAnimation(HotspotAnimData *newRecord) {
}
void Hotspot::copyTo(Surface *dest) {
-/*
- int16 xPos = x();
- int16 yPos = y();
- uint16 hWidth = width();
- uint16 hHeight = height();
-*/
- int16 xPos = _data->startX;
- int16 yPos = _data->startY;
- uint16 hWidth = _data->width;
- uint16 hHeight = _data->height;
+ int16 xPos = _startX;
+ int16 yPos = _startY;
+ uint16 hWidth = _width;
+ uint16 hHeight = _height;
Rect r(_frameNumber * hWidth, 0, (_frameNumber + 1) * hWidth - 1,
hHeight - 1);
@@ -193,7 +226,7 @@ void Hotspot::copyTo(Surface *dest) {
else if (yPos + hHeight > FULL_SCREEN_HEIGHT)
r.bottom = FULL_SCREEN_HEIGHT - yPos - 1;
- _frames->copyTo(dest, r, (uint16) xPos, (uint16) yPos, _data->colourOffset);
+ _frames->copyTo(dest, r, (uint16) xPos, (uint16) yPos, _colourOffset);
}
void Hotspot::incFrameNumber() {
@@ -203,14 +236,23 @@ void Hotspot::incFrameNumber() {
}
bool Hotspot::isActiveAnimation() {
- return ((_numFrames != 0) && (_data->layer != 0));
+ return ((_numFrames != 0) && (_layer != 0));
+}
+
+uint16 Hotspot::nameId() {
+ if (_data == NULL)
+ return 0;
+ else
+ return _data->nameId;
}
void Hotspot::setPosition(int16 newX, int16 newY) {
_startX = newX;
_startY = newY;
- _data->startX = newX;
- _data->startY = newY;
+ if (_data) {
+ _data->startX = newX;
+ _data->startY = newY;
+ }
}
void Hotspot::setSize(uint16 newWidth, uint16 newHeight) {
@@ -230,14 +272,15 @@ void Hotspot::tick() {
}
void Hotspot::setTickProc(uint16 newVal) {
- _data->tickProcOffset = newVal;
+ if (_data)
+ _data->tickProcOffset = newVal;
_tickHandler = HotspotTickHandlers::getHandler(newVal);
}
void Hotspot::walkTo(int16 endPosX, int16 endPosY, uint16 destHotspot, bool immediate) {
_destX = endPosX;
- _destY = endPosY - _data->height;
+ _destY = endPosY - _height;
_destHotspotId = destHotspot;
if (immediate)
@@ -507,19 +550,29 @@ void Hotspot::doGive(HotspotData *hotspot) {
}
void Hotspot::doTalkTo(HotspotData *hotspot) {
- // TODO: extra checking at start
+ // TODO: still some work at start
+ if ((hotspot->hotspotId != 0x3EA) && ((hotspot->roomNumber != 28) ||
+ (hotspot->hotspotId != 0x3EB))) {
+ // sub_107 call and after check
+ }
+
+ // 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;
+
Resources &res = Resources::getReference();
uint16 sequenceOffset = res.getHotspotAction(hotspot->actionsOffset, TALK_TO);
if (sequenceOffset >= 0x8000) {
Dialog::showMessage(sequenceOffset, hotspotId());
- } else if (sequenceOffset != 0) {
+ } else if (sequenceOffset == 0) {
+ startTalk(hotspot);
+ } else {
uint16 result = Script::execute(sequenceOffset);
if (result == 0) {
- // Do talking with character
- // TODO
- Dialog::show("Still need to figure out talking");
+ // Start talking with character
+ startTalk(hotspot);
}
}
}
@@ -604,7 +657,11 @@ void Hotspot::doStatus() {
if (numItems == 0) strcat(buffer, "nothing.");
// If the player has money, add it in
- // TODO
+ uint16 numGroats = resources.fieldList().numGroats();
+ if (numGroats > 0) {
+ sprintf(buffer + strlen(buffer), "\n\nYou have %d groat", numGroats);
+ if (numGroats > 1) strcat(buffer, "s");
+ }
// Display the dialog
Screen &screen = Screen::getReference();
@@ -620,7 +677,7 @@ void Hotspot::doStatus() {
}
void Hotspot::doBribe(HotspotData *hotspot) {
- // TODO
+ Dialog::show("Yet to do");
}
void Hotspot::doExamine() {
@@ -652,6 +709,31 @@ void Hotspot::doSimple(HotspotData *hotspot, Action action) {
}
}
+void Hotspot::startTalk(HotspotData *charHotspot) {
+ Resources &res = Resources::getReference();
+ uint16 talkIndex;
+
+ setTickProc(TALK_TICK_PROC_ID); // Set for providing talk listing
+
+ // Get offset of talk set to use
+ TalkHeaderData *headerEntry = res.getTalkHeader(charHotspot->hotspotId);
+ uint16 talkOffset;
+
+ // Calculate talk index to use
+ if (charHotspot->nameId == STRANGER_ID)
+ talkIndex = 0;
+ else
+ talkIndex = res.fieldList().getField(TALK_INDEX) + 1;
+ talkOffset = headerEntry->getEntry(talkIndex);
+
+ // Set the active talk data
+ res.setTalkStartEntry(0);
+ res.setTalkData(talkOffset);
+ if (!res.getTalkData())
+ error("Talk failed - invalid offset: Character=%xh, index=%d, offset=%xh",
+ charHotspot->hotspotId, talkIndex, talkOffset);
+}
+
/*------------------------------------------------------------------------*/
HandlerMethodPtr HotspotTickHandlers::getHandler(uint16 procOffset) {
@@ -660,12 +742,14 @@ HandlerMethodPtr HotspotTickHandlers::getHandler(uint16 procOffset) {
return standardAnimHandler;
case 0x7207:
return roomExitAnimHandler;
- case 0x5e44:
+ case PLAYER_TICK_PROC_ID:
return playerAnimHandler;
case 0x7F69:
return droppingTorchAnimHandler;
case 0x8009:
return fireAnimHandler;
+ case TALK_TICK_PROC_ID:
+ return talkAnimHandler;
case 0x8241:
return headAnimationHandler;
default:
@@ -786,6 +870,181 @@ void HotspotTickHandlers::fireAnimHandler(Hotspot &h) {
// TODO: figure out remainder of method
}
+// Special variables used across multiple calls to talkAnimHandler
+static TalkEntryData *_talkResponse;
+
+void HotspotTickHandlers::talkAnimHandler(Hotspot &h) {
+ // Talk handler
+ Resources &res = Resources::getReference();
+ Room &room = Room::getReference();
+ ValueTableData &fields = res.fieldList();
+ StringData &strings = StringData::getReference();
+ Screen &screen = Screen::getReference();
+ Mouse &mouse = Mouse::getReference();
+ TalkSelections &talkSelections = res.getTalkSelections();
+ TalkData *data = res.getTalkData();
+ TalkEntryList &entries = data->entries;
+ char buffer[MAX_DESC_SIZE];
+ Rect r;
+ int lineNum, numLines;
+ int selectedLine, responseNumber;
+ bool showSelections, keepTalkingFlag;
+ TalkEntryList::iterator i;
+ TalkEntryData *entry;
+ uint16 result, descId, charId;
+
+ switch (res.getTalkState()) {
+ case TALK_NONE:
+ // Handle initial setup of talking options
+ // Reset talk entry pointer list
+ for (lineNum = 0; lineNum < MAX_TALK_SELECTIONS; ++lineNum)
+ talkSelections[lineNum] = NULL;
+
+ // Loop through list to find entries to display
+ _talkResponse = NULL;
+ numLines = 0;
+ showSelections = false;
+
+ i = entries.begin();
+ for (lineNum = 0; lineNum < res.getTalkStartEntry(); ++lineNum)
+ if (i != entries.end()) ++i;
+
+ for (; i != entries.end(); ++i) {
+ entry = *i;
+ uint8 flags = (uint8) (entry->descId >> 14);
+ if (flags == 3)
+ // Skip the entry
+ continue;
+
+ uint16 sequenceOffset = entry->preSequenceId & 0x3fff;
+ bool showLine = sequenceOffset == 0;
+ if (!showLine)
+ showLine = Script::execute(sequenceOffset) != 0;
+
+ if (showLine) {
+ talkSelections[numLines++] = entry;
+ showSelections |= (entry->descId & 0x3fff) != TALK_MAGIC_ID;
+ }
+
+ if ((entry->preSequenceId & 0x8000) != 0) break;
+ }
+
+ if (showSelections && (numLines > 1))
+ res.setTalkState(TALK_SELECT);
+ else {
+ res.setTalkState(TALK_RESPOND);
+ res.setTalkSelection(1);
+ }
+ break;
+
+ case TALK_SELECT:
+ r.left = 0; r.right = FULL_SCREEN_WIDTH - 1;
+ selectedLine = mouse.y() / MENUBAR_Y_SIZE;
+ if ((selectedLine > MAX_TALK_SELECTIONS) || ((selectedLine != 0) &&
+ !talkSelections[selectedLine-1]))
+ selectedLine = 0;
+
+ for (lineNum = 0; lineNum < MAX_TALK_SELECTIONS; ++lineNum) {
+ if (!talkSelections[lineNum]) break;
+ entry = talkSelections[lineNum];
+
+ strings.getString(entry->descId & 0x3fff, buffer, NULL, NULL);
+
+ // Clear line
+ r.top = (lineNum + 1) * MENUBAR_Y_SIZE;
+ r.bottom = r.top + MENUBAR_Y_SIZE - 1;
+ screen.screen().fillRect(r, 0);
+
+ // Display line
+ byte colour = (lineNum+1 == selectedLine) ?
+ DIALOG_WHITE_COLOUR : DIALOG_TEXT_COLOUR;
+ screen.screen().writeString(r.left, r.top, buffer, false, colour);
+ }
+
+ if ((!mouse.lButton() && !mouse.rButton()) || (selectedLine == 0))
+ break;
+
+ // Set the talk response index to use
+ res.setTalkSelection(selectedLine);
+ res.setTalkState(TALK_RESPOND);
+ break;
+
+ case TALK_RESPOND:
+ // Handle initial response to show the question in a talk dialog if needed
+ selectedLine = res.getTalkSelection();
+ entry = talkSelections[selectedLine-1];
+ descId = entry->descId & 0x3fff;
+ entry->descId |= 0x4000;
+
+ if (descId != TALK_MAGIC_ID) {
+ // Set up to display the question in a talk dialog
+ room.setTalkDialog(PLAYER_ID, descId);
+ res.setTalkState(TALK_RESPONSE_WAIT);
+ } else {
+ res.setTalkState(TALK_RESPOND_2);
+ }
+ break;
+
+ case TALK_RESPOND_2:
+ if (!_talkResponse) {
+ // Handles bringing up the response talk dialog
+ charId = fields.getField(ACTIVE_HOTSPOT_ID);
+ selectedLine = res.getTalkSelection();
+ entry = talkSelections[selectedLine-1];
+
+ responseNumber = entry->postSequenceId;
+ if ((responseNumber & 0x8000) != 0)
+ responseNumber = Script::execute(responseNumber & 0x7fff);
+
+ do {
+ _talkResponse = res.getTalkData()->getResponse(responseNumber);
+ if (!_talkResponse->preSequenceId) break;
+ responseNumber = Script::execute(_talkResponse->preSequenceId);
+ } while (responseNumber != TALK_RESPONSE_MAGIC_ID);
+
+ descId = _talkResponse->descId;
+ if ((descId & 0x8000) != 0)
+ descId = Script::execute(descId & 0x7fff);
+
+ if (descId != TALK_MAGIC_ID) {
+ room.setTalkDialog(charId, descId);
+ res.setTalkState(TALK_RESPONSE_WAIT);
+ return;
+ }
+ }
+
+ // Handle checking whether to keep talking
+ result = _talkResponse->postSequenceId;
+ if (result == 0xffff)
+ keepTalkingFlag = false;
+ else {
+ if ((result & 0x8000) == 0)
+ keepTalkingFlag = true;
+ else {
+ result = Script::execute(result & 0x7fff);
+ keepTalkingFlag = result != 0xffff;
+ }
+ }
+
+ if (keepTalkingFlag) {
+ // Reset for loading the next set of talking options
+ res.setTalkStartEntry(result);
+ res.setTalkState(TALK_NONE);
+ } else {
+ // End the conversation
+ res.getActiveHotspot(PLAYER_ID)->setTickProc(PLAYER_TICK_PROC_ID);
+ res.setTalkData(0);
+ res.setCurrentAction(NONE);
+ res.setTalkState(TALK_NONE);
+ }
+ break;
+
+ case TALK_RESPONSE_WAIT:
+ // Keeps waiting while a talk dialog is active
+ break;
+ }
+}
+
void HotspotTickHandlers::headAnimationHandler(Hotspot &h) {
Resources &res = Resources::getReference();
Hotspot *character = res.getActiveHotspot(PLAYER_ID);
diff --git a/engines/lure/hotspots.h b/engines/lure/hotspots.h
index 3483522c96..b5a4eaf1d6 100644
--- a/engines/lure/hotspots.h
+++ b/engines/lure/hotspots.h
@@ -36,12 +36,14 @@ typedef void(*HandlerMethodPtr)(Hotspot &h);
class HotspotTickHandlers {
private:
+ // Handler methods
static void defaultHandler(Hotspot &h);
static void standardAnimHandler(Hotspot &h);
static void roomExitAnimHandler(Hotspot &h);
static void playerAnimHandler(Hotspot &h);
static void droppingTorchAnimHandler(Hotspot &h);
static void fireAnimHandler(Hotspot &h);
+ static void talkAnimHandler(Hotspot &h);
static void headAnimationHandler(Hotspot &h);
public:
@@ -55,25 +57,57 @@ private:
HotspotAnimData *_anim;
HandlerMethodPtr _tickHandler;
Surface *_frames;
+ uint16 _hotspotId;
+ uint16 _roomNumber;
int16 _startX, _startY;
uint16 _height, _width;
+ uint16 _heightCopy, _widthCopy;
+ int8 _talkX, _talkY;
uint16 _numFrames;
uint16 _frameNumber;
+ uint8 _layer;
+ uint16 _sequenceOffset;
uint16 _tickCtr;
+ uint32 _actions;
+ uint8 _colourOffset;
bool _persistant;
+ HotspotOverrideData *_override;
int16 _destX, _destY;
uint16 _destHotspotId;
+
+ // Support methods
+ void startTalk(HotspotData *charHotspot);
+
+ // Action set
+ void doGet(HotspotData *hotspot);
+ void doOperate(HotspotData *hotspot, Action action);
+ void doOpen(HotspotData *hotspot);
+ void doClose(HotspotData *hotspot);
+ void doLockUnlock(HotspotData *hotspot);
+ void doUse(HotspotData *hotspot);
+ void doGive(HotspotData *hotspot);
+ void doTalkTo(HotspotData *hotspot);
+ void doTell(HotspotData *hotspot);
+ void doLook();
+ void doLookAt(HotspotData *hotspot);
+ void doAsk(HotspotData *hotspot);
+ void doDrink();
+ void doStatus();
+ void doBribe(HotspotData *hotspot);
+ void doExamine();
+ void doSimple(HotspotData *hotspot, Action action);
public:
Hotspot(HotspotData *res);
+ Hotspot(Hotspot *character, uint16 objType);
~Hotspot();
void setAnimation(uint16 newAnimId);
void setAnimation(HotspotAnimData *newRecord);
- uint16 hotspotId() { return _data->hotspotId; }
+ uint16 hotspotId() { return _hotspotId; }
Surface &frames() { return *_frames; }
HotspotAnimData &anim() { return *_anim; }
- HotspotData &resource() { return *_data; }
+ HotspotData *resource() { return _data; }
uint16 numFrames() { return _numFrames; }
uint16 frameNumber() { return _frameNumber; }
void setFrameNumber(uint16 v) { _frameNumber = v; }
@@ -83,51 +117,45 @@ public:
int16 y() { return _startY; }
int16 destX() { return _destX; }
int16 destY() { return _destY; }
+ int8 talkX() { return _talkX; }
+ int8 talkY() { return _talkY; }
uint16 destHotspotId() { return _destHotspotId; }
uint16 width() { return _width; }
uint16 height() { return _height; }
- uint16 roomNumber() { return _data->roomNumber; }
- uint16 script() { return _data->sequenceOffset; }
- uint8 layer() { return _data->layer; }
+ uint16 widthCopy() { return _widthCopy; }
+ uint16 heightCopy() { return _heightCopy; }
+ uint16 roomNumber() { return _roomNumber; }
+ uint16 script() { return _sequenceOffset; }
+ uint8 layer() { return _layer; }
uint16 tickCtr() { return _tickCtr; }
void setTickCtr(uint16 newVal) { _tickCtr = newVal; }
void setTickProc(uint16 newVal);
bool persistant() { return _persistant; }
void setPersistant(bool value) { _persistant = value; }
- void setRoomNumber(uint16 roomNum) { _data->roomNumber = roomNum; }
+ void setRoomNumber(uint16 roomNum) {
+ _roomNumber = roomNum;
+ if (_data) _data->roomNumber = roomNum;
+ }
+ uint16 nameId();
bool isActiveAnimation();
void setPosition(int16 newX, int16 newY);
void setDestPosition(int16 newX, int16 newY) { _destX = newX; _destY = newY; }
void setSize(uint16 newWidth, uint16 newHeight);
- void setScript(uint16 offset) { _data->sequenceOffset = offset; }
- void setActions(uint32 newActions) { _data->actions = newActions; }
+ void setScript(uint16 offset) {
+ _sequenceOffset = offset;
+ _data->sequenceOffset = offset;
+ }
+ void setActions(uint32 newActions) { _actions = newActions; }
void copyTo(Surface *dest);
bool executeScript();
void tick();
void walkTo(int16 endPosX, int16 endPosY, uint16 destHotspot = 0, bool immediate = false);
void setDirection(Direction dir);
+ bool isRoomExit(uint16 id);
// Action set
void doAction(Action action, HotspotData *hotspot);
- bool isRoomExit(uint16 id);
- void doGet(HotspotData *hotspot);
- void doOperate(HotspotData *hotspot, Action action);
- void doOpen(HotspotData *hotspot);
- void doClose(HotspotData *hotspot);
- void doLockUnlock(HotspotData *hotspot);
- void doUse(HotspotData *hotspot);
- void doGive(HotspotData *hotspot);
- void doTalkTo(HotspotData *hotspot);
- void doTell(HotspotData *hotspot);
- void doLook();
- void doLookAt(HotspotData *hotspot);
- void doAsk(HotspotData *hotspot);
- void doDrink();
- void doStatus();
- void doBribe(HotspotData *hotspot);
- void doExamine();
- void doSimple(HotspotData *hotspot, Action action);
};
typedef ManagedList<Hotspot *> HotspotList;