diff options
Diffstat (limited to 'engines')
-rw-r--r-- | engines/draci/draci.cpp | 1 | ||||
-rw-r--r-- | engines/draci/font.h | 3 | ||||
-rw-r--r-- | engines/draci/game.cpp | 258 | ||||
-rw-r--r-- | engines/draci/game.h | 41 | ||||
-rw-r--r-- | engines/draci/mouse.h | 2 | ||||
-rw-r--r-- | engines/draci/script.cpp | 78 | ||||
-rw-r--r-- | engines/draci/script.h | 11 |
7 files changed, 356 insertions, 38 deletions
diff --git a/engines/draci/draci.cpp b/engines/draci/draci.cpp index 4060b678ad..a09f5488a9 100644 --- a/engines/draci/draci.cpp +++ b/engines/draci/draci.cpp @@ -211,6 +211,7 @@ bool DraciEngine::handleEvents() { _game->setRoomNum(_game->getEscRoom()); _game->setGateNum(0); _game->_roomChange = true; + _game->setExitLoop(true); // End any currently running GPL programs _script->endCurrentProgram(); diff --git a/engines/draci/font.h b/engines/draci/font.h index e566a5ad54..e81b344af1 100644 --- a/engines/draci/font.h +++ b/engines/draci/font.h @@ -42,7 +42,8 @@ extern const Common::String kFontBig; enum { kFontColour1 = 2, kFontColour2 = 0, kFontColour3 = 3, kFontColour4 = 4, - kOverFontColour = 255, kTitleColour = 255 + kOverFontColour = 255, kTitleColour = 255, + kLineActiveColour = 254, kLineInactiveColour = 255 }; /** diff --git a/engines/draci/game.cpp b/engines/draci/game.cpp index 6c3ee96e98..2b861c46f8 100644 --- a/engines/draci/game.cpp +++ b/engines/draci/game.cpp @@ -35,6 +35,8 @@ namespace Draci { +const Common::String dialoguePath("ROZH"); + static double real_to_double(byte real[6]); Game::Game(DraciEngine *vm) : _vm(vm) { @@ -61,21 +63,24 @@ Game::Game(DraciEngine *vm) : _vm(vm) { // Close persons file file->close(); - // Read in dialog offsets + // Read in dialogue offsets file = initArchive->getFile(4); - Common::MemoryReadStream dialogData(file->_data, file->_length); + Common::MemoryReadStream dialogueData(file->_data, file->_length); - unsigned int numDialogs = file->_length / sizeof(uint16); - _dialogOffsets = new uint[numDialogs]; + unsigned int numDialogues = file->_length / sizeof(uint16); + _dialogueOffsets = new uint[numDialogues]; unsigned int curOffset; - for (i = 0, curOffset = 0; i < numDialogs; ++i) { - _dialogOffsets[i] = curOffset; - curOffset += dialogData.readUint16LE(); + for (i = 0, curOffset = 0; i < numDialogues; ++i) { + _dialogueOffsets[i] = curOffset; + curOffset += dialogueData.readUint16LE(); } - // Close dialogs file + _dialogueVars = new int[curOffset]; + memset(_dialogueVars, 0, sizeof (int) * curOffset); + + // Close dialogues file file->close(); // Read in game info @@ -89,7 +94,7 @@ Game::Game(DraciEngine *vm) : _vm(vm) { _info._numIcons = gameData.readUint16LE(); _info._numVariables = gameData.readByte(); _info._numPersons = gameData.readByte(); - _info._numDialogs = gameData.readByte(); + _info._numDialogues = gameData.readByte(); _info._maxIconWidth = gameData.readUint16LE(); _info._maxIconHeight = gameData.readUint16LE(); _info._musicLength = gameData.readUint16LE(); @@ -98,7 +103,7 @@ Game::Game(DraciEngine *vm) : _vm(vm) { _info._crc[2] = gameData.readUint16LE(); _info._crc[3] = gameData.readUint16LE(); - _info._numDialogBlocks = curOffset; + _info._numDialogueBlocks = curOffset; // Close game info file file->close(); @@ -145,7 +150,7 @@ Game::Game(DraciEngine *vm) : _vm(vm) { // Close object status file file->close(); - assert(numDialogs == _info._numDialogs); + assert(numDialogues == _info._numDialogues); assert(numPersons == _info._numPersons); assert(numVariables == _info._numVariables); assert(numObjects == _info._numObjects); @@ -227,6 +232,19 @@ void Game::init() { Text *speech = new Text("", _vm->_bigFont, kFontColour1, 0, 0); speechAnim->addFrame(speech); + for (uint i = 0; i < kDialogueLines; ++i) { + _dialogueAnims[i] = _vm->_anims->addText(-10 - i, true); + Text *dialogueLine0 = new Text("", _vm->_smallFont, kLineInactiveColour, 0, 0); + _dialogueAnims[i]->addFrame(dialogueLine0); + + _dialogueAnims[i]->setZ(254); + _dialogueAnims[i]->setRelative(1, + kScreenHeight - (i + 1) * _vm->_smallFont->getFontHeight()); + + Text *text = reinterpret_cast<Text *>(_dialogueAnims[i]->getFrame()); + text->setText(""); + } + loadObject(kDragonObject); GameObject *dragon = getObject(kDragonObject); @@ -254,11 +272,23 @@ void Game::loop() { _vm->handleEvents(); - if (_currentRoom._mouseOn) { + // Fetch mouse coordinates + int x = _vm->_mouse->getPosX(); + int y = _vm->_mouse->getPosY(); - // Fetch mouse coordinates - int x = _vm->_mouse->getPosX(); - int y = _vm->_mouse->getPosY(); + if (_loopStatus == kStatusDialogue && _loopSubstatus == kStatusOrdinary) { + + // Find animation under cursor + _animUnderCursor = _vm->_anims->getTopAnimationID(x, y); + + if (_vm->_mouse->lButtonPressed() || _vm->_mouse->rButtonPressed()) { + _shouldExitLoop = true; + _vm->_mouse->lButtonSet(false); + _vm->_mouse->rButtonSet(false); + } + } + + if (_currentRoom._mouseOn) { // Fetch the dedicated objects' title animation / current frame Animation *titleAnim = _vm->_anims->getAnimation(kTitleText); @@ -268,8 +298,8 @@ void Game::loop() { if(_vm->_mouse->isCursorOn()) { // Find the game object under the cursor // (to be more precise, one that corresponds to the animation under the cursor) - int animUnderCursor = _vm->_anims->getTopAnimationID(x, y); - int curObject = getObjectWithAnimation(animUnderCursor); + _animUnderCursor = _vm->_anims->getTopAnimationID(x, y); + int curObject = getObjectWithAnimation(_animUnderCursor); updateTitle(); @@ -342,11 +372,12 @@ void Game::loop() { } } } - debugC(2, kDraciAnimationDebugLevel, "Anim under cursor: %d", animUnderCursor); } } } + debug(8, "Anim under cursor: %d", _animUnderCursor); + // Handle character talking (if there is any) if (_loopSubstatus == kStatusTalk) { Animation *speechAnim = _vm->_anims->getAnimation(kSpeechText); @@ -382,7 +413,8 @@ void Game::loop() { _vm->_system->delayMillis(20); // HACK: Won't be needed once the game loop is implemented properly - _shouldExitLoop = _shouldExitLoop || _roomChange; + _shouldExitLoop = _shouldExitLoop || (_roomChange && + (_loopStatus == kStatusOrdinary || _loopStatus == kStatusGate)); } while (!shouldExitLoop()); } @@ -469,7 +501,193 @@ int Game::getObjectWithAnimation(int animID) { return kObjectNotFound; } + +void Game::dialogueMenu(int dialogueID) { + + int oldLines, hit; + + char tmp[5]; + sprintf(tmp, "%d", dialogueID+1); + Common::String ext(tmp); + _dialogueArchive = new BArchive(dialoguePath + ext + ".dfw"); + + debugC(4, kDraciLogicDebugLevel, "Starting dialogue (ID: %d, Archive: %s)", + dialogueID, (dialoguePath + ext + ".dfw").c_str()); + + _currentDialogue = dialogueID; + oldLines = 255; + dialogueInit(dialogueID); + + do { + _dialogueExit = false; + hit = dialogueDraw(); + + debug(2, "Hit: %d, _lines[hit]: %d", hit, _lines[hit]); + + if ((!_dialogueExit) && (hit != -1) && (_lines[hit] != -1)) { + if ((oldLines == 1) && (_dialogueLines == 1) && (_lines[hit] == _lastBlock)) { + break; + } + _currentBlock = _lines[hit]; + runDialogueProg(_dialogueBlocks[_lines[hit]]._program, 1); + } else { + break; + } + _lastBlock = _lines[hit]; + _dialogueVars[_dialogueOffsets[dialogueID] + _lastBlock + 1] += 1; + _dialogueBegin = false; + oldLines = _dialogueLines; + + } while(!_dialogueExit); + + dialogueDone(); + _currentDialogue = kNoDialogue; +} + +int Game::dialogueDraw() { + _dialogueLines = 0; + int i = 0; + int ret = 0; + Animation *anim; + Text *dialogueLine; + + while ((_dialogueLines < 4) && (i < _blockNum)) { + + GPL2Program blockTest; + blockTest._bytecode = _dialogueBlocks[i]._canBlock; + blockTest._length = _dialogueBlocks[i]._canLen; + + debugC(3, kDraciLogicDebugLevel, "Testing dialogue block %d", i); + if (_vm->_script->testExpression(blockTest, 1)) { + anim = _dialogueAnims[_dialogueLines]; + dialogueLine = reinterpret_cast<Text *>(anim->getFrame()); + dialogueLine->setText(_dialogueBlocks[i]._title); + + dialogueLine->setColour(kLineInactiveColour); + _lines[_dialogueLines] = i; + _dialogueLines++; + } + ++i; + } + + for (i = _dialogueLines; i < kDialogueLines; ++i) { + _lines[i] = 0; + anim = _dialogueAnims[i]; + dialogueLine = reinterpret_cast<Text *>(anim->getFrame()); + dialogueLine->setText(""); + } + + _oldObjUnderCursor = kObjectNotFound; + + if (_dialogueLines > 1) { + _vm->_mouse->cursorOn(); + _shouldExitLoop = false; + loop(); + _vm->_mouse->cursorOff(); + + bool notDialogueAnim = true; + for (uint j = 0; j < kDialogueLines; ++j) { + if (_dialogueAnims[j]->getID() == _animUnderCursor) { + notDialogueAnim = false; + break; + } + } + + if (notDialogueAnim) { + ret = -1; + } else { + ret = _dialogueAnims[0]->getID() - _animUnderCursor; + } + } else { + ret = _dialogueLines - 1; + } + + for (i = 0; i < kDialogueLines; ++i) { + dialogueLine = reinterpret_cast<Text *>(_dialogueAnims[i]->getFrame()); + _dialogueAnims[i]->markDirtyRect(_vm->_screen->getSurface()); + dialogueLine->setText(""); + } + + return ret; +} + +void Game::dialogueInit(int dialogID) { + _vm->_mouse->setCursorType(kDialogueCursor); + + _blockNum = _dialogueArchive->size() / 3; + _dialogueBlocks = new Dialogue[_blockNum]; + + BAFile *f; + + for (uint i = 0; i < kDialogueLines; ++i) { + _lines[i] = 0; + } + + for (int i = 0; i < _blockNum; ++i) { + f = _dialogueArchive->getFile(i * 3); + _dialogueBlocks[i]._canLen = f->_length; + _dialogueBlocks[i]._canBlock = f->_data; + + f = _dialogueArchive->getFile(i * 3 + 1); + + // The first byte of the file is the length of the string (without the length) + assert(f->_length - 1 == f->_data[0]); + + _dialogueBlocks[i]._title = Common::String((char *)(f->_data+1), f->_length-1); + + f = _dialogueArchive->getFile(i * 3 + 2); + _dialogueBlocks[i]._program._bytecode = f->_data; + _dialogueBlocks[i]._program._length = f->_length; + } + + for (uint i = 0; i < kDialogueLines; ++i) { + _vm->_anims->play(_dialogueAnims[i]->getID()); + } + + _loopStatus = kStatusDialogue; + _lastBlock = 0; + _dialogueBegin = true; +} + +void Game::dialogueDone() { + for (uint i = 0; i < kDialogueLines; ++i) { + _vm->_anims->stop(_dialogueAnims[i]->getID()); + } + + _dialogueArchive->closeArchive(); + + delete[] _dialogueBlocks; + + _loopStatus = kStatusOrdinary; + _vm->_mouse->setCursorType(kNormalCursor); +} + +void Game::runDialogueProg(GPL2Program prog, int offset) { + + // Mark last animation + int lastAnimIndex = _vm->_anims->getLastIndex(); + + // Run gate program + _vm->_script->run(prog, offset); + + // Delete all animations loaded after the marked one + // (from objects and from the AnimationManager) + for (uint i = 0; i < getNumObjects(); ++i) { + GameObject *obj = &_objects[i]; + + for (uint j = 0; j < obj->_anims.size(); ++j) { + Animation *anim; + + anim = _vm->_anims->getAnimation(obj->_anims[j]); + if (anim != NULL && anim->getIndex() > lastAnimIndex) + obj->_anims.remove_at(j); + } + } + + _vm->_anims->deleteAfterIndex(lastAnimIndex); +} + void Game::walkHero(int x, int y) { Surface *surface = _vm->_screen->getSurface(); @@ -937,7 +1155,7 @@ void Game::setMarkedAnimationIndex(int index) { Game::~Game() { delete[] _persons; delete[] _variables; - delete[] _dialogOffsets; + delete[] _dialogueOffsets; delete[] _objects; } diff --git a/engines/draci/game.h b/engines/draci/game.h index 47b940ce7e..a712542e9e 100644 --- a/engines/draci/game.h +++ b/engines/draci/game.h @@ -27,6 +27,7 @@ #define DRACI_GAME_H #include "common/str.h" +#include "draci/barchive.h" #include "draci/script.h" #include "draci/animation.h" #include "draci/sprite.h" @@ -68,6 +69,10 @@ enum { kDefaultRoomMap = -1 }; +enum { + kNoDialogue = -1, kDialogueLines = 4 +}; + enum SpeechConstants { kBaseSpeechDuration = 200, kSpeechTimeUnit = 400 @@ -134,11 +139,11 @@ struct GameInfo { uint _numIcons; byte _numVariables; byte _numPersons; - byte _numDialogs; + byte _numDialogues; uint _maxIconWidth, _maxIconHeight; uint _musicLength; uint _crc[4]; - uint _numDialogBlocks; + uint _numDialogueBlocks; }; struct Person { @@ -146,6 +151,14 @@ struct Person { byte _fontColour; }; +struct Dialogue { + int _canLen; + byte *_canBlock; + Common::String _title; + GPL2Program _program; +}; + + struct Room { int _roomNum; byte _music; @@ -266,13 +279,18 @@ public: void updateTitle(); void updateCursor(); + void dialogueMenu(int dialogueID); + int dialogueDraw(); + void dialogueInit(int dialogID); + void dialogueDone(); + void runDialogueProg(GPL2Program, int offset); + bool _roomChange; private: DraciEngine *_vm; GameInfo _info; - uint *_dialogOffsets; int *_variables; byte *_iconStatus; @@ -286,6 +304,22 @@ private: int _currentIcon; +// HACK: remove public when tested and add getters instead +public: + uint *_dialogueOffsets; + int _currentDialogue; + int *_dialogueVars; + BArchive *_dialogueArchive; + Dialogue *_dialogueBlocks; + bool _dialogueBegin; + bool _dialogueExit; + int _currentBlock; + int _lastBlock; + int _dialogueLines; + int _blockNum; + int _lines[4]; + Animation *_dialogueAnims[4]; + LoopStatus _loopStatus; LoopStatus _loopSubstatus; @@ -296,6 +330,7 @@ private: int _objUnderCursor; int _oldObjUnderCursor; + int _animUnderCursor; int _markedAnimationIndex; //!< Used by the Mark GPL command }; diff --git a/engines/draci/mouse.h b/engines/draci/mouse.h index f3e0123f59..d6df7f312d 100644 --- a/engines/draci/mouse.h +++ b/engines/draci/mouse.h @@ -34,7 +34,7 @@ namespace Draci { enum CursorType { kNormalCursor, kArrowCursor1, kArrowCursor2, kArrowCursor3, - kArrowCursor4, kDialogCursor, + kArrowCursor4, kDialogueCursor, kHighlightedCursor, kMainMenuCursor }; diff --git a/engines/draci/script.cpp b/engines/draci/script.cpp index af64204f42..e7e4861e62 100644 --- a/engines/draci/script.cpp +++ b/engines/draci/script.cpp @@ -53,11 +53,11 @@ void Script::setupCommandList() { { 7, 1, "ObjStat", 2, { 3, 3 }, &Script::objStat }, { 7, 2, "ObjStat_On", 2, { 3, 3 }, &Script::objStatOn }, { 8, 1, "IcoStat", 2, { 3, 3 }, NULL }, - { 9, 1, "Dialogue", 1, { 2 }, NULL }, - { 9, 2, "ExitDialogue", 0, { 0 }, NULL }, - { 9, 3, "ResetDialogue", 0, { 0 }, NULL }, - { 9, 4, "ResetDialogueFrom", 0, { 0 }, NULL }, - { 9, 5, "ResetBlock", 1, { 3 }, NULL }, + { 9, 1, "Dialogue", 1, { 2 }, &Script::dialogue }, + { 9, 2, "ExitDialogue", 0, { 0 }, &Script::exitDialogue }, + { 9, 3, "ResetDialogue", 0, { 0 }, &Script::resetDialogue }, + { 9, 4, "ResetDialogueFrom", 0, { 0 }, &Script::resetDialogueFrom }, + { 9, 5, "ResetBlock", 1, { 3 }, &Script::resetBlock }, { 10, 1, "WalkOn", 3, { 1, 1, 3 }, &Script::walkOn }, { 10, 2, "StayOn", 3, { 1, 1, 3 }, &Script::walkOn }, // HACK: not a proper implementation { 10, 3, "WalkOnPlay", 3, { 1, 1, 3 }, &Script::walkOn }, // HACK: not a proper implementation @@ -126,11 +126,11 @@ void Script::setupCommandList() { { "IsObjOff", &Script::funcIsObjOff }, { "IsObjAway", &Script::funcIsObjAway }, { "ObjStat", &Script::funcObjStat }, - { "LastBlock", NULL }, - { "AtBegin", NULL }, - { "BlockVar", NULL }, - { "HasBeen", NULL }, - { "MaxLine", NULL }, + { "LastBlock", &Script::funcLastBlock }, + { "AtBegin", &Script::funcAtBegin }, + { "BlockVar", &Script::funcBlockVar }, + { "HasBeen", &Script::funcHasBeen }, + { "MaxLine", &Script::funcMaxLine }, { "ActPhase", &Script::funcActPhase }, { "Cheat", NULL }, }; @@ -218,6 +218,27 @@ int Script::funcRandom(int n) { return _vm->_rnd.getRandomNumber(n); } +int Script::funcAtBegin(int yesno) { + return _vm->_game->_dialogueBegin == yesno; +} + +int Script::funcLastBlock(int blockID) { + + return _vm->_game->_lastBlock == blockID; +} + +int Script::funcBlockVar(int blockID) { + return _vm->_game->_dialogueVars[_vm->_game->_dialogueOffsets[_vm->_game->_currentDialogue] + blockID]; +} + +int Script::funcHasBeen(int blockID) { + return _vm->_game->_dialogueVars[_vm->_game->_dialogueOffsets[_vm->_game->_currentDialogue] + blockID] > 0; +} + +int Script::funcMaxLine(int lines) { + return _vm->_game->_dialogueLines < lines; +} + int Script::funcNot(int n) { return !n; } @@ -373,8 +394,11 @@ void Script::start(Common::Queue<int> ¶ms) { return; } - int objID = params.pop() - 1; - int animID = params.pop() - 1; + int objID = params.pop(); + int animID = params.pop(); + + objID -= 1; + animID -= 1; GameObject *obj = _vm->_game->getObject(objID); @@ -623,12 +647,42 @@ void Script::talk(Common::Queue<int> ¶ms) { _vm->_game->setExitLoop(false); } +void Script::dialogue(Common::Queue<int> ¶ms) { + int dialogueID = params.pop() - 1; + + _vm->_game->dialogueMenu(dialogueID); +} + void Script::loadMap(Common::Queue<int> ¶ms) { int mapID = params.pop() - 1; _vm->_game->loadWalkingMap(mapID); } +void Script::resetDialogue(Common::Queue<int> ¶ms) { + + for (int i = 0; i < _vm->_game->_blockNum; ++i) { + _vm->_game->_dialogueVars[_vm->_game->_dialogueOffsets[_vm->_game->_currentDialogue]+i] = 0; + } +} + +void Script::resetDialogueFrom(Common::Queue<int> ¶ms) { + + for (int i = _vm->_game->_currentBlock; i < _vm->_game->_blockNum; ++i) { + _vm->_game->_dialogueVars[_vm->_game->_dialogueOffsets[_vm->_game->_currentDialogue]+i] = 0; + } +} + +void Script::resetBlock(Common::Queue<int> ¶ms) { + int blockID = params.pop(); + + _vm->_game->_dialogueVars[_vm->_game->_dialogueOffsets[_vm->_game->_currentDialogue]+blockID] = 0; +} + +void Script::exitDialogue(Common::Queue<int> ¶ms) { + _vm->_game->_dialogueExit = true; +} + void Script::roomMap(Common::Queue<int> ¶ms) { // Load the default walking map for the room diff --git a/engines/draci/script.h b/engines/draci/script.h index 6c85a7cc5b..b1f9ed9bbd 100644 --- a/engines/draci/script.h +++ b/engines/draci/script.h @@ -121,6 +121,11 @@ private: void talk(Common::Queue<int> ¶ms); void loadMap(Common::Queue<int> ¶ms); void roomMap(Common::Queue<int> ¶ms); + void dialogue(Common::Queue<int> ¶ms); + void exitDialogue(Common::Queue<int> ¶ms); + void resetDialogue(Common::Queue<int> ¶ms); + void resetDialogueFrom(Common::Queue<int> ¶ms); + void resetBlock(Common::Queue<int> ¶ms); int operAnd(int op1, int op2); int operOr(int op1, int op2); @@ -148,7 +153,11 @@ private: int funcIsObjAway(int objID); int funcActPhase(int objID); int funcObjStat(int objID); - + int funcLastBlock(int blockID); + int funcAtBegin(int yesno); + int funcBlockVar(int blockID); + int funcHasBeen(int blockID); + int funcMaxLine(int lines); void setupCommandList(); const GPL2Command *findCommand(byte num, byte subnum); |