diff options
Diffstat (limited to 'engines/hugo/hugo.cpp')
-rw-r--r-- | engines/hugo/hugo.cpp | 1377 |
1 files changed, 557 insertions, 820 deletions
diff --git a/engines/hugo/hugo.cpp b/engines/hugo/hugo.cpp index cdc74b5ae5..ef3352829d 100644 --- a/engines/hugo/hugo.cpp +++ b/engines/hugo/hugo.cpp @@ -24,7 +24,9 @@ */ #include "common/system.h" +#include "common/random.h" #include "common/events.h" +#include "common/EventRecorder.h" #include "common/debug-channels.h" #include "hugo/hugo.h" @@ -37,8 +39,10 @@ #include "hugo/inventory.h" #include "hugo/parser.h" #include "hugo/route.h" +#include "hugo/util.h" #include "hugo/sound.h" #include "hugo/intro.h" +#include "hugo/object.h" #include "engines/util.h" @@ -51,12 +55,18 @@ overlay_t HugoEngine::_overlay; overlay_t HugoEngine::_ovlBase; overlay_t HugoEngine::_objBound; +config_t _config; // User's config +maze_t _maze; // Default to not in maze +hugo_boot_t _boot; // Boot info structure file +char _textBoxBuffer[MAX_BOX]; // Buffer for text box +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), - _score(0), _maxscore(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), _heroImage(0), _defltTunes(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), _backgroundObjectsSize(0), _screenActsSize(0), _usesSize(0) { DebugMan.addDebugChannel(kDebugSchedule, "Schedule", "Script Schedule debug level"); @@ -67,73 +77,89 @@ HugoEngine::HugoEngine(OSystem *syst, const HugoGameDescription *gd) : Engine(sy DebugMan.addDebugChannel(kDebugFile, "File", "File IO debug level"); DebugMan.addDebugChannel(kDebugRoute, "Route", "Route debug level"); DebugMan.addDebugChannel(kDebugInventory, "Inventory", "Inventory debug level"); + DebugMan.addDebugChannel(kDebugObject, "Object", "Object debug level"); - for (int j = 0; j < NUM_FONTS; j++) - _arrayFont[j] = 0; + _console = new HugoConsole(this); } HugoEngine::~HugoEngine() { - delete _soundHandler; - delete _route; - delete _parser; - delete _inventoryHandler; - delete _mouseHandler; - delete _screen; - delete _scheduler; - delete _fileManager; - - free(_palette); - free(_introX); - free(_introY); - -#if 0 - freeTexts(_textData); - freeTexts(_stringtData); - freeTexts(_textEngine); - freeTexts(_textIntro); - freeTexts(_textMouse); - freeTexts(_textParser); - freeTexts(_textSchedule); - freeTexts(_textUtil); -#endif free(_textData); free(_stringtData); + + if (_arrayNouns) { + for (int i = 0; _arrayNouns[i]; i++) + free(_arrayNouns[i]); + free(_arrayNouns); + } + + if (_arrayVerbs) { + for (int i = 0; _arrayVerbs[i]; i++) + free(_arrayVerbs[i]); + free(_arrayVerbs); + } + free(_screenNames); + _screen->freePalette(); free(_textEngine); free(_textIntro); + free(_introX); + free(_introY); free(_textMouse); free(_textParser); free(_textSchedule); free(_textUtil); - - warning("Missing: free _arrayNouns"); - warning("Missing: free _arrayVerbs"); - free(_arrayReqs); free(_hotspots); free(_invent); - free(_uses); + + if (_uses) { + for (int i = 0; i < _usesSize; i++) + free(_uses[i].targets); + free(_uses); + } + free(_catchallList); - warning("Missing: free _background_objects"); + if (_backgroundObjects) { + for (int i = 0; i < _backgroundObjectsSize; i++) + free(_backgroundObjects[i]); + free(_backgroundObjects); + } free(_points); - warning("Missing: free _cmdList"); - warning("Missing: free _screenActs"); - warning("Missing: free _objects"); + if (_cmdList) { + for (int i = 0; i < _cmdListSize; i++) + free(_cmdList[i]); + free(_cmdList); + } + + if (_cmdList) { + for (int i = 0; i < _screenActsSize; i++) + free(_screenActs[i]); + free(_screenActs); + } + + _object->freeObjectArr(); + _scheduler->freeActListArr(); free(_defltTunes); free(_screenStates); - if (_arrayFont[0]) - free(_arrayFont[0]); + _screen->freeFonts(); - if (_arrayFont[1]) - free(_arrayFont[1]); + delete _object; + delete _sound; + delete _route; + delete _parser; + delete _inventory; + delete _mouse; + delete _screen; + delete _scheduler; + delete _file; - if (_arrayFont[2]) - free(_arrayFont[2]); + DebugMan.clearAllDebugChannels(); + delete _console; } GameType HugoEngine::getGameType() const { @@ -152,53 +178,59 @@ 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); 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_v1w(this); + _intro = new intro_v1w(this); + _screen = new Screen_v1w(this); + _parser = new Parser_v1w(this); + _object = new ObjectHandler_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_v1w(this); + _intro = new intro_v2w(this); + _screen = new Screen_v1w(this); + _parser = new Parser_v1w(this); + _object = new ObjectHandler_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_v1w(this); + _intro = new intro_v3w(this); + _screen = new Screen_v1w(this); + _parser = new Parser_v1w(this); + _object = new ObjectHandler_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); + _object = new ObjectHandler_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_v2d(this); + _intro = new intro_v2d(this); + _screen = new Screen_v1d(this); + _parser = new Parser_v2d(this); + _object = new ObjectHandler_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); + _object = new ObjectHandler_v1d(this); break; } @@ -216,7 +248,7 @@ Common::Error HugoEngine::run() { initialize(); initConfig(RESET); // Reset user's config - file().restoreGame(-1); + _file->restoreGame(-1); initMachine(); @@ -234,7 +266,11 @@ Common::Error HugoEngine::run() { while (_eventMan->pollEvent(event)) { switch (event.type) { case Common::EVENT_KEYDOWN: - parser().keyHandler(event.kbd.keycode, 0); + if (event.kbd.keycode == Common::KEYCODE_d && event.kbd.hasFlags(Common::KBD_CTRL)) { + this->getDebugger()->attach(); + this->getDebugger()->onFrame(); + } + _parser->keyHandler(event.kbd.keycode, 0); break; case Common::EVENT_MOUSEMOVE: _mouseX = event.mouse.x; @@ -259,6 +295,7 @@ Common::Error HugoEngine::run() { break; } } + _status.doQuitFl |= shouldQuit(); // update game quit flag } return Common::kNoError; } @@ -267,14 +304,16 @@ 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) } +/** +* Hugo game state machine - called during onIdle +*/ void HugoEngine::runMachine() { -// Hugo game state machine - called during onIdle static uint32 lastTime; status_t &gameStatus = getGameStatus(); @@ -293,32 +332,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; @@ -327,6 +366,9 @@ void HugoEngine::runMachine() { } } +/** +* Loads Hugo.dat file, which contains all the hardcoded data in the original executables +*/ bool HugoEngine::loadHugoDat() { Common::File in; in.open("hugo.dat"); @@ -379,11 +421,7 @@ bool HugoEngine::loadHugoDat() { // Read screenNames _screenNames = loadTextsVariante(in, &_numScreens); - // Read palette - _paletteSize = in.readUint16BE(); - _palette = (byte *)malloc(sizeof(byte) * _paletteSize); - for (int i = 0; i < _paletteSize; i++) - _palette[i] = in.readByte(); + _screen->loadPalette(in); // Read textEngine _textEngine = loadTexts(in); @@ -456,7 +494,7 @@ bool HugoEngine::loadHugoDat() { } } - int numElem, numSubElem, numSubAct; + int numElem, numSubElem; //Read _invent for (int varnt = 0; varnt < _numVariant; varnt++) { numElem = in.readUint16BE(); @@ -475,6 +513,7 @@ bool HugoEngine::loadHugoDat() { for (int varnt = 0; varnt < _numVariant; varnt++) { numElem = in.readUint16BE(); if (varnt == _gameVariant) { + _usesSize = numElem; _uses = (uses_t *)malloc(sizeof(uses_t) * numElem); for (int i = 0; i < numElem; i++) { _uses[i].objId = in.readSint16BE(); @@ -528,8 +567,9 @@ bool HugoEngine::loadHugoDat() { for (int varnt = 0; varnt < _numVariant; varnt++) { numElem = in.readUint16BE(); if (varnt == _gameVariant) { - _backgroundObjects = (background_t **)malloc(sizeof(background_t *) * numElem); - for (int i = 0; i < numElem; i++) { + _backgroundObjectsSize = numElem; + _backgroundObjects = (background_t **)malloc(sizeof(background_t *) * _backgroundObjectsSize); + for (int i = 0; i < _backgroundObjectsSize; i++) { numSubElem = in.readUint16BE(); _backgroundObjects[i] = (background_t *)malloc(sizeof(background_t) * numSubElem); for (int j = 0; j < numSubElem; j++) { @@ -576,8 +616,9 @@ bool HugoEngine::loadHugoDat() { for (int varnt = 0; varnt < _numVariant; varnt++) { numElem = in.readUint16BE(); if (varnt == _gameVariant) { - _cmdList = (cmd **)malloc(sizeof(cmd *) * numElem); - for (int i = 0; i < numElem; i++) { + _cmdListSize = numElem; + _cmdList = (cmd **)malloc(sizeof(cmd *) * _cmdListSize); + for (int i = 0; i < _cmdListSize; i++) { numSubElem = in.readUint16BE(); _cmdList[i] = (cmd *)malloc(sizeof(cmd) * numSubElem); for (int j = 0; j < numSubElem; j++) { @@ -608,13 +649,14 @@ bool HugoEngine::loadHugoDat() { } } -// TODO: For Hugo2 and Hugo3, if not in story mode, increment _screenActs[0][0] (ex: kALcrashStory + 1 == kALcrashNoStory) // Read _screenActs + // TODO: For Hugo2 and Hugo3, if not in story mode, increment _screenActs[0][0] (ex: kALcrashStory + 1 == kALcrashNoStory) for (int varnt = 0; varnt < _numVariant; varnt++) { numElem = in.readUint16BE(); if (varnt == _gameVariant) { - _screenActs = (uint16 **)malloc(sizeof(uint16 *) * numElem); - for (int i = 0; i < numElem; i++) { + _screenActsSize = numElem; + _screenActs = (uint16 **)malloc(sizeof(uint16 *) * _screenActsSize); + for (int i = 0; i < _screenActsSize; i++) { numSubElem = in.readUint16BE(); if (numSubElem == 0) { _screenActs[i] = 0; @@ -633,682 +675,23 @@ 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(); - } - } - } -//#define HERO 0 - _hero = &_objects[HERO]; // This always points to hero - _screen_p = &(_objects[HERO].screenIndex); // Current screen is hero's - _heroImage = HERO; // Current in use hero image + _object->loadObjectArr(in); + + _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 + + _scheduler->loadActListArr(in); -//read _actListArr - for (int varnt = 0; varnt < _numVariant; varnt++) { - numElem = in.readUint16BE(); - if (varnt == _gameVariant) { - _actListArr = (act **)malloc(sizeof(act *) * numElem); - for (int i = 0; i < numElem; i++) { - numSubElem = in.readUint16BE(); - _actListArr[i] = (act *) malloc(sizeof(act) * (numSubElem + 1)); - for (int j = 0; j < numSubElem; j++) { - _actListArr[i][j].a0.actType = (action_t) in.readByte(); - switch (_actListArr[i][j].a0.actType) { - case ANULL: // -1 - break; - case ASCHEDULE: // 0 - _actListArr[i][j].a0.timer = in.readSint16BE(); - _actListArr[i][j].a0.actIndex = in.readUint16BE(); - break; - case START_OBJ: // 1 - _actListArr[i][j].a1.timer = in.readSint16BE(); - _actListArr[i][j].a1.objNumb = in.readSint16BE(); - _actListArr[i][j].a1.cycleNumb = in.readSint16BE(); - _actListArr[i][j].a1.cycle = (cycle_t) in.readByte(); - break; - case INIT_OBJXY: // 2 - _actListArr[i][j].a2.timer = in.readSint16BE(); - _actListArr[i][j].a2.objNumb = in.readSint16BE(); - _actListArr[i][j].a2.x = in.readSint16BE(); - _actListArr[i][j].a2.y = in.readSint16BE(); - break; - case PROMPT: // 3 - _actListArr[i][j].a3.timer = in.readSint16BE(); - _actListArr[i][j].a3.promptIndex = in.readSint16BE(); - numSubAct = in.readUint16BE(); - _actListArr[i][j].a3.responsePtr = (int *) malloc(sizeof(int) * numSubAct); - for (int k = 0; k < numSubAct; k++) - _actListArr[i][j].a3.responsePtr[k] = in.readSint16BE(); - _actListArr[i][j].a3.actPassIndex = in.readUint16BE(); - _actListArr[i][j].a3.actFailIndex = in.readUint16BE(); - _actListArr[i][j].a3.encodedFl = (in.readByte() == 1) ? true : false; - break; - case BKGD_COLOR: // 4 - _actListArr[i][j].a4.timer = in.readSint16BE(); - _actListArr[i][j].a4.newBackgroundColor = in.readUint32BE(); - break; - case INIT_OBJVXY: // 5 - _actListArr[i][j].a5.timer = in.readSint16BE(); - _actListArr[i][j].a5.objNumb = in.readSint16BE(); - _actListArr[i][j].a5.vx = in.readSint16BE(); - _actListArr[i][j].a5.vy = in.readSint16BE(); - break; - case INIT_CARRY: // 6 - _actListArr[i][j].a6.timer = in.readSint16BE(); - _actListArr[i][j].a6.objNumb = in.readSint16BE(); - _actListArr[i][j].a6.carriedFl = (in.readByte() == 1) ? true : false; - break; - case INIT_HF_COORD: // 7 - _actListArr[i][j].a7.timer = in.readSint16BE(); - _actListArr[i][j].a7.objNumb = in.readSint16BE(); - break; - case NEW_SCREEN: // 8 - _actListArr[i][j].a8.timer = in.readSint16BE(); - _actListArr[i][j].a8.screenIndex = in.readSint16BE(); - break; - case INIT_OBJSTATE: // 9 - _actListArr[i][j].a9.timer = in.readSint16BE(); - _actListArr[i][j].a9.objNumb = in.readSint16BE(); - _actListArr[i][j].a9.newState = in.readByte(); - break; - case INIT_PATH: // 10 - _actListArr[i][j].a10.timer = in.readSint16BE(); - _actListArr[i][j].a10.objNumb = in.readSint16BE(); - _actListArr[i][j].a10.newPathType = in.readSint16BE(); - _actListArr[i][j].a10.vxPath = in.readByte(); - _actListArr[i][j].a10.vyPath = in.readByte(); - break; - case COND_R: // 11 - _actListArr[i][j].a11.timer = in.readSint16BE(); - _actListArr[i][j].a11.objNumb = in.readSint16BE(); - _actListArr[i][j].a11.stateReq = in.readByte(); - _actListArr[i][j].a11.actPassIndex = in.readUint16BE(); - _actListArr[i][j].a11.actFailIndex = in.readUint16BE(); - break; - case TEXT: // 12 - _actListArr[i][j].a12.timer = in.readSint16BE(); - _actListArr[i][j].a12.stringIndex = in.readSint16BE(); - break; - case SWAP_IMAGES: // 13 - _actListArr[i][j].a13.timer = in.readSint16BE(); - _actListArr[i][j].a13.obj1 = in.readSint16BE(); - _actListArr[i][j].a13.obj2 = in.readSint16BE(); - break; - case COND_SCR: // 14 - _actListArr[i][j].a14.timer = in.readSint16BE(); - _actListArr[i][j].a14.objNumb = in.readSint16BE(); - _actListArr[i][j].a14.screenReq = in.readSint16BE(); - _actListArr[i][j].a14.actPassIndex = in.readUint16BE(); - _actListArr[i][j].a14.actFailIndex = in.readUint16BE(); - break; - case AUTOPILOT: // 15 - _actListArr[i][j].a15.timer = in.readSint16BE(); - _actListArr[i][j].a15.obj1 = in.readSint16BE(); - _actListArr[i][j].a15.obj2 = in.readSint16BE(); - _actListArr[i][j].a15.dx = in.readByte(); - _actListArr[i][j].a15.dy = in.readByte(); - break; - case INIT_OBJ_SEQ: // 16 - _actListArr[i][j].a16.timer = in.readSint16BE(); - _actListArr[i][j].a16.objNumb = in.readSint16BE(); - _actListArr[i][j].a16.seqIndex = in.readSint16BE(); - break; - case SET_STATE_BITS: // 17 - _actListArr[i][j].a17.timer = in.readSint16BE(); - _actListArr[i][j].a17.objNumb = in.readSint16BE(); - _actListArr[i][j].a17.stateMask = in.readSint16BE(); - break; - case CLEAR_STATE_BITS: // 18 - _actListArr[i][j].a18.timer = in.readSint16BE(); - _actListArr[i][j].a18.objNumb = in.readSint16BE(); - _actListArr[i][j].a18.stateMask = in.readSint16BE(); - break; - case TEST_STATE_BITS: // 19 - _actListArr[i][j].a19.timer = in.readSint16BE(); - _actListArr[i][j].a19.objNumb = in.readSint16BE(); - _actListArr[i][j].a19.stateMask = in.readSint16BE(); - _actListArr[i][j].a19.actPassIndex = in.readUint16BE(); - _actListArr[i][j].a19.actFailIndex = in.readUint16BE(); - break; - case DEL_EVENTS: // 20 - _actListArr[i][j].a20.timer = in.readSint16BE(); - _actListArr[i][j].a20.actTypeDel = (action_t) in.readByte(); - break; - case GAMEOVER: // 21 - _actListArr[i][j].a21.timer = in.readSint16BE(); - break; - case INIT_HH_COORD: // 22 - _actListArr[i][j].a22.timer = in.readSint16BE(); - _actListArr[i][j].a22.objNumb = in.readSint16BE(); - break; - case EXIT: // 23 - _actListArr[i][j].a23.timer = in.readSint16BE(); - break; - case BONUS: // 24 - _actListArr[i][j].a24.timer = in.readSint16BE(); - _actListArr[i][j].a24.pointIndex = in.readSint16BE(); - break; - case COND_BOX: // 25 - _actListArr[i][j].a25.timer = in.readSint16BE(); - _actListArr[i][j].a25.objNumb = in.readSint16BE(); - _actListArr[i][j].a25.x1 = in.readSint16BE(); - _actListArr[i][j].a25.y1 = in.readSint16BE(); - _actListArr[i][j].a25.x2 = in.readSint16BE(); - _actListArr[i][j].a25.y2 = in.readSint16BE(); - _actListArr[i][j].a25.actPassIndex = in.readUint16BE(); - _actListArr[i][j].a25.actFailIndex = in.readUint16BE(); - break; - case SOUND: // 26 - _actListArr[i][j].a26.timer = in.readSint16BE(); - _actListArr[i][j].a26.soundIndex = in.readSint16BE(); - break; - case ADD_SCORE: // 27 - _actListArr[i][j].a27.timer = in.readSint16BE(); - _actListArr[i][j].a27.objNumb = in.readSint16BE(); - break; - case SUB_SCORE: // 28 - _actListArr[i][j].a28.timer = in.readSint16BE(); - _actListArr[i][j].a28.objNumb = in.readSint16BE(); - break; - case COND_CARRY: // 29 - _actListArr[i][j].a29.timer = in.readSint16BE(); - _actListArr[i][j].a29.objNumb = in.readSint16BE(); - _actListArr[i][j].a29.actPassIndex = in.readUint16BE(); - _actListArr[i][j].a29.actFailIndex = in.readUint16BE(); - break; - case INIT_MAZE: // 30 - _actListArr[i][j].a30.timer = in.readSint16BE(); - _actListArr[i][j].a30.mazeSize = in.readByte(); - _actListArr[i][j].a30.x1 = in.readSint16BE(); - _actListArr[i][j].a30.y1 = in.readSint16BE(); - _actListArr[i][j].a30.x2 = in.readSint16BE(); - _actListArr[i][j].a30.y2 = in.readSint16BE(); - _actListArr[i][j].a30.x3 = in.readSint16BE(); - _actListArr[i][j].a30.x4 = in.readSint16BE(); - _actListArr[i][j].a30.firstScreenIndex = in.readByte(); - break; - case EXIT_MAZE: // 31 - _actListArr[i][j].a31.timer = in.readSint16BE(); - break; - case INIT_PRIORITY: // 32 - _actListArr[i][j].a32.timer = in.readSint16BE(); - _actListArr[i][j].a32.objNumb = in.readSint16BE(); - _actListArr[i][j].a32.priority = in.readByte(); - break; - case INIT_SCREEN: // 33 - _actListArr[i][j].a33.timer = in.readSint16BE(); - _actListArr[i][j].a33.objNumb = in.readSint16BE(); - _actListArr[i][j].a33.screenIndex = in.readSint16BE(); - break; - case AGSCHEDULE: // 34 - _actListArr[i][j].a34.timer = in.readSint16BE(); - _actListArr[i][j].a34.actIndex = in.readUint16BE(); - break; - case REMAPPAL: // 35 - _actListArr[i][j].a35.timer = in.readSint16BE(); - _actListArr[i][j].a35.oldColorIndex = in.readSint16BE(); - _actListArr[i][j].a35.newColorIndex = in.readSint16BE(); - break; - case COND_NOUN: // 36 - _actListArr[i][j].a36.timer = in.readSint16BE(); - _actListArr[i][j].a36.nounIndex = in.readUint16BE(); - _actListArr[i][j].a36.actPassIndex = in.readUint16BE(); - _actListArr[i][j].a36.actFailIndex = in.readUint16BE(); - break; - case SCREEN_STATE: // 37 - _actListArr[i][j].a37.timer = in.readSint16BE(); - _actListArr[i][j].a37.screenIndex = in.readSint16BE(); - _actListArr[i][j].a37.newState = in.readByte(); - break; - case INIT_LIPS: // 38 - _actListArr[i][j].a38.timer = in.readSint16BE(); - _actListArr[i][j].a38.lipsObjNumb = in.readSint16BE(); - _actListArr[i][j].a38.objNumb = in.readSint16BE(); - _actListArr[i][j].a38.dxLips = in.readByte(); - _actListArr[i][j].a38.dyLips = in.readByte(); - break; - case INIT_STORY_MODE: // 39 - _actListArr[i][j].a39.timer = in.readSint16BE(); - _actListArr[i][j].a39.storyModeFl = (in.readByte() == 1); - break; - case WARN: // 40 - _actListArr[i][j].a40.timer = in.readSint16BE(); - _actListArr[i][j].a40.stringIndex = in.readSint16BE(); - break; - case COND_BONUS: // 41 - _actListArr[i][j].a41.timer = in.readSint16BE(); - _actListArr[i][j].a41.BonusIndex = in.readSint16BE(); - _actListArr[i][j].a41.actPassIndex = in.readUint16BE(); - _actListArr[i][j].a41.actFailIndex = in.readUint16BE(); - break; - case TEXT_TAKE: // 42 - _actListArr[i][j].a42.timer = in.readSint16BE(); - _actListArr[i][j].a42.objNumb = in.readSint16BE(); - break; - case YESNO: // 43 - _actListArr[i][j].a43.timer = in.readSint16BE(); - _actListArr[i][j].a43.promptIndex = in.readSint16BE(); - _actListArr[i][j].a43.actYesIndex = in.readUint16BE(); - _actListArr[i][j].a43.actNoIndex = in.readUint16BE(); - break; - case STOP_ROUTE: // 44 - _actListArr[i][j].a44.timer = in.readSint16BE(); - break; - case COND_ROUTE: // 45 - _actListArr[i][j].a45.timer = in.readSint16BE(); - _actListArr[i][j].a45.routeIndex = in.readSint16BE(); - _actListArr[i][j].a45.actPassIndex = in.readUint16BE(); - _actListArr[i][j].a45.actFailIndex = in.readUint16BE(); - break; - case INIT_JUMPEXIT: // 46 - _actListArr[i][j].a46.timer = in.readSint16BE(); - _actListArr[i][j].a46.jumpExitFl = (in.readByte() == 1); - break; - case INIT_VIEW: // 47 - _actListArr[i][j].a47.timer = in.readSint16BE(); - _actListArr[i][j].a47.objNumb = in.readSint16BE(); - _actListArr[i][j].a47.viewx = in.readSint16BE(); - _actListArr[i][j].a47.viewy = in.readSint16BE(); - _actListArr[i][j].a47.direction = in.readSint16BE(); - break; - case INIT_OBJ_FRAME: // 48 - _actListArr[i][j].a48.timer = in.readSint16BE(); - _actListArr[i][j].a48.objNumb = in.readSint16BE(); - _actListArr[i][j].a48.seqIndex = in.readSint16BE(); - _actListArr[i][j].a48.frameIndex = in.readSint16BE(); - break; - case OLD_SONG: //49 - _actListArr[i][j].a49.timer = in.readSint16BE(); - _actListArr[i][j].a49.soundIndex = in.readUint16BE(); - break; - default: - error("Engine - Unknown action type encountered: %d", _actListArr[i][j].a0.actType); - } - } - _actListArr[i][numSubElem].a0.actType = ANULL; - } - } else { - for (int i = 0; i < numElem; i++) { - numSubElem = in.readUint16BE(); - for (int j = 0; j < numSubElem; j++) { - numSubAct = in.readByte(); - switch (numSubAct) { - case ANULL: // -1 - break; - case ASCHEDULE: // 0 - in.readSint16BE(); - in.readUint16BE(); - break; - case START_OBJ: // 1 - in.readSint16BE(); - in.readSint16BE(); - in.readSint16BE(); - in.readByte(); - break; - case INIT_OBJXY: // 2 - in.readSint16BE(); - in.readSint16BE(); - in.readSint16BE(); - in.readSint16BE(); - break; - case PROMPT: // 3 - in.readSint16BE(); - in.readSint16BE(); - numSubAct = in.readUint16BE(); - for (int k = 0; k < numSubAct; k++) - in.readSint16BE(); - in.readUint16BE(); - in.readUint16BE(); - in.readByte(); - break; - case BKGD_COLOR: // 4 - in.readSint16BE(); - in.readUint32BE(); - break; - case INIT_OBJVXY: // 5 - in.readSint16BE(); - in.readSint16BE(); - in.readSint16BE(); - in.readSint16BE(); - break; - case INIT_CARRY: // 6 - in.readSint16BE(); - in.readSint16BE(); - in.readByte(); - break; - case INIT_HF_COORD: // 7 - in.readSint16BE(); - in.readSint16BE(); - break; - case NEW_SCREEN: // 8 - in.readSint16BE(); - in.readSint16BE(); - break; - case INIT_OBJSTATE: // 9 - in.readSint16BE(); - in.readSint16BE(); - in.readByte(); - break; - case INIT_PATH: // 10 - in.readSint16BE(); - in.readSint16BE(); - in.readSint16BE(); - in.readByte(); - in.readByte(); - break; - case COND_R: // 11 - in.readSint16BE(); - in.readSint16BE(); - in.readByte(); - in.readUint16BE(); - in.readUint16BE(); - break; - case TEXT: // 12 - in.readSint16BE(); - in.readSint16BE(); - break; - case SWAP_IMAGES: // 13 - in.readSint16BE(); - in.readSint16BE(); - in.readSint16BE(); - break; - case COND_SCR: // 14 - in.readSint16BE(); - in.readSint16BE(); - in.readSint16BE(); - in.readUint16BE(); - in.readUint16BE(); - break; - case AUTOPILOT: // 15 - in.readSint16BE(); - in.readSint16BE(); - in.readSint16BE(); - in.readByte(); - in.readByte(); - break; - case INIT_OBJ_SEQ: // 16 - in.readSint16BE(); - in.readSint16BE(); - in.readSint16BE(); - break; - case SET_STATE_BITS: // 17 - in.readSint16BE(); - in.readSint16BE(); - in.readSint16BE(); - break; - case CLEAR_STATE_BITS: // 18 - in.readSint16BE(); - in.readSint16BE(); - in.readSint16BE(); - break; - case TEST_STATE_BITS: // 19 - in.readSint16BE(); - in.readSint16BE(); - in.readSint16BE(); - in.readUint16BE(); - in.readUint16BE(); - break; - case DEL_EVENTS: // 20 - in.readSint16BE(); - in.readByte(); - break; - case GAMEOVER: // 21 - in.readSint16BE(); - break; - case INIT_HH_COORD: // 22 - in.readSint16BE(); - in.readSint16BE(); - break; - case EXIT: // 23 - in.readSint16BE(); - break; - case BONUS: // 24 - in.readSint16BE(); - in.readSint16BE(); - break; - case COND_BOX: // 25 - in.readSint16BE(); - in.readSint16BE(); - in.readSint16BE(); - in.readSint16BE(); - in.readSint16BE(); - in.readSint16BE(); - in.readUint16BE(); - in.readUint16BE(); - break; - case SOUND: // 26 - in.readSint16BE(); - in.readSint16BE(); - break; - case ADD_SCORE: // 27 - in.readSint16BE(); - in.readSint16BE(); - break; - case SUB_SCORE: // 28 - in.readSint16BE(); - in.readSint16BE(); - break; - case COND_CARRY: // 29 - in.readSint16BE(); - in.readSint16BE(); - in.readUint16BE(); - in.readUint16BE(); - break; - case INIT_MAZE: // 30 - in.readSint16BE(); - in.readByte(); - in.readSint16BE(); - in.readSint16BE(); - in.readSint16BE(); - in.readSint16BE(); - in.readSint16BE(); - in.readSint16BE(); - in.readByte(); - break; - case EXIT_MAZE: // 31 - in.readSint16BE(); - break; - case INIT_PRIORITY: // 32 - in.readSint16BE(); - in.readSint16BE(); - in.readByte(); - break; - case INIT_SCREEN: // 33 - in.readSint16BE(); - in.readSint16BE(); - in.readSint16BE(); - break; - case AGSCHEDULE: // 34 - in.readSint16BE(); - in.readUint16BE(); - break; - case REMAPPAL: // 35 - in.readSint16BE(); - in.readSint16BE(); - in.readSint16BE(); - break; - case COND_NOUN: // 36 - in.readSint16BE(); - in.readUint16BE(); - in.readUint16BE(); - in.readUint16BE(); - break; - case SCREEN_STATE: // 37 - in.readSint16BE(); - in.readSint16BE(); - in.readByte(); - break; - case INIT_LIPS: // 38 - in.readSint16BE(); - in.readSint16BE(); - in.readSint16BE(); - in.readByte(); - in.readByte(); - break; - case INIT_STORY_MODE: // 39 - in.readSint16BE(); - in.readByte(); - break; - case WARN: // 40 - in.readSint16BE(); - in.readSint16BE(); - break; - case COND_BONUS: // 41 - in.readSint16BE(); - in.readSint16BE(); - in.readUint16BE(); - in.readUint16BE(); - break; - case TEXT_TAKE: // 42 - in.readSint16BE(); - in.readSint16BE(); - break; - case YESNO: // 43 - in.readSint16BE(); - in.readSint16BE(); - in.readUint16BE(); - in.readUint16BE(); - break; - case STOP_ROUTE: // 44 - in.readSint16BE(); - break; - case COND_ROUTE: // 45 - in.readSint16BE(); - in.readSint16BE(); - in.readUint16BE(); - in.readUint16BE(); - break; - case INIT_JUMPEXIT: // 46 - in.readSint16BE(); - in.readByte(); - break; - case INIT_VIEW: // 47 - in.readSint16BE(); - in.readSint16BE(); - in.readSint16BE(); - in.readSint16BE(); - in.readSint16BE(); - break; - case INIT_OBJ_FRAME: // 48 - in.readSint16BE(); - in.readSint16BE(); - in.readSint16BE(); - in.readSint16BE(); - break; - case OLD_SONG: //49 - in.readSint16BE(); - in.readUint16BE(); - break; - default: - error("Engine - Unknown action type encountered %d - variante %d pos %d.%d", numSubAct, varnt, i, j); - } - } - } - } - } for (int varnt = 0; varnt < _numVariant; varnt++) { if (varnt == _gameVariant) { - _tunesNbr = in.readByte(); - _soundSilence = in.readByte(); - _soundTest = in.readByte(); + _tunesNbr = in.readSByte(); + _soundSilence = in.readSByte(); + _soundTest = in.readSByte(); } else { - in.readByte(); - in.readByte(); - in.readByte(); + in.readSByte(); + in.readSByte(); + in.readSByte(); } } @@ -1356,41 +739,9 @@ bool HugoEngine::loadHugoDat() { _numObj = numElem; } - //Read kALnewscr used by maze (Hugo 2) - for (int varnt = 0; varnt < _numVariant; varnt++) { - numElem = in.readUint16BE(); - if (varnt == _gameVariant) - _alNewscrIndex = numElem; - } - - if (_gameVariant > 2) { - _arrayFontSize[0] = in.readUint16BE(); - _arrayFont[0] = (byte *)malloc(sizeof(byte) * _arrayFontSize[0]); - for (int j = 0; j < _arrayFontSize[0]; j++) - _arrayFont[0][j] = in.readByte(); - - _arrayFontSize[1] = in.readUint16BE(); - _arrayFont[1] = (byte *)malloc(sizeof(byte) * _arrayFontSize[1]); - for (int j = 0; j < _arrayFontSize[1]; j++) - _arrayFont[1][j] = in.readByte(); - - _arrayFontSize[2] = in.readUint16BE(); - _arrayFont[2] = (byte *)malloc(sizeof(byte) * _arrayFontSize[2]); - for (int j = 0; j < _arrayFontSize[2]; j++) - _arrayFont[2][j] = in.readByte(); - } else { - numElem = in.readUint16BE(); - for (int j = 0; j < numElem; j++) - in.readByte(); + _scheduler->loadAlNewscrIndex(in); + _screen->loadFontArr(in); - numElem = in.readUint16BE(); - for (int j = 0; j < numElem; j++) - in.readByte(); - - numElem = in.readUint16BE(); - for (int j = 0; j < numElem; j++) - in.readByte(); - } return true; } @@ -1459,14 +810,15 @@ uint16 **HugoEngine::loadLongArray(Common::File &in) { char ***HugoEngine::loadTextsArray(Common::File &in) { char ***resArray = 0; + uint16 arraySize; for (int varnt = 0; varnt < _numVariant; varnt++) { - int numNouns = in.readUint16BE(); + arraySize = in.readUint16BE(); if (varnt == _gameVariant) { - resArray = (char ** *)malloc(sizeof(char **) * (numNouns + 1)); - resArray[numNouns] = 0; + resArray = (char ***)malloc(sizeof(char **) * (arraySize + 1)); + resArray[arraySize] = 0; } - for (int i = 0; i < numNouns; i++) { + for (int i = 0; i < arraySize; i++) { int numTexts = in.readUint16BE(); int entryLen = in.readUint16BE(); char *pos = (char *)malloc(entryLen); @@ -1528,4 +880,389 @@ void HugoEngine::freeTexts(char **ptr) { free(ptr); } +/** +* Sets the playlist to be the default tune selection +*/ +void HugoEngine::initPlaylist(bool playlist[MAX_TUNES]) { + debugC(1, kDebugEngine, "initPlaylist"); + + for (int16 i = 0; i < MAX_TUNES; i++) + playlist[i] = false; + for (int16 i = 0; _defltTunes[i] != -1; i++) + playlist[_defltTunes[i]] = true; +} + +/** +* Initialize the dynamic game status +*/ +void HugoEngine::initStatus() { + debugC(1, kDebugEngine, "initStatus"); + _status.initSaveFl = true; // Force initial save + _status.storyModeFl = false; // Not in story mode + _status.gameOverFl = false; // Hero not knobbled yet +// Strangerke - Suppress as related to playback +// _status.recordFl = false; // Not record mode +// _status.playbackFl = false; // Not playback mode + _status.demoFl = false; // Not demo mode + _status.textBoxFl = false; // Not processing a text box +// Strangerke - Not used ? +// _status.mmtime = false; // Multimedia timer support + _status.lookFl = false; // Toolbar "look" button + _status.recallFl = false; // Toolbar "recall" button + _status.leftButtonFl = false; // Left mouse button pressed + _status.rightButtonFl = false; // Right mouse button pressed + _status.newScreenFl = false; // Screen not just loaded + _status.jumpExitFl = false; // Can't jump to a screen exit + _status.godModeFl = false; // No special cheats allowed + _status.helpFl = false; // Not calling WinHelp() + _status.doQuitFl = false; + _status.path[0] = 0; // Path to write files + _status.saveSlot = 0; // Slot to save/restore game + _status.screenWidth = 0; // Desktop screen width + + // Initialize every start of new game + _status.tick = 0; // Tick count + _status.saveTick = 0; // Time of last save + _status.viewState = V_IDLE; // View state + _status.inventoryState = I_OFF; // Inventory icon bar state + _status.inventoryHeight = 0; // Inventory icon bar pos + _status.inventoryObjId = -1; // Inventory object selected (none) + _status.routeIndex = -1; // Hero not following a route + _status.go_for = GO_SPACE; // Hero walking to space + _status.go_id = -1; // Hero not walking to anything +} + +/** +* Initialize default config values. Must be done before Initialize(). +* Reset needed to save config.cx,cy which get splatted during OnFileNew() +*/ +void HugoEngine::initConfig(inst_t action) { + debugC(1, kDebugEngine, "initConfig(%d)", action); + + switch (action) { + case INSTALL: + _config.musicFl = true; // Music state initially on + _config.soundFl = true; // Sound state initially on + _config.turboFl = false; // Turbo state initially off + _config.backgroundMusicFl = false; // No music when inactive + _config.musicVolume = 85; // Music volume % + _config.soundVolume = 100; // Sound volume % + initPlaylist(_config.playlist); // Initialize default tune playlist + + _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); + break; + } + } + + _file->initSavedGame(); // Initialize saved game + break; + case RESTORE: + warning("Unhandled action RESTORE"); + break; + } +} + +void HugoEngine::initialize() { + debugC(1, kDebugEngine, "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 + calcMaxScore(); // Initialise maxscore + + _rnd = new Common::RandomSource(); + g_eventRec.registerRandomSource(*_rnd, "hugo"); + + _rnd->setSeed(42); // Kick random number generator + + switch (_gameVariant) { + case kGameVariantH1Dos: + _episode = "\"Hugo's House of Horrors\""; + _picDir = ""; + break; + case kGameVariantH2Dos: + _episode = "\"Hugo 2: Whodunit?\""; + _picDir = "hugo2/"; + break; + case kGameVariantH3Dos: + _episode = "\"Hugo III: Jungle of Doom\""; + _picDir = "hugo3/"; + break; + case kGameVariantH1Win: + _episode = "\"Hugo's Horrific Adventure\""; + _picDir = ""; + break; + case kGameVariantH2Win: + _episode = "\"Hugo's Mystery Adventure\""; + _picDir = "hugo2/"; + break; + case kGameVariantH3Win: + _episode = "\"Hugo's Amazon Adventure\""; + _picDir = "hugo3/"; + break; + default: + error("Unknown game"); + } +} + +/** +* Restore all resources before termination +*/ +void HugoEngine::shutdown() { + debugC(1, kDebugEngine, "shutdown"); + + _file->closeDatabaseFiles(); + _object->freeObjects(); +} + +void HugoEngine::readObjectImages() { + debugC(1, kDebugEngine, "readObjectImages"); + + for (int i = 0; i < _numObj; i++) + _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 +} + +/** +* Return maximum allowed movement (from zero to vx) such that object does +* not cross a boundary (either background or another object) +*/ +int HugoEngine::deltaX(int x1, int x2, int vx, int y) { +// Explanation of algorithm: The boundaries are drawn as contiguous +// lines 1 pixel wide. Since DX,DY are not necessarily 1, we must +// detect boundary crossing. If vx positive, examine each pixel from +// x1 old to x2 new, else x2 old to x1 new, both at the y2 line. +// If vx zero, no need to check. If vy non-zero then examine each +// pixel on the line segment x1 to x2 from y old to y new. +// Fix from Hugo I v1.5: +// Note the diff is munged in the return statement to cater for a special +// cases arising from differences in image widths from one sequence to +// another. The problem occurs reversing direction at a wall where the +// new image intersects before the object can move away. This is cured +// by comparing the intersection with half the object width pos. If the +// intersection is in the other half wrt the intended direction, use the +// desired vx, else use the computed delta. i.e. believe the desired vx + + debugC(3, kDebugEngine, "deltaX(%d, %d, %d, %d)", x1, x2, vx, y); + + if (vx == 0) + return 0 ; // Object stationary + + y *= XBYTES; // Offset into boundary file + if (vx > 0) { + // Moving to right + for (int i = x1 >> 3; i <= (x2 + vx) >> 3; i++) {// Search by byte + int b = Utils::firstBit((byte)(_boundary[y + i] | _objBound[y + i])); + if (b < 8) { // b is index or 8 + // Compute x of boundary and test if intersection + b += i << 3; + if ((b >= x1) && (b <= x2 + vx)) + return (b < x1 + ((x2 - x1) >> 1)) ? vx : b - x2 - 1; // return dx + } + } + } else { + // Moving to left + for (int i = x2 >> 3; i >= (x1 + vx) >> 3; i--) {// Search by byte + int b = Utils::lastBit((byte)(_boundary[y + i] | _objBound[y + i])); + if (b < 8) { // b is index or 8 + // Compute x of boundary and test if intersection + b += i << 3; + if ((b >= x1 + vx) && (b <= x2)) + return (b > x1 + ((x2 - x1) >> 1)) ? vx : b - x1 + 1; // return dx + } + } + } + return vx; +} + +/** +* Similar to Delta_x, but for movement in y direction. Special case of +* bytes at end of line segment; must only count boundary bits falling on +* line segment. +*/ +int HugoEngine::deltaY(int x1, int x2, int vy, int y) { + debugC(3, kDebugEngine, "deltaY(%d, %d, %d, %d)", x1, x2, vy, y); + + if (vy == 0) + return 0; // Object stationary + + int inc = (vy > 0) ? 1 : -1; + for (int j = y + inc; j != (y + vy + inc); j += inc) { //Search by byte + for (int i = x1 >> 3; i <= x2 >> 3; i++) { + int b = _boundary[j * XBYTES + i] | _objBound[j * XBYTES + i]; + if (b != 0) { // Any bit set + // Make sure boundary bits fall on line segment + if (i == (x2 >> 3)) // Adjust right end + b &= 0xff << ((i << 3) + 7 - x2); + else if (i == (x1 >> 3)) // Adjust left end + b &= 0xff >> (x1 - (i << 3)); + if (b) + return j - y - inc; + } + } + } + return vy; +} + +/** +* Store a horizontal line segment in the object boundary file +*/ +void HugoEngine::storeBoundary(int x1, int x2, int y) { + debugC(5, kDebugEngine, "storeBoundary(%d, %d, %d)", x1, x2, y); + + for (int i = x1 >> 3; i <= x2 >> 3; i++) { // For each byte in line + byte *b = &_objBound[y * XBYTES + i]; // get boundary byte + if (i == x2 >> 3) // Adjust right end + *b |= 0xff << ((i << 3) + 7 - x2); + else if (i == x1 >> 3) // Adjust left end + *b |= 0xff >> (x1 - (i << 3)); + else + *b = 0xff; + } +} + +/** +* Clear a horizontal line segment in the object boundary file +*/ +void HugoEngine::clearBoundary(int x1, int x2, int y) { + debugC(5, kDebugEngine, "clearBoundary(%d, %d, %d)", x1, x2, y); + + for (int i = x1 >> 3; i <= x2 >> 3; i++) { // For each byte in line + byte *b = &_objBound[y * XBYTES + i]; // get boundary byte + if (i == x2 >> 3) // Adjust right end + *b &= ~(0xff << ((i << 3) + 7 - x2)); + else if (i == x1 >> 3) // Adjust left end + *b &= ~(0xff >> (x1 - (i << 3))); + else + *b = 0; + } +} + +/** +* Search background command list for this screen for supplied object. +* Return first associated verb (not "look") or 0 if none found. +*/ +char *HugoEngine::useBG(char *name) { + debugC(1, kDebugEngine, "useBG(%s)", name); + + objectList_t p = _backgroundObjects[*_screen_p]; + for (int i = 0; *_arrayVerbs[p[i].verbIndex]; i++) { + if ((name == _arrayNouns[p[i].nounIndex][0] && + p[i].verbIndex != _look) && + ((p[i].roomState == DONT_CARE) || (p[i].roomState == _screenStates[*_screen_p]))) + return _arrayVerbs[p[i].verbIndex][0]; + } + + return 0; +} + +/** +* Add action lists for this screen to event queue +*/ +void HugoEngine::screenActions(int screenNum) { + debugC(1, kDebugEngine, "screenActions(%d)", screenNum); + + uint16 *screenAct = _screenActs[screenNum]; + if (screenAct) { + for (int i = 0; screenAct[i]; i++) + _scheduler->insertActionList(screenAct[i]); + } +} + +/** +* Set the new screen number into the hero object and any carried objects +*/ +void HugoEngine::setNewScreen(int screenNum) { + debugC(1, kDebugEngine, "setNewScreen(%d)", screenNum); + + *_screen_p = screenNum; // HERO object + for (int i = HERO + 1; i < _numObj; i++) { // Any others + if (_object->isCarried(i)) // being carried + _object->_objects[i].screenIndex = screenNum; + } +} + +/** +* An object has collided with a boundary. See if any actions are required +*/ +void HugoEngine::boundaryCollision(object_t *obj) { + debugC(1, kDebugEngine, "boundaryCollision"); + + if (obj == _hero) { + // Hotspots only relevant to HERO + int x; + if (obj->vx > 0) + x = obj->x + obj->currImagePtr->x2; + else + x = obj->x + obj->currImagePtr->x1; + int y = obj->y + obj->currImagePtr->y2; + + for (int i = 0; _hotspots[i].screenIndex >= 0; i++) { + 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); + break; + } + } + } else { + // Check whether an object collided with HERO + int dx = _hero->x + _hero->currImagePtr->x1 - obj->x - obj->currImagePtr->x1; + int dy = _hero->y + _hero->currImagePtr->y2 - obj->y - obj->currImagePtr->y2; + // If object's radius is infinity, use a closer value + int8 radius = obj->radius; + if (radius < 0) + radius = DX * 2; + if ((abs(dx) <= radius) && (abs(dy) <= radius)) + _scheduler->insertActionList(obj->actIndex); + } +} + +/** +* Add up all the object values and all the bonus points +*/ +void HugoEngine::calcMaxScore() { + debugC(1, kDebugEngine, "calcMaxScore"); + + for (int i = 0; i < _numObj; i++) + _maxscore += _object->_objects[i].objValue; + + for (int i = 0; i < _numBonuses; i++) + _maxscore += _points[i].score; +} + +/** +* Exit game, advertise trilogy, show copyright +*/ +void HugoEngine::endGame() { + debugC(1, kDebugEngine, "endGame"); + + if (!_boot.registered) + Utils::Box(BOX_ANY, "%s", _textEngine[kEsAdvertise]); + Utils::Box(BOX_ANY, "%s\n%s", _episode, COPYRIGHT); + _status.viewState = V_EXIT; +} + } // End of namespace Hugo |