diff options
author | Paul Gilbert | 2010-03-07 05:06:58 +0000 |
---|---|---|
committer | Paul Gilbert | 2010-03-07 05:06:58 +0000 |
commit | 7f57001e175ef2215e192968e9883e63145e7a50 (patch) | |
tree | 99a4fd17e2a9717d0763f2a19065b2c2056f59d6 | |
parent | a5a8b6c19f2601113fc3d3a14b6ec19576fdd1f8 (diff) | |
download | scummvm-rg350-7f57001e175ef2215e192968e9883e63145e7a50.tar.gz scummvm-rg350-7f57001e175ef2215e192968e9883e63145e7a50.tar.bz2 scummvm-rg350-7f57001e175ef2215e192968e9883e63145e7a50.zip |
Split up the scene.cpp file into separate files for M4 and MADS specific scene code and support classes. Also have started adding code for textual display and proper current action display
svn-id: r48172
-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 |