/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
*/
#include "mohawk/cursors.h"
#include "mohawk/myst.h"
#include "mohawk/myst_areas.h"
#include "mohawk/myst_card.h"
#include "mohawk/myst_graphics.h"
#include "mohawk/myst_state.h"
#include "mohawk/myst_sound.h"
#include "mohawk/video.h"
#include "mohawk/myst_stacks/myst.h"
#include "common/config-manager.h"
#include "common/events.h"
#include "common/math.h"
#include "common/system.h"
#include "common/textconsole.h"
namespace Mohawk {
namespace MystStacks {
Myst::Myst(MohawkEngine_Myst *vm, MystStack stackId) :
MystScriptParser(vm, stackId),
_state(_vm->_gameState->_myst),
_towerRotationCenter(Common::Point(383, 124)) {
setupOpcodes();
// Card ID preinitialized by the engine for use by opcode 18
// when linking back to Myst in the library
_savedCardId = 4329;
_towerRotationBlinkLabel = false;
_towerRotationBlinkLabelCount = 0;
_towerRotationSpeed = 0;
_towerRotationMapInitialized = 0;
_towerRotationMapRunning = false;
_towerRotationMapClicked = false;
_towerRotationMapTower = nullptr;
_towerRotationMapLabel = nullptr;
_towerRotationOverSpot = false;
_libraryBookcaseChanged = false;
_libraryBookcaseMoving = false;
_libraryBookcaseMovie = nullptr;
_libraryBookcaseSoundId = 0;
_libraryBookPagesTurning = false;
_libraryBookNumPages = 0;
_libraryBookBaseImage = 0;
_libraryBookSound1 = 0;
_libraryBookSound2 = 0;
_libraryCombinationBookPagesTurning = false;
for (uint i = 0; i < ARRAYSIZE(_fireplaceLines); i++) {
_fireplaceLines[i] = 0;
}
_dockVaultState = 0;
_cabinDoorOpened = 0;
_cabinHandleDown = 0;
_cabinMatchState = 2;
_cabinGaugeMovieEnabled = false;
_boilerPressureIncreasing = false;
_boilerPressureDecreasing = false;
_basementPressureIncreasing = false;
_basementPressureDecreasing = false;
_matchBurning = false;
_matchGoOutCnt = 0;
_matchGoOutTime = 0;
_tree = nullptr;
_treeAlcove = nullptr;
_treeStopped = false;
_treeMinPosition = 0;
_treeMinAccessiblePosition = 0;
_treeMaxAccessiblePosition = 0;
_imagerRunning = false;
_imagerRedButton = nullptr;
_imagerMovie = nullptr;
_imagerValidationRunning = false;
_imagerValidationCard = 0;
_imagerValidationStep = 0;
for (uint i = 0; i < ARRAYSIZE(_imagerSound); i++) {
_imagerSound[i] = 0;
}
_butterfliesMoviePlayed = false;
_state.treeLastMoveTime = _vm->getTotalPlayTime();
_rocketPianoSound = 0;
_rocketSlider1 = nullptr;
_rocketSlider2 = nullptr;
_rocketSlider3 = nullptr;
_rocketSlider4 = nullptr;
_rocketSlider5 = nullptr;
_rocketSliderSound = 0;
_rocketLeverPosition = 0;
_generatorControlRoomRunning = false;
_generatorVoltage = _state.generatorVoltage;
_observatoryRunning = false;
_observatoryMonthChanging = false;
_observatoryDayChanging = false;
_observatoryYearChanging = false;
_observatoryTimeChanging = false;
_observatoryVisualizer = nullptr;
_observatoryGoButton = nullptr;
_observatoryCurrentSlider = nullptr;
_observatoryDaySlider = nullptr;
_observatoryMonthSlider = nullptr;
_observatoryYearSlider = nullptr;
_observatoryTimeSlider = nullptr;
_observatoryLastTime = 0;
_observatoryNotInitialized = true;
_observatoryIncrement = 0;
_greenBookRunning = false;
_gullsFlying1 = false;
_gullsFlying2 = false;
_gullsFlying3 = false;
_gullsNextTime = 0;
_courtyardBoxSound = 0;
_clockTurningWheel = 0;
_clockWeightPosition = 0;
_clockMiddleGearMovedAlone = false;
_clockLeverPulled = false;
for (uint i = 0; i < ARRAYSIZE(_clockGearsPositions); i++) {
_clockGearsPositions[i] = 0;
}
}
Myst::~Myst() {
}
void Myst::setupOpcodes() {
// "Stack-Specific" Opcodes
REGISTER_OPCODE(100, Myst, NOP);
REGISTER_OPCODE(101, Myst, o_libraryBookPageTurnLeft);
REGISTER_OPCODE(102, Myst, o_libraryBookPageTurnRight);
REGISTER_OPCODE(103, Myst, o_fireplaceToggleButton);
REGISTER_OPCODE(104, Myst, o_fireplaceRotation);
REGISTER_OPCODE(105, Myst, o_courtyardBoxesCheckSolution);
REGISTER_OPCODE(106, Myst, o_towerRotationStart);
REGISTER_OPCODE(107, Myst, NOP);
REGISTER_OPCODE(108, Myst, o_towerRotationEnd);
REGISTER_OPCODE(109, Myst, o_imagerChangeSelection);
REGISTER_OPCODE(113, Myst, o_dockVaultOpen);
REGISTER_OPCODE(114, Myst, o_dockVaultClose);
REGISTER_OPCODE(115, Myst, o_bookGivePage);
REGISTER_OPCODE(116, Myst, o_clockWheelsExecute);
REGISTER_OPCODE(117, Myst, o_imagerPlayButton);
REGISTER_OPCODE(118, Myst, o_imagerEraseButton);
REGISTER_OPCODE(119, Myst, o_towerElevatorAnimation);
REGISTER_OPCODE(120, Myst, o_generatorButtonPressed);
REGISTER_OPCODE(121, Myst, o_cabinSafeChangeDigit);
REGISTER_OPCODE(122, Myst, o_cabinSafeHandleStartMove);
REGISTER_OPCODE(123, Myst, o_cabinSafeHandleMove);
REGISTER_OPCODE(124, Myst, o_cabinSafeHandleEndMove);
REGISTER_OPCODE(126, Myst, o_clockLeverStartMove);
REGISTER_OPCODE(127, Myst, o_clockLeverEndMove);
REGISTER_OPCODE(128, Myst, o_treePressureReleaseStart);
if (!observatoryIsDDMMYYYY2400()) {
REGISTER_OPCODE(129, Myst, o_observatoryMonthChangeStartIncrease);
REGISTER_OPCODE(130, Myst, o_observatoryMonthChangeStartDecrease);
REGISTER_OPCODE(131, Myst, o_observatoryDayChangeStartIncrease);
REGISTER_OPCODE(132, Myst, o_observatoryDayChangeStartDecrease);
} else {
REGISTER_OPCODE(129, Myst, o_observatoryDayChangeStartIncrease);
REGISTER_OPCODE(130, Myst, o_observatoryDayChangeStartDecrease);
REGISTER_OPCODE(131, Myst, o_observatoryMonthChangeStartIncrease);
REGISTER_OPCODE(132, Myst, o_observatoryMonthChangeStartDecrease);
}
REGISTER_OPCODE(133, Myst, o_observatoryGoButton);
REGISTER_OPCODE(134, Myst, o_observatoryMonthSliderMove);
REGISTER_OPCODE(135, Myst, o_observatoryDaySliderMove);
REGISTER_OPCODE(136, Myst, o_observatoryYearSliderMove);
REGISTER_OPCODE(137, Myst, o_observatoryTimeSliderMove);
REGISTER_OPCODE(138, Myst, o_clockResetLeverStartMove);
REGISTER_OPCODE(139, Myst, o_clockResetLeverMove);
REGISTER_OPCODE(140, Myst, o_clockResetLeverEndMove);
REGISTER_OPCODE(141, Myst, o_circuitBreakerStartMove);
REGISTER_OPCODE(142, Myst, o_circuitBreakerMove);
REGISTER_OPCODE(143, Myst, o_circuitBreakerEndMove);
REGISTER_OPCODE(144, Myst, o_clockLeverMoveLeft);
REGISTER_OPCODE(145, Myst, o_clockLeverMoveRight);
REGISTER_OPCODE(146, Myst, o_boilerIncreasePressureStart);
REGISTER_OPCODE(147, Myst, o_boilerLightPilot);
REGISTER_OPCODE(148, Myst, NOP);
REGISTER_OPCODE(149, Myst, o_boilerIncreasePressureStop);
REGISTER_OPCODE(150, Myst, o_boilerDecreasePressureStart);
REGISTER_OPCODE(151, Myst, o_boilerDecreasePressureStop);
REGISTER_OPCODE(152, Myst, NOP);
REGISTER_OPCODE(153, Myst, o_basementIncreasePressureStart);
REGISTER_OPCODE(154, Myst, o_basementIncreasePressureStop);
REGISTER_OPCODE(155, Myst, o_basementDecreasePressureStart);
REGISTER_OPCODE(156, Myst, o_basementDecreasePressureStop);
REGISTER_OPCODE(157, Myst, o_rocketPianoMove);
REGISTER_OPCODE(158, Myst, o_rocketSoundSliderStartMove);
REGISTER_OPCODE(159, Myst, o_rocketSoundSliderMove);
REGISTER_OPCODE(160, Myst, o_rocketSoundSliderEndMove);
REGISTER_OPCODE(161, Myst, o_rocketPianoStart);
REGISTER_OPCODE(162, Myst, o_rocketPianoStop);
REGISTER_OPCODE(163, Myst, o_rocketLeverStartMove);
REGISTER_OPCODE(164, Myst, o_rocketOpenBook);
REGISTER_OPCODE(165, Myst, o_rocketLeverMove);
REGISTER_OPCODE(166, Myst, o_rocketLeverEndMove);
REGISTER_OPCODE(167, Myst, NOP);
REGISTER_OPCODE(168, Myst, o_treePressureReleaseStop);
REGISTER_OPCODE(169, Myst, o_cabinLeave);
REGISTER_OPCODE(170, Myst, o_observatoryMonthSliderStartMove);
REGISTER_OPCODE(171, Myst, o_observatoryMonthSliderEndMove);
REGISTER_OPCODE(172, Myst, o_observatoryDaySliderStartMove);
REGISTER_OPCODE(173, Myst, o_observatoryDaySliderEndMove);
REGISTER_OPCODE(174, Myst, o_observatoryYearSliderStartMove);
REGISTER_OPCODE(175, Myst, o_observatoryYearSliderEndMove);
REGISTER_OPCODE(176, Myst, o_observatoryTimeSliderStartMove);
REGISTER_OPCODE(177, Myst, o_observatoryTimeSliderEndMove);
REGISTER_OPCODE(178, Myst, o_libraryBookPageTurnStartLeft);
REGISTER_OPCODE(179, Myst, o_libraryBookPageTurnStartRight);
REGISTER_OPCODE(180, Myst, o_libraryCombinationBookStop);
REGISTER_OPCODE(181, Myst, NOP);
REGISTER_OPCODE(182, Myst, o_cabinMatchLight);
REGISTER_OPCODE(183, Myst, o_courtyardBoxEnter);
REGISTER_OPCODE(184, Myst, o_courtyardBoxLeave);
REGISTER_OPCODE(185, Myst, NOP);
REGISTER_OPCODE(186, Myst, o_clockMinuteWheelStartTurn);
REGISTER_OPCODE(187, Myst, NOP);
REGISTER_OPCODE(188, Myst, o_clockWheelEndTurn);
REGISTER_OPCODE(189, Myst, o_clockHourWheelStartTurn);
REGISTER_OPCODE(190, Myst, o_libraryCombinationBookStartRight);
REGISTER_OPCODE(191, Myst, o_libraryCombinationBookStartLeft);
REGISTER_OPCODE(192, Myst, o_observatoryTimeChangeStartIncrease);
REGISTER_OPCODE(193, Myst, NOP);
REGISTER_OPCODE(194, Myst, o_observatoryChangeSettingStop);
REGISTER_OPCODE(195, Myst, o_observatoryTimeChangeStartDecrease);
REGISTER_OPCODE(196, Myst, o_observatoryYearChangeStartIncrease);
REGISTER_OPCODE(197, Myst, o_observatoryYearChangeStartDecrease);
REGISTER_OPCODE(198, Myst, o_dockVaultForceClose);
REGISTER_OPCODE(199, Myst, o_imagerEraseStop);
// "Init" Opcodes
REGISTER_OPCODE(200, Myst, o_libraryBook_init);
REGISTER_OPCODE(201, Myst, o_courtyardBox_init);
REGISTER_OPCODE(202, Myst, o_towerRotationMap_init);
REGISTER_OPCODE(203, Myst, o_forechamberDoor_init);
REGISTER_OPCODE(204, Myst, o_shipAccess_init);
REGISTER_OPCODE(205, Myst, NOP);
REGISTER_OPCODE(206, Myst, o_butterflies_init);
REGISTER_OPCODE(208, Myst, o_imager_init);
REGISTER_OPCODE(209, Myst, o_libraryBookcaseTransform_init);
REGISTER_OPCODE(210, Myst, o_generatorControlRoom_init);
REGISTER_OPCODE(211, Myst, o_fireplace_init);
REGISTER_OPCODE(212, Myst, o_clockGears_init);
REGISTER_OPCODE(213, Myst, o_gulls1_init);
REGISTER_OPCODE(214, Myst, o_observatory_init);
REGISTER_OPCODE(215, Myst, o_gulls2_init);
REGISTER_OPCODE(216, Myst, o_treeCard_init);
REGISTER_OPCODE(217, Myst, o_treeEntry_init);
REGISTER_OPCODE(218, Myst, o_boilerMovies_init);
REGISTER_OPCODE(219, Myst, o_rocketSliders_init);
REGISTER_OPCODE(220, Myst, o_rocketLinkVideo_init);
REGISTER_OPCODE(221, Myst, o_greenBook_init);
REGISTER_OPCODE(222, Myst, o_gulls3_init);
// "Exit" Opcodes
REGISTER_OPCODE(300, Myst, o_bookAddSpecialPage_exit);
REGISTER_OPCODE(301, Myst, NOP);
REGISTER_OPCODE(302, Myst, NOP);
REGISTER_OPCODE(303, Myst, NOP);
REGISTER_OPCODE(304, Myst, o_treeCard_exit);
REGISTER_OPCODE(305, Myst, o_treeEntry_exit);
REGISTER_OPCODE(306, Myst, o_boiler_exit);
REGISTER_OPCODE(307, Myst, o_generatorControlRoom_exit);
REGISTER_OPCODE(308, Myst, o_rocketSliders_exit);
REGISTER_OPCODE(309, Myst, NOP);
REGISTER_OPCODE(312, Myst, NOP);
}
void Myst::disablePersistentScripts() {
_libraryBookcaseMoving = false;
_generatorControlRoomRunning = false;
_libraryBookPagesTurning = false;
_libraryCombinationBookPagesTurning = false;
_clockTurningWheel = 0;
_towerRotationMapRunning = false;
_boilerPressureIncreasing = false;
_boilerPressureDecreasing = false;
_basementPressureIncreasing = false;
_basementPressureDecreasing = false;
_imagerValidationRunning = false;
_imagerRunning = false;
_observatoryRunning = false;
_observatoryMonthChanging = false;
_observatoryDayChanging = false;
_observatoryYearChanging = false;
_observatoryTimeChanging = false;
_greenBookRunning = false;
_clockLeverPulled = false;
_gullsFlying1 = false;
_gullsFlying2 = false;
_gullsFlying3 = false;
}
void Myst::runPersistentScripts() {
if (_towerRotationMapRunning)
towerRotationMap_run();
if (_generatorControlRoomRunning)
generatorControlRoom_run();
if (_libraryCombinationBookPagesTurning)
libraryCombinationBook_run();
if (_libraryBookPagesTurning)
libraryBook_run();
if (_libraryBookcaseMoving)
libraryBookcaseTransform_run();
if (_clockTurningWheel)
clockWheel_run();
if (_matchBurning)
matchBurn_run();
if (_boilerPressureIncreasing)
boilerPressureIncrease_run();
if (_boilerPressureDecreasing)
boilerPressureDecrease_run();
if (_basementPressureIncreasing)
basementPressureIncrease_run();
if (_basementPressureDecreasing)
basementPressureDecrease_run();
if (!_treeStopped)
tree_run();
if (_imagerValidationRunning)
imagerValidation_run();
if (_imagerRunning)
imager_run();
if (_observatoryRunning)
observatory_run();
if (_observatoryMonthChanging)
observatoryMonthChange_run();
if (_observatoryDayChanging)
observatoryDayChange_run();
if (_observatoryYearChanging)
observatoryYearChange_run();
if (_observatoryTimeChanging)
observatoryTimeChange_run();
if (_greenBookRunning)
greenBook_run();
if (_clockLeverPulled)
clockGears_run();
if (_gullsFlying1)
gullsFly1_run();
if (_gullsFlying2)
gullsFly2_run();
if (_gullsFlying3)
gullsFly3_run();
}
uint16 Myst::getVar(uint16 var) {
switch(var) {
case 0: // Myst Library Bookcase Closed
return _state.libraryBookcaseDoor;
case 1:
if (_globals.ending != kBooksDestroyed)
return _state.libraryBookcaseDoor != 1;
else if (_state.libraryBookcaseDoor == 1)
return 2;
else
return 3;
case 2: // Marker Switch Near Cabin
return _state.cabinMarkerSwitch;
case 3: // Marker Switch Near Clock Tower
return _state.clockTowerMarkerSwitch;
case 4: // Marker Switch on Dock
return _state.dockMarkerSwitch;
case 5: // Marker Switch Near Ship Pool
return _state.poolMarkerSwitch;
case 6: // Marker Switch Near Cogs
return _state.gearsMarkerSwitch;
case 7: // Marker Switch Near Generator Room
return _state.generatorMarkerSwitch;
case 8: // Marker Switch Near Stellar Observatory
return _state.observatoryMarkerSwitch;
case 9: // Marker Switch Near Rocket Ship
return _state.rocketshipMarkerSwitch;
case 10: // Ship Floating State
return _state.shipFloating;
case 11: // Cabin Door Open State
return _cabinDoorOpened;
case 12: // Clock tower gears bridge
return _state.clockTowerBridgeOpen;
case 13: // Tower in right position
return _state.towerRotationAngle == 271
|| _state.towerRotationAngle == 83
|| _state.towerRotationAngle == 129
|| _state.towerRotationAngle == 152;
case 14: // Tower Solution (Key) Plaque
switch (_state.towerRotationAngle) {
case 271:
return 1;
case 83:
return 2;
case 129:
return 3;
case 152:
return 4;
default:
return 0;
}
case 15: // Tower Window (Book) View
switch (_state.towerRotationAngle) {
case 271:
return 1;
case 83:
if (_state.gearsOpen)
return 6;
else
return 2;
case 129:
if (_state.shipFloating)
return 5;
else
return 3;
case 152:
return 4;
default:
return 0;
}
case 16: // Tower Window (Book) View From Ladder Top
if (_state.towerRotationAngle != 271 && _state.towerRotationAngle != 83 && _state.towerRotationAngle != 129) {
if (_state.towerRotationAngle == 152)
return 2;
else
return 0;
} else
return 1;
case 23: // Fireplace Pattern Correct
return _fireplaceLines[0] == 195
&& _fireplaceLines[1] == 107
&& _fireplaceLines[2] == 163
&& _fireplaceLines[3] == 147
&& _fireplaceLines[4] == 204
&& _fireplaceLines[5] == 250;
case 24: // Fireplace Blue Page Present
if (_globals.ending != kBooksDestroyed)
return !(_globals.bluePagesInBook & 32) && (_globals.heldPage != kBlueFirePlacePage);
else
return 0;
case 25: // Fireplace Red Page Present
if (_globals.ending != kBooksDestroyed)
return !(_globals.redPagesInBook & 32) && (_globals.heldPage != kRedFirePlacePage);
else
return 0;
case 26: // Courtyard Image Box - Cross
case 27: // Courtyard Image Box - Leaf
case 28: // Courtyard Image Box - Arrow
case 29: // Courtyard Image Box - Eye
case 30: // Courtyard Image Box - Snake
case 31: // Courtyard Image Box - Spider
case 32: // Courtyard Image Box - Anchor
case 33: // Courtyard Image Box - Ostrich
if (!_tempVar)
return 0;
else if (_state.courtyardImageBoxes & (0x01 << (var - 26)))
return 2;
else
return 1;
case 34: // Sound Control In Dock forechamber
if (_state.imagerActive) {
if (_state.imagerSelection == 40 && !_state.imagerMountainErased)
return 1;
else if (_state.imagerSelection == 67 && !_state.imagerWaterErased)
return 2;
else
return 0;
}
return 0;
case 35: // Dock Forechamber Imager Control Left Digit
if (_state.imagerSelection > 9)
return _state.imagerSelection / 10 - 1;
else
return 9;
case 36: // Dock Forechamber Imager Control Right Digit
return (10 + _state.imagerSelection - 1) % 10;
case 37: // Clock Tower Control Wheels Position
return 3 * ((_state.clockTowerMinutePosition / 5) % 3) + _state.clockTowerHourPosition % 3;
case 40: // Gears Open State
return _state.gearsOpen;
case 41: // Dock Marker Switch Vault State
return _dockVaultState;
case 43: // Clock Tower Time
return _state.clockTowerHourPosition * 12 + _state.clockTowerMinutePosition / 5;
case 44: // Rocket ship power state
if (_state.generatorBreakers || _state.generatorVoltage == 0)
return 0;
else if (_state.generatorVoltage != 59)
return 1;
else
return 2;
case 45: // Dock Vault Imager Active On Water
return _state.imagerActive && _state.imagerSelection == 67 && !_state.imagerWaterErased;
case 46:
return bookCountPages(100);
case 47:
return bookCountPages(101);
case 48:
if (_state.dockMarkerSwitch && !_state.shipFloating)
return 1;
else if (!_state.dockMarkerSwitch && _state.shipFloating)
return 2;
else
return 0;
case 49: // Generator running
return _state.generatorVoltage > 0;
case 51: // Forechamber Imager Movie Control
if (_state.imagerSelection == 40 && !_state.imagerMountainErased)
return 1;
else if (_state.imagerSelection == 67 && !_state.imagerWaterErased)
return 2;
else if (_state.imagerSelection == 8 && !_state.imagerAtrusErased)
return 3;
else if (_state.imagerSelection == 47 && !_state.imagerMarkerErased)
return 4;
else
return 0;
case 52: // Generator Switch #1
case 53: // Generator Switch #2
case 54: // Generator Switch #3
case 55: // Generator Switch #4
case 56: // Generator Switch #5
case 57: // Generator Switch #6
case 58: // Generator Switch #7
case 59: // Generator Switch #8
case 60: // Generator Switch #9
case 61: // Generator Switch #10
return (_state.generatorButtons & (1 << (var - 52))) != 0;
case 62: // Generator Power Dial Left LED Digit
return _generatorVoltage / 10;
case 63: // Generator Power Dial Right LED Digit
return _generatorVoltage % 10;
case 64: // Generator Power To Spaceship Dial Left LED Digit
if (_state.generatorVoltage > 59 || _state.generatorBreakers)
return 0;
else
return _state.generatorVoltage / 10;
case 65: // Generator Power To Spaceship Dial Right LED Digit
if (_state.generatorVoltage > 59 || _state.generatorBreakers)
return 0;
else
return _state.generatorVoltage % 10;
case 66: // Generators lights on
return 0;
case 67: // Cabin Safe Lock Number #1 - Left
return _state.cabinSafeCombination / 100;
case 68: // Cabin Safe Lock Number #2
return (_state.cabinSafeCombination / 10) % 10;
case 69: // Cabin Safe Lock Number #3 - Right
return _state.cabinSafeCombination % 10;
case 70: // Cabin Safe Matchbox State
return _cabinMatchState;
case 71: // Stellar Observatory Lights
return _state.observatoryLights;
case 72: // Channelwood tree position
return _state.treePosition;
case 73: // Stellar Observatory Date - Month
return _state.observatoryMonthSetting;
case 74: // Stellar Observatory Date - Day #1 (Left)
if (_state.observatoryDaySetting / 10 == 0)
return 10;
else
return _state.observatoryDaySetting / 10;
case 75: // Stellar Observatory Date - Day #2 (Right)
return _state.observatoryDaySetting % 10;
case 76: // Stellar Observatory Date - Year #1 (Left)
if (_state.observatoryYearSetting >= 1000)
return (_state.observatoryYearSetting / 1000) % 10;
else
return 10;
case 77: // Stellar Observatory Date - Year #2
if (_state.observatoryYearSetting >= 100)
return (_state.observatoryYearSetting / 100) % 10;
else
return 10;
case 78: // Stellar Observatory Date - Year #3
if (_state.observatoryYearSetting >= 10)
return (_state.observatoryYearSetting / 10) % 10;
else
return 10;
case 79: // Stellar Observatory Date - Year #4 (Right)
return (_state.observatoryYearSetting / 1) % 10;
case 80: // Stellar Observatory Hour #1 - Left ( Hour digits can be 10 (Blank), or 0-2)
uint32 observatoryLeftMinutes;
if (!observatoryIsDDMMYYYY2400()) {
// 12 Hour Format
observatoryLeftMinutes = _state.observatoryTimeSetting % (12 * 60);
if (observatoryLeftMinutes > 59 && observatoryLeftMinutes < (10 * 60))
return 10;
else
return 1;
} else {
// 24 Hour Format
observatoryLeftMinutes = _state.observatoryTimeSetting;
if (observatoryLeftMinutes < (10 * 60))
return 0;
else if (observatoryLeftMinutes < (20 * 60))
return 1;
else
return 2;
}
case 81: // Stellar Observatory Hour #2 - Right
uint32 observatoryRightMinutes,observatoryRightHour;
if (!observatoryIsDDMMYYYY2400()) {
// 12 Hour Format
observatoryRightMinutes = _state.observatoryTimeSetting % (12 * 60);
observatoryRightHour = observatoryRightMinutes / 60;
if (observatoryRightHour % 12 == 0)
return 2;
else
return observatoryRightHour % 10;
} else {
// 24 Hour Format
observatoryRightMinutes = _state.observatoryTimeSetting;
observatoryRightHour = observatoryRightMinutes / 60;
return observatoryRightHour % 10;
}
case 82: // Stellar Observatory Minutes #1 - Left
return (_state.observatoryTimeSetting % 60) / 10;
case 83: // Stellar Observatory Minutes #2 - Right
return (_state.observatoryTimeSetting % 60) % 10;
case 88: // Stellar Observatory AM/PM
if (_state.observatoryTimeSetting < (12 * 60))
return 0; // AM
else
return 1; // PM
case 89:
case 90:
case 91:
case 92: // Stellar observatory sliders state
return 1;
case 93: // Breaker nearest Generator Room Blown
return _state.generatorBreakers == 1;
case 94: // Breaker nearest Rocket Ship Blown
return _state.generatorBreakers == 2;
case 95: // Going out of tree destination selection
if (_state.treePosition == 0)
return 0;
else if (_state.treePosition == 4 || _state.treePosition == 5)
return 1;
else
return 2;
case 96: // Generator Power Dial Needle Position
return _state.generatorVoltage / 4;
case 97: // Generator Power To Spaceship Dial Needle Position
if (_state.generatorVoltage > 59 || _state.generatorBreakers)
return 0;
else
return _state.generatorVoltage / 4;
case 98: // Cabin Boiler Pilot Light Lit
return _state.cabinPilotLightLit;
case 99: // Cabin Boiler Gas Valve Position
return _state.cabinValvePosition % 6;
case 102: // Red page
if (_globals.ending != kBooksDestroyed)
return !(_globals.redPagesInBook & 1) && (_globals.heldPage != kRedLibraryPage);
else
return 0;
case 103: // Blue page
if (_globals.ending != kBooksDestroyed)
return !(_globals.bluePagesInBook & 1) && (_globals.heldPage != kBlueLibraryPage);
else
return 0;
case 300: // Rocket Ship Music Puzzle Slider State
return 1;
case 302: // Green Book Opened Before Flag
return _state.greenBookOpenedBefore;
case 303: // Library Bookcase status changed
return _libraryBookcaseChanged;
case 304: // Tower Rotation Map Initialized
return _towerRotationMapInitialized;
case 305: // Cabin Boiler Lit
return _state.cabinPilotLightLit == 1 && _state.cabinValvePosition > 0;
case 306: // Cabin Boiler Steam Sound Control
if (_state.cabinPilotLightLit == 1) {
if (_state.cabinValvePosition <= 0)
return 26;
else
return 27;
}
return _state.cabinValvePosition;
case 307: // Cabin Boiler Fully Pressurized
return _state.cabinPilotLightLit == 1 && _state.cabinValvePosition > 12;
case 308: // Cabin handle position
return _cabinHandleDown;
default:
return MystScriptParser::getVar(var);
}
}
void Myst::toggleVar(uint16 var) {
switch(var) {
case 2: // Marker Switch Near Cabin
_state.cabinMarkerSwitch = (_state.cabinMarkerSwitch + 1) % 2;
break;
case 3: // Marker Switch Near Clock Tower
_state.clockTowerMarkerSwitch = (_state.clockTowerMarkerSwitch + 1) % 2;
break;
case 4: // Marker Switch on Dock
_state.dockMarkerSwitch = (_state.dockMarkerSwitch + 1) % 2;
break;
case 5: // Marker Switch Near Ship Pool
_state.poolMarkerSwitch = (_state.poolMarkerSwitch + 1) % 2;
break;
case 6: // Marker Switch Near Cogs
_state.gearsMarkerSwitch = (_state.gearsMarkerSwitch + 1) % 2;
break;
case 7: // Marker Switch Near Generator Room
_state.generatorMarkerSwitch = (_state.generatorMarkerSwitch + 1) % 2;
break;
case 8: // Marker Switch Near Stellar Observatory
_state.observatoryMarkerSwitch = (_state.observatoryMarkerSwitch + 1) % 2;
break;
case 9: // Marker Switch Near Rocket Ship
_state.rocketshipMarkerSwitch = (_state.rocketshipMarkerSwitch + 1) % 2;
break;
case 24: // Fireplace Blue Page
if (_globals.ending != kBooksDestroyed && !(_globals.bluePagesInBook & 32)) {
if (_globals.heldPage == kBlueFirePlacePage)
_globals.heldPage = kNoPage;
else
_globals.heldPage = kBlueFirePlacePage;
}
break;
case 25: // Fireplace Red page
if (_globals.ending != kBooksDestroyed && !(_globals.redPagesInBook & 32)) {
if (_globals.heldPage == kRedFirePlacePage)
_globals.heldPage = kNoPage;
else
_globals.heldPage = kRedFirePlacePage;
}
break;
case 26: // Courtyard Image Box - Cross
case 27: // Courtyard Image Box - Leaf
case 28: // Courtyard Image Box - Arrow
case 29: // Courtyard Image Box - Eye
case 30: // Courtyard Image Box - Snake
case 31: // Courtyard Image Box - Spider
case 32: // Courtyard Image Box - Anchor
case 33: // Courtyard Image Box - Ostrich
{
uint16 mask = 0x01 << (var - 26);
if (_state.courtyardImageBoxes & mask)
_state.courtyardImageBoxes &= ~mask;
else
_state.courtyardImageBoxes |= mask;
}
break;
case 41: // Vault white page
if (_globals.ending != kBooksDestroyed) {
if (_dockVaultState == 1) {
_dockVaultState = 2;
_globals.heldPage = kNoPage;
} else if (_dockVaultState == 2) {
_dockVaultState = 1;
_globals.heldPage = kWhitePage;
}
}
break;
case 102: // Red page
if (_globals.ending != kBooksDestroyed && !(_globals.redPagesInBook & 1)) {
if (_globals.heldPage == kRedLibraryPage)
_globals.heldPage = kNoPage;
else
_globals.heldPage = kRedLibraryPage;
}
break;
case 103: // Blue page
if (_globals.ending != kBooksDestroyed && !(_globals.bluePagesInBook & 1)) {
if (_globals.heldPage == kBlueLibraryPage)
_globals.heldPage = kNoPage;
else
_globals.heldPage = kBlueLibraryPage;
}
break;
default:
MystScriptParser::toggleVar(var);
break;
}
}
bool Myst::setVarValue(uint16 var, uint16 value) {
bool refresh = false;
switch (var) {
case 0: // Myst Library Bookcase Closed
if (_state.libraryBookcaseDoor != value) {
_state.libraryBookcaseDoor = value;
_tempVar = 0;
refresh = true;
}
break;
case 11: // Cabin Door Open State
if (_cabinDoorOpened != value) {
_cabinDoorOpened = value;
refresh = true;
}
break;
case 70: // Cabin Safe Matchbox State
if (_cabinMatchState != value) {
_cabinMatchState = value;
refresh = true;
}
break;
case 71: // Stellar Observatory Lights
_state.observatoryLights = value;
break;
case 89:
case 90:
case 91:
case 92:
case 300: // Set slider value
break; // Do nothing
case 302: // Green Book Opened Before Flag
_state.greenBookOpenedBefore = value;
break;
case 303: // Library Bookcase status changed
_libraryBookcaseChanged = value;
break;
case 304: // Myst Library Image Present on Tower Rotation Map
_towerRotationMapInitialized = value;
break;
case 308: // Cabin handle position
_cabinHandleDown = value;
break;
case 309: // Tree stopped
_treeStopped = value;
break;
case 310: // Imager validation step
_imagerValidationStep = value;
break;
default:
refresh = MystScriptParser::setVarValue(var, value);
break;
}
return refresh;
}
uint16 Myst::bookCountPages(uint16 var) {
uint16 pages = 0;
uint16 cnt = 0;
// Select book according to var
if (var == 100)
pages = _globals.redPagesInBook;
else if (var == 101)
pages = _globals.bluePagesInBook;
// Special page present
if (pages & 64)
return 6;
// Count pages
if (pages & 1)
cnt++;
if (pages & 2)
cnt++;
if (pages & 4)
cnt++;
if (pages & 8)
cnt++;
if (pages & 16)
cnt++;
return cnt;
}
void Myst::o_libraryBookPageTurnLeft(uint16 var, const ArgumentsArray &args) {
libraryBookPageTurnLeft();
}
void Myst::libraryBookPageTurnLeft() {
if (_libraryBookPage - 1 >= 0) {
_libraryBookPage--;
Common::Rect rect = Common::Rect(0, 0, 544, 333);
_vm->_gfx->copyImageToScreen(_libraryBookBaseImage + _libraryBookPage, rect);
if (_vm->_rnd->getRandomBit())
_vm->_sound->playEffect(_libraryBookSound1);
else
_vm->_sound->playEffect(_libraryBookSound2);
}
}
void Myst::o_libraryBookPageTurnRight(uint16 var, const ArgumentsArray &args) {
libraryBookPageTurnRight();
}
void Myst::libraryBookPageTurnRight() {
if (_libraryBookPage + 1 < _libraryBookNumPages) {
_libraryBookPage++;
Common::Rect rect = Common::Rect(0, 0, 544, 333);
_vm->_gfx->copyImageToScreen(_libraryBookBaseImage + _libraryBookPage, rect);
if (_vm->_rnd->getRandomBit())
_vm->_sound->playEffect(_libraryBookSound1);
else
_vm->_sound->playEffect(_libraryBookSound2);
}
}
void Myst::o_fireplaceToggleButton(uint16 var, const ArgumentsArray &args) {
// Used on Myst Card 4162 (Fireplace Grid)
uint16 bitmask = args[0];
uint16 line = _fireplaceLines[var - 17];
Common::Rect buttonRect = getInvokingResource()->getRect();
// The animations are too slow when playing each animation image at 60fps.
// Only play every second image.
if (line & bitmask) {
// Unset button
for (uint i = 4795; i >= 4779; i -= 2) {
_vm->_gfx->copyImageToScreen(i, buttonRect);
_vm->doFrame();
}
_vm->_gfx->copyBackBufferToScreen(buttonRect);
_fireplaceLines[var - 17] &= ~bitmask;
} else {
// Set button
for (uint i = 4779; i <= 4795; i += 2) {
_vm->_gfx->copyImageToScreen(i, buttonRect);
_vm->doFrame();
}
_fireplaceLines[var - 17] |= bitmask;
}
}
void Myst::o_fireplaceRotation(uint16 var, const ArgumentsArray &args) {
// Used on Myst Card 4162 and 4166 (Fireplace Puzzle Rotation Movies)
uint16 movieNum = args[0];
if (movieNum)
_vm->playMovieBlocking("fpout", kMystStack, 167, 4);
else
_vm->playMovieBlocking("fpin", kMystStack, 167, 4);
}
void Myst::o_courtyardBoxesCheckSolution(uint16 var, const ArgumentsArray &args) {
uint16 soundId = args[0];
// Change ship state if the boxes are correctly enabled
if (_state.courtyardImageBoxes == 50 && !_state.shipFloating) {
_vm->_cursor->hideCursor();
_state.shipFloating = 1;
_vm->playSoundBlocking(soundId);
_vm->_cursor->showCursor();
} else if (_state.courtyardImageBoxes != 50 && _state.shipFloating) {
_vm->_cursor->hideCursor();
_state.shipFloating = 0;
_vm->playSoundBlocking(soundId);
_vm->_cursor->showCursor();
}
}
void Myst::o_towerRotationStart(uint16 var, const ArgumentsArray &args) {
_towerRotationBlinkLabel = false;
_towerRotationMapClicked = true;
_towerRotationSpeed = 0;
_vm->_cursor->setCursor(700);
Common::Point end = towerRotationMapComputeCoords(_state.towerRotationAngle);
towerRotationMapComputeAngle();
towerRotationMapDrawLine(end, true);
_vm->_sound->playEffect(5378, true);
}
void Myst::o_towerRotationEnd(uint16 var, const ArgumentsArray &args) {
_towerRotationMapClicked = false;
// Set angle value to expected value
if (_state.towerRotationAngle >= 265
&& _state.towerRotationAngle <= 277
&& _state.rocketshipMarkerSwitch) {
_state.towerRotationAngle = 271;
} else if (_state.towerRotationAngle >= 77
&& _state.towerRotationAngle <= 89
&& _state.gearsMarkerSwitch) {
_state.towerRotationAngle = 83;
} else if (_state.towerRotationAngle >= 123
&& _state.towerRotationAngle <= 135
&& _state.dockMarkerSwitch) {
_state.towerRotationAngle = 129;
} else if (_state.towerRotationAngle >= 146
&& _state.towerRotationAngle <= 158
&& _state.cabinMarkerSwitch) {
_state.towerRotationAngle = 152;
}
_vm->_sound->playEffect(6378);
_towerRotationBlinkLabel = true;
_towerRotationBlinkLabelCount = 0;
}
void Myst::o_imagerChangeSelection(uint16 var, const ArgumentsArray &args) {
if (_imagerValidationStep != 10) {
_imagerValidationStep = 0;
int16 signedValue = args[0];
uint16 d1 = (_state.imagerSelection / 10) % 10;
uint16 d2 = _state.imagerSelection % 10;
if (var == 35 && signedValue > 0 && d1 < 9)
d1++;
else if (var == 35 && signedValue < 0 && d1 > 0)
d1--;
else if (var == 36 && signedValue > 0 && d2 < 9)
d2++;
else if (var == 36 && signedValue < 0 && d2 > 0)
d2--;
_state.imagerSelection = 10 * d1 + d2;
_state.imagerActive = 0;
_vm->getCard()->redrawArea(var);
}
}
void Myst::o_dockVaultOpen(uint16 var, const ArgumentsArray &args) {
// Used on Myst 4143 (Dock near Marker Switch)
uint16 soundId = args[0];
uint16 delay = args[1];
uint16 directionalUpdateDataSize = args[2];
if ((_state.cabinMarkerSwitch == 1) &&
(_state.clockTowerMarkerSwitch == 1) &&
(_state.dockMarkerSwitch == 0) &&
(_state.gearsMarkerSwitch == 1) &&
(_state.generatorMarkerSwitch == 1) &&
(_state.observatoryMarkerSwitch == 1) &&
(_state.poolMarkerSwitch == 1) &&
(_state.rocketshipMarkerSwitch == 1)) {
if (_globals.heldPage != kWhitePage && _globals.ending != kBooksDestroyed)
_dockVaultState = 2;
else
_dockVaultState = 1;
_vm->_sound->playEffect(soundId);
_vm->getCard()->redrawArea(41, false);
animatedUpdate(ArgumentsArray(args.begin() + 3, directionalUpdateDataSize), delay);
}
}
void Myst::o_dockVaultClose(uint16 var, const ArgumentsArray &args) {
// Used on Myst 4143 (Dock near Marker Switch)
uint16 soundId = args[0];
uint16 delay = args[1];
uint16 directionalUpdateDataSize = args[2];
if ((_state.cabinMarkerSwitch == 1) &&
(_state.clockTowerMarkerSwitch == 1) &&
(_state.dockMarkerSwitch == 1) &&
(_state.gearsMarkerSwitch == 1) &&
(_state.generatorMarkerSwitch == 1) &&
(_state.observatoryMarkerSwitch == 1) &&
(_state.poolMarkerSwitch == 1) &&
(_state.rocketshipMarkerSwitch == 1)) {
if (_dockVaultState == 1 || _dockVaultState == 2)
_dockVaultState = 0;
_vm->_sound->playEffect(soundId);
_vm->getCard()->redrawArea(41, false);
animatedUpdate(ArgumentsArray(args.begin() + 3, directionalUpdateDataSize), delay);
}
}
void Myst::o_bookGivePage(uint16 var, const ArgumentsArray &args) {
uint16 cardIdLose = args[0];
uint16 cardIdBookCover = args[1];
uint16 soundIdAddPage = args[2];
debugC(kDebugScript, "Card Id (Lose): %d", cardIdLose);
debugC(kDebugScript, "Card Id (Book Cover): %d", cardIdBookCover);
debugC(kDebugScript, "SoundId (Add Page): %d", soundIdAddPage);
uint16 bookVar = 101;
uint16 mask = 0;
switch (_globals.heldPage) {
case kNoPage:
case kWhitePage:
_vm->changeToCard(cardIdBookCover, kTransitionDissolve);
return;
case kRedLibraryPage:
bookVar = 100;
// fallthrough
case kBlueLibraryPage:
mask = 1;
break;
case kRedSeleniticPage:
bookVar = 100;
// fallthrough
case kBlueSeleniticPage:
mask = 2;
break;
case kRedMechanicalPage:
bookVar = 100;
// fallthrough
case kBlueMechanicalPage:
mask = 4;
break;
case kRedStoneshipPage:
bookVar = 100;
// fallthrough
case kBlueStoneshipPage:
mask = 8;
break;
case kRedChannelwoodPage:
bookVar = 100;
// fallthrough
case kBlueChannelwoodPage:
mask = 16;
break;
case kRedFirePlacePage:
bookVar = 100;
// fallthrough
case kBlueFirePlacePage:
mask = 32;
break;
default:
break;
}
// Wrong book
if (bookVar != var) {
_vm->changeToCard(cardIdBookCover, kTransitionDissolve);
return;
}
_vm->_cursor->hideCursor();
_vm->playSoundBlocking(soundIdAddPage);
_vm->setMainCursor(kDefaultMystCursor);
// Add page to book
if (var == 100)
_globals.redPagesInBook |= mask;
else
_globals.bluePagesInBook |= mask;
// Remove page from hand
_globals.heldPage = kNoPage;
_vm->_cursor->showCursor();
if (mask == 32) {
// You lose!
if (var == 100)
_globals.currentAge = kSirrusEnding;
else
_globals.currentAge = kAchenarEnding;
_vm->changeToCard(cardIdLose, kTransitionDissolve);
} else {
_vm->changeToCard(cardIdBookCover, kTransitionDissolve);
}
}
void Myst::o_clockWheelsExecute(uint16 var, const ArgumentsArray &args) {
// Used on Card 4006 (Clock Tower Time Controls)
uint16 soundId = args[0];
// Correct time is 2:40
bool correctTime = _state.clockTowerHourPosition == 2
&& _state.clockTowerMinutePosition == 40;
if (!_state.clockTowerBridgeOpen && correctTime) {
_vm->_sound->playEffect(soundId);
_vm->wait(500);
// Gears rise up
VideoEntryPtr gears = _vm->playMovie("gears", kMystStack);
gears->moveTo(305, 33);
gears->setBounds(Audio::Timestamp(0, 0, 600), Audio::Timestamp(0, 650, 600));
_vm->waitUntilMovieEnds(gears);
_state.clockTowerBridgeOpen = 1;
_vm->getCard()->redrawArea(12);
} else if (_state.clockTowerBridgeOpen && !correctTime) {
_vm->_sound->playEffect(soundId);
_vm->wait(500);
// Gears sink down
VideoEntryPtr gears = _vm->playMovie("gears", kMystStack);
gears->moveTo(305, 33);
gears->setBounds(Audio::Timestamp(0, 700, 600), Audio::Timestamp(0, 1300, 600));
_vm->waitUntilMovieEnds(gears);
_state.clockTowerBridgeOpen = 0;
_vm->getCard()->redrawArea(12);
}
}
void Myst::o_imagerPlayButton(uint16 var, const ArgumentsArray &args) {
uint16 video = getVar(51);
// Press button
_vm->_sound->playEffect(4698);
Common::Rect src = Common::Rect(0, 0, 32, 75);
Common::Rect dest = Common::Rect(261, 257, 293, 332);
_vm->_gfx->copyImageSectionToScreen(4699, src, dest);
_vm->wait(200);
_vm->_gfx->copyBackBufferToScreen(dest);
_vm->doFrame();
_vm->_cursor->hideCursor();
// Play selected video
if (!_state.imagerActive && video != 3)
_vm->_sound->playEffect(args[0]);
switch (video) {
case 0: // Nothing
case 3: // Atrus
case 4: // Marker
_imagerMovie->playMovie();
break;
case 1: // Mountain
if (_state.imagerActive) {
// Mountains disappearing
Common::String file = "vltmntn";
VideoEntryPtr mountain = _vm->playMovie(file, kMystStack);
mountain->moveTo(159, 96);
mountain->setBounds(Audio::Timestamp(0, 11180, 600), Audio::Timestamp(0, 16800, 600));
_state.imagerActive = 0;
} else {
// Mountains appearing
Common::String file = "vltmntn";
VideoEntryPtr mountain = _vm->playMovie(file, kMystStack);
mountain->moveTo(159, 96);
mountain->setBounds(Audio::Timestamp(0, 0, 600), Audio::Timestamp(0, 11180, 600));
_state.imagerActive = 1;
}
break;
case 2: // Water
_imagerMovie->setBlocking(false);
if (_state.imagerActive) {
_vm->_sound->playEffect(args[1]);
// Water disappearing
VideoEntryPtr water = _imagerMovie->playMovie();
water->setBounds(Audio::Timestamp(0, 4204, 600), Audio::Timestamp(0, 6040, 600));
water->setLooping(false);
_state.imagerActive = 0;
} else {
// Water appearing
VideoEntryPtr water = _imagerMovie->playMovie();
water->setBounds(Audio::Timestamp(0, 0, 600), Audio::Timestamp(0, 1814, 600));
_vm->waitUntilMovieEnds(water);
// Water looping
water = _imagerMovie->playMovie();
water->setBounds(Audio::Timestamp(0, 1814, 600), Audio::Timestamp(0, 4204, 600));
water->setLooping(true);
_state.imagerActive = 1;
}
break;
default:
break;
}
_vm->_cursor->showCursor();
}
void Myst::o_imagerEraseButton(uint16 var, const ArgumentsArray &args) {
_imagerRedButton = static_cast(getInvokingResource()->_parent);
for (uint i = 0; i < 4; i++)
_imagerSound[i] = args[i];
_imagerValidationCard = args[4];
if (_imagerValidationStep == 0) {
// Validation script is not running, run it
_startTime = _vm->getTotalPlayTime() + 100;
_imagerValidationRunning = true;
return;
} else if (_imagerValidationStep < 7) {
// Too early
_vm->playSoundBlocking(_imagerSound[2]);
_imagerValidationStep = 0;
return;
} else if (_imagerValidationStep < 11) {
_vm->playSoundBlocking(_imagerSound[3]);
// Erase selected video from imager
switch (_state.imagerSelection) {
case 8:
_state.imagerAtrusErased = 1;
break;
case 40:
_state.imagerMountainErased = 1;
break;
case 47:
_state.imagerMarkerErased = 1;
break;
case 67:
_state.imagerWaterErased = 1;
break;
default:
break;
}
_state.imagerActive = 0;
_imagerValidationStep = 0;
return;
} else if (_imagerValidationStep == 11) {
// Too late
_imagerValidationStep = 0;
return;
}
}
void Myst::imagerValidation_run() {
uint32 time = _vm->getTotalPlayTime();
if (time > _startTime) {
_imagerRedButton->drawConditionalDataToScreen(1);
if (_imagerValidationStep < 6)
_vm->_sound->playEffect(_imagerSound[0]);
else if (_imagerValidationStep < 10)
_vm->_sound->playEffect(_imagerSound[1]);
else if (_imagerValidationStep == 10)
_vm->_sound->playEffect(_imagerSound[2]);
_imagerValidationStep++;
_vm->wait(50);
_imagerRedButton->drawConditionalDataToScreen(0);
if (_imagerValidationStep == 11) {
_imagerValidationStep = 0;
_vm->changeToCard(_imagerValidationCard, kTransitionBottomToTop);
} else {
_startTime = time + 100;
}
}
}
void Myst::o_towerElevatorAnimation(uint16 var, const ArgumentsArray &args) {
_treeStopped = true;
_vm->_cursor->hideCursor();
_vm->_sound->stopEffect();
_vm->_sound->pauseBackground();
switch (args[0]) {
case 0:
_vm->playMovieBlocking("libdown", kMystStack, 216, 78);
break;
case 1:
_vm->playMovieBlocking("libup", kMystStack, 216, 78);
break;
default:
break;
}
_vm->_sound->resumeBackground();
_vm->_cursor->showCursor();
_treeStopped = false;
}
void Myst::o_generatorButtonPressed(uint16 var, const ArgumentsArray &args) {
MystArea *button = getInvokingResource()->_parent;
generatorRedrawRocket();
_generatorVoltage = _state.generatorVoltage;
uint16 mask = 0;
uint16 value = 0;
generatorButtonValue(button, mask, value);
// Button pressed
if (_state.generatorButtons & mask) {
_state.generatorButtons &= ~mask;
_state.generatorVoltage -= value;
if (_state.generatorVoltage)
_vm->_sound->playEffect(8297);
else {
_vm->_sound->playEffect(9297);
_vm->_sound->stopBackground();
}
} else {
if (_generatorVoltage)
_vm->_sound->playEffect(6297);
else {
_vm->_sound->playBackground(4297);
_vm->_sound->playEffect(7297);
}
_state.generatorButtons |= mask;
_state.generatorVoltage += value;
}
// Redraw button
_vm->getCard()->redrawArea(button->getImageSwitchVar());
// Blow breaker
if (_state.generatorVoltage > 59)
_state.generatorBreakers = _vm->_rnd->getRandomNumberRng(1, 2);
}
void Myst::generatorRedrawRocket() {
_vm->getCard()->redrawArea(64);
_vm->getCard()->redrawArea(65);
_vm->getCard()->redrawArea(97);
}
void Myst::generatorButtonValue(MystArea *button, uint16 &mask, uint16 &value) {
switch (button->getImageSwitchVar()) {
case 52: // Generator Switch #1
mask = 1;
value = 10;
break;
case 53: // Generator Switch #2
mask = 2;
value = 7;
break;
case 54: // Generator Switch #3
mask = 4;
value = 8;
break;
case 55: // Generator Switch #4
mask = 8;
value = 16;
break;
case 56: // Generator Switch #5
mask = 16;
value = 5;
break;
case 57: // Generator Switch #6
mask = 32;
value = 1;
break;
case 58: // Generator Switch #7
mask = 64;
value = 2;
break;
case 59: // Generator Switch #8
mask = 128;
value = 22;
break;
case 60: // Generator Switch #9
mask = 256;
value = 19;
break;
case 61: // Generator Switch #10
mask = 512;
value = 9;
break;
default:
break;
}
}
void Myst::o_cabinSafeChangeDigit(uint16 var, const ArgumentsArray &args) {
uint16 d1 = _state.cabinSafeCombination / 100;
uint16 d2 = (_state.cabinSafeCombination / 10) % 10;
uint16 d3 = _state.cabinSafeCombination % 10;
if (var == 67)
d1 = (d1 + 1) % 10;
else if (var == 68)
d2 = (d2 + 1) % 10;
else
d3 = (d3 + 1) % 10;
_state.cabinSafeCombination = 100 * d1 + 10 * d2 + d3;
_vm->getCard()->redrawArea(var);
}
void Myst::o_cabinSafeHandleStartMove(uint16 var, const ArgumentsArray &args) {
// Used on Card 4100
MystVideoInfo *handle = getInvokingResource();
handle->drawFrame(0);
_vm->_cursor->setCursor(700);
_tempVar = 0;
}
void Myst::o_cabinSafeHandleMove(uint16 var, const ArgumentsArray &args) {
// Used on Card 4100
MystVideoInfo *handle = getInvokingResource();
if (handle->pullLeverV()) {
// Sound not played yet
if (_tempVar == 0) {
uint16 soundId = handle->getList2(0);
if (soundId)
_vm->_sound->playEffect(soundId);
}
// Combination is right
if (_state.cabinSafeCombination == 724) {
uint16 soundId = handle->getList2(1);
if (soundId)
_vm->_sound->playEffect(soundId);
_vm->changeToCard(4103, kNoTransition);
Common::Rect screenRect = Common::Rect(544, 333);
_vm->_gfx->runTransition(kTransitionLeftToRight, screenRect, 2, 5);
}
_tempVar = 1;
} else {
_tempVar = 0;
}
}
void Myst::o_cabinSafeHandleEndMove(uint16 var, const ArgumentsArray &args) {
// Used on Card 4100
MystVideoInfo *handle = getInvokingResource();
handle->drawFrame(0);
_vm->refreshCursor();
}
void Myst::o_observatoryMonthChangeStartIncrease(uint16 var, const ArgumentsArray &args) {
observatoryMonthChangeStart(true);
}
void Myst::o_observatoryMonthChangeStartDecrease(uint16 var, const ArgumentsArray &args) {
observatoryMonthChangeStart(false);
}
void Myst::observatoryMonthChangeStart(bool increase) {
_vm->_sound->pauseBackground();
if (increase) {
// Increase
if (observatoryIsDDMMYYYY2400())
_vm->_gfx->copyImageSectionToScreen(11098, Common::Rect(36, 0, 48, 9), Common::Rect(351, 70, 363, 79));
else
_vm->_gfx->copyImageSectionToScreen(11098, Common::Rect(0, 0, 12, 9), Common::Rect(315, 70, 327, 79));
_observatoryIncrement = -1;
} else {
// Decrease
if (observatoryIsDDMMYYYY2400())
_vm->_gfx->copyImageSectionToScreen(11097, Common::Rect(36, 0, 48, 9), Common::Rect(351, 204, 363, 213));
else
_vm->_gfx->copyImageSectionToScreen(11097, Common::Rect(0, 0, 12, 9), Common::Rect(315, 204, 327, 213));
_observatoryIncrement = 1;
}
// Highlight slider
_observatoryMonthSlider->drawConditionalDataToScreen(2);
_observatoryCurrentSlider = _observatoryMonthSlider;
// First increment
observatoryIncrementMonth(_observatoryIncrement);
// Start persistent script
_startTime = _vm->getTotalPlayTime();
_observatoryMonthChanging = true;
}
void Myst::observatoryIncrementMonth(int16 increment) {
int16 newMonth = _state.observatoryMonthSetting + increment;
if (newMonth >= 0 && newMonth <= 11) {
_state.observatoryMonthSetting = newMonth;
// Redraw digits
_vm->getCard()->redrawArea(73);
// Update slider
_observatoryMonthSlider->setPosition(94 + 94 * _state.observatoryMonthSetting / 11);
_observatoryMonthSlider->restoreBackground();
_observatoryMonthSlider->drawConditionalDataToScreen(2);
_state.observatoryMonthSlider = _observatoryMonthSlider->_pos.y;
}
_vm->_sound->playEffect(8500);
_vm->wait(20);
}
void Myst::observatoryMonthChange_run() {
if (_startTime + 500 < _vm->getTotalPlayTime())
observatoryIncrementMonth(_observatoryIncrement);
}
void Myst::o_observatoryDayChangeStartIncrease(uint16 var, const ArgumentsArray &args) {
observatoryDayChangeStart(true);
}
void Myst::o_observatoryDayChangeStartDecrease(uint16 var, const ArgumentsArray &args) {
observatoryDayChangeStart(false);
}
void Myst::observatoryDayChangeStart(bool increase) {
_vm->_sound->pauseBackground();
if (increase) {
// Increase
if (observatoryIsDDMMYYYY2400())
_vm->_gfx->copyImageSectionToScreen(11098, Common::Rect(0, 0, 12, 9), Common::Rect(315, 70, 327, 79));
else
_vm->_gfx->copyImageSectionToScreen(11098, Common::Rect(36, 0, 48, 9), Common::Rect(351, 70, 363, 79));
_observatoryIncrement = -1;
} else {
// Decrease
if (observatoryIsDDMMYYYY2400())
_vm->_gfx->copyImageSectionToScreen(11097, Common::Rect(0, 0, 12, 9), Common::Rect(315, 204, 327, 213));
else
_vm->_gfx->copyImageSectionToScreen(11097, Common::Rect(36, 0, 48, 9), Common::Rect(351, 204, 363, 213));
_observatoryIncrement = 1;
}
// Highlight slider
_observatoryDaySlider->drawConditionalDataToScreen(2);
_observatoryCurrentSlider = _observatoryDaySlider;
// First increment
observatoryIncrementDay(_observatoryIncrement);
// Start persistent script
_startTime = _vm->getTotalPlayTime();
_observatoryDayChanging = true;
}
void Myst::observatoryIncrementDay(int16 increment) {
int16 newDay = _state.observatoryDaySetting + increment;
if (newDay >= 1 && newDay <= 31) {
_state.observatoryDaySetting = newDay;
// Redraw digits
_vm->getCard()->redrawArea(75);
_vm->getCard()->redrawArea(74);
// Update slider
// WORKAROUND: Have the day setting increment at 315/100 rather than x3 so that the slider
// will reach the bottom spot on day 31st. Only relevant when using the down button and
// not dragging the slider. Fixes Trac#10572. The original engine incremented it with x3
// and has this bug, but it is less noticeable.
_observatoryDaySlider->setPosition(91 + (_state.observatoryDaySetting * 315) / 100 );
_observatoryDaySlider->restoreBackground();
_observatoryDaySlider->drawConditionalDataToScreen(2);
_state.observatoryDaySlider = _observatoryDaySlider->_pos.y;
}
_vm->_sound->playEffect(8500);
_vm->wait(20);
}
void Myst::observatoryDayChange_run() {
if (_startTime + 500 < _vm->getTotalPlayTime())
observatoryIncrementDay(_observatoryIncrement);
}
void Myst::o_observatoryYearChangeStartIncrease(uint16 var, const ArgumentsArray &args) {
observatoryYearChangeStart(true);
}
void Myst::o_observatoryYearChangeStartDecrease(uint16 var, const ArgumentsArray &args) {
observatoryYearChangeStart(false);
}
void Myst::observatoryYearChangeStart(bool increase) {
_vm->_sound->pauseBackground();
if (increase) {
// Increase
_vm->_gfx->copyImageSectionToScreen(11098, Common::Rect(72, 0, 84, 9), Common::Rect(387, 70, 399, 79));
_observatoryIncrement = -1;
} else {
// Decrease
_vm->_gfx->copyImageSectionToScreen(11097, Common::Rect(72, 0, 84, 9), Common::Rect(387, 204, 399, 213));
_observatoryIncrement = 1;
}
// Highlight slider
_observatoryYearSlider->drawConditionalDataToScreen(2);
_observatoryCurrentSlider = _observatoryYearSlider;
// First increment
observatoryIncrementYear(_observatoryIncrement);
// Start persistent script
_startTime = _vm->getTotalPlayTime();
_observatoryYearChanging = true;
}
void Myst::observatoryIncrementYear(int16 increment) {
int16 newYear = _state.observatoryYearSetting + increment;
if (newYear >= 0 && newYear <= 9999) {
_state.observatoryYearSetting = newYear;
// Redraw digits
_vm->getCard()->redrawArea(79);
_vm->getCard()->redrawArea(78);
_vm->getCard()->redrawArea(77);
_vm->getCard()->redrawArea(76);
// Update slider
_observatoryYearSlider->setPosition(94 + 94 * _state.observatoryYearSetting / 9999);
_observatoryYearSlider->restoreBackground();
_observatoryYearSlider->drawConditionalDataToScreen(2);
_state.observatoryYearSlider = _observatoryYearSlider->_pos.y;
}
_vm->_sound->playEffect(8500);
_vm->wait(20);
}
void Myst::observatoryYearChange_run() {
if (_startTime + 500 < _vm->getTotalPlayTime())
observatoryIncrementYear(_observatoryIncrement);
}
void Myst::o_observatoryTimeChangeStartIncrease(uint16 var, const ArgumentsArray &args) {
observatoryTimeChangeStart(true);
}
void Myst::o_observatoryTimeChangeStartDecrease(uint16 var, const ArgumentsArray &args) {
observatoryTimeChangeStart(false);
}
void Myst::observatoryTimeChangeStart(bool increase) {
_vm->_sound->pauseBackground();
if (increase) {
// Increase
_vm->_gfx->copyImageSectionToScreen(11098, Common::Rect(109, 0, 121, 9), Common::Rect(424, 70, 436, 79));
_observatoryIncrement = -1;
} else {
// Decrease
_vm->_gfx->copyImageSectionToScreen(11097, Common::Rect(109, 0, 121, 9), Common::Rect(424, 204, 436, 213));
_observatoryIncrement = 1;
}
// Highlight slider
_observatoryTimeSlider->drawConditionalDataToScreen(2);
_observatoryCurrentSlider = _observatoryTimeSlider;
// First increment
observatoryIncrementTime(_observatoryIncrement);
// Start persistent script
_startTime = _vm->getTotalPlayTime();
_observatoryTimeChanging = true;
}
void Myst::observatoryIncrementTime(int16 increment) {
int16 newTime = _state.observatoryTimeSetting + increment;
if (newTime >= 0 && newTime <= 1439) {
_state.observatoryTimeSetting = newTime;
// Redraw digits
_vm->getCard()->redrawArea(80);
_vm->getCard()->redrawArea(81);
_vm->getCard()->redrawArea(82);
_vm->getCard()->redrawArea(83);
// Draw AM/PM
if (!observatoryIsDDMMYYYY2400()) {
_vm->getCard()->redrawArea(88);
}
// Update slider
_observatoryTimeSlider->setPosition(94 + 94 * _state.observatoryTimeSetting / 1439);
_observatoryTimeSlider->restoreBackground();
_observatoryTimeSlider->drawConditionalDataToScreen(2);
_state.observatoryTimeSlider = _observatoryTimeSlider->_pos.y;
}
_vm->_sound->playEffect(8500);
_vm->wait(20);
}
void Myst::observatoryTimeChange_run() {
if (_startTime + 500 < _vm->getTotalPlayTime())
observatoryIncrementTime(_observatoryIncrement);
}
void Myst::o_observatoryGoButton(uint16 var, const ArgumentsArray &args) {
// Setting not at target
if (_state.observatoryDayTarget != _state.observatoryDaySetting
|| _state.observatoryMonthTarget != _state.observatoryMonthSetting
|| _state.observatoryYearTarget != _state.observatoryYearSetting
|| _state.observatoryTimeTarget != _state.observatoryTimeSetting) {
uint16 soundId = args[0];
_vm->_sound->playEffect(soundId);
int16 distance = _state.observatoryYearTarget - _state.observatoryYearSetting;
uint32 end = _vm->getTotalPlayTime() + 32 * ABS(distance) / 50 + 800;
while (end > _vm->getTotalPlayTime()) {
_vm->wait(50);
observatoryUpdateVisualizer(_vm->_rnd->getRandomNumber(406), _vm->_rnd->getRandomNumber(406));
_vm->redrawResource(_observatoryVisualizer);
}
_vm->_sound->resumeBackground();
// Redraw visualizer
observatorySetTargetToSetting();
_vm->redrawResource(_observatoryVisualizer);
// Redraw button
_tempVar = 0;
_vm->getCard()->redrawArea(105);
}
}
void Myst::o_observatoryMonthSliderMove(uint16 var, const ArgumentsArray &args) {
observatoryUpdateMonth();
}
void Myst::o_observatoryDaySliderMove(uint16 var, const ArgumentsArray &args) {
observatoryUpdateDay();
}
void Myst::o_observatoryYearSliderMove(uint16 var, const ArgumentsArray &args) {
observatoryUpdateYear();
}
void Myst::o_observatoryTimeSliderMove(uint16 var, const ArgumentsArray &args) {
observatoryUpdateTime();
}
void Myst::o_circuitBreakerStartMove(uint16 var, const ArgumentsArray &args) {
MystVideoInfo *breaker = getInvokingResource();
breaker->drawFrame(0);
_vm->_cursor->setCursor(700);
_tempVar = 0;
}
void Myst::o_circuitBreakerMove(uint16 var, const ArgumentsArray &args) {
MystVideoInfo *breaker = getInvokingResource();
const Common::Point &mouse = _vm->_system->getEventManager()->getMousePos();
int16 maxStep = breaker->getStepsV() - 1;
int16 step = ((mouse.y - 80) * breaker->getStepsV()) / 65;
step = CLIP(step, 0, maxStep);
breaker->drawFrame(step);
if (_tempVar != step) {
_tempVar = step;
// Breaker switched
if (step == maxStep) {
// Choose breaker
if (breaker->getImageSwitchVar() == 93) {
// Voltage is still too high or not broken
if (_state.generatorVoltage > 59 || _state.generatorBreakers != 1) {
uint16 soundId = breaker->getList2(1);
if (soundId)
_vm->_sound->playEffect(soundId);
} else {
uint16 soundId = breaker->getList2(0);
if (soundId)
_vm->_sound->playEffect(soundId);
// Reset breaker state
_state.generatorBreakers = 0;
}
} else {
// Voltage is still too high or not broken
if (_state.generatorVoltage > 59 || _state.generatorBreakers != 2) {
uint16 soundId = breaker->getList2(1);
if (soundId)
_vm->_sound->playEffect(soundId);
} else {
uint16 soundId = breaker->getList2(0);
if (soundId)
_vm->_sound->playEffect(soundId);
// Reset breaker state
_state.generatorBreakers = 0;
}
}
}
}
}
void Myst::o_circuitBreakerEndMove(uint16 var, const ArgumentsArray &args) {
MystVideoInfo *breaker = getInvokingResource();
_vm->getCard()->redrawArea(breaker->getImageSwitchVar());
_vm->refreshCursor();
}
void Myst::o_boilerIncreasePressureStart(uint16 var, const ArgumentsArray &args) {
_treeStopped = true;
if (_state.cabinValvePosition < 25)
_vm->_sound->stopBackground();
_boilerPressureIncreasing = true;
}
void Myst::o_boilerLightPilot(uint16 var, const ArgumentsArray &args) {
// Match is lit
if (_cabinMatchState == 1) {
_state.cabinPilotLightLit = 1;
_vm->getCard()->redrawArea(98);
boilerFireUpdate(false);
// Put out match
_matchGoOutTime = _vm->getTotalPlayTime();
if (_state.cabinValvePosition > 0)
_vm->_sound->playBackground(8098, 49152);
if (_state.cabinValvePosition > 12) {
// Compute the speed of the gauge to synchronize it with the next tree move
uint32 delay = treeNextMoveDelay(_state.cabinValvePosition);
Common::Rational rate = boilerComputeGaugeRate(_state.cabinValvePosition, delay);
boilerResetGauge(rate);
_state.treeLastMoveTime = _vm->getTotalPlayTime();
}
}
}
Common::Rational Myst::boilerComputeGaugeRate(uint16 pressure, uint32 delay) {
Common::Rational rate = Common::Rational(2088, delay);
if (pressure < 12)
return -rate;
else
return rate;
}
void Myst::boilerResetGauge(const Common::Rational &rate) {
if (!_cabinGaugeMovie || _cabinGaugeMovie->endOfVideo()) {
if (_vm->getCard()->getId() == 4098) {
_cabinGaugeMovie = _vm->playMovie("cabingau", kMystStack);
_cabinGaugeMovie->moveTo(243, 96);
} else {
_cabinGaugeMovie = _vm->playMovie("cabcgfar", kMystStack);
_cabinGaugeMovie->moveTo(254, 136);
}
}
Audio::Timestamp goTo;
if (rate > 0)
goTo = Audio::Timestamp(0, 0, 600);
else
goTo = _cabinGaugeMovie->getDuration();
_cabinGaugeMovie->seek(goTo);
_cabinGaugeMovie->setRate(rate);
}
void Myst::o_boilerIncreasePressureStop(uint16 var, const ArgumentsArray &args) {
_treeStopped = false;
_boilerPressureIncreasing = false;
_state.treeLastMoveTime = _vm->getTotalPlayTime();
while (_vm->_sound->isEffectPlaying()) {
_vm->doFrame();
}
if (_state.cabinPilotLightLit == 1) {
if (_state.cabinValvePosition > 0)
_vm->_sound->playBackground(8098, 49152);
if (_cabinGaugeMovie && !_cabinGaugeMovie->endOfVideo()) {
uint16 delay = treeNextMoveDelay(_state.cabinValvePosition);
Common::Rational rate = boilerComputeGaugeRate(_state.cabinValvePosition, delay);
_cabinGaugeMovie->setRate(rate);
}
} else if (_state.cabinValvePosition > 0)
_vm->_sound->playBackground(4098, _state.cabinValvePosition << 10);
}
void Myst::boilerPressureIncrease_run() {
// Allow increasing pressure if sound has stopped
if (!_vm->_sound->isEffectPlaying() && _state.cabinValvePosition < 25) {
_state.cabinValvePosition++;
if (_state.cabinValvePosition == 1) {
// Set fire to high
boilerFireUpdate(false);
// Draw fire
_vm->getCard()->redrawArea(305);
} else if (_state.cabinValvePosition == 25) {
if (_state.cabinPilotLightLit == 1)
_vm->_sound->playBackground(8098, 49152);
else
_vm->_sound->playBackground(4098, 25600);
}
// Pressure increasing sound
_vm->_sound->playEffect(5098);
// Redraw wheel
_vm->getCard()->redrawArea(99);
}
}
void Myst::boilerPressureDecrease_run() {
// Allow decreasing pressure if sound has stopped
if (!_vm->_sound->isEffectPlaying() && _state.cabinValvePosition > 0) {
_state.cabinValvePosition--;
if (_state.cabinValvePosition == 0) {
// Set fire to low
boilerFireUpdate(false);
// Draw fire
_vm->getCard()->redrawArea(305);
}
// Pressure increasing sound
_vm->_sound->playEffect(5098);
// Redraw wheel
_vm->getCard()->redrawArea(99);
}
}
void Myst::o_boilerDecreasePressureStart(uint16 var, const ArgumentsArray &args) {
_treeStopped = true;
_vm->_sound->stopBackground();
_boilerPressureDecreasing = true;
}
void Myst::o_boilerDecreasePressureStop(uint16 var, const ArgumentsArray &args) {
_treeStopped = false;
_boilerPressureDecreasing = false;
_state.treeLastMoveTime = _vm->getTotalPlayTime();
while (_vm->_sound->isEffectPlaying()) {
_vm->doFrame();
}
if (_state.cabinPilotLightLit == 1) {
if (_state.cabinValvePosition > 0)
_vm->_sound->playBackground(8098, 49152);
if (_cabinGaugeMovie && !_cabinGaugeMovie->endOfVideo()) {
uint16 delay = treeNextMoveDelay(_state.cabinValvePosition);
Common::Rational rate = boilerComputeGaugeRate(_state.cabinValvePosition, delay);
_cabinGaugeMovie->setRate(rate);
}
} else {
if (_state.cabinValvePosition > 0)
_vm->_sound->playBackground(4098, _state.cabinValvePosition << 10);
}
}
void Myst::o_basementIncreasePressureStart(uint16 var, const ArgumentsArray &args) {
_treeStopped = true;
_basementPressureIncreasing = true;
}
void Myst::o_basementIncreasePressureStop(uint16 var, const ArgumentsArray &args) {
_treeStopped = false;
_basementPressureIncreasing = false;
_state.treeLastMoveTime = _vm->getTotalPlayTime();
}
void Myst::basementPressureIncrease_run() {
// Allow increasing pressure if sound has stopped
if (!_vm->_sound->isEffectPlaying() && _state.cabinValvePosition < 25) {
_state.cabinValvePosition++;
// Pressure increasing sound
_vm->_sound->playEffect(4642);
// Redraw wheel
_vm->getCard()->redrawArea(99);
}
}
void Myst::basementPressureDecrease_run() {
// Allow decreasing pressure if sound has stopped
if (!_vm->_sound->isEffectPlaying() && _state.cabinValvePosition > 0) {
_state.cabinValvePosition--;
// Pressure decreasing sound
_vm->_sound->playEffect(4642);
// Redraw wheel
_vm->getCard()->redrawArea(99);
}
}
void Myst::o_basementDecreasePressureStart(uint16 var, const ArgumentsArray &args) {
_treeStopped = true;
_basementPressureDecreasing = true;
}
void Myst::o_basementDecreasePressureStop(uint16 var, const ArgumentsArray &args) {
_treeStopped = false;
_basementPressureDecreasing = false;
_state.treeLastMoveTime = _vm->getTotalPlayTime();
}
void Myst::tree_run() {
uint16 pressure;
if (_state.cabinPilotLightLit)
pressure = _state.cabinValvePosition;
else
pressure = 0;
// 12 means tree is balanced
if (pressure != 12) {
bool goingDown = true;
if (pressure >= 12)
goingDown = false;
// Tree is within bounds
if ((_state.treePosition < 12 && !goingDown)
|| (_state.treePosition > _treeMinPosition && goingDown)) {
uint16 delay = treeNextMoveDelay(pressure);
uint32 time = _vm->getTotalPlayTime();
if (delay < time - _state.treeLastMoveTime) {
// Tree movement
if (goingDown) {
_state.treePosition--;
_vm->_sound->playEffect(2);
} else {
_state.treePosition++;
_vm->_sound->playEffect(1);
}
// Stop background music if going up from book room
if (_vm->getCard()->getId() == 4630) {
if (_state.treePosition > 0)
_vm->_sound->stopBackground();
else
_vm->_sound->playBackground(4630, 24576);
}
// Redraw tree
_vm->getCard()->redrawArea(72);
// Check if alcove is accessible
treeSetAlcoveAccessible();
if (_cabinGaugeMovieEnabled) {
Common::Rational rate = boilerComputeGaugeRate(pressure, delay);
boilerResetGauge(rate);
}
_state.treeLastMoveTime = time;
}
}
}
}
void Myst::treeSetAlcoveAccessible() {
if (_treeAlcove) {
// Make alcove accessible if the tree is in the correct position
_treeAlcove->setEnabled(_state.treePosition >= _treeMinAccessiblePosition
&& _state.treePosition <= _treeMaxAccessiblePosition);
}
}
uint32 Myst::treeNextMoveDelay(uint16 pressure) {
if (pressure >= 12)
return 25000 * (13 - (pressure - 12)) / 12 + 3000;
else
return 25000 * pressure / 13 + 3000;
}
void Myst::o_rocketSoundSliderStartMove(uint16 var, const ArgumentsArray &args) {
_rocketSliderSound = 0;
_vm->_cursor->setCursor(700);
_vm->_sound->pauseBackground();
rocketSliderMove();
}
void Myst::o_rocketSoundSliderMove(uint16 var, const ArgumentsArray &args) {
rocketSliderMove();
}
void Myst::o_rocketSoundSliderEndMove(uint16 var, const ArgumentsArray &args) {
_vm->refreshCursor();
if (_state.generatorVoltage == 59 && !_state.generatorBreakers && _rocketSliderSound)
_vm->_sound->stopEffect();
if (getInvokingResource() == _rocketSlider1)
_state.rocketSliderPosition[0] = _rocketSlider1->_pos.y;
else if (getInvokingResource() == _rocketSlider2)
_state.rocketSliderPosition[1] = _rocketSlider2->_pos.y;
else if (getInvokingResource() == _rocketSlider3)
_state.rocketSliderPosition[2] = _rocketSlider3->_pos.y;
else if (getInvokingResource() == _rocketSlider4)
_state.rocketSliderPosition[3] = _rocketSlider4->_pos.y;
else if (getInvokingResource() == _rocketSlider5)
_state.rocketSliderPosition[4] = _rocketSlider5->_pos.y;
_vm->_sound->resumeBackground();
}
void Myst::rocketSliderMove() {
MystAreaSlider *slider = getInvokingResource();
if (_state.generatorVoltage == 59 && !_state.generatorBreakers) {
uint16 soundId = rocketSliderGetSound(slider->_pos.y);
if (soundId != _rocketSliderSound) {
_rocketSliderSound = soundId;
_vm->_sound->playEffect(soundId, true);
}
}
}
uint16 Myst::rocketSliderGetSound(uint16 pos) {
return (uint16)(9530 + (pos - 216) * 35.0 / 61.0);
}
uint16 Myst::rocketCheckIfSoundMatches(uint16 sound1, uint16 sound2) {
debugN("rocketCheckIfSoundMatches: %i %i (diff:% 3i) ", sound1, sound2, sound1 - sound2);
if (!ConfMan.getBool("fuzzy_logic")) {
debugN("strict\n");
return sound1 == sound2;
} else {
debugN("fuzzy\n");
return abs(sound1 - sound2) < 5;
}
}
void Myst::rocketCheckSolution() {
_vm->_cursor->hideCursor();
uint16 soundId;
bool solved = true;
soundId = rocketSliderGetSound(_rocketSlider1->_pos.y);
_vm->_sound->playEffect(soundId);
_rocketSlider1->drawConditionalDataToScreen(2);
_vm->wait(250);
if (!rocketCheckIfSoundMatches(soundId, 9558))
solved = false;
soundId = rocketSliderGetSound(_rocketSlider2->_pos.y);
_vm->_sound->playEffect(soundId);
_rocketSlider2->drawConditionalDataToScreen(2);
_vm->wait(250);
if (!rocketCheckIfSoundMatches(soundId, 9546))
solved = false;
soundId = rocketSliderGetSound(_rocketSlider3->_pos.y);
_vm->_sound->playEffect(soundId);
_rocketSlider3->drawConditionalDataToScreen(2);
_vm->wait(250);
if (!rocketCheckIfSoundMatches(soundId, 9543))
solved = false;
soundId = rocketSliderGetSound(_rocketSlider4->_pos.y);
_vm->_sound->playEffect(soundId);
_rocketSlider4->drawConditionalDataToScreen(2);
_vm->wait(250);
if (!rocketCheckIfSoundMatches(soundId, 9553))
solved = false;
soundId = rocketSliderGetSound(_rocketSlider5->_pos.y);
_vm->_sound->playEffect(soundId);
_rocketSlider5->drawConditionalDataToScreen(2);
_vm->wait(250);
if (!rocketCheckIfSoundMatches(soundId, 9560))
solved = false;
_vm->_sound->stopEffect();
if (solved && !_rocketLinkBook) {
// Reset lever position
MystVideoInfo *lever = getInvokingResource();
lever->drawFrame(0);
// Book appearing
Common::String movieFile = "selenbok";
_rocketLinkBook = _vm->playMovie(movieFile, kMystStack);
_rocketLinkBook->moveTo(224, 41);
_rocketLinkBook->setBounds(Audio::Timestamp(0, 0, 600), Audio::Timestamp(0, 660, 600));
_vm->waitUntilMovieEnds(_rocketLinkBook);
// Book looping closed
_rocketLinkBook = _vm->playMovie(movieFile, kMystStack);
_rocketLinkBook->moveTo(224, 41);
_rocketLinkBook->setLooping(true);
_rocketLinkBook->setBounds(Audio::Timestamp(0, 660, 600), Audio::Timestamp(0, 3500, 600));
_tempVar = 1;
}
_rocketSlider1->drawConditionalDataToScreen(1);
_rocketSlider2->drawConditionalDataToScreen(1);
_rocketSlider3->drawConditionalDataToScreen(1);
_rocketSlider4->drawConditionalDataToScreen(1);
_rocketSlider5->drawConditionalDataToScreen(1);
_vm->_cursor->showCursor();
}
void Myst::o_rocketPianoStart(uint16 var, const ArgumentsArray &args) {
MystAreaDrag *key = getInvokingResource();
// What the hell??
Common::Rect src = key->getSubImage(1).rect;
Common::Rect rect = key->getSubImage(0).rect;
Common::Rect dest = rect;
dest.top = 332 - rect.bottom;
dest.bottom = 332 - rect.top;
// Draw pressed piano key
_vm->_gfx->copyImageSectionToScreen(key->getSubImage(1).wdib, src, dest);
// Play note
_rocketPianoSound = 0;
if (_state.generatorVoltage == 59 && !_state.generatorBreakers) {
_vm->_sound->pauseBackground();
_rocketPianoSound = key->getList1(0);
_vm->_sound->playEffect(_rocketPianoSound, true);
}
}
void Myst::o_rocketPianoMove(uint16 var, const ArgumentsArray &args) {
const Common::Point &mouse = _vm->_system->getEventManager()->getMousePos();
Common::Rect piano = Common::Rect(85, 123, 460, 270);
// Unpress previous key
MystAreaDrag *key = getInvokingResource();
Common::Rect src = key->getSubImage(0).rect;
Common::Rect dest = src;
dest.top = 332 - src.bottom;
dest.bottom = 332 - src.top;
// Draw unpressed piano key
_vm->_gfx->copyImageSectionToScreen(key->getSubImage(0).wdib, src, dest);
if (piano.contains(mouse)) {
MystArea *resource = _vm->getCard()->forceUpdateClickedResource(mouse);
if (resource && resource->hasType(kMystAreaDrag)) {
// Press new key
key = static_cast(resource);
src = key->getSubImage(1).rect;
Common::Rect rect = key->getSubImage(0).rect;
dest = rect;
dest.top = 332 - rect.bottom;
dest.bottom = 332 - rect.top;
// Draw pressed piano key
_vm->_gfx->copyImageSectionToScreen(key->getSubImage(1).wdib, src, dest);
// Play note
if (_state.generatorVoltage == 59 && !_state.generatorBreakers) {
uint16 soundId = key->getList1(0);
if (soundId != _rocketPianoSound) {
_rocketPianoSound = soundId;
_vm->_sound->playEffect(soundId, true);
}
}
} else {
// Not pressing a key anymore
_vm->_sound->stopEffect();
_vm->_sound->resumeBackground();
}
}
}
void Myst::o_rocketPianoStop(uint16 var, const ArgumentsArray &args) {
MystAreaImageSwitch *key = getInvokingResource();
Common::Rect src = key->getSubImage(0).rect;
Common::Rect dest = src;
dest.top = 332 - src.bottom;
dest.bottom = 332 - src.top;
// Draw unpressed piano key
_vm->_gfx->copyImageSectionToScreen(key->getSubImage(0).wdib, src, dest);
_vm->_sound->stopEffect();
_vm->_sound->resumeBackground();
}
void Myst::o_rocketLeverStartMove(uint16 var, const ArgumentsArray &args) {
MystVideoInfo *lever = getInvokingResource();
_vm->_cursor->setCursor(700);
_rocketLeverPosition = 0;
lever->drawFrame(0);
}
void Myst::o_rocketOpenBook(uint16 var, const ArgumentsArray &args) {
// Flyby movie
_rocketLinkBook->setBounds(Audio::Timestamp(0, 3500, 600), Audio::Timestamp(0, 13100, 600));
// Set linkable
_tempVar = 2;
}
void Myst::o_rocketLeverMove(uint16 var, const ArgumentsArray &args) {
MystVideoInfo *lever = getInvokingResource();
const Common::Point &mouse = _vm->_system->getEventManager()->getMousePos();
// Make the lever follow the mouse
int16 maxStep = lever->getStepsV() - 1;
Common::Rect rect = lever->getRect();
int16 step = ((mouse.y - rect.top) * lever->getStepsV()) / rect.height();
step = CLIP(step, 0, maxStep);
lever->drawFrame(step);
// If lever pulled
if (step == maxStep && step != _rocketLeverPosition) {
uint16 soundId = lever->getList2(0);
if (soundId)
_vm->playSoundBlocking(soundId);
// If rocket correctly powered
if (_state.generatorVoltage == 59 && !_state.generatorBreakers)
rocketCheckSolution();
}
_rocketLeverPosition = step;
}
void Myst::o_rocketLeverEndMove(uint16 var, const ArgumentsArray &args) {
MystVideoInfo *lever = getInvokingResource();
_vm->refreshCursor();
_rocketLeverPosition = 0;
lever->drawFrame(0);
}
void Myst::o_cabinLeave(uint16 var, const ArgumentsArray &args) {
// If match is lit, put out
if (_cabinMatchState == 1) {
_matchGoOutTime = _vm->getTotalPlayTime();
} else if (_cabinMatchState == 0) {
_vm->setMainCursor(_savedCursorId);
_cabinMatchState = 2;
}
}
void Myst::o_treePressureReleaseStart(uint16 var, const ArgumentsArray &args) {
Common::Rect src = Common::Rect(0, 0, 49, 86);
Common::Rect dest = Common::Rect(78, 46, 127, 132);
_vm->_gfx->copyImageSectionToScreen(4631, src, dest);
_tempVar = _state.cabinValvePosition;
if (_state.treePosition >= 4) {
_state.cabinValvePosition = 0;
_treeMinPosition = 4;
_state.treeLastMoveTime = 0;
}
}
void Myst::o_treePressureReleaseStop(uint16 var, const ArgumentsArray &args) {
Common::Rect rect = Common::Rect(78, 46, 127, 132);
_vm->_gfx->copyBackBufferToScreen(rect);
_state.cabinValvePosition = _tempVar;
_treeMinPosition = 0;
}
void Myst::o_observatoryMonthSliderStartMove(uint16 var, const ArgumentsArray &args) {
_vm->_cursor->setCursor(700);
_vm->_sound->pauseBackground();
observatoryUpdateMonth();
}
void Myst::o_observatoryMonthSliderEndMove(uint16 var, const ArgumentsArray &args) {
_vm->refreshCursor();
_vm->_sound->resumeBackground();
observatoryUpdateMonth();
}
void Myst::observatoryUpdateMonth() {
int16 month = (_observatoryMonthSlider->_pos.y - 94) / 8;
if (month != _state.observatoryMonthSetting) {
_state.observatoryMonthSetting = month;
_state.observatoryMonthSlider = _observatoryMonthSlider->_pos.y;
_vm->_sound->playEffect(8500);
_vm->wait(20);
// Redraw digits
_vm->getCard()->redrawArea(73);
}
}
void Myst::o_observatoryDaySliderStartMove(uint16 var, const ArgumentsArray &args) {
_vm->_cursor->setCursor(700);
_vm->_sound->pauseBackground();
observatoryUpdateDay();
}
void Myst::o_observatoryDaySliderEndMove(uint16 var, const ArgumentsArray &args) {
_vm->refreshCursor();
_vm->_sound->resumeBackground();
observatoryUpdateDay();
}
void Myst::observatoryUpdateDay() {
int16 day = (_observatoryDaySlider->_pos.y - 94) * 30 / 94 + 1;
if (day != _state.observatoryDaySetting) {
_state.observatoryDaySetting = day;
_state.observatoryDaySlider = _observatoryDaySlider->_pos.y;
_vm->_sound->playEffect(8500);
_vm->wait(20);
// Redraw digits
_vm->getCard()->redrawArea(75);
_vm->getCard()->redrawArea(74);
}
}
void Myst::o_observatoryYearSliderStartMove(uint16 var, const ArgumentsArray &args) {
_vm->_cursor->setCursor(700);
_vm->_sound->pauseBackground();
observatoryUpdateYear();
}
void Myst::o_observatoryYearSliderEndMove(uint16 var, const ArgumentsArray &args) {
_vm->refreshCursor();
_vm->_sound->resumeBackground();
observatoryUpdateYear();
}
void Myst::observatoryUpdateYear() {
int16 year = (_observatoryYearSlider->_pos.y - 94) * 9999 / 94;
if (year != _state.observatoryYearSetting) {
_state.observatoryYearSetting = year;
_state.observatoryYearSlider = _observatoryYearSlider->_pos.y;
_vm->_sound->playEffect(8500);
_vm->wait(20);
// Redraw digits
_vm->getCard()->redrawArea(79);
_vm->getCard()->redrawArea(78);
_vm->getCard()->redrawArea(77);
_vm->getCard()->redrawArea(76);
}
}
void Myst::o_observatoryTimeSliderStartMove(uint16 var, const ArgumentsArray &args) {
_vm->_cursor->setCursor(700);
_vm->_sound->pauseBackground();
observatoryUpdateTime();
}
void Myst::o_observatoryTimeSliderEndMove(uint16 var, const ArgumentsArray &args) {
_vm->refreshCursor();
_vm->_sound->resumeBackground();
observatoryUpdateTime();
}
void Myst::observatoryUpdateTime() {
int16 time = (_observatoryTimeSlider->_pos.y - 94) * 1439 / 94;
if (time != _state.observatoryTimeSetting) {
_state.observatoryTimeSetting = time;
_state.observatoryTimeSlider = _observatoryTimeSlider->_pos.y;
_vm->_sound->playEffect(8500);
_vm->wait(20);
// Redraw digits
_vm->getCard()->redrawArea(80);
_vm->getCard()->redrawArea(81);
_vm->getCard()->redrawArea(82);
_vm->getCard()->redrawArea(83);
// Draw AM/PM
if (!observatoryIsDDMMYYYY2400())
_vm->getCard()->redrawArea(88);
}
}
void Myst::o_libraryBookPageTurnStartLeft(uint16 var, const ArgumentsArray &args) {
_tempVar = -1;
libraryBookPageTurnLeft();
_startTime = _vm->getTotalPlayTime();
_libraryBookPagesTurning = true;
}
void Myst::o_libraryBookPageTurnStartRight(uint16 var, const ArgumentsArray &args) {
_tempVar = 1;
libraryBookPageTurnRight();
_startTime = _vm->getTotalPlayTime();
_libraryBookPagesTurning = true;
}
void Myst::libraryBook_run() {
uint32 time = _vm->getTotalPlayTime();
if (time >= _startTime + 500) {
if (_tempVar > 0) {
libraryBookPageTurnRight();
_startTime = time;
} else if (_tempVar < 0) {
libraryBookPageTurnLeft();
_startTime = time;
}
}
}
void Myst::o_libraryCombinationBookStop(uint16 var, const ArgumentsArray &args) {
_libraryBookPagesTurning = false;
_libraryCombinationBookPagesTurning = false;
}
void Myst::o_cabinMatchLight(uint16 var, const ArgumentsArray &args) {
if (!_cabinMatchState) {
_vm->_sound->playEffect(4103);
// Match is lit
_cabinMatchState = 1;
_matchBurning = true;
_matchGoOutCnt = 0;
_vm->setMainCursor(kLitMatchCursor);
// Match will stay lit for one minute
_matchGoOutTime = _vm->getTotalPlayTime() + 60 * 1000;
}
}
void Myst::matchBurn_run() {
uint32 time = _vm->getTotalPlayTime();
if (time > _matchGoOutTime) {
_matchGoOutTime = time + 150;
// Switch between lit match and dead match every 150 ms when match is dying
if (_matchGoOutCnt % 2)
_vm->setMainCursor(kLitMatchCursor);
else
_vm->setMainCursor(kDeadMatchCursor);
_matchGoOutCnt++;
// Match is dead
if (_matchGoOutCnt >= 5) {
_matchBurning = false;
_vm->setMainCursor(_savedCursorId);
_cabinMatchState = 2;
}
}
}
void Myst::o_courtyardBoxEnter(uint16 var, const ArgumentsArray &args) {
_tempVar = 1;
_vm->_sound->playEffect(_courtyardBoxSound);
_vm->getCard()->redrawArea(var);
}
void Myst::o_courtyardBoxLeave(uint16 var, const ArgumentsArray &args) {
_tempVar = 0;
_vm->getCard()->redrawArea(var);
}
void Myst::o_clockMinuteWheelStartTurn(uint16 var, const ArgumentsArray &args) {
// Used on Card 4006
clockWheelStartTurn(2);
}
void Myst::o_clockWheelEndTurn(uint16 var, const ArgumentsArray &args) {
// Used on Card 4006
_clockTurningWheel = 0;
}
void Myst::o_clockHourWheelStartTurn(uint16 var, const ArgumentsArray &args) {
// Used on Card 4006
clockWheelStartTurn(1);
}
void Myst::clockWheel_run() {
// Turn wheel one step each second
uint32 time = _vm->getTotalPlayTime();
if (time > _startTime + 1000) {
_startTime = time;
if (_clockTurningWheel == 1)
clockWheelTurn(39);
else
clockWheelTurn(38);
_vm->getCard()->redrawArea(37);
}
}
void Myst::clockWheelStartTurn(uint16 wheel) {
MystAreaDrag *resource = getInvokingResource();
uint16 soundId = resource->getList1(0);
if (soundId)
_vm->_sound->playEffect(soundId);
// Turn wheel one step
if (wheel == 1)
clockWheelTurn(39);
else
clockWheelTurn(38);
_vm->getCard()->redrawArea(37);
// Continue turning wheel until mouse button is released
_clockTurningWheel = wheel;
_startTime = _vm->getTotalPlayTime();
}
void Myst::clockWheelTurn(uint16 var) {
if (var == 38) {
// Hours
_state.clockTowerHourPosition = (_state.clockTowerHourPosition + 1) % 12;
} else {
// Minutes
_state.clockTowerMinutePosition = (_state.clockTowerMinutePosition + 5) % 60;
}
}
void Myst::o_libraryCombinationBookStartRight(uint16 var, const ArgumentsArray &args) {
_tempVar = 0;
libraryCombinationBookTurnRight();
_startTime = _vm->getTotalPlayTime();
_libraryCombinationBookPagesTurning = true;
}
void Myst::o_libraryCombinationBookStartLeft(uint16 var, const ArgumentsArray &args) {
_tempVar = 0;
libraryCombinationBookTurnLeft();
_startTime = _vm->getTotalPlayTime();
_libraryCombinationBookPagesTurning = true;
}
void Myst::libraryCombinationBookTurnLeft() {
// Turn page left
if (_libraryBookPage - 1 >= 0) {
_tempVar--;
if (_tempVar >= -5) {
_libraryBookPage--;
} else {
_libraryBookPage -= 5;
_tempVar = -5;
}
_libraryBookPage = CLIP(_libraryBookPage, 0, _libraryBookNumPages - 1);
Common::Rect rect = Common::Rect(157, 113, 446, 220);
_vm->_gfx->copyImageToScreen(_libraryBookBaseImage + _libraryBookPage, rect);
if (_vm->_rnd->getRandomBit())
_vm->_sound->playEffect(_libraryBookSound1);
else
_vm->_sound->playEffect(_libraryBookSound2);
}
}
void Myst::libraryCombinationBookTurnRight() {
// Turn page right
if (_libraryBookPage + 1 < _libraryBookNumPages) {
_tempVar++;
if (_tempVar <= 5) {
_libraryBookPage++;
} else {
_libraryBookPage += 5;
_tempVar = 5;
}
_libraryBookPage = CLIP(_libraryBookPage, 0, _libraryBookNumPages - 1);
Common::Rect rect = Common::Rect(157, 113, 446, 220);
_vm->_gfx->copyImageToScreen(_libraryBookBaseImage + _libraryBookPage, rect);
if (_vm->_rnd->getRandomBit())
_vm->_sound->playEffect(_libraryBookSound1);
else
_vm->_sound->playEffect(_libraryBookSound2);
}
}
void Myst::libraryCombinationBook_run() {
uint32 time = _vm->getTotalPlayTime();
if (time >= _startTime + 500) {
if (_tempVar > 0) {
libraryCombinationBookTurnRight();
_startTime = time;
} else if (_tempVar < 0) {
libraryCombinationBookTurnLeft();
_startTime = time;
}
}
}
void Myst::o_observatoryChangeSettingStop(uint16 var, const ArgumentsArray &args) {
// Stop persistent scripts
_observatoryMonthChanging = false;
_observatoryDayChanging = false;
_observatoryYearChanging = false;
_observatoryTimeChanging = false;
_observatoryIncrement = 0;
// Restore button and slider
_vm->_gfx->copyBackBufferToScreen(getInvokingResource()->getRect());
if (_observatoryCurrentSlider) {
_vm->redrawResource(_observatoryCurrentSlider);
_observatoryCurrentSlider = nullptr;
}
_vm->_sound->resumeBackground();
}
void Myst::o_dockVaultForceClose(uint16 var, const ArgumentsArray &args) {
// Used on Myst 4143 (Dock near Marker Switch)
uint16 soundId = args[0];
uint16 delay = args[1];
uint16 directionalUpdateDataSize = args[2];
if (_dockVaultState) {
// Open switch
_state.dockMarkerSwitch = 1;
_vm->_sound->playEffect(4143);
_vm->getCard()->redrawArea(4);
// Close vault
_dockVaultState = 0;
_vm->_sound->playEffect(soundId);
_vm->getCard()->redrawArea(41, false);
animatedUpdate(ArgumentsArray(args.begin() + 3, directionalUpdateDataSize), delay);
}
}
void Myst::o_imagerEraseStop(uint16 var, const ArgumentsArray &args) {
_imagerValidationRunning = false;
}
void Myst::o_clockLeverStartMove(uint16 var, const ArgumentsArray &args) {
MystVideoInfo *lever = getInvokingResource();
lever->drawFrame(0);
_vm->_cursor->setCursor(700);
_clockMiddleGearMovedAlone = false;
_clockLeverPulled = false;
}
void Myst::o_clockLeverMoveLeft(uint16 var, const ArgumentsArray &args) {
clockLeverMove(true);
}
void Myst::o_clockLeverMoveRight(uint16 var, const ArgumentsArray &args) {
clockLeverMove(false);
}
void Myst::clockLeverMove(bool leftLever) {
if (!_clockLeverPulled) {
MystVideoInfo *lever = getInvokingResource();
// If lever pulled
if (lever->pullLeverV()) {
// Start videos for first step
if (_clockWeightPosition < 2214) {
_vm->_sound->playEffect(5113);
clockGearForwardOneStep(1);
// Left lever
if (leftLever)
clockGearForwardOneStep(2);
else // Right lever
clockGearForwardOneStep(0);
clockWeightDownOneStep();
}
_clockLeverPulled = true;
}
}
}
void Myst::clockGearForwardOneStep(uint16 gear) {
static const uint16 startTime[] = { 0, 324, 618 };
static const uint16 endTime[] = { 324, 618, 950 };
static const char *videos[] = { "cl1wg1", "cl1wg2", "cl1wg3" };
static const uint16 x[] = { 224, 224, 224 };
static const uint16 y[] = { 49, 82, 109 };
// Increment value by one
_clockGearsPositions[gear] = _clockGearsPositions[gear] % 3 + 1;
// Set video bounds
uint16 gearPosition = _clockGearsPositions[gear] - 1;
_clockGearsVideos[gear] = _vm->playMovie(videos[gear], kMystStack);
_clockGearsVideos[gear]->moveTo(x[gear], y[gear]);
_clockGearsVideos[gear]->setBounds(
Audio::Timestamp(0, startTime[gearPosition], 600),
Audio::Timestamp(0, endTime[gearPosition], 600));
}
void Myst::clockWeightDownOneStep() {
// The Myst ME version of this video is encoded faster than the original
// The weight goes on the floor one step too early. Original ME engine also has this behavior.
bool updateVideo = !_vm->isGameVariant(GF_ME) || _clockWeightPosition < (2214 - 246);
// Set video bounds
if (updateVideo) {
_clockWeightVideo = _vm->playMovie("cl1wlfch", kMystStack);
_clockWeightVideo->moveTo(124, 0);
_clockWeightVideo->setBounds(
Audio::Timestamp(0, _clockWeightPosition, 600),
Audio::Timestamp(0, _clockWeightPosition + 246, 600));
}
// Increment value by one step
_clockWeightPosition += 246;
}
void Myst::clockGears_run() {
if (!_vm->_video->isVideoPlaying() && _clockWeightPosition < 2214) {
_clockMiddleGearMovedAlone = true;
_vm->_sound->playEffect(5113);
clockGearForwardOneStep(1);
clockWeightDownOneStep();
}
}
void Myst::o_clockLeverEndMove(uint16 var, const ArgumentsArray &args) {
static const char *videos[] = { "cl1wg1", "cl1wg2", "cl1wg3", "cl1wlfch" };
_vm->_cursor->hideCursor();
_clockLeverPulled = false;
// Let movies stop playing
for (uint i = 0; i < ARRAYSIZE(videos); i++) {
VideoEntryPtr handle = _vm->findVideo(videos[i], kMystStack);
if (handle)
_vm->waitUntilMovieEnds(handle);
}
if (_clockMiddleGearMovedAlone)
_vm->_sound->playEffect(8113);
// Release lever
MystVideoInfo *lever = getInvokingResource();
lever->releaseLeverV();
// Check if puzzle is solved
clockGearsCheckSolution();
_vm->_cursor->showCursor();
}
void Myst::clockGearsCheckSolution() {
if (_clockGearsPositions[0] == 2
&& _clockGearsPositions[1] == 2
&& _clockGearsPositions[2] == 1
&& !_state.gearsOpen) {
// Make weight go down
_vm->_sound->playEffect(9113);
_clockWeightVideo = _vm->playMovie("cl1wlfch", kMystStack);
_clockWeightVideo->moveTo(124, 0);
_clockWeightVideo->setBounds(
Audio::Timestamp(0, _clockWeightPosition, 600),
Audio::Timestamp(0, 2214, 600));
_vm->waitUntilMovieEnds(_clockWeightVideo);
_clockWeightPosition = 2214;
_vm->_sound->playEffect(6113);
_vm->wait(1000);
_vm->_sound->playEffect(7113);
// Gear opening video
_vm->playMovieBlocking("cl1wggat", kMystStack, 195, 225);
_state.gearsOpen = 1;
_vm->getCard()->redrawArea(40);
_vm->_sound->playBackground(4113, 16384);
}
}
void Myst::o_clockResetLeverStartMove(uint16 var, const ArgumentsArray &args) {
MystVideoInfo *lever = getInvokingResource();
lever->drawFrame(0);
_vm->_cursor->setCursor(700);
}
void Myst::o_clockResetLeverMove(uint16 var, const ArgumentsArray &args) {
MystVideoInfo *lever = getInvokingResource();
// If pulled
if (lever->pullLeverV() && _clockWeightPosition != 0)
clockReset();
}
void Myst::clockReset() {
static const char *videos[] = { "cl1wg1", "cl1wg2", "cl1wg3", "cl1wlfch" };
_vm->_cursor->hideCursor();
_vm->_sound->stopBackground();
_vm->_sound->playEffect(5113);
// Play reset videos
clockResetWeight();
clockResetGear(0);
clockResetGear(1);
clockResetGear(2);
// Let movies stop playing
for (uint i = 0; i < ARRAYSIZE(videos); i++) {
VideoEntryPtr handle = _vm->findVideo(videos[i], kMystStack);
if (handle)
_vm->waitUntilMovieEnds(handle);
}
_vm->_sound->playEffect(10113);
// Close gear
if (_state.gearsOpen) {
_vm->_sound->playEffect(6113);
_vm->wait(1000);
_vm->_sound->playEffect(7113);
// Gear closing movie
VideoEntryPtr handle = _vm->playMovie("cl1wggat", kMystStack);
handle->moveTo(195, 225);
handle->seek(handle->getDuration());
handle->setRate(-1);
_vm->waitUntilMovieEnds(handle);
// Redraw gear
_state.gearsOpen = 0;
_vm->getCard()->redrawArea(40);
}
_vm->_cursor->showCursor();
}
void Myst::clockResetWeight() {
_vm->_sound->playEffect(9113);
_clockWeightVideo = _vm->playMovie("cl1wlfch", kMystStack);
_clockWeightVideo->moveTo(124, 0);
// Play the movie backwards, weight going up
_clockWeightVideo->seek(Audio::Timestamp(0, _clockWeightPosition, 600));
_clockWeightVideo->setRate(-1);
// Reset position
_clockWeightPosition = 0;
}
void Myst::clockResetGear(uint16 gear) {
static const uint16 time[] = { 324, 618, 950 };
static const char *videos[] = { "cl1wg1", "cl1wg2", "cl1wg3" };
static const uint16 x[] = { 224, 224, 224 };
static const uint16 y[] = { 49, 82, 109 };
// Set video bounds, gears going to 3
uint16 gearPosition = _clockGearsPositions[gear] - 1;
if (gearPosition != 2) {
_clockGearsVideos[gear] = _vm->playMovie(videos[gear], kMystStack);
_clockGearsVideos[gear]->moveTo(x[gear], y[gear]);
_clockGearsVideos[gear]->setBounds(
Audio::Timestamp(0, time[gearPosition], 600),
Audio::Timestamp(0, time[2], 600));
}
// Reset gear position
_clockGearsPositions[gear] = 3;
}
void Myst::o_clockResetLeverEndMove(uint16 var, const ArgumentsArray &args) {
// Get current lever frame
MystVideoInfo *lever = getInvokingResource();
lever->releaseLeverV();
_vm->refreshCursor();
}
void Myst::o_libraryBook_init(uint16 var, const ArgumentsArray &args) {
_libraryBookPage = 0;
_libraryBookNumPages = args[0];
_libraryBookBaseImage = args[1];
_libraryBookSound1 = args[2];
_libraryBookSound2 = args[3];
}
void Myst::o_courtyardBox_init(uint16 var, const ArgumentsArray &args) {
_courtyardBoxSound = args[0];
}
void Myst::towerRotationMap_run() {
if (!_towerRotationMapInitialized) {
_towerRotationMapInitialized = true;
_vm->_sound->playEffect(4378);
towerRotationDrawBuildings();
// Draw to screen
_vm->_gfx->copyBackBufferToScreen(Common::Rect(106, 42, 459, 273));
}
uint32 time = _vm->getTotalPlayTime();
if (time > _startTime) {
if (_towerRotationMapClicked) {
towerRotationMapRotate();
_startTime = time + 100;
} else if (_towerRotationBlinkLabel
&& _vm->_sound->isEffectPlaying()) {
// Blink tower rotation label while sound is playing
_towerRotationBlinkLabelCount = (_towerRotationBlinkLabelCount + 1) % 14;
if (_towerRotationBlinkLabelCount == 7)
_towerRotationMapLabel->drawConditionalDataToScreen(0);
else if (_towerRotationBlinkLabelCount == 0)
_towerRotationMapLabel->drawConditionalDataToScreen(1);
_startTime = time + 100;
} else {
// Stop blinking label
_towerRotationBlinkLabel = false;
towerRotationMapRedraw();
// Blink tower
_startTime = time + 500;
_tempVar = (_tempVar + 1) % 2;
_towerRotationMapTower->drawConditionalDataToScreen(_tempVar);
}
}
}
void Myst::o_towerRotationMap_init(uint16 var, const ArgumentsArray &args) {
_towerRotationMapRunning = true;
_towerRotationMapTower = getInvokingResource();
_towerRotationMapLabel = _vm->getCard()->getResource(args[0]);
_tempVar = 0;
_startTime = 0;
_towerRotationMapClicked = false;
}
void Myst::towerRotationDrawBuildings() {
// Draw library
_vm->getCard()->redrawArea(304, false);
// Draw other resources
for (uint i = 1; i <= 10; i++) {
MystAreaImageSwitch *resource = _vm->getCard()->getResource(i);
_vm->redrawResource(resource, false);
}
}
uint16 Myst::towerRotationMapComputeAngle() {
_towerRotationSpeed++;
if (_towerRotationSpeed >= 7)
_towerRotationSpeed = 7;
else
_towerRotationSpeed++;
_state.towerRotationAngle = (_state.towerRotationAngle + _towerRotationSpeed) % 360;
uint16 angle = _state.towerRotationAngle;
_towerRotationOverSpot = false;
if (angle >= 265 && angle <= 277
&& _state.rocketshipMarkerSwitch) {
angle = 271;
_towerRotationOverSpot = true;
_towerRotationSpeed = 1;
} else if (angle >= 77 && angle <= 89
&& _state.gearsMarkerSwitch) {
angle = 83;
_towerRotationOverSpot = true;
_towerRotationSpeed = 1;
} else if (angle >= 123 && angle <= 135
&& _state.dockMarkerSwitch) {
angle = 129;
_towerRotationOverSpot = true;
_towerRotationSpeed = 1;
} else if (angle >= 146 && angle <= 158
&& _state.cabinMarkerSwitch) {
angle = 152;
_towerRotationOverSpot = true;
_towerRotationSpeed = 1;
}
return angle;
}
Common::Point Myst::towerRotationMapComputeCoords(uint16 angle) {
Common::Point end;
// Polar to rect coords
float radians = Common::deg2rad(angle);
end.x = (int16)(_towerRotationCenter.x + cos(radians) * 310.0f);
end.y = (int16)(_towerRotationCenter.y + sin(radians) * 310.0f);
return end;
}
void Myst::towerRotationMapDrawLine(const Common::Point &end, bool rotationLabelVisible) {
uint32 color;
if (_vm->isGameVariant(GF_ME)) {
Graphics::PixelFormat pf = _vm->_system->getScreenFormat();
if (!_towerRotationOverSpot)
color = pf.RGBToColor(0xFF, 0xFF, 0xFF); // White
else
color = pf.RGBToColor(0xFF, 0, 0); // Red
} else {
if (!_towerRotationOverSpot)
color = 0xFF; // White
else
color = 0xF9; // Red
}
const Common::Rect rect = Common::Rect(106, 42, 459, 273);
Common::Rect src;
src.left = rect.left;
src.top = 332 - rect.bottom;
src.right = rect.right;
src.bottom = 332 - rect.top;
// Redraw background
_vm->_gfx->copyImageSectionToBackBuffer(_vm->getCard()->getBackgroundImageId(), src, rect);
// Draw buildings
towerRotationDrawBuildings();
// Draw tower
_towerRotationMapTower->drawConditionalDataToScreen(0, false);
// Draw label
_towerRotationMapLabel->drawConditionalDataToScreen(rotationLabelVisible ? 1 : 0, false);
// Draw line
_vm->_gfx->drawLine(_towerRotationCenter, end, color);
_vm->_gfx->copyBackBufferToScreen(rect);
}
void Myst::towerRotationMapRotate() {
uint16 angle = towerRotationMapComputeAngle();
Common::Point end = towerRotationMapComputeCoords(angle);
towerRotationMapDrawLine(end, true);
}
void Myst::towerRotationMapRedraw() {
Common::Point end = towerRotationMapComputeCoords(_state.towerRotationAngle);
towerRotationMapDrawLine(end, false);
}
void Myst::o_forechamberDoor_init(uint16 var, const ArgumentsArray &args) {
// Used for Card 4138 (Dock Forechamber Door)
// Set forechamber door to closed
_tempVar = 0;
}
void Myst::o_shipAccess_init(uint16 var, const ArgumentsArray &args) {
// Enable access to the ship
if (_state.shipFloating) {
getInvokingResource()->setEnabled(true);
}
}
void Myst::o_butterflies_init(uint16 var, const ArgumentsArray &args) {
// Used for Card 4256 (Butterfly Movie Activation)
if (!_butterfliesMoviePlayed) {
MystAreaVideo *butterflies = getInvokingResource();
butterflies->playMovie();
_butterfliesMoviePlayed = true;
}
}
void Myst::o_imager_init(uint16 var, const ArgumentsArray &args) {
MystAreaActionSwitch *select = getInvokingResource();
_imagerMovie = static_cast(select->getSubResource(getVar(var)));
_imagerRunning = true;
}
void Myst::imager_run() {
_imagerRunning = false;
if (_state.imagerActive && _state.imagerSelection == 67) {
VideoEntryPtr water = _imagerMovie->playMovie();
water->setBounds(Audio::Timestamp(0, 1814, 600), Audio::Timestamp(0, 4204, 600));
water->setLooping(true);
}
}
void Myst::libraryBookcaseTransform_run(void) {
if (_libraryBookcaseChanged) {
_libraryBookcaseChanged = false;
_libraryBookcaseMoving = false;
_vm->_cursor->hideCursor();
// Play transform sound and video
_vm->_sound->playEffect(_libraryBookcaseSoundId);
_libraryBookcaseMovie->playMovie();
if (_state.libraryBookcaseDoor) {
_vm->_gfx->copyImageSectionToBackBuffer(11179, Common::Rect(0, 0, 106, 81), Common::Rect(0, 72, 106, 153));
_vm->_gfx->runTransition(kTransitionBottomToTop, Common::Rect(0, 72, 106, 153), 5, 10);
_vm->playSoundBlocking(7348);
_vm->_sound->playBackground(4348, 16384);
} else {
_vm->_gfx->copyImageSectionToBackBuffer(11178, Common::Rect(0, 0, 107, 67), Common::Rect(437, 84, 544, 151));
_vm->_gfx->copyBackBufferToScreen(Common::Rect(437, 84, 544, 151));
_vm->playSoundBlocking(7348);
_vm->_sound->playBackground(4334, 16384);
}
_vm->_cursor->showCursor();
}
}
void Myst::o_libraryBookcaseTransform_init(uint16 var, const ArgumentsArray &args) {
if (_libraryBookcaseChanged) {
MystAreaActionSwitch *resource = getInvokingResource();
_libraryBookcaseMovie = static_cast(resource->getSubResource(getVar(0)));
_libraryBookcaseSoundId = args[0];
_libraryBookcaseMoving = true;
}
}
void Myst::generatorControlRoom_run(void) {
if (_generatorVoltage == _state.generatorVoltage) {
generatorRedrawRocket();
} else {
// Animate generator gauge
if (_generatorVoltage > _state.generatorVoltage)
_generatorVoltage--;
else
_generatorVoltage++;
// Redraw generator gauge
_vm->getCard()->redrawArea(62);
_vm->getCard()->redrawArea(63);
_vm->getCard()->redrawArea(96);
}
}
void Myst::o_generatorControlRoom_init(uint16 var, const ArgumentsArray &args) {
_generatorVoltage = _state.generatorVoltage;
_generatorControlRoomRunning = true;
}
void Myst::o_fireplace_init(uint16 var, const ArgumentsArray &args) {
// Clear fireplace grid
for (uint i = 0; i < 6; i++)
_fireplaceLines[i] = 0;
}
void Myst::o_clockGears_init(uint16 var, const ArgumentsArray &args) {
// Used for Card 4113 (Clock Tower Cog Puzzle)
// Set gears position
if (_state.gearsOpen) {
_clockGearsPositions[0] = 2;
_clockGearsPositions[1] = 2;
_clockGearsPositions[2] = 1;
_clockWeightPosition = 2214;
} else {
_clockGearsPositions[0] = 3;
_clockGearsPositions[1] = 3;
_clockGearsPositions[2] = 3;
_clockWeightPosition = 0;
}
}
void Myst::o_gulls1_init(uint16 var, const ArgumentsArray &args) {
if (!_state.shipFloating) {
_gullsNextTime = _vm->getTotalPlayTime() + 2000;
_gullsFlying1 = true;
}
}
void Myst::gullsFly1_run() {
static const char* gulls[] = { "birds1", "birds2", "birds3" };
uint32 time = _vm->getTotalPlayTime();
if (time > _gullsNextTime) {
uint16 video = _vm->_rnd->getRandomNumber(3);
if (video != 3) {
uint16 x = 0;
if (_vm->_rnd->getRandomBit())
x = _vm->_rnd->getRandomNumber(110);
else
x = _vm->_rnd->getRandomNumber(160) + 260;
VideoEntryPtr handle = _vm->playMovie(gulls[video], kMystStack);
handle->moveTo(x, 0);
_gullsNextTime = time + _vm->_rnd->getRandomNumber(16667) + 13334;
}
}
}
void Myst::o_observatory_init(uint16 var, const ArgumentsArray &args) {
_tempVar = 0;
_observatoryNotInitialized = true;
_observatoryVisualizer = getInvokingResource();
_observatoryGoButton = _vm->getCard()->getResource(args[0]);
if (observatoryIsDDMMYYYY2400()) {
_observatoryDaySlider = _vm->getCard()->getResource(args[1]);
_observatoryMonthSlider = _vm->getCard()->getResource(args[2]);
} else {
_observatoryMonthSlider = _vm->getCard()->getResource(args[1]);
_observatoryDaySlider = _vm->getCard()->getResource(args[2]);
}
_observatoryYearSlider = _vm->getCard()->getResource(args[3]);
_observatoryTimeSlider = _vm->getCard()->getResource(args[4]);
// Set date selection sliders position
_observatoryDaySlider->setPosition(_state.observatoryDaySlider);
_observatoryMonthSlider->setPosition(_state.observatoryMonthSlider);
_observatoryYearSlider->setPosition(_state.observatoryYearSlider);
_observatoryTimeSlider->setPosition(_state.observatoryTimeSlider);
_observatoryLastTime = _vm->getTotalPlayTime();
observatorySetTargetToSetting();
_observatoryRunning = true;
}
bool Myst::observatoryIsDDMMYYYY2400() {
// TODO: Auto-detect based on the month rect position
return !_vm->isGameVariant(GF_ME) && (_vm->getLanguage() == Common::FR_FRA
|| _vm->getLanguage() == Common::DE_DEU);
}
void Myst::observatoryUpdateVisualizer(uint16 x, uint16 y) {
Common::Rect visu;
visu.left = x;
visu.right = visu.left + 105;
visu.bottom = 512 - y;
visu.top = visu.bottom - 106;
_observatoryVisualizer->setSubImageRect(0, visu);
_observatoryVisualizer->setSubImageRect(1, visu);
}
void Myst::observatorySetTargetToSetting() {
uint32 visuX = _state.observatoryTimeSetting * 7 / 25;
uint32 visuY = 250 * _state.observatoryYearSetting
+ 65 * (_state.observatoryMonthSetting + 1)
+ 20 * _state.observatoryDaySetting;
observatoryUpdateVisualizer(visuX % 407, visuY % 407);
_state.observatoryDayTarget = _state.observatoryDaySetting;
_state.observatoryMonthTarget = _state.observatoryMonthSetting;
_state.observatoryYearTarget = _state.observatoryYearSetting;
_state.observatoryTimeTarget = _state.observatoryTimeSetting;
}
void Myst::observatory_run() {
if (_observatoryNotInitialized) {
_observatoryNotInitialized = false;
_vm->_cursor->hideCursor();
// Make sliders "initialize"
if (observatoryIsDDMMYYYY2400()) {
_vm->_sound->playEffect(8500);
_observatoryDaySlider->drawConditionalDataToScreen(2);
_vm->wait(200);
_vm->redrawResource(_observatoryDaySlider);
_vm->_sound->playEffect(8500);
_observatoryMonthSlider->drawConditionalDataToScreen(2);
_vm->wait(200);
_vm->redrawResource(_observatoryMonthSlider);
} else {
_vm->_sound->playEffect(8500);
_observatoryMonthSlider->drawConditionalDataToScreen(2);
_vm->wait(200);
_vm->redrawResource(_observatoryMonthSlider);
_vm->_sound->playEffect(8500);
_observatoryDaySlider->drawConditionalDataToScreen(2);
_vm->wait(200);
_vm->redrawResource(_observatoryDaySlider);
}
_vm->_sound->playEffect(8500);
_observatoryYearSlider->drawConditionalDataToScreen(2);
_vm->wait(200);
_vm->redrawResource(_observatoryYearSlider);
_vm->_sound->playEffect(8500);
_observatoryTimeSlider->drawConditionalDataToScreen(2);
_vm->wait(200);
_vm->redrawResource(_observatoryTimeSlider);
_vm->_cursor->showCursor();
}
// Setting not at target
if (_state.observatoryDayTarget != _state.observatoryDaySetting
|| _state.observatoryMonthTarget != _state.observatoryMonthSetting
|| _state.observatoryYearTarget != _state.observatoryYearSetting
|| _state.observatoryTimeTarget != _state.observatoryTimeSetting) {
// Blink the go button
uint32 time = _vm->getTotalPlayTime();
if (time > _observatoryLastTime + 250) {
_tempVar = (_tempVar + 1) % 2;
_observatoryGoButton->drawConditionalDataToScreen(_tempVar);
_observatoryLastTime = time;
}
}
}
void Myst::o_gulls2_init(uint16 var, const ArgumentsArray &args) {
if (!_state.shipFloating) {
_gullsNextTime = _vm->getTotalPlayTime() + 2000;
_gullsFlying2 = true;
}
}
void Myst::gullsFly2_run() {
static const char* gulls[] = { "birds1", "birds2", "birds3" };
uint32 time = _vm->getTotalPlayTime();
if (time > _gullsNextTime) {
uint16 video = _vm->_rnd->getRandomNumber(3);
if (video != 3) {
VideoEntryPtr handle = _vm->playMovie(gulls[video], kMystStack);
handle->moveTo(424, 0);
_gullsNextTime = time + _vm->_rnd->getRandomNumber(16667) + 13334;
}
}
}
void Myst::o_treeCard_init(uint16 var, const ArgumentsArray &args) {
_tree = getInvokingResource();
}
void Myst::o_treeEntry_init(uint16 var, const ArgumentsArray &args) {
_treeAlcove = getInvokingResource();
_treeMinAccessiblePosition = args[0];
_treeMaxAccessiblePosition = args[1];
treeSetAlcoveAccessible();
}
void Myst::o_boilerMovies_init(uint16 var, const ArgumentsArray &args) {
boilerFireInit();
boilerGaugeInit();
}
void Myst::boilerFireInit() {
if (_vm->getCard()->getId() == 4098) {
_cabinFireMovie = _vm->playMovie("cabfire", kMystStack);
_cabinFireMovie->moveTo(240, 279);
_cabinFireMovie->setLooping(true);
_cabinFireMovie->pause(true);
_vm->getCard()->redrawArea(305);
boilerFireUpdate(true);
} else {
if (_state.cabinPilotLightLit == 1 && _state.cabinValvePosition >= 1) {
_cabinFireMovie = _vm->playMovie("cabfirfr", kMystStack);
_cabinFireMovie->moveTo(254, 244);
_cabinFireMovie->setLooping(true);
}
}
}
void Myst::boilerFireUpdate(bool init) {
uint position = _cabinFireMovie->getTime();
if (_state.cabinPilotLightLit == 1) {
if (_state.cabinValvePosition == 0) {
if (position > (uint)Audio::Timestamp(0, 200, 600).msecs() || init) {
_cabinFireMovie->setBounds(Audio::Timestamp(0, 0, 600), Audio::Timestamp(0, 100, 600));
_cabinFireMovie->pause(false);
}
} else {
if (position < (uint)Audio::Timestamp(0, 200, 600).msecs() || init) {
_cabinFireMovie->setBounds(Audio::Timestamp(0, 201, 600), Audio::Timestamp(0, 1900, 600));
_cabinFireMovie->pause(false);
}
}
}
}
void Myst::boilerGaugeInit() {
if (_vm->getCard()->getId() == 4098) {
_cabinGaugeMovie = _vm->playMovie("cabingau", kMystStack);
_cabinGaugeMovie->moveTo(243, 96);
} else {
_cabinGaugeMovie = _vm->playMovie("cabcgfar", kMystStack);
_cabinGaugeMovie->moveTo(254, 136);
}
Audio::Timestamp frame;
if (_state.cabinPilotLightLit == 1 && _state.cabinValvePosition > 12)
frame = _cabinGaugeMovie->getDuration();
else
frame = Audio::Timestamp(0, 0, 600);
_vm->_video->drawVideoFrame(_cabinGaugeMovie, frame);
_cabinGaugeMovieEnabled = true;
}
void Myst::o_rocketSliders_init(uint16 var, const ArgumentsArray &args) {
_rocketLinkBook.reset();
_rocketSlider1 = _vm->getCard()->getResource(args[0]);
_rocketSlider2 = _vm->getCard()->getResource(args[1]);
_rocketSlider3 = _vm->getCard()->getResource(args[2]);
_rocketSlider4 = _vm->getCard()->getResource(args[3]);
_rocketSlider5 = _vm->getCard()->getResource(args[4]);
// Initialize sliders position
for (uint i = 0; i < 5; i++)
if (!_state.rocketSliderPosition[i])
_state.rocketSliderPosition[i] = 277;
_rocketSlider1->setPosition(_state.rocketSliderPosition[0]);
_rocketSlider2->setPosition(_state.rocketSliderPosition[1]);
_rocketSlider3->setPosition(_state.rocketSliderPosition[2]);
_rocketSlider4->setPosition(_state.rocketSliderPosition[3]);
_rocketSlider5->setPosition(_state.rocketSliderPosition[4]);
}
void Myst::o_rocketLinkVideo_init(uint16 var, const ArgumentsArray &args) {
_tempVar = 0;
}
void Myst::o_greenBook_init(uint16 var, const ArgumentsArray &args) {
// Used for Card 4168 (Green Book Movies)
_greenBookRunning = true;
_tempVar = 1;
}
void Myst::greenBook_run() {
uint loopStart = 0;
uint loopEnd = 0;
Common::String videoName;
if (!_state.greenBookOpenedBefore) {
loopStart = 113200;
loopEnd = 116400;
videoName = "atrusbk1";
} else {
loopStart = 8800;
loopEnd = 9700;
videoName = "atrusbk2";
}
if (_tempVar == 1) {
_vm->_sound->stopEffect();
_vm->_sound->pauseBackground();
VideoEntryPtr book = _vm->playMovie(videoName, kMystStack);
book->moveTo(314, 76);
if (_globals.ending != kBooksDestroyed) {
_tempVar = 2;
} else {
book->setBounds(Audio::Timestamp(0, loopStart, 600), Audio::Timestamp(0, loopEnd, 600));
book->setLooping(true);
_tempVar = 0;
}
} else if (_tempVar == 2 && !_vm->_video->isVideoPlaying()) {
VideoEntryPtr book = _vm->playMovie(videoName, kMystStack);
book->moveTo(314, 76);
book->setBounds(Audio::Timestamp(0, loopStart, 600), Audio::Timestamp(0, loopEnd, 600));
book->setLooping(true);
_tempVar = 0;
}
}
void Myst::o_gulls3_init(uint16 var, const ArgumentsArray &args) {
if (!_state.shipFloating) {
_gullsNextTime = _vm->getTotalPlayTime() + 2000;
_gullsFlying3 = true;
}
}
void Myst::gullsFly3_run() {
static const char* gulls[] = { "birds1", "birds2", "birds3" };
uint32 time = _vm->getTotalPlayTime();
if (time > _gullsNextTime) {
uint16 video = _vm->_rnd->getRandomNumber(3);
if (video != 3) {
uint16 x = _vm->_rnd->getRandomNumber(280) + 135;
VideoEntryPtr handle = _vm->playMovie(gulls[video], kMystStack);
handle->moveTo(x, 0);
_gullsNextTime = time + _vm->_rnd->getRandomNumber(16667) + 13334;
}
}
}
void Myst::o_bookAddSpecialPage_exit(uint16 var, const ArgumentsArray &args) {
uint16 numPages = bookCountPages(var);
// Add special page
if (numPages == 5) {
if (var == 100)
_globals.redPagesInBook |= 64;
else
_globals.bluePagesInBook |= 64;
}
}
void Myst::o_treeCard_exit(uint16 var, const ArgumentsArray &args) {
_tree = nullptr;
}
void Myst::o_treeEntry_exit(uint16 var, const ArgumentsArray &args) {
_treeAlcove = nullptr;
}
void Myst::o_boiler_exit(uint16 var, const ArgumentsArray &args) {
_cabinGaugeMovie = VideoEntryPtr();
_cabinFireMovie = VideoEntryPtr();
_cabinGaugeMovieEnabled = false;
}
void Myst::o_generatorControlRoom_exit(uint16 var, const ArgumentsArray &args) {
_generatorVoltage = _state.generatorVoltage;
}
void Myst::o_rocketSliders_exit(uint16 var, const ArgumentsArray &args) {
_rocketLinkBook.reset();
_rocketSlider1 = nullptr;
_rocketSlider2 = nullptr;
_rocketSlider3 = nullptr;
_rocketSlider4 = nullptr;
_rocketSlider5 = nullptr;
}
} // End of namespace MystStacks
} // End of namespace Mohawk