diff options
Diffstat (limited to 'engines/hugo/hugo.cpp')
-rw-r--r-- | engines/hugo/hugo.cpp | 737 |
1 files changed, 89 insertions, 648 deletions
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; |