diff options
Diffstat (limited to 'engines')
41 files changed, 1548 insertions, 1424 deletions
diff --git a/engines/hugo/display.cpp b/engines/hugo/display.cpp index 1a951e5a59..5a5069b06c 100644 --- a/engines/hugo/display.cpp +++ b/engines/hugo/display.cpp @@ -48,7 +48,7 @@ namespace Hugo { #define INY(Y, B) (Y >= B->y && Y <= B->y + B->dy) #define OVERLAP(A, B) ((INX(A->x, B) || INX(A->x + A->dx, B) || INX(B->x, A) || INX(B->x + B->dx, A)) && (INY(A->y, B) || INY(A->y + A->dy, B) || INY(B->y, A) || INY(B->y + B->dy, A))) -Screen::Screen(HugoEngine &vm) : _vm(vm) { +Screen::Screen(HugoEngine *vm) : _vm(vm) { } @@ -58,7 +58,7 @@ Screen::~Screen() { void Screen::createPal() { debugC(1, kDebugDisplay, "createPal"); - g_system->setPalette(_vm._palette, 0, NUM_COLORS); + g_system->setPalette(_vm->_palette, 0, NUM_COLORS); } void Screen::initDisplay() { @@ -135,7 +135,7 @@ overlayState_t Screen::findOvl(seq_t *seq_p, image_pt dst_p, uint16 y) { debugC(4, kDebugDisplay, "findOvl"); for (; y < seq_p->lines; y++) { // Each line in object - image_pt ovb_p = _vm.getBaseBoundaryOverlay() + ((uint16)(dst_p - _frontBuffer) >> 3); // Ptr into overlay bits + image_pt ovb_p = _vm->getBaseBoundaryOverlay() + ((uint16)(dst_p - _frontBuffer) >> 3); // Ptr into overlay bits if (*ovb_p & (0x80 >> ((uint16)(dst_p - _frontBuffer) & 7))) // Overlay bit is set return FG; // Found a bit - must be foreground dst_p += XPIX; @@ -151,7 +151,7 @@ void Screen::displayFrame(int sx, int sy, seq_t *seq, bool foreFl) { image_pt image = seq->imagePtr; // Ptr to object image data image_pt subFrontBuffer = &_frontBuffer[sy * XPIX + sx]; // Ptr to offset in _frontBuffer - image_pt overlay = &_vm.getFirstOverlay()[(sy * XPIX + sx) >> 3]; // Ptr to overlay data + image_pt overlay = &_vm->getFirstOverlay()[(sy * XPIX + sx) >> 3]; // Ptr to overlay data int16 frontBufferwrap = XPIX - seq->x2 - 1; // Wraps dest_p after each line int16 imageWrap = seq->bytesPerLine8 - seq->x2 - 1; @@ -159,7 +159,7 @@ void Screen::displayFrame(int sx, int sy, seq_t *seq, bool foreFl) { for (uint16 y = 0; y < seq->lines; y++) { // Each line in object for (uint16 x = 0; x <= seq->x2; x++) { if (*image) { // Non-transparent - overlay = _vm.getFirstOverlay() + ((uint16)(subFrontBuffer - _frontBuffer) >> 3); // Ptr into overlay bits + overlay = _vm->getFirstOverlay() + ((uint16)(subFrontBuffer - _frontBuffer) >> 3); // Ptr into overlay bits if (*overlay & (0x80 >> ((uint16)(subFrontBuffer - _frontBuffer) & 7))) { // Overlay bit is set if (overlayState == UNDEF) // Overlay defined yet? overlayState = findOvl(seq, subFrontBuffer, y);// No, find it. @@ -269,8 +269,8 @@ void Screen::displayList(dupdate_t update, ...) { // Don't blit if newscreen just loaded because _frontBuffer will // get blitted via InvalidateRect() at end of this cycle // and blitting here causes objects to appear too soon. - if (_vm.getGameStatus().newScreenFl) { - _vm.getGameStatus().newScreenFl = false; + if (_vm->getGameStatus().newScreenFl) { + _vm->getGameStatus().newScreenFl = false; break; } @@ -394,18 +394,18 @@ void Screen::drawStatusText() { debugC(4, kDebugDisplay, "drawStatusText"); loadFont(U_FONT8); - uint16 sdx = stringLength(_vm._statusLine); + uint16 sdx = stringLength(_vm->_statusLine); uint16 sdy = fontHeight() + 1; // + 1 for shadow uint16 posX = 0; uint16 posY = YPIX - sdy; // Display the string and add rect to display list - writeStr(posX, posY, _vm._statusLine, _TLIGHTYELLOW); + writeStr(posX, posY, _vm->_statusLine, _TLIGHTYELLOW); displayList(D_ADD, posX, posY, sdx, sdy); - sdx = stringLength(_vm._scoreLine); + sdx = stringLength(_vm->_scoreLine); posY = 0; - writeStr(posX, posY, _vm._scoreLine, _TCYAN); + writeStr(posX, posY, _vm->_scoreLine, _TCYAN); displayList(D_ADD, posX, posY, sdx, sdy); } @@ -447,7 +447,7 @@ void Screen::initNewScreenDisplay() { displayBackground(); // Stop premature object display in Display_list(D_DISPLAY) - _vm.getGameStatus().newScreenFl = true; + _vm->getGameStatus().newScreenFl = true; } } // End of namespace Hugo diff --git a/engines/hugo/display.h b/engines/hugo/display.h index 6e8b15940a..dc687e0bb6 100644 --- a/engines/hugo/display.h +++ b/engines/hugo/display.h @@ -46,7 +46,7 @@ struct rect_t { // Rectangle used in Display class Screen { public: - Screen(HugoEngine &vm); + Screen(HugoEngine *vm); virtual ~Screen(); int16 fontHeight(); @@ -93,7 +93,7 @@ public: } protected: - HugoEngine &_vm; + HugoEngine *_vm; // Fonts used in dib (non-GDI) byte _fnt; // Current font number @@ -116,7 +116,7 @@ private: class Screen_v1d : public Screen { public: - Screen_v1d(HugoEngine &vm); + Screen_v1d(HugoEngine *vm); ~Screen_v1d(); virtual void loadFont(int16 fontId); @@ -124,7 +124,7 @@ public: class Screen_v1w : public Screen { public: - Screen_v1w(HugoEngine &vm); + Screen_v1w(HugoEngine *vm); ~Screen_v1w(); virtual void loadFont(int16 fontId); diff --git a/engines/hugo/display_v1d.cpp b/engines/hugo/display_v1d.cpp index 6cf20d413f..a46f5a8bec 100644 --- a/engines/hugo/display_v1d.cpp +++ b/engines/hugo/display_v1d.cpp @@ -40,7 +40,7 @@ namespace Hugo { -Screen_v1d::Screen_v1d(HugoEngine &vm) : Screen(vm) { +Screen_v1d::Screen_v1d(HugoEngine *vm) : Screen(vm) { } Screen_v1d::~Screen_v1d() { @@ -61,7 +61,7 @@ void Screen_v1d::loadFont(int16 fontId) { fontLoadedFl[_fnt] = true; - memcpy(_fontdata[_fnt], _vm._arrayFont[_fnt], _vm._arrayFontSize[_fnt]); + memcpy(_fontdata[_fnt], _vm->_arrayFont[_fnt], _vm->_arrayFontSize[_fnt]); _font[_fnt][0] = _fontdata[_fnt]; // Store height,width of fonts int16 offset = 2; // Start at fontdata[2] ([0],[1] used for height,width) diff --git a/engines/hugo/display_v1w.cpp b/engines/hugo/display_v1w.cpp index c98374dcde..3dd8328c43 100644 --- a/engines/hugo/display_v1w.cpp +++ b/engines/hugo/display_v1w.cpp @@ -41,7 +41,7 @@ namespace Hugo { -Screen_v1w::Screen_v1w(HugoEngine &vm) : Screen(vm) { +Screen_v1w::Screen_v1w(HugoEngine *vm) : Screen(vm) { } Screen_v1w::~Screen_v1w() { @@ -59,7 +59,7 @@ void Screen_v1w::loadFont(int16 fontId) { return; fontLoadedFl[_fnt] = true; - _vm.file().readUIFItem(fontId, _fontdata[_fnt]); + _vm->_file->readUIFItem(fontId, _fontdata[_fnt]); // Compile font ptrs. Note: First ptr points to height,width of font _font[_fnt][0] = _fontdata[_fnt]; // Store height,width of fonts diff --git a/engines/hugo/file.cpp b/engines/hugo/file.cpp index 9165640f3f..5c3b72f1aa 100644 --- a/engines/hugo/file.cpp +++ b/engines/hugo/file.cpp @@ -39,9 +39,10 @@ #include "hugo/schedule.h" #include "hugo/display.h" #include "hugo/util.h" +#include "hugo/object.h" namespace Hugo { -FileManager::FileManager(HugoEngine &vm) : _vm(vm) { +FileManager::FileManager(HugoEngine *vm) : _vm(vm) { } FileManager::~FileManager() { @@ -143,7 +144,7 @@ void FileManager::readImage(int objNum, object_t *objPtr) { if (!objPtr->seqNumb) // This object has no images return; - if (_vm.isPacked()) { + if (_vm->isPacked()) { _objectsArchive.seek((uint32)objNum * sizeof(objBlock_t), SEEK_SET); objBlock_t objBlock; // Info on file within database @@ -153,10 +154,10 @@ void FileManager::readImage(int objNum, object_t *objPtr) { _objectsArchive.seek(objBlock.objOffset, SEEK_SET); } else { char *buf = (char *) malloc(2048 + 1); // Buffer for file access - strcat(strcat(strcpy(buf, _vm._picDir), _vm._arrayNouns[objPtr->nounIndex][0]), OBJEXT); + strcat(strcat(strcpy(buf, _vm->_picDir), _vm->_arrayNouns[objPtr->nounIndex][0]), OBJEXT); if (!_objectsArchive.open(buf)) { - warning("File %s not found, trying again with %s%s", buf, _vm._arrayNouns[objPtr->nounIndex][0], OBJEXT); - strcat(strcpy(buf, _vm._arrayNouns[objPtr->nounIndex][0]), OBJEXT); + warning("File %s not found, trying again with %s%s", buf, _vm->_arrayNouns[objPtr->nounIndex][0], OBJEXT); + strcat(strcpy(buf, _vm->_arrayNouns[objPtr->nounIndex][0]), OBJEXT); if (!_objectsArchive.open(buf)) Utils::Error(FILE_ERR, "%s", buf); } @@ -170,12 +171,12 @@ void FileManager::readImage(int objNum, object_t *objPtr) { for (int k = 0; k < objPtr->seqList[j].imageNbr; k++) { // each image if (k == 0) { // First image // Read this image - allocate both seq and image memory - seqPtr = readPCX(_objectsArchive, 0, 0, firstFl, _vm._arrayNouns[objPtr->nounIndex][0]); + seqPtr = readPCX(_objectsArchive, 0, 0, firstFl, _vm->_arrayNouns[objPtr->nounIndex][0]); objPtr->seqList[j].seqPtr = seqPtr; firstFl = false; } else { // Subsequent image // Read this image - allocate both seq and image memory - seqPtr->nextSeqPtr = readPCX(_objectsArchive, 0, 0, firstFl, _vm._arrayNouns[objPtr->nounIndex][0]); + seqPtr->nextSeqPtr = readPCX(_objectsArchive, 0, 0, firstFl, _vm->_arrayNouns[objPtr->nounIndex][0]); seqPtr = seqPtr->nextSeqPtr; } @@ -222,7 +223,7 @@ void FileManager::readImage(int objNum, object_t *objPtr) { warning("Unexpected cycling: %d", objPtr->cycling); } - if (!_vm.isPacked()) + if (!_vm->isPacked()) _objectsArchive.close(); } @@ -232,7 +233,7 @@ sound_pt FileManager::getSound(int16 sound, uint16 *size) { debugC(1, kDebugFile, "getSound(%d, %d)", sound, *size); // No more to do if SILENCE (called for cleanup purposes) - if (sound == _vm._soundSilence) + if (sound == _vm->_soundSilence) return 0; // Open sounds file @@ -283,35 +284,6 @@ bool FileManager::fileExists(char *filename) { return false; } -void FileManager::saveSeq(object_t *obj) { -// Save sequence number and image number in given object - debugC(1, kDebugFile, "saveSeq"); - - bool found = false; - for (int j = 0; !found && (j < obj->seqNumb); j++) { - seq_t *q = obj->seqList[j].seqPtr; - for (int k = 0; !found && (k < obj->seqList[j].imageNbr); k++) { - if (obj->currImagePtr == q) { - found = true; - obj->curSeqNum = j; - obj->curImageNum = k; - } else { - q = q->nextSeqPtr; - } - } - } -} - -void FileManager::restoreSeq(object_t *obj) { -// Set up cur_seq_p from stored sequence and image number in object - debugC(1, kDebugFile, "restoreSeq"); - - seq_t *q = obj->seqList[obj->curSeqNum].seqPtr; - for (int j = 0; j < obj->curImageNum; j++) - q = q->nextSeqPtr; - obj->currImagePtr = q; -} - void FileManager::saveGame(int16 slot, const char *descrip) { // Save game to supplied slot (-1 is INITFILE) debugC(1, kDebugFile, "saveGame(%d, %s)", slot, descrip); @@ -320,11 +292,11 @@ void FileManager::saveGame(int16 slot, const char *descrip) { Common::String path; // Full path of saved game if (slot == -1) - path = _vm._initFilename; + path = _vm->_initFilename; else - path = Common::String::printf(_vm._saveFilename.c_str(), slot); + path = Common::String::printf(_vm->_saveFilename.c_str(), slot); - Common::WriteStream *out = _vm.getSaveFileManager()->openForSaving(path); + Common::WriteStream *out = _vm->getSaveFileManager()->openForSaving(path); if (!out) { warning("Can't create file '%s', game not saved", path.c_str()); return; @@ -337,19 +309,19 @@ void FileManager::saveGame(int16 slot, const char *descrip) { out->write(descrip, DESCRIPLEN); // Save objects - for (int i = 0; i < _vm._numObj; i++) { + for (int i = 0; i < _vm->_numObj; i++) { // Save where curr_seq_p is pointing to - saveSeq(&_vm._objects[i]); - out->write(&_vm._objects[i], sizeof(object_t)); + _vm->_object->saveSeq(&_vm->_object->_objects[i]); + out->write(&_vm->_object->_objects[i], sizeof(object_t)); } - const status_t &gameStatus = _vm.getGameStatus(); + const status_t &gameStatus = _vm->getGameStatus(); // Save whether hero image is swapped - out->write(&_vm._heroImage, sizeof(_vm._heroImage)); + out->write(&_vm->_heroImage, sizeof(_vm->_heroImage)); // Save score - int score = _vm.getScore(); + int score = _vm->getScore(); out->write(&score, sizeof(score)); // Save story mode @@ -362,16 +334,16 @@ void FileManager::saveGame(int16 slot, const char *descrip) { out->write(&gameStatus.gameOverFl, sizeof(gameStatus.gameOverFl)); // Save screen states - out->write(_vm._screenStates, sizeof(*_vm._screenStates) * _vm._numScreens); + out->write(_vm->_screenStates, sizeof(*_vm->_screenStates) * _vm->_numScreens); // Save points table - out->write(_vm._points, sizeof(point_t) * _vm._numBonuses); + out->write(_vm->_points, sizeof(point_t) * _vm->_numBonuses); // Now save current time and all current events in event queue - _vm.scheduler().saveEvents(out); + _vm->_scheduler->saveEvents(out); // Save palette table - _vm.screen().savePal(out); + _vm->_screen->savePal(out); // Save maze status out->write(&_maze, sizeof(maze_t)); @@ -386,17 +358,17 @@ void FileManager::restoreGame(int16 slot) { debugC(1, kDebugFile, "restoreGame(%d)", slot); // Initialize new-game status - _vm.initStatus(); + _vm->initStatus(); // Get full path of saved game file - note test for INITFILE Common::String path; // Full path of saved game if (slot == -1) - path = _vm._initFilename; + path = _vm->_initFilename; else - path = Common::String::printf(_vm._saveFilename.c_str(), slot); + path = Common::String::printf(_vm->_saveFilename.c_str(), slot); - Common::SeekableReadStream *in = _vm.getSaveFileManager()->openForLoading(path); + Common::SeekableReadStream *in = _vm->getSaveFileManager()->openForLoading(path); if (!in) return; @@ -412,13 +384,13 @@ void FileManager::restoreGame(int16 slot) { in->seek(DESCRIPLEN, SEEK_CUR); // If hero image is currently swapped, swap it back before restore - if (_vm._heroImage != HERO) - _vm.scheduler().swapImages(HERO, _vm._heroImage); + if (_vm->_heroImage != HERO) + _vm->_object->swapImages(HERO, _vm->_heroImage); // Restore objects, retain current seqList which points to dynamic mem // Also, retain cmnd_t pointers - for (int i = 0; i < _vm._numObj; i++) { - object_t *p = &_vm._objects[i]; + for (int i = 0; i < _vm->_numObj; i++) { + object_t *p = &_vm->_object->_objects[i]; seqList_t seqList[MAX_SEQUENCES]; memcpy(seqList, p->seqList, sizeof(seqList_t)); uint16 cmdIndex = p->cmdIndex; @@ -427,37 +399,37 @@ void FileManager::restoreGame(int16 slot) { memcpy(p->seqList, seqList, sizeof(seqList_t)); } - in->read(&_vm._heroImage, sizeof(_vm._heroImage)); + in->read(&_vm->_heroImage, sizeof(_vm->_heroImage)); // If hero swapped in saved game, swap it - int heroImg = _vm._heroImage; + int heroImg = _vm->_heroImage; if (heroImg != HERO) - _vm.scheduler().swapImages(HERO, _vm._heroImage); - _vm._heroImage = heroImg; + _vm->_object->swapImages(HERO, _vm->_heroImage); + _vm->_heroImage = heroImg; - status_t &gameStatus = _vm.getGameStatus(); + status_t &gameStatus = _vm->getGameStatus(); int score; in->read(&score, sizeof(score)); - _vm.setScore(score); + _vm->setScore(score); in->read(&gameStatus.storyModeFl, sizeof(gameStatus.storyModeFl)); in->read(&gameStatus.jumpExitFl, sizeof(gameStatus.jumpExitFl)); in->read(&gameStatus.gameOverFl, sizeof(gameStatus.gameOverFl)); - in->read(_vm._screenStates, sizeof(*_vm._screenStates) * _vm._numScreens); + in->read(_vm->_screenStates, sizeof(*_vm->_screenStates) * _vm->_numScreens); // Restore points table - in->read(_vm._points, sizeof(point_t) * _vm._numBonuses); + in->read(_vm->_points, sizeof(point_t) * _vm->_numBonuses); // Restore ptrs to currently loaded objects - for (int i = 0; i < _vm._numObj; i++) - restoreSeq(&_vm._objects[i]); + for (int i = 0; i < _vm->_numObj; i++) + _vm->_object->restoreSeq(&_vm->_object->_objects[i]); // Now restore time of the save and the event queue - _vm.scheduler().restoreEvents(in); + _vm->_scheduler->restoreEvents(in); // Restore palette and change it if necessary - _vm.screen().restorePal(in); + _vm->_screen->restorePal(in); // Restore maze status in->read(&_maze, sizeof(maze_t)); @@ -475,27 +447,27 @@ void FileManager::initSavedGame() { debugC(1, kDebugFile, "initSavedGame"); // Force save of initial game - if (_vm.getGameStatus().initSaveFl) + if (_vm->getGameStatus().initSaveFl) saveGame(-1, ""); // If initial game doesn't exist, create it - Common::SeekableReadStream *in = _vm.getSaveFileManager()->openForLoading(_vm._initFilename); + Common::SeekableReadStream *in = _vm->getSaveFileManager()->openForLoading(_vm->_initFilename); if (!in) { saveGame(-1, ""); - in = _vm.getSaveFileManager()->openForLoading(_vm._initFilename); + in = _vm->getSaveFileManager()->openForLoading(_vm->_initFilename); if (!in) { - Utils::Error(WRITE_ERR, "%s", _vm._initFilename.c_str()); + Utils::Error(WRITE_ERR, "%s", _vm->_initFilename.c_str()); return; } } // Must have an open saved game now - _vm.getGameStatus().saveSize = in->size(); + _vm->getGameStatus().saveSize = in->size(); delete in; // Check sanity - maybe disk full or path set to read-only drive? - if (_vm.getGameStatus().saveSize == -1) - Utils::Error(WRITE_ERR, "%s", _vm._initFilename.c_str()); + if (_vm->getGameStatus().saveSize == -1) + Utils::Error(WRITE_ERR, "%s", _vm->_initFilename.c_str()); } void FileManager::openPlaybackFile(bool playbackFl, bool recordFl) { @@ -520,7 +492,7 @@ void FileManager::printBootText() { Common::File ofp; if (!ofp.open(BOOTFILE)) { - if (_vm._gameVariant == 3) { + if (_vm->_gameVariant == 3) { //TODO initialize properly _boot structure warning("printBootText - Skipping as H1 Dos may be a freeware"); return; @@ -559,7 +531,7 @@ void FileManager::readBootFile() { Common::File ofp; if (!ofp.open(BOOTFILE)) { - if (_vm._gameVariant == 3) { + if (_vm->_gameVariant == 3) { //TODO initialize properly _boot structure warning("readBootFile - Skipping as H1 Dos may be a freeware"); return; @@ -673,5 +645,12 @@ void FileManager::instructions() { f.close(); } +// Read the uif image file (inventory icons) +void FileManager::readUIFImages() { + debugC(1, kDebugFile, "readUIFImages"); + + readUIFItem(UIF_IMAGES, _vm->_screen->getGUIBuffer()); // Read all uif images +} + } // End of namespace Hugo diff --git a/engines/hugo/file.h b/engines/hugo/file.h index a5679d0e1b..5d8c8bd429 100644 --- a/engines/hugo/file.h +++ b/engines/hugo/file.h @@ -57,7 +57,7 @@ namespace Hugo { class FileManager { public: - FileManager(HugoEngine &vm); + FileManager(HugoEngine *vm); virtual ~FileManager(); @@ -69,11 +69,10 @@ public: void instructions(); void readBootFile(); void readImage(int objNum, object_t *objPtr); + void readUIFImages(); void readUIFItem(short id, byte *buf); void restoreGame(short slot); - void restoreSeq(object_t *obj); void saveGame(short slot, const char *descrip); - void saveSeq(object_t *obj); virtual void openDatabaseFiles() = 0; virtual void closeDatabaseFiles() = 0; @@ -84,7 +83,7 @@ public: virtual char *fetchString(int index) = 0; protected: - HugoEngine &_vm; + HugoEngine *_vm; Common::File _stringArchive; // Handle for string file Common::File _sceneryArchive1; // Handle for scenery file @@ -108,7 +107,7 @@ private: class FileManager_v1d : public FileManager { public: - FileManager_v1d(HugoEngine &vm); + FileManager_v1d(HugoEngine *vm); ~FileManager_v1d(); void openDatabaseFiles(); @@ -120,7 +119,7 @@ public: class FileManager_v2d : public FileManager { public: - FileManager_v2d(HugoEngine &vm); + FileManager_v2d(HugoEngine *vm); ~FileManager_v2d(); void openDatabaseFiles(); @@ -132,7 +131,7 @@ public: class FileManager_v3d : public FileManager_v2d { public: - FileManager_v3d(HugoEngine &vm); + FileManager_v3d(HugoEngine *vm); ~FileManager_v3d(); void openDatabaseFiles(); @@ -145,7 +144,7 @@ private: class FileManager_v1w : public FileManager_v2d { public: - FileManager_v1w(HugoEngine &vm); + FileManager_v1w(HugoEngine *vm); ~FileManager_v1w(); void readOverlay(int screenNum, image_pt image, ovl_t overlayType); diff --git a/engines/hugo/file_v1d.cpp b/engines/hugo/file_v1d.cpp index b6239aa5dc..115a691ffc 100644 --- a/engines/hugo/file_v1d.cpp +++ b/engines/hugo/file_v1d.cpp @@ -38,7 +38,7 @@ #include "hugo/util.h" namespace Hugo { -FileManager_v1d::FileManager_v1d(HugoEngine &vm) : FileManager(vm) { +FileManager_v1d::FileManager_v1d(HugoEngine *vm) : FileManager(vm) { } FileManager_v1d::~FileManager_v1d() { @@ -59,7 +59,7 @@ void FileManager_v1d::readOverlay(int screenNum, image_pt image, ovl_t overlayTy const char *ovl_ext[] = {".b", ".o", ".ob"}; char *buf = (char *) malloc(2048 + 1); // Buffer for file access - strcat(strcpy(buf, _vm._screenNames[screenNum]), ovl_ext[overlayType]); + strcat(strcpy(buf, _vm->_screenNames[screenNum]), ovl_ext[overlayType]); if (!fileExists(buf)) { for (uint32 i = 0; i < OVL_SIZE; i++) @@ -81,12 +81,12 @@ void FileManager_v1d::readBackground(int screenIndex) { debugC(1, kDebugFile, "readBackground(%d)", screenIndex); char *buf = (char *) malloc(2048 + 1); // Buffer for file access - strcat(strcpy(buf, _vm._screenNames[screenIndex]), ".ART"); + strcat(strcpy(buf, _vm->_screenNames[screenIndex]), ".ART"); if (!_sceneryArchive1.open(buf)) Utils::Error(FILE_ERR, "%s", buf); // Read the image into dummy seq and static dib_a seq_t dummySeq; // Image sequence structure for Read_pcx - readPCX(_sceneryArchive1, &dummySeq, _vm.screen().getFrontBuffer(), true, _vm._screenNames[screenIndex]); + readPCX(_sceneryArchive1, &dummySeq, _vm->_screen->getFrontBuffer(), true, _vm->_screenNames[screenIndex]); _sceneryArchive1.close(); } @@ -94,7 +94,7 @@ void FileManager_v1d::readBackground(int screenIndex) { char *FileManager_v1d::fetchString(int index) { debugC(1, kDebugFile, "fetchString(%d)", index); - return _vm._stringtData[index]; + return _vm->_stringtData[index]; } } // End of namespace Hugo diff --git a/engines/hugo/file_v1w.cpp b/engines/hugo/file_v1w.cpp index 6ab21a853e..5218876caf 100644 --- a/engines/hugo/file_v1w.cpp +++ b/engines/hugo/file_v1w.cpp @@ -37,7 +37,7 @@ #include "hugo/util.h" namespace Hugo { -FileManager_v1w::FileManager_v1w(HugoEngine &vm) : FileManager_v2d(vm) { +FileManager_v1w::FileManager_v1w(HugoEngine *vm) : FileManager_v2d(vm) { } FileManager_v1w::~FileManager_v1w() { diff --git a/engines/hugo/file_v2d.cpp b/engines/hugo/file_v2d.cpp index 43de3fac4c..ef5c633ee9 100644 --- a/engines/hugo/file_v2d.cpp +++ b/engines/hugo/file_v2d.cpp @@ -40,7 +40,7 @@ #include "hugo/util.h" namespace Hugo { -FileManager_v2d::FileManager_v2d(HugoEngine &vm) : FileManager(vm) { +FileManager_v2d::FileManager_v2d(HugoEngine *vm) : FileManager(vm) { } FileManager_v2d::~FileManager_v2d() { @@ -85,7 +85,7 @@ void FileManager_v2d::readBackground(int screenIndex) { // Read the image into dummy seq and static dib_a seq_t dummySeq; // Image sequence structure for Read_pcx - readPCX(_sceneryArchive1, &dummySeq, _vm.screen().getFrontBuffer(), true, _vm._screenNames[screenIndex]); + readPCX(_sceneryArchive1, &dummySeq, _vm->_screen->getFrontBuffer(), true, _vm->_screenNames[screenIndex]); } void FileManager_v2d::readOverlay(int screenNum, image_pt image, ovl_t overlayType) { @@ -170,7 +170,7 @@ char *FileManager_v2d::fetchString(int index) { // Null terminate, decode and return it _textBoxBuffer[off2-off1] = '\0'; - _vm.scheduler().decodeString(_textBoxBuffer); + _vm->_scheduler->decodeString(_textBoxBuffer); return _textBoxBuffer; } } // End of namespace Hugo diff --git a/engines/hugo/file_v3d.cpp b/engines/hugo/file_v3d.cpp index e4809a7208..095a225a39 100644 --- a/engines/hugo/file_v3d.cpp +++ b/engines/hugo/file_v3d.cpp @@ -39,7 +39,7 @@ #include "hugo/util.h" namespace Hugo { -FileManager_v3d::FileManager_v3d(HugoEngine &vm) : FileManager_v2d(vm) { +FileManager_v3d::FileManager_v3d(HugoEngine *vm) : FileManager_v2d(vm) { } FileManager_v3d::~FileManager_v3d() { @@ -65,11 +65,11 @@ void FileManager_v3d::readBackground(int screenIndex) { if (screenIndex < 20) { _sceneryArchive1.seek(sceneBlock.scene_off, SEEK_SET); // Read the image into dummy seq and static dib_a - readPCX(_sceneryArchive1, &dummySeq, _vm.screen().getFrontBuffer(), true, _vm._screenNames[screenIndex]); + readPCX(_sceneryArchive1, &dummySeq, _vm->_screen->getFrontBuffer(), true, _vm->_screenNames[screenIndex]); } else { _sceneryArchive2.seek(sceneBlock.scene_off, SEEK_SET); // Read the image into dummy seq and static dib_a - readPCX(_sceneryArchive2, &dummySeq, _vm.screen().getFrontBuffer(), true, _vm._screenNames[screenIndex]); + readPCX(_sceneryArchive2, &dummySeq, _vm->_screen->getFrontBuffer(), true, _vm->_screenNames[screenIndex]); } } diff --git a/engines/hugo/hugo.cpp b/engines/hugo/hugo.cpp index a94a0b8302..e59ee9a61c 100644 --- a/engines/hugo/hugo.cpp +++ b/engines/hugo/hugo.cpp @@ -42,6 +42,7 @@ #include "hugo/util.h" #include "hugo/sound.h" #include "hugo/intro.h" +#include "hugo/object.h" #include "engines/util.h" @@ -63,8 +64,8 @@ command_t _line; // Line of user text input HugoEngine::HugoEngine(OSystem *syst, const HugoGameDescription *gd) : Engine(syst), _gameDescription(gd), _mouseX(0), _mouseY(0), _textData(0), _stringtData(0), _screenNames(0), _textEngine(0), _textIntro(0), _textMouse(0), _textParser(0), _textSchedule(0), _textUtil(0), _arrayNouns(0), _arrayVerbs(0), _arrayReqs(0), _hotspots(0), _invent(0), _uses(0), _catchallList(0), _backgroundObjects(0), - _points(0), _cmdList(0), _screenActs(0), _objects(0), _actListArr(0), _heroImage(0), _defltTunes(0), _palette(0), _introX(0), - _introY(0), _maxInvent(0), _numBonuses(0), _numScreens(0), _tunesNbr(0), _soundSilence(0), _soundTest(0), _screenStates(0), _numObj(0), + _points(0), _cmdList(0), _screenActs(0), _actListArr(0), _heroImage(0), _defltTunes(0), _palette(0), _introX(0), _introY(0), + _maxInvent(0), _numBonuses(0), _numScreens(0), _tunesNbr(0), _soundSilence(0), _soundTest(0), _screenStates(0), _numObj(0), _score(0), _maxscore(0) { @@ -82,14 +83,15 @@ HugoEngine::HugoEngine(OSystem *syst, const HugoGameDescription *gd) : Engine(sy } HugoEngine::~HugoEngine() { - delete _soundHandler; + delete _object; + delete _sound; delete _route; delete _parser; - delete _inventoryHandler; - delete _mouseHandler; + delete _inventory; + delete _mouse; delete _screen; delete _scheduler; - delete _fileManager; + delete _file; free(_palette); free(_introX); @@ -161,53 +163,54 @@ Common::Error HugoEngine::run() { s_Engine = this; initGraphics(320, 200, false); - _mouseHandler = new MouseHandler(*this); - _inventoryHandler = new InventoryHandler(*this); - _route = new Route(*this); - _soundHandler = new SoundHandler(*this); + _mouse = new MouseHandler(this); + _inventory = new InventoryHandler(this); + _route = new Route(this); + _sound = new SoundHandler(this); + _object = new ObjectHandler(this); switch (_gameVariant) { case 0: // H1 Win - _fileManager = new FileManager_v1w(*this); - _scheduler = new Scheduler_v3d(*this); - _introHandler = new intro_v1w(*this); - _screen = new Screen_v1w(*this); - _parser = new Parser_v1w(*this); + _file = new FileManager_v1w(this); + _scheduler = new Scheduler_v3d(this); + _intro = new intro_v1w(this); + _screen = new Screen_v1w(this); + _parser = new Parser_v1w(this); break; case 1: - _fileManager = new FileManager_v2d(*this); - _scheduler = new Scheduler_v3d(*this); - _introHandler = new intro_v2w(*this); - _screen = new Screen_v1w(*this); - _parser = new Parser_v1w(*this); + _file = new FileManager_v2d(this); + _scheduler = new Scheduler_v3d(this); + _intro = new intro_v2w(this); + _screen = new Screen_v1w(this); + _parser = new Parser_v1w(this); break; case 2: - _fileManager = new FileManager_v2d(*this); - _scheduler = new Scheduler_v3d(*this); - _introHandler = new intro_v3w(*this); - _screen = new Screen_v1w(*this); - _parser = new Parser_v1w(*this); + _file = new FileManager_v2d(this); + _scheduler = new Scheduler_v3d(this); + _intro = new intro_v3w(this); + _screen = new Screen_v1w(this); + _parser = new Parser_v1w(this); break; case 3: // H1 DOS - _fileManager = new FileManager_v1d(*this); - _scheduler = new Scheduler_v1d(*this); - _introHandler = new intro_v1d(*this); - _screen = new Screen_v1d(*this); - _parser = new Parser_v1d(*this); + _file = new FileManager_v1d(this); + _scheduler = new Scheduler_v1d(this); + _intro = new intro_v1d(this); + _screen = new Screen_v1d(this); + _parser = new Parser_v1d(this); break; case 4: - _fileManager = new FileManager_v2d(*this); - _scheduler = new Scheduler_v1d(*this); - _introHandler = new intro_v2d(*this); - _screen = new Screen_v1d(*this); - _parser = new Parser_v2d(*this); + _file = new FileManager_v2d(this); + _scheduler = new Scheduler_v1d(this); + _intro = new intro_v2d(this); + _screen = new Screen_v1d(this); + _parser = new Parser_v2d(this); break; case 5: - _fileManager = new FileManager_v3d(*this); - _scheduler = new Scheduler_v3d(*this); - _introHandler = new intro_v3d(*this); - _screen = new Screen_v1d(*this); - _parser = new Parser_v3d(*this); + _file = new FileManager_v3d(this); + _scheduler = new Scheduler_v3d(this); + _intro = new intro_v3d(this); + _screen = new Screen_v1d(this); + _parser = new Parser_v3d(this); break; } @@ -225,7 +228,7 @@ Common::Error HugoEngine::run() { initialize(); initConfig(RESET); // Reset user's config - file().restoreGame(-1); + _file->restoreGame(-1); initMachine(); @@ -243,7 +246,7 @@ Common::Error HugoEngine::run() { while (_eventMan->pollEvent(event)) { switch (event.type) { case Common::EVENT_KEYDOWN: - parser().keyHandler(event.kbd.keycode, 0); + _parser->keyHandler(event.kbd.keycode, 0); break; case Common::EVENT_MOUSEMOVE: _mouseX = event.mouse.x; @@ -276,10 +279,10 @@ void HugoEngine::initMachine() { if (_gameVariant == kGameVariantH1Dos) readScreenFiles(0); else - file().readBackground(_numScreens - 1); // Splash screen + _file->readBackground(_numScreens - 1); // Splash screen readObjectImages(); // Read all object images if (_platform == Common::kPlatformWindows) - readUIFImages(); // Read all uif images (only in Win versions) + _file->readUIFImages(); // Read all uif images (only in Win versions) } void HugoEngine::runMachine() { @@ -302,32 +305,32 @@ void HugoEngine::runMachine() { switch (gameStatus.viewState) { case V_IDLE: // Not processing state machine - intro().preNewGame(); // Any processing before New Game selected + _intro->preNewGame(); // Any processing before New Game selected break; case V_INTROINIT: // Initialization before intro begins - intro().introInit(); + _intro->introInit(); g_system->showMouse(false); gameStatus.viewState = V_INTRO; break; case V_INTRO: // Do any game-dependant preamble - if (intro().introPlay()) { // Process intro screen - scheduler().newScreen(0); // Initialize first screen + if (_intro->introPlay()) { // Process intro screen + _scheduler->newScreen(0); // Initialize first screen gameStatus.viewState = V_PLAY; } break; case V_PLAY: // Playing game g_system->showMouse(true); - parser().charHandler(); // Process user cmd input - moveObjects(); // Process object movement - scheduler().runScheduler(); // Process any actions - screen().displayList(D_RESTORE); // Restore previous background - updateImages(); // Draw into _frontBuffer, compile display list - mouse().mouseHandler(); // Mouse activity - adds to display list - screen().drawStatusText(); - screen().displayList(D_DISPLAY); // Blit the display list to screen + _parser->charHandler(); // Process user cmd input + _object->moveObjects(); // Process object movement + _scheduler->runScheduler(); // Process any actions + _screen->displayList(D_RESTORE); // Restore previous background + _object->updateImages(); // Draw into _frontBuffer, compile display list + _mouse->mouseHandler(); // Mouse activity - adds to display list + _screen->drawStatusText(); + _screen->displayList(D_DISPLAY); // Blit the display list to screen break; case V_INVENT: // Accessing inventory - inventory().runInventory(); // Process Inventory state machine + _inventory->runInventory(); // Process Inventory state machine break; case V_EXIT: // Game over or user exited gameStatus.viewState = V_IDLE; @@ -642,108 +645,10 @@ bool HugoEngine::loadHugoDat() { } } -// TODO: For Hugo3, if not in story mode, set _objects[2].state to 3 - for (int varnt = 0; varnt < _numVariant; varnt++) { - numElem = in.readUint16BE(); - if (varnt == _gameVariant) { - _objects = (object_t *)malloc(sizeof(object_t) * numElem); - for (int i = 0; i < numElem; i++) { - _objects[i].nounIndex = in.readUint16BE(); - _objects[i].dataIndex = in.readUint16BE(); - numSubElem = in.readUint16BE(); - if (numSubElem == 0) - _objects[i].stateDataIndex = 0; - else - _objects[i].stateDataIndex = (uint16 *)malloc(sizeof(uint16) * numSubElem); - for (int j = 0; j < numSubElem; j++) - _objects[i].stateDataIndex[j] = in.readUint16BE(); - _objects[i].pathType = (path_t) in.readSint16BE(); - _objects[i].vxPath = in.readSint16BE(); - _objects[i].vyPath = in.readSint16BE(); - _objects[i].actIndex = in.readUint16BE(); - _objects[i].seqNumb = in.readByte(); - _objects[i].currImagePtr = 0; - if (_objects[i].seqNumb == 0) { - _objects[i].seqList[0].imageNbr = 0; - _objects[i].seqList[0].seqPtr = 0; - } - for (int j = 0; j < _objects[i].seqNumb; j++) { - _objects[i].seqList[j].imageNbr = in.readUint16BE(); - _objects[i].seqList[j].seqPtr = 0; - } - _objects[i].cycling = (cycle_t)in.readByte(); - _objects[i].cycleNumb = in.readByte(); - _objects[i].frameInterval = in.readByte(); - _objects[i].frameTimer = in.readByte(); - _objects[i].radius = in.readByte(); - _objects[i].screenIndex = in.readByte(); - _objects[i].x = in.readSint16BE(); - _objects[i].y = in.readSint16BE(); - _objects[i].oldx = in.readSint16BE(); - _objects[i].oldy = in.readSint16BE(); - _objects[i].vx = in.readByte(); - _objects[i].vy = in.readByte(); - _objects[i].objValue = in.readByte(); - _objects[i].genericCmd = in.readSint16BE(); - _objects[i].cmdIndex = in.readUint16BE(); - _objects[i].carriedFl = (in.readByte() != 0); - _objects[i].state = in.readByte(); - _objects[i].verbOnlyFl = (in.readByte() != 0); - _objects[i].priority = in.readByte(); - _objects[i].viewx = in.readSint16BE(); - _objects[i].viewy = in.readSint16BE(); - _objects[i].direction = in.readSint16BE(); - _objects[i].curSeqNum = in.readByte(); - _objects[i].curImageNum = in.readByte(); - _objects[i].oldvx = in.readByte(); - _objects[i].oldvy = in.readByte(); - } - } else { - for (int i = 0; i < numElem; i++) { - in.readUint16BE(); - in.readUint16BE(); - numSubElem = in.readUint16BE(); - for (int j = 0; j < numSubElem; j++) - in.readUint16BE(); - in.readSint16BE(); - in.readSint16BE(); - in.readSint16BE(); - in.readUint16BE(); - numSubElem = in.readByte(); - for (int j = 0; j < numSubElem; j++) - in.readUint16BE(); - in.readByte(); - in.readByte(); - in.readByte(); - in.readByte(); - in.readByte(); - in.readByte(); - in.readSint16BE(); - in.readSint16BE(); - in.readSint16BE(); - in.readSint16BE(); - in.readByte(); - in.readByte(); - in.readByte(); - in.readSint16BE(); - in.readUint16BE(); - in.readByte(); - in.readByte(); - in.readByte(); - in.readByte(); - in.readSint16BE(); - in.readSint16BE(); - in.readUint16BE(); - in.readByte(); - in.readByte(); - in.readByte(); - in.readByte(); - } - } - } + _object->loadObject(in); //#define HERO 0 - _hero = &_objects[HERO]; // This always points to hero - _screen_p = &(_objects[HERO].screenIndex); // Current screen is hero's + _hero = &_object->_objects[HERO]; // This always points to hero + _screen_p = &(_object->_objects[HERO].screenIndex); // Current screen is hero's _heroImage = HERO; // Current in use hero image //read _actListArr @@ -1599,18 +1504,18 @@ void HugoEngine::initConfig(inst_t action) { _config.soundVolume = 100; // Sound volume % initPlaylist(_config.playlist); // Initialize default tune playlist - file().readBootFile(); // Read startup structure + _file->readBootFile(); // Read startup structure break; case RESET: // Find first tune and play it for (int16 i = 0; i < MAX_TUNES; i++) { if (_config.playlist[i]) { - sound().playMusic(i); + _sound->playMusic(i); break; } } - file().initSavedGame(); // Initialize saved game + _file->initSavedGame(); // Initialize saved game break; case RESTORE: warning("Unhandled action RESTORE"); @@ -1624,10 +1529,10 @@ void HugoEngine::initialize() { _maze.enabledFl = false; _line[0] = '\0'; - sound().initSound(); - scheduler().initEventQueue(); // Init scheduler stuff - screen().initDisplay(); // Create Dibs and palette - file().openDatabaseFiles(); // Open database files + _sound->initSound(); + _scheduler->initEventQueue(); // Init scheduler stuff + _screen->initDisplay(); // Create Dibs and palette + _file->openDatabaseFiles(); // Open database files calcMaxScore(); // Initialise maxscore _rnd = new Common::RandomSource(); @@ -1657,214 +1562,28 @@ void HugoEngine::initialize() { void HugoEngine::shutdown() { debugC(1, kDebugEngine, "shutdown"); - file().closeDatabaseFiles(); + _file->closeDatabaseFiles(); if (_status.recordFl || _status.playbackFl) - file().closePlaybackFile(); - freeObjects(); + _file->closePlaybackFile(); + _object->freeObjects(); } void HugoEngine::readObjectImages() { debugC(1, kDebugEngine, "readObjectImages"); for (int i = 0; i < _numObj; i++) - file().readImage(i, &_objects[i]); -} - -// Read the uif image file (inventory icons) -void HugoEngine::readUIFImages() { - debugC(1, kDebugEngine, "readUIFImages"); - - file().readUIFItem(UIF_IMAGES, screen().getGUIBuffer()); // Read all uif images + _file->readImage(i, &_object->_objects[i]); } // Read scenery, overlay files for given screen number void HugoEngine::readScreenFiles(int screenNum) { debugC(1, kDebugEngine, "readScreenFiles(%d)", screenNum); - file().readBackground(screenNum); // Scenery file - memcpy(screen().getBackBuffer(), screen().getFrontBuffer(), sizeof(screen().getFrontBuffer()));// Make a copy - file().readOverlay(screenNum, _boundary, BOUNDARY); // Boundary file - file().readOverlay(screenNum, _overlay, OVERLAY); // Overlay file - file().readOverlay(screenNum, _ovlBase, OVLBASE); // Overlay base file -} - -// Update all object positions. Process object 'local' events -// including boundary events and collisions -void HugoEngine::moveObjects() { - debugC(4, kDebugEngine, "moveObjects"); - - // If route mode enabled, do special route processing - if (_status.routeIndex >= 0) - route().processRoute(); - - // Perform any adjustments to velocity based on special path types - // and store all (visible) object baselines into the boundary file. - // Don't store foreground or background objects - for (int i = 0; i < _numObj; i++) { - object_t *obj = &_objects[i]; // Get pointer to object - seq_t *currImage = obj->currImagePtr; // Get ptr to current image - if (obj->screenIndex == *_screen_p) { - switch (obj->pathType) { - case CHASE: - case CHASE2: { - int8 radius = obj->radius; // Default to object's radius - if (radius < 0) // If radius infinity, use closer value - radius = DX; - - // Allowable motion wrt boundary - int dx = _hero->x + _hero->currImagePtr->x1 - obj->x - currImage->x1; - int dy = _hero->y + _hero->currImagePtr->y2 - obj->y - currImage->y2 - 1; - if (abs(dx) <= radius) - obj->vx = 0; - else - obj->vx = (dx > 0) ? MIN(dx, obj->vxPath) : MAX(dx, -obj->vxPath); - if (abs(dy) <= radius) - obj->vy = 0; - else - obj->vy = (dy > 0) ? MIN(dy, obj->vyPath) : MAX(dy, -obj->vyPath); - - // Set first image in sequence (if multi-seq object) - switch (obj->seqNumb) { - case 4: - if (!obj->vx) { // Got 4 directions - if (obj->vx != obj->oldvx) { // vx just stopped - if (dy >= 0) - obj->currImagePtr = obj->seqList[DOWN].seqPtr; - else - obj->currImagePtr = obj->seqList[_UP].seqPtr; - } - } else if (obj->vx != obj->oldvx) { - if (dx > 0) - obj->currImagePtr = obj->seqList[RIGHT].seqPtr; - else - obj->currImagePtr = obj->seqList[LEFT].seqPtr; - } - break; - case 3: - case 2: - if (obj->vx != obj->oldvx) { // vx just stopped - if (dx > 0) // Left & right only - obj->currImagePtr = obj->seqList[RIGHT].seqPtr; - else - obj->currImagePtr = obj->seqList[LEFT].seqPtr; - } - break; - } - - if (obj->vx || obj->vy) - obj->cycling = CYCLE_FORWARD; - else { - obj->cycling = NOT_CYCLING; - boundaryCollision(obj); // Must have got hero! - } - obj->oldvx = obj->vx; - obj->oldvy = obj->vy; - currImage = obj->currImagePtr; // Get (new) ptr to current image - break; - } - case WANDER2: - case WANDER: - if (!_rnd->getRandomNumber(3 * NORMAL_TPS)) { // Kick on random interval - obj->vx = _rnd->getRandomNumber(obj->vxPath << 1) - obj->vxPath; - obj->vy = _rnd->getRandomNumber(obj->vyPath << 1) - obj->vyPath; - - // Set first image in sequence (if multi-seq object) - if (obj->seqNumb > 1) { - if (!obj->vx && (obj->seqNumb >= 4)) { - if (obj->vx != obj->oldvx) { // vx just stopped - if (obj->vy > 0) - obj->currImagePtr = obj->seqList[DOWN].seqPtr; - else - obj->currImagePtr = obj->seqList[_UP].seqPtr; - } - } else if (obj->vx != obj->oldvx) { - if (obj->vx > 0) - obj->currImagePtr = obj->seqList[RIGHT].seqPtr; - else - obj->currImagePtr = obj->seqList[LEFT].seqPtr; - } - } - obj->oldvx = obj->vx; - obj->oldvy = obj->vy; - currImage = obj->currImagePtr; // Get (new) ptr to current image - } - if (obj->vx || obj->vy) - obj->cycling = CYCLE_FORWARD; - break; - default: - ; // Really, nothing - } - // Store boundaries - if ((obj->cycling > ALMOST_INVISIBLE) && (obj->priority == FLOATING)) - storeBoundary(obj->x + currImage->x1, obj->x + currImage->x2, obj->y + currImage->y2); - } - } - - // Move objects, allowing for boundaries - for (int i = 0; i < _numObj; i++) { - object_t *obj = &_objects[i]; // Get pointer to object - if ((obj->screenIndex == *_screen_p) && (obj->vx || obj->vy)) { - // Only process if it's moving - - // Do object movement. Delta_x,y return allowed movement in x,y - // to move as close to a boundary as possible without crossing it. - seq_t *currImage = obj->currImagePtr; // Get ptr to current image - // object coordinates - int x1 = obj->x + currImage->x1; // Left edge of object - int x2 = obj->x + currImage->x2; // Right edge - int y1 = obj->y + currImage->y1; // Top edge - int y2 = obj->y + currImage->y2; // Bottom edge - - if ((obj->cycling > ALMOST_INVISIBLE) && (obj->priority == FLOATING)) - clearBoundary(x1, x2, y2); // Clear our own boundary - - // Allowable motion wrt boundary - int dx = deltaX(x1, x2, obj->vx, y2); - if (dx != obj->vx) { - // An object boundary collision! - boundaryCollision(obj); - obj->vx = 0; - } - - int dy = deltaY(x1, x2, obj->vy, y2); - if (dy != obj->vy) { - // An object boundary collision! - boundaryCollision(obj); - obj->vy = 0; - } - - if ((obj->cycling > ALMOST_INVISIBLE) && (obj->priority == FLOATING)) - storeBoundary(x1, x2, y2); // Re-store our own boundary - - obj->x += dx; // Update object position - obj->y += dy; - - // Don't let object go outside screen - if (x1 < EDGE) - obj->x = EDGE2; - if (x2 > (XPIX - EDGE)) - obj->x = XPIX - EDGE2 - (x2 - x1); - if (y1 < EDGE) - obj->y = EDGE2; - if (y2 > (YPIX - EDGE)) - obj->y = YPIX - EDGE2 - (y2 - y1); - - if ((obj->vx == 0) && (obj->vy == 0) && (obj->pathType != WANDER2) && (obj->pathType != CHASE2)) - obj->cycling = NOT_CYCLING; - } - } - - // Clear all object baselines from the boundary file. - for (int i = 0; i < _numObj; i++) { - object_t *obj = &_objects[i]; // Get pointer to object - seq_t *currImage = obj->currImagePtr; // Get ptr to current image - if ((obj->screenIndex == *_screen_p) && (obj->cycling > ALMOST_INVISIBLE) && (obj->priority == FLOATING)) - clearBoundary(obj->oldx + currImage->x1, obj->oldx + currImage->x2, obj->oldy + currImage->y2); - } - - // If maze mode is enabled, do special maze processing - if (_maze.enabledFl) - processMaze(); + _file->readBackground(screenNum); // Scenery file + memcpy(_screen->getBackBuffer(), _screen->getFrontBuffer(), sizeof(_screen->getFrontBuffer()));// Make a copy + _file->readOverlay(screenNum, _boundary, BOUNDARY); // Boundary file + _file->readOverlay(screenNum, _overlay, OVERLAY); // Overlay file + _file->readOverlay(screenNum, _ovlBase, OVLBASE); // Overlay base file } // Return maximum allowed movement (from zero to vx) such that object does @@ -1993,218 +1712,31 @@ void HugoEngine::processMaze() { _actListArr[_alNewscrIndex][0].a2.x = _maze.x2 - SHIFT - (x2 - x1); _actListArr[_alNewscrIndex][0].a2.y = _hero->y; _status.routeIndex = -1; - scheduler().insertActionList(_alNewscrIndex); + _scheduler->insertActionList(_alNewscrIndex); } else if (x2 > _maze.x2) { // Exit east _actListArr[_alNewscrIndex][3].a8.screenIndex = *_screen_p + 1; _actListArr[_alNewscrIndex][0].a2.x = _maze.x1 + SHIFT; _actListArr[_alNewscrIndex][0].a2.y = _hero->y; _status.routeIndex = -1; - scheduler().insertActionList(_alNewscrIndex); + _scheduler->insertActionList(_alNewscrIndex); } else if (y1 < _maze.y1 - SHIFT) { // Exit north _actListArr[_alNewscrIndex][3].a8.screenIndex = *_screen_p - _maze.size; _actListArr[_alNewscrIndex][0].a2.x = _maze.x3; _actListArr[_alNewscrIndex][0].a2.y = _maze.y2 - SHIFT - (y2 - y1); _status.routeIndex = -1; - scheduler().insertActionList(_alNewscrIndex); + _scheduler->insertActionList(_alNewscrIndex); } else if (y2 > _maze.y2 - SHIFT / 2) { // Exit south _actListArr[_alNewscrIndex][3].a8.screenIndex = *_screen_p + _maze.size; _actListArr[_alNewscrIndex][0].a2.x = _maze.x4; _actListArr[_alNewscrIndex][0].a2.y = _maze.y1 + SHIFT; _status.routeIndex = -1; - scheduler().insertActionList(_alNewscrIndex); + _scheduler->insertActionList(_alNewscrIndex); } } -// Compare function for the quicksort. The sort is to order the objects in -// increasing vertical position, using y+y2 as the baseline -// Returns -1 if ay2 < by2 else 1 if ay2 > by2 else 0 -int HugoEngine::y2comp(const void *a, const void *b) { - debugC(6, kDebugEngine, "y2comp"); - - const object_t *p1 = &s_Engine->_objects[*(const byte *)a]; - const object_t *p2 = &s_Engine->_objects[*(const byte *)b]; - - if (p1 == p2) - // Why does qsort try the same indexes? - return 0; - - if (p1->priority == BACKGROUND) - return -1; - - if (p2->priority == BACKGROUND) - return 1; - - if (p1->priority == FOREGROUND) - return 1; - - if (p2->priority == FOREGROUND) - return -1; - - int ay2 = p1->y + p1->currImagePtr->y2; - int by2 = p2->y + p2->currImagePtr->y2; - - return ay2 - by2; -} - -// Draw all objects on screen as follows: -// 1. Sort 'FLOATING' objects in order of y2 (base of object) -// 2. Display new object frames/positions in dib -// Finally, cycle any animating objects to next frame -void HugoEngine::updateImages() { - debugC(5, kDebugEngine, "updateImages"); - - // Initialise the index array to visible objects in current screen - int num_objs = 0; - byte objindex[MAX_OBJECTS]; // Array of indeces to objects - - for (int i = 0; i < _numObj; i++) { - object_t *obj = &_objects[i]; - if ((obj->screenIndex == *_screen_p) && (obj->cycling >= ALMOST_INVISIBLE)) - objindex[num_objs++] = i; - } - - // Sort the objects into increasing y+y2 (painter's algorithm) - qsort(objindex, num_objs, sizeof(objindex[0]), y2comp); - - // Add each visible object to display list - for (int i = 0; i < num_objs; i++) { - object_t *obj = &_objects[objindex[i]]; - // Count down inter-frame timer - if (obj->frameTimer) - obj->frameTimer--; - - if (obj->cycling > ALMOST_INVISIBLE) { // Only if visible - switch (obj->cycling) { - case NOT_CYCLING: - screen().displayFrame(obj->x, obj->y, obj->currImagePtr, obj->priority == OVEROVL); - break; - case CYCLE_FORWARD: - if (obj->frameTimer) // Not time to see next frame yet - screen().displayFrame(obj->x, obj->y, obj->currImagePtr, obj->priority == OVEROVL); - else - screen().displayFrame(obj->x, obj->y, obj->currImagePtr->nextSeqPtr, obj->priority == OVEROVL); - break; - case CYCLE_BACKWARD: { - seq_t *seqPtr = obj->currImagePtr; - if (!obj->frameTimer) { // Show next frame - while (seqPtr->nextSeqPtr != obj->currImagePtr) - seqPtr = seqPtr->nextSeqPtr; - } - screen().displayFrame(obj->x, obj->y, seqPtr, obj->priority == OVEROVL); - break; - } - default: - break; - } - } - } - - // Cycle any animating objects - for (int i = 0; i < num_objs; i++) { - object_t *obj = &_objects[objindex[i]]; - if (obj->cycling != INVISIBLE) { - // Only if it's visible - if (obj->cycling == ALMOST_INVISIBLE) - obj->cycling = INVISIBLE; - - // Now Rotate to next picture in sequence - switch (obj->cycling) { - case NOT_CYCLING: - break; - case CYCLE_FORWARD: - if (!obj->frameTimer) { - // Time to step to next frame - obj->currImagePtr = obj->currImagePtr->nextSeqPtr; - // Find out if this is last frame of sequence - // If so, reset frame_timer and decrement n_cycle - if (obj->frameInterval || obj->cycleNumb) { - obj->frameTimer = obj->frameInterval; - for (int j = 0; j < obj->seqNumb; j++) { - if (obj->currImagePtr->nextSeqPtr == obj->seqList[j].seqPtr) { - if (obj->cycleNumb) { // Decr cycleNumb if Non-continous - if (!--obj->cycleNumb) - obj->cycling = NOT_CYCLING; - } - } - } - } - } - break; - case CYCLE_BACKWARD: { - if (!obj->frameTimer) { - // Time to step to prev frame - seq_t *seqPtr = obj->currImagePtr; - while (obj->currImagePtr->nextSeqPtr != seqPtr) - obj->currImagePtr = obj->currImagePtr->nextSeqPtr; - // Find out if this is first frame of sequence - // If so, reset frame_timer and decrement n_cycle - if (obj->frameInterval || obj->cycleNumb) { - obj->frameTimer = obj->frameInterval; - for (int j = 0; j < obj->seqNumb; j++) { - if (obj->currImagePtr == obj->seqList[j].seqPtr) { - if (obj->cycleNumb){ // Decr cycleNumb if Non-continous - if (!--obj->cycleNumb) - obj->cycling = NOT_CYCLING; - } - } - } - } - } - break; - } - default: - break; - } - obj->oldx = obj->x; - obj->oldy = obj->y; - } - } -} - -// Return object index of the topmost object under the cursor, or -1 if none -// Objects are filtered if not "useful" -int16 HugoEngine::findObject(uint16 x, uint16 y) { - debugC(3, kDebugEngine, "findObject(%d, %d)", x, y); - - int16 objIndex = -1; // Index of found object - uint16 y2Max = 0; // Greatest y2 - object_t *obj = _objects; - // Check objects on screen - for (int i = 0; i < _numObj; i++, obj++) { - // Object must be in current screen and "useful" - if (obj->screenIndex == *_screen_p && (obj->genericCmd || obj->objValue || obj->cmdIndex)) { - seq_t *curImage = obj->currImagePtr; - // Object must have a visible image... - if (curImage != 0 && obj->cycling != INVISIBLE) { - // If cursor inside object - if (x >= (uint16)obj->x && x <= obj->x + curImage->x2 && y >= (uint16)obj->y && y <= obj->y + curImage->y2) { - // If object is closest so far - if (obj->y + curImage->y2 > y2Max) { - y2Max = obj->y + curImage->y2; - objIndex = i; // Found an object! - } - } - } else { - // ...or a dummy object that has a hotspot rectangle - if (curImage == 0 && obj->vxPath != 0 && !obj->carriedFl) { - // If cursor inside special rectangle - if ((int16)x >= obj->oldx && (int16)x < obj->oldx + obj->vxPath && (int16)y >= obj->oldy && (int16)y < obj->oldy + obj->vyPath) { - // If object is closest so far - if (obj->oldy + obj->vyPath - 1 > (int16)y2Max) { - y2Max = obj->oldy + obj->vyPath - 1; - objIndex = i; // Found an object! - } - } - } - } - } - } - return objIndex; -} - // Find a clear space around supplied object that hero can walk to bool HugoEngine::findObjectSpace(object_t *obj, int16 *destx, int16 *desty) { debugC(1, kDebugEngine, "findObjectSpace(obj, %d, %d)", *destx, *desty); @@ -2264,97 +1796,6 @@ char *HugoEngine::useBG(char *name) { return 0; } -// If status.objid = -1, pick up objid, else use status.objid on objid, -// if objid can't be picked up, use it directly -void HugoEngine::useObject(int16 objId) { - debugC(1, kDebugEngine, "useObject(%d)", objId); - - char *verb; // Background verb to use directly - object_t *obj = &_objects[objId]; // Ptr to object - if (_status.inventoryObjId == -1) { - // Get or use objid directly - if ((obj->genericCmd & TAKE) || obj->objValue) // Get collectible item - sprintf(_line, "%s %s", _arrayVerbs[_take][0], _arrayNouns[obj->nounIndex][0]); - else if (obj->genericCmd & LOOK) // Look item - sprintf(_line, "%s %s", _arrayVerbs[_look][0], _arrayNouns[obj->nounIndex][0]); - else if (obj->genericCmd & DROP) // Drop item - sprintf(_line, "%s %s", _arrayVerbs[_drop][0], _arrayNouns[obj->nounIndex][0]); - else if (obj->cmdIndex != 0) // Use non-collectible item if able - sprintf(_line, "%s %s", _arrayVerbs[_cmdList[obj->cmdIndex][1].verbIndex][0], _arrayNouns[obj->nounIndex][0]); - else if ((verb = useBG(_arrayNouns[obj->nounIndex][0])) != 0) - sprintf(_line, "%s %s", verb, _arrayNouns[obj->nounIndex][0]); - else - return; // Can't use object directly - } else { - // Use status.objid on objid - // Default to first cmd verb - sprintf(_line, "%s %s %s", _arrayVerbs[_cmdList[_objects[_status.inventoryObjId].cmdIndex][1].verbIndex][0], _arrayNouns[_objects[_status.inventoryObjId].nounIndex][0], _arrayNouns[obj->nounIndex][0]); - - // Check valid use of objects and override verb if necessary - for (uses_t *use = _uses; use->objId != _numObj; use++) { - if (_status.inventoryObjId == use->objId) { - // Look for secondary object, if found use matching verb - bool foundFl = false; - for (target_t *target = use->targets; _arrayNouns[target->nounIndex] != 0; target++) - if (_arrayNouns[target->nounIndex][0] == _arrayNouns[obj->nounIndex][0]) { - foundFl = true; - sprintf(_line, "%s %s %s", _arrayVerbs[target->verbIndex][0], _arrayNouns[_objects[_status.inventoryObjId].nounIndex][0], _arrayNouns[obj->nounIndex][0]); - } - - // No valid use of objects found, print failure string - if (!foundFl) { - // Deselect dragged icon if inventory not active - if (_status.inventoryState != I_ACTIVE) - _status.inventoryObjId = -1; - Utils::Box(BOX_ANY, "%s", _textData[use->dataIndex]); - return; - } - } - } - } - - if (_status.inventoryState == I_ACTIVE) // If inventory active, remove it - _status.inventoryState = I_UP; - _status.inventoryObjId = -1; // Deselect any dragged icon - parser().lineHandler(); // and process command -} - -// Issue "Look at <object>" command -// Note special case of swapped hero image -void HugoEngine::lookObject(object_t *obj) { - debugC(1, kDebugEngine, "lookObject"); - - if (obj == _hero) - // Hero swapped - look at other - obj = &_objects[_heroImage]; - - parser().command("%s %s", _arrayVerbs[_look][0], _arrayNouns[obj->nounIndex][0]); -} - -// Free all object images -void HugoEngine::freeObjects() { - debugC(1, kDebugEngine, "freeObjects"); - - // Nothing to do if not allocated yet - if (_hero->seqList[0].seqPtr == 0) - return; - - // Free all sequence lists and image data - for (int i = 0; i < _numObj; i++) { - object_t *obj = &_objects[i]; - for (int j = 0; j < obj->seqNumb; j++) { // for each sequence - seq_t *seq = obj->seqList[j].seqPtr; // Free image - if (seq == 0) // Failure during database load - break; - do { - free(seq->imagePtr); - seq = seq->nextSeqPtr; - } while (seq != obj->seqList[j].seqPtr); - free(seq); // Free sequence record - } - } -} - // Add action lists for this screen to event queue void HugoEngine::screenActions(int screenNum) { debugC(1, kDebugEngine, "screenActions(%d)", screenNum); @@ -2362,7 +1803,7 @@ void HugoEngine::screenActions(int screenNum) { uint16 *screenAct = _screenActs[screenNum]; if (screenAct) { for (int i = 0; screenAct[i]; i++) - scheduler().insertActionList(screenAct[i]); + _scheduler->insertActionList(screenAct[i]); } } @@ -2372,8 +1813,8 @@ void HugoEngine::setNewScreen(int screenNum) { *_screen_p = screenNum; // HERO object for (int i = HERO + 1; i < _numObj; i++) { // Any others - if (_objects[i].carriedFl) // being carried - _objects[i].screenIndex = screenNum; + if (_object->isCarried(i)) // being carried + _object->_objects[i].screenIndex = screenNum; } } @@ -2394,7 +1835,7 @@ void HugoEngine::boundaryCollision(object_t *obj) { hotspot_t *hotspot = &_hotspots[i]; if (hotspot->screenIndex == obj->screenIndex) if ((x >= hotspot->x1) && (x <= hotspot->x2) && (y >= hotspot->y1) && (y <= hotspot->y2)) { - scheduler().insertActionList(hotspot->actIndex); + _scheduler->insertActionList(hotspot->actIndex); break; } } @@ -2407,7 +1848,7 @@ void HugoEngine::boundaryCollision(object_t *obj) { if (radius < 0) radius = DX * 2; if ((abs(dx) <= radius) && (abs(dy) <= radius)) - scheduler().insertActionList(obj->actIndex); + _scheduler->insertActionList(obj->actIndex); } } @@ -2416,7 +1857,7 @@ void HugoEngine::calcMaxScore() { debugC(1, kDebugEngine, "calcMaxScore"); for (int i = 0; i < _numObj; i++) - _maxscore += _objects[i].objValue; + _maxscore += _object->_objects[i].objValue; for (int i = 0; i < _numBonuses; i++) _maxscore += _points[i].score; diff --git a/engines/hugo/hugo.h b/engines/hugo/hugo.h index cf01eb83ca..633f1829ab 100644 --- a/engines/hugo/hugo.h +++ b/engines/hugo/hugo.h @@ -38,7 +38,6 @@ #define EDGE 10 // Closest object can get to edge of screen #define EDGE2 (EDGE * 2) // Push object further back on edge collision #define SHIFT 8 // Place hero this far inside bounding box -#define MAX_OBJECTS 128 // Used in Update_images() #define BOUND(X, Y) ((_boundary[Y * XBYTES + X / 8] & (0x80 >> X % 8)) != 0) // Boundary bit set namespace Common { @@ -103,6 +102,7 @@ class Parser; class Route; class SoundHandler; class IntroHandler; +class ObjectHandler; class HugoEngine : public Engine { @@ -149,7 +149,6 @@ public: point_t *_points; cmd **_cmdList; uint16 **_screenActs; - object_t *_objects; act **_actListArr; int16 *_defltTunes; uint16 _look; @@ -181,34 +180,6 @@ public: return *s_Engine; } - FileManager &file() { - return *_fileManager; - } - Scheduler &scheduler() { - return *_scheduler; - } - Screen &screen() { - return *_screen; - } - MouseHandler &mouse() { - return *_mouseHandler; - } - InventoryHandler &inventory() { - return *_inventoryHandler; - } - Parser &parser() { - return *_parser; - } - Route &route() { - return *_route; - } - SoundHandler &sound() { - return *_soundHandler; - } - IntroHandler &intro() { - return *_introHandler; - } - void initGame(const HugoGameDescription *gd); void initGamePart(const HugoGameDescription *gd); bool loadHugoDat(); @@ -220,22 +191,24 @@ public: return _mouseY; } - void initStatus(); - void readObjectImages(); - void readUIFImages(); - void updateImages(); - void moveObjects(); - void useObject(int16 objId); bool findObjectSpace(object_t *obj, int16 *destx, int16 *desty); - int16 findObject(uint16 x, uint16 y); - void lookObject(object_t *obj); - void storeBoundary(int x1, int x2, int y); + + void boundaryCollision(object_t *obj); void clearBoundary(int x1, int x2, int y); void endGame(); + void initStatus(); + void processMaze(); + void readObjectImages(); void readScreenFiles(int screen); - void setNewScreen(int screen); void screenActions(int screen); + void setNewScreen(int screen); void shutdown(); + void storeBoundary(int x1, int x2, int y); + + char *useBG(char *name); + + int deltaX(int x1, int x2, int vx, int y); + int deltaY(int x1, int x2, int vy, int y); overlay_t &getBoundaryOverlay() { return _boundary; @@ -271,6 +244,17 @@ public: return _introXSize; } + FileManager *_file; + Scheduler *_scheduler; + Screen *_screen; + MouseHandler *_mouse; + InventoryHandler *_inventory; + Parser *_parser; + Route *_route; + SoundHandler *_sound; + IntroHandler *_intro; + ObjectHandler *_object; + protected: // Engine APIs @@ -301,16 +285,6 @@ private: Common::Platform _platform; bool _packedFl; - FileManager *_fileManager; - Scheduler *_scheduler; - Screen *_screen; - MouseHandler *_mouseHandler; - InventoryHandler *_inventoryHandler; - Parser *_parser; - Route *_route; - SoundHandler *_soundHandler; - IntroHandler *_introHandler; - int _score; // Holds current score int _maxscore; // Holds maximum score @@ -323,19 +297,10 @@ private: void initPlaylist(bool playlist[MAX_TUNES]); void initConfig(inst_t action); void initialize(); - int deltaX(int x1, int x2, int vx, int y); - int deltaY(int x1, int x2, int vy, int y); - void processMaze(); - //int y2comp (const void *a, const void *b); - char *useBG(char *name); - void freeObjects(); - void boundaryCollision(object_t *obj); void calcMaxScore(); void initMachine(); void runMachine(); - static int y2comp(const void *a, const void *b); - }; } // End of namespace Hugo diff --git a/engines/hugo/intro.cpp b/engines/hugo/intro.cpp index b818bef027..d63a979fe1 100644 --- a/engines/hugo/intro.cpp +++ b/engines/hugo/intro.cpp @@ -37,7 +37,7 @@ namespace Hugo { -IntroHandler::IntroHandler(HugoEngine &vm) : _vm(vm) { +IntroHandler::IntroHandler(HugoEngine *vm) : _vm(vm) { } IntroHandler::~IntroHandler() { diff --git a/engines/hugo/intro.h b/engines/hugo/intro.h index f8f1f95514..f1de01e609 100644 --- a/engines/hugo/intro.h +++ b/engines/hugo/intro.h @@ -43,7 +43,7 @@ enum seqTextIntro { class IntroHandler { public: - IntroHandler(HugoEngine &vm); + IntroHandler(HugoEngine *vm); virtual ~IntroHandler(); virtual void preNewGame() = 0; @@ -51,13 +51,13 @@ public: virtual bool introPlay() = 0; protected: - HugoEngine &_vm; + HugoEngine *_vm; int16 introTicks; // Count calls to introPlay() }; class intro_v1w : public IntroHandler { public: - intro_v1w(HugoEngine &vm); + intro_v1w(HugoEngine *vm); ~intro_v1w(); void preNewGame(); @@ -67,7 +67,7 @@ public: class intro_v1d : public IntroHandler { public: - intro_v1d(HugoEngine &vm); + intro_v1d(HugoEngine *vm); ~intro_v1d(); void preNewGame(); @@ -77,7 +77,7 @@ public: class intro_v2w : public IntroHandler { public: - intro_v2w(HugoEngine &vm); + intro_v2w(HugoEngine *vm); ~intro_v2w(); void preNewGame(); @@ -87,7 +87,7 @@ public: class intro_v2d : public IntroHandler { public: - intro_v2d(HugoEngine &vm); + intro_v2d(HugoEngine *vm); ~intro_v2d(); void preNewGame(); @@ -97,7 +97,7 @@ public: class intro_v3w : public IntroHandler { public: - intro_v3w(HugoEngine &vm); + intro_v3w(HugoEngine *vm); ~intro_v3w(); void preNewGame(); @@ -107,7 +107,7 @@ public: class intro_v3d : public IntroHandler { public: - intro_v3d(HugoEngine &vm); + intro_v3d(HugoEngine *vm); ~intro_v3d(); void preNewGame(); diff --git a/engines/hugo/intro_v1d.cpp b/engines/hugo/intro_v1d.cpp index 0e3067f0e9..61626e8172 100644 --- a/engines/hugo/intro_v1d.cpp +++ b/engines/hugo/intro_v1d.cpp @@ -37,7 +37,7 @@ #include "hugo/display.h" namespace Hugo { -intro_v1d::intro_v1d(HugoEngine &vm) : IntroHandler(vm) { +intro_v1d::intro_v1d(HugoEngine *vm) : IntroHandler(vm) { } intro_v1d::~intro_v1d() { @@ -52,116 +52,116 @@ void intro_v1d::introInit() { bool intro_v1d::introPlay() { static int state = 0; - byte introSize = _vm.getIntroSize(); + byte introSize = _vm->getIntroSize(); if (introTicks < introSize) { switch (state++) { case 0: - _vm.screen().drawRectangle(true, 0, 0, 319, 199, _TMAGENTA); - _vm.screen().drawRectangle(true, 10, 10, 309, 189, _TBLACK); + _vm->_screen->drawRectangle(true, 0, 0, 319, 199, _TMAGENTA); + _vm->_screen->drawRectangle(true, 10, 10, 309, 189, _TBLACK); break; case 1: - _vm.screen().drawShape(20, 92,_TLIGHTMAGENTA,_TMAGENTA); - _vm.screen().drawShape(250,92,_TLIGHTMAGENTA,_TMAGENTA); + _vm->_screen->drawShape(20, 92,_TLIGHTMAGENTA,_TMAGENTA); + _vm->_screen->drawShape(250,92,_TLIGHTMAGENTA,_TMAGENTA); // HACK: use of TROMAN, size 10-5 - _vm.screen().loadFont(0); + _vm->_screen->loadFont(0); char buffer[80]; if (_boot.registered) strcpy(buffer, "Registered Version"); else strcpy(buffer, "Shareware Version"); - _vm.screen().writeStr(CENTER, 163, buffer, _TLIGHTMAGENTA); - _vm.screen().writeStr(CENTER, 176, COPYRIGHT, _TLIGHTMAGENTA); + _vm->_screen->writeStr(CENTER, 163, buffer, _TLIGHTMAGENTA); + _vm->_screen->writeStr(CENTER, 176, COPYRIGHT, _TLIGHTMAGENTA); if (scumm_stricmp(_boot.distrib, "David P. Gray")) { sprintf(buffer, "Distributed by %s.", _boot.distrib); - _vm.screen().writeStr(CENTER, 75, buffer, _TMAGENTA); + _vm->_screen->writeStr(CENTER, 75, buffer, _TMAGENTA); } // HACK: use of SCRIPT size 24-16 - _vm.screen().loadFont(2); + _vm->_screen->loadFont(2); strcpy(buffer, "Hugo's"); - _vm.screen().writeStr(CENTER, 20, buffer, _TMAGENTA); + _vm->_screen->writeStr(CENTER, 20, buffer, _TMAGENTA); // HACK: use of TROMAN, size 30-24 strcpy(buffer, "House of Horrors !"); - _vm.screen().writeStr(CENTER, 50, buffer, _TLIGHTMAGENTA); + _vm->_screen->writeStr(CENTER, 50, buffer, _TLIGHTMAGENTA); break; case 2: - _vm.screen().drawRectangle(true, 82, 92, 237, 138, _TBLACK); + _vm->_screen->drawRectangle(true, 82, 92, 237, 138, _TBLACK); // HACK: use of TROMAN, size 16-9 - _vm.screen().loadFont(2); + _vm->_screen->loadFont(2); strcpy(buffer, "S t a r r i n g :"); - _vm.screen().writeStr(CENTER, 95, buffer, _TMAGENTA); + _vm->_screen->writeStr(CENTER, 95, buffer, _TMAGENTA); break; case 3: // HACK: use of TROMAN size 20-9 - _vm.screen().loadFont(2); + _vm->_screen->loadFont(2); strcpy(buffer, "Hugo !"); - _vm.screen().writeStr(CENTER, 115, buffer, _TLIGHTMAGENTA); + _vm->_screen->writeStr(CENTER, 115, buffer, _TLIGHTMAGENTA); break; case 4: - _vm.screen().drawRectangle(true, 82, 92, 237, 138, _TBLACK); + _vm->_screen->drawRectangle(true, 82, 92, 237, 138, _TBLACK); // HACK: use of TROMAN size 16-9 - _vm.screen().loadFont(2); + _vm->_screen->loadFont(2); strcpy(buffer, "P r o d u c e d b y :"); - _vm.screen().writeStr(CENTER, 95, buffer, _TMAGENTA); + _vm->_screen->writeStr(CENTER, 95, buffer, _TMAGENTA); break; case 5: // HACK: use of TROMAN size 16-9 - _vm.screen().loadFont(2); + _vm->_screen->loadFont(2); strcpy(buffer, "David P Gray !"); - _vm.screen().writeStr(CENTER, 115, buffer, _TLIGHTMAGENTA); + _vm->_screen->writeStr(CENTER, 115, buffer, _TLIGHTMAGENTA); break; case 6: - _vm.screen().drawRectangle(true, 82, 92, 237, 138, _TBLACK); + _vm->_screen->drawRectangle(true, 82, 92, 237, 138, _TBLACK); // HACK: use of TROMAN size 16-9 - _vm.screen().loadFont(2); + _vm->_screen->loadFont(2); strcpy(buffer, "D i r e c t e d b y :"); - _vm.screen().writeStr(CENTER, 95, buffer, _TMAGENTA); + _vm->_screen->writeStr(CENTER, 95, buffer, _TMAGENTA); break; case 7: // HACK: use of TROMAN size 16-9 - _vm.screen().loadFont(2); + _vm->_screen->loadFont(2); strcpy(buffer, "David P Gray !"); - _vm.screen().writeStr(CENTER, 115, buffer, _TLIGHTMAGENTA); + _vm->_screen->writeStr(CENTER, 115, buffer, _TLIGHTMAGENTA); break; case 8: - _vm.screen().drawRectangle(true, 82, 92, 237, 138, _TBLACK); + _vm->_screen->drawRectangle(true, 82, 92, 237, 138, _TBLACK); // HACK: use of TROMAN size 16-9 - _vm.screen().loadFont(2); + _vm->_screen->loadFont(2); strcpy(buffer, "M u s i c b y :"); - _vm.screen().writeStr(CENTER, 95, buffer, _TMAGENTA); + _vm->_screen->writeStr(CENTER, 95, buffer, _TMAGENTA); break; case 9: // HACK: use of TROMAN size 16-9 - _vm.screen().loadFont(2); + _vm->_screen->loadFont(2); strcpy(buffer, "David P Gray !"); - _vm.screen().writeStr(CENTER, 115, buffer, _TLIGHTMAGENTA); + _vm->_screen->writeStr(CENTER, 115, buffer, _TLIGHTMAGENTA); break; case 10: - _vm.screen().drawRectangle(true, 82, 92, 237, 138, _TBLACK); + _vm->_screen->drawRectangle(true, 82, 92, 237, 138, _TBLACK); // HACK: use of TROMAN size 20-14 - _vm.screen().loadFont(2); + _vm->_screen->loadFont(2); strcpy(buffer, "E n j o y !"); - _vm.screen().writeStr(CENTER, 100, buffer, _TLIGHTMAGENTA); + _vm->_screen->writeStr(CENTER, 100, buffer, _TLIGHTMAGENTA); break; } - _vm.screen().displayBackground(); + _vm->_screen->displayBackground(); g_system->updateScreen(); g_system->delayMillis(1000); } diff --git a/engines/hugo/intro_v1w.cpp b/engines/hugo/intro_v1w.cpp index 38921fd3e4..74efc4ff8c 100644 --- a/engines/hugo/intro_v1w.cpp +++ b/engines/hugo/intro_v1w.cpp @@ -39,7 +39,7 @@ namespace Hugo { -intro_v1w::intro_v1w(HugoEngine &vm) : IntroHandler(vm) { +intro_v1w::intro_v1w(HugoEngine *vm) : IntroHandler(vm) { } intro_v1w::~intro_v1w() { @@ -47,8 +47,8 @@ intro_v1w::~intro_v1w() { void intro_v1w::preNewGame() { // Auto-start a new game - _vm.file().restoreGame(-1); - _vm.getGameStatus().viewState = V_INTROINIT; + _vm->_file->restoreGame(-1); + _vm->getGameStatus().viewState = V_INTROINIT; } void intro_v1w::introInit() { diff --git a/engines/hugo/intro_v2d.cpp b/engines/hugo/intro_v2d.cpp index bfae11b77e..0c9f85d1ea 100644 --- a/engines/hugo/intro_v2d.cpp +++ b/engines/hugo/intro_v2d.cpp @@ -39,7 +39,7 @@ namespace Hugo { -intro_v2d::intro_v2d(HugoEngine &vm) : IntroHandler(vm) { +intro_v2d::intro_v2d(HugoEngine *vm) : IntroHandler(vm) { } intro_v2d::~intro_v2d() { @@ -49,8 +49,8 @@ void intro_v2d::preNewGame() { } void intro_v2d::introInit() { - _vm.screen().loadFont(0); - _vm.file().readBackground(_vm._numScreens - 1); // display splash screen + _vm->_screen->loadFont(0); + _vm->_file->readBackground(_vm->_numScreens - 1); // display splash screen char buffer[128]; @@ -58,14 +58,14 @@ void intro_v2d::introInit() { sprintf(buffer, "%s Registered Version", COPYRIGHT); else sprintf(buffer, "%s Shareware Version", COPYRIGHT); - _vm.screen().writeStr(CENTER, 186, buffer, _TLIGHTRED); + _vm->_screen->writeStr(CENTER, 186, buffer, _TLIGHTRED); if (scumm_stricmp(_boot.distrib, "David P. Gray")) { sprintf(buffer, "Distributed by %s.", _boot.distrib); - _vm.screen().writeStr(CENTER, 1, buffer, _TLIGHTRED); + _vm->_screen->writeStr(CENTER, 1, buffer, _TLIGHTRED); } - _vm.screen().displayBackground(); + _vm->_screen->displayBackground(); g_system->updateScreen(); g_system->delayMillis(5000); } diff --git a/engines/hugo/intro_v2w.cpp b/engines/hugo/intro_v2w.cpp index f68761eac9..414846bfc7 100644 --- a/engines/hugo/intro_v2w.cpp +++ b/engines/hugo/intro_v2w.cpp @@ -38,7 +38,7 @@ namespace Hugo { -intro_v2w::intro_v2w(HugoEngine &vm) : IntroHandler(vm) { +intro_v2w::intro_v2w(HugoEngine *vm) : IntroHandler(vm) { } intro_v2w::~intro_v2w() { diff --git a/engines/hugo/intro_v3d.cpp b/engines/hugo/intro_v3d.cpp index 3dd2a58d8b..cedd78e4c8 100644 --- a/engines/hugo/intro_v3d.cpp +++ b/engines/hugo/intro_v3d.cpp @@ -40,7 +40,7 @@ namespace Hugo { -intro_v3d::intro_v3d(HugoEngine &vm) : IntroHandler(vm) { +intro_v3d::intro_v3d(HugoEngine *vm) : IntroHandler(vm) { } intro_v3d::~intro_v3d() { @@ -50,8 +50,8 @@ void intro_v3d::preNewGame() { } void intro_v3d::introInit() { - _vm.screen().loadFont(0); - _vm.file().readBackground(_vm._numScreens - 1); // display splash screen + _vm->_screen->loadFont(0); + _vm->_file->readBackground(_vm->_numScreens - 1); // display splash screen char buffer[128]; if (_boot.registered) @@ -59,43 +59,43 @@ void intro_v3d::introInit() { else sprintf(buffer,"%s Shareware Version", COPYRIGHT); - _vm.screen().writeStr(CENTER, 190, buffer, _TBROWN); + _vm->_screen->writeStr(CENTER, 190, buffer, _TBROWN); if (scumm_stricmp(_boot.distrib, "David P. Gray")) { sprintf(buffer, "Distributed by %s.", _boot.distrib); - _vm.screen().writeStr(CENTER, 0, buffer, _TBROWN); + _vm->_screen->writeStr(CENTER, 0, buffer, _TBROWN); } - _vm.screen().displayBackground(); + _vm->_screen->displayBackground(); g_system->updateScreen(); g_system->delayMillis(5000); - _vm.file().readBackground(22); // display screen MAP_3d - _vm.screen().displayBackground(); + _vm->_file->readBackground(22); // display screen MAP_3d + _vm->_screen->displayBackground(); introTicks = 0; } bool intro_v3d::introPlay() { - byte introSize = _vm.getIntroSize(); + byte introSize = _vm->getIntroSize(); // Hugo 3 - Preamble screen before going into game. Draws path of Hugo's plane. // Called every tick. Returns TRUE when complete //TODO : Add proper check of story mode //#if STORY if (introTicks < introSize) { - _vm.screen().writeStr(_vm._introX[introTicks], _vm._introY[introTicks] - DIBOFF_Y, "x", _TBRIGHTWHITE); - _vm.screen().displayBackground(); + _vm->_screen->writeStr(_vm->_introX[introTicks], _vm->_introY[introTicks] - DIBOFF_Y, "x", _TBRIGHTWHITE); + _vm->_screen->displayBackground(); // Text boxes at various times switch (introTicks) { case 4: - Utils::Box(BOX_OK, "%s", _vm._textIntro[kIntro1]); + Utils::Box(BOX_OK, "%s", _vm->_textIntro[kIntro1]); break; case 9: - Utils::Box(BOX_OK, "%s", _vm._textIntro[kIntro2]); + Utils::Box(BOX_OK, "%s", _vm->_textIntro[kIntro2]); break; case 35: - Utils::Box(BOX_OK, "%s", _vm._textIntro[kIntro3]); + Utils::Box(BOX_OK, "%s", _vm->_textIntro[kIntro3]); break; } } diff --git a/engines/hugo/intro_v3w.cpp b/engines/hugo/intro_v3w.cpp index 924fa46805..a0bc624760 100644 --- a/engines/hugo/intro_v3w.cpp +++ b/engines/hugo/intro_v3w.cpp @@ -40,7 +40,7 @@ namespace Hugo { -intro_v3w::intro_v3w(HugoEngine &vm) : IntroHandler(vm) { +intro_v3w::intro_v3w(HugoEngine *vm) : IntroHandler(vm) { } intro_v3w::~intro_v3w() { @@ -52,15 +52,15 @@ void intro_v3w::preNewGame() { void intro_v3w::introInit() { // Hugo 3 - show map and set up for introPlay() //#if STORY - _vm.file().readBackground(22); // display screen MAP_3w - _vm.screen().displayBackground(); + _vm->_file->readBackground(22); // display screen MAP_3w + _vm->_screen->displayBackground(); introTicks = 0; - _vm.screen().loadFont(0); + _vm->_screen->loadFont(0); //#endif } bool intro_v3w::introPlay() { - byte introSize = _vm.getIntroSize(); + byte introSize = _vm->getIntroSize(); // Hugo 3 - Preamble screen before going into game. Draws path of Hugo's plane. // Called every tick. Returns TRUE when complete @@ -68,20 +68,20 @@ bool intro_v3w::introPlay() { //#if STORY if (introTicks < introSize) { // Scale viewport x_intro,y_intro to screen (offsetting y) - _vm.screen().writeStr(_vm._introX[introTicks], _vm._introY[introTicks] - DIBOFF_Y, "x", _TBRIGHTWHITE); - _vm.screen().displayBackground(); + _vm->_screen->writeStr(_vm->_introX[introTicks], _vm->_introY[introTicks] - DIBOFF_Y, "x", _TBRIGHTWHITE); + _vm->_screen->displayBackground(); // Text boxes at various times switch (introTicks) { case 4: - Utils::Box(BOX_OK, "%s", _vm._textIntro[kIntro1]); + Utils::Box(BOX_OK, "%s", _vm->_textIntro[kIntro1]); break; case 9: - Utils::Box(BOX_OK, "%s", _vm._textIntro[kIntro2]); + Utils::Box(BOX_OK, "%s", _vm->_textIntro[kIntro2]); break; case 35: - Utils::Box(BOX_OK, "%s", _vm._textIntro[kIntro3]); + Utils::Box(BOX_OK, "%s", _vm->_textIntro[kIntro3]); break; } } diff --git a/engines/hugo/inventory.cpp b/engines/hugo/inventory.cpp index 5046d191c3..ad0d5cbce9 100644 --- a/engines/hugo/inventory.cpp +++ b/engines/hugo/inventory.cpp @@ -40,12 +40,13 @@ #include "hugo/mouse.h" #include "hugo/inventory.h" #include "hugo/parser.h" +#include "hugo/object.h" namespace Hugo { #define MAX_DISP (XPIX / INV_DX) // Max icons displayable -InventoryHandler::InventoryHandler(HugoEngine &vm) : _vm(vm) { +InventoryHandler::InventoryHandler(HugoEngine *vm) : _vm(vm) { } // Construct the inventory scrollbar in dib_i @@ -57,12 +58,12 @@ void InventoryHandler::constructInventory(int16 imageTotNumb, int displayNumb, b debugC(1, kDebugInventory, "constructInventory(%d, %d, %d, %d)", imageTotNumb, displayNumb, (scrollFl) ? 0 : 1, firstObjId); // Clear out icon buffer - memset(_vm.screen().getIconBuffer(), 0, sizeof(_vm.screen().getIconBuffer())); + memset(_vm->_screen->getIconBuffer(), 0, sizeof(_vm->_screen->getIconBuffer())); // If needed, copy arrows - reduce number of icons displayable if (scrollFl) { // Display at first and last icon positions - _vm.screen().moveImage(_vm.screen().getGUIBuffer(), 0, 0, INV_DX, INV_DY, XPIX, _vm.screen().getIconBuffer(), 0, 0, XPIX); - _vm.screen().moveImage(_vm.screen().getGUIBuffer(), INV_DX, 0, INV_DX, INV_DY, XPIX, _vm.screen().getIconBuffer(), INV_DX *(MAX_DISP - 1), 0, XPIX); + _vm->_screen->moveImage(_vm->_screen->getGUIBuffer(), 0, 0, INV_DX, INV_DY, XPIX, _vm->_screen->getIconBuffer(), 0, 0, XPIX); + _vm->_screen->moveImage(_vm->_screen->getGUIBuffer(), INV_DX, 0, INV_DX, INV_DY, XPIX, _vm->_screen->getIconBuffer(), INV_DX *(MAX_DISP - 1), 0, XPIX); displayNumb = MIN(displayNumb, MAX_DISP - NUM_ARROWS); } else // No, override first index - we can show 'em all! firstObjId = 0; @@ -71,7 +72,7 @@ void InventoryHandler::constructInventory(int16 imageTotNumb, int displayNumb, b int16 displayed = 0; int16 carried = 0; for (int16 i = 0; i < imageTotNumb; i++) { - if (_vm._objects[_vm._invent[i]].carriedFl) { + if (_vm->_object->isCarried(_vm->_invent[i])) { // Check still room to display and past first scroll index if (displayed < displayNumb && carried >= firstObjId) { // Compute source coordinates in dib_u @@ -83,7 +84,7 @@ void InventoryHandler::constructInventory(int16 imageTotNumb, int displayNumb, b displayed++; // Count number displayed // Copy the icon - _vm.screen().moveImage(_vm.screen().getGUIBuffer(), ux, uy, INV_DX, INV_DY, XPIX, _vm.screen().getIconBuffer(), ix, 0, XPIX); + _vm->_screen->moveImage(_vm->_screen->getGUIBuffer(), ux, uy, INV_DX, INV_DY, XPIX, _vm->_screen->getIconBuffer(), ix, 0, XPIX); } carried++; // Count number carried } @@ -100,8 +101,8 @@ int16 InventoryHandler::processInventory(invact_t action, ...) { int16 imageNumb; // Total number of inventory items int displayNumb; // Total number displayed/carried // Compute total number and number displayed, i.e. number carried - for (imageNumb = 0, displayNumb = 0; imageNumb < _vm._maxInvent && _vm._invent[imageNumb] != -1; imageNumb++) { - if (_vm._objects[_vm._invent[imageNumb]].carriedFl) + for (imageNumb = 0, displayNumb = 0; imageNumb < _vm->_maxInvent && _vm->_invent[imageNumb] != -1; imageNumb++) { + if (_vm->_object->isCarried(_vm->_invent[imageNumb])) displayNumb++; } @@ -148,8 +149,8 @@ int16 InventoryHandler::processInventory(invact_t action, ...) { if (objId == -1 && i < displayNumb) { // Find objid by counting # carried objects == i+1 int16 j; - for (j = 0, i++; i > 0 && j < _vm._numObj; j++) { - if (_vm._objects[j].carriedFl) { + for (j = 0, i++; i > 0 && j < _vm->_numObj; j++) { + if (_vm->_object->isCarried(j)) { if (--i == 0) objId = j; } @@ -162,7 +163,7 @@ int16 InventoryHandler::processInventory(invact_t action, ...) { } void InventoryHandler::runInventory() { - status_t &gameStatus = _vm.getGameStatus(); + status_t &gameStatus = _vm->getGameStatus(); debugC(1, kDebugInventory, "runInventory"); @@ -176,15 +177,15 @@ void InventoryHandler::runInventory() { gameStatus.inventoryHeight = 0; // Move visible portion to _frontBuffer, restore uncovered portion, display results - _vm.screen().moveImage(_vm.screen().getIconBuffer(), 0, 0, XPIX, gameStatus.inventoryHeight, XPIX, _vm.screen().getFrontBuffer(), 0, DIBOFF_Y, XPIX); - _vm.screen().moveImage(_vm.screen().getBackBufferBackup(), 0, gameStatus.inventoryHeight + DIBOFF_Y, XPIX, STEP_DY, XPIX, _vm.screen().getFrontBuffer(), 0, gameStatus.inventoryHeight + DIBOFF_Y, XPIX); - _vm.screen().displayRect(0, DIBOFF_Y, XPIX, gameStatus.inventoryHeight + STEP_DY); + _vm->_screen->moveImage(_vm->_screen->getIconBuffer(), 0, 0, XPIX, gameStatus.inventoryHeight, XPIX, _vm->_screen->getFrontBuffer(), 0, DIBOFF_Y, XPIX); + _vm->_screen->moveImage(_vm->_screen->getBackBufferBackup(), 0, gameStatus.inventoryHeight + DIBOFF_Y, XPIX, STEP_DY, XPIX, _vm->_screen->getFrontBuffer(), 0, gameStatus.inventoryHeight + DIBOFF_Y, XPIX); + _vm->_screen->displayRect(0, DIBOFF_Y, XPIX, gameStatus.inventoryHeight + STEP_DY); if (gameStatus.inventoryHeight == 0) { // Finished moving up? // Yes, restore dibs and exit back to game state machine - _vm.screen().moveImage(_vm.screen().getBackBufferBackup(), 0, 0, XPIX, YPIX, XPIX, _vm.screen().getBackBuffer(), 0, 0, XPIX); - _vm.screen().moveImage(_vm.screen().getBackBuffer(), 0, 0, XPIX, YPIX, XPIX, _vm.screen().getFrontBuffer(), 0, 0, XPIX); - _vm.updateImages(); // Add objects back into display list for restore + _vm->_screen->moveImage(_vm->_screen->getBackBufferBackup(), 0, 0, XPIX, YPIX, XPIX, _vm->_screen->getBackBuffer(), 0, 0, XPIX); + _vm->_screen->moveImage(_vm->_screen->getBackBuffer(), 0, 0, XPIX, YPIX, XPIX, _vm->_screen->getFrontBuffer(), 0, 0, XPIX); + _vm->_object->updateImages(); // Add objects back into display list for restore gameStatus.inventoryState = I_OFF; gameStatus.viewState = V_PLAY; } @@ -194,9 +195,9 @@ void InventoryHandler::runInventory() { // and get any icon/text out of _frontBuffer if (gameStatus.inventoryHeight == 0) { processInventory(INV_INIT); // Initialize dib_i - _vm.screen().displayList(D_RESTORE); // Restore _frontBuffer - _vm.updateImages(); // Rebuild _frontBuffer without icons/text - _vm.screen().displayList(D_DISPLAY); // Blit display list to screen + _vm->_screen->displayList(D_RESTORE); // Restore _frontBuffer + _vm->_object->updateImages(); // Rebuild _frontBuffer without icons/text + _vm->_screen->displayList(D_DISPLAY); // Blit display list to screen } gameStatus.inventoryHeight += STEP_DY; // Move the icon bar down @@ -204,8 +205,8 @@ void InventoryHandler::runInventory() { gameStatus.inventoryHeight = INV_DY; // Move visible portion to _frontBuffer, display results - _vm.screen().moveImage(_vm.screen().getIconBuffer(), 0, 0, XPIX, gameStatus.inventoryHeight, XPIX, _vm.screen().getFrontBuffer(), 0, DIBOFF_Y, XPIX); - _vm.screen().displayRect(0, DIBOFF_Y, XPIX, gameStatus.inventoryHeight); + _vm->_screen->moveImage(_vm->_screen->getIconBuffer(), 0, 0, XPIX, gameStatus.inventoryHeight, XPIX, _vm->_screen->getFrontBuffer(), 0, DIBOFF_Y, XPIX); + _vm->_screen->displayRect(0, DIBOFF_Y, XPIX, gameStatus.inventoryHeight); if (gameStatus.inventoryHeight == INV_DY) { // Finished moving down? // Yes, prepare view dibs for special inventory display since @@ -213,17 +214,17 @@ void InventoryHandler::runInventory() { // 1. Save backing store _backBuffer in temporary dib_c // 2. Make snapshot of _frontBuffer the new _backBuffer backing store // 3. Reset the display list - _vm.screen().moveImage(_vm.screen().getBackBuffer(), 0, 0, XPIX, YPIX, XPIX, _vm.screen().getBackBufferBackup(), 0, 0, XPIX); - _vm.screen().moveImage(_vm.screen().getFrontBuffer(), 0, 0, XPIX, YPIX, XPIX, _vm.screen().getBackBuffer(), 0, 0, XPIX); - _vm.screen().displayList(D_INIT); + _vm->_screen->moveImage(_vm->_screen->getBackBuffer(), 0, 0, XPIX, YPIX, XPIX, _vm->_screen->getBackBufferBackup(), 0, 0, XPIX); + _vm->_screen->moveImage(_vm->_screen->getFrontBuffer(), 0, 0, XPIX, YPIX, XPIX, _vm->_screen->getBackBuffer(), 0, 0, XPIX); + _vm->_screen->displayList(D_INIT); gameStatus.inventoryState = I_ACTIVE; } break; case I_ACTIVE: // Inventory active - _vm.parser().charHandler(); // Still allow commands - _vm.screen().displayList(D_RESTORE); // Restore previous background - _vm.mouse().mouseHandler(); // Mouse activity - adds to display list - _vm.screen().displayList(D_DISPLAY); // Blit the display list to screen + _vm->_parser->charHandler(); // Still allow commands + _vm->_screen->displayList(D_RESTORE); // Restore previous background + _vm->_mouse->mouseHandler(); // Mouse activity - adds to display list + _vm->_screen->displayList(D_DISPLAY); // Blit the display list to screen break; } } diff --git a/engines/hugo/inventory.h b/engines/hugo/inventory.h index 5cc1af28c2..36fca71a43 100644 --- a/engines/hugo/inventory.h +++ b/engines/hugo/inventory.h @@ -40,13 +40,13 @@ namespace Hugo { class InventoryHandler { public: - InventoryHandler(HugoEngine &vm); + InventoryHandler(HugoEngine *vm); int16 processInventory(invact_t action, ...); void runInventory(); private: - HugoEngine &_vm; + HugoEngine *_vm; void constructInventory(int16 imageTotNumb, int displayNumb, bool scrollFl, int16 firstObjId); }; diff --git a/engines/hugo/module.mk b/engines/hugo/module.mk index 4e9ebaf122..12d671f764 100644 --- a/engines/hugo/module.mk +++ b/engines/hugo/module.mk @@ -20,6 +20,7 @@ MODULE_OBJS := \ intro_v3w.o \ inventory.o \ mouse.o \ + object.o \ parser.o \ parser_v1w.o \ parser_v1d.o \ diff --git a/engines/hugo/mouse.cpp b/engines/hugo/mouse.cpp index b305489568..247b859793 100644 --- a/engines/hugo/mouse.cpp +++ b/engines/hugo/mouse.cpp @@ -43,6 +43,7 @@ #include "hugo/inventory.h" #include "hugo/route.h" #include "hugo/util.h" +#include "hugo/object.h" namespace Hugo { @@ -59,24 +60,24 @@ enum seqTextMouse { kMsExit = 1 }; -MouseHandler::MouseHandler(HugoEngine &vm) : _vm(vm) { +MouseHandler::MouseHandler(HugoEngine *vm) : _vm(vm) { } // Shadow-blit supplied string into dib_a at cx,cy and add to display list void MouseHandler::cursorText(char *buffer, int16 cx, int16 cy, uif_t fontId, int16 color) { debugC(1, kDebugMouse, "cursorText(%s, %d, %d, %d, %d)", buffer, cx, cy, fontId, color); - _vm.screen().loadFont(fontId); + _vm->_screen->loadFont(fontId); // Find bounding rect for string - int16 sdx = _vm.screen().stringLength(buffer); - int16 sdy = _vm.screen().fontHeight() + 1; // + 1 for shadow + int16 sdx = _vm->_screen->stringLength(buffer); + int16 sdy = _vm->_screen->fontHeight() + 1; // + 1 for shadow int16 sx = (cx < XPIX / 2) ? cx + SX_OFF : cx - sdx - SX_OFF / 2; int16 sy = cy + SY_OFF; // Display the string and add rect to display list - _vm.screen().shadowStr(sx, sy, buffer, _TBRIGHTWHITE); - _vm.screen().displayList(D_ADD, sx, sy, sdx, sdy); + _vm->_screen->shadowStr(sx, sy, buffer, _TBRIGHTWHITE); + _vm->_screen->displayList(D_ADD, sx, sy, sdx, sdy); } // Find the exit hotspot containing cx, cy. @@ -85,8 +86,8 @@ int16 MouseHandler::findExit(int16 cx, int16 cy) { debugC(2, kDebugMouse, "findExit(%d, %d)", cx, cy); int i = 0; - for (hotspot_t *hotspot = _vm._hotspots; hotspot->screenIndex >= 0; i++, hotspot++) { - if (hotspot->screenIndex == *_vm._screen_p) { + for (hotspot_t *hotspot = _vm->_hotspots; hotspot->screenIndex >= 0; i++, hotspot++) { + if (hotspot->screenIndex == *_vm->_screen_p) { if (cx >= hotspot->x1 && cx <= hotspot->x2 && cy >= hotspot->y1 && cy <= hotspot->y2) return i; } @@ -98,9 +99,9 @@ int16 MouseHandler::findExit(int16 cx, int16 cy) { void MouseHandler::processRightClick(int16 objId, int16 cx, int16 cy) { debugC(1, kDebugMouse, "Process_rclick(%d, %d, %d)", objId, cx, cy); - status_t &gameStatus = _vm.getGameStatus(); + status_t &gameStatus = _vm->getGameStatus(); - if (gameStatus.storyModeFl || _vm._hero->pathType == QUIET) // Make sure user has control + if (gameStatus.storyModeFl || _vm->_hero->pathType == QUIET) // Make sure user has control return; bool foundFl = false; // TRUE if route found to object @@ -111,26 +112,26 @@ void MouseHandler::processRightClick(int16 objId, int16 cx, int16 cy) { else if (gameStatus.inventoryObjId == objId) gameStatus.inventoryObjId = -1; // Same icon - deselect it else - _vm.useObject(objId); // Use status.objid on object + _vm->_object->useObject(objId); // Use status.objid on object } else { // Clicked over viewport object - object_t *obj = &_vm._objects[objId]; + object_t *obj = &_vm->_object->_objects[objId]; int16 x, y; switch (obj->viewx) { // Where to walk to case -1: // Walk to object position - if (_vm.findObjectSpace(obj, &x, &y)) - foundFl = _vm.route().startRoute(GO_GET, objId, x, y); + if (_vm->findObjectSpace(obj, &x, &y)) + foundFl = _vm->_route->startRoute(GO_GET, objId, x, y); if (!foundFl) // Can't get there, try to use from here - _vm.useObject(objId); + _vm->_object->useObject(objId); break; case 0: // Immediate use - _vm.useObject(objId); // Pick up or use object + _vm->_object->useObject(objId); // Pick up or use object break; default: // Walk to view point if possible - if (!_vm.route().startRoute(GO_GET, objId, obj->viewx, obj->viewy)) { - if (_vm._hero->cycling == INVISIBLE)// If invisible do - _vm.useObject(objId); // immediate use + if (!_vm->_route->startRoute(GO_GET, objId, obj->viewx, obj->viewy)) { + if (_vm->_hero->cycling == INVISIBLE)// If invisible do + _vm->_object->useObject(objId); // immediate use else - Utils::Box(BOX_ANY, "%s", _vm._textMouse[kMsNoWayText]); // Can't get there + Utils::Box(BOX_ANY, "%s", _vm->_textMouse[kMsNoWayText]); // Can't get there } break; } @@ -149,41 +150,41 @@ void MouseHandler::processLeftClick(int16 objId, int16 cx, int16 cy) { int16 i, x, y; object_t *obj; - status_t &gameStatus = _vm.getGameStatus(); + status_t &gameStatus = _vm->getGameStatus(); - if (gameStatus.storyModeFl || _vm._hero->pathType == QUIET) // Make sure user has control + if (gameStatus.storyModeFl || _vm->_hero->pathType == QUIET) // Make sure user has control return; switch (objId) { case -1: // Empty space - attempt to walk there - _vm.route().startRoute(GO_SPACE, 0, cx, cy); + _vm->_route->startRoute(GO_SPACE, 0, cx, cy); break; case LEFT_ARROW: // A scroll arrow - scroll the iconbar case RIGHT_ARROW: // Scroll the iconbar and display results - _vm.inventory().processInventory((objId == LEFT_ARROW) ? INV_LEFT : INV_RIGHT); - _vm.screen().moveImage(_vm.screen().getIconBuffer(), 0, 0, XPIX, INV_DY, XPIX, _vm.screen().getFrontBuffer(), 0, DIBOFF_Y, XPIX); - _vm.screen().moveImage(_vm.screen().getIconBuffer(), 0, 0, XPIX, INV_DY, XPIX, _vm.screen().getBackBuffer(), 0, DIBOFF_Y, XPIX); - _vm.screen().displayList(D_ADD, 0, DIBOFF_Y, XPIX, INV_DY); + _vm->_inventory->processInventory((objId == LEFT_ARROW) ? INV_LEFT : INV_RIGHT); + _vm->_screen->moveImage(_vm->_screen->getIconBuffer(), 0, 0, XPIX, INV_DY, XPIX, _vm->_screen->getFrontBuffer(), 0, DIBOFF_Y, XPIX); + _vm->_screen->moveImage(_vm->_screen->getIconBuffer(), 0, 0, XPIX, INV_DY, XPIX, _vm->_screen->getBackBuffer(), 0, DIBOFF_Y, XPIX); + _vm->_screen->displayList(D_ADD, 0, DIBOFF_Y, XPIX, INV_DY); break; case EXIT_HOTSPOT: // Walk to exit hotspot i = findExit(cx, cy); - x = _vm._hotspots[i].viewx; - y = _vm._hotspots[i].viewy; + x = _vm->_hotspots[i].viewx; + y = _vm->_hotspots[i].viewy; if (x >= 0) { // Hotspot refers to an exit // Special case of immediate exit if (gameStatus.jumpExitFl) { // Get rid of iconbar if necessary if (gameStatus.inventoryState != I_OFF) gameStatus.inventoryState = I_UP; - _vm.scheduler().insertActionList(_vm._hotspots[i].actIndex); + _vm->_scheduler->insertActionList(_vm->_hotspots[i].actIndex); } else { // Set up route to exit spot - if (_vm._hotspots[i].direction == Common::KEYCODE_RIGHT) + if (_vm->_hotspots[i].direction == Common::KEYCODE_RIGHT) x -= HERO_MAX_WIDTH; - else if (_vm._hotspots[i].direction == Common::KEYCODE_LEFT) + else if (_vm->_hotspots[i].direction == Common::KEYCODE_LEFT) x += HERO_MAX_WIDTH; - if (!_vm.route().startRoute(GO_EXIT, i, x, y)) - Utils::Box(BOX_ANY, "%s", _vm._textMouse[kMsNoWayText]); // Can't get there + if (!_vm->_route->startRoute(GO_EXIT, i, x, y)) + Utils::Box(BOX_ANY, "%s", _vm->_textMouse[kMsNoWayText]); // Can't get there } // Get rid of any attached icon @@ -191,29 +192,29 @@ void MouseHandler::processLeftClick(int16 objId, int16 cx, int16 cy) { } break; default: // Look at an icon or object - obj = &_vm._objects[objId]; + obj = &_vm->_object->_objects[objId]; // Over iconbar - immediate description if (gameStatus.inventoryState == I_ACTIVE && cy < INV_DY + DIBOFF_Y) - _vm.lookObject(obj); + _vm->_object->lookObject(obj); else { bool foundFl = false; // TRUE if route found to object switch (obj->viewx) { // Clicked over viewport object case -1: // Walk to object position - if (_vm.findObjectSpace(obj, &x, &y)) - foundFl = _vm.route().startRoute(GO_LOOK, objId, x, y); + if (_vm->findObjectSpace(obj, &x, &y)) + foundFl = _vm->_route->startRoute(GO_LOOK, objId, x, y); if (!foundFl) // Can't get there, immediate description - _vm.lookObject(obj); + _vm->_object->lookObject(obj); break; case 0: // Immediate description - _vm.lookObject(obj); + _vm->_object->lookObject(obj); break; default: // Walk to view point if possible - if (!_vm.route().startRoute(GO_LOOK, objId, obj->viewx, obj->viewy)) { - if (_vm._hero->cycling == INVISIBLE) // If invisible do - _vm.lookObject(obj); // immediate decription + if (!_vm->_route->startRoute(GO_LOOK, objId, obj->viewx, obj->viewy)) { + if (_vm->_hero->cycling == INVISIBLE) // If invisible do + _vm->_object->lookObject(obj); // immediate decription else - Utils::Box(BOX_ANY, "%s", _vm._textMouse[kMsNoWayText]); // Can't get there + Utils::Box(BOX_ANY, "%s", _vm->_textMouse[kMsNoWayText]); // Can't get there } break; } @@ -226,10 +227,10 @@ void MouseHandler::processLeftClick(int16 objId, int16 cx, int16 cy) { void MouseHandler::mouseHandler() { debugC(2, kDebugMouse, "mouseHandler"); - int16 cx = _vm.getMouseX(); - int16 cy = _vm.getMouseY(); + int16 cx = _vm->getMouseX(); + int16 cy = _vm->getMouseY(); - status_t &gameStatus = _vm.getGameStatus(); + status_t &gameStatus = _vm->getGameStatus(); gameStatus.cx = cx; // Save cursor coords gameStatus.cy = cy; @@ -242,8 +243,8 @@ void MouseHandler::mouseHandler() { if (gameStatus.inventoryObjId != -1) { // Find index of icon int16 iconId; // Find index of dragged icon - for (iconId = 0; iconId < _vm._maxInvent; iconId++) { - if (gameStatus.inventoryObjId == _vm._invent[iconId]) + for (iconId = 0; iconId < _vm->_maxInvent; iconId++) { + if (gameStatus.inventoryObjId == _vm->_invent[iconId]) break; } @@ -260,20 +261,20 @@ void MouseHandler::mouseHandler() { icony = MIN(icony, YPIX - INV_DY); // Copy the icon and add to display list - _vm.screen().moveImage(_vm.screen().getGUIBuffer(), ux, uy, INV_DX, INV_DY, XPIX, _vm.screen().getFrontBuffer(), iconx, icony, XPIX); - _vm.screen().displayList(D_ADD, iconx, icony, INV_DX, INV_DY); + _vm->_screen->moveImage(_vm->_screen->getGUIBuffer(), ux, uy, INV_DX, INV_DY, XPIX, _vm->_screen->getFrontBuffer(), iconx, icony, XPIX); + _vm->_screen->displayList(D_ADD, iconx, icony, INV_DX, INV_DY); } int16 objId = -1; // Current source object // Process cursor over an object or icon if (gameStatus.inventoryState == I_ACTIVE) // Check inventory icon bar first - objId = _vm.inventory().processInventory(INV_GET, cx, cy); + objId = _vm->_inventory->processInventory(INV_GET, cx, cy); if (objId == -1) // No match, check rest of view - objId = _vm.findObject(cx, cy); + objId = _vm->_object->findObject(cx, cy); if (objId >= 0) { // Got a match // Display object name next to cursor (unless CURSOR_NOCHAR) // Note test for swapped hero name - char *name = _vm._arrayNouns[_vm._objects[(objId == HERO) ? _vm._heroImage : objId].nounIndex][CURSOR_NAME]; + char *name = _vm->_arrayNouns[_vm->_object->_objects[(objId == HERO) ? _vm->_heroImage : objId].nounIndex][CURSOR_NAME]; if (name[0] != CURSOR_NOCHAR) cursorText(name, cx, cy, U_FONT8, _TBRIGHTWHITE); @@ -285,9 +286,9 @@ void MouseHandler::mouseHandler() { // Process cursor over an exit hotspot if (objId == -1) { int i = findExit(cx, cy); - if (i != -1 && _vm._hotspots[i].viewx >= 0) { + if (i != -1 && _vm->_hotspots[i].viewx >= 0) { objId = EXIT_HOTSPOT; - cursorText(_vm._textMouse[kMsExit], cx, cy, U_FONT8, _TBRIGHTWHITE); + cursorText(_vm->_textMouse[kMsExit], cx, cy, U_FONT8, _TBRIGHTWHITE); } } diff --git a/engines/hugo/mouse.h b/engines/hugo/mouse.h index 3ac5f19f32..0fcb651b3a 100644 --- a/engines/hugo/mouse.h +++ b/engines/hugo/mouse.h @@ -36,12 +36,12 @@ namespace Hugo { class MouseHandler { public: - MouseHandler(HugoEngine &vm); + MouseHandler(HugoEngine *vm); void mouseHandler(); private: - HugoEngine &_vm; + HugoEngine *_vm; void cursorText(char *buffer, int16 cx, int16 cy, uif_t fontId, int16 color); int16 findExit(int16 cx, int16 cy); diff --git a/engines/hugo/object.cpp b/engines/hugo/object.cpp new file mode 100644 index 0000000000..f2b4d08644 --- /dev/null +++ b/engines/hugo/object.cpp @@ -0,0 +1,695 @@ +/* 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$ + * + */ + +/* + * This code is based on original Hugo Trilogy source code + * + * Copyright (c) 1989-1995 David P. Gray + * + */ + +#include "common/system.h" +#include "common/random.h" + +#include "hugo/game.h" +#include "hugo/hugo.h" +#include "hugo/object.h" +#include "hugo/global.h" +#include "hugo/display.h" +#include "hugo/file.h" +#include "hugo/route.h" +#include "hugo/util.h" +#include "hugo/parser.h" + +namespace Hugo { + +ObjectHandler::ObjectHandler(HugoEngine *vm) : _vm(vm) { +} + +ObjectHandler::~ObjectHandler() { +} + +// Draw all objects on screen as follows: +// 1. Sort 'FLOATING' objects in order of y2 (base of object) +// 2. Display new object frames/positions in dib +// Finally, cycle any animating objects to next frame +void ObjectHandler::updateImages() { + debugC(5, kDebugEngine, "updateImages"); + + // Initialise the index array to visible objects in current screen + int num_objs = 0; + byte objindex[MAXOBJECTS]; // Array of indeces to objects + + for (int i = 0; i < _vm->_numObj; i++) { + object_t *obj = &_objects[i]; + if ((obj->screenIndex == *_vm->_screen_p) && (obj->cycling >= ALMOST_INVISIBLE)) + objindex[num_objs++] = i; + } + + // Sort the objects into increasing y+y2 (painter's algorithm) + qsort(objindex, num_objs, sizeof(objindex[0]), y2comp); + + // Add each visible object to display list + for (int i = 0; i < num_objs; i++) { + object_t *obj = &_objects[objindex[i]]; + // Count down inter-frame timer + if (obj->frameTimer) + obj->frameTimer--; + + if (obj->cycling > ALMOST_INVISIBLE) { // Only if visible + switch (obj->cycling) { + case NOT_CYCLING: + _vm->_screen->displayFrame(obj->x, obj->y, obj->currImagePtr, obj->priority == OVEROVL); + break; + case CYCLE_FORWARD: + if (obj->frameTimer) // Not time to see next frame yet + _vm->_screen->displayFrame(obj->x, obj->y, obj->currImagePtr, obj->priority == OVEROVL); + else + _vm->_screen->displayFrame(obj->x, obj->y, obj->currImagePtr->nextSeqPtr, obj->priority == OVEROVL); + break; + case CYCLE_BACKWARD: { + seq_t *seqPtr = obj->currImagePtr; + if (!obj->frameTimer) { // Show next frame + while (seqPtr->nextSeqPtr != obj->currImagePtr) + seqPtr = seqPtr->nextSeqPtr; + } + _vm->_screen->displayFrame(obj->x, obj->y, seqPtr, obj->priority == OVEROVL); + break; + } + default: + break; + } + } + } + + // Cycle any animating objects + for (int i = 0; i < num_objs; i++) { + object_t *obj = &_objects[objindex[i]]; + if (obj->cycling != INVISIBLE) { + // Only if it's visible + if (obj->cycling == ALMOST_INVISIBLE) + obj->cycling = INVISIBLE; + + // Now Rotate to next picture in sequence + switch (obj->cycling) { + case NOT_CYCLING: + break; + case CYCLE_FORWARD: + if (!obj->frameTimer) { + // Time to step to next frame + obj->currImagePtr = obj->currImagePtr->nextSeqPtr; + // Find out if this is last frame of sequence + // If so, reset frame_timer and decrement n_cycle + if (obj->frameInterval || obj->cycleNumb) { + obj->frameTimer = obj->frameInterval; + for (int j = 0; j < obj->seqNumb; j++) { + if (obj->currImagePtr->nextSeqPtr == obj->seqList[j].seqPtr) { + if (obj->cycleNumb) { // Decr cycleNumb if Non-continous + if (!--obj->cycleNumb) + obj->cycling = NOT_CYCLING; + } + } + } + } + } + break; + case CYCLE_BACKWARD: { + if (!obj->frameTimer) { + // Time to step to prev frame + seq_t *seqPtr = obj->currImagePtr; + while (obj->currImagePtr->nextSeqPtr != seqPtr) + obj->currImagePtr = obj->currImagePtr->nextSeqPtr; + // Find out if this is first frame of sequence + // If so, reset frame_timer and decrement n_cycle + if (obj->frameInterval || obj->cycleNumb) { + obj->frameTimer = obj->frameInterval; + for (int j = 0; j < obj->seqNumb; j++) { + if (obj->currImagePtr == obj->seqList[j].seqPtr) { + if (obj->cycleNumb){ // Decr cycleNumb if Non-continous + if (!--obj->cycleNumb) + obj->cycling = NOT_CYCLING; + } + } + } + } + } + break; + } + default: + break; + } + obj->oldx = obj->x; + obj->oldy = obj->y; + } + } +} + +void ObjectHandler::swapImages(int objNumb1, int objNumb2) { +// Swap all the images of one object with another. Set hero_image (we make +// the assumption for now that the first obj is always the HERO) to the object +// number of the swapped image + debugC(1, kDebugSchedule, "swapImages(%d, %d)", objNumb1, objNumb2); + + saveSeq(&_objects[objNumb1]); + + seqList_t tmpSeqList[MAX_SEQUENCES]; + int seqListSize = sizeof(seqList_t) * MAX_SEQUENCES; + + memcpy(tmpSeqList, _objects[objNumb1].seqList, seqListSize); + memcpy(_objects[objNumb1].seqList, _objects[objNumb2].seqList, seqListSize); + memcpy(_objects[objNumb2].seqList, tmpSeqList, seqListSize); + restoreSeq(&_objects[objNumb1]); + _objects[objNumb2].currImagePtr = _objects[objNumb2].seqList[0].seqPtr; + _vm->_heroImage = (_vm->_heroImage == HERO) ? objNumb2 : HERO; + + // Make sure baseline stays constant + _objects[objNumb1].y += _objects[objNumb2].currImagePtr->y2 - _objects[objNumb1].currImagePtr->y2; +} + +void ObjectHandler::saveSeq(object_t *obj) { +// Save sequence number and image number in given object + debugC(1, kDebugFile, "saveSeq"); + + bool found = false; + for (int j = 0; !found && (j < obj->seqNumb); j++) { + seq_t *q = obj->seqList[j].seqPtr; + for (int k = 0; !found && (k < obj->seqList[j].imageNbr); k++) { + if (obj->currImagePtr == q) { + found = true; + obj->curSeqNum = j; + obj->curImageNum = k; + } else { + q = q->nextSeqPtr; + } + } + } +} + +void ObjectHandler::restoreSeq(object_t *obj) { +// Set up cur_seq_p from stored sequence and image number in object + debugC(1, kDebugFile, "restoreSeq"); + + seq_t *q = obj->seqList[obj->curSeqNum].seqPtr; + for (int j = 0; j < obj->curImageNum; j++) + q = q->nextSeqPtr; + obj->currImagePtr = q; +} + +// Update all object positions. Process object 'local' events +// including boundary events and collisions +void ObjectHandler::moveObjects() { + debugC(4, kDebugEngine, "moveObjects"); + + // If route mode enabled, do special route processing + if (_vm->getGameStatus().routeIndex >= 0) + _vm->_route->processRoute(); + + // Perform any adjustments to velocity based on special path types + // and store all (visible) object baselines into the boundary file. + // Don't store foreground or background objects + for (int i = 0; i < _vm->_numObj; i++) { + object_t *obj = &_objects[i]; // Get pointer to object + seq_t *currImage = obj->currImagePtr; // Get ptr to current image + if (obj->screenIndex == *_vm->_screen_p) { + switch (obj->pathType) { + case CHASE: + case CHASE2: { + int8 radius = obj->radius; // Default to object's radius + if (radius < 0) // If radius infinity, use closer value + radius = DX; + + // Allowable motion wrt boundary + int dx = _vm->_hero->x + _vm->_hero->currImagePtr->x1 - obj->x - currImage->x1; + int dy = _vm->_hero->y + _vm->_hero->currImagePtr->y2 - obj->y - currImage->y2 - 1; + if (abs(dx) <= radius) + obj->vx = 0; + else + obj->vx = (dx > 0) ? MIN(dx, obj->vxPath) : MAX(dx, -obj->vxPath); + if (abs(dy) <= radius) + obj->vy = 0; + else + obj->vy = (dy > 0) ? MIN(dy, obj->vyPath) : MAX(dy, -obj->vyPath); + + // Set first image in sequence (if multi-seq object) + switch (obj->seqNumb) { + case 4: + if (!obj->vx) { // Got 4 directions + if (obj->vx != obj->oldvx) { // vx just stopped + if (dy >= 0) + obj->currImagePtr = obj->seqList[DOWN].seqPtr; + else + obj->currImagePtr = obj->seqList[_UP].seqPtr; + } + } else if (obj->vx != obj->oldvx) { + if (dx > 0) + obj->currImagePtr = obj->seqList[RIGHT].seqPtr; + else + obj->currImagePtr = obj->seqList[LEFT].seqPtr; + } + break; + case 3: + case 2: + if (obj->vx != obj->oldvx) { // vx just stopped + if (dx > 0) // Left & right only + obj->currImagePtr = obj->seqList[RIGHT].seqPtr; + else + obj->currImagePtr = obj->seqList[LEFT].seqPtr; + } + break; + } + + if (obj->vx || obj->vy) + obj->cycling = CYCLE_FORWARD; + else { + obj->cycling = NOT_CYCLING; + _vm->boundaryCollision(obj); // Must have got hero! + } + obj->oldvx = obj->vx; + obj->oldvy = obj->vy; + currImage = obj->currImagePtr; // Get (new) ptr to current image + break; + } + case WANDER2: + case WANDER: + if (!_vm->_rnd->getRandomNumber(3 * NORMAL_TPS)) { // Kick on random interval + obj->vx = _vm->_rnd->getRandomNumber(obj->vxPath << 1) - obj->vxPath; + obj->vy = _vm->_rnd->getRandomNumber(obj->vyPath << 1) - obj->vyPath; + + // Set first image in sequence (if multi-seq object) + if (obj->seqNumb > 1) { + if (!obj->vx && (obj->seqNumb >= 4)) { + if (obj->vx != obj->oldvx) { // vx just stopped + if (obj->vy > 0) + obj->currImagePtr = obj->seqList[DOWN].seqPtr; + else + obj->currImagePtr = obj->seqList[_UP].seqPtr; + } + } else if (obj->vx != obj->oldvx) { + if (obj->vx > 0) + obj->currImagePtr = obj->seqList[RIGHT].seqPtr; + else + obj->currImagePtr = obj->seqList[LEFT].seqPtr; + } + } + obj->oldvx = obj->vx; + obj->oldvy = obj->vy; + currImage = obj->currImagePtr; // Get (new) ptr to current image + } + if (obj->vx || obj->vy) + obj->cycling = CYCLE_FORWARD; + break; + default: + ; // Really, nothing + } + // Store boundaries + if ((obj->cycling > ALMOST_INVISIBLE) && (obj->priority == FLOATING)) + _vm->storeBoundary(obj->x + currImage->x1, obj->x + currImage->x2, obj->y + currImage->y2); + } + } + + // Move objects, allowing for boundaries + for (int i = 0; i < _vm->_numObj; i++) { + object_t *obj = &_objects[i]; // Get pointer to object + if ((obj->screenIndex == *_vm->_screen_p) && (obj->vx || obj->vy)) { + // Only process if it's moving + + // Do object movement. Delta_x,y return allowed movement in x,y + // to move as close to a boundary as possible without crossing it. + seq_t *currImage = obj->currImagePtr; // Get ptr to current image + // object coordinates + int x1 = obj->x + currImage->x1; // Left edge of object + int x2 = obj->x + currImage->x2; // Right edge + int y1 = obj->y + currImage->y1; // Top edge + int y2 = obj->y + currImage->y2; // Bottom edge + + if ((obj->cycling > ALMOST_INVISIBLE) && (obj->priority == FLOATING)) + _vm->clearBoundary(x1, x2, y2); // Clear our own boundary + + // Allowable motion wrt boundary + int dx = _vm->deltaX(x1, x2, obj->vx, y2); + if (dx != obj->vx) { + // An object boundary collision! + _vm->boundaryCollision(obj); + obj->vx = 0; + } + + int dy = _vm->deltaY(x1, x2, obj->vy, y2); + if (dy != obj->vy) { + // An object boundary collision! + _vm->boundaryCollision(obj); + obj->vy = 0; + } + + if ((obj->cycling > ALMOST_INVISIBLE) && (obj->priority == FLOATING)) + _vm->storeBoundary(x1, x2, y2); // Re-store our own boundary + + obj->x += dx; // Update object position + obj->y += dy; + + // Don't let object go outside screen + if (x1 < EDGE) + obj->x = EDGE2; + if (x2 > (XPIX - EDGE)) + obj->x = XPIX - EDGE2 - (x2 - x1); + if (y1 < EDGE) + obj->y = EDGE2; + if (y2 > (YPIX - EDGE)) + obj->y = YPIX - EDGE2 - (y2 - y1); + + if ((obj->vx == 0) && (obj->vy == 0) && (obj->pathType != WANDER2) && (obj->pathType != CHASE2)) + obj->cycling = NOT_CYCLING; + } + } + + // Clear all object baselines from the boundary file. + for (int i = 0; i < _vm->_numObj; i++) { + object_t *obj = &_objects[i]; // Get pointer to object + seq_t *currImage = obj->currImagePtr; // Get ptr to current image + if ((obj->screenIndex == *_vm->_screen_p) && (obj->cycling > ALMOST_INVISIBLE) && (obj->priority == FLOATING)) + _vm->clearBoundary(obj->oldx + currImage->x1, obj->oldx + currImage->x2, obj->oldy + currImage->y2); + } + + // If maze mode is enabled, do special maze processing + if (_maze.enabledFl) + _vm->processMaze(); +} + +// If status.objid = -1, pick up objid, else use status.objid on objid, +// if objid can't be picked up, use it directly +void ObjectHandler::useObject(int16 objId) { + debugC(1, kDebugEngine, "useObject(%d)", objId); + + char *verb; // Background verb to use directly + object_t *obj = &_objects[objId]; // Ptr to object + if (_vm->getGameStatus().inventoryObjId == -1) { + // Get or use objid directly + if ((obj->genericCmd & TAKE) || obj->objValue) // Get collectible item + sprintf(_line, "%s %s", _vm->_arrayVerbs[_vm->_take][0], _vm->_arrayNouns[obj->nounIndex][0]); + else if (obj->genericCmd & LOOK) // Look item + sprintf(_line, "%s %s", _vm->_arrayVerbs[_vm->_look][0], _vm->_arrayNouns[obj->nounIndex][0]); + else if (obj->genericCmd & DROP) // Drop item + sprintf(_line, "%s %s", _vm->_arrayVerbs[_vm->_drop][0], _vm->_arrayNouns[obj->nounIndex][0]); + else if (obj->cmdIndex != 0) // Use non-collectible item if able + sprintf(_line, "%s %s", _vm->_arrayVerbs[_vm->_cmdList[obj->cmdIndex][1].verbIndex][0], _vm->_arrayNouns[obj->nounIndex][0]); + else if ((verb = _vm->useBG(_vm->_arrayNouns[obj->nounIndex][0])) != 0) + sprintf(_line, "%s %s", verb, _vm->_arrayNouns[obj->nounIndex][0]); + else + return; // Can't use object directly + } else { + // Use status.objid on objid + // Default to first cmd verb + sprintf(_line, "%s %s %s", _vm->_arrayVerbs[_vm->_cmdList[_objects[_vm->getGameStatus().inventoryObjId].cmdIndex][1].verbIndex][0], + _vm->_arrayNouns[_objects[_vm->getGameStatus().inventoryObjId].nounIndex][0], + _vm->_arrayNouns[obj->nounIndex][0]); + + // Check valid use of objects and override verb if necessary + for (uses_t *use = _vm->_uses; use->objId != _vm->_numObj; use++) { + if (_vm->getGameStatus().inventoryObjId == use->objId) { + // Look for secondary object, if found use matching verb + bool foundFl = false; + for (target_t *target = use->targets; _vm->_arrayNouns[target->nounIndex] != 0; target++) + if (_vm->_arrayNouns[target->nounIndex][0] == _vm->_arrayNouns[obj->nounIndex][0]) { + foundFl = true; + sprintf(_line, "%s %s %s", _vm->_arrayVerbs[target->verbIndex][0], + _vm->_arrayNouns[_objects[_vm->getGameStatus().inventoryObjId].nounIndex][0], + _vm->_arrayNouns[obj->nounIndex][0]); + } + + // No valid use of objects found, print failure string + if (!foundFl) { + // Deselect dragged icon if inventory not active + if (_vm->getGameStatus().inventoryState != I_ACTIVE) + _vm->getGameStatus().inventoryObjId = -1; + Utils::Box(BOX_ANY, "%s", _vm->_textData[use->dataIndex]); + return; + } + } + } + } + + if (_vm->getGameStatus().inventoryState == I_ACTIVE) // If inventory active, remove it + _vm->getGameStatus().inventoryState = I_UP; + _vm->getGameStatus().inventoryObjId = -1; // Deselect any dragged icon + _vm->_parser->lineHandler(); // and process command +} + +// Return object index of the topmost object under the cursor, or -1 if none +// Objects are filtered if not "useful" +int16 ObjectHandler::findObject(uint16 x, uint16 y) { + debugC(3, kDebugEngine, "findObject(%d, %d)", x, y); + + int16 objIndex = -1; // Index of found object + uint16 y2Max = 0; // Greatest y2 + object_t *obj = _objects; + // Check objects on screen + for (int i = 0; i < _vm->_numObj; i++, obj++) { + // Object must be in current screen and "useful" + if (obj->screenIndex == *_vm->_screen_p && (obj->genericCmd || obj->objValue || obj->cmdIndex)) { + seq_t *curImage = obj->currImagePtr; + // Object must have a visible image... + if (curImage != 0 && obj->cycling != INVISIBLE) { + // If cursor inside object + if (x >= (uint16)obj->x && x <= obj->x + curImage->x2 && y >= (uint16)obj->y && y <= obj->y + curImage->y2) { + // If object is closest so far + if (obj->y + curImage->y2 > y2Max) { + y2Max = obj->y + curImage->y2; + objIndex = i; // Found an object! + } + } + } else { + // ...or a dummy object that has a hotspot rectangle + if (curImage == 0 && obj->vxPath != 0 && !obj->carriedFl) { + // If cursor inside special rectangle + if ((int16)x >= obj->oldx && (int16)x < obj->oldx + obj->vxPath && (int16)y >= obj->oldy && (int16)y < obj->oldy + obj->vyPath) { + // If object is closest so far + if (obj->oldy + obj->vyPath - 1 > (int16)y2Max) { + y2Max = obj->oldy + obj->vyPath - 1; + objIndex = i; // Found an object! + } + } + } + } + } + } + return objIndex; +} + +// Issue "Look at <object>" command +// Note special case of swapped hero image +void ObjectHandler::lookObject(object_t *obj) { + debugC(1, kDebugEngine, "lookObject"); + + if (obj == _vm->_hero) + // Hero swapped - look at other + obj = &_objects[_vm->_heroImage]; + + _vm->_parser->command("%s %s", _vm->_arrayVerbs[_vm->_look][0], _vm->_arrayNouns[obj->nounIndex][0]); +} + +// Free all object images +void ObjectHandler::freeObjects() { + debugC(1, kDebugEngine, "freeObjects"); + + // Nothing to do if not allocated yet + if (_vm->_hero->seqList[0].seqPtr == 0) + return; + + // Free all sequence lists and image data + for (int i = 0; i < _vm->_numObj; i++) { + object_t *obj = &_objects[i]; + for (int j = 0; j < obj->seqNumb; j++) { // for each sequence + seq_t *seq = obj->seqList[j].seqPtr; // Free image + if (seq == 0) // Failure during database load + break; + do { + free(seq->imagePtr); + seq = seq->nextSeqPtr; + } while (seq != obj->seqList[j].seqPtr); + free(seq); // Free sequence record + } + } +} + +// Compare function for the quicksort. The sort is to order the objects in +// increasing vertical position, using y+y2 as the baseline +// Returns -1 if ay2 < by2 else 1 if ay2 > by2 else 0 +int ObjectHandler::y2comp(const void *a, const void *b) { + debugC(6, kDebugEngine, "y2comp"); + +// const object_t *p1 = &s_Engine->_objects[*(const byte *)a]; +// const object_t *p2 = &s_Engine->_objects[*(const byte *)b]; + const object_t *p1 = &HugoEngine::get()._object->_objects[*(const byte *)a]; + const object_t *p2 = &HugoEngine::get()._object->_objects[*(const byte *)b]; + + if (p1 == p2) + // Why does qsort try the same indexes? + return 0; + + if (p1->priority == BACKGROUND) + return -1; + + if (p2->priority == BACKGROUND) + return 1; + + if (p1->priority == FOREGROUND) + return 1; + + if (p2->priority == FOREGROUND) + return -1; + + int ay2 = p1->y + p1->currImagePtr->y2; + int by2 = p2->y + p2->currImagePtr->y2; + + return ay2 - by2; +} + +// Return TRUE if object being carried by hero +bool ObjectHandler::isCarrying(uint16 wordIndex) { + debugC(1, kDebugParser, "isCarrying(%d)", wordIndex); + + for (int i = 0; i < _vm->_numObj; i++) { + if ((wordIndex == _objects[i].nounIndex) && _objects[i].carriedFl) + return true; + } + return false; +} + +// Describe any takeable objects visible in this screen +void ObjectHandler::showTakeables() { + debugC(1, kDebugParser, "showTakeables"); + + for (int j = 0; j < _vm->_numObj; j++) { + object_t *obj = &_objects[j]; + if ((obj->cycling != INVISIBLE) && + (obj->screenIndex == *_vm->_screen_p) && + (((TAKE & obj->genericCmd) == TAKE) || obj->objValue)) { + Utils::Box(BOX_ANY, "You can also see:\n%s.", _vm->_arrayNouns[obj->nounIndex][LOOK_NAME]); + } + } +} + +void ObjectHandler::loadObject(Common::File &in) { +// TODO: For Hugo3, if not in story mode, set _objects[2].state to 3 + for (int varnt = 0; varnt < _vm->_numVariant; varnt++) { + uint16 numElem = in.readUint16BE(); + if (varnt == _vm->_gameVariant) { + _objects = (object_t *)malloc(sizeof(object_t) * numElem); + for (int i = 0; i < numElem; i++) { + _objects[i].nounIndex = in.readUint16BE(); + _objects[i].dataIndex = in.readUint16BE(); + uint16 numSubElem = in.readUint16BE(); + if (numSubElem == 0) + _objects[i].stateDataIndex = 0; + else + _objects[i].stateDataIndex = (uint16 *)malloc(sizeof(uint16) * numSubElem); + for (int j = 0; j < numSubElem; j++) + _objects[i].stateDataIndex[j] = in.readUint16BE(); + _objects[i].pathType = (path_t) in.readSint16BE(); + _objects[i].vxPath = in.readSint16BE(); + _objects[i].vyPath = in.readSint16BE(); + _objects[i].actIndex = in.readUint16BE(); + _objects[i].seqNumb = in.readByte(); + _objects[i].currImagePtr = 0; + if (_objects[i].seqNumb == 0) { + _objects[i].seqList[0].imageNbr = 0; + _objects[i].seqList[0].seqPtr = 0; + } + for (int j = 0; j < _objects[i].seqNumb; j++) { + _objects[i].seqList[j].imageNbr = in.readUint16BE(); + _objects[i].seqList[j].seqPtr = 0; + } + _objects[i].cycling = (cycle_t)in.readByte(); + _objects[i].cycleNumb = in.readByte(); + _objects[i].frameInterval = in.readByte(); + _objects[i].frameTimer = in.readByte(); + _objects[i].radius = in.readByte(); + _objects[i].screenIndex = in.readByte(); + _objects[i].x = in.readSint16BE(); + _objects[i].y = in.readSint16BE(); + _objects[i].oldx = in.readSint16BE(); + _objects[i].oldy = in.readSint16BE(); + _objects[i].vx = in.readByte(); + _objects[i].vy = in.readByte(); + _objects[i].objValue = in.readByte(); + _objects[i].genericCmd = in.readSint16BE(); + _objects[i].cmdIndex = in.readUint16BE(); + _objects[i].carriedFl = (in.readByte() != 0); + _objects[i].state = in.readByte(); + _objects[i].verbOnlyFl = (in.readByte() != 0); + _objects[i].priority = in.readByte(); + _objects[i].viewx = in.readSint16BE(); + _objects[i].viewy = in.readSint16BE(); + _objects[i].direction = in.readSint16BE(); + _objects[i].curSeqNum = in.readByte(); + _objects[i].curImageNum = in.readByte(); + _objects[i].oldvx = in.readByte(); + _objects[i].oldvy = in.readByte(); + } + } else { + for (int i = 0; i < numElem; i++) { + in.readUint16BE(); + in.readUint16BE(); + uint16 numSubElem = in.readUint16BE(); + for (int j = 0; j < numSubElem; j++) + in.readUint16BE(); + in.readSint16BE(); + in.readSint16BE(); + in.readSint16BE(); + in.readUint16BE(); + numSubElem = in.readByte(); + for (int j = 0; j < numSubElem; j++) + in.readUint16BE(); + in.readByte(); + in.readByte(); + in.readByte(); + in.readByte(); + in.readByte(); + in.readByte(); + in.readSint16BE(); + in.readSint16BE(); + in.readSint16BE(); + in.readSint16BE(); + in.readByte(); + in.readByte(); + in.readByte(); + in.readSint16BE(); + in.readUint16BE(); + in.readByte(); + in.readByte(); + in.readByte(); + in.readByte(); + in.readSint16BE(); + in.readSint16BE(); + in.readUint16BE(); + in.readByte(); + in.readByte(); + in.readByte(); + in.readByte(); + } + } + } +} + +} // End of namespace Hugo diff --git a/engines/hugo/object.h b/engines/hugo/object.h new file mode 100644 index 0000000000..b270b3dd75 --- /dev/null +++ b/engines/hugo/object.h @@ -0,0 +1,90 @@ +/* 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$ + * + */ + +/* + * This code is based on original Hugo Trilogy source code + * + * Copyright (c) 1989-1995 David P. Gray + * + */ + +#ifndef HUGO_OBJECT_H +#define HUGO_OBJECT_H + +#include "common/file.h" + +#define MAXOBJECTS 128 // Used in Update_images() + +namespace Hugo { + +class ObjectHandler { +public: + ObjectHandler(HugoEngine *vm); + ~ObjectHandler(); + + object_t *_objects; + + bool isCarrying(uint16 wordIndex); + + int16 findObject(uint16 x, uint16 y); + + void lookObject(object_t *obj); + void freeObjects(); + void loadObject(Common::File &in); + void moveObjects(); + void restoreSeq(object_t *obj); + void saveSeq(object_t *obj); + void showTakeables(); + void swapImages(int objNumb1, int objNumb2); + void updateImages(); + void useObject(int16 objId); + + static int y2comp(const void *a, const void *b); + + bool isCarried(int objIndex) { + return _objects[objIndex].carriedFl; + } + + void setCarry(int objIndex, bool val) { + _objects[objIndex].carriedFl = val; + } + + void setVelocity(int objIndex, int8 vx, int8 vy) { + _objects[objIndex].vx = vx; + _objects[objIndex].vy = vy; + } + + void setPath(int objIndex, path_t pathType, int16 vxPath, int16 vyPath) { + _objects[objIndex].pathType = pathType; + _objects[objIndex].vxPath = vxPath; + _objects[objIndex].vyPath = vyPath; + } +private: + HugoEngine *_vm; +}; + +} // End of namespace Hugo + +#endif //HUGO_OBJECT_H diff --git a/engines/hugo/parser.cpp b/engines/hugo/parser.cpp index 4277d6e845..a1f493706e 100644 --- a/engines/hugo/parser.cpp +++ b/engines/hugo/parser.cpp @@ -39,6 +39,7 @@ #include "hugo/route.h" #include "hugo/util.h" #include "hugo/sound.h" +#include "hugo/object.h" namespace Hugo { @@ -46,7 +47,7 @@ namespace Hugo { #define CX(X) LOWORD(X) #define CY(Y) HIWORD(Y) -Parser::Parser(HugoEngine &vm) : +Parser::Parser(HugoEngine *vm) : _vm(vm), _putIndex(0), _getIndex(0), _checkDoubleF1Fl(false) { } @@ -56,7 +57,7 @@ Parser::~Parser() { void Parser::keyHandler(uint16 nChar, uint16 nFlags) { debugC(1, kDebugParser, "keyHandler(%d, %d)", nChar, nFlags); - status_t &gameStatus = _vm.getGameStatus(); + status_t &gameStatus = _vm->getGameStatus(); bool repeatedFl = (nFlags & 0x4000); // TRUE if key is a repeat // Process key down event - called from OnKeyDown() @@ -74,14 +75,14 @@ void Parser::keyHandler(uint16 nChar, uint16 nFlags) { case Common::KEYCODE_DOWN: if (!repeatedFl) { gameStatus.routeIndex = -1; // Stop any automatic route - _vm.route().setWalk(nChar); // Direction of hero travel + _vm->_route->setWalk(nChar); // Direction of hero travel } break; case Common::KEYCODE_F1: // User Help (DOS) if (_checkDoubleF1Fl) - _vm.file().instructions(); + _vm->_file->instructions(); else - _vm.screen().userHelp(); + _vm->_screen->userHelp(); _checkDoubleF1Fl = !_checkDoubleF1Fl; break; case Common::KEYCODE_F6: // Inventory @@ -91,8 +92,8 @@ void Parser::keyHandler(uint16 nChar, uint16 nFlags) { _config.turboFl = !_config.turboFl; break; case Common::KEYCODE_F2: // Toggle sound - _vm.sound().toggleSound(); - _vm.sound().toggleMusic(); + _vm->_sound->toggleSound(); + _vm->_sound->toggleMusic(); break; case Common::KEYCODE_F3: // Repeat last line gameStatus.recallFl = true; @@ -129,7 +130,7 @@ void Parser::charHandler() { static uint32 tick = 0; // For flashing cursor static char cursor = '_'; static command_t cmdLine; // Build command line - status_t &gameStatus = _vm.getGameStatus(); + status_t &gameStatus = _vm->getGameStatus(); // Check for one or more characters in ring buffer while (_getIndex != _putIndex) { @@ -143,7 +144,7 @@ void Parser::charHandler() { cmdLine[--lineIndex] = '\0'; break; case Common::KEYCODE_RETURN: // EOL, pass line to line handler - if (lineIndex && (_vm._hero->pathType != QUIET)) { + if (lineIndex && (_vm->_hero->pathType != QUIET)) { // Remove inventory bar if active if (gameStatus.inventoryState == I_ACTIVE) gameStatus.inventoryState = I_UP; @@ -176,8 +177,8 @@ void Parser::charHandler() { lineIndex = strlen(cmdLine); } - sprintf(_vm._statusLine, ">%s%c", cmdLine, cursor); - sprintf(_vm._scoreLine, "F1-Help %s Score: %d of %d Sound %s", (_config.turboFl) ? "T" : " ", _vm.getScore(), _vm.getMaxScore(), (_config.soundFl) ? "On" : "Off"); + sprintf(_vm->_statusLine, ">%s%c", cmdLine, cursor); + sprintf(_vm->_scoreLine, "F1-Help %s Score: %d of %d Sound %s", (_config.turboFl) ? "T" : " ", _vm->getScore(), _vm->getMaxScore(), (_config.soundFl) ? "On" : "Off"); // See if "look" button pressed if (gameStatus.lookFl) { @@ -216,10 +217,10 @@ bool Parser::isWordPresent(char **wordArr) { char *Parser::findNoun() { debugC(1, kDebugParser, "findNoun()"); - for (int i = 0; _vm._arrayNouns[i]; i++) { - for (int j = 0; strlen(_vm._arrayNouns[i][j]); j++) { - if (strstr(_line, _vm._arrayNouns[i][j])) - return _vm._arrayNouns[i][0]; + for (int i = 0; _vm->_arrayNouns[i]; i++) { + for (int j = 0; strlen(_vm->_arrayNouns[i][j]); j++) { + if (strstr(_line, _vm->_arrayNouns[i][j])) + return _vm->_arrayNouns[i][0]; } } return 0; @@ -229,49 +230,24 @@ char *Parser::findNoun() { char *Parser::findVerb() { debugC(1, kDebugParser, "findVerb()"); - for (int i = 0; _vm._arrayVerbs[i]; i++) { - for (int j = 0; strlen(_vm._arrayVerbs[i][j]); j++) { - if (strstr(_line, _vm._arrayVerbs[i][j])) - return _vm._arrayVerbs[i][0]; + for (int i = 0; _vm->_arrayVerbs[i]; i++) { + for (int j = 0; strlen(_vm->_arrayVerbs[i][j]); j++) { + if (strstr(_line, _vm->_arrayVerbs[i][j])) + return _vm->_arrayVerbs[i][0]; } } return 0; } -// Describe any takeable objects visible in this screen -void Parser::showTakeables() { - debugC(1, kDebugParser, "showTakeables"); - - for (int j = 0; j < _vm._numObj; j++) { - object_t *obj = &_vm._objects[j]; - if ((obj->cycling != INVISIBLE) && - (obj->screenIndex == *_vm._screen_p) && - (((TAKE & obj->genericCmd) == TAKE) || obj->objValue)) { - Utils::Box(BOX_ANY, "You can also see:\n%s.", _vm._arrayNouns[obj->nounIndex][LOOK_NAME]); - } - } -} - -// Return TRUE if object being carried by hero -bool Parser::isCarrying(uint16 wordIndex) { - debugC(1, kDebugParser, "isCarrying(%d)", wordIndex); - - for (int i = 0; i < _vm._numObj; i++) { - if ((wordIndex == _vm._objects[i].nounIndex) && _vm._objects[i].carriedFl) - return true; - } - return false; -} - // Show user all objects being carried in a variable width 2 column format void Parser::showDosInventory() { debugC(1, kDebugParser, "showDosInventory()"); static const char *blanks = " "; uint16 index = 0, len1 = 0, len2 = 0; - for (int i = 0; i < _vm._numObj; i++) { // Find widths of 2 columns - if (_vm._objects[i].carriedFl) { - uint16 len = strlen(_vm._arrayNouns[_vm._objects[i].nounIndex][1]); + for (int i = 0; i < _vm->_numObj; i++) { // Find widths of 2 columns + if (_vm->_object->isCarried(i)) { + uint16 len = strlen(_vm->_arrayNouns[_vm->_object->_objects[i].nounIndex][1]); if (index++ & 1) // Right hand column len2 = (len > len2) ? len : len2; else @@ -280,24 +256,24 @@ void Parser::showDosInventory() { } len1 += 1; // For gap between columns - if (len1 + len2 < (uint16)strlen(_vm._textParser[kTBOutro])) - len1 = strlen(_vm._textParser[kTBOutro]); + if (len1 + len2 < (uint16)strlen(_vm->_textParser[kTBOutro])) + len1 = strlen(_vm->_textParser[kTBOutro]); char buffer[XBYTES *NUM_ROWS] = "\0"; - strncat(buffer, blanks, (len1 + len2 - strlen(_vm._textParser[kTBIntro])) / 2); - strcat(strcat(buffer, _vm._textParser[kTBIntro]), "\n"); + strncat(buffer, blanks, (len1 + len2 - strlen(_vm->_textParser[kTBIntro])) / 2); + strcat(strcat(buffer, _vm->_textParser[kTBIntro]), "\n"); index = 0; - for (int i = 0; i < _vm._numObj; i++) { // Assign strings - if (_vm._objects[i].carriedFl) { + for (int i = 0; i < _vm->_numObj; i++) { // Assign strings + if (_vm->_object->isCarried(i)) { if (index++ & 1) - strcat(strcat(buffer, _vm._arrayNouns[_vm._objects[i].nounIndex][1]), "\n"); + strcat(strcat(buffer, _vm->_arrayNouns[_vm->_object->_objects[i].nounIndex][1]), "\n"); else - strncat(strcat(buffer, _vm._arrayNouns[_vm._objects[i].nounIndex][1]), blanks, len1 - strlen(_vm._arrayNouns[_vm._objects[i].nounIndex][1])); + strncat(strcat(buffer, _vm->_arrayNouns[_vm->_object->_objects[i].nounIndex][1]), blanks, len1 - strlen(_vm->_arrayNouns[_vm->_object->_objects[i].nounIndex][1])); } } if (index & 1) strcat(buffer, "\n"); - strcat(buffer, _vm._textParser[kTBOutro]); + strcat(buffer, _vm->_textParser[kTBOutro]); Utils::Box(BOX_ANY, "%s", buffer); } diff --git a/engines/hugo/parser.h b/engines/hugo/parser.h index 5226304d51..1d4678b3af 100644 --- a/engines/hugo/parser.h +++ b/engines/hugo/parser.h @@ -44,7 +44,7 @@ enum seqTextParser { class Parser { public: - Parser(HugoEngine &vm); + Parser(HugoEngine *vm); virtual ~Parser(); bool isWordPresent(char **wordArr); @@ -55,16 +55,12 @@ public: virtual void lineHandler() = 0; protected: - HugoEngine &_vm; + HugoEngine *_vm; protected: - bool isCarrying(uint16 wordIndex); - char *findNoun(); char *findVerb(); - void showTakeables(); - private: char _ringBuffer[32]; // Ring buffer uint16 _putIndex; @@ -76,7 +72,7 @@ private: class Parser_v1w : public Parser { public: - Parser_v1w(HugoEngine &vm); + Parser_v1w(HugoEngine *vm); ~Parser_v1w(); virtual void lineHandler(); @@ -95,7 +91,7 @@ private: class Parser_v1d : public Parser { public: - Parser_v1d(HugoEngine &vm); + Parser_v1d(HugoEngine *vm); ~Parser_v1d(); virtual void lineHandler(); @@ -113,7 +109,7 @@ protected: class Parser_v2d : public Parser_v1d { public: - Parser_v2d(HugoEngine &vm); + Parser_v2d(HugoEngine *vm); ~Parser_v2d(); void lineHandler(); @@ -121,7 +117,7 @@ public: class Parser_v3d : public Parser_v1w { public: - Parser_v3d(HugoEngine &vm); + Parser_v3d(HugoEngine *vm); ~Parser_v3d(); void lineHandler(); diff --git a/engines/hugo/parser_v1d.cpp b/engines/hugo/parser_v1d.cpp index 9364cd9532..dcdc2c74ac 100644 --- a/engines/hugo/parser_v1d.cpp +++ b/engines/hugo/parser_v1d.cpp @@ -39,10 +39,11 @@ #include "hugo/file.h" #include "hugo/schedule.h" #include "hugo/util.h" +#include "hugo/object.h" namespace Hugo { -Parser_v1d::Parser_v1d(HugoEngine &vm) : Parser(vm) { +Parser_v1d::Parser_v1d(HugoEngine *vm) : Parser(vm) { } Parser_v1d::~Parser_v1d() { @@ -55,15 +56,15 @@ char *Parser_v1d::findNextNoun(char *noun) { int currNounIndex = -1; if (noun) { // If noun not NULL, find index - for (currNounIndex = 0; _vm._arrayNouns[currNounIndex]; currNounIndex++) { - if (noun == _vm._arrayNouns[currNounIndex][0]) + for (currNounIndex = 0; _vm->_arrayNouns[currNounIndex]; currNounIndex++) { + if (noun == _vm->_arrayNouns[currNounIndex][0]) break; } } - for (int i = currNounIndex + 1; _vm._arrayNouns[i]; i++) { - for (int j = 0; strlen(_vm._arrayNouns[i][j]); j++) { - if (strstr(_line, _vm._arrayNouns[i][j])) - return _vm._arrayNouns[i][0]; + for (int i = currNounIndex + 1; _vm->_arrayNouns[i]; i++) { + for (int j = 0; strlen(_vm->_arrayNouns[i][j]); j++) { + if (strstr(_line, _vm->_arrayNouns[i][j])) + return _vm->_arrayNouns[i][0]; } } return 0; @@ -78,33 +79,33 @@ bool Parser_v1d::isNear(char *verb, char *noun, object_t *obj, char *comment) { if (!noun && !obj->verbOnlyFl) { // No noun specified & object not context senesitive return false; - } else if (noun && (noun != _vm._arrayNouns[obj->nounIndex][0])) { // Noun specified & not same as object + } else if (noun && (noun != _vm->_arrayNouns[obj->nounIndex][0])) { // Noun specified & not same as object return false; } else if (obj->carriedFl) { // Object is being carried return true; - } else if (obj->screenIndex != *_vm._screen_p) { // Not in same screen + } else if (obj->screenIndex != *_vm->_screen_p) { // Not in same screen if (obj->objValue) - strcpy (comment, _vm._textParser[kCmtAny4]); + strcpy (comment, _vm->_textParser[kCmtAny4]); return false; } if (obj->cycling == INVISIBLE) { if (obj->seqNumb) { // There is an image - strcpy(comment, _vm._textParser[kCmtAny5]); + strcpy(comment, _vm->_textParser[kCmtAny5]); return false; } else { // No image, assume visible if ((obj->radius < 0) || - ((abs(obj->x - _vm._hero->x) <= obj->radius) && - (abs(obj->y - _vm._hero->y - _vm._hero->currImagePtr->y2) <= obj->radius))) { + ((abs(obj->x - _vm->_hero->x) <= obj->radius) && + (abs(obj->y - _vm->_hero->y - _vm->_hero->currImagePtr->y2) <= obj->radius))) { return true; } else { // User is either not close enough (stationary, valueless objects) // or is not carrying it (small, portable objects of value) if (noun) { // Don't say unless object specified - if (obj->objValue && (verb != _vm._arrayVerbs[_vm._take][0])) - strcpy(comment, _vm._textParser[kCmtAny4]); + if (obj->objValue && (verb != _vm->_arrayVerbs[_vm->_take][0])) + strcpy(comment, _vm->_textParser[kCmtAny4]); else - strcpy(comment, _vm._textParser[kCmtClose]); + strcpy(comment, _vm->_textParser[kCmtClose]); } return false; } @@ -112,17 +113,17 @@ bool Parser_v1d::isNear(char *verb, char *noun, object_t *obj, char *comment) { } if ((obj->radius < 0) || - ((abs(obj->x - _vm._hero->x) <= obj->radius) && - (abs(obj->y + obj->currImagePtr->y2 - _vm._hero->y - _vm._hero->currImagePtr->y2) <= obj->radius))) { + ((abs(obj->x - _vm->_hero->x) <= obj->radius) && + (abs(obj->y + obj->currImagePtr->y2 - _vm->_hero->y - _vm->_hero->currImagePtr->y2) <= obj->radius))) { return true; } else { // User is either not close enough (stationary, valueless objects) // or is not carrying it (small, portable objects of value) if (noun) { // Don't say unless object specified - if (obj->objValue && (verb != _vm._arrayVerbs[_vm._take][0])) - strcpy(comment, _vm._textParser[kCmtAny4]); + if (obj->objValue && (verb != _vm->_arrayVerbs[_vm->_take][0])) + strcpy(comment, _vm->_textParser[kCmtAny4]); else - strcpy(comment, _vm._textParser[kCmtClose]); + strcpy(comment, _vm->_textParser[kCmtClose]); } return false; } @@ -140,27 +141,27 @@ bool Parser_v1d::isGenericVerb(char *word, object_t *obj) { return false; // Following is equivalent to switch, but couldn't do one - if (word == _vm._arrayVerbs[_vm._look][0]) { + if (word == _vm->_arrayVerbs[_vm->_look][0]) { if ((LOOK & obj->genericCmd) == LOOK) - Utils::Box(BOX_ANY, "%s", _vm._textData[obj->dataIndex]); + Utils::Box(BOX_ANY, "%s", _vm->_textData[obj->dataIndex]); else - Utils::Box(BOX_ANY, "%s", _vm._textParser[kTBUnusual_1d]); - } else if (word == _vm._arrayVerbs[_vm._take][0]) { + Utils::Box(BOX_ANY, "%s", _vm->_textParser[kTBUnusual_1d]); + } else if (word == _vm->_arrayVerbs[_vm->_take][0]) { if (obj->carriedFl) - Utils::Box(BOX_ANY, "%s", _vm._textParser[kTBHave]); + Utils::Box(BOX_ANY, "%s", _vm->_textParser[kTBHave]); else if ((TAKE & obj->genericCmd) == TAKE) takeObject(obj); else if (!obj->verbOnlyFl) // Make sure not taking object in context! - Utils::Box(BOX_ANY, "%s", _vm._textParser[kTBNoUse]); + Utils::Box(BOX_ANY, "%s", _vm->_textParser[kTBNoUse]); else return false; - } else if (word == _vm._arrayVerbs[_vm._drop][0]) { + } else if (word == _vm->_arrayVerbs[_vm->_drop][0]) { if (!obj->carriedFl) - Utils::Box(BOX_ANY, "%s", _vm._textParser[kTBDontHave]); + Utils::Box(BOX_ANY, "%s", _vm->_textParser[kTBDontHave]); else if ((DROP & obj->genericCmd) == DROP) dropObject(obj); else - Utils::Box(BOX_ANY, "%s", _vm._textParser[kTBNeed]); + Utils::Box(BOX_ANY, "%s", _vm->_textParser[kTBNeed]); } else { // It was not a generic cmd return false; } @@ -181,21 +182,21 @@ bool Parser_v1d::isObjectVerb(char *word, object_t *obj) { return false; int i; - for (i = 0; _vm._cmdList[cmdIndex][i].verbIndex != 0; i++) { // For each cmd - if (!strcmp(word, _vm._arrayVerbs[_vm._cmdList[cmdIndex][i].verbIndex][0])) // Is this verb catered for? + for (i = 0; _vm->_cmdList[cmdIndex][i].verbIndex != 0; i++) { // For each cmd + if (!strcmp(word, _vm->_arrayVerbs[_vm->_cmdList[cmdIndex][i].verbIndex][0])) // Is this verb catered for? break; } - if (_vm._cmdList[cmdIndex][i].verbIndex == 0) // No + if (_vm->_cmdList[cmdIndex][i].verbIndex == 0) // No return false; // Verb match found, check all required objects are being carried - cmd *cmnd = &_vm._cmdList[cmdIndex][i]; // ptr to struct cmd + cmd *cmnd = &_vm->_cmdList[cmdIndex][i]; // ptr to struct cmd if (cmnd->reqIndex) { // At least 1 thing in list - uint16 *reqs = _vm._arrayReqs[cmnd->reqIndex]; // ptr to list of required objects + uint16 *reqs = _vm->_arrayReqs[cmnd->reqIndex]; // ptr to list of required objects for (i = 0; reqs[i]; i++) { // for each obj - if (!isCarrying(reqs[i])) { - Utils::Box(BOX_ANY, "%s", _vm._textData[cmnd->textDataNoCarryIndex]); + if (!_vm->_object->isCarrying(reqs[i])) { + Utils::Box(BOX_ANY, "%s", _vm->_textData[cmnd->textDataNoCarryIndex]); return true; } } @@ -203,17 +204,17 @@ bool Parser_v1d::isObjectVerb(char *word, object_t *obj) { // Required objects are present, now check state is correct if ((obj->state != cmnd->reqState) && (cmnd->reqState != DONT_CARE)){ - Utils::Box(BOX_ANY, "%s", _vm._textData[cmnd->textDataWrongIndex]); + Utils::Box(BOX_ANY, "%s", _vm->_textData[cmnd->textDataWrongIndex]); return true; } // Everything checked. Change the state and carry out any actions if (cmnd->reqState != DONT_CARE) // Don't change new state if required state didn't care obj->state = cmnd->newState; - Utils::Box(BOX_ANY, "%s", _vm._textData[cmnd->textDataDoneIndex]); - _vm.scheduler().insertActionList(cmnd->actIndex); + Utils::Box(BOX_ANY, "%s", _vm->_textData[cmnd->textDataDoneIndex]); + _vm->_scheduler->insertActionList(cmnd->actIndex); // Special case if verb is Take or Drop. Assume additional generic actions - if ((word == _vm._arrayVerbs[_vm._take][0]) || (word == _vm._arrayVerbs[_vm._drop][0])) + if ((word == _vm->_arrayVerbs[_vm->_take][0]) || (word == _vm->_arrayVerbs[_vm->_drop][0])) isGenericVerb(word, obj); return true; } @@ -227,8 +228,8 @@ bool Parser_v1d::isBackgroundWord(char *noun, char *verb, objectList_t obj) { return false; for (int i = 0; obj[i].verbIndex; i++) { - if ((verb == _vm._arrayVerbs[obj[i].verbIndex][0]) && (noun == _vm._arrayNouns[obj[i].nounIndex][0])) { - Utils::Box(BOX_ANY, "%s", _vm.file().fetchString(obj[i].commentIndex)); + if ((verb == _vm->_arrayVerbs[obj[i].verbIndex][0]) && (noun == _vm->_arrayNouns[obj[i].nounIndex][0])) { + Utils::Box(BOX_ANY, "%s", _vm->_file->fetchString(obj[i].commentIndex)); return true; } } @@ -243,9 +244,9 @@ void Parser_v1d::takeObject(object_t *obj) { if (obj->seqNumb) // Don't change if no image to display obj->cycling = ALMOST_INVISIBLE; - _vm.adjustScore(obj->objValue); + _vm->adjustScore(obj->objValue); - Utils::Box(BOX_ANY, TAKE_TEXT, _vm._arrayNouns[obj->nounIndex][TAKE_NAME]); + Utils::Box(BOX_ANY, TAKE_TEXT, _vm->_arrayNouns[obj->nounIndex][TAKE_NAME]); } // Do all necessary things to drop an object @@ -253,13 +254,13 @@ void Parser_v1d::dropObject(object_t *obj) { debugC(1, kDebugParser, "dropObject(object_t *obj)"); obj->carriedFl = false; - obj->screenIndex = *_vm._screen_p; + obj->screenIndex = *_vm->_screen_p; if (obj->seqNumb) // Don't change if no image to display obj->cycling = NOT_CYCLING; - obj->x = _vm._hero->x - 1; - obj->y = _vm._hero->y + _vm._hero->currImagePtr->y2 - 1; - _vm.adjustScore(-obj->objValue); - Utils::Box(BOX_ANY, "%s", _vm._textParser[kTBOk]); + obj->x = _vm->_hero->x - 1; + obj->y = _vm->_hero->y + _vm->_hero->currImagePtr->y2 - 1; + _vm->adjustScore(-obj->objValue); + Utils::Box(BOX_ANY, "%s", _vm->_textParser[kTBOk]); } // Print text for possible background object. Return TRUE if match found @@ -271,8 +272,8 @@ bool Parser_v1d::isCatchallVerb(bool testNounFl, char *noun, char *verb, objectL return false; for (int i = 0; obj[i].verbIndex; i++) { - if ((verb == _vm._arrayVerbs[obj[i].verbIndex][0]) && ((noun == _vm._arrayNouns[obj[i].nounIndex][0]) || (obj[i].nounIndex == 0))) { - Utils::Box(BOX_ANY, "%s", _vm.file().fetchString(obj[i].commentIndex)); + if ((verb == _vm->_arrayVerbs[obj[i].verbIndex][0]) && ((noun == _vm->_arrayNouns[obj[i].nounIndex][0]) || (obj[i].nounIndex == 0))) { + Utils::Box(BOX_ANY, "%s", _vm->_file->fetchString(obj[i].commentIndex)); return true; } } @@ -284,15 +285,15 @@ void Parser_v1d::lineHandler() { debugC(1, kDebugParser, "lineHandler()"); object_t *obj; - status_t &gameStatus = _vm.getGameStatus(); + status_t &gameStatus = _vm->getGameStatus(); char farComment[XBYTES * 5] = ""; // hold 5 line comment if object not nearby // Reset_prompt_line (); Utils::strlwr(_line); // Convert to lower case if (!strcmp("exit", _line) || strstr(_line, "quit")) { - if (Utils::Box(BOX_YESNO, "%s", _vm._textParser[kTBExit_1d]) != 0) - _vm.endGame(); + if (Utils::Box(BOX_YESNO, "%s", _vm->_textParser[kTBExit_1d]) != 0) + _vm->endGame(); return; } @@ -301,13 +302,13 @@ void Parser_v1d::lineHandler() { if (gameStatus.gameOverFl) Utils::gameOverMsg(); else -// _vm.file().saveOrRestore(true); +// _vm->_file->saveOrRestore(true); warning("STUB: saveOrRestore()"); return; } if (!strcmp("restore", _line)) { -// _vm.file().saveOrRestore(false); +// _vm->_file->saveOrRestore(false); warning("STUB: saveOrRestore()"); return; } @@ -331,25 +332,25 @@ void Parser_v1d::lineHandler() { do { noun = findNextNoun(noun); // Find a noun in the line // Must try at least once for objects allowing verb-context - for (int i = 0; i < _vm._numObj; i++) { - obj = &_vm._objects[i]; + for (int i = 0; i < _vm->_numObj; i++) { + obj = &_vm->_object->_objects[i]; if (isNear(verb, noun, obj, farComment)) { if (isObjectVerb(verb, obj) // Foreground object || isGenericVerb(verb, obj)) // Common action type return; } } - if ((*farComment == '\0') && isBackgroundWord(noun, verb, _vm._backgroundObjects[*_vm._screen_p])) + if ((*farComment == '\0') && isBackgroundWord(noun, verb, _vm->_backgroundObjects[*_vm->_screen_p])) return; } while (noun); } noun = findNextNoun(noun); if (*farComment != '\0') // An object matched but not near enough Utils::Box(BOX_ANY, "%s", farComment); - else if (!isCatchallVerb(true, noun, verb, _vm._catchallList) && - !isCatchallVerb(false, noun, verb, _vm._backgroundObjects[*_vm._screen_p]) && - !isCatchallVerb(false, noun, verb, _vm._catchallList)) - Utils::Box(BOX_ANY, "%s", _vm._textParser[kTBEh_1d]); + else if (!isCatchallVerb(true, noun, verb, _vm->_catchallList) && + !isCatchallVerb(false, noun, verb, _vm->_backgroundObjects[*_vm->_screen_p]) && + !isCatchallVerb(false, noun, verb, _vm->_catchallList)) + Utils::Box(BOX_ANY, "%s", _vm->_textParser[kTBEh_1d]); } } // End of namespace Hugo diff --git a/engines/hugo/parser_v1w.cpp b/engines/hugo/parser_v1w.cpp index 417b31e794..5021db4c6e 100644 --- a/engines/hugo/parser_v1w.cpp +++ b/engines/hugo/parser_v1w.cpp @@ -40,9 +40,10 @@ #include "hugo/schedule.h" #include "hugo/util.h" #include "hugo/sound.h" +#include "hugo/object.h" namespace Hugo { -Parser_v1w::Parser_v1w(HugoEngine &vm) : Parser(vm) { +Parser_v1w::Parser_v1w(HugoEngine *vm) : Parser(vm) { } Parser_v1w::~Parser_v1w() { @@ -60,26 +61,26 @@ bool Parser_v1w::isObjectVerb(object_t *obj, char *comment) { return false; int i; - for (i = 0; _vm._cmdList[cmdIndex][i].verbIndex != 0; i++) { // For each cmd - if (isWordPresent(_vm._arrayVerbs[_vm._cmdList[cmdIndex][i].verbIndex])) // Was this verb used? + for (i = 0; _vm->_cmdList[cmdIndex][i].verbIndex != 0; i++) { // For each cmd + if (isWordPresent(_vm->_arrayVerbs[_vm->_cmdList[cmdIndex][i].verbIndex])) // Was this verb used? break; } - if (_vm._cmdList[cmdIndex][i].verbIndex == 0) // No verbs used. + if (_vm->_cmdList[cmdIndex][i].verbIndex == 0) // No verbs used. return false; // Verb match found. Check if object is Near - char *verb = *_vm._arrayVerbs[_vm._cmdList[cmdIndex][i].verbIndex]; + char *verb = *_vm->_arrayVerbs[_vm->_cmdList[cmdIndex][i].verbIndex]; if (!isNear(obj, verb, comment)) return false; // Check all required objects are being carried - cmd *cmnd = &_vm._cmdList[cmdIndex][i]; // ptr to struct cmd + cmd *cmnd = &_vm->_cmdList[cmdIndex][i]; // ptr to struct cmd if (cmnd->reqIndex) { // At least 1 thing in list - uint16 *reqs = _vm._arrayReqs[cmnd->reqIndex]; // ptr to list of required objects + uint16 *reqs = _vm->_arrayReqs[cmnd->reqIndex]; // ptr to list of required objects for (i = 0; reqs[i]; i++) { // for each obj - if (!isCarrying(reqs[i])) { - Utils::Box(BOX_ANY, "%s", _vm._textData[cmnd->textDataNoCarryIndex]); + if (!_vm->_object->isCarrying(reqs[i])) { + Utils::Box(BOX_ANY, "%s", _vm->_textData[cmnd->textDataNoCarryIndex]); return true; } } @@ -87,18 +88,18 @@ bool Parser_v1w::isObjectVerb(object_t *obj, char *comment) { // Required objects are present, now check state is correct if ((obj->state != cmnd->reqState) && (cmnd->reqState != DONT_CARE)) { - Utils::Box(BOX_ANY, "%s", _vm._textData[cmnd->textDataWrongIndex]); + Utils::Box(BOX_ANY, "%s", _vm->_textData[cmnd->textDataWrongIndex]); return true; } // Everything checked. Change the state and carry out any actions if (cmnd->reqState != DONT_CARE) // Don't change new state if required state didn't care obj->state = cmnd->newState; - Utils::Box(BOX_ANY, "%s", _vm._textData[cmnd->textDataDoneIndex]); - _vm.scheduler().insertActionList(cmnd->actIndex); + Utils::Box(BOX_ANY, "%s", _vm->_textData[cmnd->textDataDoneIndex]); + _vm->_scheduler->insertActionList(cmnd->actIndex); // See if any additional generic actions - if ((verb == _vm._arrayVerbs[_vm._look][0]) || (verb == _vm._arrayVerbs[_vm._take][0]) || (verb == _vm._arrayVerbs[_vm._drop][0])) + if ((verb == _vm->_arrayVerbs[_vm->_look][0]) || (verb == _vm->_arrayVerbs[_vm->_take][0]) || (verb == _vm->_arrayVerbs[_vm->_drop][0])) isGenericVerb(obj, comment); return true; } @@ -111,39 +112,39 @@ bool Parser_v1w::isGenericVerb(object_t *obj, char *comment) { return false; // Following is equivalent to switch, but couldn't do one - if (isWordPresent(_vm._arrayVerbs[_vm._look]) && isNear(obj, _vm._arrayVerbs[_vm._look][0], comment)) { + if (isWordPresent(_vm->_arrayVerbs[_vm->_look]) && isNear(obj, _vm->_arrayVerbs[_vm->_look][0], comment)) { // Test state-dependent look before general look if ((obj->genericCmd & LOOK_S) == LOOK_S) { - Utils::Box(BOX_ANY, "%s", _vm._textData[obj->stateDataIndex[obj->state]]); + Utils::Box(BOX_ANY, "%s", _vm->_textData[obj->stateDataIndex[obj->state]]); warning("isGenericVerb: use of state dependant look - To be validated"); } else { if ((LOOK & obj->genericCmd) == LOOK) { - if (_vm._textData[obj->dataIndex]) - Utils::Box(BOX_ANY, "%s", _vm._textData[obj->dataIndex]); + if (_vm->_textData[obj->dataIndex]) + Utils::Box(BOX_ANY, "%s", _vm->_textData[obj->dataIndex]); else return false; } else { - Utils::Box(BOX_ANY, "%s", _vm._textParser[kTBUnusual]); + Utils::Box(BOX_ANY, "%s", _vm->_textParser[kTBUnusual]); } } - } else if (isWordPresent(_vm._arrayVerbs[_vm._take]) && isNear(obj, _vm._arrayVerbs[_vm._take][0], comment)) { + } else if (isWordPresent(_vm->_arrayVerbs[_vm->_take]) && isNear(obj, _vm->_arrayVerbs[_vm->_take][0], comment)) { if (obj->carriedFl) - Utils::Box(BOX_ANY, "%s", _vm._textParser[kTBHave]); + Utils::Box(BOX_ANY, "%s", _vm->_textParser[kTBHave]); else if ((TAKE & obj->genericCmd) == TAKE) takeObject(obj); else if (obj->cmdIndex != 0) // No comment if possible commands return false; else if (!obj->verbOnlyFl && (TAKE & obj->genericCmd) == TAKE) // Make sure not taking object in context! - Utils::Box(BOX_ANY, "%s", _vm._textParser[kTBNoUse]); + Utils::Box(BOX_ANY, "%s", _vm->_textParser[kTBNoUse]); else return false; - } else if (isWordPresent(_vm._arrayVerbs[_vm._drop])) { + } else if (isWordPresent(_vm->_arrayVerbs[_vm->_drop])) { if (!obj->carriedFl && ((DROP & obj->genericCmd) == DROP)) - Utils::Box(BOX_ANY, "%s", _vm._textParser[kTBDontHave]); + Utils::Box(BOX_ANY, "%s", _vm->_textParser[kTBDontHave]); else if (obj->carriedFl && ((DROP & obj->genericCmd) == DROP)) dropObject(obj); else if (obj->cmdIndex == 0) - Utils::Box(BOX_ANY, "%s", _vm._textParser[kTBNeed]); + Utils::Box(BOX_ANY, "%s", _vm->_textParser[kTBNeed]); else return false; } else { // It was not a generic cmd @@ -163,47 +164,47 @@ bool Parser_v1w::isNear(object_t *obj, char *verb, char *comment) { if (obj->carriedFl) // Object is being carried return true; - if (obj->screenIndex != *_vm._screen_p) { + if (obj->screenIndex != *_vm->_screen_p) { // Not in same screen if (obj->objValue) - strcpy(comment, _vm._textParser[kCmtAny1]); + strcpy(comment, _vm->_textParser[kCmtAny1]); else - strcpy(comment, _vm._textParser[kCmtAny2]); + strcpy(comment, _vm->_textParser[kCmtAny2]); return false; } if (obj->cycling == INVISIBLE) { if (obj->seqNumb) { // There is an image - strcpy(comment, _vm._textParser[kCmtAny3]); + strcpy(comment, _vm->_textParser[kCmtAny3]); return false; } else { // No image, assume visible if ((obj->radius < 0) || - ((abs(obj->x - _vm._hero->x) <= obj->radius) && - (abs(obj->y - _vm._hero->y - _vm._hero->currImagePtr->y2) <= obj->radius))) { + ((abs(obj->x - _vm->_hero->x) <= obj->radius) && + (abs(obj->y - _vm->_hero->y - _vm->_hero->currImagePtr->y2) <= obj->radius))) { return true; } else { // User is not close enough - if (obj->objValue && (verb != _vm._arrayVerbs[_vm._take][0])) - strcpy(comment, _vm._textParser[kCmtAny1]); + if (obj->objValue && (verb != _vm->_arrayVerbs[_vm->_take][0])) + strcpy(comment, _vm->_textParser[kCmtAny1]); else - strcpy(comment, _vm._textParser[kCmtClose]); + strcpy(comment, _vm->_textParser[kCmtClose]); return false; } } } if ((obj->radius < 0) || - ((abs(obj->x - _vm._hero->x) <= obj->radius) && - (abs(obj->y + obj->currImagePtr->y2 - _vm._hero->y - _vm._hero->currImagePtr->y2) <= obj->radius))) { + ((abs(obj->x - _vm->_hero->x) <= obj->radius) && + (abs(obj->y + obj->currImagePtr->y2 - _vm->_hero->y - _vm->_hero->currImagePtr->y2) <= obj->radius))) { return true; } else { // User is not close enough - if (obj->objValue && (verb != _vm._arrayVerbs[_vm._take][0])) - strcpy(comment, _vm._textParser[kCmtAny1]); + if (obj->objValue && (verb != _vm->_arrayVerbs[_vm->_take][0])) + strcpy(comment, _vm->_textParser[kCmtAny1]); else - strcpy(comment, _vm._textParser[kCmtClose]); + strcpy(comment, _vm->_textParser[kCmtClose]); return false; } return true; @@ -217,11 +218,11 @@ void Parser_v1w::takeObject(object_t *obj) { if (obj->seqNumb) { // Don't change if no image to display obj->cycling = INVISIBLE; } - _vm.adjustScore(obj->objValue); + _vm->adjustScore(obj->objValue); if (obj->seqNumb > 0) // If object has an image, force walk to dropped obj->viewx = -1; // (possibly moved) object next time taken! - Utils::Box(BOX_ANY, TAKE_TEXT, _vm._arrayNouns[obj->nounIndex][TAKE_NAME]); + Utils::Box(BOX_ANY, TAKE_TEXT, _vm->_arrayNouns[obj->nounIndex][TAKE_NAME]); } // Do all necessary things to drop an object @@ -229,16 +230,16 @@ void Parser_v1w::dropObject(object_t *obj) { debugC(1, kDebugParser, "dropObject(object_t *obj)"); obj->carriedFl = false; - obj->screenIndex = *_vm._screen_p; + obj->screenIndex = *_vm->_screen_p; if ((obj->seqNumb > 1) || (obj->seqList[0].imageNbr > 1)) obj->cycling = CYCLE_FORWARD; else obj->cycling = NOT_CYCLING; - obj->x = _vm._hero->x - 1; - obj->y = _vm._hero->y + _vm._hero->currImagePtr->y2 - 1; + obj->x = _vm->_hero->x - 1; + obj->y = _vm->_hero->y + _vm->_hero->currImagePtr->y2 - 1; obj->y = (obj->y + obj->currImagePtr->y2 < YPIX) ? obj->y : YPIX - obj->currImagePtr->y2 - 10; - _vm.adjustScore(-obj->objValue); - Utils::Box(BOX_ANY, "%s", _vm._textParser[kTBOk]); + _vm->adjustScore(-obj->objValue); + Utils::Box(BOX_ANY, "%s", _vm->_textParser[kTBOk]); } // Search for matching verbs in background command list. @@ -249,16 +250,16 @@ bool Parser_v1w::isCatchallVerb(objectList_t obj) { debugC(1, kDebugParser, "isCatchallVerb(object_list_t obj)"); for (int i = 0; obj[i].verbIndex != 0; i++) { - if (isWordPresent(_vm._arrayVerbs[obj[i].verbIndex]) && obj[i].nounIndex == 0 && + if (isWordPresent(_vm->_arrayVerbs[obj[i].verbIndex]) && obj[i].nounIndex == 0 && (!obj[i].matchFl || !findNoun()) && ((obj[i].roomState == DONT_CARE) || - (obj[i].roomState == _vm._screenStates[*_vm._screen_p]))) { - Utils::Box(BOX_ANY, "%s", _vm.file().fetchString(obj[i].commentIndex)); - _vm.scheduler().processBonus(obj[i].bonusIndex); + (obj[i].roomState == _vm->_screenStates[*_vm->_screen_p]))) { + Utils::Box(BOX_ANY, "%s", _vm->_file->fetchString(obj[i].commentIndex)); + _vm->_scheduler->processBonus(obj[i].bonusIndex); // If this is LOOK (without a noun), show any takeable objects - if (*(_vm._arrayVerbs[obj[i].verbIndex]) == _vm._arrayVerbs[_vm._look][0]) - showTakeables(); + if (*(_vm->_arrayVerbs[obj[i].verbIndex]) == _vm->_arrayVerbs[_vm->_look][0]) + _vm->_object->showTakeables(); return true; } @@ -272,12 +273,12 @@ bool Parser_v1w::isBackgroundWord(objectList_t obj) { debugC(1, kDebugParser, "isBackgroundWord(object_list_t obj)"); for (int i = 0; obj[i].verbIndex != 0; i++) { - if (isWordPresent(_vm._arrayVerbs[obj[i].verbIndex]) && - isWordPresent(_vm._arrayNouns[obj[i].nounIndex]) && + if (isWordPresent(_vm->_arrayVerbs[obj[i].verbIndex]) && + isWordPresent(_vm->_arrayNouns[obj[i].nounIndex]) && ((obj[i].roomState == DONT_CARE) || - (obj[i].roomState == _vm._screenStates[*_vm._screen_p]))) { - Utils::Box(BOX_ANY, "%s", _vm.file().fetchString(obj[i].commentIndex)); - _vm.scheduler().processBonus(obj[i].bonusIndex); + (obj[i].roomState == _vm->_screenStates[*_vm->_screen_p]))) { + Utils::Box(BOX_ANY, "%s", _vm->_file->fetchString(obj[i].commentIndex)); + _vm->_scheduler->processBonus(obj[i].bonusIndex); return true; } } @@ -288,11 +289,11 @@ bool Parser_v1w::isBackgroundWord(objectList_t obj) { void Parser_v1w::lineHandler() { debugC(1, kDebugParser, "lineHandler()"); - status_t &gameStatus = _vm.getGameStatus(); + status_t &gameStatus = _vm->getGameStatus(); // Toggle God Mode if (!strncmp(_line, "PPG", 3)) { - _vm.sound().playSound(!_vm._soundTest, BOTH_CHANNELS, HIGH_PRI); + _vm->_sound->playSound(!_vm->_soundTest, BOTH_CHANNELS, HIGH_PRI); gameStatus.godModeFl ^= 1; return; } @@ -307,9 +308,9 @@ void Parser_v1w::lineHandler() { if (gameStatus.godModeFl) { // Special code to allow me to go straight to any screen if (strstr(_line, "goto")) { - for (int i = 0; i < _vm._numScreens; i++) { - if (!strcmp(&_line[strlen("goto") + 1], _vm._screenNames[i])) { - _vm.scheduler().newScreen(i); + for (int i = 0; i < _vm->_numScreens; i++) { + if (!strcmp(&_line[strlen("goto") + 1], _vm->_screenNames[i])) { + _vm->_scheduler->newScreen(i); return; } } @@ -317,17 +318,17 @@ void Parser_v1w::lineHandler() { // Special code to allow me to get objects from anywhere if (strstr(_line, "fetch all")) { - for (int i = 0; i < _vm._numObj; i++) { - if (_vm._objects[i].genericCmd & TAKE) - takeObject(&_vm._objects[i]); + for (int i = 0; i < _vm->_numObj; i++) { + if (_vm->_object->_objects[i].genericCmd & TAKE) + takeObject(&_vm->_object->_objects[i]); } return; } if (strstr(_line, "fetch")) { - for (int i = 0; i < _vm._numObj; i++) { - if (!strcmp(&_line[strlen("fetch") + 1], _vm._arrayNouns[_vm._objects[i].nounIndex][0])) { - takeObject(&_vm._objects[i]); + for (int i = 0; i < _vm->_numObj; i++) { + if (!strcmp(&_line[strlen("fetch") + 1], _vm->_arrayNouns[_vm->_object->_objects[i].nounIndex][0])) { + takeObject(&_vm->_object->_objects[i]); return; } } @@ -335,9 +336,9 @@ void Parser_v1w::lineHandler() { // Special code to allow me to goto objects if (strstr(_line, "find")) { - for (int i = 0; i < _vm._numObj; i++) { - if (!strcmp(&_line[strlen("find") + 1], _vm._arrayNouns[_vm._objects[i].nounIndex][0])) { - _vm.scheduler().newScreen(_vm._objects[i].screenIndex); + for (int i = 0; i < _vm->_numObj; i++) { + if (!strcmp(&_line[strlen("find") + 1], _vm->_arrayNouns[_vm->_object->_objects[i].nounIndex][0])) { + _vm->_scheduler->newScreen(_vm->_object->_objects[i].screenIndex); return; } } @@ -347,19 +348,19 @@ void Parser_v1w::lineHandler() { // Special meta commands // EXIT/QUIT if (!strcmp("exit", _line) || strstr(_line, "quit")) { - Utils::Box(BOX_ANY, "%s", _vm._textParser[kTBExit]); + Utils::Box(BOX_ANY, "%s", _vm->_textParser[kTBExit]); return; } // SAVE/RESTORE if (!strcmp("save", _line) && gameStatus.viewState == V_PLAY) { - _vm.file().saveGame(gameStatus.saveSlot, "Current game"); + _vm->_file->saveGame(gameStatus.saveSlot, "Current game"); return; } if (!strcmp("restore", _line) && (gameStatus.viewState == V_PLAY || gameStatus.viewState == V_IDLE)) { - _vm.file().restoreGame(gameStatus.saveSlot); - _vm.scheduler().restoreScreen(*_vm._screen_p); + _vm->_file->restoreGame(gameStatus.saveSlot); + _vm->_scheduler->restoreScreen(*_vm->_screen_p); gameStatus.viewState = V_PLAY; return; } @@ -379,9 +380,9 @@ void Parser_v1w::lineHandler() { char farComment[XBYTES * 5] = ""; // hold 5 line comment if object not nearby // Test for nearby objects referenced explicitly - for (int i = 0; i < _vm._numObj; i++) { - object_t *obj = &_vm._objects[i]; - if (isWordPresent(_vm._arrayNouns[obj->nounIndex])) { + for (int i = 0; i < _vm->_numObj; i++) { + object_t *obj = &_vm->_object->_objects[i]; + if (isWordPresent(_vm->_arrayNouns[obj->nounIndex])) { if (isObjectVerb(obj, farComment) || isGenericVerb(obj, farComment)) return; } @@ -389,8 +390,8 @@ void Parser_v1w::lineHandler() { // Test for nearby objects that only require a verb // Note comment is unused if not near. - for (int i = 0; i < _vm._numObj; i++) { - object_t *obj = &_vm._objects[i]; + for (int i = 0; i < _vm->_numObj; i++) { + object_t *obj = &_vm->_object->_objects[i]; if (obj->verbOnlyFl) { char contextComment[XBYTES * 5] = ""; // Unused comment for context objects if (isObjectVerb(obj, contextComment) || isGenericVerb(obj, contextComment)) @@ -399,13 +400,13 @@ void Parser_v1w::lineHandler() { } // No objects match command line, try background and catchall commands - if (isBackgroundWord(_vm._backgroundObjects[*_vm._screen_p])) + if (isBackgroundWord(_vm->_backgroundObjects[*_vm->_screen_p])) return; - if (isCatchallVerb(_vm._backgroundObjects[*_vm._screen_p])) + if (isCatchallVerb(_vm->_backgroundObjects[*_vm->_screen_p])) return; - if (isBackgroundWord(_vm._catchallList)) + if (isBackgroundWord(_vm->_catchallList)) return; - if (isCatchallVerb(_vm._catchallList)) + if (isCatchallVerb(_vm->_catchallList)) return; // If a not-near comment was generated, print it @@ -417,17 +418,17 @@ void Parser_v1w::lineHandler() { // Nothing matches. Report recognition success to user. char *verb = findVerb(); char *noun = findNoun(); - if (verb == _vm._arrayVerbs[_vm._look][0] && _maze.enabledFl) { - Utils::Box(BOX_ANY, "%s", _vm._textParser[kTBMaze]); - showTakeables(); + if (verb == _vm->_arrayVerbs[_vm->_look][0] && _maze.enabledFl) { + Utils::Box(BOX_ANY, "%s", _vm->_textParser[kTBMaze]); + _vm->_object->showTakeables(); } else if (verb && noun) { // A combination I didn't think of - Utils::Box(BOX_ANY, "%s", _vm._textParser[kTBNoPoint]); + Utils::Box(BOX_ANY, "%s", _vm->_textParser[kTBNoPoint]); } else if (noun) { - Utils::Box(BOX_ANY, "%s", _vm._textParser[kTBNoun]); + Utils::Box(BOX_ANY, "%s", _vm->_textParser[kTBNoun]); } else if (verb) { - Utils::Box(BOX_ANY, "%s", _vm._textParser[kTBVerb]); + Utils::Box(BOX_ANY, "%s", _vm->_textParser[kTBVerb]); } else { - Utils::Box(BOX_ANY, "%s", _vm._textParser[kTBEh]); + Utils::Box(BOX_ANY, "%s", _vm->_textParser[kTBEh]); } } diff --git a/engines/hugo/parser_v2d.cpp b/engines/hugo/parser_v2d.cpp index adaf5e9f9f..99fcf63a4e 100644 --- a/engines/hugo/parser_v2d.cpp +++ b/engines/hugo/parser_v2d.cpp @@ -37,10 +37,11 @@ #include "hugo/hugo.h" #include "hugo/parser.h" #include "hugo/util.h" +#include "hugo/object.h" namespace Hugo { -Parser_v2d::Parser_v2d(HugoEngine &vm) : Parser_v1d(vm) { +Parser_v2d::Parser_v2d(HugoEngine *vm) : Parser_v1d(vm) { } Parser_v2d::~Parser_v2d() { @@ -51,15 +52,15 @@ void Parser_v2d::lineHandler() { debugC(1, kDebugParser, "lineHandler()"); object_t *obj; - status_t &gameStatus = _vm.getGameStatus(); + status_t &gameStatus = _vm->getGameStatus(); char farComment[XBYTES * 5] = ""; // hold 5 line comment if object not nearby // Reset_prompt_line (); Utils::strlwr(_line); // Convert to lower case if (!strcmp("exit", _line) || strstr(_line, "quit")) { - if (Utils::Box(BOX_YESNO, "%s", _vm._textParser[kTBExit_1d]) != 0) - _vm.endGame(); + if (Utils::Box(BOX_YESNO, "%s", _vm->_textParser[kTBExit_1d]) != 0) + _vm->endGame(); else return; } @@ -70,14 +71,14 @@ void Parser_v2d::lineHandler() { if (gameStatus.gameOverFl) Utils::gameOverMsg(); else -// _vm.file().saveOrRestore(true); +// _vm->_file->saveOrRestore(true); warning("STUB: saveOrRestore()"); return; } if (!strcmp("restore", _line)) { _config.soundFl = false; -// _vm.file().saveOrRestore(false); +// _vm->_file->saveOrRestore(false); warning("STUB: saveOrRestore()"); return; } @@ -101,35 +102,35 @@ void Parser_v2d::lineHandler() { do { noun = findNextNoun(noun); // Find a noun in the line // Must try at least once for objects allowing verb-context - for (int i = 0; i < _vm._numObj; i++) { - obj = &_vm._objects[i]; + for (int i = 0; i < _vm->_numObj; i++) { + obj = &_vm->_object->_objects[i]; if (isNear(verb, noun, obj, farComment)) { if (isObjectVerb(verb, obj) // Foreground object || isGenericVerb(verb, obj)) // Common action type return; } } - if ((*farComment != '\0') && isBackgroundWord(noun, verb, _vm._backgroundObjects[*_vm._screen_p])) + if ((*farComment != '\0') && isBackgroundWord(noun, verb, _vm->_backgroundObjects[*_vm->_screen_p])) return; } while (noun); } noun = findNextNoun(noun); - if ( !isCatchallVerb(true, noun, verb, _vm._backgroundObjects[*_vm._screen_p]) - && !isCatchallVerb(true, noun, verb, _vm._catchallList) - && !isCatchallVerb(false, noun, verb, _vm._backgroundObjects[*_vm._screen_p]) - && !isCatchallVerb(false, noun, verb, _vm._catchallList)) { + if ( !isCatchallVerb(true, noun, verb, _vm->_backgroundObjects[*_vm->_screen_p]) + && !isCatchallVerb(true, noun, verb, _vm->_catchallList) + && !isCatchallVerb(false, noun, verb, _vm->_backgroundObjects[*_vm->_screen_p]) + && !isCatchallVerb(false, noun, verb, _vm->_catchallList)) { if (*farComment != '\0') { // An object matched but not near enough Utils::Box(BOX_ANY, "%s", farComment); - } else if (_maze.enabledFl && (verb == _vm._arrayVerbs[_vm._look][0])) { - Utils::Box(BOX_ANY, "%s", _vm._textParser[kTBMaze]); - showTakeables(); + } else if (_maze.enabledFl && (verb == _vm->_arrayVerbs[_vm->_look][0])) { + Utils::Box(BOX_ANY, "%s", _vm->_textParser[kTBMaze]); + _vm->_object->showTakeables(); } else if (verb && noun) { // A combination I didn't think of - Utils::Box(BOX_ANY, "%s", _vm._textParser[kTBNoUse_2d]); + Utils::Box(BOX_ANY, "%s", _vm->_textParser[kTBNoUse_2d]); } else if (verb || noun) { - Utils::Box(BOX_ANY, "%s", _vm._textParser[kTBNoun]); + Utils::Box(BOX_ANY, "%s", _vm->_textParser[kTBNoun]); } else { - Utils::Box(BOX_ANY, "%s", _vm._textParser[kTBEh_2d]); + Utils::Box(BOX_ANY, "%s", _vm->_textParser[kTBEh_2d]); } } } diff --git a/engines/hugo/parser_v3d.cpp b/engines/hugo/parser_v3d.cpp index 501d8fba20..e7cc387161 100644 --- a/engines/hugo/parser_v3d.cpp +++ b/engines/hugo/parser_v3d.cpp @@ -39,10 +39,11 @@ #include "hugo/schedule.h" #include "hugo/util.h" #include "hugo/sound.h" +#include "hugo/object.h" namespace Hugo { -Parser_v3d::Parser_v3d(HugoEngine &vm) : Parser_v1w(vm) { +Parser_v3d::Parser_v3d(HugoEngine *vm) : Parser_v1w(vm) { } Parser_v3d::~Parser_v3d() { @@ -52,11 +53,11 @@ Parser_v3d::~Parser_v3d() { void Parser_v3d::lineHandler() { debugC(1, kDebugParser, "lineHandler()"); - status_t &gameStatus = _vm.getGameStatus(); + status_t &gameStatus = _vm->getGameStatus(); // Toggle God Mode if (!strncmp(_line, "PPG", 3)) { - _vm.sound().playSound(!_vm._soundTest, BOTH_CHANNELS, HIGH_PRI); + _vm->_sound->playSound(!_vm->_soundTest, BOTH_CHANNELS, HIGH_PRI); gameStatus.godModeFl ^= 1; return; } @@ -71,9 +72,9 @@ void Parser_v3d::lineHandler() { if (gameStatus.godModeFl) { // Special code to allow me to go straight to any screen if (strstr(_line, "goto")) { - for (int i = 0; i < _vm._numScreens; i++) { - if (!strcmp(&_line[strlen("goto") + 1], _vm._screenNames[i])) { - _vm.scheduler().newScreen(i); + for (int i = 0; i < _vm->_numScreens; i++) { + if (!strcmp(&_line[strlen("goto") + 1], _vm->_screenNames[i])) { + _vm->_scheduler->newScreen(i); return; } } @@ -81,17 +82,17 @@ void Parser_v3d::lineHandler() { // Special code to allow me to get objects from anywhere if (strstr(_line, "fetch all")) { - for (int i = 0; i < _vm._numObj; i++) { - if (_vm._objects[i].genericCmd & TAKE) - takeObject(&_vm._objects[i]); + for (int i = 0; i < _vm->_numObj; i++) { + if (_vm->_object->_objects[i].genericCmd & TAKE) + takeObject(&_vm->_object->_objects[i]); } return; } if (strstr(_line, "fetch")) { - for (int i = 0; i < _vm._numObj; i++) { - if (!strcmp(&_line[strlen("fetch") + 1], _vm._arrayNouns[_vm._objects[i].nounIndex][0])) { - takeObject(&_vm._objects[i]); + for (int i = 0; i < _vm->_numObj; i++) { + if (!strcmp(&_line[strlen("fetch") + 1], _vm->_arrayNouns[_vm->_object->_objects[i].nounIndex][0])) { + takeObject(&_vm->_object->_objects[i]); return; } } @@ -99,9 +100,9 @@ void Parser_v3d::lineHandler() { // Special code to allow me to goto objects if (strstr(_line, "find")) { - for (int i = 0; i < _vm._numObj; i++) { - if (!strcmp(&_line[strlen("find") + 1], _vm._arrayNouns[_vm._objects[i].nounIndex][0])) { - _vm.scheduler().newScreen(_vm._objects[i].screenIndex); + for (int i = 0; i < _vm->_numObj; i++) { + if (!strcmp(&_line[strlen("find") + 1], _vm->_arrayNouns[_vm->_object->_objects[i].nounIndex][0])) { + _vm->_scheduler->newScreen(_vm->_object->_objects[i].screenIndex); return; } } @@ -111,8 +112,8 @@ void Parser_v3d::lineHandler() { // Special meta commands // EXIT/QUIT if (!strcmp("exit", _line) || strstr(_line, "quit")) { - if (Utils::Box(BOX_YESNO, "%s", _vm._textParser[kTBExit_1d]) != 0) - _vm.endGame(); + if (Utils::Box(BOX_YESNO, "%s", _vm->_textParser[kTBExit_1d]) != 0) + _vm->endGame(); else return; } @@ -123,14 +124,14 @@ void Parser_v3d::lineHandler() { if (gameStatus.gameOverFl) Utils::gameOverMsg(); else -// _vm.file().saveOrRestore(true); +// _vm->_file->saveOrRestore(true); warning("STUB: saveOrRestore()"); return; } if (!strcmp("restore", _line)) { _config.soundFl = false; -// _vm.file().saveOrRestore(false); +// _vm->_file->saveOrRestore(false); warning("STUB: saveOrRestore()"); return; } @@ -150,9 +151,9 @@ void Parser_v3d::lineHandler() { char farComment[XBYTES * 5] = ""; // hold 5 line comment if object not nearby // Test for nearby objects referenced explicitly - for (int i = 0; i < _vm._numObj; i++) { - object_t *obj = &_vm._objects[i]; - if (isWordPresent(_vm._arrayNouns[obj->nounIndex])) { + for (int i = 0; i < _vm->_numObj; i++) { + object_t *obj = &_vm->_object->_objects[i]; + if (isWordPresent(_vm->_arrayNouns[obj->nounIndex])) { if (isObjectVerb(obj, farComment) || isGenericVerb(obj, farComment)) return; } @@ -160,8 +161,8 @@ void Parser_v3d::lineHandler() { // Test for nearby objects that only require a verb // Note comment is unused if not near. - for (int i = 0; i < _vm._numObj; i++) { - object_t *obj = &_vm._objects[i]; + for (int i = 0; i < _vm->_numObj; i++) { + object_t *obj = &_vm->_object->_objects[i]; if (obj->verbOnlyFl) { char contextComment[XBYTES * 5] = ""; // Unused comment for context objects if (isObjectVerb(obj, contextComment) || isGenericVerb(obj, contextComment)) @@ -170,13 +171,13 @@ void Parser_v3d::lineHandler() { } // No objects match command line, try background and catchall commands - if (isBackgroundWord(_vm._backgroundObjects[*_vm._screen_p])) + if (isBackgroundWord(_vm->_backgroundObjects[*_vm->_screen_p])) return; - if (isCatchallVerb(_vm._backgroundObjects[*_vm._screen_p])) + if (isCatchallVerb(_vm->_backgroundObjects[*_vm->_screen_p])) return; - if (isBackgroundWord(_vm._catchallList)) + if (isBackgroundWord(_vm->_catchallList)) return; - if (isCatchallVerb(_vm._catchallList)) + if (isCatchallVerb(_vm->_catchallList)) return; // If a not-near comment was generated, print it @@ -190,13 +191,13 @@ void Parser_v3d::lineHandler() { char *noun = findNoun(); if (verb && noun) { // A combination I didn't think of - Utils::Box(BOX_ANY, "%s", _vm._textParser[kTBNoPoint]); + Utils::Box(BOX_ANY, "%s", _vm->_textParser[kTBNoPoint]); } else if (noun) { - Utils::Box(BOX_ANY, "%s", _vm._textParser[kTBNoun]); + Utils::Box(BOX_ANY, "%s", _vm->_textParser[kTBNoun]); } else if (verb) { - Utils::Box(BOX_ANY, "%s", _vm._textParser[kTBVerb]); + Utils::Box(BOX_ANY, "%s", _vm->_textParser[kTBVerb]); } else { - Utils::Box(BOX_ANY, "%s", _vm._textParser[kTBEh]); + Utils::Box(BOX_ANY, "%s", _vm->_textParser[kTBEh]); } } diff --git a/engines/hugo/route.cpp b/engines/hugo/route.cpp index 2ba95fb7d7..2b372947cf 100644 --- a/engines/hugo/route.cpp +++ b/engines/hugo/route.cpp @@ -38,16 +38,17 @@ #include "hugo/game.h" #include "hugo/route.h" #include "hugo/global.h" +#include "hugo/object.h" namespace Hugo { -Route::Route(HugoEngine &vm) : _vm(vm) { +Route::Route(HugoEngine *vm) : _vm(vm) { } // Face hero in new direction, based on cursor key input by user. void Route::setDirection(uint16 keyCode) { debugC(1, kDebugRoute, "setDirection(%d)", keyCode); - object_t *obj = _vm._hero; // Pointer to hero object + object_t *obj = _vm->_hero; // Pointer to hero object // Set first image in sequence switch (keyCode) { @@ -84,9 +85,9 @@ void Route::setWalk(uint16 direction) { debugC(1, kDebugRoute, "setWalk(%d)", direction); static uint16 oldDirection = 0; // Last direction char - object_t *obj = _vm._hero; // Pointer to hero object + object_t *obj = _vm->_hero; // Pointer to hero object - if (_vm.getGameStatus().storyModeFl || obj->pathType != USER) // Make sure user has control + if (_vm->getGameStatus().storyModeFl || obj->pathType != USER) // Make sure user has control return; if (!obj->vx && !obj->vy) @@ -195,7 +196,7 @@ void Route::segment(int16 x, int16 y) { if (y <= 0 || y >= YPIX - 1) return; - if (_vm._hero->x < x1) { + if (_vm->_hero->x < x1) { // Hero x not in segment, search x1..x2 // Find all segments above current for (x = x1; !(_routeFoundFl | _fullStackFl | _fullSegmentFl) && x <= x2; x++) { @@ -208,7 +209,7 @@ void Route::segment(int16 x, int16 y) { if (_boundaryMap[y + 1][x] == 0) segment(x, y + 1); } - } else if (_vm._hero->x + HERO_MAX_WIDTH > x2) { + } else if (_vm->_hero->x + HERO_MAX_WIDTH > x2) { // Hero x not in segment, search x1..x2 // Find all segments above current for (x = x2; !(_routeFoundFl | _fullStackFl | _fullSegmentFl) && x >= x1; x--) { @@ -224,22 +225,22 @@ void Route::segment(int16 x, int16 y) { } else { // Organize search around hero x position - this gives // better chance for more direct route. - for (x = _vm._hero->x; !(_routeFoundFl | _fullStackFl | _fullSegmentFl) && x <= x2; x++) { + for (x = _vm->_hero->x; !(_routeFoundFl | _fullStackFl | _fullSegmentFl) && x <= x2; x++) { if (_boundaryMap[y - 1][x] == 0) segment(x, y - 1); } - for (x = x1; !(_routeFoundFl | _fullStackFl | _fullSegmentFl) && x < _vm._hero->x; x++) { + for (x = x1; !(_routeFoundFl | _fullStackFl | _fullSegmentFl) && x < _vm->_hero->x; x++) { if (_boundaryMap[y - 1][x] == 0) segment(x, y - 1); } - for (x = _vm._hero->x; !(_routeFoundFl | _fullStackFl | _fullSegmentFl) && x <= x2; x++) { + for (x = _vm->_hero->x; !(_routeFoundFl | _fullStackFl | _fullSegmentFl) && x <= x2; x++) { if (_boundaryMap[y + 1][x] == 0) segment(x, y + 1); } - for (x = x1; !(_routeFoundFl | _fullStackFl | _fullSegmentFl) && x < _vm._hero->x; x++) { + for (x = x1; !(_routeFoundFl | _fullStackFl | _fullSegmentFl) && x < _vm->_hero->x; x++) { if (_boundaryMap[y + 1][x] == 0) segment(x, y + 1); } @@ -289,30 +290,30 @@ bool Route::findRoute(int16 cx, int16 cy) { _destY = cy; // Destination coords _destX = cx; // Destination coords - int16 herox1 = _vm._hero->x + _vm._hero->currImagePtr->x1; // Hero baseline - int16 herox2 = _vm._hero->x + _vm._hero->currImagePtr->x2; // Hero baseline - int16 heroy = _vm._hero->y + _vm._hero->currImagePtr->y2; // Hero baseline + int16 herox1 = _vm->_hero->x + _vm->_hero->currImagePtr->x1; // Hero baseline + int16 herox2 = _vm->_hero->x + _vm->_hero->currImagePtr->x2; // Hero baseline + int16 heroy = _vm->_hero->y + _vm->_hero->currImagePtr->y2; // Hero baseline // Store all object baselines into objbound (except hero's = [0]) object_t *obj; // Ptr to object int i; - for (i = 1, obj = &_vm._objects[i]; i < _vm._numObj; i++, obj++) { - if ((obj->screenIndex == *_vm._screen_p) && (obj->cycling != INVISIBLE) && (obj->priority == FLOATING)) - _vm.storeBoundary(obj->oldx + obj->currImagePtr->x1, obj->oldx + obj->currImagePtr->x2, obj->oldy + obj->currImagePtr->y2); + for (i = 1, obj = &_vm->_object->_objects[i]; i < _vm->_numObj; i++, obj++) { + if ((obj->screenIndex == *_vm->_screen_p) && (obj->cycling != INVISIBLE) && (obj->priority == FLOATING)) + _vm->storeBoundary(obj->oldx + obj->currImagePtr->x1, obj->oldx + obj->currImagePtr->x2, obj->oldy + obj->currImagePtr->y2); } // Combine objbound and boundary bitmaps to local byte map for (int16 y = 0; y < YPIX; y++) { for (int16 x = 0; x < XBYTES; x++) { for (i = 0; i < 8; i++) - _boundaryMap[y][x * 8 + i] = ((_vm.getObjectBoundaryOverlay()[y * XBYTES + x] | _vm.getBoundaryOverlay()[y * XBYTES + x]) & (0x80 >> i)) ? kMapBound : 0; + _boundaryMap[y][x * 8 + i] = ((_vm->getObjectBoundaryOverlay()[y * XBYTES + x] | _vm->getBoundaryOverlay()[y * XBYTES + x]) & (0x80 >> i)) ? kMapBound : 0; } } // Clear all object baselines from objbound - for (i = 0, obj = _vm._objects; i < _vm._numObj; i++, obj++) { - if ((obj->screenIndex == *_vm._screen_p) && (obj->cycling != INVISIBLE) && (obj->priority == FLOATING)) - _vm.clearBoundary(obj->oldx + obj->currImagePtr->x1, obj->oldx + obj->currImagePtr->x2, obj->oldy + obj->currImagePtr->y2); + for (i = 0, obj = _vm->_object->_objects; i < _vm->_numObj; i++, obj++) { + if ((obj->screenIndex == *_vm->_screen_p) && (obj->cycling != INVISIBLE) && (obj->priority == FLOATING)) + _vm->clearBoundary(obj->oldx + obj->currImagePtr->x1, obj->oldx + obj->currImagePtr->x2, obj->oldy + obj->currImagePtr->y2); } // Search from hero to destination @@ -389,43 +390,43 @@ void Route::processRoute() { static bool turnedFl = false; // Used to get extra cylce for turning // Current hero position - int16 herox = _vm._hero->x + _vm._hero->currImagePtr->x1; - int16 heroy = _vm._hero->y + _vm._hero->currImagePtr->y2; - status_t &gameStatus = _vm.getGameStatus(); + int16 herox = _vm->_hero->x + _vm->_hero->currImagePtr->x1; + int16 heroy = _vm->_hero->y + _vm->_hero->currImagePtr->y2; + status_t &gameStatus = _vm->getGameStatus(); Point *routeNode = &_route[gameStatus.routeIndex]; // Arrived at node? if (abs(herox - routeNode->x) < DX + 1 && abs(heroy - routeNode->y) < DY) { // DX too low // Close enough - position hero exactly - _vm._hero->x = _vm._hero->oldx = routeNode->x - _vm._hero->currImagePtr->x1; - _vm._hero->y = _vm._hero->oldy = routeNode->y - _vm._hero->currImagePtr->y2; - _vm._hero->vx = _vm._hero->vy = 0; - _vm._hero->cycling = NOT_CYCLING; + _vm->_hero->x = _vm->_hero->oldx = routeNode->x - _vm->_hero->currImagePtr->x1; + _vm->_hero->y = _vm->_hero->oldy = routeNode->y - _vm->_hero->currImagePtr->y2; + _vm->_hero->vx = _vm->_hero->vy = 0; + _vm->_hero->cycling = NOT_CYCLING; // Arrived at final node? if (--gameStatus.routeIndex < 0) { // See why we walked here switch (gameStatus.go_for) { case GO_EXIT: // Walked to an exit, proceed into it - setWalk(_vm._hotspots[gameStatus.go_id].direction); + setWalk(_vm->_hotspots[gameStatus.go_id].direction); break; case GO_LOOK: // Look at an object if (turnedFl) { - _vm.lookObject(&_vm._objects[gameStatus.go_id]); + _vm->_object->lookObject(&_vm->_object->_objects[gameStatus.go_id]); turnedFl = false; } else { - setDirection(_vm._objects[gameStatus.go_id].direction); + setDirection(_vm->_object->_objects[gameStatus.go_id].direction); gameStatus.routeIndex++; // Come round again turnedFl = true; } break; case GO_GET: // Get (or use) an object if (turnedFl) { - _vm.useObject(gameStatus.go_id); + _vm->_object->useObject(gameStatus.go_id); turnedFl = false; } else { - setDirection(_vm._objects[gameStatus.go_id].direction); + setDirection(_vm->_object->_objects[gameStatus.go_id].direction); gameStatus.routeIndex++; // Come round again turnedFl = true; } @@ -435,7 +436,7 @@ void Route::processRoute() { break; } } - } else if (_vm._hero->vx == 0 && _vm._hero->vy == 0) { + } else if (_vm->_hero->vx == 0 && _vm->_hero->vy == 0) { // Set direction of travel if at a node // Note realignment when changing to (thinner) up/down sprite, // otherwise hero could bump into boundaries along route. @@ -445,10 +446,10 @@ void Route::processRoute() { setWalk(Common::KEYCODE_LEFT); } else if (heroy < routeNode->y) { setWalk(Common::KEYCODE_DOWN); - _vm._hero->x = _vm._hero->oldx = routeNode->x - _vm._hero->currImagePtr->x1; + _vm->_hero->x = _vm->_hero->oldx = routeNode->x - _vm->_hero->currImagePtr->x1; } else if (heroy > routeNode->y) { setWalk(Common::KEYCODE_UP); - _vm._hero->x = _vm._hero->oldx = routeNode->x - _vm._hero->currImagePtr->x1; + _vm->_hero->x = _vm->_hero->oldx = routeNode->x - _vm->_hero->currImagePtr->x1; } } } @@ -460,10 +461,10 @@ bool Route::startRoute(go_t go_for, int16 id, int16 cx, int16 cy) { debugC(1, kDebugRoute, "startRoute(%d, %d, %d, %d)", go_for, id, cx, cy); // Don't attempt to walk if user does not have control - if (_vm._hero->pathType != USER) + if (_vm->_hero->pathType != USER) return false; - status_t &gameStatus = _vm.getGameStatus(); + status_t &gameStatus = _vm->getGameStatus(); // if inventory showing, make it go away if (gameStatus.inventoryState != I_OFF) gameStatus.inventoryState = I_UP; @@ -478,7 +479,7 @@ bool Route::startRoute(go_t go_for, int16 id, int16 cx, int16 cy) { bool foundFl = false; // TRUE if route found ok if ((foundFl = findRoute(cx, cy))) { // Found a route? gameStatus.routeIndex = _routeListIndex; // Node index - _vm._hero->vx = _vm._hero->vy = 0; // Stop manual motion + _vm->_hero->vx = _vm->_hero->vy = 0; // Stop manual motion } return foundFl; diff --git a/engines/hugo/route.h b/engines/hugo/route.h index 09b4575fcd..b2185a4bb7 100644 --- a/engines/hugo/route.h +++ b/engines/hugo/route.h @@ -53,7 +53,7 @@ struct segment_t { // Search segment class Route { public: - Route(HugoEngine &vm); + Route(HugoEngine *vm); void processRoute(); bool startRoute(go_t go_for, short id, short cx, short cy); @@ -61,7 +61,7 @@ public: void setWalk(uint16 direction); private: - HugoEngine &_vm; + HugoEngine *_vm; byte _boundaryMap[YPIX][XPIX]; // Boundary byte map segment_t _segment[kMaxSeg]; // List of points in fill-path diff --git a/engines/hugo/schedule.cpp b/engines/hugo/schedule.cpp index 6c98cecdff..629b39f339 100644 --- a/engines/hugo/schedule.cpp +++ b/engines/hugo/schedule.cpp @@ -43,12 +43,13 @@ #include "hugo/parser.h" #include "hugo/util.h" #include "hugo/sound.h" +#include "hugo/object.h" namespace Hugo { #define SIGN(X) ((X < 0) ? -1 : 1) -Scheduler::Scheduler(HugoEngine &vm) : _vm(vm) { +Scheduler::Scheduler(HugoEngine *vm) : _vm(vm) { } Scheduler::~Scheduler() { @@ -169,9 +170,9 @@ void Scheduler::insertActionList(uint16 actIndex) { // Call Insert_action for each action in the list supplied debugC(1, kDebugSchedule, "insertActionList(%d)", actIndex); - if (_vm._actListArr[actIndex]) { - for (int i = 0; _vm._actListArr[actIndex][i].a0.actType != ANULL; i++) - insertAction(&_vm._actListArr[actIndex][i]); + if (_vm->_actListArr[actIndex]) { + for (int i = 0; _vm->_actListArr[actIndex][i].a0.actType != ANULL; i++) + insertAction(&_vm->_actListArr[actIndex][i]); } } @@ -192,7 +193,7 @@ event_t *Scheduler::doAction(event_t *curEvent) { // to the next action in the list, except special case of NEW_SCREEN debugC(1, kDebugSchedule, "doAction - Event action type : %d", curEvent->action->a0.actType); - status_t &gameStatus = _vm.getGameStatus(); + status_t &gameStatus = _vm->getGameStatus(); act *action = curEvent->action; char *response; // User's response string object_t *obj1; @@ -208,16 +209,16 @@ event_t *Scheduler::doAction(event_t *curEvent) { insertActionList(action->a0.actIndex); break; case START_OBJ: // act1: Start an object cycling - _vm._objects[action->a1.objNumb].cycleNumb = action->a1.cycleNumb; - _vm._objects[action->a1.objNumb].cycling = action->a1.cycle; + _vm->_object->_objects[action->a1.objNumb].cycleNumb = action->a1.cycleNumb; + _vm->_object->_objects[action->a1.objNumb].cycling = action->a1.cycle; break; case INIT_OBJXY: // act2: Initialise an object - _vm._objects[action->a2.objNumb].x = action->a2.x; // Coordinates - _vm._objects[action->a2.objNumb].y = action->a2.y; + _vm->_object->_objects[action->a2.objNumb].x = action->a2.x; // Coordinates + _vm->_object->_objects[action->a2.objNumb].y = action->a2.y; break; case PROMPT: { // act3: Prompt user for key phrase // TODO : Add specific code for Hugo 1 DOS, which is handled differently, - response = Utils::Box(BOX_PROMPT, "%s", _vm.file().fetchString(action->a3.promptIndex)); + response = Utils::Box(BOX_PROMPT, "%s", _vm->_file->fetchString(action->a3.promptIndex)); warning("STUB: doAction(act3), expecting answer %s", response); @@ -227,7 +228,7 @@ event_t *Scheduler::doAction(event_t *curEvent) { char *tmpStr; // General purpose string ptr for (found = false, dx = 0; !found && (action->a3.responsePtr[dx] != -1); dx++) { - tmpStr = _vm.file().Fetch_string(action->a3.responsePtr[dx]); + tmpStr = _vm->_file->Fetch_string(action->a3.responsePtr[dx]); if (strstr(Utils::strlwr(response) , tmpStr)) found = true; } @@ -243,53 +244,50 @@ event_t *Scheduler::doAction(event_t *curEvent) { break; } case BKGD_COLOR: // act4: Set new background color - _vm.screen().setBackgroundColor(action->a4.newBackgroundColor); + _vm->_screen->setBackgroundColor(action->a4.newBackgroundColor); break; - case INIT_OBJVXY: // act5: Initialise an object - _vm._objects[action->a5.objNumb].vx = action->a5.vx; // velocities - _vm._objects[action->a5.objNumb].vy = action->a5.vy; + case INIT_OBJVXY: // act5: Initialise an object velocity + _vm->_object->setVelocity(action->a5.objNumb, action->a5.vx, action->a5.vy); break; case INIT_CARRY: // act6: Initialise an object - _vm._objects[action->a6.objNumb].carriedFl = action->a6.carriedFl; // carried status + _vm->_object->setCarry(action->a6.objNumb, action->a6.carriedFl); // carried status break; case INIT_HF_COORD: // act7: Initialise an object to hero's "feet" coords - _vm._objects[action->a7.objNumb].x = _vm._hero->x - 1; - _vm._objects[action->a7.objNumb].y = _vm._hero->y + _vm._hero->currImagePtr->y2 - 1; - _vm._objects[action->a7.objNumb].screenIndex = *_vm._screen_p; // Don't forget screen! + _vm->_object->_objects[action->a7.objNumb].x = _vm->_hero->x - 1; + _vm->_object->_objects[action->a7.objNumb].y = _vm->_hero->y + _vm->_hero->currImagePtr->y2 - 1; + _vm->_object->_objects[action->a7.objNumb].screenIndex = *_vm->_screen_p; // Don't forget screen! break; case NEW_SCREEN: // act8: Start new screen newScreen(action->a8.screenIndex); break; case INIT_OBJSTATE: // act9: Initialise an object state - _vm._objects[action->a9.objNumb].state = action->a9.newState; + _vm->_object->_objects[action->a9.objNumb].state = action->a9.newState; break; case INIT_PATH: // act10: Initialise an object path and velocity - _vm._objects[action->a10.objNumb].pathType = (path_t) action->a10.newPathType; - _vm._objects[action->a10.objNumb].vxPath = action->a10.vxPath; - _vm._objects[action->a10.objNumb].vyPath = action->a10.vyPath; + _vm->_object->setPath(action->a10.objNumb, (path_t) action->a10.newPathType, action->a10.vxPath, action->a10.vyPath); break; case COND_R: // act11: action lists conditional on object state - if (_vm._objects[action->a11.objNumb].state == action->a11.stateReq) + if (_vm->_object->_objects[action->a11.objNumb].state == action->a11.stateReq) insertActionList(action->a11.actPassIndex); else insertActionList(action->a11.actFailIndex); break; case TEXT: // act12: Text box (CF WARN) - Utils::Box(BOX_ANY, "%s", _vm.file().fetchString(action->a12.stringIndex)); // Fetch string from file + Utils::Box(BOX_ANY, "%s", _vm->_file->fetchString(action->a12.stringIndex)); // Fetch string from file break; case SWAP_IMAGES: // act13: Swap 2 object images - swapImages(action->a13.obj1, action->a13.obj2); + _vm->_object->swapImages(action->a13.obj1, action->a13.obj2); break; case COND_SCR: // act14: Conditional on current screen - if (_vm._objects[action->a14.objNumb].screenIndex == action->a14.screenReq) + if (_vm->_object->_objects[action->a14.objNumb].screenIndex == action->a14.screenReq) insertActionList(action->a14.actPassIndex); else insertActionList(action->a14.actFailIndex); break; case AUTOPILOT: // act15: Home in on a (stationary) object // object p1 will home in on object p2 - obj1 = &_vm._objects[action->a15.obj1]; - obj2 = &_vm._objects[action->a15.obj2]; + obj1 = &_vm->_object->_objects[action->a15.obj1]; + obj2 = &_vm->_object->_objects[action->a15.obj2]; obj1->pathType = AUTO; dx = obj1->x + obj1->currImagePtr->x1 - obj2->x - obj2->currImagePtr->x1; dy = obj1->y + obj1->currImagePtr->y1 - obj2->y - obj2->currImagePtr->y1; @@ -310,16 +308,16 @@ event_t *Scheduler::doAction(event_t *curEvent) { case INIT_OBJ_SEQ: // act16: Set sequence number to use // Note: Don't set a sequence at time 0 of a new screen, it causes // problems clearing the boundary bits of the object! t>0 is safe - _vm._objects[action->a16.objNumb].currImagePtr = _vm._objects[action->a16.objNumb].seqList[action->a16.seqIndex].seqPtr; + _vm->_object->_objects[action->a16.objNumb].currImagePtr = _vm->_object->_objects[action->a16.objNumb].seqList[action->a16.seqIndex].seqPtr; break; case SET_STATE_BITS: // act17: OR mask with curr obj state - _vm._objects[action->a17.objNumb].state |= action->a17.stateMask; + _vm->_object->_objects[action->a17.objNumb].state |= action->a17.stateMask; break; case CLEAR_STATE_BITS: // act18: AND ~mask with curr obj state - _vm._objects[action->a18.objNumb].state &= ~action->a18.stateMask; + _vm->_object->_objects[action->a18.objNumb].state &= ~action->a18.stateMask; break; case TEST_STATE_BITS: // act19: If all bits set, do apass else afail - if ((_vm._objects[action->a19.objNumb].state & action->a19.stateMask) == action->a19.stateMask) + if ((_vm->_object->_objects[action->a19.objNumb].state & action->a19.stateMask) == action->a19.stateMask) insertActionList(action->a19.actPassIndex); else insertActionList(action->a19.actFailIndex); @@ -340,18 +338,18 @@ event_t *Scheduler::doAction(event_t *curEvent) { gameStatus.gameOverFl = true; break; case INIT_HH_COORD: // act22: Initialise an object to hero's actual coords - _vm._objects[action->a22.objNumb].x = _vm._hero->x; - _vm._objects[action->a22.objNumb].y = _vm._hero->y; - _vm._objects[action->a22.objNumb].screenIndex = *_vm._screen_p;// Don't forget screen! + _vm->_object->_objects[action->a22.objNumb].x = _vm->_hero->x; + _vm->_object->_objects[action->a22.objNumb].y = _vm->_hero->y; + _vm->_object->_objects[action->a22.objNumb].screenIndex = *_vm->_screen_p;// Don't forget screen! break; case EXIT: // act23: Exit game back to DOS - _vm.endGame(); + _vm->endGame(); break; case BONUS: // act24: Get bonus score for action processBonus(action->a24.pointIndex); break; case COND_BOX: // act25: Conditional on bounding box - obj1 = &_vm._objects[action->a25.objNumb]; + obj1 = &_vm->_object->_objects[action->a25.objNumb]; dx = obj1->x + obj1->currImagePtr->x1; dy = obj1->y + obj1->currImagePtr->y2; if ((dx >= action->a25.x1) && (dx <= action->a25.x2) && @@ -361,19 +359,19 @@ event_t *Scheduler::doAction(event_t *curEvent) { insertActionList(action->a25.actFailIndex); break; case SOUND: // act26: Play a sound (or tune) - if (action->a26.soundIndex < _vm._tunesNbr) - _vm.sound().playMusic(action->a26.soundIndex); + if (action->a26.soundIndex < _vm->_tunesNbr) + _vm->_sound->playMusic(action->a26.soundIndex); else - _vm.sound().playSound(action->a26.soundIndex, BOTH_CHANNELS, MED_PRI); + _vm->_sound->playSound(action->a26.soundIndex, BOTH_CHANNELS, MED_PRI); break; case ADD_SCORE: // act27: Add object's value to score - _vm.adjustScore(_vm._objects[action->a27.objNumb].objValue); + _vm->adjustScore(_vm->_object->_objects[action->a27.objNumb].objValue); break; case SUB_SCORE: // act28: Subtract object's value from score - _vm.adjustScore(-_vm._objects[action->a28.objNumb].objValue); + _vm->adjustScore(-_vm->_object->_objects[action->a28.objNumb].objValue); break; case COND_CARRY: // act29: Conditional on object being carried - if (_vm._objects[action->a29.objNumb].carriedFl) + if (_vm->_object->isCarried(action->a29.objNumb)) insertActionList(action->a29.actPassIndex); else insertActionList(action->a29.actFailIndex); @@ -393,31 +391,31 @@ event_t *Scheduler::doAction(event_t *curEvent) { _maze.enabledFl = false; break; case INIT_PRIORITY: - _vm._objects[action->a32.objNumb].priority = action->a32.priority; + _vm->_object->_objects[action->a32.objNumb].priority = action->a32.priority; break; case INIT_SCREEN: - _vm._objects[action->a33.objNumb].screenIndex = action->a33.screenIndex; + _vm->_object->_objects[action->a33.objNumb].screenIndex = action->a33.screenIndex; break; case AGSCHEDULE: // act34: Schedule a (global) action list insertActionList(action->a34.actIndex); break; case REMAPPAL: // act35: Remap a palette color - _vm.screen().remapPal(action->a35.oldColorIndex, action->a35.newColorIndex); + _vm->_screen->remapPal(action->a35.oldColorIndex, action->a35.newColorIndex); break; case COND_NOUN: // act36: Conditional on noun mentioned - if (_vm.parser().isWordPresent(_vm._arrayNouns[action->a36.nounIndex])) + if (_vm->_parser->isWordPresent(_vm->_arrayNouns[action->a36.nounIndex])) insertActionList(action->a36.actPassIndex); else insertActionList(action->a36.actFailIndex); break; case SCREEN_STATE: // act37: Set new screen state - _vm._screenStates[action->a37.screenIndex] = action->a37.newState; + _vm->_screenStates[action->a37.screenIndex] = action->a37.newState; break; case INIT_LIPS: // act38: Position lips on object - _vm._objects[action->a38.lipsObjNumb].x = _vm._objects[action->a38.objNumb].x + action->a38.dxLips; - _vm._objects[action->a38.lipsObjNumb].y = _vm._objects[action->a38.objNumb].y + action->a38.dyLips; - _vm._objects[action->a38.lipsObjNumb].screenIndex = *_vm._screen_p; // Don't forget screen! - _vm._objects[action->a38.lipsObjNumb].cycling = CYCLE_FORWARD; + _vm->_object->_objects[action->a38.lipsObjNumb].x = _vm->_object->_objects[action->a38.objNumb].x + action->a38.dxLips; + _vm->_object->_objects[action->a38.lipsObjNumb].y = _vm->_object->_objects[action->a38.objNumb].y + action->a38.dyLips; + _vm->_object->_objects[action->a38.lipsObjNumb].screenIndex = *_vm->_screen_p; // Don't forget screen! + _vm->_object->_objects[action->a38.lipsObjNumb].cycling = CYCLE_FORWARD; break; case INIT_STORY_MODE: // act39: Init story_mode flag // This is similar to the QUIET path mode, except that it is @@ -426,23 +424,23 @@ event_t *Scheduler::doAction(event_t *curEvent) { // End the game after story if this is special vendor demo mode if (gameStatus.demoFl && action->a39.storyModeFl == false) - _vm.endGame(); + _vm->endGame(); break; case WARN: // act40: Text box (CF TEXT) - Utils::Box(BOX_OK, "%s", _vm.file().fetchString(action->a40.stringIndex)); + Utils::Box(BOX_OK, "%s", _vm->_file->fetchString(action->a40.stringIndex)); break; case COND_BONUS: // act41: Perform action if got bonus - if (_vm._points[action->a41.BonusIndex].scoredFl) + if (_vm->_points[action->a41.BonusIndex].scoredFl) insertActionList(action->a41.actPassIndex); else insertActionList(action->a41.actFailIndex); break; case TEXT_TAKE: // act42: Text box with "take" message - Utils::Box(BOX_ANY, TAKE_TEXT, _vm._arrayNouns[_vm._objects[action->a42.objNumb].nounIndex][TAKE_NAME]); + Utils::Box(BOX_ANY, TAKE_TEXT, _vm->_arrayNouns[_vm->_object->_objects[action->a42.objNumb].nounIndex][TAKE_NAME]); break; case YESNO: // act43: Prompt user for Yes or No warning("doAction(act43) - Yes/No Box"); - if (Utils::Box(BOX_YESNO, "%s", _vm.file().fetchString(action->a43.promptIndex)) != 0) + if (Utils::Box(BOX_YESNO, "%s", _vm->_file->fetchString(action->a43.promptIndex)) != 0) insertActionList(action->a43.actYesIndex); else insertActionList(action->a43.actNoIndex); @@ -463,16 +461,16 @@ event_t *Scheduler::doAction(event_t *curEvent) { gameStatus.jumpExitFl = action->a46.jumpExitFl; break; case INIT_VIEW: // act47: Init object.viewx, viewy, dir - _vm._objects[action->a47.objNumb].viewx = action->a47.viewx; - _vm._objects[action->a47.objNumb].viewy = action->a47.viewy; - _vm._objects[action->a47.objNumb].direction = action->a47.direction; + _vm->_object->_objects[action->a47.objNumb].viewx = action->a47.viewx; + _vm->_object->_objects[action->a47.objNumb].viewy = action->a47.viewy; + _vm->_object->_objects[action->a47.objNumb].direction = action->a47.direction; break; case INIT_OBJ_FRAME: // act48: Set seq,frame number to use // Note: Don't set a sequence at time 0 of a new screen, it causes // problems clearing the boundary bits of the object! t>0 is safe - _vm._objects[action->a48.objNumb].currImagePtr = _vm._objects[action->a48.objNumb].seqList[action->a48.seqIndex].seqPtr; + _vm->_object->_objects[action->a48.objNumb].currImagePtr = _vm->_object->_objects[action->a48.objNumb].seqList[action->a48.seqIndex].seqPtr; for (dx = 0; dx < action->a48.frameIndex; dx++) - _vm._objects[action->a48.objNumb].currImagePtr = _vm._objects[action->a48.objNumb].currImagePtr->nextSeqPtr; + _vm->_object->_objects[action->a48.objNumb].currImagePtr = _vm->_object->_objects[action->a48.objNumb].currImagePtr->nextSeqPtr; break; case OLD_SONG: //TODO For Hugo 1 and Hugo2 DOS: The songs were not stored in a DAT file, but directly as @@ -500,7 +498,7 @@ event_t *Scheduler::doAction(event_t *curEvent) { void Scheduler::runScheduler() { debugC(6, kDebugSchedule, "runScheduler"); - status_t &gameStatus = _vm.getGameStatus(); + status_t &gameStatus = _vm->getGameStatus(); event_t *curEvent = _headEvent; // The earliest event while (curEvent && curEvent->time <= gameStatus.tick) // While mature events found @@ -512,16 +510,16 @@ uint32 Scheduler::getTicks() { // Return system time in ticks. A tick is 1/TICKS_PER_SEC mS debugC(3, kDebugSchedule, "getTicks"); - return _vm.getGameStatus().tick; + return _vm->getGameStatus().tick; } void Scheduler::processBonus(int bonusIndex) { // Add indecated bonus to score if not added already debugC(1, kDebugSchedule, "processBonus(%d)", bonusIndex); - if (!_vm._points[bonusIndex].scoredFl) { - _vm.adjustScore(_vm._points[bonusIndex].score); - _vm._points[bonusIndex].scoredFl = true; + if (!_vm->_points[bonusIndex].scoredFl) { + _vm->adjustScore(_vm->_points[bonusIndex].score); + _vm->_points[bonusIndex].scoredFl = true; } } @@ -535,11 +533,11 @@ void Scheduler::newScreen(int screenIndex) { debugC(1, kDebugSchedule, "newScreen(%d)", screenIndex); // Make sure the background file exists! - if (!_vm.isPacked()) { + if (!_vm->isPacked()) { char line[32]; - if (!_vm.file().fileExists(strcat(strncat(strcpy(line, _vm._picDir), _vm._screenNames[screenIndex], NAME_LEN), BKGEXT)) && - !_vm.file().fileExists(strcat(strcpy(line, _vm._screenNames[screenIndex]), ".ART"))) { - Utils::Box(BOX_ANY, "%s", _vm._textSchedule[kSsNoBackground]); + if (!_vm->_file->fileExists(strcat(strncat(strcpy(line, _vm->_picDir), _vm->_screenNames[screenIndex], NAME_LEN), BKGEXT)) && + !_vm->_file->fileExists(strcat(strcpy(line, _vm->_screenNames[screenIndex]), ".ART"))) { + Utils::Box(BOX_ANY, "%s", _vm->_textSchedule[kSsNoBackground]); return; } } @@ -555,16 +553,16 @@ void Scheduler::newScreen(int screenIndex) { } // 2. Set the new screen in the hero object and any being carried - _vm.setNewScreen(screenIndex); + _vm->setNewScreen(screenIndex); // 3. Read in new screen files - _vm.readScreenFiles(screenIndex); + _vm->readScreenFiles(screenIndex); // 4. Schedule action list for this screen - _vm.screenActions(screenIndex); + _vm->screenActions(screenIndex); // 5. Initialise prompt line and status line - _vm.screen().initNewScreenDisplay(); + _vm->_screen->initNewScreenDisplay(); } // Write the event queue to the file with handle f @@ -642,35 +640,13 @@ void Scheduler::restoreScreen(int screenIndex) { debugC(1, kDebugSchedule, "restoreScreen(%d)", screenIndex); // 1. Set the new screen in the hero object and any being carried - _vm.setNewScreen(screenIndex); + _vm->setNewScreen(screenIndex); // 2. Read in new screen files - _vm.readScreenFiles(screenIndex); + _vm->readScreenFiles(screenIndex); // 3. Initialise prompt line and status line - _vm.screen().initNewScreenDisplay(); -} - -void Scheduler::swapImages(int objNumb1, int objNumb2) { -// Swap all the images of one object with another. Set hero_image (we make -// the assumption for now that the first obj is always the HERO) to the object -// number of the swapped image - debugC(1, kDebugSchedule, "swapImages(%d, %d)", objNumb1, objNumb2); - - _vm.file().saveSeq(&_vm._objects[objNumb1]); - - seqList_t tmpSeqList[MAX_SEQUENCES]; - int seqListSize = sizeof(seqList_t) * MAX_SEQUENCES; - - memcpy(tmpSeqList, _vm._objects[objNumb1].seqList, seqListSize); - memcpy(_vm._objects[objNumb1].seqList, _vm._objects[objNumb2].seqList, seqListSize); - memcpy(_vm._objects[objNumb2].seqList, tmpSeqList, seqListSize); - _vm.file().restoreSeq(&_vm._objects[objNumb1]); - _vm._objects[objNumb2].currImagePtr = _vm._objects[objNumb2].seqList[0].seqPtr; - _vm._heroImage = (_vm._heroImage == HERO) ? objNumb2 : HERO; - - // Make sure baseline stays constant - _vm._objects[objNumb1].y += _vm._objects[objNumb2].currImagePtr->y2 - _vm._objects[objNumb1].currImagePtr->y2; + _vm->_screen->initNewScreenDisplay(); } } // End of namespace Hugo diff --git a/engines/hugo/schedule.h b/engines/hugo/schedule.h index b77abd4302..39aa1504bb 100644 --- a/engines/hugo/schedule.h +++ b/engines/hugo/schedule.h @@ -47,7 +47,7 @@ struct event_t { class Scheduler { public: - Scheduler(HugoEngine &vm); + Scheduler(HugoEngine *vm); virtual ~Scheduler(); void initEventQueue(); @@ -61,7 +61,6 @@ public: void restoreEvents(Common::SeekableReadStream *f); void saveEvents(Common::WriteStream *f); void restoreScreen(int screenIndex); - void swapImages(int objNumb1, int objNumb2); private: enum seqTextSchedule { @@ -69,7 +68,7 @@ private: kSsBadSaveGame = 1 }; - HugoEngine &_vm; + HugoEngine *_vm; event_t _events[kMaxEvents]; // Statically declare event structures @@ -86,7 +85,7 @@ private: class Scheduler_v1d : public Scheduler { public: - Scheduler_v1d(HugoEngine &vm); + Scheduler_v1d(HugoEngine *vm); ~Scheduler_v1d(); const char *getCypher(); @@ -94,7 +93,7 @@ public: class Scheduler_v3d : public Scheduler { public: - Scheduler_v3d(HugoEngine &vm); + Scheduler_v3d(HugoEngine *vm); ~Scheduler_v3d(); const char *getCypher(); diff --git a/engines/hugo/schedule_v1d.cpp b/engines/hugo/schedule_v1d.cpp index 81daf639f6..3fc4b4c984 100644 --- a/engines/hugo/schedule_v1d.cpp +++ b/engines/hugo/schedule_v1d.cpp @@ -39,7 +39,7 @@ namespace Hugo { -Scheduler_v1d::Scheduler_v1d(HugoEngine &vm) : Scheduler(vm) { +Scheduler_v1d::Scheduler_v1d(HugoEngine *vm) : Scheduler(vm) { } Scheduler_v1d::~Scheduler_v1d() { diff --git a/engines/hugo/schedule_v3d.cpp b/engines/hugo/schedule_v3d.cpp index 9421b0f5f9..41c60902a4 100644 --- a/engines/hugo/schedule_v3d.cpp +++ b/engines/hugo/schedule_v3d.cpp @@ -39,7 +39,7 @@ namespace Hugo { -Scheduler_v3d::Scheduler_v3d(HugoEngine &vm) : Scheduler(vm) { +Scheduler_v3d::Scheduler_v3d(HugoEngine *vm) : Scheduler(vm) { } Scheduler_v3d::~Scheduler_v3d() { diff --git a/engines/hugo/sound.cpp b/engines/hugo/sound.cpp index e5f55afcc8..d3c8fa0238 100644 --- a/engines/hugo/sound.cpp +++ b/engines/hugo/sound.cpp @@ -239,7 +239,7 @@ void MidiPlayer::timerCallback(void *p) { player->updateTimer(); } -SoundHandler::SoundHandler(HugoEngine &vm) : _vm(vm) { +SoundHandler::SoundHandler(HugoEngine *vm) : _vm(vm) { MidiDriver::DeviceHandle dev = MidiDriver::detectDevice(MDT_MIDI | MDT_ADLIB | MDT_PREFER_GM); MidiDriver *driver = MidiDriver::createMidi(dev); @@ -254,7 +254,7 @@ void SoundHandler::setMusicVolume() { void SoundHandler::stopSound() { /* Stop any sound that might be playing */ - _vm._mixer->stopAll(); + _vm->_mixer->stopAll(); } void SoundHandler::stopMusic() { @@ -285,8 +285,8 @@ void SoundHandler::playMusic(int16 tune) { uint16 size; // Size of sequence data if (_config.musicFl) { - _vm.getGameStatus().song = tune; - seqPtr = _vm.file().getSound(tune, &size); + _vm->getGameStatus().song = tune; + seqPtr = _vm->_file->getSound(tune, &size); playMIDI(seqPtr, size); } } @@ -302,7 +302,7 @@ void SoundHandler::playSound(int16 sound, stereo_t channel, byte priority) { static byte curPriority = 0; // Priority of currently playing sound // /* Sound disabled */ - if (!_config.soundFl || !_vm._mixer->isReady()) + if (!_config.soundFl || !_vm->_mixer->isReady()) return; // // // See if last wave still playing - if so, check priority @@ -314,11 +314,11 @@ void SoundHandler::playSound(int16 sound, stereo_t channel, byte priority) { curPriority = priority; // /* Get sound data */ - if ((sound_p = _vm.file().getSound(sound, &size)) == 0) + if ((sound_p = _vm->_file->getSound(sound, &size)) == 0) return; Audio::AudioStream *stream = Audio::makeRawStream(sound_p, size, 11025, Audio::FLAG_UNSIGNED); - _vm._mixer->playStream(Audio::Mixer::kSpeechSoundType, &_soundHandle, stream); + _vm->_mixer->playStream(Audio::Mixer::kSpeechSoundType, &_soundHandle, stream); } diff --git a/engines/hugo/sound.h b/engines/hugo/sound.h index 53a5912a92..a4e9932901 100644 --- a/engines/hugo/sound.h +++ b/engines/hugo/sound.h @@ -41,7 +41,7 @@ class MidiPlayer; class SoundHandler { public: - SoundHandler(HugoEngine &vm); + SoundHandler(HugoEngine *vm); void toggleMusic(); void toggleSound(); @@ -51,7 +51,7 @@ public: void initSound(); private: - HugoEngine &_vm; + HugoEngine *_vm; Audio::SoundHandle _soundHandle; MidiPlayer *_midiPlayer; |