diff options
Diffstat (limited to 'engines/tsage/ringworld2/ringworld2_logic.cpp')
-rw-r--r-- | engines/tsage/ringworld2/ringworld2_logic.cpp | 1438 |
1 files changed, 971 insertions, 467 deletions
diff --git a/engines/tsage/ringworld2/ringworld2_logic.cpp b/engines/tsage/ringworld2/ringworld2_logic.cpp index 97042cb621..e1d6e79423 100644 --- a/engines/tsage/ringworld2/ringworld2_logic.cpp +++ b/engines/tsage/ringworld2/ringworld2_logic.cpp @@ -21,6 +21,8 @@ */ #include "common/config-manager.h" +#include "common/rect.h" +#include "tsage/graphics.h" #include "tsage/scenes.h" #include "tsage/tsage.h" #include "tsage/staticres.h" @@ -36,8 +38,6 @@ namespace TsAGE { namespace Ringworld2 { Scene *Ringworld2Game::createScene(int sceneNumber) { - warning("Switching to scene %d", sceneNumber); - switch (sceneNumber) { /* Scene group #0 */ case 50: @@ -86,8 +86,10 @@ Scene *Ringworld2Game::createScene(int sceneNumber) { // Cutscene - Walking in hall return new Scene525(); case 600: + // Drive Room return new Scene600(); case 700: + // Lander Bay 2 return new Scene700(); case 800: // Sick bay @@ -99,19 +101,24 @@ Scene *Ringworld2Game::createScene(int sceneNumber) { // Deck #5 - By Lift return new Scene850(); case 900: + // Lander Bay 2 - Crane Controls return new Scene900(); /* Scene group #1 */ // case 1000: - error("Missing scene %d from group 1", sceneNumber); + // Cutscene scene + return new Scene1000(); case 1010: // Cutscene - trip in space return new Scene1010(); case 1020: + // Cutscene - trip in space 2 return new Scene1020(); case 1100: + // Canyon return new Scene1100(); case 1200: + // ARM Base - Air Ducts Maze return new Scene1200(); case 1337: case 1330: @@ -124,11 +131,13 @@ Scene *Ringworld2Game::createScene(int sceneNumber) { // Cutscene - Ship return new Scene1525(); case 1530: - // Cutscene - Elevator + // Cutscene - Crashing on Rimwall return new Scene1530(); case 1550: + // Spaceport return new Scene1550(); case 1575: + // Spaceport - unused ship scene return new Scene1575(); case 1580: // Inside wreck @@ -137,83 +146,93 @@ Scene *Ringworld2Game::createScene(int sceneNumber) { // Miranda being questioned return new Scene1625(); case 1700: + // Rim return new Scene1700(); case 1750: + // Rim Transport Vechile return new Scene1750(); case 1800: + // Rim Lift Exterior return new Scene1800(); case 1850: + // Rim Lift Interior return new Scene1850(); case 1875: + // Rim Lift Computer return new Scene1875(); case 1900: + // Spill Mountains Elevator Exit return new Scene1900(); case 1925: + // Spill Mountains Elevator Shaft return new Scene1925(); case 1945: + // Spill Mountains Shaft Bottom return new Scene1945(); case 1950: + // Flup Tube Corridor Maze return new Scene1950(); /* Scene group #2 */ - // case 2000: - // Ice Maze + // Spill Mountains return new Scene2000(); case 2350: - // Ice Maze: Balloon Launch Platform + // Spill Mountains: Balloon Launch Platform return new Scene2350(); case 2400: - // Ice Maze: Large empty room + // Spill Mountains: Unused large empty room return new Scene2400(); case 2425: - // Ice Maze: + // Spill Mountains: The Hall of Records return new Scene2425(); case 2430: - // Ice Maze: Bedroom + // Spill Mountains: Bedroom return new Scene2430(); case 2435: - // Ice Maze: Throne room + // Spill Mountains: Throne room return new Scene2435(); case 2440: - // Ice Maze: Another bedroom + // Spill Mountains: Another bedroom return new Scene2440(); case 2445: - // Ice Maze: + // Spill Mountains: return new Scene2445(); case 2450: - // Ice Maze: Another bedroom + // Spill Mountains: Another bedroom return new Scene2450(); case 2455: - // Ice Maze: Inside crevasse + // Spill Mountains: Inside crevasse return new Scene2455(); case 2500: - // Ice Maze: Large Cave + // Spill Mountains: Large Ledge return new Scene2500(); case 2525: - // Ice Maze: Furnace room + // Spill Mountains: Furnace room return new Scene2525(); case 2530: - // Ice Maze: Well + // Spill Mountains: Well return new Scene2530(); case 2535: - // Ice Maze: Tannery + // Spill Mountains: Tannery return new Scene2535(); case 2600: - // Ice Maze: Exit + // Spill Mountains: Exit return new Scene2600(); case 2700: - // Forest Maze + // Outer Forest return new Scene2700(); case 2750: - // Forest Maze + // Inner Forest return new Scene2750(); case 2800: - // Exiting Forest + // Guard post return new Scene2800(); case 2900: - error("Missing scene %d from group 2", sceneNumber); + // Balloon Cutscene + return new Scene2900(); + /* Scene group #3 */ - // + // ARM Base Hanager case 3100: return new Scene3100(); case 3125: @@ -247,34 +266,43 @@ Scene *Ringworld2Game::createScene(int sceneNumber) { // Room with large stasis field negator return new Scene3250(); case 3255: + // Guard Post return new Scene3255(); case 3260: - // Computer room + // ARM Base - Computer room return new Scene3260(); case 3275: - // Hall + // ARM Base - Hall return new Scene3275(); case 3350: // Cutscene - Ship landing return new Scene3350(); case 3375: + // Circular Walkway return new Scene3375(); case 3385: + // Corridor return new Scene3385(); case 3395: + // Walkway return new Scene3395(); case 3400: + // Confrontation return new Scene3400(); case 3500: + // Flub tube maze return new Scene3500(); case 3600: + // Cutscene - walking at gunpoint return new Scene3600(); case 3700: // Cutscene - Teleport outside return new Scene3700(); case 3800: + // Desert return new Scene3800(); case 3900: + // Forest Entrance return new Scene3900(); default: error("Unknown scene number - %d", sceneNumber); @@ -294,8 +322,11 @@ bool Ringworld2Game::canLoadGameStateCurrently() { * Returns true if it is currently okay to save the game */ bool Ringworld2Game::canSaveGameStateCurrently() { - // Don't allow a game to be saved if a dialog is active - return g_globals->_gfxManagers.size() == 1; + // Don't allow a game to be saved if a dialog is active, or if an animation + // is playing, or if an active scene prevents it + return g_globals->_gfxManagers.size() == 1 && R2_GLOBALS._animationCtr == 0 && + (!R2_GLOBALS._sceneManager._scene || + !((SceneExt *)R2_GLOBALS._sceneManager._scene)->_preventSaving); } /*--------------------------------------------------------------------------*/ @@ -305,12 +336,28 @@ SceneExt::SceneExt(): Scene() { _stripManager._onEnd = SceneExt::endStrip; for (int i = 0; i < 256; i++) - _field312[i] = 0; - _field372 = _field37A = 0; + _shadowPaletteMap[i] = 0; + _savedPlayerEnabled = false; _savedUiEnabled = false; _savedCanWalk = false; - _focusObject = NULL; + _preventSaving = false; + + // Reset screen clipping area + R2_GLOBALS._screenSurface._clipRect = Rect(); + + // WORKAROUND: In the original, playing animations don't reset the global _animationCtr + // counter as scene changes unless the playing animation explicitly finishes. For now, + // to make inter-scene debugging easier, I'm explicitly resetting the _animationCtr + // on scene start, since scene objects aren't drawn while it's non-zero + R2_GLOBALS._animationCtr = 0; +} + +void SceneExt::synchronize(Serializer &s) { + Scene::synchronize(s); + + s.syncBytes(&_shadowPaletteMap[0], 256); + _sceneAreas.synchronize(s); } void SceneExt::postInit(SceneObjectList *OwnerList) { @@ -319,18 +366,18 @@ void SceneExt::postInit(SceneObjectList *OwnerList) { // Exclude the bottom area of the screen to allow room for the UI T2_GLOBALS._interfaceY = UI_INTERFACE_Y; - // Initialise fields + // Initialize fields _action = NULL; _field12 = 0; _sceneMode = 0; + static_cast<SceneHandlerExt *>(R2_GLOBALS._sceneHandler)->setupPaletteMaps(); + int prevScene = R2_GLOBALS._sceneManager._previousScene; int sceneNumber = R2_GLOBALS._sceneManager._sceneNumber; if (((prevScene == -1) && (sceneNumber != 180) && (sceneNumber != 205) && (sceneNumber != 50)) || (sceneNumber == 50) - || ((prevScene == 205) && (sceneNumber == 100)) - || ((prevScene == 180) && (sceneNumber == 100))) { - static_cast<SceneHandlerExt *>(R2_GLOBALS._sceneHandler)->setupPaletteMaps(); + || ((sceneNumber == 100) && (prevScene == 0 || prevScene == 180 || prevScene == 205))) { R2_GLOBALS._uiElements._active = true; R2_GLOBALS._uiElements.show(); } else { @@ -341,6 +388,11 @@ void SceneExt::postInit(SceneObjectList *OwnerList) { void SceneExt::remove() { _sceneAreas.clear(); Scene::remove(); + R2_GLOBALS._uiElements._active = true; + + if (R2_GLOBALS._events.getCursor() >= EXITCURSOR_N && + R2_GLOBALS._events.getCursor() <= SHADECURSOR_DOWN) + R2_GLOBALS._events.setCursor(CURSOR_WALK); } void SceneExt::process(Event &event) { @@ -349,43 +401,9 @@ void SceneExt::process(Event &event) { } void SceneExt::dispatch() { -/* - _timerList.dispatch(); - - if (_field37A) { - if ((--_field37A == 0) && R2_GLOBALS._dayNumber) { - if (R2_GLOBALS._uiElements._active && R2_GLOBALS._player._enabled) { - R2_GLOBALS._uiElements.show(); - } - - _field37A = 0; - } - } -*/ Scene::dispatch(); } -void SceneExt::loadScene(int sceneNum) { - Scene::loadScene(sceneNum); - - _v51C34.top = 0; - _v51C34.bottom = 300; - - int prevScene = R2_GLOBALS._sceneManager._previousScene; - int sceneNumber = R2_GLOBALS._sceneManager._sceneNumber; - - if (((prevScene == -1) && (sceneNumber != 180) && (sceneNumber != 205) && (sceneNumber != 50)) || - (sceneNumber == 50) || ((prevScene == 205) && (sceneNumber == 100)) || - ((prevScene == 180) && (sceneNumber == 100))) { - // TODO: sub_17875 - R2_GLOBALS._uiElements._active = true; - R2_GLOBALS._uiElements.show(); - } else { - // Update the user interface - R2_GLOBALS._uiElements.updateInventory(); - } -} - bool SceneExt::display(CursorType action, Event &event) { switch (action) { case CURSOR_CROSSHAIRS: @@ -407,17 +425,19 @@ bool SceneExt::display(CursorType action, Event &event) { SceneItem::display2(5, 0); break; case R2_SONIC_STUNNER: - if ((R2_GLOBALS._v565F1[1] == 2) || ((R2_GLOBALS._v565F1[1] == 1) && - (R2_GLOBALS._v565F1[2] == 2) && (R2_GLOBALS._sceneManager._previousScene == 300))) { + if ((R2_GLOBALS._scannerFrequencies[R2_QUINN] == 2) + || ((R2_GLOBALS._scannerFrequencies[R2_QUINN] == 1) && + (R2_GLOBALS._scannerFrequencies[R2_SEEKER] == 2) && + (R2_GLOBALS._sceneManager._previousScene == 300))) { R2_GLOBALS._sound4.stop(); R2_GLOBALS._sound3.play(46); SceneItem::display2(5, 15); + + R2_GLOBALS._sound4.play(45); } else { R2_GLOBALS._sound3.play(43, 0); - SceneItem::display2(2, 0); + SceneItem::display2(2, R2_SONIC_STUNNER); } - - R2_GLOBALS._sound4.play(45); break; case R2_COM_SCANNER: case R2_COM_SCANNER_2: @@ -445,7 +465,6 @@ void SceneExt::fadeOut() { void SceneExt::startStrip() { SceneExt *scene = (SceneExt *)R2_GLOBALS._sceneManager._scene; - scene->_field372 = 1; scene->_savedPlayerEnabled = R2_GLOBALS._player._enabled; if (scene->_savedPlayerEnabled) { @@ -461,7 +480,6 @@ void SceneExt::startStrip() { void SceneExt::endStrip() { SceneExt *scene = (SceneExt *)R2_GLOBALS._sceneManager._scene; - scene->_field372 = 0; if (scene->_savedPlayerEnabled) { R2_GLOBALS._player.enableControl(); @@ -509,10 +527,12 @@ void SceneExt::refreshBackground(int xAmount, int yAmount) { assert(screenSize == (s.w * s.h)); // Copy the data - byte *destP = (byte *)s.getBasePtr(0, 0); + byte *destP = (byte *)s.getPixels(); Common::copy(dataP, dataP + (s.w * s.h), destP); _backSurface.unlockSurface(); + R2_GLOBALS._screenSurface.addDirtyRect(_backSurface.getBounds()); + // Free the resource data DEALLOCATE(dataP); } @@ -553,14 +573,24 @@ void SceneExt::scalePalette(int RFactor, int GFactor, int BFactor) { varC = tmp; varD = j; } - this->_field312[i] = varD; + this->_shadowPaletteMap[i] = varD; } } +void SceneExt::loadBlankScene() { + _backSurface.create(SCREEN_WIDTH, SCREEN_HEIGHT * 3 / 2); + _backSurface.fillRect(_backSurface.getBounds(), 0); + + R2_GLOBALS._screenSurface.fillRect(R2_GLOBALS._screenSurface.getBounds(), 0); +} + /*--------------------------------------------------------------------------*/ void SceneHandlerExt::postInit(SceneObjectList *OwnerList) { SceneHandler::postInit(OwnerList); + + if (!R2_GLOBALS._playStream.setFile("SND4K.RES")) + warning("Could not find SND4K.RES voice file"); } void SceneHandlerExt::process(Event &event) { @@ -573,7 +603,7 @@ void SceneHandlerExt::process(Event &event) { SceneExt *scene = static_cast<SceneExt *>(R2_GLOBALS._sceneManager._scene); if (scene && R2_GLOBALS._player._uiEnabled) { // Handle any scene areas that have been registered - SynchronizedList<SceneArea *>::iterator saIter; + SynchronizedList<EventHandler *>::iterator saIter; for (saIter = scene->_sceneAreas.begin(); saIter != scene->_sceneAreas.end() && !event.handled; ++saIter) { (*saIter)->process(event); } @@ -583,11 +613,31 @@ void SceneHandlerExt::process(Event &event) { SceneHandler::process(event); } +void SceneHandlerExt::postLoad(int priorSceneBeforeLoad, int currentSceneBeforeLoad) { + // Set up the shading maps used for showing the player in shadows + setupPaletteMaps(); + + if (currentSceneBeforeLoad == 2900) { + R2_GLOBALS._gfxFontNumber = 50; + R2_GLOBALS._gfxColors.background = 0; + R2_GLOBALS._gfxColors.foreground = 59; + R2_GLOBALS._fontColors.background = 4; + R2_GLOBALS._fontColors.foreground = 15; + R2_GLOBALS._frameEdgeColor = 2; + + R2_GLOBALS._scenePalette.loadPalette(0); + R2_GLOBALS._scenePalette.setEntry(255, 0xff, 0xff, 0xff); + R2_GLOBALS._fadePaletteFlag = false; + setupPaletteMaps(); + } +} + void SceneHandlerExt::setupPaletteMaps() { byte *palP = &R2_GLOBALS._scenePalette._palette[0]; - if (!R2_GLOBALS._v1000Flag) { - R2_GLOBALS._v1000Flag = true; + // Set up the mapping table for giving faded versions of pixels at different fade percentages + if (!R2_GLOBALS._fadePaletteFlag) { + R2_GLOBALS._fadePaletteFlag = true; for (int idx = 0; idx < 10; ++idx) { for (int palIndex = 0; palIndex < 224; ++palIndex) { @@ -617,7 +667,7 @@ void SceneHandlerExt::setupPaletteMaps() { break; } - // Scan for the palette index with the closest matching colour + // Scan for the palette index with the closest matching color int threshold = 769; int foundIndex = -1; for (int pIndex2 = 223; pIndex2 >= 0; --pIndex2) { @@ -637,18 +687,19 @@ void SceneHandlerExt::setupPaletteMaps() { foundIndex = pIndex2; } - R2_GLOBALS._palIndexList[idx][palIndex] = foundIndex; + R2_GLOBALS._fadePaletteMap[idx][palIndex] = foundIndex; } } } for (int palIndex = 0; palIndex < 224; ++palIndex) { - int r = palP[palIndex * 3] >> 2; - int g = palP[palIndex * 3 + 1] >> 2; - int b = palP[palIndex * 3 + 2] >> 2; + int r = palP[palIndex * 3] >> 4; + int g = palP[palIndex * 3 + 1] >> 4; + int b = palP[palIndex * 3 + 2] >> 4; - int idx = (((r << 4) | g) << 4) | b; - R2_GLOBALS._v1000[idx] = palIndex; + int v = (r << 8) | (g << 4) | b; + assert(v < 0x1000); + R2_GLOBALS._paletteMap[v] = palIndex; } int vdx = 0; @@ -656,9 +707,9 @@ void SceneHandlerExt::setupPaletteMaps() { int palIndex = 224; for (int vIndex = 0; vIndex < 4096; ++vIndex) { - int v = R2_GLOBALS._v1000[vIndex]; + int v = R2_GLOBALS._paletteMap[vIndex]; if (!v) { - R2_GLOBALS._v1000[vIndex] = idx; + R2_GLOBALS._paletteMap[vIndex] = idx; } else { idx = v; } @@ -733,113 +784,113 @@ bool DisplayObject::performAction(int action) { Ringworld2InvObjectList::Ringworld2InvObjectList(): _none(1, 1), - _inv1(1, 2), - _inv2(1, 3), + _optoDisk(1, 2), + _reader(1, 3), _negatorGun(1, 4), _steppingDisks(1, 5), - _inv5(1, 6), - _inv6(1, 7), - _inv7(1, 8), - _inv8(1, 9), - _inv9(1, 10), - _inv10(1, 11), - _inv11(1, 12), - _inv12(1, 13), - _inv13(1, 14), - _inv14(1, 15), - _inv15(1, 16), - _inv16(1, 17), - _inv17(2, 2), - _inv18(2, 3), - _inv19(2, 4), - _inv20(2, 5), - _inv21(2, 5), - _inv22(2, 6), - _inv23(2, 7), - _inv24(2, 8), - _inv25(2, 9), - _inv26(2, 10), - _inv27(2, 11), - _inv28(2, 12), - _inv29(2, 13), - _inv30(2, 14), - _inv31(2, 15), - _inv32(2, 16), - _inv33(3, 2), - _inv34(3, 3), - _inv35(3, 4), - _inv36(3, 5), - _inv37(3, 6), - _inv38(3, 7), - _inv39(1, 10), - _inv40(3, 8), - _inv41(3, 9), - _inv42(3, 10), - _inv43(3, 11), - _inv44(3, 12), - _inv45(3, 13), - _inv46(3, 17), - _inv47(3, 14), - _inv48(3, 14), - _inv49(3, 15), - _inv50(3, 15), - _inv51(3, 17), - _inv52(4, 2) { + _attractorUnit(1, 6), + _sensorProbe(1, 7), + _sonicStunner(1, 8), + _cableHarness(1, 9), + _comScanner(1, 10), + _spentPowerCapsule(1, 11), // 10 + _chargedPowerCapsule(1, 12), + _aerosol(1, 13), + _remoteControl(1, 14), + _opticalFibre(1, 15), + _clamp(1, 16), + _attractorHarness(1, 17), + _fuelCell(2, 2), + _gyroscope(2, 3), + _airbag(2, 4), + _rebreatherTank(2, 5), // 20 + _reserveTank(2, 5), + _guidanceModule(2, 6), + _thrusterValve(2, 7), + _balloonBackpack(2, 8), + _radarMechanism(2, 9), + _joystick(2, 10), + _ignitor(2, 11), + _diagnosticsDisplay(2, 12), + _glassDome(2, 13), + _wickLamp(2, 14), // 30 + _scrithKey(2, 15), + _tannerMask(2, 16), + _pureGrainAlcohol(3, 2), + _blueSapphire(3, 3), + _ancientScrolls(3, 4), + _flute(3, 5), + _gunpowder(3, 6), + _unused(3, 7), + _comScanner2(1, 10), + _superconductorWire(3, 8), // 40 + _pillow(3, 9), + _foodTray(3, 10), + _laserHacksaw(3, 11), + _photonStunner(3, 12), + _battery(3, 13), + _soakedFaceMask(2, 17), + _lightBulb(3, 14), + _alcoholLamp1(2, 14), + _alcoholLamp2(3, 15), + _alocholLamp3(3, 15), // 50 + _brokenDisplay(3, 17), + _toolbox(4, 2) { // Add the items to the list _itemList.push_back(&_none); - _itemList.push_back(&_inv1); - _itemList.push_back(&_inv2); + _itemList.push_back(&_optoDisk); + _itemList.push_back(&_reader); _itemList.push_back(&_negatorGun); _itemList.push_back(&_steppingDisks); - _itemList.push_back(&_inv5); - _itemList.push_back(&_inv6); - _itemList.push_back(&_inv7); - _itemList.push_back(&_inv8); - _itemList.push_back(&_inv9); - _itemList.push_back(&_inv10); - _itemList.push_back(&_inv11); - _itemList.push_back(&_inv12); - _itemList.push_back(&_inv13); - _itemList.push_back(&_inv14); - _itemList.push_back(&_inv15); - _itemList.push_back(&_inv16); - _itemList.push_back(&_inv17); - _itemList.push_back(&_inv18); - _itemList.push_back(&_inv19); - _itemList.push_back(&_inv20); - _itemList.push_back(&_inv21); - _itemList.push_back(&_inv22); - _itemList.push_back(&_inv23); - _itemList.push_back(&_inv24); - _itemList.push_back(&_inv25); - _itemList.push_back(&_inv26); - _itemList.push_back(&_inv27); - _itemList.push_back(&_inv28); - _itemList.push_back(&_inv29); - _itemList.push_back(&_inv30); - _itemList.push_back(&_inv31); - _itemList.push_back(&_inv32); - _itemList.push_back(&_inv33); - _itemList.push_back(&_inv34); - _itemList.push_back(&_inv35); - _itemList.push_back(&_inv36); - _itemList.push_back(&_inv37); - _itemList.push_back(&_inv38); - _itemList.push_back(&_inv39); - _itemList.push_back(&_inv40); - _itemList.push_back(&_inv41); - _itemList.push_back(&_inv42); - _itemList.push_back(&_inv43); - _itemList.push_back(&_inv44); - _itemList.push_back(&_inv45); - _itemList.push_back(&_inv46); - _itemList.push_back(&_inv47); - _itemList.push_back(&_inv48); - _itemList.push_back(&_inv49); - _itemList.push_back(&_inv50); - _itemList.push_back(&_inv51); - _itemList.push_back(&_inv52); + _itemList.push_back(&_attractorUnit); + _itemList.push_back(&_sensorProbe); + _itemList.push_back(&_sonicStunner); + _itemList.push_back(&_cableHarness); + _itemList.push_back(&_comScanner); + _itemList.push_back(&_spentPowerCapsule); // 10 + _itemList.push_back(&_chargedPowerCapsule); + _itemList.push_back(&_aerosol); + _itemList.push_back(&_remoteControl); + _itemList.push_back(&_opticalFibre); + _itemList.push_back(&_clamp); + _itemList.push_back(&_attractorHarness); + _itemList.push_back(&_fuelCell); + _itemList.push_back(&_gyroscope); + _itemList.push_back(&_airbag); + _itemList.push_back(&_rebreatherTank); // 20 + _itemList.push_back(&_reserveTank); + _itemList.push_back(&_guidanceModule); + _itemList.push_back(&_thrusterValve); + _itemList.push_back(&_balloonBackpack); + _itemList.push_back(&_radarMechanism); + _itemList.push_back(&_joystick); + _itemList.push_back(&_ignitor); + _itemList.push_back(&_diagnosticsDisplay); + _itemList.push_back(&_glassDome); + _itemList.push_back(&_wickLamp); // 30 + _itemList.push_back(&_scrithKey); + _itemList.push_back(&_tannerMask); + _itemList.push_back(&_pureGrainAlcohol); + _itemList.push_back(&_blueSapphire); + _itemList.push_back(&_ancientScrolls); + _itemList.push_back(&_flute); + _itemList.push_back(&_gunpowder); + _itemList.push_back(&_unused); + _itemList.push_back(&_comScanner2); + _itemList.push_back(&_superconductorWire); // 40 + _itemList.push_back(&_pillow); + _itemList.push_back(&_foodTray); + _itemList.push_back(&_laserHacksaw); + _itemList.push_back(&_photonStunner); + _itemList.push_back(&_battery); + _itemList.push_back(&_soakedFaceMask); + _itemList.push_back(&_lightBulb); + _itemList.push_back(&_alcoholLamp1); + _itemList.push_back(&_alcoholLamp2); + _itemList.push_back(&_alocholLamp3); // 50 + _itemList.push_back(&_brokenDisplay); + _itemList.push_back(&_toolbox); _selectedItem = NULL; } @@ -904,6 +955,9 @@ void Ringworld2InvObjectList::reset() { setObjectScene(R2_ALCOHOL_LAMP_3, 2435); setObjectScene(R2_BROKEN_DISPLAY, 1580); setObjectScene(R2_TOOLBOX, 3260); + + // Set up the select item handler method + T2_GLOBALS._onSelectItem = SelectItem; } void Ringworld2InvObjectList::setObjectScene(int objectNum, int sceneNumber) { @@ -918,7 +972,129 @@ void Ringworld2InvObjectList::setObjectScene(int objectNum, int sceneNumber) { R2_GLOBALS._events.setCursor(CURSOR_USE); // Update the user interface if necessary - T2_GLOBALS._uiElements.updateInventory(); + T2_GLOBALS._uiElements.updateInventory( + (sceneNumber == R2_GLOBALS._player._characterIndex) ? objectNum : 0); +} + +/** + * When an inventory item is selected, in Return to Ringworld two objects can be combined + */ +bool Ringworld2InvObjectList::SelectItem(int objectNumber) { + // If no existing item selected, don't go any further + int currentItem = R2_GLOBALS._events.getCursor(); + if (currentItem >= 256) + return false; + + switch (objectNumber) { + case R2_NEGATOR_GUN: + switch (currentItem) { + case R2_SENSOR_PROBE: + if (R2_GLOBALS.getFlag(1)) + SceneItem::display2(5, 1); + else if (R2_INVENTORY.getObjectScene(R2_SPENT_POWER_CAPSULE) != 100) + SceneItem::display2(5, 3); + else { + R2_GLOBALS._sound3.play(48); + SceneItem::display2(5, 2); + R2_INVENTORY.setObjectScene(R2_SPENT_POWER_CAPSULE, 1); + } + break; + case R2_COM_SCANNER: + R2_GLOBALS._sound3.play(44); + if (R2_GLOBALS.getFlag(1)) + SceneItem::display2(5, 9); + else if (R2_INVENTORY.getObjectScene(R2_SPENT_POWER_CAPSULE) == 100) + SceneItem::display2(5, 8); + else + SceneItem::display2(5, 10); + + R2_GLOBALS._sound3.stop(); + break; + case R2_CHARGED_POWER_CAPSULE: + if (R2_INVENTORY.getObjectScene(R2_SPENT_POWER_CAPSULE) == 1) { + R2_GLOBALS._sound3.play(49); + R2_INVENTORY.setObjectScene(R2_CHARGED_POWER_CAPSULE, 100); + R2_GLOBALS.setFlag(1); + SceneItem::display2(5, 4); + } else { + SceneItem::display2(5, 5); + } + break; + default: + selectDefault(objectNumber); + break; + } + break; + case R2_STEPPING_DISKS: + switch (currentItem) { + case R2_SENSOR_PROBE: + if (R2_INVENTORY.getObjectScene(R2_CHARGED_POWER_CAPSULE) == 400) { + R2_GLOBALS._sound3.play(48); + SceneItem::display2(5, 6); + R2_INVENTORY.setObjectScene(R2_CHARGED_POWER_CAPSULE, 1); + } else { + SceneItem::display2(5, 7); + } + break; + case R2_COM_SCANNER: + R2_GLOBALS._sound3.play(44); + if (R2_INVENTORY.getObjectScene(R2_CHARGED_POWER_CAPSULE) == 400) + SceneItem::display2(5, 16); + else + SceneItem::display2(5, 17); + R2_GLOBALS._sound3.stop(); + break; + default: + selectDefault(objectNumber); + break; + } + break; + case R2_ATTRACTOR_UNIT: + case R2_CABLE_HARNESS: + if (currentItem == R2_CABLE_HARNESS || + currentItem == R2_ATTRACTOR_UNIT) { + R2_INVENTORY.setObjectScene(R2_CABLE_HARNESS, 0); + R2_INVENTORY.setObjectScene(R2_ATTRACTOR_UNIT, 0); + R2_INVENTORY.setObjectScene(R2_ATTRACTOR_CABLE_HARNESS, 1); + } else { + selectDefault(objectNumber); + } + break; + case R2_TANNER_MASK: + case R2_PURE_GRAIN_ALCOHOL: + if (currentItem == R2_TANNER_MASK || + currentItem == R2_PURE_GRAIN_ALCOHOL) { + R2_INVENTORY.setObjectScene(R2_TANNER_MASK, 0); + R2_INVENTORY.setObjectScene(R2_PURE_GRAIN_ALCOHOL, 0); + R2_INVENTORY.setObjectScene(R2_SOAKED_FACEMASK, R2_SEEKER); + } else { + selectDefault(objectNumber); + } + break; + default: + // Standard item selection + return false; + } + + return true; +} + +void Ringworld2InvObjectList::selectDefault(int objectNumber) { + Common::String msg1 = g_resourceManager->getMessage(4, 53); + Common::String msg2 = g_resourceManager->getMessage(4, R2_GLOBALS._events.getCursor()); + Common::String msg3 = g_resourceManager->getMessage(4, 54); + Common::String msg4 = g_resourceManager->getMessage(4, objectNumber); + Common::String line = Common::String::format("%.5s%.5s%.5s%.5s%s %s %s %s.", + msg1.c_str(), msg2.c_str(), msg3.c_str(), msg4.c_str(), + msg1.c_str() + 5, msg2.c_str() + 5, msg3.c_str() + 5, msg4.c_str() + 5); + + SceneItem::display(-1, -1, line.c_str(), + SET_WIDTH, 280, + SET_X, 160, + SET_Y, 20, + SET_POS_MODE, 1, + SET_EXT_BGCOLOR, 7, + LIST_END); } /*--------------------------------------------------------------------------*/ @@ -939,19 +1115,31 @@ void Ringworld2Game::start() { if (slot >= 0) R2_GLOBALS._sceneHandler->_loadGameSlot = slot; else { - // Switch to the first game scene + // Switch to the first title screen R2_GLOBALS._events.setCursor(CURSOR_WALK); R2_GLOBALS._uiElements._active = true; - R2_GLOBALS._sceneManager.setNewScene(100); + R2_GLOBALS._sceneManager.setNewScene(180); } g_globals->_events.showCursor(); } +void Ringworld2Game::restartGame() { + if (MessageDialog::show(Ringworld2::R2_RESTART_MSG, CANCEL_BTN_STRING, YES_MSG) == 1) + restart(); +} + void Ringworld2Game::restart() { g_globals->_scenePalette.clearListeners(); g_globals->_soundHandler.stop(); + // Reset the globals + g_globals->reset(); + + // Clear save/load slots + g_globals->_sceneHandler->_saveGameSlot = -1; + g_globals->_sceneHandler->_loadGameSlot = -1; + // Change to the first game scene g_globals->_sceneManager.changeScene(100); } @@ -1008,25 +1196,25 @@ void Ringworld2Game::processEvent(Event &event) { case Common::KEYCODE_F4: // F4 - Restart restartGame(); - g_globals->_events.setCursorFromFlag(); + R2_GLOBALS._events.setCursorFromFlag(); break; case Common::KEYCODE_F7: // F7 - Restore restoreGame(); - g_globals->_events.setCursorFromFlag(); + R2_GLOBALS._events.setCursorFromFlag(); break; case Common::KEYCODE_F8: // F8 - Credits - warning("TODO: Show Credits"); + R2_GLOBALS._sceneManager.changeScene(205); break; case Common::KEYCODE_F10: // F10 - Pause GfxDialog::setPalette(); MessageDialog::show(GAME_PAUSED_MSG, OK_BTN_STRING); - g_globals->_events.setCursorFromFlag(); + R2_GLOBALS._events.setCursorFromFlag(); break; default: @@ -1037,8 +1225,13 @@ void Ringworld2Game::processEvent(Event &event) { void Ringworld2Game::rightClick() { RightClickDialog *dlg = new RightClickDialog(); - dlg->execute(); + int option = dlg->execute(); delete dlg; + + if (option == 0) + CharacterDialog::show(); + else if (option == 1) + HelpDialog::show(); } /*--------------------------------------------------------------------------*/ @@ -1083,6 +1276,14 @@ void SceneActor::postInit(SceneObjectList *OwnerList) { SceneObject::postInit(); } +void SceneActor::remove() { + R2_GLOBALS._sceneItems.remove(this); + _shadowMap = NULL; + _linkedActor = NULL; + + SceneObject::remove(); +} + bool SceneActor::startAction(CursorType action, Event &event) { bool handled = true; @@ -1115,13 +1316,20 @@ bool SceneActor::startAction(CursorType action, Event &event) { return handled; } +GfxSurface SceneActor::getFrame() { + GfxSurface frame = SceneObject::getFrame(); + + return frame; +} + /*--------------------------------------------------------------------------*/ -SceneArea::SceneArea(): EventHandler() { +SceneArea::SceneArea(): SceneItem() { _enabled = true; _insideArea = false; _savedCursorNum = CURSOR_NONE; _cursorState = 0; + _cursorNum = CURSOR_NONE; } void SceneArea::synchronize(Serializer &s) { @@ -1130,8 +1338,8 @@ void SceneArea::synchronize(Serializer &s) { _bounds.synchronize(s); s.syncAsSint16LE(_enabled); s.syncAsSint16LE(_insideArea); - s.syncAsSint16LE(_cursorNum); - s.syncAsSint16LE(_savedCursorNum); + s.syncAsSint32LE(_cursorNum); + s.syncAsSint32LE(_savedCursorNum); s.syncAsSint16LE(_cursorState); } @@ -1140,10 +1348,13 @@ void SceneArea::remove() { } void SceneArea::process(Event &event) { + Common::Point mousePos = event.mousePos; + mousePos.x += R2_GLOBALS._sceneManager._scene->_sceneBounds.left; + if (!R2_GLOBALS._insetUp && _enabled && R2_GLOBALS._events.isCursorVisible()) { CursorType cursor = R2_GLOBALS._events.getCursor(); - if (_bounds.contains(event.mousePos)) { + if (_bounds.contains(mousePos)) { // Cursor moving in bounded area if (cursor != _cursorNum) { _savedCursorNum = cursor; @@ -1151,7 +1362,7 @@ void SceneArea::process(Event &event) { R2_GLOBALS._events.setCursor(_cursorNum); } _insideArea = true; - } else if ((event.mousePos.y < 171) && _insideArea && (_cursorNum == cursor) && + } else if ((mousePos.y < 171) && _insideArea && (_cursorNum == cursor) && (_savedCursorNum != CURSOR_NONE)) { // Cursor moved outside bounded area R2_GLOBALS._events.setCursor(_savedCursorNum); @@ -1171,6 +1382,8 @@ void SceneArea::setDetails(const Rect &bounds, CursorType cursor) { SceneExit::SceneExit(): SceneArea() { _moving = false; _destPos = Common::Point(-1, -1); + + _sceneNumber = 0; } void SceneExit::synchronize(Serializer &s) { @@ -1191,20 +1404,23 @@ void SceneExit::changeScene() { } void SceneExit::process(Event &event) { + Common::Point mousePos = event.mousePos; + mousePos.x += R2_GLOBALS._sceneManager._scene->_sceneBounds.left; + if (!R2_GLOBALS._insetUp) { SceneArea::process(event); if (_enabled) { if (event.eventType == EVENT_BUTTON_DOWN) { - if (!_bounds.contains(event.mousePos)) + if (!_bounds.contains(mousePos)) _moving = false; else if (!R2_GLOBALS._player._canWalk) { _moving = false; changeScene(); event.handled = true; } else { - Common::Point dest((_destPos.x == -1) ? event.mousePos.x : _destPos.x, - (_destPos.y == -1) ? event.mousePos.y : _destPos.y); + Common::Point dest((_destPos.x == -1) ? mousePos.x : _destPos.x, + (_destPos.y == -1) ? mousePos.y : _destPos.y); ADD_PLAYER_MOVER(dest.x, dest.y); _moving = true; @@ -1221,6 +1437,7 @@ void SceneExit::process(Event &event) { /*--------------------------------------------------------------------------*/ void SceneAreaObject::remove() { + R2_GLOBALS._sceneItems.remove(this); _object1.remove(); SceneArea::remove(); --R2_GLOBALS._insetUp; @@ -1230,19 +1447,22 @@ void SceneAreaObject::process(Event &event) { if (_insetCount == R2_GLOBALS._insetUp) { CursorType cursor = R2_GLOBALS._events.getCursor(); - if (_bounds.contains(event.mousePos)) { + if (_object1._bounds.contains(event.mousePos)) { // Cursor moving in bounded area if (cursor == _cursorNum) { R2_GLOBALS._events.setCursor(_savedCursorNum); } } else if (event.mousePos.y < 168) { - if (_cursorNum != cursor) + if (_cursorNum != cursor) { // Cursor moved outside bounded area - R2_GLOBALS._events.setCursor(_savedCursorNum); + _savedCursorNum = R2_GLOBALS._events.getCursor(); + R2_GLOBALS._events.setCursor(CURSOR_INVALID); + } if (event.eventType == EVENT_BUTTON_DOWN) { - R2_GLOBALS._events.setCursor(_savedCursorNum); event.handled = true; + R2_GLOBALS._events.setCursor(_savedCursorNum); + remove(); } } } @@ -1262,293 +1482,214 @@ void SceneAreaObject::setDetails(int visage, int strip, int frameNumber, const C } void SceneAreaObject::setDetails(int resNum, int lookLineNum, int talkLineNum, int useLineNum) { - ((SceneHotspot *)(this))->setDetails(resNum, lookLineNum, talkLineNum, useLineNum, + _object1.setDetails(resNum, lookLineNum, talkLineNum, useLineNum, 2, (SceneItem *)NULL); } /*****************************************************************************/ -UnkObject1200::UnkObject1200() { - _field16 = _field3A = NULL; - _field12 = _field14 = 0; - _field26 = _field28 = _field2A = _field2C = _field2E = _field30 = 0; - _field32 = _field34 = _field36 = _field38 = _field3E = _field40 = 0; +MazeUI::MazeUI() { + _mapData = NULL; + _cellsVisible.x = _cellsVisible.y = 0; + _mapCells.x = _mapCells.y = 0; + _cellSize.x = _cellSize.y = 0; + _mapOffset.x = _mapOffset.y = 0; + _resNum = _cellsResNum = 0; + _frameCount = _resCount = _mapImagePitch = 0; } -void UnkObject1200::synchronize(Serializer &s) { - SavedObject::synchronize(s); +MazeUI::~MazeUI() { + DEALLOCATE(_mapData); +} - _rect1.synchronize(s); - _rect2.synchronize(s); +void MazeUI::synchronize(Serializer &s) { + SceneObject::synchronize(s); - // FIXME: syncrhonize _field16 and _field3A + s.syncAsSint16LE(_resNum); + if (s.isLoading()) + load(_resNum); - s.syncAsSint16LE(_field12); - s.syncAsSint16LE(_field14); - s.syncAsSint16LE(_field26); - s.syncAsSint16LE(_field28); - s.syncAsSint16LE(_field2A); - s.syncAsSint16LE(_field2C); - s.syncAsSint16LE(_field2E); - s.syncAsSint16LE(_field30); - s.syncAsSint16LE(_field32); - s.syncAsSint16LE(_field34); - s.syncAsSint16LE(_field36); - s.syncAsSint16LE(_field38); - s.syncAsSint16LE(_field3E); - s.syncAsSint16LE(_field40); -} + s.syncAsSint16LE(_mapOffset.x); + s.syncAsSint16LE(_mapOffset.y); -void UnkObject1200::sub51AE9(int arg1) { - warning("STUB: UnkObject1200::sub51AE9()"); + int dummy = 0; + s.syncAsSint16LE(dummy); } -int UnkObject1200::sub51AF8(Common::Point pt) { - if (!_rect1.contains(pt)) - return -1; +void MazeUI::load(int resNum) { + clear(); + _resNum = resNum; - int tmp1 = (pt.x - _rect1.left + _field2E) / _field2A; - int tmp2 = (pt.y - _rect1.top + _field30) / _field2C; + const byte *header = g_resourceManager->getResource(RT17, resNum, 0); - if ((tmp1 >= 0) && (tmp2 >= 0) && (_field26 > tmp1) && (_field28 > tmp2)) - return _field16[(((_field26 * tmp2) + tmp1)* 2)]; + _cellsResNum = resNum + 1000; + _mapCells.x = READ_LE_UINT16(header + 2); + _mapCells.y = READ_LE_UINT16(header + 4); + _frameCount = 10; + _resCount = _frameCount << 3; - return -1; + Visage visage; + visage.setVisage(_cellsResNum, 1); + + GfxSurface frame = visage.getFrame(2); + _cellSize.x = frame.getBounds().width(); + _cellSize.y = frame.getBounds().height(); + + _mapData = g_resourceManager->getResource(RT17, resNum, 1); + + _mapOffset.y = _mapOffset.x = 0; + _cellsVisible.x = (_bounds.width() + _cellSize.x - 1) / _cellSize.x; + _cellsVisible.y = (_bounds.height() + _cellSize.y - 1) / _cellSize.y; + + _mapImagePitch = (_cellsVisible.x + 1) * _cellSize.x; + _mapImage.create(_mapImagePitch, _cellSize.y); + + _mapBounds = Rect(0, 0, _cellSize.x * _mapCells.x, _cellSize.y * _mapCells.y); } -bool UnkObject1200::sub51AFD(Common::Point pt) { - int retval = false; +void MazeUI::clear() { + if (!_resNum) + _resNum = 1; - _field2E = pt.x; - _field30 = pt.y; + if (_mapData) + DEALLOCATE(_mapData); + _mapData = NULL; - if (_field2E < _rect2.top) { - _field2E = _rect2.top; + _mapImage.clear(); +} + +bool MazeUI::setMazePosition(const Common::Point &pt) { + bool retval = false; + + _mapOffset = pt; + + if (_mapOffset.x < _mapBounds.top) { + _mapOffset.x = _mapBounds.top; retval = true; } - if (_field30 < _rect2.left) { - _field30 = _rect2.left; + if (_mapOffset.y < _mapBounds.left) { + _mapOffset.y = _mapBounds.left; retval = true; } - if (_field2E + _rect1.width() > _rect2.right) { - _field2E = _rect2.right - _rect1.width(); + if (_mapOffset.x + _bounds.width() > _mapBounds.right) { + _mapOffset.x = _mapBounds.right - _bounds.width(); retval = true; } - if (_field30 + _rect1.height() > _rect2.bottom) { - _field30 = _rect2.bottom - _rect1.height(); + if (_mapOffset.y + _bounds.height() > _mapBounds.bottom) { + _mapOffset.y = _mapBounds.bottom - _bounds.height(); retval = true; } return retval; } -void UnkObject1200::sub51B02() { - warning("STUB: UnkObject1200::sub51B02()"); +void MazeUI::reposition() { } -void UnkObject1200::sub9EDE8(Rect rect) { - _rect1 = rect; - warning("FIXME: UnkObject1200::sub9EDE8()"); -// _rect1.clip(g_globals->gfxManager()._bounds); -} +void MazeUI::draw() { + int yPos = 0; + int ySize; + Visage visage; -int UnkObject1200::sub9EE22(int &arg1, int &arg2) { - arg1 /= _field2A; - arg2 /= _field2C; + _cellsVisible.y = ((_mapOffset.y % _cellSize.y) + _bounds.height() + + (_cellSize.y - 1)) / _cellSize.y; - if ((arg1 >= 0) && (arg2 >= 0) && (_field26 > arg1) && (_field28 > arg2)) { - return _field16[(((_field26 * arg2) + arg1) * 2)]; - } + // Loop to handle the cell rows of the visible display area one at a time + for (int yCtr = 0; yCtr <= _cellsVisible.y; ++yCtr, yPos += ySize) { + int cellY = _mapOffset.y / _cellSize.y + yCtr; - return -1; -} + // Loop to iterate through the horizontal visible cells to build up + // an entire cell high horizontal slice of the map, plus one extra cell + // to allow for partial cell scrolling on-screen on the left/right sides + for (int xCtr = 0; xCtr <= _cellsVisible.x; ++xCtr) { + int cellX = _mapOffset.x / _cellSize.x + xCtr; -void Scene1200::sub9DAD6(int indx) { - _object1.sub9EE22(R2_GLOBALS._v56AA2, R2_GLOBALS._v56AA4); + // Get the type of content to display in the cell + int cell = getCellFromCellXY(Common::Point(cellX, cellY)) - 1; + if (cell >= 0) { + int frameNum = (cell % _frameCount) + 1; + int rlbNum = (cell % _resCount) / _frameCount + 1; + int resNum = _cellsResNum + (cell / _resCount); - switch (indx) { - case 0: - if ( ((_object1.sub51AF8(Common::Point(200, 50)) > 36) || (_object1.sub51AF8(Common::Point(200, 88)) > 36)) - && ( ((R2_GLOBALS._v56AA2 == 3) && (R2_GLOBALS._v56AA4 == 33) && (_field418 != 4)) - || ((R2_GLOBALS._v56AA2 == 13) && (R2_GLOBALS._v56AA4 == 21) && (_field418 != 2)) - || ((R2_GLOBALS._v56AA2 == 29) && (R2_GLOBALS._v56AA4 == 17) && (_field418 != 1)) - || ((R2_GLOBALS._v56AA2 == 33) && (R2_GLOBALS._v56AA4 == 41)) ) - ) { - R2_GLOBALS._player.disableControl(); - _sceneMode = 1200; - setAction(&_sequenceManager, this, 1200, &_actor1, NULL); - } else if (_object1.sub51AF8(Common::Point(200, 69)) == 36) { - switch (_field412 - 1) { - case 0: - if (R2_GLOBALS._player._visage == 3155) - _sceneMode = 15; - else - _sceneMode = 10; - break; - case 1: - if (R2_GLOBALS._player._visage == 3156) - _sceneMode = 76; - else - _sceneMode = 75; - break; - case 2: - if (R2_GLOBALS._player._visage == 3156) - _sceneMode = 101; - else - _sceneMode = 100; - break; - case 3: - if (R2_GLOBALS._player._visage == 3156) - _sceneMode = 111; - else - _sceneMode = 110; - break; - default: - break; - } - R2_GLOBALS._player.disableControl(); - _field412 = 1; - signal(); - } - break; - case 1: - if ( ((_object1.sub51AF8(Common::Point(120, 50)) > 36) || (_object1.sub51AF8(Common::Point(120, 88)) > 36)) - && ( ((R2_GLOBALS._v56AA2 == 7) && (R2_GLOBALS._v56AA4 == 33) && (_field418 != 4)) - || ((R2_GLOBALS._v56AA2 == 17) && (R2_GLOBALS._v56AA4 == 21) && (_field418 != 2)) - || ((R2_GLOBALS._v56AA2 == 33) && (R2_GLOBALS._v56AA4 == 17) && (_field418 != 1)) - || ((R2_GLOBALS._v56AA2 == 5) && (R2_GLOBALS._v56AA4 == 5)) ) - ) { - R2_GLOBALS._player.disableControl(); - _sceneMode = 1201; - setAction(&_sequenceManager, this, 1201, &_actor1, NULL); - } else if (_object1.sub51AF8(Common::Point(120, 69)) == 36) { - switch (_field412 - 1) { - case 0: - if (R2_GLOBALS._player._visage == 3156) - _sceneMode = 56; - else - _sceneMode = 55; - break; - case 1: - if (R2_GLOBALS._player._visage == 3155) - _sceneMode = 25; - else - _sceneMode = 20; - break; - case 2: - if (R2_GLOBALS._player._visage == 3156) - _sceneMode = 91; - else - _sceneMode = 90; - break; - case 3: - if (R2_GLOBALS._player._visage == 3156) - _sceneMode = 121; - else - _sceneMode = 120; - break; - default: - break; - } - R2_GLOBALS._player.disableControl(); - _field412 = 2; - signal(); - } - break; - case 2: - if ( ((_object1.sub51AF8(Common::Point(140, 110)) > 36) || (_object1.sub51AF8(Common::Point(178, 110)) > 36)) - && ( ((R2_GLOBALS._v56AA2 == 17) && (R2_GLOBALS._v56AA4 == 5) && (_field418 != 3)) - || ((R2_GLOBALS._v56AA2 == 41) && (R2_GLOBALS._v56AA4 == 21)) ) - ) { - R2_GLOBALS._player.disableControl(); - _sceneMode = 1203; - setAction(&_sequenceManager, this, 1203, &_actor1, NULL); - } else if (_object1.sub51AF8(Common::Point(160, 110)) == 36) { - switch (_field412 - 1) { - case 0: - if (R2_GLOBALS._player._visage == 3156) - _sceneMode = 51; - else - _sceneMode = 50; - break; - case 1: - if (R2_GLOBALS._player._visage == 3156) - _sceneMode = 81; - else - _sceneMode = 80; - break; - case 2: - if (R2_GLOBALS._player._visage == 3155) - _sceneMode = 35; - else - _sceneMode = 30; - break; - case 3: - if (R2_GLOBALS._player._visage == 3156) - _sceneMode = 116; - else - _sceneMode = 115; - break; - default: - break; + visage.setVisage(resNum, rlbNum); + GfxSurface frame = visage.getFrame(frameNum); + + _mapImage.copyFrom(frame, xCtr * _cellSize.x, 0); + } else { + GfxSurface emptyRect; + emptyRect.create(_cellSize.x, _cellSize.y); + + _mapImage.copyFrom(emptyRect, xCtr * _cellSize.x, 0); } - R2_GLOBALS._player.disableControl(); - _field412 = 3; - signal(); } - break; - case 3: - if ( ((_object1.sub51AF8(Common::Point(140, 30)) > 36) || (_object1.sub51AF8(Common::Point(178, 30)) > 36)) - && ( ((R2_GLOBALS._v56AA2 == 17) && (R2_GLOBALS._v56AA4 == 9) && (_field418 != 3)) - || ((R2_GLOBALS._v56AA2 == 35) && (R2_GLOBALS._v56AA4 == 17)) ) - ) { - R2_GLOBALS._player.disableControl(); - _sceneMode = 1202; - setAction(&_sequenceManager, this, 1202, &_actor1, NULL); - } else if (_object1.sub51AF8(Common::Point(160, 30)) == 36) { - switch (_field412 - 1) { - case 0: - if (R2_GLOBALS._player._visage == 3156) - _sceneMode = 61; - else - _sceneMode = 60; - break; - case 1: - if (R2_GLOBALS._player._visage == 3156) - _sceneMode = 71; - else - _sceneMode = 70; - break; - case 2: - if (R2_GLOBALS._player._visage == 3156) - _sceneMode = 96; - else - _sceneMode = 95; - break; - case 3: - if (R2_GLOBALS._player._visage == 3155) - _sceneMode = 45; - else - _sceneMode = 40; - break; - default: - _sceneMode = 1; - R2_GLOBALS._player.setup(3156, 4, 6); - break; + + if (yPos == 0) { + // First line of the map to be displayed - only the bottom portion of that + // first cell row may be visible + yPos = _bounds.top; + ySize = _cellSize.y - (_mapOffset.y % _cellSize.y); + + Rect srcBounds(_mapOffset.x % _cellSize.x, _mapOffset.y % _cellSize.y, + (_mapOffset.x % _cellSize.x) + _bounds.width(), _cellSize.y); + Rect destBounds(_bounds.left, yPos, _bounds.right, yPos + ySize); + + R2_GLOBALS.gfxManager().copyFrom(_mapImage, srcBounds, destBounds); + } else { + if ((yPos + _cellSize.y) < _bounds.bottom) { + ySize = _cellSize.y; + } else { + ySize = _bounds.bottom - yPos; } - R2_GLOBALS._player.disableControl(); - _field412 = 4; - signal(); + + Rect srcBounds(_mapOffset.x % _cellSize.x, 0, + (_mapOffset.x % _cellSize.x) + _bounds.width(), ySize); + Rect destBounds(_bounds.left, yPos, _bounds.right, yPos + ySize); + + R2_GLOBALS.gfxManager().copyFrom(_mapImage, srcBounds, destBounds); } - break; - default: - break; } } +int MazeUI::getCellFromPixelXY(const Common::Point &pt) { + if (!_bounds.contains(pt)) + return -1; + + int cellX = (pt.x - _bounds.left + _mapOffset.x) / _cellSize.x; + int cellY = (pt.y - _bounds.top + _mapOffset.y) / _cellSize.y; + + if ((cellX >= 0) && (cellY >= 0) && (cellX < _mapCells.x) && (cellY < _mapCells.y)) + return (int16)READ_LE_UINT16(_mapData + (_mapCells.x * cellY + cellX) * 2); + + return -1; +} + +int MazeUI::getCellFromCellXY(const Common::Point &p) { + if (p.x < 0 || p.y < 0 || p.x >= _mapCells.x || p.y >= _mapCells.y) { + return -1; + } else { + return (int16)READ_LE_UINT16(_mapData + (_mapCells.x * p.y + p.x) * 2); + } +} + +int MazeUI::pixelToCellXY(Common::Point &pt) { + pt.x /= _cellSize.x; + pt.y /= _cellSize.y; + + if ((pt.x >= 0) && (pt.y >= 0) && (pt.x < _mapCells.x) && (pt.y < _mapCells.y)) { + return (int16)READ_LE_UINT16(_mapData + (_mapCells.x * pt.y + pt.x) * 2); + } + + return -1; +} + +void MazeUI::setDisplayBounds(const Rect &r) { + _bounds = r; + _bounds.clip(g_globals->gfxManager()._bounds); +} + /*--------------------------------------------------------------------------*/ void AnimationSlice::load(Common::File &f) { @@ -1563,6 +1704,12 @@ void AnimationSlice::load(Common::File &f) { AnimationSlices::AnimationSlices() { _pixelData = NULL; + + _dataSize = 0; + _dataSize2 = 0; + _slices->_sliceOffset = 0; + _slices->_drawMode = 0; + _slices->_secondaryIndex = 0; } AnimationSlices::~AnimationSlices() { @@ -1624,10 +1771,21 @@ AnimationPlayer::AnimationPlayer(): EventHandler() { _screenBounds = R2_GLOBALS._gfxManagerInstance._bounds; _rect1 = R2_GLOBALS._gfxManagerInstance._bounds; _paletteMode = ANIMPALMODE_REPLACE_PALETTE; - _field3A = 1; + _canSkip = true; _sliceHeight = 1; - _field58 = 1; _endAction = NULL; + + _sliceCurrent = nullptr; + _sliceNext = nullptr; + _animLoaded = false; + _objectMode = ANIMOBJMODE_1; + _dataNeeded = 0; + _playbackTick = 0; + _playbackTickPrior = 0; + _position = 0; + _nextSlicesPosition = 0; + _frameDelay = 0; + _gameFrame = 0; } AnimationPlayer::~AnimationPlayer() { @@ -1637,7 +1795,9 @@ AnimationPlayer::~AnimationPlayer() { void AnimationPlayer::synchronize(Serializer &s) { EventHandler::synchronize(s); - warning("TODO AnimationPlayer::load"); + + // TODO: Implement saving for animation player state. Currently, I disable saving + // when an animation is active, so saving it's state would a "nice to have". } void AnimationPlayer::remove() { @@ -1648,8 +1808,7 @@ void AnimationPlayer::remove() { } void AnimationPlayer::process(Event &event) { - if ((event.eventType == EVENT_KEYPRESS) && (event.kbd.keycode == Common::KEYCODE_ESCAPE) && - (_field3A)) { + if ((event.eventType == EVENT_KEYPRESS) && (event.kbd.keycode == Common::KEYCODE_ESCAPE) && _canSkip) { // Move the current position to the end _position = _subData._duration; } @@ -1695,11 +1854,13 @@ bool AnimationPlayer::load(int animId, Action *endAction) { _playbackTickPrior = -1; _playbackTick = 0; - // The final multiplication is used to deliberately slow down playback, since the original - // was slowed down by the amount of time spent to decode and display the frames - _frameDelay = (60 / _subData._frameRate) * 8; + _frameDelay = (60 / _subData._frameRate); _gameFrame = R2_GLOBALS._events.getFrameNumber(); + // WORKAROUND: Slow down the title sequences to better match the original + if (animId <= 4 || animId == 15) + _frameDelay *= 8; + if (_subData._totalSize) { _dataNeeded = _subData._totalSize; } else { @@ -1755,7 +1916,7 @@ bool AnimationPlayer::load(int animId, Action *endAction) { default: // ANIMPALMODE_CURR_PALETTE - // Use the closest matching colours in the currently active palette to those specified in the animation + // Use the closest matching colors in the currently active palette to those specified in the animation for (int idx = _subData._palStart; idx < (_subData._palStart + _subData._palSize); ++idx) { byte r = _subData._palData[idx * 3]; byte g = _subData._palData[idx * 3 + 1]; @@ -1768,7 +1929,7 @@ bool AnimationPlayer::load(int animId, Action *endAction) { } ++R2_GLOBALS._animationCtr; - _field38 = 1; + _animLoaded = true; return true; } @@ -1865,7 +2026,7 @@ void AnimationPlayer::drawFrame(int sliceIndex) { // Unlock the screen surface R2_GLOBALS._screenSurface.unlockSurface(); - if (_objectMode == 42) { + if (_objectMode == ANIMOBJMODE_42) { _screenBounds.expandPanes(); // Copy the drawn frame to the back surface @@ -1915,7 +2076,7 @@ bool AnimationPlayer::isCompleted() { } void AnimationPlayer::close() { - if (_field38) { + if (_animLoaded) { switch (_paletteMode) { case 0: R2_GLOBALS._scenePalette.replace(&_palette); @@ -1934,7 +2095,7 @@ void AnimationPlayer::close() { // Close the resource file _resourceFile.close(); - if (_objectMode != 42) { + if (_objectMode != ANIMOBJMODE_42) { // flip screen in original } @@ -1944,9 +2105,9 @@ void AnimationPlayer::close() { _animData1 = NULL; _animData2 = NULL; - _field38 = 0; + _animLoaded = false; if (g_globals != NULL) - R2_GLOBALS._animationCtr = MAX(R2_GLOBALS._animationCtr, 0); + R2_GLOBALS._animationCtr = MAX(R2_GLOBALS._animationCtr - 1, 0); } void AnimationPlayer::rleDecode(const byte *pSrc, byte *pDest, int size) { @@ -1992,15 +2153,358 @@ void AnimationPlayer::getSlices() { /*--------------------------------------------------------------------------*/ AnimationPlayerExt::AnimationPlayerExt(): AnimationPlayer() { - _v = 0; - _field3A = 0; + _isActive = false; + _canSkip = false; } void AnimationPlayerExt::synchronize(Serializer &s) { AnimationPlayer::synchronize(s); - s.syncAsSint16LE(_v); + s.syncAsSint16LE(_isActive); +} + +/*--------------------------------------------------------------------------*/ + +ModalWindow::ModalWindow() { + _insetCount = 0; +} + +void ModalWindow::remove() { + R2_GLOBALS._sceneItems.remove(&_object1); + _object1.remove(); + + SceneArea::remove(); + + --R2_GLOBALS._insetUp; +} + +void ModalWindow::synchronize(Serializer &s) { + SceneArea::synchronize(s); + + s.syncAsByte(_insetCount); +} + +void ModalWindow::process(Event &event) { + if (_insetCount != R2_GLOBALS._insetUp) + return; + + CursorType cursor = R2_GLOBALS._events.getCursor(); + + if (_object1._bounds.contains(event.mousePos.x + g_globals->gfxManager()._bounds.left , event.mousePos.y)) { + if (cursor == _cursorNum) { + R2_GLOBALS._events.setCursor(_savedCursorNum); + } + } else if (event.mousePos.y < 168) { + if (cursor != _cursorNum) { + _savedCursorNum = cursor; + R2_GLOBALS._events.setCursor(CURSOR_INVALID); + } + if (event.eventType == EVENT_BUTTON_DOWN) { + event.handled = true; + R2_GLOBALS._events.setCursor(_savedCursorNum); + remove(); + } + } +} + +void ModalWindow::setup2(int visage, int stripFrameNum, int frameNum, int posX, int posY) { + Scene1200 *scene = (Scene1200 *)R2_GLOBALS._sceneManager._scene; + + _object1.postInit(); + _object1.setup(visage, stripFrameNum, frameNum); + _object1.setPosition(Common::Point(posX, posY)); + _object1.fixPriority(250); + _cursorNum = CURSOR_INVALID; + scene->_sceneAreas.push_front(this); + ++R2_GLOBALS._insetUp; + _insetCount = R2_GLOBALS._insetUp; +} + +void ModalWindow::setup3(int resNum, int lookLineNum, int talkLineNum, int useLineNum) { + _object1.setDetails(resNum, lookLineNum, talkLineNum, useLineNum, 2, (SceneItem *) NULL); +} + +/*--------------------------------------------------------------------------*/ + +ScannerDialog::Button::Button() { + _buttonId = 0; + _buttonDown = false; +} + +void ScannerDialog::Button::setup(int buttonId) { + _buttonId = buttonId; + _buttonDown = false; + SceneActor::postInit(); + + SceneObject::setup(4, 2, 2); + fixPriority(255); + + if (_buttonId == 1) + setPosition(Common::Point(141, 99)); + else if (_buttonId == 2) + setPosition(Common::Point(141, 108)); + + static_cast<SceneExt *>(R2_GLOBALS._sceneManager._scene)->_sceneAreas.push_front(this); +} + +void ScannerDialog::Button::synchronize(Serializer &s) { + SceneActor::synchronize(s); + s.syncAsSint16LE(_buttonId); +} + +void ScannerDialog::Button::process(Event &event) { + if (event.eventType == EVENT_BUTTON_DOWN && R2_GLOBALS._events.getCursor() == CURSOR_USE + && _bounds.contains(event.mousePos) && !_buttonDown) { + setFrame(3); + _buttonDown = true; + event.handled = true; + } + + if (event.eventType == EVENT_BUTTON_UP && _buttonDown) { + setFrame(2); + _buttonDown = false; + event.handled = true; + + reset(); + } +} + +bool ScannerDialog::Button::startAction(CursorType action, Event &event) { + if (action == CURSOR_USE) + return false; + + return startAction(action, event); +} + +void ScannerDialog::Button::reset() { + Scene *scene = R2_GLOBALS._sceneManager._scene; + ScannerDialog &scanner = *R2_GLOBALS._scannerDialog; + + switch (_buttonId) { + case 1: + // Talk button + switch (R2_GLOBALS._sceneManager._sceneNumber) { + case 1550: + scene->_sceneMode = 80; + scene->signal(); + break; + case 1700: + scene->_sceneMode = 30; + scene->signal(); + remove(); + break; + default: + break; + } + break; + case 2: + // Scan button + switch (R2_GLOBALS._sceneManager._sceneNumber) { + case 1550: + scanner._obj4.setup(4, 3, 1); + + scanner._obj5.postInit(); + scanner._obj5.setup(4, 4, 1); + scanner._obj5.setPosition(Common::Point(R2_GLOBALS._s1550PlayerArea[R2_QUINN].x + 145, + R2_GLOBALS._s1550PlayerArea[R2_QUINN].y + 59)); + scanner._obj5.fixPriority(257); + + scanner._obj6.postInit(); + scanner._obj6.setup(4, 4, 2); + scanner._obj6.setPosition(Common::Point(R2_GLOBALS._s1550PlayerArea[R2_SEEKER].x + 145, + R2_GLOBALS._s1550PlayerArea[R2_SEEKER].y + 59)); + scanner._obj6.fixPriority(257); + break; + case 1700: + case 1800: + if (R2_GLOBALS._rimLocation < 1201) + scanner._obj4.setup(4, 3, 3); + else if (R2_GLOBALS._rimLocation < 1201) + scanner._obj4.setup(4, 3, 4); + else + scanner._obj4.setup(4, 3, 5); + break; + case 3800: + case 3900: + if ((R2_GLOBALS._desertWrongDirCtr + 1) == 0 && R2_GLOBALS._desertCorrectDirection == 0) { + do { + R2_GLOBALS._desertCorrectDirection = R2_GLOBALS._randomSource.getRandomNumber(3) + 1; + } while (R2_GLOBALS._desertCorrectDirection == R2_GLOBALS._desertPreviousDirection); + } + + scanner._obj4.setup(4, 7, R2_GLOBALS._desertCorrectDirection); + if (!R2_GLOBALS.getFlag(46)) + R2_GLOBALS.setFlag(46); + break; + default: + scanner._obj4.setup(4, 3, 2); + break; + } + break; + default: + break; + } +} + +/*--------------------------------------------------------------------------*/ + +ScannerDialog::Slider::Slider() { + _initial = _xStart = _yp = 0; + _width = _xInc = 0; + _sliderDown = false; +} + +void ScannerDialog::Slider::synchronize(Serializer &s) { + SceneActor::synchronize(s); + + s.syncAsSint16LE(_initial); + s.syncAsSint16LE(_xStart); + s.syncAsSint16LE(_yp); + s.syncAsSint16LE(_width); + s.syncAsSint16LE(_xInc); +} + +void ScannerDialog::Slider::remove() { + static_cast<SceneExt *>(R2_GLOBALS._sceneManager._scene)->_sceneAreas.remove(this); + SceneActor::remove(); +} + +void ScannerDialog::Slider::process(Event &event) { + if (event.eventType == EVENT_BUTTON_DOWN && R2_GLOBALS._events.getCursor() == CURSOR_USE + && _bounds.contains(event.mousePos)) { + _sliderDown = true; + } + + if (event.eventType == EVENT_BUTTON_UP && _sliderDown) { + _sliderDown = false; + event.handled = true; + update(); + } + + if (_sliderDown) { + event.handled = true; + if (event.mousePos.x < _xStart) { + setPosition(Common::Point(_xStart, _yp)); + } else if (event.mousePos.x >= (_xStart + _width)) { + setPosition(Common::Point(_xStart + _width, _yp)); + } else { + setPosition(Common::Point(event.mousePos.x, _yp)); + } + } +} + +bool ScannerDialog::Slider::startAction(CursorType action, Event &event) { + if (action == CURSOR_USE) + return false; + + return startAction(action, event); } +void ScannerDialog::Slider::update() { + int incHalf = (_width / (_xInc - 1)) / 2; + int newFrequency = ((_position.x - _xStart + incHalf) * _xInc) / (_width + incHalf * 2); + setPosition(Common::Point(_xStart + ((_width * newFrequency) / (_xInc - 1)), _yp)); + + R2_GLOBALS._scannerFrequencies[R2_GLOBALS._player._characterIndex] = newFrequency + 1; + + switch (newFrequency) { + case 0: + R2_GLOBALS._sound4.stop(); + break; + case 1: + R2_GLOBALS._sound4.play(45); + break; + case 2: + R2_GLOBALS._sound4.play(4); + break; + case 3: + R2_GLOBALS._sound4.play(5); + break; + case 4: + R2_GLOBALS._sound4.play(6); + break; + default: + break; + } +} + +void ScannerDialog::Slider::setup(int initial, int xStart, int yp, int width, int xInc) { + _initial = initial; + _xStart = xStart; + _yp = yp; + _width = width; + _xInc = xInc; + _sliderDown = false; + SceneActor::postInit(); + SceneObject::setup(4, 2, 1); + fixPriority(255); + setPosition(Common::Point(_width * (_initial - 1) / (_xInc - 1) + _xStart, yp)); + + static_cast<SceneExt *>(R2_GLOBALS._sceneManager._scene)->_sceneAreas.push_front(this); +} + +/*--------------------------------------------------------------------------*/ + +ScannerDialog::ScannerDialog() { +} + +void ScannerDialog::remove() { + switch (R2_GLOBALS._sceneManager._sceneNumber) { + case 1550: + case 1700: + R2_GLOBALS._events.setCursor(R2_GLOBALS._player._canWalk ? CURSOR_WALK : CURSOR_USE); + break; + case 3800: + case 3900: { + Scene *scene = R2_GLOBALS._sceneManager._scene; + scene->_sceneMode = 3806; + scene->signal(); + break; + } + default: + break; + } + + SceneExt *scene = static_cast<SceneExt *>(R2_GLOBALS._sceneManager._scene); + scene->_sceneAreas.remove(&_talkButton); + scene->_sceneAreas.remove(&_scanButton); + _talkButton.remove(); + _scanButton.remove(); + _slider.remove(); + _obj4.remove(); + _obj5.remove(); + _obj6.remove(); + _obj7.remove(); + + ModalWindow::remove(); +} + +void ScannerDialog::setup2(int visage, int stripFrameNum, int frameNum, int posX, int posY) { + // Stop player moving if currently doing so + if (R2_GLOBALS._player._mover) + R2_GLOBALS._player.addMover(NULL); + + R2_GLOBALS._events.setCursor(CURSOR_USE); + ModalWindow::setup2(visage, stripFrameNum, frameNum, posX, posY); + + setup3(100, -1, -1, -1); + _talkButton.setup(1); + _scanButton.setup(2); + _slider.setup(R2_GLOBALS._scannerFrequencies[R2_GLOBALS._player._characterIndex], 142, 124, 35, 5); + + _obj4.postInit(); + _obj4.setup(4, 3, 2); + _obj4.setPosition(Common::Point(160, 83)); + _obj4.fixPriority(256); + + if (R2_GLOBALS._sceneManager._sceneNumber == 3800 || R2_GLOBALS._sceneManager._sceneNumber == 3900) { + Scene *scene = R2_GLOBALS._sceneManager._scene; + scene->_sceneMode = 3805; + scene->signal(); + } +} + +/*--------------------------------------------------------------------------*/ + } // End of namespace Ringworld2 } // End of namespace TsAGE |