aboutsummaryrefslogtreecommitdiff
path: root/engines/m4/mads_scene.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'engines/m4/mads_scene.cpp')
-rw-r--r--engines/m4/mads_scene.cpp472
1 files changed, 237 insertions, 235 deletions
diff --git a/engines/m4/mads_scene.cpp b/engines/m4/mads_scene.cpp
index e4f84aeb5a..d44fa2a753 100644
--- a/engines/m4/mads_scene.cpp
+++ b/engines/m4/mads_scene.cpp
@@ -48,6 +48,17 @@ static const int SCROLLER_DELAY = 200;
//--------------------------------------------------------------------------
+void SceneNode::load(Common::SeekableReadStream *stream) {
+ // Get the next data block
+ pt.x = stream->readUint16LE();
+ pt.y = stream->readUint16LE();
+
+ for (int i = 0; i < MAX_ROUTE_NODES; ++i)
+ indexes[i] = stream->readUint16LE();
+}
+
+//--------------------------------------------------------------------------
+
MadsScene::MadsScene(MadsEngine *vm): _sceneResources(), Scene(vm, &_sceneResources), MadsView(this) {
_vm = vm;
_activeAnimation = NULL;
@@ -55,6 +66,8 @@ MadsScene::MadsScene(MadsEngine *vm): _sceneResources(), Scene(vm, &_sceneResour
MadsView::_bgSurface = Scene::_backgroundSurface;
MadsView::_depthSurface = Scene::_walkSurface;
_interfaceSurface = new MadsInterfaceView(vm);
+ _showMousePos = false;
+ _mouseMsgIndex = -1;
}
MadsScene::~MadsScene() {
@@ -182,24 +195,21 @@ void MadsScene::loadSceneHotspots(int sceneNumber) {
int hotspotCount = hotspotStream->readUint16LE();
delete hotspotStream;
- _sceneResources.hotspotCount = hotspotCount;
-
hotspotStream = hotSpotData.getItemStream(1);
// Clear current hotspot lists
_sceneResources.hotspots->clear();
-
- _sceneResources.hotspots->loadHotSpots(hotspotStream, _sceneResources.hotspotCount);
+ _sceneResources.hotspots->loadHotSpots(hotspotStream, hotspotCount);
delete hotspotStream;
}
void MadsScene::leaveScene() {
_sceneResources.hotspots->clear();
- _sceneResources.props->clear();
+ _sceneResources.dynamicHotspots->clear();
delete _sceneResources.hotspots;
- delete _sceneResources.props;
+ delete _sceneResources.dynamicHotspots;
delete _walkSurface;
if (_activeAnimation) {
@@ -228,43 +238,28 @@ void MadsScene::loadSceneCodes(int sceneNumber, int index) {
}
}
-void MadsScene::checkHotspotAtMousePos(int x, int y) {
+void MadsScene::mouseMove(int x, int y) {
HotSpot *currentHotSpot = _sceneResources.hotspots->findByXY(x, y);
if (currentHotSpot != NULL) {
_vm->_mouse->setCursorNum(currentHotSpot->getCursor());
- // This is the "easy" interface, which updates the status text when the mouse is moved
- // TODO: toggle this code for easy/normal interface mode
- char statusText[50];
- int verbId = 0;//***DEBUG****_currentAction;
- if (verbId == kVerbNone)
- verbId = currentHotSpot->getVerbID();
- if (verbId == kVerbNone)
- verbId = kVerbWalkTo;
-
- sprintf(statusText, "%s %s\n", _madsVm->globals()->getVocab(verbId), currentHotSpot->getVocab());
+ _action._selectedRow = -1;
+ _action._actionMode = ACTMODE_NONE;
+ _action._actionMode2 = ACTMODE2_4;
+ _action._hotspotId = currentHotSpot->getIndex();
- statusText[0] = toupper(statusText[0]); // capitalize first letter
- setStatusText(statusText);
} else {
_vm->_mouse->setCursorNum(0);
- setStatusText("");
}
}
void MadsScene::leftClick(int x, int y) {
- HotSpot *currentHotSpot = _sceneResources.hotspots->findByXY(x, y);
- if (currentHotSpot != NULL) {
- char statusText[50];
- if (currentHotSpot->getVerbID() != 0) {
- sprintf(statusText, "%s %s\n", currentHotSpot->getVerb(), currentHotSpot->getVocab());
- } else {
- sprintf(statusText, "%s %s\n", _madsVm->globals()->getVocab(kVerbWalkTo), currentHotSpot->getVocab());
- }
-
- statusText[0] = toupper(statusText[0]); // capitalize first letter
- setStatusText(statusText);
- }
+ // TODO: figure out the rest of Scene_leftClick, and implements relevant parts in the interface class
+ _action._v86F4C = -1;
+ _action._v86F4E = 0;
+ _customDest = _madsVm->_mouse->currentPos();
+ _action._selectedAction = -1;
+ _action._v86F4A = true;
}
void MadsScene::rightClick(int x, int y) {
@@ -280,7 +275,6 @@ void MadsScene::rightClick(int x, int y) {
void MadsScene::setAction(int action, int objectId) {
VALIDATE_MADS;
- char statusText[50];
error("todo");
// TODO: Actually executing actions directly for objects. Also, some object actions are special in that
@@ -297,7 +291,7 @@ void MadsScene::setAction(int action, int objectId) {
_currentAction = action;
}
*/
- setStatusText(statusText);
+// setStatusText(statusText);
}
/**
@@ -316,39 +310,77 @@ void MadsScene::update() {
drawElements();
_action.set();
- const char *sStatusText = _action.statusText();
-
- // Handle display of any status text
- if (sStatusText[0]) {
- // Text colors are inverted in Dragonsphere
- if (_vm->getGameType() == GType_DragonSphere)
- _vm->_font->current()->setColours(_vm->_palette->BLACK, _vm->_palette->WHITE, _vm->_palette->BLACK);
- else
- _vm->_font->current()->setColours(_vm->_palette->WHITE, _vm->_palette->BLACK, _vm->_palette->BLACK);
-
- _vm->_font->setFont(FONT_MAIN_MADS);
- _vm->_font->current()->writeString(this, sStatusText, (width() - _vm->_font->current()->getWidth(sStatusText)) / 2, 142, 0);
- }
}
void MadsScene::updateState() {
- _madsVm->_player.update();
+ if (!_abortTimers && !_madsVm->_player._unk3) {
+ if (_dynamicHotspots._changed)
+ _dynamicHotspots.refresh();
- // Step through the scene
- _sceneLogic.sceneStep();
+// int v = (_madsVm->_player._stepEnabled && !_action._startWalkFlag && !_abortTimers2) ? 1 : 0;
+// _screenObjects.check(v, false);
+ }
- _madsVm->_player.step();
- _madsVm->_player._unk3 = 0;
+ // Handle starting off any selected action
+ bool doPreAction = false;
+ if ((_action._selectedAction != 0) && _madsVm->_player._stepEnabled &&
+ !_action._startWalkFlag && !_abortTimers && !_madsVm->_player._unk3) {
+ // Start the action
+ _action.startAction();
- if (_abortTimersMode == ABORTMODE_1)
- _abortTimers = 0;
+ if (_action._action.verbId == kVerbLookAt) {
+ _action._action.verbId = kVerbLook;
+ _action._savedFields.selectedRow = 0;
+ }
+ doPreAction = true;
+ }
+ if (doPreAction || ((_abortTimers != 0) && (_abortTimersMode == ABORTMODE_2)))
+ doPreactions();
+
+ checkStartWalk();
+
+ if (_action._inProgress && !_madsVm->_player._moving && !_action._startWalkFlag &&
+ (_madsVm->_player._newDirection == _madsVm->_player._direction)) {
+ // Reached the end of action movement, so ready to actually do action
+ doAction();
+ } else if ((_abortTimers != 0) && (_abortTimersMode == ABORTMODE_0))
+ // Do an action designated by scripts
+ doAction();
+
+ bool freeFlag = false;
+ if (_currentScene != _nextScene)
+ freeFlag = true;
+ else {
+ doSceneStep();
+
+ if (_currentScene != _nextScene)
+ freeFlag = true;
+ else {
+ // Update the player
+ _madsVm->_player.nextFrame();
+
+ // Handle updating the animation
+ if (!_abortTimers && (_activeAnimation))
+ _activeAnimation->update();
+
+ // Handle refreshing the mouse position display
+ if (_mouseMsgIndex != -1)
+ _madsVm->scene()->_kernelMessages.remove(_mouseMsgIndex);
+ if (_showMousePos) {
+ char buffer[20];
+ sprintf(buffer, "(%d,%d)", _madsVm->_mouse->currentPos().x, _madsVm->_mouse->currentPos().y);
+
+ _mouseMsgIndex = _madsVm->scene()->_kernelMessages.add(Common::Point(5, 5), 0x203, 0, 0, 1, buffer);
+ }
+ }
+ }
- // Handle updating the player frame
- _madsVm->_player.nextFrame();
+ if (_madsVm->globals()->_config.easyMouse)
+ _action.refresh();
if ((_activeAnimation) && !_abortTimers) {
_activeAnimation->update();
- if (((MadsAnimation *) _activeAnimation)->freeFlag()) {
+ if (((MadsAnimation *) _activeAnimation)->freeFlag() || freeFlag) {
delete _activeAnimation;
_activeAnimation = NULL;
}
@@ -359,8 +391,48 @@ void MadsScene::updateState() {
// Remove the animation if it's been completed
if ((_activeAnimation) && ((MadsAnimation *)_activeAnimation)->freeFlag())
freeAnimation();
+
+ if ((_action._selectedAction != 0) || !_madsVm->_player._stepEnabled) {
+ _action.clear();
+ _action._selectedAction = 0;
+ }
}
+void MadsScene::checkStartWalk() {
+ if (_action._startWalkFlag && _action._walkFlag) {
+ _madsVm->_player.setDest(_destPos.x, _destPos.y, _destFacing);
+ _action._startWalkFlag = false;
+ }
+}
+
+void MadsScene::doPreactions() {
+ if ((_screenObjects._v832EC == 0) || (_screenObjects._v832EC == 2)) {
+ _abortTimersMode2 = ABORTMODE_2;
+ _action.checkAction();
+
+ _sceneLogic.doPreactions();
+
+ if (_abortTimersMode == ABORTMODE_2)
+ _abortTimers = 0;
+ }
+}
+
+void MadsScene::doSceneStep() {
+ // Step through the scene
+ _sceneLogic.doSceneStep();
+
+ _madsVm->_player.step();
+ _madsVm->_player._unk3 = 0;
+
+ if (_abortTimersMode == ABORTMODE_1)
+ _abortTimers = 0;
+}
+
+void MadsScene::doAction() {
+ warning("TODO MadsScene::doAction");
+}
+
+
/**
* Does extra work at cleaning up the animation, and then deletes it
*/
@@ -503,179 +575,20 @@ void MadsScene::loadAnimation(const Common::String &animName, int abortTimers) {
_activeAnimation = anim;
}
-/*--------------------------------------------------------------------------*/
-
-MadsAction::MadsAction() {
- clear();
-}
-
-void MadsAction::clear() {
- _actionMode = ACTMODE_NONE;
- _actionMode2 = ACTMODE2_0;
- _word_86F42 = 0;
- _word_86F4E = 0;
- _articleNumber = 0;
- _lookFlag = false;
- _word_86F4A = 0;
- _statusText[0] = '\0';
- _selectedRow = -1;
- _currentHotspot = -1;
- _word_86F3A = -1;
- _word_86F4C = -1;
- //word_86F3A/word_86F4C
- _currentAction = kVerbNone;
- _objectNameId = -1;
- _objectDescId = -1;
- _word_83334 = -1;
-}
-
-void MadsAction::appendVocab(int vocabId, bool capitalise) {
- char *s = _statusText + strlen(_statusText);
- const char *vocabStr = _madsVm->globals()->getVocab(vocabId);
- strcpy(s, vocabStr);
- if (capitalise)
- *s = toupper(*s);
+bool MadsScene::getDepthHighBit(const Common::Point &pt) {
+ const byte *p = _depthSurface->getBasePtr(pt.x, pt.y);
+ if (_sceneResources._depthStyle == 2)
+ return ((*p << 4) & 0x80) != 0;
- strcat(s, " ");
+ return (*p & 0x80) != 0;
}
-void MadsAction::set() {
- int hotspotCount = _madsVm->scene()->getSceneResources().hotspotCount;
- bool flag = false;
- _currentAction = -1;
- _objectNameId = -1;
- _objectDescId = -1;
-
- if (_actionMode == ACTMODE_TALK) {
- // Handle showing the conversation selection. Rex at least doesn't actually seem to use this
- if (_selectedRow >= 0) {
- const char *desc = _madsVm->_converse[_selectedRow].desc;
- if (desc)
- strcpy(_statusText, desc);
- }
- } else if (_lookFlag && (_selectedRow == 0)) {
- // Two 'look' actions in succession, so the action becomes 'Look around'
- strcpy(_statusText, lookAroundStr);
- } else {
- if ((_actionMode == ACTMODE_OBJECT) && (_selectedRow >= 0) && (_flags1 == 2) && (_flags2 == 0)) {
- // Use/to action
- int selectedObject = _madsVm->scene()->getInterface()->getSelectedObject();
- MadsObject *objEntry = _madsVm->globals()->getObject(selectedObject);
-
- _objectNameId = objEntry->descId;
- _currentAction = objEntry->vocabList[_selectedRow].vocabId;
-
- // Set up the status text stirng
- strcpy(_statusText, useStr);
- appendVocab(_objectNameId);
- strcpy(_statusText, toStr);
- appendVocab(_currentAction);
- } else {
- // Handling for if an action has been selected
- if (_selectedRow >= 0) {
- if (_actionMode == ACTMODE_VERB) {
- // Standard verb action
- _currentAction = verbList[_selectedRow].verb;
- } else {
- // Selected action on an inventory object
- int selectedObject = _madsVm->scene()->getInterface()->getSelectedObject();
- MadsObject *objEntry = _madsVm->globals()->getObject(selectedObject);
-
- _currentAction = objEntry->vocabList[_selectedRow].vocabId;
- }
-
- appendVocab(_currentAction, true);
-
- if (_currentAction == kVerbLook) {
- // Add in the word 'add'
- strcat(_statusText, atStr);
- strcat(_statusText, " ");
- }
- }
-
- // Handling for if a hotspot has been selected/highlighted
- if ((_currentHotspot >= 0) && (_selectedRow >= 0) && (_articleNumber > 0) && (_flags1 == 2)) {
- flag = true;
-
- strcat(_statusText, englishMADSArticleList[_articleNumber]);
- strcat(_statusText, " ");
- }
-
- if (_currentHotspot >= 0) {
- if (_selectedRow < 0) {
- int verbId;
-
- if (_currentHotspot < hotspotCount) {
- // Get the verb Id from the hotspot
- verbId = (*_madsVm->scene()->getSceneResources().hotspots)[_currentHotspot].getVerbID();
- } else {
- // Get the verb Id from the scene object
- verbId = (*_madsVm->scene()->getSceneResources().props)[_currentHotspot - hotspotCount].getVerbID();
- }
-
- if (verbId > 0) {
- // Set the specified action
- _currentAction = verbId;
- appendVocab(_currentAction, true);
- } else {
- // Default to a standard 'walk to'
- _currentAction = kVerbWalkTo;
- strcat(_statusText, walkToStr);
- }
- }
-
- if ((_actionMode2 == ACTMODE2_2) || (_actionMode2 == ACTMODE2_5)) {
- // Get name from given inventory object
- int objectId = _madsVm->scene()->getInterface()->getInventoryObject(_currentHotspot);
- _objectNameId = _madsVm->globals()->getObject(objectId)->descId;
- } else if (_currentHotspot < hotspotCount) {
- // Get name from scene hotspot
- _objectNameId = (*_madsVm->scene()->getSceneResources().hotspots)[_currentHotspot].getVocabID();
- } else {
- // Get name from temporary scene hotspot
- _objectNameId = (*_madsVm->scene()->getSceneResources().props)[_currentHotspot].getVocabID();
- }
- }
- }
-
- if ((_currentHotspot >= 0) && (_articleNumber > 0) && !flag) {
- if (_articleNumber == -1) {
- if (_word_86F3A >= 0) {
- int articleNum = 0;
-
- if ((_word_86F42 == 2) || (_word_86F42 == 5)) {
- int objectId = _madsVm->scene()->getInterface()->getInventoryObject(_currentHotspot);
- articleNum = _madsVm->globals()->getObject(objectId)->article;
- } else if (_word_86F3A < hotspotCount) {
- articleNum = (*_madsVm->scene()->getSceneResources().hotspots)[_currentHotspot].getArticle();
- } else {
-
- }
- }
-
- } else if ((_articleNumber == kVerbLook) || (_vm->getGameType() != GType_RexNebular) ||
- (strcmp(_madsVm->globals()->getVocab(_objectDescId), fenceStr) != 0)) {
- // Write out the article
- strcat(_statusText, englishMADSArticleList[_articleNumber]);
- } else {
- // Special case for a 'fence' entry in Rex Nebular
- strcat(_statusText, overStr);
- }
-
- strcat(_statusText, " ");
- }
-
- // Append object description if necessary
- if (_word_86F3A >= 0)
- appendVocab(_objectDescId);
-
- // Remove any trailing space character
- int statusLen = strlen(_statusText);
- if ((statusLen > 0) && (_statusText[statusLen - 1] == ' '))
- _statusText[statusLen - 1] = '\0';
- }
+bool MadsScene::getDepthHighBits(const Common::Point &pt) {
+ if (_sceneResources._depthStyle == 2)
+ return 0;
- _word_83334 = -1;
+ const byte *p = _depthSurface->getBasePtr(pt.x, pt.y);
+ return (*p & 0x70) >> 4;
}
/*--------------------------------------------------------------------------*/
@@ -722,7 +635,7 @@ void MadsSceneResources::load(int sceneNumber, const char *resName, int v0, M4Su
stream->skip(24);
- int objectCount = stream->readUint16LE();
+ int nodeCount = stream->readUint16LE();
_yBandsEnd = stream->readUint16LE();
_yBandsStart = stream->readUint16LE();
_maxScale = stream->readSint16LE();
@@ -732,14 +645,20 @@ void MadsSceneResources::load(int sceneNumber, const char *resName, int v0, M4Su
stream->skip(2);
// Load in any scene objects
- for (int i = 0; i < objectCount; ++i) {
- MadsObject rec;
+ for (int i = 0; i < nodeCount; ++i) {
+ SceneNode rec;
rec.load(stream);
- _objects.push_back(rec);
+ _nodes.push_back(rec);
}
- for (int i = 0; i < 20 - objectCount; ++i)
+ for (int i = 0; i < 20 - nodeCount; ++i)
stream->skip(48);
+ // Add two extra nodes in that will be used for player movement
+ for (int i = 0; i < 2; ++i) {
+ SceneNode rec;
+ _nodes.push_back(rec);
+ }
+
int setCount = stream->readUint16LE();
stream->readUint16LE();
for (int i = 0; i < setCount; ++i) {
@@ -810,6 +729,84 @@ void MadsSceneResources::load(int sceneNumber, const char *resName, int v0, M4Su
delete depthSurface;
}
+void MadsSceneResources::setRouteNode(int nodeIndex, const Common::Point &pt, M4Surface *depthSurface) {
+ int flags, hypotenuse;
+
+ _nodes[nodeIndex].pt = pt;
+
+ // Recalculate inter-node lengths
+ for (uint idx = 0; idx < _nodes.size(); ++idx) {
+ int entry;
+ if (idx == (uint)nodeIndex) {
+ entry = 0x3FFF;
+ } else {
+ // Process the node
+ flags = getRouteFlags(pt, _nodes[idx].pt, depthSurface);
+
+ int xDiff = ABS(_nodes[idx].pt.x - pt.x);
+ int yDiff = ABS(_nodes[idx].pt.y - pt.y);
+ hypotenuse = SqrtF16(xDiff * xDiff + yDiff * yDiff);
+
+ if (hypotenuse >= 0x3FFF)
+ // Shouldn't ever be this large
+ hypotenuse = 0x3FFF;
+
+ entry = hypotenuse | flags;
+ _nodes[idx].indexes[nodeIndex] = entry;
+ _nodes[nodeIndex].indexes[idx] = entry;
+ }
+ }
+}
+
+int MadsSceneResources::getRouteFlags(const Common::Point &src, const Common::Point &dest, M4Surface *depthSurface) {
+ int result = 0x8000;
+ bool flag = false;
+
+ int xDiff = ABS(dest.x - src.x);
+ int yDiff = ABS(dest.y - src.y);
+ int xDirection = dest.x >= src.x ? 1 : -1;
+ int yDirection = dest.y >= src.y ? depthSurface->width() : -depthSurface->width();
+ int majorDiff = 0;
+ if (dest.x < src.x)
+ majorDiff = MAX(xDiff, yDiff);
+ ++xDiff;
+ ++yDiff;
+
+ byte *srcP = depthSurface->getBasePtr(src.x, src.y);
+
+ int totalCtr = majorDiff;
+ for (int xCtr = 0; xCtr < xDiff; ++xCtr, srcP += xDirection) {
+ totalCtr += yDiff;
+
+ if ((*srcP & 0x80) == 0)
+ flag = false;
+ else if (!flag) {
+ flag = true;
+ result -= 0x4000;
+ if (result == 0)
+ break;
+ }
+
+ while (totalCtr >= xDiff) {
+ totalCtr -= xDiff;
+
+ if ((*srcP & 0x80) == 0)
+ flag = false;
+ else if (!flag) {
+ flag = true;
+ result -= 0x4000;
+ if (result == 0)
+ break;
+ }
+
+ srcP += yDirection;
+ }
+ if (result == 0)
+ break;
+ }
+
+ return result;
+}
/*--------------------------------------------------------------------------*/
@@ -1024,7 +1021,7 @@ void MadsInterfaceView::onRefresh(RectList *rects, M4Surface *destSurface) {
}
bool MadsInterfaceView::onEvent(M4EventType eventType, int32 param1, int x, int y, bool &captureEvents) {
- MadsAction &act = _madsVm->scene()->getAction();
+ MadsAction &act = _madsVm->scene()->_action;
// If the mouse isn't being held down, then reset the repeated scroll timer
if (eventType != MEVENT_LEFT_HOLD)
@@ -1071,7 +1068,7 @@ bool MadsInterfaceView::onEvent(M4EventType eventType, int32 param1, int x, int
act._flags1 = obj->vocabList[1].flags1;
act._flags2 = obj->vocabList[1].flags2;
- act._currentHotspot = _selectedObject;
+ act._action.verbId = _selectedObject;
act._articleNumber = act._flags2;
}
}
@@ -1124,8 +1121,13 @@ bool MadsInterfaceView::handleCheatKey(int32 keycode) {
// TODO: Move player to current destination
return true;
- case Common::KEYCODE_t | (Common::KEYCODE_LALT):
- case Common::KEYCODE_t | (Common::KEYCODE_RALT):
+ case Common::KEYCODE_c | (Common::KBD_CTRL << 24):
+ // Toggle display of mouse position
+ _madsVm->scene()->_showMousePos = !_madsVm->scene()->_showMousePos;
+ break;
+
+ case Common::KEYCODE_t | (Common::KEYCODE_LALT << 24):
+ case Common::KEYCODE_t | (Common::KEYCODE_RALT << 24):
{
// Teleport to room
//Scene *sceneView = (Scene *)vm->_viewManager->getView(VIEWID_SCENE);