diff options
-rw-r--r-- | engines/m4/console.cpp | 5 | ||||
-rw-r--r-- | engines/m4/converse.cpp | 22 | ||||
-rw-r--r-- | engines/m4/converse.h | 19 | ||||
-rw-r--r-- | engines/m4/m4.cpp | 6 | ||||
-rw-r--r-- | engines/m4/m4.h | 8 | ||||
-rw-r--r-- | engines/m4/m4_scene.cpp | 226 | ||||
-rw-r--r-- | engines/m4/m4_scene.h | 68 | ||||
-rw-r--r-- | engines/m4/mads_scene.cpp | 647 | ||||
-rw-r--r-- | engines/m4/mads_scene.h | 199 | ||||
-rw-r--r-- | engines/m4/mads_views.h | 3 | ||||
-rw-r--r-- | engines/m4/module.mk | 2 | ||||
-rw-r--r-- | engines/m4/scene.cpp | 559 | ||||
-rw-r--r-- | engines/m4/scene.h | 123 | ||||
-rw-r--r-- | engines/m4/script.cpp | 2 | ||||
-rw-r--r-- | engines/m4/staticres.cpp | 17 | ||||
-rw-r--r-- | engines/m4/staticres.h | 13 |
16 files changed, 1225 insertions, 694 deletions
diff --git a/engines/m4/console.cpp b/engines/m4/console.cpp index 9683f4544e..8476b3ff53 100644 --- a/engines/m4/console.cpp +++ b/engines/m4/console.cpp @@ -214,8 +214,11 @@ bool Console::cmdStartConversation(int argc, const char **argv) { if (argc != 2) { DebugPrintf("Usage: %s <conversation file name>\n", argv[0]); return true; + } else if (_vm->isM4()) { + ((M4Engine *)_vm)->_converse->startConversation(argv[1]); + return false; } else { - _vm->_converse->startConversation(argv[1]); + error("MADS engine does not support conversations yet"); return false; } } diff --git a/engines/m4/converse.cpp b/engines/m4/converse.cpp index 18d61ef7ce..746ced5d11 100644 --- a/engines/m4/converse.cpp +++ b/engines/m4/converse.cpp @@ -103,7 +103,7 @@ void ConversationView::setNode(int32 nodeIndex) { _activeItems.clear(); if (nodeIndex != -1) { - ConvEntry *node = _vm->_converse->getNode(nodeIndex); + ConvEntry *node = _m4Vm->_converse->getNode(nodeIndex); for (uint i = 0; i < node->entries.size(); ++i) { if (!node->entries[i]->visible) @@ -137,7 +137,7 @@ void ConversationView::setNode(int32 nodeIndex) { //printf("Current node falls through node at offset %i when entries are less or equal than %i\n", // node->fallthroughOffset, node->fallthroughMinEntries); if (_activeItems.size() <= (uint32)node->fallthroughMinEntries) { - const EntryInfo *entryInfo = _vm->_converse->getEntryInfo(node->fallthroughOffset); + const EntryInfo *entryInfo = _m4Vm->_converse->getEntryInfo(node->fallthroughOffset); //printf("Entries are less than or equal to %i, falling through to node at offset %i, index %i\n", // node->fallthroughMinEntries, node->fallthroughOffset, entryInfo->nodeIndex); setNode(entryInfo->nodeIndex); @@ -228,7 +228,7 @@ void ConversationView::selectEntry(int entryIndex) { // Hide selected entry, unless it has a persistent flag set if (!(_activeItems[entryIndex]->flags & kEntryPersists)) { //printf("Hiding selected entry\n"); - _vm->_converse->getNode(_currentNodeIndex)->entries[entryIndex]->visible = false; + _m4Vm->_converse->getNode(_currentNodeIndex)->entries[entryIndex]->visible = false; } else { //printf("Selected entry is persistent, not hiding it\n"); } @@ -266,8 +266,8 @@ void ConversationView::playNextReply() { ConvEntry *currentEntry = _activeItems[_highlightedIndex]->entries[i]; if (currentEntry->isConditional) { - if (!_vm->_converse->evaluateCondition( - _vm->_converse->getValue(currentEntry->condition.offset), + if (!_m4Vm->_converse->evaluateCondition( + _m4Vm->_converse->getValue(currentEntry->condition.offset), currentEntry->condition.op, currentEntry->condition.val)) continue; // don't play this reply } @@ -315,7 +315,7 @@ void ConversationView::playNextReply() { //printf("Current selection does %i actions\n", _activeItems[entryIndex]->actions.size()); for (uint32 i = 0; i < _activeItems[_highlightedIndex]->actions.size(); i++) { - if (!_vm->_converse->performAction(_activeItems[_highlightedIndex]->actions[i])) + if (!_m4Vm->_converse->performAction(_activeItems[_highlightedIndex]->actions[i])) break; } // end for @@ -1220,4 +1220,14 @@ bool Converse::performAction(EntryAction *action) { } // end switch } +/*--------------------------------------------------------------------------*/ + +MadsConversation::MadsConversation() { + for (int i = 0; i < MADS_TALK_SIZE; ++i) { + _talkList[i].desc = NULL; + _talkList[i].id = 0; + } +} + + } // End of namespace M4 diff --git a/engines/m4/converse.h b/engines/m4/converse.h index 973122b9f2..609711b10f 100644 --- a/engines/m4/converse.h +++ b/engines/m4/converse.h @@ -30,8 +30,8 @@ #include "common/hashmap.h" #include "m4/globals.h" -#include "m4/m4.h" #include "m4/viewmgr.h" +#include "m4/sound.h" namespace M4 { @@ -195,6 +195,23 @@ private: void setEntryInfo(int32 offset, EntryType type, int32 nodeIndex, int32 entryIndex); }; + +struct MadsTalkEntry { + uint16 id; + const char *desc; +}; + +#define MADS_TALK_SIZE 5 + +class MadsConversation { +private: + MadsTalkEntry _talkList[MADS_TALK_SIZE]; +public: + MadsConversation(); + + MadsTalkEntry &operator[](int index) { return _talkList[index]; } +}; + } // End of namespace M4 #endif diff --git a/engines/m4/m4.cpp b/engines/m4/m4.cpp index 7b3a84e98d..5ce21b4a57 100644 --- a/engines/m4/m4.cpp +++ b/engines/m4/m4.cpp @@ -137,7 +137,6 @@ MadsM4Engine::~MadsM4Engine() { delete _inventory; delete _viewManager; delete _rails; - delete _converse; delete _script; delete _ws; delete _random; @@ -178,7 +177,6 @@ Common::Error MadsM4Engine::run() { _viewManager = new ViewManager(this); _inventory = new Inventory(this); _sound = new Sound(this, _mixer, 255); - _converse = new Converse(this); _script = new ScriptInterpreter(this); _ws = new WoodScript(this); _animation = new Animation(this); @@ -304,6 +302,7 @@ M4Engine::M4Engine(OSystem *syst, const M4GameDescription *gameDesc): MadsM4Engi M4Engine::~M4Engine() { delete _resourceManager; delete _globals; + delete _converse; } Common::Error M4Engine::run() { @@ -316,6 +315,9 @@ Common::Error M4Engine::run() { // Set up needed common functionality MadsM4Engine::run(); + // M4 specific initialisation + _converse = new Converse(this); + _scene = new M4Scene(this); _script->open("m4.dat"); diff --git a/engines/m4/m4.h b/engines/m4/m4.h index 6d79b47f5f..bebda02ca6 100644 --- a/engines/m4/m4.h +++ b/engines/m4/m4.h @@ -40,6 +40,8 @@ #include "m4/events.h" #include "m4/font.h" #include "m4/scene.h" +#include "m4/mads_scene.h" +#include "m4/m4_scene.h" #include "m4/actor.h" #include "m4/sound.h" #include "m4/rails.h" @@ -84,6 +86,7 @@ class M4InterfaceView; class ConversationView; class Actor; class Converse; +class MadsConversation; class ScriptInterpreter; class WoodScript; class Animation; @@ -193,7 +196,6 @@ public: ConversationView *_conversationView; Sound *_sound; Rails *_rails; - Converse *_converse; ScriptInterpreter *_script; WoodScript *_ws; Animation *_animation; @@ -204,6 +206,8 @@ public: class MadsEngine : public MadsM4Engine { public: + MadsConversation _converse; +public: MadsEngine(OSystem *syst, const M4GameDescription *gameDesc); virtual ~MadsEngine(); @@ -215,6 +219,8 @@ public: class M4Engine : public MadsM4Engine { public: + Converse *_converse; +public: M4Engine(OSystem *syst, const M4GameDescription *gameDesc); virtual ~M4Engine(); diff --git a/engines/m4/m4_scene.cpp b/engines/m4/m4_scene.cpp new file mode 100644 index 0000000000..1d5cc171a3 --- /dev/null +++ b/engines/m4/m4_scene.cpp @@ -0,0 +1,226 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $URL$ + * $Id$ + * + */ + +#include "common/system.h" + +#include "m4/dialogs.h" +#include "m4/globals.h" +#include "m4/scene.h" +#include "m4/events.h" +#include "m4/graphics.h" +#include "m4/rails.h" +#include "m4/font.h" +#include "m4/m4_views.h" +#include "m4/mads_views.h" +#include "m4/compression.h" + +namespace M4 { + +M4Scene::M4Scene(M4Engine *vm): Scene(vm) { + _vm = vm; + _sceneSprites = NULL; + _interfaceSurface = new M4InterfaceView(vm); +} + +M4Scene::~M4Scene() { + delete _sceneSprites; +} + +void M4Scene::loadSceneSprites(int sceneNumber) { + char filename[kM4MaxFilenameSize]; + sprintf(filename, "%i.ssb", sceneNumber); + + Common::SeekableReadStream *sceneS = _vm->res()->get(filename); + _sceneSprites = new SpriteAsset(_vm, sceneS, sceneS->size(), filename); + _vm->res()->toss(filename); + + printf("Scene has %d sprites, each one having %d colors\n", _sceneSprites->getCount(), _sceneSprites->getColorCount()); +} + +void M4Scene::loadScene(int sceneNumber) { + Scene::loadScene(sceneNumber); + + _backgroundSurface->loadBackground(sceneNumber); + _palData = NULL; + + if (_vm->getGameType() == GType_Burger && + sceneNumber != TITLE_SCENE_BURGER && sceneNumber != MAINMENU_SCENE_BURGER) + setStatusText(""); + + // Load scene def file (*.CHK) + loadSceneResources(sceneNumber); + loadSceneInverseColorTable(sceneNumber); + + // TODO: set walker scaling + // TODO: destroy woodscript buffer + + // Load scene walk path file (*.COD/*.WW?) + loadSceneCodes(sceneNumber); + + // Load inverse color table file (*.IPL) + loadSceneInverseColorTable(sceneNumber); + + if (_vm->getGameType() != GType_Burger) { + // Load scene sprites file (*.SSB) + loadSceneSprites(sceneNumber); + + // Load scene sprite codes file (*.SSC) + loadSceneSpriteCodes(sceneNumber); + } + + + if (sceneNumber != TITLE_SCENE_BURGER && sceneNumber != MAINMENU_SCENE_BURGER) { + _m4Vm->scene()->getInterface()->show(); + showSprites(); + } + + // Purge resources + _vm->res()->purge(); +} + +void M4Scene::loadSceneCodes(int sceneNumber, int index) { + char filename[kM4MaxFilenameSize]; + Common::SeekableReadStream *sceneS; + + sprintf(filename, "%i.cod", sceneNumber); + sceneS = _vm->res()->openFile(filename); + _walkSurface->loadCodesM4(sceneS); + _vm->res()->toss(filename); +} + +void M4Scene::show() { + Scene::show(); + _vm->_viewManager->addView(_interfaceSurface); +} + +void M4Scene::checkHotspotAtMousePos(int x, int y) { + if (_vm->getGameType() == GType_Riddle) + return; + + // TODO: loads of things to do here, only the mouse cursor and the status + // text is changed for now + + // Only scene hotspots are checked for now, not parallax/props, as the + // latter ones are not used by Orion Burger + HotSpot *currentHotSpot = _sceneResources.hotspots->findByXY(x, y); + if (currentHotSpot != NULL && currentHotSpot->getActive()) { + if (_vm->_mouse->getCursorNum() != CURSOR_LOOK && + _vm->_mouse->getCursorNum() != CURSOR_TAKE && + _vm->_mouse->getCursorNum() != CURSOR_USE && + _m4Vm->scene()->getInterface()->_inventory.getSelectedIndex() == -1) { + _vm->_mouse->setCursorNum(currentHotSpot->getCursor()); + } + _m4Vm->scene()->getInterface()->setStatusText(currentHotSpot->getPrep()); + } else { + if (_vm->_mouse->getCursorNum() != CURSOR_LOOK && + _vm->_mouse->getCursorNum() != CURSOR_TAKE && + _vm->_mouse->getCursorNum() != CURSOR_USE && + _m4Vm->scene()->getInterface()->_inventory.getSelectedIndex() == -1) { + _vm->_mouse->setCursorNum(0); + } else { + + } + } +} + +void M4Scene::leftClick(int x, int y) { + if (_vm->getGameType() == GType_Burger) { + // Place a Wilbur sprite with the correct facing + HotSpot *currentHotSpot = _sceneResources.hotspots->findByXY(x, y); + if (currentHotSpot != NULL && currentHotSpot->getActive()) { + update(); + _vm->_actor->setWalkerDirection(currentHotSpot->getFacing()); + /* + int posX = currentHotSpot->getFeetX(); + int posY = currentHotSpot->getFeetY() - + scaleValue(_vm->_actor->getWalkerHeight(), _vm->_actor->getWalkerScaling(), 0); + //_vm->_actor->placeWalkerSpriteAt(0, posX, posY); + */ + + // Player said.... (for scene scripts) + printf("Player said: %s %s\n", currentHotSpot->getVerb(), currentHotSpot->getVocab()); + + // FIXME: This should be moved somewhere else, and is incomplete + if (_m4Vm->scene()->getInterface()->_inventory.getSelectedIndex() == -1) { + if (_vm->_mouse->getVerb() == NULL) { + strcpy(_vm->_player->verb, currentHotSpot->getVerb()); + } else { + strcpy(_vm->_player->verb, _vm->_mouse->getVerb()); + } + } else { + strcpy(_vm->_player->verb, _m4Vm->scene()->getInterface()->_inventory.getSelectedObjectName()); + } + strcpy(_vm->_player->noun, currentHotSpot->getVocab()); + strcpy(_vm->_player->object, ""); + _vm->_player->commandReady = true; + + printf("## Player said: %s %s\n", _vm->_player->verb, _vm->_player->noun); + + } + } +} + +void M4Scene::rightClick(int x, int y) { + if (_vm->getGameType() == GType_Burger) { + nextCommonCursor(); + _m4Vm->scene()->getInterface()->_inventory.clearSelected(); + } +} + +void M4Scene::setAction(int action, int objectId) { +} + +void M4Scene::setStatusText(const char *text) { + getInterface()->setStatusText(text); +} + +void M4Scene::update() { + +} + +void M4Scene::nextCommonCursor() { + int cursorIndex = _vm->_mouse->getCursorNum(); + + switch (cursorIndex) { + case CURSOR_ARROW: + cursorIndex = CURSOR_LOOK; + break; + case CURSOR_LOOK: + cursorIndex = CURSOR_TAKE; + break; + case CURSOR_TAKE: + cursorIndex = CURSOR_USE; + break; + case CURSOR_USE: + cursorIndex = CURSOR_ARROW; + break; + default: + cursorIndex = CURSOR_ARROW; + } + + _vm->_mouse->setCursorNum(cursorIndex); +} + +} // End of namespace M4 diff --git a/engines/m4/m4_scene.h b/engines/m4/m4_scene.h new file mode 100644 index 0000000000..be04a52dce --- /dev/null +++ b/engines/m4/m4_scene.h @@ -0,0 +1,68 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $URL$ + * $Id$ + * + */ + +#ifndef M4_M4_SCENE_H +#define M4_M4_SCENE_H + +class View; + +#include "m4/scene.h" + +namespace M4 { + +#define TITLE_SCENE_BURGER 951 // 951 = intro, 901 = demo menu, 971 = first scene +#define MAINMENU_SCENE_BURGER 903 +#define FIRST_SCENE 101 + +class M4Scene : public Scene { +private: + M4Engine *_vm; + SpriteAsset *_sceneSprites; + SpriteAsset *_walkerSprite; + + void loadSceneSprites(int sceneNumber); + void nextCommonCursor(); +public: + M4Scene(M4Engine *vm); + virtual ~M4Scene(); + + // Methods that differ between engines + virtual void loadScene(int sceneNumber); + virtual void leaveScene() {}; + virtual void loadSceneCodes(int sceneNumber, int index = 0); + virtual void show(); + virtual void checkHotspotAtMousePos(int x, int y); + virtual void leftClick(int x, int y); + virtual void rightClick(int x, int y); + virtual void setAction(int action, int objectId = -1); + virtual void setStatusText(const char *text); + virtual void update(); + + M4InterfaceView *getInterface() { return (M4InterfaceView *)_interfaceSurface; }; +}; + +} // End of namespace M4 + +#endif diff --git a/engines/m4/mads_scene.cpp b/engines/m4/mads_scene.cpp new file mode 100644 index 0000000000..51f4cb72ba --- /dev/null +++ b/engines/m4/mads_scene.cpp @@ -0,0 +1,647 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $URL$ + * $Id$ + * + */ + +#include "common/system.h" + +#include "m4/mads_scene.h" +#include "m4/dialogs.h" +#include "m4/globals.h" +#include "m4/scene.h" +#include "m4/events.h" +#include "m4/graphics.h" +#include "m4/rails.h" +#include "m4/font.h" +#include "m4/m4_views.h" +#include "m4/mads_views.h" +#include "m4/compression.h" +#include "m4/staticres.h" + +namespace M4 { + +MadsScene::MadsScene(MadsEngine *vm): Scene(vm) { + _vm = vm; + + strcpy(_statusText, ""); + _interfaceSurface = new MadsInterfaceView(vm); + _spriteSlotsStart = 0; + for (int i = 0; i < 3; ++i) + actionNouns[i] = 0; +} + +/** + * Secondary scene loading code + */ +void MadsScene::loadScene2(const char *aaName) { + // Load up the properties for the scene + _sceneInfo.load(_currentScene); + + // Load scene walk paths + loadSceneCodes(_currentScene); +} + +/** + * Existing ScummVM code that needs to be eventually replaced with MADS code + */ +void MadsScene::loadSceneTemporary() { + /* Existing code that eventually needs to be replaced with the proper MADS code */ + // Set system palette entries + _vm->_palette->blockRange(0, 7); + RGB8 sysColors[3] = { {0x1f<<2, 0x2d<<2, 0x31<<2, 0}, {0x24<<2, 0x37<<2, 0x3a<<2, 0}, + {0x00<<2, 0x10<<2, 0x16<<2, 0}}; + _vm->_palette->setPalette(&sysColors[0], 4, 3); + + _backgroundSurface->loadBackground(_currentScene, &_palData); + _vm->_palette->addRange(_palData); + _backgroundSurface->translate(_palData); + + if (_currentScene < 900) { + /*_backgroundSurface->fillRect(Common::Rect(0, MADS_SURFACE_HEIGHT, + _backgroundSurface->width(), _backgroundSurface->height()), + _vm->_palette->BLACK);*/ + // TODO: interface palette + _interfaceSurface->madsloadInterface(0, &_interfacePal); + _vm->_palette->addRange(_interfacePal); + _interfaceSurface->translate(_interfacePal); + _backgroundSurface->copyFrom(_interfaceSurface, Common::Rect(0, 0, 320, 44), 0, 200 - 44); + + _interfaceSurface->initialise(); + } + + // Don't load other screen resources for system screens + if (_currentScene >= 900) + return; + + loadSceneHotSpotsMads(_currentScene); + + // TODO: set walker scaling + // TODO: destroy woodscript buffer + + // Load inverse color table file (*.IPL) + loadSceneInverseColorTable(_currentScene); +} + +void MadsScene::loadScene(int sceneNumber) { + // Close the menu if it's active + View *mainMenu = _vm->_viewManager->getView(VIEWID_MAINMENU); + if (mainMenu != NULL) { + _vm->_viewManager->deleteView(mainMenu); + } + + // Handle common scene setting + Scene::loadScene(sceneNumber); + + // Signal the script engine what scene is to be active + _sceneLogic.selectScene(sceneNumber); + _sceneLogic.setupScene(); + + // Add the scene if necessary to the list of scenes that have been visited + _vm->globals()->addVisitedScene(sceneNumber); + + // Secondary scene load routine + loadScene2("*I0.AA"); + + // Do any scene specific setup + _sceneLogic.enterScene(); + + // Existing ScummVM code that needs to be eventually replaced with MADS code + loadSceneTemporary(); + + // Purge resources + _vm->res()->purge(); +} + +void MadsScene::leaveScene() { + _sceneResources.hotspots->clear(); + _sceneResources.parallax->clear(); + _sceneResources.props->clear(); + + delete _sceneResources.hotspots; + delete _sceneResources.parallax; + delete _sceneResources.props; + + // Delete the sprites + for (uint i = 0; i <_sceneSprites.size(); ++i) delete _sceneSprites[i]; + _sceneSprites.clear(); + + delete _backgroundSurface; + delete _walkSurface; + + Scene::leaveScene(); +} + +void MadsScene::show() { + Scene::show(); + _vm->_viewManager->addView(_interfaceSurface); +} + +void MadsScene::loadSceneCodes(int sceneNumber, int index) { + char filename[kM4MaxFilenameSize]; + Common::SeekableReadStream *sceneS; + + if (_vm->getGameType() == GType_Phantom || _vm->getGameType() == GType_DragonSphere) { + sprintf(filename, "rm%i.ww%i", sceneNumber, index); + MadsPack walkData(filename, _vm); + sceneS = walkData.getItemStream(0); + _walkSurface->loadCodesMads(sceneS); + _vm->res()->toss(filename); + } else if (_vm->getGameType() == GType_RexNebular) { + // For Rex Nebular, the walk areas are part of the scene info + byte *destP = _walkSurface->getBasePtr(0, 0); + const byte *srcP = _sceneInfo.walkData; + byte runLength; + while ((runLength = *srcP++) != 0) { + Common::set_to(destP, destP + runLength, *srcP++); + destP += runLength; + } + } +} + +void MadsScene::checkHotspotAtMousePos(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()); + + 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); + } +} + +void MadsScene::rightClick(int x, int y) { + // ***DEBUG*** - sample dialog display + int idx = 3; //_madsVm->_globals->messageIndexOf(0x277a); + const char *msg = _madsVm->globals()->loadMessage(idx); + Dialog *dlg = new Dialog(_vm, msg, "TEST DIALOG"); + _vm->_viewManager->addView(dlg); + _vm->_viewManager->moveToFront(dlg); +} + +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 + // a second object can be selected, as in 'use gun to shoot person', with requires a target +/* + // Set up the new action + strcpy(statusText, _madsVm->globals()->getVocab(action)); + statusText[0] = toupper(statusText[0]); // capitalize first letter + + if (objectId != -1) { + MadsObject *obj = _madsVm->globals()->getObject(objectId); + sprintf(statusText + strlen(statusText), " %s", _madsVm->globals()->getVocab(obj->descId)); + } else { + _currentAction = action; + } +*/ + setStatusText(statusText); +} + +void MadsScene::setStatusText(const char *text) { + strcpy(_statusText, text); +} + +/** + * Draws all the elements of the scene + */ +void MadsScene::drawElements() { + + // Display animations + for (int idx = 0; idx < _spriteSlotsStart; ++idx) { + + } + + + // Text display + _textDisplay.draw(this); + + // Copy the user interface surface onto the surface + _interfaceSurface->copyTo(this, 0, this->height() - _interfaceSurface->height()); + +/* + // At this point, in the original engine, the dirty/changed areas were copied to the screen. At the moment, + // the current M4 engine framework doesn't support dirty areas, but this is being kept in case that ever changes + for (int idx = 0; idx < DIRTY_AREA_SIZE; ++idx) { + if (_dirtyAreas[idx].active && _dirtyAreas[idx].active2 && + (_dirtyAreas[idx].bounds.width() > 0) && (_dirtyAreas[idx].bounds.height() > 0)) { + // Copy changed area to screen + + } + } +*/ + + // Some kind of copying over of slot entries + for (int idx = 0, idx2 = 0; idx < _spriteSlotsStart; ++idx) { + if (_spriteSlots[idx].spriteId >= 0) { + if (idx != idx2) { + // Copy over the slot entry + _spriteSlots[idx2] = _spriteSlots[idx]; + } + ++idx2; + } + } +} + + +void MadsScene::update() { + // Copy the bare scene in + _backgroundSurface->copyTo(this); + + // Draw all the various elements + drawElements(); + + // Handle display of any status text + if (_statusText[0]) { + // Text colors are inverted in Dragonsphere + if (_vm->getGameType() == GType_DragonSphere) + _vm->_font->setColors(_vm->_palette->BLACK, _vm->_palette->WHITE, _vm->_palette->BLACK); + else + _vm->_font->setColors(_vm->_palette->WHITE, _vm->_palette->BLACK, _vm->_palette->BLACK); + + _vm->_font->setFont(FONT_MAIN_MADS); + _vm->_font->writeString(this, _statusText, (width() - _vm->_font->getWidth(_statusText)) / 2, 142, 0); + } + + //***DEBUG*** + _sceneSprites[0]->getFrame(1)->copyTo(this, 120, 90, 0); +} + +int MadsScene::loadSceneSpriteSet(const char *setName) { + char resName[100]; + strcpy(resName, setName); + + // Append a '.SS' if it doesn't alreayd have an extension + if (!strchr(resName, '.')) + strcat(resName, ".SS"); + + Common::SeekableReadStream *data = _vm->res()->get(resName); + SpriteAsset *spriteSet = new SpriteAsset(_vm, data, data->size(), resName); + spriteSet->translate(_vm->_palette); + _vm->res()->toss(resName); + + _sceneSprites.push_back(spriteSet); + return _sceneSprites.size() - 1; +} + +void MadsScene::loadPlayerSprites(const char *prefix) { + const char suffixList[8] = { '8', '9', '6', '3', '2', '7', '4', '1' }; + char setName[80]; + + strcpy(setName, "*"); + strcat(setName, prefix); + strcat(setName, "_0.SS"); + char *digitP = strchr(setName, '_') + 1; + + for (int idx = 0; idx < 8; ++idx) { + *digitP = suffixList[idx]; + + if (_vm->res()->resourceExists(setName)) { + loadSceneSpriteSet(setName); + return; + } + } + + error("Couldn't find player sprites"); +} + +/*--------------------------------------------------------------------------*/ + +MadsAction::MadsAction() { + clear(); +} + +void MadsAction::clear() { + _actionMode = ACTMODE_NONE; + _articleNumber = 0; + _lookFlag = false; + _statusText[0] = '\0'; + _selectedRow = -1; + _currentHotspot = -1; + //word_86F3A/word_86F4C + _currentAction = kVerbNone; + _objectNameId = -1; + _objectDescId = -1; + //word_83334 +} + +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); + + strcat(s, " "); +} + +void MadsAction::set() { + 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) { + + } + + //loc_21CE2 + } + } + } + + //word_83334 = -1; +} + +/*--------------------------------------------------------------------------*/ + +void MadsSceneInfo::load(int sId) { + const char *sceneInfoStr = MADSResourceManager::getResourceName(RESPREFIX_RM, sId, ".DAT"); + Common::SeekableReadStream *rawStream = _vm->_resourceManager->get(sceneInfoStr); + MadsPack sceneInfo(rawStream); + + // Basic scene info + Common::SeekableReadStream *stream = sceneInfo.getItemStream(0); + + int resSceneId = stream->readUint16LE(); + assert(resSceneId == sId); + + artFileNum = stream->readUint16LE(); + field_4 = stream->readUint16LE(); + width = stream->readUint16LE(); + height = stream->readUint16LE(); + assert((width == 320) && (height == 156)); + + stream->skip(24); + + objectCount = stream->readUint16LE(); + + stream->skip(40); + + for (int i = 0; i < objectCount; ++i) { + objects[i].load(stream); + } + + // For Rex Nebular, read in the scene's compressed walk surface information + if (_vm->getGameType() == GType_RexNebular) { + delete walkData; + + stream = sceneInfo.getItemStream(1); + walkData = (byte *)malloc(stream->size()); + stream->read(walkData, stream->size()); + } + + _vm->_resourceManager->toss(sceneInfoStr); +} + +/*--------------------------------------------------------------------------*/ + +MadsScreenText::MadsScreenText() { + for (int i = 0; i < TEXT_DISPLAY_SIZE; ++i) + _textDisplay[i].active = false; + for (int i = 0; i < TIMED_TEXT_SIZE; ++i) + _timedText[i].flags = 0; + _abortTimedText = false; +} + +/** + * Adds the specified string to the list of on-screen display text + */ +int MadsScreenText::add(const Common::Point &destPos, uint fontColours, int widthAdjust, const char *msg, Font *font) { + // Find a free slot + int idx = 0; + while ((idx < TEXT_DISPLAY_SIZE) && _textDisplay[idx].active) + ++idx; + if (idx == TEXT_DISPLAY_SIZE) + error("Ran out of text display slots"); + + // Set up the entry values + _textDisplay[idx].active = true; + _textDisplay[idx].active2 = 1; + _textDisplay[idx].bounds.left = destPos.x; + _textDisplay[idx].bounds.top = destPos.y; + _textDisplay[idx].bounds.setWidth(font->getWidth(msg, widthAdjust)); + _textDisplay[idx].bounds.setHeight(font->getHeight()); + _textDisplay[idx].font = font; + strncpy(_textDisplay[idx].message, msg, 100); + _textDisplay[idx].message[99] = '\0'; + _textDisplay[idx].colour1 = fontColours & 0xff; + _textDisplay[idx].colour2 = fontColours >> 8; + _textDisplay[idx].spacing = widthAdjust; + + return idx; +} + +/** + * Adds a new entry to the timed on-screen text display list + */ +int MadsScreenText::addTimed(const Common::Point &destPos, uint fontColours, uint flags, int vUnknown, uint32 timeout, const char *message) { + // Find a free slot + int idx = 0; + while ((idx < TIMED_TEXT_SIZE) && ((_timedText[idx].flags & TEXTFLAG_ACTIVE) != 0)) + ++idx; + if (idx == TIMED_TEXT_SIZE) { + if (vUnknown == 0) + return -1; + + error("Ran out of timed text display slots"); + } + + // Set up the entry values + _timedText[idx].flags = flags | TEXTFLAG_ACTIVE; + strcpy(_timedText[idx].message, message); + _timedText[idx].colour1 = fontColours & 0xff; + _timedText[idx].colour2 = fontColours >> 8; + _timedText[idx].position.x = destPos.x; + _timedText[idx].position.y = destPos.y; + _timedText[idx].textDisplayIndex = -1; + _timedText[idx].timeout = timeout; + _timedText[idx].frameTimer = g_system->getMillis(); + _timedText[idx].field_1C = vUnknown; + _timedText[idx].field_1D = 0; /* word_84206 */ + + // Copy the current action noun list + for (int i = 0; i < 3; ++i) + _timedText[idx].actionNouns[i] = _madsVm->scene()->actionNouns[i]; + + if (flags & TEXTFLAG_2) { + warning("word_844b8 and dword_845a0 not yet implemented"); + } + + return idx; +} + +/** + * Draws any text display entries to the screen + */ +void MadsScreenText::draw(M4Surface *surface) { + for (int idx = 0; idx < TEXT_DISPLAY_SIZE; ++idx) { + if (_textDisplay[idx].active && (_textDisplay[idx].active2 >= 0)) { + _textDisplay[idx].font->setColours(_textDisplay[idx].colour1, 0xFF, + (_textDisplay[idx].colour2 == 0) ? _textDisplay[idx].colour1 : _textDisplay[idx].colour2); + _textDisplay[idx].font->writeString(surface, _textDisplay[idx].message, + _textDisplay[idx].bounds.left, _textDisplay[idx].bounds.top, _textDisplay[idx].bounds.width(), + _textDisplay[idx].spacing); + } + } + + // Clear up any now inactive text display entries + for (int idx = 0; idx < TEXT_DISPLAY_SIZE; ++idx) { + if (_textDisplay[idx].active2 < 0) { + _textDisplay[idx].active = false; + _textDisplay[idx].active2 = 0; + } + } +} + +void MadsScreenText::timedDisplay() { + for (int idx = 0; !_abortTimedText && (idx < TEXT_DISPLAY_SIZE); ++idx) { + if (((_timedText[idx].flags & TEXTFLAG_ACTIVE) != 0) && + (_timedText[idx].frameTimer <= g_system->getMillis())) + // Add the specified entry + addTimedText(&_timedText[idx]); + } +} + +void MadsScreenText::addTimedText(TimedText *entry) { + if ((entry->flags & TEXTFLAG_40) != 0) { + this->setActive2(entry->textDisplayIndex); + entry->flags &= 0x7F; + return; + } + + if ((entry->flags & TEXTFLAG_8) == 0) + // FIXME: Adjust timeouts for ScumVM's milli counter + entry->timeout -= 3; + + if ((entry->flags & TEXTFLAG_4) != 0) { + Text4A &rec = _text4A[entry->unk4AIndex]; + if ((rec.field25 != 0) || (rec.active == 0)) + entry->timeout = 0; + } + + if ((entry->timeout == 0) && !_abortTimedText) { + entry->flags |= TEXTFLAG_40; + + if (entry->field_1C) { + _abortTimedText = entry->field_1C; + //word_84208 = entry->field_1D; + + if (entry->field_1D != 1) { + // Restore the action list + for (int i = 0; i < 3; ++i) + _madsVm->scene()->actionNouns[i] = entry->actionNouns[i]; + } + } + } + + // TODO: code from 'loc_244ec' onwards +} + +} // End of namespace M4 diff --git a/engines/m4/mads_scene.h b/engines/m4/mads_scene.h new file mode 100644 index 0000000000..321c13103e --- /dev/null +++ b/engines/m4/mads_scene.h @@ -0,0 +1,199 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $URL$ + * $Id$ + * + */ + +#ifndef M4_MADS_SCENE_H +#define M4_MADS_SCENE_H + +#include "m4/scene.h" + +namespace M4 { + +#define INTERFACE_HEIGHT 106 +#define MADS_SURFACE_HEIGHT 156 + +struct SpriteSlot { + int16 spriteId; + int16 scale; + uint16 spriteListIndex; +}; + +struct DirtyArea { + bool active; + bool active2; + Common::Rect bounds; +}; + +class MadsSceneInfo { +public: + int sceneId; + int artFileNum; + int field_4; + int width; + int height; + + int objectCount; + MadsObject objects[32]; + + int walkSize; + byte *walkData; + + MadsSceneInfo() { walkSize = 0; walkData = NULL; } + ~MadsSceneInfo() { delete walkData; } + void load(int sceneId); +}; + +#define TIMED_TEXT_SIZE 10 +#define TEXT_DISPLAY_SIZE 40 +#define TEXT_4A_SIZE 30 + +enum TalkTextFlags {TEXTFLAG_2 = 2, TEXTFLAG_4 = 4, TEXTFLAG_8 = 8, TEXTFLAG_40 = 0x40, + TEXTFLAG_ACTIVE = 0x80}; + +struct TextDisplay { + bool active; + int spacing; + int16 active2; + Common::Rect bounds; + int colour1, colour2; + Font *font; + char message[100]; +}; + +struct TimedText { + uint8 flags; + int colour1; + int colour2; + Common::Point position; + int textDisplayIndex; + int unk4AIndex; + uint32 timeout; + uint32 frameTimer; + bool field_1C; + uint8 field_1D; + uint16 actionNouns[3]; + char message[100]; +}; + +struct Text4A { + uint8 active; + uint8 field25; +}; + +class MadsScreenText { +private: + TextDisplay _textDisplay[TEXT_DISPLAY_SIZE]; + TimedText _timedText[TIMED_TEXT_SIZE]; + Text4A _text4A[TEXT_4A_SIZE]; + bool _abortTimedText; + + void addTimedText(TimedText *entry); +public: + MadsScreenText(); + + // TextDisplay list + int add(const Common::Point &destPos, uint fontColours, int widthAdjust, const char *msg, Font *font); + void setActive2(int16 idx) { _textDisplay[idx].active2 = -1; } + // TimedText list + int addTimed(const Common::Point &destPos, uint fontColours, uint flags, int vUnknown, uint32 timeout, const char *message); + + void draw(M4Surface *surface); + void timedDisplay(); +}; + +enum MadsActionMode {ACTMODE_NONE = 0, ACTMODE_VERB = 1, ACTMODE_OBJECT = 3, ACTMODE_TALK = 6}; + +class MadsAction { +private: + char _statusText[100]; + int _currentHotspot; + int _objectNameId; + int _objectDescId; + int _currentAction; + int8 _flags1, _flags2; + MadsActionMode _actionMode; + int _articleNumber; + bool _lookFlag; + int _selectedRow; + + void appendVocab(int vocabId, bool capitalise = false); +public: + MadsAction(); + + void clear(); + void set(); +}; + +typedef Common::Array<SpriteAsset *> SpriteAssetArray; + +#define SPRITE_SLOTS_SIZE 50 +#define DIRTY_AREA_SIZE 90 + +class MadsScene : public Scene { +private: + MadsEngine *_vm; + char _statusText[100]; + + MadsSceneLogic _sceneLogic; + MadsSceneInfo _sceneInfo; + SpriteAsset *_playerSprites; + SpriteAssetArray _sceneSprites; + SpriteSlot _spriteSlots[50]; + MadsScreenText _textDisplay; + DirtyArea _dirtyAreas[DIRTY_AREA_SIZE]; + int _spriteSlotsStart; + + void drawElements(); + void loadScene2(const char *aaName); + void loadSceneTemporary(); + void clearAction(); + void appendActionVocab(int vocabId, bool capitalise); + void setAction(); +public: + char _aaName[100]; + uint16 actionNouns[3]; +public: + MadsScene(MadsEngine *vm); + + // Methods that differ between engines + virtual void loadScene(int sceneNumber); + virtual void leaveScene(); + virtual void loadSceneCodes(int sceneNumber, int index = 0); + virtual void show(); + virtual void checkHotspotAtMousePos(int x, int y); + virtual void leftClick(int x, int y); + virtual void rightClick(int x, int y); + virtual void setAction(int action, int objectId = -1); + virtual void setStatusText(const char *text); + virtual void update(); + + int loadSceneSpriteSet(const char *setName); + void loadPlayerSprites(const char *prefix); + + MadsInterfaceView *getInterface() { return (MadsInterfaceView *)_interfaceSurface; }; +}; + +} // End of namespace M4 + +#endif diff --git a/engines/m4/mads_views.h b/engines/m4/mads_views.h index d984f77589..fa6247d4a9 100644 --- a/engines/m4/mads_views.h +++ b/engines/m4/mads_views.h @@ -34,6 +34,8 @@ namespace M4 { +#define CHEAT_SEQUENCE_MAX 8 + class IntegerList : public Common::Array<int> { public: int indexOf(int v) { @@ -74,6 +76,7 @@ public: virtual void initialise(); virtual void setSelectedObject(int objectNumber); virtual void addObjectToInventory(int objectNumber); + int getSelectedObject() { return _selectedObject; } void onRefresh(RectList *rects, M4Surface *destSurface); bool onEvent(M4EventType eventType, int32 param1, int x, int y, bool &captureEvents); diff --git a/engines/m4/module.mk b/engines/m4/module.mk index d88536fa1a..1b08ea2188 100644 --- a/engines/m4/module.mk +++ b/engines/m4/module.mk @@ -17,10 +17,12 @@ MODULE_OBJS = \ hotspot.o \ m4.o \ m4_menus.o \ + m4_scene.o \ m4_views.o \ mads_anim.o \ mads_logic.o \ mads_menus.o \ + mads_scene.o \ mads_views.o \ midi.o \ rails.o \ diff --git a/engines/m4/scene.cpp b/engines/m4/scene.cpp index 673a375fa2..a9905f5b2f 100644 --- a/engines/m4/scene.cpp +++ b/engines/m4/scene.cpp @@ -406,563 +406,4 @@ void Scene::showMADSV2TextBox(char *text, int x, int y, char *faceName) { boxSprites->getFrame(bottomRight)->copyTo(_backgroundSurface, curX, curY + 1); } -/*--------------------------------------------------------------------------*/ - -M4Scene::M4Scene(M4Engine *vm): Scene(vm) { - _vm = vm; - _sceneSprites = NULL; - _interfaceSurface = new M4InterfaceView(vm); -} - -M4Scene::~M4Scene() { - delete _sceneSprites; -} - -void M4Scene::loadSceneSprites(int sceneNumber) { - char filename[kM4MaxFilenameSize]; - sprintf(filename, "%i.ssb", sceneNumber); - - Common::SeekableReadStream *sceneS = _vm->res()->get(filename); - _sceneSprites = new SpriteAsset(_vm, sceneS, sceneS->size(), filename); - _vm->res()->toss(filename); - - printf("Scene has %d sprites, each one having %d colors\n", _sceneSprites->getCount(), _sceneSprites->getColorCount()); -} - -void M4Scene::loadScene(int sceneNumber) { - Scene::loadScene(sceneNumber); - - _backgroundSurface->loadBackground(sceneNumber); - _palData = NULL; - - if (_vm->getGameType() == GType_Burger && - sceneNumber != TITLE_SCENE_BURGER && sceneNumber != MAINMENU_SCENE_BURGER) - setStatusText(""); - - // Load scene def file (*.CHK) - loadSceneResources(sceneNumber); - loadSceneInverseColorTable(sceneNumber); - - // TODO: set walker scaling - // TODO: destroy woodscript buffer - - // Load scene walk path file (*.COD/*.WW?) - loadSceneCodes(sceneNumber); - - // Load inverse color table file (*.IPL) - loadSceneInverseColorTable(sceneNumber); - - if (_vm->getGameType() != GType_Burger) { - // Load scene sprites file (*.SSB) - loadSceneSprites(sceneNumber); - - // Load scene sprite codes file (*.SSC) - loadSceneSpriteCodes(sceneNumber); - } - - - if (sceneNumber != TITLE_SCENE_BURGER && sceneNumber != MAINMENU_SCENE_BURGER) { - _m4Vm->scene()->getInterface()->show(); - showSprites(); - } - - // Purge resources - _vm->res()->purge(); -} - -void M4Scene::loadSceneCodes(int sceneNumber, int index) { - char filename[kM4MaxFilenameSize]; - Common::SeekableReadStream *sceneS; - - sprintf(filename, "%i.cod", sceneNumber); - sceneS = _vm->res()->openFile(filename); - _walkSurface->loadCodesM4(sceneS); - _vm->res()->toss(filename); -} - -void M4Scene::show() { - Scene::show(); - _vm->_viewManager->addView(_interfaceSurface); -} - -void M4Scene::checkHotspotAtMousePos(int x, int y) { - if (_vm->getGameType() == GType_Riddle) - return; - - // TODO: loads of things to do here, only the mouse cursor and the status - // text is changed for now - - // Only scene hotspots are checked for now, not parallax/props, as the - // latter ones are not used by Orion Burger - HotSpot *currentHotSpot = _sceneResources.hotspots->findByXY(x, y); - if (currentHotSpot != NULL && currentHotSpot->getActive()) { - if (_vm->_mouse->getCursorNum() != CURSOR_LOOK && - _vm->_mouse->getCursorNum() != CURSOR_TAKE && - _vm->_mouse->getCursorNum() != CURSOR_USE && - _m4Vm->scene()->getInterface()->_inventory.getSelectedIndex() == -1) { - _vm->_mouse->setCursorNum(currentHotSpot->getCursor()); - } - _m4Vm->scene()->getInterface()->setStatusText(currentHotSpot->getPrep()); - } else { - if (_vm->_mouse->getCursorNum() != CURSOR_LOOK && - _vm->_mouse->getCursorNum() != CURSOR_TAKE && - _vm->_mouse->getCursorNum() != CURSOR_USE && - _m4Vm->scene()->getInterface()->_inventory.getSelectedIndex() == -1) { - _vm->_mouse->setCursorNum(0); - } else { - - } - } -} - -void M4Scene::leftClick(int x, int y) { - if (_vm->getGameType() == GType_Burger) { - // Place a Wilbur sprite with the correct facing - HotSpot *currentHotSpot = _sceneResources.hotspots->findByXY(x, y); - if (currentHotSpot != NULL && currentHotSpot->getActive()) { - update(); - _vm->_actor->setWalkerDirection(currentHotSpot->getFacing()); - /* - int posX = currentHotSpot->getFeetX(); - int posY = currentHotSpot->getFeetY() - - scaleValue(_vm->_actor->getWalkerHeight(), _vm->_actor->getWalkerScaling(), 0); - //_vm->_actor->placeWalkerSpriteAt(0, posX, posY); - */ - - // Player said.... (for scene scripts) - printf("Player said: %s %s\n", currentHotSpot->getVerb(), currentHotSpot->getVocab()); - - // FIXME: This should be moved somewhere else, and is incomplete - if (_m4Vm->scene()->getInterface()->_inventory.getSelectedIndex() == -1) { - if (_vm->_mouse->getVerb() == NULL) { - strcpy(_vm->_player->verb, currentHotSpot->getVerb()); - } else { - strcpy(_vm->_player->verb, _vm->_mouse->getVerb()); - } - } else { - strcpy(_vm->_player->verb, _m4Vm->scene()->getInterface()->_inventory.getSelectedObjectName()); - } - strcpy(_vm->_player->noun, currentHotSpot->getVocab()); - strcpy(_vm->_player->object, ""); - _vm->_player->commandReady = true; - - printf("## Player said: %s %s\n", _vm->_player->verb, _vm->_player->noun); - - } - } -} - -void M4Scene::rightClick(int x, int y) { - if (_vm->getGameType() == GType_Burger) { - nextCommonCursor(); - _m4Vm->scene()->getInterface()->_inventory.clearSelected(); - } -} - -void M4Scene::setAction(int action, int objectId) { -} - -void M4Scene::setStatusText(const char *text) { - getInterface()->setStatusText(text); -} - -void M4Scene::update() { - -} - -void M4Scene::nextCommonCursor() { - int cursorIndex = _vm->_mouse->getCursorNum(); - - switch (cursorIndex) { - case CURSOR_ARROW: - cursorIndex = CURSOR_LOOK; - break; - case CURSOR_LOOK: - cursorIndex = CURSOR_TAKE; - break; - case CURSOR_TAKE: - cursorIndex = CURSOR_USE; - break; - case CURSOR_USE: - cursorIndex = CURSOR_ARROW; - break; - default: - cursorIndex = CURSOR_ARROW; - } - - _vm->_mouse->setCursorNum(cursorIndex); -} - -/*--------------------------------------------------------------------------*/ - -MadsScene::MadsScene(MadsEngine *vm): Scene(vm) { - _vm = vm; - - strcpy(_statusText, ""); - _interfaceSurface = new MadsInterfaceView(vm); - _currentAction = kVerbNone; - _spriteSlotsStart = 0; -} - -/** - * Secondary scene loading code - */ -void MadsScene::loadScene2(const char *aaName) { - // Load up the properties for the scene - _sceneInfo.load(_currentScene); - - // Load scene walk paths - loadSceneCodes(_currentScene); -} - -/** - * Existing ScummVM code that needs to be eventually replaced with MADS code - */ -void MadsScene::loadSceneTemporary() { - /* Existing code that eventually needs to be replaced with the proper MADS code */ - // Set system palette entries - _vm->_palette->blockRange(0, 7); - RGB8 sysColors[3] = { {0x1f<<2, 0x2d<<2, 0x31<<2, 0}, {0x24<<2, 0x37<<2, 0x3a<<2, 0}, - {0x00<<2, 0x10<<2, 0x16<<2, 0}}; - _vm->_palette->setPalette(&sysColors[0], 4, 3); - - _backgroundSurface->loadBackground(_currentScene, &_palData); - _vm->_palette->addRange(_palData); - _backgroundSurface->translate(_palData); - - if (_currentScene < 900) { - /*_backgroundSurface->fillRect(Common::Rect(0, MADS_SURFACE_HEIGHT, - _backgroundSurface->width(), _backgroundSurface->height()), - _vm->_palette->BLACK);*/ - // TODO: interface palette - _interfaceSurface->madsloadInterface(0, &_interfacePal); - _vm->_palette->addRange(_interfacePal); - _interfaceSurface->translate(_interfacePal); - _backgroundSurface->copyFrom(_interfaceSurface, Common::Rect(0, 0, 320, 44), 0, 200 - 44); - - _interfaceSurface->initialise(); - } - - // Don't load other screen resources for system screens - if (_currentScene >= 900) - return; - - loadSceneHotSpotsMads(_currentScene); - - // TODO: set walker scaling - // TODO: destroy woodscript buffer - - // Load inverse color table file (*.IPL) - loadSceneInverseColorTable(_currentScene); -} - -void MadsScene::loadScene(int sceneNumber) { - // Close the menu if it's active - View *mainMenu = _vm->_viewManager->getView(VIEWID_MAINMENU); - if (mainMenu != NULL) { - _vm->_viewManager->deleteView(mainMenu); - } - - // Handle common scene setting - Scene::loadScene(sceneNumber); - - // Signal the script engine what scene is to be active - _sceneLogic.selectScene(sceneNumber); - _sceneLogic.setupScene(); - - // Add the scene if necessary to the list of scenes that have been visited - _vm->globals()->addVisitedScene(sceneNumber); - - // Secondary scene load routine - loadScene2("*I0.AA"); - - // Do any scene specific setup - _sceneLogic.enterScene(); - - // Existing ScummVM code that needs to be eventually replaced with MADS code - loadSceneTemporary(); - - // Purge resources - _vm->res()->purge(); -} - -void MadsScene::leaveScene() { - _sceneResources.hotspots->clear(); - _sceneResources.parallax->clear(); - _sceneResources.props->clear(); - - delete _sceneResources.hotspots; - delete _sceneResources.parallax; - delete _sceneResources.props; - - // Delete the sprites - for (uint i = 0; i <_sceneSprites.size(); ++i) delete _sceneSprites[i]; - _sceneSprites.clear(); - - delete _backgroundSurface; - delete _walkSurface; - - Scene::leaveScene(); -} - -void MadsScene::show() { - Scene::show(); - _vm->_viewManager->addView(_interfaceSurface); -} - -void MadsScene::loadSceneCodes(int sceneNumber, int index) { - char filename[kM4MaxFilenameSize]; - Common::SeekableReadStream *sceneS; - - if (_vm->getGameType() == GType_Phantom || _vm->getGameType() == GType_DragonSphere) { - sprintf(filename, "rm%i.ww%i", sceneNumber, index); - MadsPack walkData(filename, _vm); - sceneS = walkData.getItemStream(0); - _walkSurface->loadCodesMads(sceneS); - _vm->res()->toss(filename); - } else if (_vm->getGameType() == GType_RexNebular) { - // For Rex Nebular, the walk areas are part of the scene info - byte *destP = _walkSurface->getBasePtr(0, 0); - const byte *srcP = _sceneInfo.walkData; - byte runLength; - while ((runLength = *srcP++) != 0) { - Common::set_to(destP, destP + runLength, *srcP++); - destP += runLength; - } - } -} - -void MadsScene::checkHotspotAtMousePos(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 = _currentAction; - if (verbId == kVerbNone) - verbId = currentHotSpot->getVerbID(); - if (verbId == kVerbNone) - verbId = kVerbWalkTo; - - sprintf(statusText, "%s %s\n", _madsVm->globals()->getVocab(verbId), currentHotSpot->getVocab()); - - 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); - } -} - -void MadsScene::rightClick(int x, int y) { - // ***DEBUG*** - sample dialog display - int idx = 3; //_madsVm->_globals->messageIndexOf(0x277a); - const char *msg = _madsVm->globals()->loadMessage(idx); - Dialog *dlg = new Dialog(_vm, msg, "TEST DIALOG"); - _vm->_viewManager->addView(dlg); - _vm->_viewManager->moveToFront(dlg); -} - -void MadsScene::setAction(int action, int objectId) { - VALIDATE_MADS; - char statusText[50]; - - // TODO: Actually executing actions directly for objects. Also, some object actions are special in that - // a second object can be selected, as in 'use gun to shoot person', with requires a target - - // Set up the new action - strcpy(statusText, _madsVm->globals()->getVocab(action)); - statusText[0] = toupper(statusText[0]); // capitalize first letter - - if (objectId != -1) { - MadsObject *obj = _madsVm->globals()->getObject(objectId); - sprintf(statusText + strlen(statusText), " %s", _madsVm->globals()->getVocab(obj->descId)); - } else { - _currentAction = action; - } - - setStatusText(statusText); -} - -void MadsScene::setStatusText(const char *text) { - strcpy(_statusText, text); -} - -/** - * Draws all the elements of the scene - */ -void MadsScene::drawElements() { - - // Display animations - for (int idx = 0; idx < _spriteSlotsStart; ++idx) { - - } - - - // Text display loop - for (int idx = 0; idx < TEXT_DISPLAY_SIZE; ++idx) { - if (_textDisplay[idx].active && (_textDisplay[idx].field_A >= 0)) { - _textDisplay[idx].font->setColours(0xFF, (_textDisplay[idx].colour2 == 0) ? - _textDisplay[idx].colour1 : _textDisplay[idx].colour2, _textDisplay[idx].colour1); - _textDisplay[idx].font->writeString(this, _textDisplay[idx].message, - _textDisplay[idx].bounds.left, _textDisplay[idx].bounds.top, - width() - _textDisplay[idx].bounds.left, _textDisplay[idx].spacing); - } - } - - // Copy the user interface surface onto the surface - _interfaceSurface->copyTo(this, 0, this->height() - _interfaceSurface->height()); - -/* - // At this point, in the original engine, the dirty/changed areas were copied to the screen. At the moment, - // the current M4 engine framework doesn't support dirty areas, but this is being kept in case that ever changes - for (int idx = 0; idx < DIRTY_AREA_SIZE; ++idx) { - if (_dirtyAreas[idx].active && _dirtyAreas[idx].active2 && - (_dirtyAreas[idx].bounds.width() > 0) && (_dirtyAreas[idx].bounds.height() > 0)) { - // Copy changed area to screen - - } - } -*/ - - // Some kind of copying over of slot entries - for (int idx = 0, idx2 = 0; idx < _spriteSlotsStart; ++idx) { - if (_spriteSlots[idx].spriteId >= 0) { - if (idx != idx2) { - // Copy over the slot entry - _spriteSlots[idx2] = _spriteSlots[idx]; - } - ++idx2; - } - } - - // Clear up any now inactive text display entries - for (int idx = 0; idx < TEXT_DISPLAY_SIZE; ++idx) { - if (_textDisplay[idx].field_A < 0) { - _textDisplay[idx].active = false; - _textDisplay[idx].field_A = 0; - } - } -} - - -void MadsScene::update() { - // Copy the bare scene in - _backgroundSurface->copyTo(this); - - // Draw all the various elements - drawElements(); - - // Handle display of any status text - if (_statusText[0]) { - // Text colors are inverted in Dragonsphere - if (_vm->getGameType() == GType_DragonSphere) - _vm->_font->setColors(_vm->_palette->BLACK, _vm->_palette->WHITE, _vm->_palette->BLACK); - else - _vm->_font->setColors(_vm->_palette->WHITE, _vm->_palette->BLACK, _vm->_palette->BLACK); - - _vm->_font->setFont(FONT_MAIN_MADS); - _vm->_font->writeString(this, _statusText, (width() - _vm->_font->getWidth(_statusText)) / 2, 142, 0); - } - - //***DEBUG*** - _sceneSprites[0]->getFrame(1)->copyTo(this, 120, 90, 0); -} - -int MadsScene::loadSceneSpriteSet(const char *setName) { - char resName[100]; - strcpy(resName, setName); - - // Append a '.SS' if it doesn't alreayd have an extension - if (!strchr(resName, '.')) - strcat(resName, ".SS"); - - Common::SeekableReadStream *data = _vm->res()->get(resName); - SpriteAsset *spriteSet = new SpriteAsset(_vm, data, data->size(), resName); - spriteSet->translate(_vm->_palette); - _vm->res()->toss(resName); - - _sceneSprites.push_back(spriteSet); - return _sceneSprites.size() - 1; -} - -void MadsScene::loadPlayerSprites(const char *prefix) { - const char suffixList[8] = { '8', '9', '6', '3', '2', '7', '4', '1' }; - char setName[80]; - - strcpy(setName, "*"); - strcat(setName, prefix); - strcat(setName, "_0.SS"); - char *digitP = strchr(setName, '_') + 1; - - for (int idx = 0; idx < 8; ++idx) { - *digitP = suffixList[idx]; - - if (_vm->res()->resourceExists(setName)) { - loadSceneSpriteSet(setName); - return; - } - } - - error("Couldn't find player sprites"); -} - -/*--------------------------------------------------------------------------*/ - -void MadsSceneInfo::load(int sId) { - const char *sceneInfoStr = MADSResourceManager::getResourceName(RESPREFIX_RM, sId, ".DAT"); - Common::SeekableReadStream *rawStream = _vm->_resourceManager->get(sceneInfoStr); - MadsPack sceneInfo(rawStream); - - // Basic scene info - Common::SeekableReadStream *stream = sceneInfo.getItemStream(0); - - int resSceneId = stream->readUint16LE(); - assert(resSceneId == sId); - - artFileNum = stream->readUint16LE(); - field_4 = stream->readUint16LE(); - width = stream->readUint16LE(); - height = stream->readUint16LE(); - assert((width == 320) && (height == 156)); - - stream->skip(24); - - objectCount = stream->readUint16LE(); - - stream->skip(40); - - for (int i = 0; i < objectCount; ++i) { - objects[i].load(stream); - } - - // For Rex Nebular, read in the scene's compressed walk surface information - if (_vm->getGameType() == GType_RexNebular) { - delete walkData; - - stream = sceneInfo.getItemStream(1); - walkData = (byte *)malloc(stream->size()); - stream->read(walkData, stream->size()); - } - - _vm->_resourceManager->toss(sceneInfoStr); -} - } // End of namespace M4 diff --git a/engines/m4/scene.h b/engines/m4/scene.h index 78e179b4ac..0f4fc6c48d 100644 --- a/engines/m4/scene.h +++ b/engines/m4/scene.h @@ -41,16 +41,8 @@ class View; namespace M4 { -#define TITLE_SCENE_BURGER 951 // 951 = intro, 901 = demo menu, 971 = first scene -#define MAINMENU_SCENE_BURGER 903 -#define FIRST_SCENE 101 #define MAX_CHK_FILENAME_SIZE 144 -#define INTERFACE_HEIGHT 106 -#define MADS_SURFACE_HEIGHT 156 - -#define CHEAT_SEQUENCE_MAX 8 - enum MADSVerbs { kVerbNone = 0, kVerbLook = 3, @@ -136,121 +128,6 @@ public: bool onEvent(M4EventType eventType, int32 param1, int x, int y, bool &captureEvents); }; -class M4Scene : public Scene { -private: - M4Engine *_vm; - SpriteAsset *_sceneSprites; - SpriteAsset *_walkerSprite; - - void loadSceneSprites(int sceneNumber); - void nextCommonCursor(); -public: - M4Scene(M4Engine *vm); - virtual ~M4Scene(); - - // Methods that differ between engines - virtual void loadScene(int sceneNumber); - virtual void leaveScene() {}; - virtual void loadSceneCodes(int sceneNumber, int index = 0); - virtual void show(); - virtual void checkHotspotAtMousePos(int x, int y); - virtual void leftClick(int x, int y); - virtual void rightClick(int x, int y); - virtual void setAction(int action, int objectId = -1); - virtual void setStatusText(const char *text); - virtual void update(); - - M4InterfaceView *getInterface() { return (M4InterfaceView *)_interfaceSurface; }; -}; - -struct SpriteSlot { - int16 spriteId; - int16 scale; - uint16 spriteListIndex; -}; - -struct TextDisplay { - bool active; - int spacing; - Common::Rect bounds; - int16 field_A; - uint8 colour1, colour2; - Font *font; - char message[100]; -}; - -struct DirtyArea { - bool active; - bool active2; - Common::Rect bounds; -}; - -class MadsSceneInfo { -public: - int sceneId; - int artFileNum; - int field_4; - int width; - int height; - - int objectCount; - MadsObject objects[32]; - - int walkSize; - byte *walkData; - - MadsSceneInfo() { walkSize = 0; walkData = NULL; } - ~MadsSceneInfo() { delete walkData; } - void load(int sceneId); -}; - -typedef Common::Array<SpriteAsset *> SpriteAssetArray; - -#define SPRITE_SLOTS_SIZE 50 -#define TEXT_DISPLAY_SIZE 40 -#define DIRTY_AREA_SIZE 90 - -class MadsScene : public Scene { -private: - MadsEngine *_vm; - - int _currentAction; - char _statusText[100]; - MadsSceneLogic _sceneLogic; - MadsSceneInfo _sceneInfo; - SpriteAsset *_playerSprites; - SpriteAssetArray _sceneSprites; - SpriteSlot _spriteSlots[50]; - TextDisplay _textDisplay[TEXT_DISPLAY_SIZE]; - DirtyArea _dirtyAreas[DIRTY_AREA_SIZE]; - int _spriteSlotsStart; - - void drawElements(); - void loadScene2(const char *aaName); - void loadSceneTemporary(); -public: - char _aaName[100]; -public: - MadsScene(MadsEngine *vm); - - // Methods that differ between engines - virtual void loadScene(int sceneNumber); - virtual void leaveScene(); - virtual void loadSceneCodes(int sceneNumber, int index = 0); - virtual void show(); - virtual void checkHotspotAtMousePos(int x, int y); - virtual void leftClick(int x, int y); - virtual void rightClick(int x, int y); - virtual void setAction(int action, int objectId = -1); - virtual void setStatusText(const char *text); - virtual void update(); - - int loadSceneSpriteSet(const char *setName); - void loadPlayerSprites(const char *prefix); - - MadsInterfaceView *getInterface() { return (MadsInterfaceView *)_interfaceSurface; }; -}; - } // End of namespace M4 #endif diff --git a/engines/m4/script.cpp b/engines/m4/script.cpp index 62fade13d3..412707d95e 100644 --- a/engines/m4/script.cpp +++ b/engines/m4/script.cpp @@ -1103,7 +1103,7 @@ int ScriptInterpreter::o1_loadConversation() { //int flag = INTEGER(2); // TODO; just to show something - _vm->_converse->startConversation(name); + _m4Vm->_converse->startConversation(name); return 3; } diff --git a/engines/m4/staticres.cpp b/engines/m4/staticres.cpp index d376c30bcc..21cb719a2c 100644 --- a/engines/m4/staticres.cpp +++ b/engines/m4/staticres.cpp @@ -37,5 +37,22 @@ const char *cheatingEnabledDesc[3] = { NULL }; +const char *atStr = "at"; +const char *lookAroundStr = "Look around"; +const char *toStr = "to "; +const char *useStr = "Use "; + +VerbInit verbList[10] = { + {kVerbLook, 2, 0}, + {kVerbTake, 2, 0}, + {kVerbPush, 2, 0}, + {kVerbOpen, 2, 0}, + {kVerbPut, 1, -1}, + {kVerbTalkTo, 2, 0}, + {kVerbGive, 1, 2}, + {kVerbPull, 2, 0}, + {kVerbClose, 2, 0}, + {kVerbThrow, 1, 3} +}; } // End of namespace M4 diff --git a/engines/m4/staticres.h b/engines/m4/staticres.h index 754e37db46..7d33aff189 100644 --- a/engines/m4/staticres.h +++ b/engines/m4/staticres.h @@ -35,6 +35,19 @@ extern const char *englishMADSArticleList[9]; extern const char *cheatingEnabledDesc[3]; +extern const char *atStr; +extern const char *lookAroundStr; +extern const char *toStr; +extern const char *useStr; + +struct VerbInit { + int verb; + int8 flag1; + int8 flag2; +}; + +extern VerbInit verbList[10]; + } // End of namespace M4 #endif |