Files
scummvm/engines/mohawk/myst_stacks/myst.cpp
T
Torbjörn Andersson 85ba7876d9 MOHAWK: Add missing break in switch, CID 1003750
Clicking on any of the image boxes would fall through to the case
where it checks if you are picking up or putting away the white
page, which just doesn't make any sense. It didn't have any
noticeable impact on the game, because that case only does
something if the hiding place for the white page is open, and
apparently that can only happen while you're at that hiding place.

I have verified that it's still possible to get the white page,
and that it's still possible to raise the sunken ship.
2013-08-20 07:59:24 +02:00

3757 lines
109 KiB
C++

/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*/
#include "mohawk/cursors.h"
#include "mohawk/myst.h"
#include "mohawk/myst_areas.h"
#include "mohawk/myst_graphics.h"
#include "mohawk/myst_state.h"
#include "mohawk/sound.h"
#include "mohawk/video.h"
#include "mohawk/myst_stacks/myst.h"
#include "common/events.h"
#include "common/system.h"
#include "common/textconsole.h"
#include "gui/message.h"
namespace Mohawk {
namespace MystStacks {
Myst::Myst(MohawkEngine_Myst *vm) :
MystScriptParser(vm), _state(_vm->_gameState->_myst) {
setupOpcodes();
// Card ID preinitialized by the engine for use by opcode 18
// when linking back to Myst in the library
_savedCardId = 4329;
_towerRotationBlinkLabel = false;
_libraryBookcaseChanged = false;
_dockVaultState = 0;
_cabinDoorOpened = 0;
_cabinMatchState = 2;
_cabinGaugeMovie = NULL_VID_HANDLE;
_cabinFireMovie = NULL_VID_HANDLE;
_matchBurning = false;
_tree = 0;
_treeAlcove = 0;
_treeStopped = false;
_treeMinPosition = 0;
_imagerValidationStep = 0;
_observatoryCurrentSlider = 0;
_butterfliesMoviePlayed = false;
_state.treeLastMoveTime = _vm->_system->getMillis();
}
Myst::~Myst() {
}
#define OPCODE(op, x) _opcodes.push_back(new MystOpcode(op, (OpcodeProcMyst) &Myst::x, #x))
void Myst::setupOpcodes() {
// "Stack-Specific" Opcodes
OPCODE(100, NOP);
OPCODE(101, o_libraryBookPageTurnLeft);
OPCODE(102, o_libraryBookPageTurnRight);
OPCODE(103, o_fireplaceToggleButton);
OPCODE(104, o_fireplaceRotation);
OPCODE(105, o_courtyardBoxesCheckSolution);
OPCODE(106, o_towerRotationStart);
OPCODE(107, NOP);
OPCODE(108, o_towerRotationEnd);
OPCODE(109, o_imagerChangeSelection);
OPCODE(113, o_dockVaultOpen);
OPCODE(114, o_dockVaultClose);
OPCODE(115, o_bookGivePage);
OPCODE(116, o_clockWheelsExecute);
OPCODE(117, o_imagerPlayButton);
OPCODE(118, o_imagerEraseButton);
OPCODE(119, o_towerElevatorAnimation);
OPCODE(120, o_generatorButtonPressed);
OPCODE(121, o_cabinSafeChangeDigit);
OPCODE(122, o_cabinSafeHandleStartMove);
OPCODE(123, o_cabinSafeHandleMove);
OPCODE(124, o_cabinSafeHandleEndMove);
OPCODE(126, o_clockLeverStartMove);
OPCODE(127, o_clockLeverEndMove);
OPCODE(128, o_treePressureReleaseStart);
if (!observatoryIsDDMMYYYY2400()) {
OPCODE(129, o_observatoryMonthChangeStart);
OPCODE(130, o_observatoryMonthChangeStart);
OPCODE(131, o_observatoryDayChangeStart);
OPCODE(132, o_observatoryDayChangeStart);
} else {
OPCODE(129, o_observatoryDayChangeStart);
OPCODE(130, o_observatoryDayChangeStart);
OPCODE(131, o_observatoryMonthChangeStart);
OPCODE(132, o_observatoryMonthChangeStart);
}
OPCODE(133, o_observatoryGoButton);
OPCODE(134, o_observatoryMonthSliderMove);
OPCODE(135, o_observatoryDaySliderMove);
OPCODE(136, o_observatoryYearSliderMove);
OPCODE(137, o_observatoryTimeSliderMove);
OPCODE(138, o_clockResetLeverStartMove);
OPCODE(139, o_clockResetLeverMove);
OPCODE(140, o_clockResetLeverEndMove);
OPCODE(141, o_circuitBreakerStartMove);
OPCODE(142, o_circuitBreakerMove);
OPCODE(143, o_circuitBreakerEndMove);
OPCODE(144, o_clockLeverMove);
OPCODE(145, o_clockLeverMove);
OPCODE(146, o_boilerIncreasePressureStart);
OPCODE(147, o_boilerLightPilot);
OPCODE(148, NOP);
OPCODE(149, o_boilerIncreasePressureStop);
OPCODE(150, o_boilerDecreasePressureStart);
OPCODE(151, o_boilerDecreasePressureStop);
OPCODE(152, NOP);
OPCODE(153, o_basementIncreasePressureStart);
OPCODE(154, o_basementIncreasePressureStop);
OPCODE(155, o_basementDecreasePressureStart);
OPCODE(156, o_basementDecreasePressureStop);
OPCODE(157, o_rocketPianoMove);
OPCODE(158, o_rocketSoundSliderStartMove);
OPCODE(159, o_rocketSoundSliderMove);
OPCODE(160, o_rocketSoundSliderEndMove);
OPCODE(161, o_rocketPianoStart);
OPCODE(162, o_rocketPianoStop);
OPCODE(163, o_rocketLeverStartMove);
OPCODE(164, o_rocketOpenBook);
OPCODE(165, o_rocketLeverMove);
OPCODE(166, o_rocketLeverEndMove);
OPCODE(167, NOP);
OPCODE(168, o_treePressureReleaseStop);
OPCODE(169, o_cabinLeave);
OPCODE(170, o_observatoryMonthSliderStartMove);
OPCODE(171, o_observatoryMonthSliderEndMove);
OPCODE(172, o_observatoryDaySliderStartMove);
OPCODE(173, o_observatoryDaySliderEndMove);
OPCODE(174, o_observatoryYearSliderStartMove);
OPCODE(175, o_observatoryYearSliderEndMove);
OPCODE(176, o_observatoryTimeSliderStartMove);
OPCODE(177, o_observatoryTimeSliderEndMove);
OPCODE(180, o_libraryCombinationBookStop);
OPCODE(181, NOP);
OPCODE(182, o_cabinMatchLight);
OPCODE(183, o_courtyardBoxEnter);
OPCODE(184, o_courtyardBoxLeave);
OPCODE(185, NOP);
OPCODE(186, o_clockMinuteWheelStartTurn);
OPCODE(187, NOP);
OPCODE(188, o_clockWheelEndTurn);
OPCODE(189, o_clockHourWheelStartTurn);
OPCODE(190, o_libraryCombinationBookStartRight);
OPCODE(191, o_libraryCombinationBookStartLeft);
OPCODE(192, o_observatoryTimeChangeStart);
OPCODE(193, NOP);
OPCODE(194, o_observatoryChangeSettingStop);
OPCODE(195, o_observatoryTimeChangeStart);
OPCODE(196, o_observatoryYearChangeStart);
OPCODE(197, o_observatoryYearChangeStart);
OPCODE(198, o_dockVaultForceClose);
OPCODE(199, o_imagerEraseStop);
// "Init" Opcodes
OPCODE(200, o_libraryBook_init);
OPCODE(201, o_courtyardBox_init);
OPCODE(202, o_towerRotationMap_init);
OPCODE(203, o_forechamberDoor_init);
OPCODE(204, o_shipAccess_init);
OPCODE(205, NOP);
OPCODE(206, o_butterflies_init);
OPCODE(208, o_imager_init);
OPCODE(209, o_libraryBookcaseTransform_init);
OPCODE(210, o_generatorControlRoom_init);
OPCODE(211, o_fireplace_init);
OPCODE(212, o_clockGears_init);
OPCODE(213, o_gulls1_init);
OPCODE(214, o_observatory_init);
OPCODE(215, o_gulls2_init);
OPCODE(216, o_treeCard_init);
OPCODE(217, o_treeEntry_init);
OPCODE(218, o_boilerMovies_init);
OPCODE(219, o_rocketSliders_init);
OPCODE(220, o_rocketLinkVideo_init);
OPCODE(221, o_greenBook_init);
OPCODE(222, o_gulls3_init);
// "Exit" Opcodes
OPCODE(300, o_bookAddSpecialPage_exit);
OPCODE(301, NOP);
OPCODE(302, NOP);
OPCODE(303, NOP);
OPCODE(304, o_treeCard_exit);
OPCODE(305, o_treeEntry_exit);
OPCODE(306, o_boiler_exit);
OPCODE(307, o_generatorControlRoom_exit);
OPCODE(308, NOP);
OPCODE(309, NOP);
OPCODE(312, NOP);
}
#undef OPCODE
void Myst::disablePersistentScripts() {
_libraryBookcaseMoving = false;
_generatorControlRoomRunning = 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 (_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 != 4)
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 != 4)
return !(_globals.bluePagesInBook & 32) && (_globals.heldPage != 6);
else
return 0;
case 25: // Fireplace Red Page Present
if (_globals.ending != 4)
return !(_globals.redPagesInBook & 32) && (_globals.heldPage != 12);
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 ( Number 1 (0) or Blank (10))
if (!observatoryIsDDMMYYYY2400()) {
if (_state.observatoryTimeSetting % (12 * 60) < (10 * 60))
return 10;
else
return 1;
} else {
if (_state.observatoryTimeSetting < (10 * 60))
return 10;
else if (_state.observatoryTimeSetting < (20 * 60))
return 1;
else
return 2;
}
case 81: // Stellar Observatory Hour #2 - Right
if (!observatoryIsDDMMYYYY2400())
return ((_state.observatoryTimeSetting % (12 * 60)) / 60) % 10;
else
return (_state.observatoryTimeSetting / 60) % 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 != 4)
return !(_globals.redPagesInBook & 1) && (_globals.heldPage != 7);
else
return 0;
case 103: // Blue page
if (_globals.ending != 4)
return !(_globals.bluePagesInBook & 1) && (_globals.heldPage != 1);
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 0; // Not implemented in the original
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 != 4 && !(_globals.bluePagesInBook & 32)) {
if (_globals.heldPage == 6)
_globals.heldPage = 0;
else
_globals.heldPage = 6;
}
break;
case 25: // Fireplace Red page
if (_globals.ending != 4 && !(_globals.redPagesInBook & 32)) {
if (_globals.heldPage == 12)
_globals.heldPage = 0;
else
_globals.heldPage = 12;
}
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 != 4) {
if (_dockVaultState == 1) {
_dockVaultState = 2;
_globals.heldPage = 0;
} else if (_dockVaultState == 2) {
_dockVaultState = 1;
_globals.heldPage = 13;
}
}
break;
case 102: // Red page
if (_globals.ending != 4 && !(_globals.redPagesInBook & 1)) {
if (_globals.heldPage == 7)
_globals.heldPage = 0;
else
_globals.heldPage = 7;
}
break;
case 103: // Blue page
if (_globals.ending != 4 && !(_globals.bluePagesInBook & 1)) {
if (_globals.heldPage == 1)
_globals.heldPage = 0;
else
_globals.heldPage = 1;
}
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 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 op, uint16 var, uint16 argc, uint16 *argv) {
debugC(kDebugScript, "Opcode %d: Turn book page left", op);
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->replaceSoundMyst(_libraryBookSound1);
else
_vm->_sound->replaceSoundMyst(_libraryBookSound2);
_vm->_system->updateScreen();
}
}
void Myst::o_libraryBookPageTurnRight(uint16 op, uint16 var, uint16 argc, uint16 *argv) {
debugC(kDebugScript, "Opcode %d: Turn book page right", op);
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->replaceSoundMyst(_libraryBookSound1);
else
_vm->_sound->replaceSoundMyst(_libraryBookSound2);
_vm->_system->updateScreen();
}
}
void Myst::o_fireplaceToggleButton(uint16 op, uint16 var, uint16 argc, uint16 *argv) {
// Used on Myst Card 4162 (Fireplace Grid)
debugC(kDebugScript, "Opcode %d: Fireplace grid toggle button", op);
uint16 bitmask = argv[0];
uint16 line = _fireplaceLines[var - 17];
debugC(kDebugScript, "\tvar: %d", var);
debugC(kDebugScript, "\tbitmask: 0x%02X", bitmask);
if (line & bitmask) {
// Unset button
for (uint i = 4795; i >= 4779; i--) {
_vm->_gfx->copyImageToScreen(i, _invokingResource->getRect());
_vm->_system->updateScreen();
}
_fireplaceLines[var - 17] &= ~bitmask;
} else {
// Set button
for (uint i = 4779; i <= 4795; i++) {
_vm->_gfx->copyImageToScreen(i, _invokingResource->getRect());
_vm->_system->updateScreen();
}
_fireplaceLines[var - 17] |= bitmask;
}
}
void Myst::o_fireplaceRotation(uint16 op, uint16 var, uint16 argc, uint16 *argv) {
// Used on Myst Card 4162 and 4166 (Fireplace Puzzle Rotation Movies)
uint16 movieNum = argv[0];
debugC(kDebugScript, "Opcode %d: Play Fireplace Puzzle Rotation Movies", op);
debugC(kDebugScript, "\tmovieNum: %d", movieNum);
if (movieNum)
_vm->_video->playMovieBlocking(_vm->wrapMovieFilename("fpout", kMystStack), 167, 4);
else
_vm->_video->playMovieBlocking(_vm->wrapMovieFilename("fpin", kMystStack), 167, 4);
}
void Myst::o_courtyardBoxesCheckSolution(uint16 op, uint16 var, uint16 argc, uint16 *argv) {
uint16 soundId = argv[0];
debugC(kDebugScript, "Opcode %d: Ship Puzzle Logic", op);
debugC(kDebugScript, "\tsoundId: %d", soundId);
// Change ship state if the boxes are correctly enabled
if (_state.courtyardImageBoxes == 50 && !_state.shipFloating) {
_vm->_cursor->hideCursor();
_state.shipFloating = 1;
_vm->_sound->playSoundBlocking(soundId);
_vm->_cursor->showCursor();
} else if (_state.courtyardImageBoxes != 50 && _state.shipFloating) {
_vm->_cursor->hideCursor();
_state.shipFloating = 0;
_vm->_sound->playSoundBlocking(soundId);
_vm->_cursor->showCursor();
}
}
void Myst::o_towerRotationStart(uint16 op, uint16 var, uint16 argc, uint16 *argv) {
_towerRotationBlinkLabel = false;
_towerRotationMapClicked = true;
_towerRotationSpeed = 0;
_vm->_cursor->setCursor(700);
const Common::Point center = Common::Point(383, 124);
Common::Point end = towerRotationMapComputeCoords(center, _state.towerRotationAngle);
towerRotationMapComputeAngle();
towerRotationMapDrawLine(center, end);
_vm->_sound->replaceSoundMyst(5378, Audio::Mixer::kMaxChannelVolume, true);
}
void Myst::o_towerRotationEnd(uint16 op, uint16 var, uint16 argc, uint16 *argv) {
_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->replaceSoundMyst(6378);
_towerRotationBlinkLabel = true;
_towerRotationBlinkLabelCount = 0;
}
void Myst::o_imagerChangeSelection(uint16 op, uint16 var, uint16 argc, uint16 *argv) {
debugC(kDebugScript, "Opcode %d: Dock imager change selection", op);
if (_imagerValidationStep != 10) {
_imagerValidationStep = 0;
int16 signedValue = argv[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->redrawArea(var);
}
}
void Myst::o_dockVaultOpen(uint16 op, uint16 var, uint16 argc, uint16 *argv) {
// Used on Myst 4143 (Dock near Marker Switch)
uint16 soundId = argv[0];
uint16 delay = argv[1];
uint16 directionalUpdateDataSize = argv[2];
debugC(kDebugScript, "Opcode %d: Vault Open Logic", op);
debugC(kDebugScript, "\tsoundId: %d", soundId);
debugC(kDebugScript, "\tdirectionalUpdateDataSize: %d", directionalUpdateDataSize);
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 != 13 && _globals.ending != 4)
_dockVaultState = 2;
else
_dockVaultState = 1;
_vm->_sound->replaceSoundMyst(soundId);
_vm->redrawArea(41, false);
animatedUpdate(directionalUpdateDataSize, &argv[3], delay);
}
}
void Myst::o_dockVaultClose(uint16 op, uint16 var, uint16 argc, uint16 *argv) {
// Used on Myst 4143 (Dock near Marker Switch)
uint16 soundId = argv[0];
uint16 delay = argv[1];
uint16 directionalUpdateDataSize = argv[2];
debugC(kDebugScript, "Opcode %d: Vault Close Logic", op);
debugC(kDebugScript, "\tsoundId: %d", soundId);
debugC(kDebugScript, "\tdirectionalUpdateDataSize: %d", directionalUpdateDataSize);
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->replaceSoundMyst(soundId);
_vm->redrawArea(41, false);
animatedUpdate(directionalUpdateDataSize, &argv[3], delay);
}
}
void Myst::o_bookGivePage(uint16 op, uint16 var, uint16 argc, uint16 *argv) {
uint16 cardIdLose = argv[0];
uint16 cardIdBookCover = argv[1];
uint16 soundIdAddPage = argv[2];
debugC(kDebugScript, "Opcode %d: Red and Blue Book/Page Interaction", op);
debugC(kDebugScript, "Var: %d", var);
debugC(kDebugScript, "Card Id (Lose): %d", cardIdLose);
debugC(kDebugScript, "Card Id (Book Cover): %d", cardIdBookCover);
debugC(kDebugScript, "SoundId (Add Page): %d", soundIdAddPage);
// No page or white page
if (!_globals.heldPage || _globals.heldPage == 13) {
_vm->changeToCard(cardIdBookCover, kTransitionDissolve);
return;
}
uint16 bookVar = 101;
uint16 mask = 0;
switch (_globals.heldPage) {
case 7:
bookVar = 100;
case 1:
mask = 1;
break;
case 8:
bookVar = 100;
case 2:
mask = 2;
break;
case 9:
bookVar = 100;
case 3:
mask = 4;
break;
case 10:
bookVar = 100;
case 4:
mask = 8;
break;
case 11:
bookVar = 100;
case 5:
mask = 16;
break;
case 12:
bookVar = 100;
case 6:
mask = 32;
break;
}
// Wrong book
if (bookVar != var) {
_vm->changeToCard(cardIdBookCover, kTransitionDissolve);
return;
}
_vm->_cursor->hideCursor();
_vm->_sound->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 = 0;
_vm->_cursor->showCursor();
if (mask == 32) {
// You lose!
if (var == 100)
_globals.currentAge = 9;
else
_globals.currentAge = 10;
_vm->changeToCard(cardIdLose, kTransitionDissolve);
} else {
_vm->changeToCard(cardIdBookCover, kTransitionDissolve);
}
}
void Myst::o_clockWheelsExecute(uint16 op, uint16 var, uint16 argc, uint16 *argv) {
// Used on Card 4006 (Clock Tower Time Controls)
uint16 soundId = argv[0];
debugC(kDebugScript, "Opcode %d: Clock Tower Bridge Puzzle Execute Button", op);
// Correct time is 2:40
bool correctTime = _state.clockTowerHourPosition == 2
&& _state.clockTowerMinutePosition == 40;
if (!_state.clockTowerBridgeOpen && correctTime) {
_vm->_sound->replaceSoundMyst(soundId);
_vm->_system->delayMillis(500);
// Gears rise up
VideoHandle gears = _vm->_video->playMovie(_vm->wrapMovieFilename("gears", kMystStack), 305, 33);
_vm->_video->setVideoBounds(gears, Audio::Timestamp(0, 0, 600), Audio::Timestamp(0, 650, 600));
_vm->_video->waitUntilMovieEnds(gears);
_state.clockTowerBridgeOpen = 1;
_vm->redrawArea(12);
} else if (_state.clockTowerBridgeOpen && !correctTime) {
_vm->_sound->replaceSoundMyst(soundId);
_vm->_system->delayMillis(500);
// Gears sink down
VideoHandle gears = _vm->_video->playMovie(_vm->wrapMovieFilename("gears", kMystStack), 305, 33);
_vm->_video->setVideoBounds(gears, Audio::Timestamp(0, 700, 600), Audio::Timestamp(0, 1300, 600));
_vm->_video->waitUntilMovieEnds(gears);
_state.clockTowerBridgeOpen = 0;
_vm->redrawArea(12);
}
}
void Myst::o_imagerPlayButton(uint16 op, uint16 var, uint16 argc, uint16 *argv) {
debugC(kDebugScript, "Opcode %d: Imager play button", op);
uint16 video = getVar(51);
// Press button
_vm->_sound->replaceSoundMyst(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->_system->updateScreen();
_vm->_system->delayMillis(200);
_vm->_gfx->copyBackBufferToScreen(dest);
_vm->_system->updateScreen();
_vm->_cursor->hideCursor();
// Play selected video
if (!_state.imagerActive && video != 3)
_vm->_sound->replaceSoundMyst(argv[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 = _vm->wrapMovieFilename("vltmntn", kMystStack);
VideoHandle mountain = _vm->_video->playMovie(file, 159, 96, false);
_vm->_video->setVideoBounds(mountain, Audio::Timestamp(0, 11180, 600), Audio::Timestamp(0, 16800, 600));
_state.imagerActive = 0;
} else {
// Mountains appearing
Common::String file = _vm->wrapMovieFilename("vltmntn", kMystStack);
VideoHandle mountain = _vm->_video->playMovie(file, 159, 96, false);
_vm->_video->setVideoBounds(mountain, 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->replaceSoundMyst(argv[1]);
// Water disappearing
VideoHandle water = _imagerMovie->playMovie();
_vm->_video->setVideoBounds(water, Audio::Timestamp(0, 4204, 600), Audio::Timestamp(0, 6040, 600));
_vm->_video->setVideoLooping(water, false);
_state.imagerActive = 0;
} else {
// Water appearing
VideoHandle water = _imagerMovie->playMovie();
_vm->_video->setVideoBounds(water, Audio::Timestamp(0, 0, 600), Audio::Timestamp(0, 1814, 600));
_vm->_video->waitUntilMovieEnds(water);
// Water looping
water = _imagerMovie->playMovie();
_vm->_video->setVideoBounds(water, Audio::Timestamp(0, 1814, 600), Audio::Timestamp(0, 4204, 600));
_vm->_video->setVideoLooping(water, true);
_state.imagerActive = 1;
}
break;
}
_vm->_cursor->showCursor();
}
void Myst::o_imagerEraseButton(uint16 op, uint16 var, uint16 argc, uint16 *argv) {
debugC(kDebugScript, "Opcode %d: Imager erase button", op);
_imagerRedButton = static_cast<MystResourceType8 *>(_invokingResource->_parent);
for (uint i = 0; i < 4; i++)
_imagerSound[i] = argv[i];
_imagerValidationCard = argv[4];
if (_imagerValidationStep == 0) {
// Validation script is not running, run it
_startTime = _vm->_system->getMillis() + 100;
_imagerValidationRunning = true;
return;
} else if (_imagerValidationStep < 7) {
// Too early
_vm->_sound->playSoundBlocking(_imagerSound[2]);
_imagerValidationStep = 0;
return;
} else if (_imagerValidationStep < 11) {
_vm->_sound->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;
}
_state.imagerActive = 0;
_imagerValidationStep = 0;
return;
} else if (_imagerValidationStep == 11) {
// Too late
_imagerValidationStep = 0;
return;
}
}
void Myst::imagerValidation_run() {
uint32 time = _vm->_system->getMillis();
if (time > _startTime) {
_imagerRedButton->drawConditionalDataToScreen(1);
if (_imagerValidationStep < 6)
_vm->_sound->replaceSoundMyst(_imagerSound[0]);
else if (_imagerValidationStep < 10)
_vm->_sound->replaceSoundMyst(_imagerSound[1]);
else if (_imagerValidationStep == 10)
_vm->_sound->replaceSoundMyst(_imagerSound[2]);
_imagerValidationStep++;
_vm->_system->delayMillis(50);
_imagerRedButton->drawConditionalDataToScreen(0);
if (_imagerValidationStep == 11) {
_imagerValidationStep = 0;
_vm->changeToCard(_imagerValidationCard, kTransitionBottomToTop);
} else {
_startTime = time + 100;
}
}
}
void Myst::o_towerElevatorAnimation(uint16 op, uint16 var, uint16 argc, uint16 *argv) {
debugC(kDebugScript, "Opcode %d: Tower elevator animation", op);
_treeStopped = true;
_vm->_cursor->hideCursor();
_vm->_sound->stopSound();
_vm->_sound->pauseBackgroundMyst();
switch (argv[0]) {
case 0:
_vm->_video->playMovieBlocking(_vm->wrapMovieFilename("libdown", kMystStack), 216, 78);
break;
case 1:
_vm->_video->playMovieBlocking(_vm->wrapMovieFilename("libup", kMystStack), 216, 78);
break;
default:
break;
}
_vm->_sound->resumeBackgroundMyst();
_vm->_cursor->showCursor();
_treeStopped = false;
}
void Myst::o_generatorButtonPressed(uint16 op, uint16 var, uint16 argc, uint16 *argv) {
debugC(kDebugScript, "Opcode %d: Generator button pressed", op);
MystResource *button = _invokingResource->_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->replaceSoundMyst(8297);
else {
_vm->_sound->replaceSoundMyst(9297);
_vm->_sound->stopBackgroundMyst();
}
} else {
if (_generatorVoltage)
_vm->_sound->replaceSoundMyst(6297);
else {
_vm->_sound->replaceSoundMyst(7297); // TODO: Replace with play sound and replace background 4297
_vm->_sound->replaceBackgroundMyst(4297);
}
_state.generatorButtons |= mask;
_state.generatorVoltage += value;
}
// Redraw button
_vm->redrawArea(button->getType8Var());
// Blow breaker
if (_state.generatorVoltage > 59)
_state.generatorBreakers = _vm->_rnd->getRandomNumberRng(1, 2);
}
void Myst::generatorRedrawRocket() {
_vm->redrawArea(64);
_vm->redrawArea(65);
_vm->redrawArea(97);
}
void Myst::generatorButtonValue(MystResource *button, uint16 &mask, uint16 &value) {
switch (button->getType8Var()) {
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;
}
}
void Myst::o_cabinSafeChangeDigit(uint16 op, uint16 var, uint16 argc, uint16 *argv) {
debugC(kDebugScript, "Opcode %d: Cabin safe change digit", op);
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->redrawArea(var);
}
void Myst::o_cabinSafeHandleStartMove(uint16 op, uint16 var, uint16 argc, uint16 *argv) {
debugC(kDebugScript, "Opcode %d: Cabin safe handle start move", op);
// Used on Card 4100
MystResourceType12 *handle = static_cast<MystResourceType12 *>(_invokingResource);
handle->drawFrame(0);
_vm->_cursor->setCursor(700);
_tempVar = 0;
}
void Myst::o_cabinSafeHandleMove(uint16 op, uint16 var, uint16 argc, uint16 *argv) {
debugC(kDebugScript, "Opcode %d: Cabin safe handle move", op);
// Used on Card 4100
MystResourceType12 *handle = static_cast<MystResourceType12 *>(_invokingResource);
if (handle->pullLeverV()) {
// Sound not played yet
if (_tempVar == 0) {
uint16 soundId = handle->getList2(0);
if (soundId)
_vm->_sound->replaceSoundMyst(soundId);
}
// Combination is right
if (_state.cabinSafeCombination == 724) {
uint16 soundId = handle->getList2(1);
if (soundId)
_vm->_sound->replaceSoundMyst(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 op, uint16 var, uint16 argc, uint16 *argv) {
debugC(kDebugScript, "Opcode %d: Cabin safe handle end move", op);
// Used on Card 4100
MystResourceType12 *handle = static_cast<MystResourceType12 *>(_invokingResource);
handle->drawFrame(0);
_vm->checkCursorHints();
}
void Myst::o_observatoryMonthChangeStart(uint16 op, uint16 var, uint16 argc, uint16 *argv) {
debugC(kDebugScript, "Opcode %d: Observatory month change start", op);
_vm->_sound->pauseBackgroundMyst();
if (op == 129 || op == 131) {
// 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->_system->getMillis();
_observatoryMonthChanging = true;
}
void Myst::observatoryIncrementMonth(int16 increment) {
int16 newMonth = _state.observatoryMonthSetting + increment;
if (newMonth >= 0 && newMonth <= 11) {
_state.observatoryMonthSetting = newMonth;
// Redraw digits
_vm->redrawArea(73);
// Update slider
_observatoryMonthSlider->setPosition(94 + 94 * _state.observatoryMonthSetting / 11);
_observatoryMonthSlider->restoreBackground();
_observatoryMonthSlider->drawConditionalDataToScreen(2);
_state.observatoryMonthSlider = _observatoryMonthSlider->_pos.y;
}
_vm->_sound->replaceSoundMyst(8500);
}
void Myst::observatoryMonthChange_run() {
if (_startTime + 500 < _vm->_system->getMillis())
observatoryIncrementMonth(_observatoryIncrement);
}
void Myst::o_observatoryDayChangeStart(uint16 op, uint16 var, uint16 argc, uint16 *argv) {
debugC(kDebugScript, "Opcode %d: Observatory day change start", op);
_vm->_sound->pauseBackgroundMyst();
if (op == 129 || op == 131) {
// 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->_system->getMillis();
_observatoryDayChanging = true;
}
void Myst::observatoryIncrementDay(int16 increment) {
int16 newDay = _state.observatoryDaySetting + increment;
if (newDay >= 1 && newDay <= 31) {
_state.observatoryDaySetting = newDay;
// Redraw digits
_vm->redrawArea(75);
_vm->redrawArea(74);
// Update slider
_observatoryDaySlider->setPosition(91 + 3 * _state.observatoryDaySetting);
_observatoryDaySlider->restoreBackground();
_observatoryDaySlider->drawConditionalDataToScreen(2);
_state.observatoryDaySlider = _observatoryDaySlider->_pos.y;
}
_vm->_sound->replaceSoundMyst(8500);
}
void Myst::observatoryDayChange_run() {
if (_startTime + 500 < _vm->_system->getMillis())
observatoryIncrementDay(_observatoryIncrement);
}
void Myst::o_observatoryYearChangeStart(uint16 op, uint16 var, uint16 argc, uint16 *argv) {
debugC(kDebugScript, "Opcode %d: Observatory year change start", op);
_vm->_sound->pauseBackgroundMyst();
if (op == 196) {
// 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->_system->getMillis();
_observatoryYearChanging = true;
}
void Myst::observatoryIncrementYear(int16 increment) {
int16 newYear = _state.observatoryYearSetting + increment;
if (newYear >= 0 && newYear <= 9999) {
_state.observatoryYearSetting = newYear;
// Redraw digits
_vm->redrawArea(79);
_vm->redrawArea(78);
_vm->redrawArea(77);
_vm->redrawArea(76);
// Update slider
_observatoryYearSlider->setPosition(94 + 94 * _state.observatoryYearSetting / 9999);
_observatoryYearSlider->restoreBackground();
_observatoryYearSlider->drawConditionalDataToScreen(2);
_state.observatoryYearSlider = _observatoryYearSlider->_pos.y;
}
_vm->_sound->replaceSoundMyst(8500);
}
void Myst::observatoryYearChange_run() {
if (_startTime + 500 < _vm->_system->getMillis())
observatoryIncrementYear(_observatoryIncrement);
}
void Myst::o_observatoryTimeChangeStart(uint16 op, uint16 var, uint16 argc, uint16 *argv) {
debugC(kDebugScript, "Opcode %d: Observatory time change start", op);
_vm->_sound->pauseBackgroundMyst();
if (op == 192) {
// 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->_system->getMillis();
_observatoryTimeChanging = true;
}
void Myst::observatoryIncrementTime(int16 increment) {
int16 newTime = _state.observatoryTimeSetting + increment;
if (newTime >= 0 && newTime <= 1439) {
_state.observatoryTimeSetting = newTime;
// Redraw digits
_vm->redrawArea(80);
_vm->redrawArea(81);
_vm->redrawArea(82);
_vm->redrawArea(83);
// Draw AM/PM
if (!observatoryIsDDMMYYYY2400()) {
_vm->redrawArea(88);
}
// Update slider
_observatoryTimeSlider->setPosition(94 + 94 * _state.observatoryTimeSetting / 1439);
_observatoryTimeSlider->restoreBackground();
_observatoryTimeSlider->drawConditionalDataToScreen(2);
_state.observatoryTimeSlider = _observatoryTimeSlider->_pos.y;
}
_vm->_sound->replaceSoundMyst(8500);
}
void Myst::observatoryTimeChange_run() {
if (_startTime + 500 < _vm->_system->getMillis())
observatoryIncrementTime(_observatoryIncrement);
}
void Myst::o_observatoryGoButton(uint16 op, uint16 var, uint16 argc, uint16 *argv) {
debugC(kDebugScript, "Opcode %d: Observatory go button", op);
// Setting not at target
if (_state.observatoryDayTarget != _state.observatoryDaySetting
|| _state.observatoryMonthTarget != _state.observatoryMonthSetting
|| _state.observatoryYearTarget != _state.observatoryYearSetting
|| _state.observatoryTimeTarget != _state.observatoryTimeSetting) {
uint16 soundId = argv[0];
_vm->_sound->replaceSoundMyst(soundId);
int16 distance = _state.observatoryYearTarget - _state.observatoryYearSetting;
uint32 end = _vm->_system->getMillis() + 32 * ABS(distance) / 50 + 800;
while (end > _vm->_system->getMillis()) {
_vm->_system->delayMillis(50);
observatoryUpdateVisualizer(_vm->_rnd->getRandomNumber(409), _vm->_rnd->getRandomNumber(409));
_vm->redrawResource(_observatoryVisualizer);
}
_vm->_sound->resumeBackgroundMyst();
// Redraw visualizer
observatorySetTargetToSetting();
_vm->redrawResource(_observatoryVisualizer);
// Redraw button
_tempVar = 0;
_vm->redrawArea(105);
}
}
void Myst::o_observatoryMonthSliderMove(uint16 op, uint16 var, uint16 argc, uint16 *argv) {
debugC(kDebugScript, "Opcode %d: Month slider move", op);
observatoryUpdateMonth();
}
void Myst::o_observatoryDaySliderMove(uint16 op, uint16 var, uint16 argc, uint16 *argv) {
debugC(kDebugScript, "Opcode %d: Day slider move", op);
observatoryUpdateDay();
}
void Myst::o_observatoryYearSliderMove(uint16 op, uint16 var, uint16 argc, uint16 *argv) {
debugC(kDebugScript, "Opcode %d: Year slider move", op);
observatoryUpdateYear();
}
void Myst::o_observatoryTimeSliderMove(uint16 op, uint16 var, uint16 argc, uint16 *argv) {
debugC(kDebugScript, "Opcode %d: Time slider move", op);
observatoryUpdateTime();
}
void Myst::o_circuitBreakerStartMove(uint16 op, uint16 var, uint16 argc, uint16 *argv) {
debugC(kDebugScript, "Opcode %d: Circuit breaker start move", op);
MystResourceType12 *breaker = static_cast<MystResourceType12 *>(_invokingResource);
breaker->drawFrame(0);
_vm->_cursor->setCursor(700);
_tempVar = 0;
}
void Myst::o_circuitBreakerMove(uint16 op, uint16 var, uint16 argc, uint16 *argv) {
debugC(kDebugScript, "Opcode %d: Circuit breaker move", op);
MystResourceType12 *breaker = static_cast<MystResourceType12 *>(_invokingResource);
const Common::Point &mouse = _vm->_system->getEventManager()->getMousePos();
int16 maxStep = breaker->getStepsV() - 1;
int16 step = ((mouse.y - 80) * breaker->getStepsV()) / 65;
step = CLIP<uint16>(step, 0, maxStep);
breaker->drawFrame(step);
if (_tempVar != step) {
_tempVar = step;
// Breaker switched
if (step == maxStep) {
// Choose breaker
if (breaker->getType8Var() == 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->replaceSoundMyst(soundId);
} else {
uint16 soundId = breaker->getList2(0);
if (soundId)
_vm->_sound->replaceSoundMyst(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->replaceSoundMyst(soundId);
} else {
uint16 soundId = breaker->getList2(0);
if (soundId)
_vm->_sound->replaceSoundMyst(soundId);
// Reset breaker state
_state.generatorBreakers = 0;
}
}
}
}
}
void Myst::o_circuitBreakerEndMove(uint16 op, uint16 var, uint16 argc, uint16 *argv) {
debugC(kDebugScript, "Opcode %d: Circuit breaker end move", op);
MystResourceType12 *breaker = static_cast<MystResourceType12 *>(_invokingResource);
_vm->redrawArea(breaker->getType8Var());
_vm->checkCursorHints();
}
void Myst::o_boilerIncreasePressureStart(uint16 op, uint16 var, uint16 argc, uint16 *argv) {
debugC(kDebugScript, "Opcode %d: Boiler increase pressure start", op);
_treeStopped = true;
if (_state.cabinValvePosition < 25)
_vm->_sound->stopBackgroundMyst();
_boilerPressureIncreasing = true;
}
void Myst::o_boilerLightPilot(uint16 op, uint16 var, uint16 argc, uint16 *argv) {
debugC(kDebugScript, "Opcode %d: Boiler light pilot", op);
// Match is lit
if (_cabinMatchState == 1) {
_state.cabinPilotLightLit = 1;
_vm->redrawArea(98);
boilerFireUpdate(false);
// Put out match
_matchGoOutTime = _vm->_system->getMillis();
if (_state.cabinValvePosition > 0)
_vm->_sound->replaceBackgroundMyst(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->_system->getMillis();
}
}
}
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 (_vm->_video->endOfVideo(_cabinGaugeMovie)) {
if (_vm->getCurCard() == 4098) {
_cabinGaugeMovie = _vm->_video->playMovie(_vm->wrapMovieFilename("cabingau", kMystStack), 243, 96);
} else {
_cabinGaugeMovie = _vm->_video->playMovie(_vm->wrapMovieFilename("cabcgfar", kMystStack), 254, 136);
}
}
Audio::Timestamp goTo;
if (rate > 0)
goTo = Audio::Timestamp(0, 0, 600);
else
goTo = _vm->_video->getDuration(_cabinGaugeMovie);
_vm->_video->seekToTime(_cabinGaugeMovie, goTo);
_vm->_video->setVideoRate(_cabinGaugeMovie, rate);
}
void Myst::o_boilerIncreasePressureStop(uint16 op, uint16 var, uint16 argc, uint16 *argv) {
debugC(kDebugScript, "Opcode %d: Boiler increase pressure stop", op);
_treeStopped = false;
_boilerPressureIncreasing = false;
_state.treeLastMoveTime = _vm->_system->getMillis();
if (_state.cabinPilotLightLit == 1) {
if (_state.cabinValvePosition > 0)
_vm->_sound->replaceBackgroundMyst(8098, 49152);
if (!_vm->_video->endOfVideo(_cabinGaugeMovie)) {
uint16 delay = treeNextMoveDelay(_state.cabinValvePosition);
Common::Rational rate = boilerComputeGaugeRate(_state.cabinValvePosition, delay);
_vm->_video->setVideoRate(_cabinGaugeMovie, rate);
}
} else if (_state.cabinValvePosition > 0)
_vm->_sound->replaceBackgroundMyst(4098, _state.cabinValvePosition << 10);
}
void Myst::boilerPressureIncrease_run() {
// Allow increasing pressure if sound has stopped
if (!_vm->_sound->isPlaying(5098) && _state.cabinValvePosition < 25) {
_state.cabinValvePosition++;
if (_state.cabinValvePosition == 1) {
// Set fire to high
boilerFireUpdate(false);
// Draw fire
_vm->redrawArea(305);
} else if (_state.cabinValvePosition == 25) {
if (_state.cabinPilotLightLit == 1)
_vm->_sound->replaceBackgroundMyst(8098, 49152);
else
_vm->_sound->replaceBackgroundMyst(4098, 25600);
}
// Pressure increasing sound
_vm->_sound->replaceSoundMyst(5098);
// Redraw wheel
_vm->redrawArea(99);
}
}
void Myst::boilerPressureDecrease_run() {
// Allow decreasing pressure if sound has stopped
if (!_vm->_sound->isPlaying(5098) && _state.cabinValvePosition > 0) {
_state.cabinValvePosition--;
if (_state.cabinValvePosition == 0) {
// Set fire to low
boilerFireUpdate(false);
// Draw fire
_vm->redrawArea(305);
}
// Pressure increasing sound
_vm->_sound->replaceSoundMyst(5098);
// Redraw wheel
_vm->redrawArea(99);
}
}
void Myst::o_boilerDecreasePressureStart(uint16 op, uint16 var, uint16 argc, uint16 *argv) {
debugC(kDebugScript, "Opcode %d: Boiler decrease pressure start", op);
_treeStopped = true;
_vm->_sound->stopBackgroundMyst();
_boilerPressureDecreasing = true;
}
void Myst::o_boilerDecreasePressureStop(uint16 op, uint16 var, uint16 argc, uint16 *argv) {
debugC(kDebugScript, "Opcode %d: Boiler decrease pressure stop", op);
_treeStopped = false;
_boilerPressureDecreasing = false;
_state.treeLastMoveTime = _vm->_system->getMillis();
if (_state.cabinPilotLightLit == 1) {
if (_state.cabinValvePosition > 0)
_vm->_sound->replaceBackgroundMyst(8098, 49152);
if (!_vm->_video->endOfVideo(_cabinGaugeMovie)) {
uint16 delay = treeNextMoveDelay(_state.cabinValvePosition);
Common::Rational rate = boilerComputeGaugeRate(_state.cabinValvePosition, delay);
_vm->_video->setVideoRate(_cabinGaugeMovie, rate);
}
} else {
if (_state.cabinValvePosition > 0)
_vm->_sound->replaceBackgroundMyst(4098, _state.cabinValvePosition << 10);
}
}
void Myst::o_basementIncreasePressureStart(uint16 op, uint16 var, uint16 argc, uint16 *argv) {
debugC(kDebugScript, "Opcode %d: Basement increase pressure start", op);
_treeStopped = true;
_basementPressureIncreasing = true;
}
void Myst::o_basementIncreasePressureStop(uint16 op, uint16 var, uint16 argc, uint16 *argv) {
debugC(kDebugScript, "Opcode %d: Basement increase pressure stop", op);
_treeStopped = false;
_basementPressureIncreasing = false;
_state.treeLastMoveTime = _vm->_system->getMillis();
}
void Myst::basementPressureIncrease_run() {
// Allow increasing pressure if sound has stopped
if (!_vm->_sound->isPlaying(4642) && _state.cabinValvePosition < 25) {
_state.cabinValvePosition++;
// Pressure increasing sound
_vm->_sound->replaceSoundMyst(4642);
// Redraw wheel
_vm->redrawArea(99);
}
}
void Myst::basementPressureDecrease_run() {
// Allow decreasing pressure if sound has stopped
if (!_vm->_sound->isPlaying(4642) && _state.cabinValvePosition > 0) {
_state.cabinValvePosition--;
// Pressure decreasing sound
_vm->_sound->replaceSoundMyst(4642);
// Redraw wheel
_vm->redrawArea(99);
}
}
void Myst::o_basementDecreasePressureStart(uint16 op, uint16 var, uint16 argc, uint16 *argv) {
debugC(kDebugScript, "Opcode %d: Basement decrease pressure start", op);
_treeStopped = true;
_basementPressureDecreasing = true;
}
void Myst::o_basementDecreasePressureStop(uint16 op, uint16 var, uint16 argc, uint16 *argv) {
debugC(kDebugScript, "Opcode %d: Basement decrease pressure stop", op);
_treeStopped = false;
_basementPressureDecreasing = false;
_state.treeLastMoveTime = _vm->_system->getMillis();
}
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->_system->getMillis();
if (delay < time - _state.treeLastMoveTime) {
// Tree movement
if (goingDown) {
_state.treePosition--;
_vm->_sound->replaceSoundMyst(2);
} else {
_state.treePosition++;
_vm->_sound->replaceSoundMyst(1);
}
// Stop background music if going up from book room
if (_vm->getCurCard() == 4630) {
if (_state.treePosition > 0)
_vm->_sound->stopBackgroundMyst();
else
_vm->_sound->replaceBackgroundMyst(4630, 24576);
}
// Redraw tree
_vm->redrawArea(72);
// Check if alcove is accessible
treeSetAlcoveAccessible();
if (_cabinGaugeMovie != NULL_VID_HANDLE) {
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 op, uint16 var, uint16 argc, uint16 *argv) {
debugC(kDebugScript, "Opcode %d: Rocket slider start move", op);
_rocketSliderSound = 0;
_vm->_cursor->setCursor(700);
_vm->_sound->pauseBackgroundMyst();
rocketSliderMove();
}
void Myst::o_rocketSoundSliderMove(uint16 op, uint16 var, uint16 argc, uint16 *argv) {
debugC(kDebugScript, "Opcode %d: Rocket slider move", op);
rocketSliderMove();
}
void Myst::o_rocketSoundSliderEndMove(uint16 op, uint16 var, uint16 argc, uint16 *argv) {
debugC(kDebugScript, "Opcode %d: Rocket slider end move", op);
_vm->checkCursorHints();
if (_state.generatorVoltage == 59 && !_state.generatorBreakers && _rocketSliderSound)
_vm->_sound->stopSound();
if (_invokingResource == _rocketSlider1)
_state.rocketSliderPosition[0] = _rocketSlider1->_pos.y;
else if (_invokingResource == _rocketSlider2)
_state.rocketSliderPosition[1] = _rocketSlider2->_pos.y;
else if (_invokingResource == _rocketSlider3)
_state.rocketSliderPosition[2] = _rocketSlider3->_pos.y;
else if (_invokingResource == _rocketSlider4)
_state.rocketSliderPosition[3] = _rocketSlider4->_pos.y;
else if (_invokingResource == _rocketSlider5)
_state.rocketSliderPosition[4] = _rocketSlider5->_pos.y;
_vm->_sound->resumeBackgroundMyst();
}
void Myst::rocketSliderMove() {
MystResourceType10 *slider = static_cast<MystResourceType10 *>(_invokingResource);
if (_state.generatorVoltage == 59 && !_state.generatorBreakers) {
uint16 soundId = rocketSliderGetSound(slider->_pos.y);
if (soundId != _rocketSliderSound) {
_rocketSliderSound = soundId;
_vm->_sound->replaceSoundMyst(soundId, Audio::Mixer::kMaxChannelVolume, true);
}
}
}
uint16 Myst::rocketSliderGetSound(uint16 pos) {
return (uint16)(9530 + (pos - 216) * 35.0 / 61.0);
}
void Myst::rocketCheckSolution() {
_vm->_cursor->hideCursor();
uint16 soundId;
bool solved = true;
soundId = rocketSliderGetSound(_rocketSlider1->_pos.y);
_vm->_sound->replaceSoundMyst(soundId);
_rocketSlider1->drawConditionalDataToScreen(2);
_vm->_system->delayMillis(250);
if (soundId != 9558)
solved = false;
soundId = rocketSliderGetSound(_rocketSlider2->_pos.y);
_vm->_sound->replaceSoundMyst(soundId);
_rocketSlider2->drawConditionalDataToScreen(2);
_vm->_system->delayMillis(250);
if (soundId != 9546)
solved = false;
soundId = rocketSliderGetSound(_rocketSlider3->_pos.y);
_vm->_sound->replaceSoundMyst(soundId);
_rocketSlider3->drawConditionalDataToScreen(2);
_vm->_system->delayMillis(250);
if (soundId != 9543)
solved = false;
soundId = rocketSliderGetSound(_rocketSlider4->_pos.y);
_vm->_sound->replaceSoundMyst(soundId);
_rocketSlider4->drawConditionalDataToScreen(2);
_vm->_system->delayMillis(250);
if (soundId != 9553)
solved = false;
soundId = rocketSliderGetSound(_rocketSlider5->_pos.y);
_vm->_sound->replaceSoundMyst(soundId);
_rocketSlider5->drawConditionalDataToScreen(2);
_vm->_system->delayMillis(250);
if (soundId != 9560)
solved = false;
_vm->_sound->stopSound();
if (solved) {
// Reset lever position
MystResourceType12 *lever = static_cast<MystResourceType12 *>(_invokingResource);
lever->drawFrame(0);
// Book appearing
Common::String movieFile = _vm->wrapMovieFilename("selenbok", kMystStack);
_rocketLinkBook = _vm->_video->playMovie(movieFile, 224, 41);
_vm->_video->setVideoBounds(_rocketLinkBook, Audio::Timestamp(0, 0, 600), Audio::Timestamp(0, 660, 600));
_vm->_video->waitUntilMovieEnds(_rocketLinkBook);
// Book looping closed
_rocketLinkBook = _vm->_video->playMovie(movieFile, 224, 41, true);
_vm->_video->setVideoBounds(_rocketLinkBook, 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 op, uint16 var, uint16 argc, uint16 *argv) {
debugC(kDebugScript, "Opcode %d: Rocket piano start move", op);
MystResourceType11 *key = static_cast<MystResourceType11 *>(_invokingResource);
// What the hell??
Common::Rect src = key->_subImages[1].rect;
Common::Rect rect = key->_subImages[0].rect;
Common::Rect dest = rect;
dest.top = 332 - rect.bottom;
dest.bottom = 332 - rect.top;
// Draw pressed piano key
_vm->_gfx->copyImageSectionToScreen(key->_subImages[1].wdib, src, dest);
_vm->_system->updateScreen();
// Play note
if (_state.generatorVoltage == 59 && !_state.generatorBreakers) {
uint16 soundId = key->getList1(0);
_vm->_sound->replaceSoundMyst(soundId, Audio::Mixer::kMaxChannelVolume, true);
}
}
void Myst::o_rocketPianoMove(uint16 op, uint16 var, uint16 argc, uint16 *argv) {
debugC(kDebugScript, "Opcode %d: Rocket piano move", op);
const Common::Point &mouse = _vm->_system->getEventManager()->getMousePos();
Common::Rect piano = Common::Rect(85, 123, 460, 270);
// Unpress previous key
MystResourceType11 *key = static_cast<MystResourceType11 *>(_invokingResource);
Common::Rect src = key->_subImages[0].rect;
Common::Rect dest = src;
dest.top = 332 - src.bottom;
dest.bottom = 332 - src.top;
// Draw unpressed piano key
_vm->_gfx->copyImageSectionToScreen(key->_subImages[0].wdib, src, dest);
if (piano.contains(mouse)) {
MystResource *resource = _vm->updateCurrentResource();
if (resource && resource->type == kMystDragArea) {
// Press new key
key = static_cast<MystResourceType11 *>(resource);
src = key->_subImages[1].rect;
Common::Rect rect = key->_subImages[0].rect;
dest = rect;
dest.top = 332 - rect.bottom;
dest.bottom = 332 - rect.top;
// Draw pressed piano key
_vm->_gfx->copyImageSectionToScreen(key->_subImages[1].wdib, src, dest);
// Play note
if (_state.generatorVoltage == 59 && !_state.generatorBreakers) {
uint16 soundId = key->getList1(0);
_vm->_sound->replaceSoundMyst(soundId, Audio::Mixer::kMaxChannelVolume, true);
}
} else {
// Not pressing a key anymore
_vm->_sound->stopSound();
_vm->_sound->resumeBackgroundMyst();
}
}
_vm->_system->updateScreen();
}
void Myst::o_rocketPianoStop(uint16 op, uint16 var, uint16 argc, uint16 *argv) {
debugC(kDebugScript, "Opcode %d: Rocket piano end move", op);
MystResourceType8 *key = static_cast<MystResourceType8 *>(_invokingResource);
Common::Rect &src = key->_subImages[0].rect;
Common::Rect dest = src;
dest.top = 332 - src.bottom;
dest.bottom = 332 - src.top;
// Draw unpressed piano key
_vm->_gfx->copyImageSectionToScreen(key->_subImages[0].wdib, src, dest);
_vm->_system->updateScreen();
_vm->_sound->stopSound();
_vm->_sound->resumeBackgroundMyst();
}
void Myst::o_rocketLeverStartMove(uint16 op, uint16 var, uint16 argc, uint16 *argv) {
debugC(kDebugScript, "Opcode %d: Rocket lever start move", op);
MystResourceType12 *lever = static_cast<MystResourceType12 *>(_invokingResource);
_vm->_cursor->setCursor(700);
_rocketLeverPosition = 0;
lever->drawFrame(0);
}
void Myst::o_rocketOpenBook(uint16 op, uint16 var, uint16 argc, uint16 *argv) {
debugC(kDebugScript, "Opcode %d: Rocket open link book", op);
// Flyby movie
_vm->_video->setVideoBounds(_rocketLinkBook, Audio::Timestamp(0, 3500, 600), Audio::Timestamp(0, 13100, 600));
// Set linkable
_tempVar = 2;
}
void Myst::o_rocketLeverMove(uint16 op, uint16 var, uint16 argc, uint16 *argv) {
debugC(kDebugScript, "Opcode %d: Rocket lever move", op);
MystResourceType12 *lever = static_cast<MystResourceType12 *>(_invokingResource);
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<uint16>(step, 0, maxStep);
lever->drawFrame(step);
// If lever pulled
if (step == maxStep && step != _rocketLeverPosition) {
uint16 soundId = lever->getList2(0);
if (soundId)
_vm->_sound->replaceSoundMyst(soundId);
// If rocket correctly powered
if (_state.generatorVoltage == 59 && !_state.generatorBreakers)
rocketCheckSolution();
}
_rocketLeverPosition = step;
}
void Myst::o_rocketLeverEndMove(uint16 op, uint16 var, uint16 argc, uint16 *argv) {
debugC(kDebugScript, "Opcode %d: Rocket lever end move", op);
MystResourceType12 *lever = static_cast<MystResourceType12 *>(_invokingResource);
_vm->checkCursorHints();
_rocketLeverPosition = 0;
lever->drawFrame(0);
}
void Myst::o_cabinLeave(uint16 op, uint16 var, uint16 argc, uint16 *argv) {
debugC(kDebugScript, "Opcode %d: Leave cabin", op);
// If match is lit, put out
if (_cabinMatchState == 1) {
_matchGoOutTime = _vm->_system->getMillis();
} else if (_cabinMatchState == 0) {
_vm->setMainCursor(_savedCursorId);
_cabinMatchState = 2;
}
}
void Myst::o_treePressureReleaseStart(uint16 op, uint16 var, uint16 argc, uint16 *argv) {
debugC(kDebugScript, "Opcode %d: Tree pressure release start", op);
Common::Rect src = Common::Rect(0, 0, 49, 86);
Common::Rect dest = Common::Rect(78, 46, 127, 132);
_vm->_gfx->copyImageSectionToScreen(4631, src, dest);
_vm->_system->updateScreen();
_tempVar = _state.cabinValvePosition;
if (_state.treePosition >= 4) {
_state.cabinValvePosition = 0;
_treeMinPosition = 4;
_state.treeLastMoveTime = 0;
}
}
void Myst::o_treePressureReleaseStop(uint16 op, uint16 var, uint16 argc, uint16 *argv) {
debugC(kDebugScript, "Opcode %d: Tree pressure release stop", op);
Common::Rect rect = Common::Rect(78, 46, 127, 132);
_vm->_gfx->copyBackBufferToScreen(rect);
_vm->_system->updateScreen();
_state.cabinValvePosition = _tempVar;
_treeMinPosition = 0;
}
void Myst::o_observatoryMonthSliderStartMove(uint16 op, uint16 var, uint16 argc, uint16 *argv) {
debugC(kDebugScript, "Opcode %d: Month slider start move", op);
_vm->_cursor->setCursor(700);
_vm->_sound->pauseBackgroundMyst();
observatoryUpdateMonth();
}
void Myst::o_observatoryMonthSliderEndMove(uint16 op, uint16 var, uint16 argc, uint16 *argv) {
debugC(kDebugScript, "Opcode %d: Month slider end move", op);
_vm->checkCursorHints();
_vm->_sound->resumeBackgroundMyst();
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->replaceSoundMyst(8500);
// Redraw digits
_vm->redrawArea(73);
}
}
void Myst::o_observatoryDaySliderStartMove(uint16 op, uint16 var, uint16 argc, uint16 *argv) {
debugC(kDebugScript, "Opcode %d: Day slider start move", op);
_vm->_cursor->setCursor(700);
_vm->_sound->pauseBackgroundMyst();
observatoryUpdateDay();
}
void Myst::o_observatoryDaySliderEndMove(uint16 op, uint16 var, uint16 argc, uint16 *argv) {
debugC(kDebugScript, "Opcode %d: Day slider end move", op);
_vm->checkCursorHints();
_vm->_sound->resumeBackgroundMyst();
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->replaceSoundMyst(8500);
// Redraw digits
_vm->redrawArea(75);
_vm->redrawArea(74);
}
}
void Myst::o_observatoryYearSliderStartMove(uint16 op, uint16 var, uint16 argc, uint16 *argv) {
debugC(kDebugScript, "Opcode %d: Year slider start move", op);
_vm->_cursor->setCursor(700);
_vm->_sound->pauseBackgroundMyst();
observatoryUpdateYear();
}
void Myst::o_observatoryYearSliderEndMove(uint16 op, uint16 var, uint16 argc, uint16 *argv) {
debugC(kDebugScript, "Opcode %d: Year slider end move", op);
_vm->checkCursorHints();
_vm->_sound->resumeBackgroundMyst();
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->replaceSoundMyst(8500);
// Redraw digits
_vm->redrawArea(79);
_vm->redrawArea(78);
_vm->redrawArea(77);
_vm->redrawArea(76);
}
}
void Myst::o_observatoryTimeSliderStartMove(uint16 op, uint16 var, uint16 argc, uint16 *argv) {
debugC(kDebugScript, "Opcode %d: Time slider start move", op);
_vm->_cursor->setCursor(700);
_vm->_sound->pauseBackgroundMyst();
observatoryUpdateTime();
}
void Myst::o_observatoryTimeSliderEndMove(uint16 op, uint16 var, uint16 argc, uint16 *argv) {
debugC(kDebugScript, "Opcode %d: Time slider end move", op);
_vm->checkCursorHints();
_vm->_sound->resumeBackgroundMyst();
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->replaceSoundMyst(8500);
// Redraw digits
_vm->redrawArea(80);
_vm->redrawArea(81);
_vm->redrawArea(82);
_vm->redrawArea(83);
// Draw AM/PM
if (!observatoryIsDDMMYYYY2400())
_vm->redrawArea(88);
}
}
void Myst::o_libraryCombinationBookStop(uint16 op, uint16 var, uint16 argc, uint16 *argv) {
debugC(kDebugScript, "Opcode %d: Combination book stop turning pages", op);
_libraryCombinationBookPagesTurning = false;
}
void Myst::o_cabinMatchLight(uint16 op, uint16 var, uint16 argc, uint16 *argv) {
if (!_cabinMatchState) {
_vm->_sound->replaceSoundMyst(4103);
// Match is lit
_cabinMatchState = 1;
_matchBurning = true;
_matchGoOutCnt = 0;
_vm->setMainCursor(kLitMatchCursor);
// Match will stay lit for one minute
_matchGoOutTime = _vm->_system->getMillis() + 60 * 1000;
}
}
void Myst::matchBurn_run() {
uint32 time = _vm->_system->getMillis();
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 op, uint16 var, uint16 argc, uint16 *argv) {
debugC(kDebugScript, "Opcode %d: Mouse enters courtyard box", op);
_tempVar = 1;
_vm->_sound->playSound(_courtyardBoxSound);
_vm->redrawArea(var);
}
void Myst::o_courtyardBoxLeave(uint16 op, uint16 var, uint16 argc, uint16 *argv) {
debugC(kDebugScript, "Opcode %d: Mouse leaves courtyard box", op);
_tempVar = 0;
_vm->redrawArea(var);
}
void Myst::o_clockMinuteWheelStartTurn(uint16 op, uint16 var, uint16 argc, uint16 *argv) {
// Used on Card 4006
debugC(kDebugScript, "Opcode %d: Minute wheel start turn", op);
clockWheelStartTurn(2);
}
void Myst::o_clockWheelEndTurn(uint16 op, uint16 var, uint16 argc, uint16 *argv) {
// Used on Card 4006
debugC(kDebugScript, "Opcode %d: Wheel end turn", op);
_clockTurningWheel = 0;
}
void Myst::o_clockHourWheelStartTurn(uint16 op, uint16 var, uint16 argc, uint16 *argv) {
// Used on Card 4006
debugC(kDebugScript, "Opcode %d: Hour wheel start turn", op);
clockWheelStartTurn(1);
}
void Myst::clockWheel_run() {
// Turn wheel one step each second
uint32 time = _vm->_system->getMillis();
if (time > _startTime + 1000) {
_startTime = time;
if (_clockTurningWheel == 1)
clockWheelTurn(39);
else
clockWheelTurn(38);
_vm->redrawArea(37);
}
}
void Myst::clockWheelStartTurn(uint16 wheel) {
MystResourceType11 *resource = static_cast<MystResourceType11 *>(_invokingResource);
uint16 soundId = resource->getList1(0);
if (soundId)
_vm->_sound->replaceSoundMyst(soundId);
// Turn wheel one step
if (wheel == 1)
clockWheelTurn(39);
else
clockWheelTurn(38);
_vm->redrawArea(37);
// Continue turning wheel until mouse button is released
_clockTurningWheel = wheel;
_startTime = _vm->_system->getMillis();
}
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 op, uint16 var, uint16 argc, uint16 *argv) {
debugC(kDebugScript, "Opcode %d: Combination book start turning pages right", op);
_tempVar = 0;
libraryCombinationBookTurnRight();
_startTime = _vm->_system->getMillis();
_libraryCombinationBookPagesTurning = true;
}
void Myst::o_libraryCombinationBookStartLeft(uint16 op, uint16 var, uint16 argc, uint16 *argv) {
debugC(kDebugScript, "Opcode %d: Combination book start turning pages left", op);
_tempVar = 0;
libraryCombinationBookTurnLeft();
_startTime = _vm->_system->getMillis();
_libraryCombinationBookPagesTurning = true;
}
void Myst::libraryCombinationBookTurnLeft() {
// Turn page left
if (_libraryBookPage - 1 >= 0) {
_tempVar--;
if (_tempVar >= -5) {
_libraryBookPage--;
} else {
_libraryBookPage -= 5;
_tempVar = -5;
}
_libraryBookPage = CLIP<int16>(_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->replaceSoundMyst(_libraryBookSound1);
else
_vm->_sound->replaceSoundMyst(_libraryBookSound2);
_vm->_system->updateScreen();
}
}
void Myst::libraryCombinationBookTurnRight() {
// Turn page right
if (_libraryBookPage + 1 < _libraryBookNumPages) {
_tempVar++;
if (_tempVar <= 5) {
_libraryBookPage++;
} else {
_libraryBookPage += 5;
_tempVar = 5;
}
_libraryBookPage = CLIP<uint16>(_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->replaceSoundMyst(_libraryBookSound1);
else
_vm->_sound->replaceSoundMyst(_libraryBookSound2);
_vm->_system->updateScreen();
}
}
void Myst::libraryCombinationBook_run() {
uint32 time = _vm->_system->getMillis();
if (time >= _startTime + 500) {
if (_tempVar > 0) {
libraryCombinationBookTurnRight();
_startTime = time;
} else if (_tempVar < 0) {
libraryCombinationBookTurnLeft();
_startTime = time;
}
}
}
void Myst::o_observatoryChangeSettingStop(uint16 op, uint16 var, uint16 argc, uint16 *argv) {
debugC(kDebugScript, "Opcode %d: Observatory change setting stop", op);
// Stop persistent scripts
_observatoryMonthChanging = false;
_observatoryDayChanging = false;
_observatoryYearChanging = false;
_observatoryTimeChanging = false;
_observatoryIncrement = 0;
// Restore button and slider
_vm->_gfx->copyBackBufferToScreen(_invokingResource->getRect());
if (_observatoryCurrentSlider) {
_vm->redrawResource(_observatoryCurrentSlider);
_observatoryCurrentSlider = 0;
}
_vm->_sound->resumeBackgroundMyst();
}
void Myst::o_dockVaultForceClose(uint16 op, uint16 var, uint16 argc, uint16 *argv) {
// Used on Myst 4143 (Dock near Marker Switch)
uint16 soundId = argv[0];
uint16 delay = argv[1];
uint16 directionalUpdateDataSize = argv[2];
debugC(kDebugScript, "Opcode %d: Vault Force Close", op);
debugC(kDebugScript, "\tsoundId: %d", soundId);
debugC(kDebugScript, "\tdirectionalUpdateDataSize: %d", directionalUpdateDataSize);
if (_dockVaultState) {
// Open switch
_state.dockMarkerSwitch = 1;
_vm->_sound->replaceSoundMyst(4143);
_vm->redrawArea(4);
// Close vault
_dockVaultState = 0;
_vm->_sound->replaceSoundMyst(soundId);
_vm->redrawArea(41, false);
animatedUpdate(directionalUpdateDataSize, &argv[3], delay);
}
}
void Myst::o_imagerEraseStop(uint16 op, uint16 var, uint16 argc, uint16 *argv) {
debugC(kDebugScript, "Opcode %d: Imager stop erase", op);
_imagerValidationRunning = false;
}
void Myst::o_clockLeverStartMove(uint16 op, uint16 var, uint16 argc, uint16 *argv) {
debugC(kDebugScript, "Opcode %d: Clock lever start move", op);
MystResourceType12 *lever = static_cast<MystResourceType12 *>(_invokingResource);
lever->drawFrame(0);
_vm->_cursor->setCursor(700);
_clockMiddleGearMovedAlone = false;
_clockLeverPulled = false;
}
void Myst::o_clockLeverMove(uint16 op, uint16 var, uint16 argc, uint16 *argv) {
debugC(kDebugScript, "Opcode %d: Clock left lever move", op);
if (!_clockLeverPulled) {
MystResourceType12 *lever = static_cast<MystResourceType12 *>(_invokingResource);
// If lever pulled
if (lever->pullLeverV()) {
// Start videos for first step
if (_clockWeightPosition < 2214) {
_vm->_sound->replaceSoundMyst(5113);
clockGearForwardOneStep(1);
// Left lever
if (op == 144)
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->_video->playMovie(_vm->wrapMovieFilename(videos[gear], kMystStack), x[gear], y[gear]);
_vm->_video->setVideoBounds(_clockGearsVideos[gear],
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->getFeatures() & GF_ME) || _clockWeightPosition < (2214 - 246);
// Set video bounds
if (updateVideo) {
_clockWeightVideo = _vm->_video->playMovie(_vm->wrapMovieFilename("cl1wlfch", kMystStack) , 124, 0);
_vm->_video->setVideoBounds(_clockWeightVideo,
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->replaceSoundMyst(5113);
clockGearForwardOneStep(1);
clockWeightDownOneStep();
}
}
void Myst::o_clockLeverEndMove(uint16 op, uint16 var, uint16 argc, uint16 *argv) {
debugC(kDebugScript, "Opcode %d: Clock lever end move", op);
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++) {
VideoHandle handle = _vm->_video->findVideoHandle(_vm->wrapMovieFilename(videos[i], kMystStack));
if (handle != NULL_VID_HANDLE)
_vm->_video->delayUntilMovieEnds(handle);
}
if (_clockMiddleGearMovedAlone)
_vm->_sound->replaceSoundMyst(8113);
// Release lever
MystResourceType12 *lever = static_cast<MystResourceType12 *>(_invokingResource);
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->replaceSoundMyst(9113);
_clockWeightVideo = _vm->_video->playMovie(_vm->wrapMovieFilename("cl1wlfch", kMystStack) , 124, 0);
_vm->_video->setVideoBounds(_clockWeightVideo,
Audio::Timestamp(0, _clockWeightPosition, 600),
Audio::Timestamp(0, 2214, 600));
_vm->_video->waitUntilMovieEnds(_clockWeightVideo);
_clockWeightPosition = 2214;
_vm->_sound->replaceSoundMyst(6113);
_vm->_system->delayMillis(1000);
_vm->_sound->replaceSoundMyst(7113);
// Gear opening video
_vm->_video->playMovieBlocking(_vm->wrapMovieFilename("cl1wggat", kMystStack) , 195, 225);
_state.gearsOpen = 1;
_vm->redrawArea(40);
_vm->_sound->replaceBackgroundMyst(4113, 16384);
}
}
void Myst::o_clockResetLeverStartMove(uint16 op, uint16 var, uint16 argc, uint16 *argv) {
debugC(kDebugScript, "Opcode %d: Clock reset lever start move", op);
MystResourceType12 *lever = static_cast<MystResourceType12 *>(_invokingResource);
lever->drawFrame(0);
_vm->_cursor->setCursor(700);
}
void Myst::o_clockResetLeverMove(uint16 op, uint16 var, uint16 argc, uint16 *argv) {
debugC(kDebugScript, "Opcode %d: Clock reset lever move", op);
MystResourceType12 *lever = static_cast<MystResourceType12 *>(_invokingResource);
// If pulled
if (lever->pullLeverV() && _clockWeightPosition != 0)
clockReset();
}
void Myst::clockReset() {
static const char *videos[] = { "cl1wg1", "cl1wg2", "cl1wg3", "cl1wlfch" };
_vm->_cursor->hideCursor();
_vm->_sound->stopBackgroundMyst();
_vm->_sound->replaceSoundMyst(5113);
// Play reset videos
clockResetWeight();
clockResetGear(0);
clockResetGear(1);
clockResetGear(2);
// Let movies stop playing
for (uint i = 0; i < ARRAYSIZE(videos); i++) {
VideoHandle handle = _vm->_video->findVideoHandle(_vm->wrapMovieFilename(videos[i], kMystStack));
if (handle != NULL_VID_HANDLE)
_vm->_video->delayUntilMovieEnds(handle);
}
_vm->_sound->replaceSoundMyst(10113);
// Close gear
if (_state.gearsOpen) {
_vm->_sound->replaceSoundMyst(6113);
_vm->_system->delayMillis(1000);
_vm->_sound->replaceSoundMyst(7113);
// Gear closing movie
VideoHandle handle = _vm->_video->playMovie(_vm->wrapMovieFilename("cl1wggat", kMystStack) , 195, 225);
_vm->_video->seekToTime(handle, _vm->_video->getDuration(handle));
_vm->_video->setVideoRate(handle, -1);
_vm->_video->waitUntilMovieEnds(handle);
// Redraw gear
_state.gearsOpen = 0;
_vm->redrawArea(40);
}
_vm->_cursor->showCursor();
}
void Myst::clockResetWeight() {
_clockWeightVideo = _vm->_video->playMovie(_vm->wrapMovieFilename("cl1wlfch", kMystStack) , 124, 0);
// Play the movie backwards, weight going up
_vm->_video->seekToTime(_clockWeightVideo, Audio::Timestamp(0, _clockWeightPosition, 600));
_vm->_video->setVideoRate(_clockWeightVideo, -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->_video->playMovie(_vm->wrapMovieFilename(videos[gear], kMystStack), x[gear], y[gear]);
_vm->_video->setVideoBounds(_clockGearsVideos[gear],
Audio::Timestamp(0, time[gearPosition], 600),
Audio::Timestamp(0, time[2], 600));
}
// Reset gear position
_clockGearsPositions[gear] = 3;
}
void Myst::o_clockResetLeverEndMove(uint16 op, uint16 var, uint16 argc, uint16 *argv) {
debugC(kDebugScript, "Opcode %d: Clock reset lever end move", op);
// Get current lever frame
MystResourceType12 *lever = static_cast<MystResourceType12 *>(_invokingResource);
lever->releaseLeverV();
_vm->checkCursorHints();
}
void Myst::o_libraryBook_init(uint16 op, uint16 var, uint16 argc, uint16 *argv) {
_libraryBookPage = 0;
_libraryBookNumPages = argv[0];
_libraryBookBaseImage = argv[1];
_libraryBookSound1 = argv[2];
_libraryBookSound2 = argv[3];
}
void Myst::o_courtyardBox_init(uint16 op, uint16 var, uint16 argc, uint16 *argv) {
debugC(kDebugScript, "Opcode %d: Courtyard box init", op);
_courtyardBoxSound = argv[0];
}
void Myst::towerRotationMap_run() {
if (!_towerRotationMapInitialized) {
_towerRotationMapInitialized = true;
_vm->_sound->replaceSoundMyst(4378);
towerRotationDrawBuildings();
// Draw to screen
_vm->_gfx->copyBackBufferToScreen(Common::Rect(106, 42, 459, 273));
_vm->_system->updateScreen();
}
uint32 time = _vm->_system->getMillis();
if (time > _startTime) {
if (_towerRotationMapClicked) {
towerRotationMapRotate();
_startTime = time + 100;
} else if (_towerRotationBlinkLabel
&& _vm->_sound->isPlaying(6378)) {
// 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;
_towerRotationMapLabel->drawConditionalDataToScreen(0);
// Blink tower
_startTime = time + 500;
_tempVar = (_tempVar + 1) % 2;
_towerRotationMapTower->drawConditionalDataToScreen(_tempVar);
}
}
}
void Myst::o_towerRotationMap_init(uint16 op, uint16 var, uint16 argc, uint16 *argv) {
_towerRotationMapRunning = true;
_towerRotationMapTower = static_cast<MystResourceType11 *>(_invokingResource);
_towerRotationMapLabel = static_cast<MystResourceType8 *>(_vm->_resources[argv[0]]);
_tempVar = 0;
_startTime = 0;
_towerRotationMapClicked = false;
}
void Myst::towerRotationDrawBuildings() {
// Draw library
_vm->redrawArea(304, false);
// Draw other resources
for (uint i = 1; i <= 10; i++) {
MystResourceType8 *resource = static_cast<MystResourceType8 *>(_vm->_resources[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(const Common::Point &center, uint16 angle) {
Common::Point end;
// Polar to rect coords
double radians = angle * M_PI / 180.0;
end.x = (int16)(center.x + cos(radians) * 310.0);
end.y = (int16)(center.y + sin(radians) * 310.0);
return end;
}
void Myst::towerRotationMapDrawLine(const Common::Point &center, const Common::Point &end) {
Graphics::PixelFormat pf = _vm->_system->getScreenFormat();
uint32 color = 0;
if (!_towerRotationOverSpot)
color = pf.RGBToColor(0xFF, 0xFF, 0xFF); // White
else
color = pf.RGBToColor(0xFF, 0, 0); // Red
const Common::Rect rect = Common::Rect(106, 42, 459, 273);
Common::Rect src;
src.left = rect.left;
src.top = 333 - rect.bottom;
src.right = rect.right;
src.bottom = 333 - rect.top;
// Redraw background
_vm->_gfx->copyImageSectionToBackBuffer(_vm->getCardBackgroundId(), src, rect);
// Draw buildings
towerRotationDrawBuildings();
// Draw tower
_towerRotationMapTower->drawConditionalDataToScreen(0, false);
// Draw label
_towerRotationMapLabel->drawConditionalDataToScreen(1, false);
// Draw line
_vm->_gfx->drawLine(center, end, color);
_vm->_gfx->copyBackBufferToScreen(rect);
_vm->_system->updateScreen();
}
void Myst::towerRotationMapRotate() {
const Common::Point center = Common::Point(383, 124);
uint16 angle = towerRotationMapComputeAngle();
Common::Point end = towerRotationMapComputeCoords(center, angle);
towerRotationMapDrawLine(center, end);
}
void Myst::o_forechamberDoor_init(uint16 op, uint16 var, uint16 argc, uint16 *argv) {
// Used for Card 4138 (Dock Forechamber Door)
// Set forechamber door to closed
_tempVar = 0;
}
void Myst::o_shipAccess_init(uint16 op, uint16 var, uint16 argc, uint16 *argv) {
// Enable acces to the ship
if (_state.shipFloating) {
_invokingResource->setEnabled(true);
}
}
void Myst::o_butterflies_init(uint16 op, uint16 var, uint16 argc, uint16 *argv) {
debugC(kDebugScript, "Opcode %d: Butterflies movie init", op);
// Used for Card 4256 (Butterfly Movie Activation)
if (!_butterfliesMoviePlayed) {
MystResourceType6 *butterflies = static_cast<MystResourceType6 *>(_invokingResource);
butterflies->playMovie();
_butterfliesMoviePlayed = true;
}
}
void Myst::o_imager_init(uint16 op, uint16 var, uint16 argc, uint16 *argv) {
debugC(kDebugScript, "Opcode %d: Imager init", op);
debugC(kDebugScript, "Var: %d", var);
MystResourceType7 *select = static_cast<MystResourceType7 *>(_invokingResource);
_imagerMovie = static_cast<MystResourceType6 *>(select->getSubResource(getVar(var)));
_imagerRunning = true;
}
void Myst::imager_run() {
_imagerRunning = false;
if (_state.imagerActive && _state.imagerSelection == 67) {
VideoHandle water = _imagerMovie->playMovie();
_vm->_video->setVideoBounds(water, Audio::Timestamp(0, 1814, 600), Audio::Timestamp(0, 4204, 600));
_vm->_video->setVideoLooping(water, true);
}
}
void Myst::libraryBookcaseTransform_run(void) {
if (_libraryBookcaseChanged) {
_libraryBookcaseChanged = false;
_libraryBookcaseMoving = false;
_vm->_cursor->hideCursor();
// Play transform sound and video
_vm->_sound->replaceSoundMyst(_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->_sound->playSoundBlocking(7348);
_vm->_sound->replaceBackgroundMyst(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->_sound->playSoundBlocking(7348);
_vm->_sound->replaceBackgroundMyst(4334, 16384);
}
_vm->_cursor->showCursor();
}
}
void Myst::o_libraryBookcaseTransform_init(uint16 op, uint16 var, uint16 argc, uint16 *argv) {
if (_libraryBookcaseChanged) {
MystResourceType7 *resource = static_cast<MystResourceType7 *>(_invokingResource);
_libraryBookcaseMovie = static_cast<MystResourceType6 *>(resource->getSubResource(getVar(0)));
_libraryBookcaseSoundId = argv[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->redrawArea(62);
_vm->redrawArea(63);
_vm->redrawArea(96);
}
}
void Myst::o_generatorControlRoom_init(uint16 op, uint16 var, uint16 argc, uint16 *argv) {
debugC(kDebugScript, "Opcode %d: Generator control room init", op);
_generatorVoltage = _state.generatorVoltage;
_generatorControlRoomRunning = true;
}
void Myst::o_fireplace_init(uint16 op, uint16 var, uint16 argc, uint16 *argv) {
debugC(kDebugScript, "Opcode %d: Fireplace grid init", op);
// Clear fireplace grid
for (uint i = 0; i < 6; i++)
_fireplaceLines[i] = 0;
}
void Myst::o_clockGears_init(uint16 op, uint16 var, uint16 argc, uint16 *argv) {
// Used for Card 4113 (Clock Tower Cog Puzzle)
debugC(kDebugScript, "Opcode %d: Gears puzzle init", op);
// 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 op, uint16 var, uint16 argc, uint16 *argv) {
debugC(kDebugScript, "Opcode %d: Gulls init", op);
if (!_state.shipFloating) {
_gullsNextTime = _vm->_system->getMillis() + 2000;
_gullsFlying1 = true;
}
}
void Myst::gullsFly1_run() {
static const char* gulls[] = { "birds1", "birds2", "birds3" };
uint32 time = _vm->_system->getMillis();
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;
_vm->_video->playMovie(_vm->wrapMovieFilename(gulls[video], kMystStack), x, 0);
_gullsNextTime = time + _vm->_rnd->getRandomNumber(16667) + 13334;
}
}
}
void Myst::o_observatory_init(uint16 op, uint16 var, uint16 argc, uint16 *argv) {
debugC(kDebugScript, "Opcode %d: Stellar observatory init", op);
_tempVar = 0;
_observatoryNotInitialized = true;
_observatoryVisualizer = static_cast<MystResourceType8 *>(_invokingResource);
_observatoryGoButton = static_cast<MystResourceType8 *>(_vm->_resources[argv[0]]);
if (observatoryIsDDMMYYYY2400()) {
_observatoryDaySlider = static_cast<MystResourceType10 *>(_vm->_resources[argv[1]]);
_observatoryMonthSlider = static_cast<MystResourceType10 *>(_vm->_resources[argv[2]]);
} else {
_observatoryMonthSlider = static_cast<MystResourceType10 *>(_vm->_resources[argv[1]]);
_observatoryDaySlider = static_cast<MystResourceType10 *>(_vm->_resources[argv[2]]);
}
_observatoryYearSlider = static_cast<MystResourceType10 *>(_vm->_resources[argv[3]]);
_observatoryTimeSlider = static_cast<MystResourceType10 *>(_vm->_resources[argv[4]]);
// Set date selection sliders position
_observatoryDaySlider->setPosition(_state.observatoryDaySlider);
_observatoryMonthSlider->setPosition(_state.observatoryMonthSlider);
_observatoryYearSlider->setPosition(_state.observatoryYearSlider);
_observatoryTimeSlider->setPosition(_state.observatoryTimeSlider);
_observatoryLastTime = _vm->_system->getMillis();
observatorySetTargetToSetting();
_observatoryRunning = true;
}
bool Myst::observatoryIsDDMMYYYY2400() {
// TODO: Auto-detect based on the month rect position
return !(_vm->getFeatures() & GF_ME) && (_vm->getLanguage() == Common::FR_FRA
|| _vm->getLanguage() == Common::DE_DEU);
}
void Myst::observatoryUpdateVisualizer(uint16 x, uint16 y) {
Common::Rect &visu0 = _observatoryVisualizer->_subImages[0].rect;
Common::Rect &visu1 = _observatoryVisualizer->_subImages[1].rect;
visu0.left = x;
visu0.right = visu0.left + 105;
visu0.bottom = 512 - y;
visu0.top = visu0.bottom - 106;
visu1.left = visu0.left;
visu1.top = visu0.top;
visu1.right = visu0.right;
visu1.bottom = visu0.bottom;
}
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->replaceSoundMyst(8500);
_observatoryDaySlider->drawConditionalDataToScreen(2);
_vm->_system->delayMillis(200);
_vm->redrawResource(_observatoryDaySlider);
_vm->_sound->replaceSoundMyst(8500);
_observatoryMonthSlider->drawConditionalDataToScreen(2);
_vm->_system->delayMillis(200);
_vm->redrawResource(_observatoryMonthSlider);
} else {
_vm->_sound->replaceSoundMyst(8500);
_observatoryMonthSlider->drawConditionalDataToScreen(2);
_vm->_system->delayMillis(200);
_vm->redrawResource(_observatoryMonthSlider);
_vm->_sound->replaceSoundMyst(8500);
_observatoryDaySlider->drawConditionalDataToScreen(2);
_vm->_system->delayMillis(200);
_vm->redrawResource(_observatoryDaySlider);
}
_vm->_sound->replaceSoundMyst(8500);
_observatoryYearSlider->drawConditionalDataToScreen(2);
_vm->_system->delayMillis(200);
_vm->redrawResource(_observatoryYearSlider);
_vm->_sound->replaceSoundMyst(8500);
_observatoryTimeSlider->drawConditionalDataToScreen(2);
_vm->_system->delayMillis(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->_system->getMillis();
if (time > _observatoryLastTime + 250) {
_tempVar = (_tempVar + 1) % 2;
_observatoryGoButton->drawConditionalDataToScreen(_tempVar);
_observatoryLastTime = time;
}
}
}
void Myst::o_gulls2_init(uint16 op, uint16 var, uint16 argc, uint16 *argv) {
debugC(kDebugScript, "Opcode %d: Gulls init", op);
if (!_state.shipFloating) {
_gullsNextTime = _vm->_system->getMillis() + 2000;
_gullsFlying2 = true;
}
}
void Myst::gullsFly2_run() {
static const char* gulls[] = { "birds1", "birds2", "birds3" };
uint32 time = _vm->_system->getMillis();
if (time > _gullsNextTime) {
uint16 video = _vm->_rnd->getRandomNumber(3);
if (video != 3) {
_vm->_video->playMovie(_vm->wrapMovieFilename(gulls[video], kMystStack), 424, 0);
_gullsNextTime = time + _vm->_rnd->getRandomNumber(16667) + 13334;
}
}
}
void Myst::o_treeCard_init(uint16 op, uint16 var, uint16 argc, uint16 *argv) {
debugC(kDebugScript, "Opcode %d: Enter tree card", op);
_tree = static_cast<MystResourceType8 *>(_invokingResource);
}
void Myst::o_treeEntry_init(uint16 op, uint16 var, uint16 argc, uint16 *argv) {
debugC(kDebugScript, "Opcode %d: Enter tree card with entry", op);
_treeAlcove = static_cast<MystResourceType5 *>(_invokingResource);
_treeMinAccessiblePosition = argv[0];
_treeMaxAccessiblePosition = argv[1];
treeSetAlcoveAccessible();
}
void Myst::o_boilerMovies_init(uint16 op, uint16 var, uint16 argc, uint16 *argv) {
debugC(kDebugScript, "Opcode %d: Boiler movies init", op);
boilerFireInit();
boilerGaugeInit();
}
void Myst::boilerFireInit() {
if (_vm->getCurCard() == 4098) {
_cabinFireMovie = _vm->_video->playMovie(_vm->wrapMovieFilename("cabfire", kMystStack), 240, 279, true);
_vm->_video->pauseMovie(_cabinFireMovie, true);
_vm->redrawArea(305);
boilerFireUpdate(true);
} else {
if (_state.cabinPilotLightLit == 1 && _state.cabinValvePosition >= 1) {
_cabinFireMovie = _vm->_video->playMovie(_vm->wrapMovieFilename("cabfirfr", kMystStack), 254, 244, true);
}
}
}
void Myst::boilerFireUpdate(bool init) {
uint position = _vm->_video->getTime(_cabinFireMovie);
if (_state.cabinPilotLightLit == 1) {
if (_state.cabinValvePosition == 0) {
if (position > (uint)Audio::Timestamp(0, 200, 600).msecs() || init) {
_vm->_video->setVideoBounds(_cabinFireMovie, Audio::Timestamp(0, 0, 600), Audio::Timestamp(0, 100, 600));
_vm->_video->pauseMovie(_cabinFireMovie, false);
}
} else {
if (position < (uint)Audio::Timestamp(0, 200, 600).msecs() || init) {
_vm->_video->setVideoBounds(_cabinFireMovie, Audio::Timestamp(0, 201, 600), Audio::Timestamp(0, 1900, 600));
_vm->_video->pauseMovie(_cabinFireMovie, false);
}
}
}
}
void Myst::boilerGaugeInit() {
if (_vm->getCurCard() == 4098) {
_cabinGaugeMovie = _vm->_video->playMovie(_vm->wrapMovieFilename("cabingau", kMystStack), 243, 96);
} else {
_cabinGaugeMovie = _vm->_video->playMovie(_vm->wrapMovieFilename("cabcgfar", kMystStack), 254, 136);
}
Audio::Timestamp frame;
if (_state.cabinPilotLightLit == 1 && _state.cabinValvePosition > 12)
frame = _vm->_video->getDuration(_cabinGaugeMovie);
else
frame = Audio::Timestamp(0, 0, 600);
_vm->_video->drawVideoFrame(_cabinGaugeMovie, frame);
}
void Myst::o_rocketSliders_init(uint16 op, uint16 var, uint16 argc, uint16 *argv) {
debugC(kDebugScript, "Opcode %d: Rocket sliders init", op);
_rocketSlider1 = static_cast<MystResourceType10 *>(_vm->_resources[argv[0]]);
_rocketSlider2 = static_cast<MystResourceType10 *>(_vm->_resources[argv[1]]);
_rocketSlider3 = static_cast<MystResourceType10 *>(_vm->_resources[argv[2]]);
_rocketSlider4 = static_cast<MystResourceType10 *>(_vm->_resources[argv[3]]);
_rocketSlider5 = static_cast<MystResourceType10 *>(_vm->_resources[argv[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 op, uint16 var, uint16 argc, uint16 *argv) {
debugC(kDebugScript, "Opcode %d: Rocket link video init", op);
_tempVar = 0;
}
void Myst::o_greenBook_init(uint16 op, uint16 var, uint16 argc, uint16 *argv) {
// Used for Card 4168 (Green Book Movies)
debugC(kDebugScript, "Opcode %d: Green book init", op);
_greenBookRunning = true;
_tempVar = 1;
}
void Myst::greenBook_run() {
uint loopStart = 0;
uint loopEnd = 0;
Common::String file;
if (!_state.greenBookOpenedBefore) {
loopStart = 113200;
loopEnd = 116400;
file = _vm->wrapMovieFilename("atrusbk1", kMystStack);
} else {
loopStart = 8800;
loopEnd = 9700;
file = _vm->wrapMovieFilename("atrusbk2", kMystStack);
}
if (_tempVar == 1) {
_vm->_sound->stopSound();
_vm->_sound->pauseBackgroundMyst();
if (_globals.ending != 4) {
_tempVar = 2;
_vm->_video->playMovie(file, 314, 76);
} else {
VideoHandle book = _vm->_video->playMovie(file, 314, 76, true);
_vm->_video->setVideoBounds(book, Audio::Timestamp(0, loopStart, 600), Audio::Timestamp(0, loopEnd, 600));
_tempVar = 0;
}
} else if (_tempVar == 2 && !_vm->_video->isVideoPlaying()) {
VideoHandle book = _vm->_video->playMovie(file, 314, 76);
_vm->_video->setVideoBounds(book, Audio::Timestamp(0, loopStart, 600), Audio::Timestamp(0, loopEnd, 600));
_vm->_video->setVideoLooping(book, true);
_tempVar = 0;
}
}
void Myst::o_gulls3_init(uint16 op, uint16 var, uint16 argc, uint16 *argv) {
debugC(kDebugScript, "Opcode %d: Gulls init", op);
if (!_state.shipFloating) {
_gullsNextTime = _vm->_system->getMillis() + 2000;
_gullsFlying3 = true;
}
}
void Myst::gullsFly3_run() {
static const char* gulls[] = { "birds1", "birds2", "birds3" };
uint32 time = _vm->_system->getMillis();
if (time > _gullsNextTime) {
uint16 video = _vm->_rnd->getRandomNumber(3);
if (video != 3) {
uint16 x = _vm->_rnd->getRandomNumber(280) + 135;
_vm->_video->playMovie(_vm->wrapMovieFilename(gulls[video], kMystStack), x, 0);
_gullsNextTime = time + _vm->_rnd->getRandomNumber(16667) + 13334;
}
}
}
void Myst::o_bookAddSpecialPage_exit(uint16 op, uint16 var, uint16 argc, uint16 *argv) {
debugC(kDebugScript, "Opcode %d: Book Exit Function", op);
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 op, uint16 var, uint16 argc, uint16 *argv) {
debugC(kDebugScript, "Opcode %d: Exit tree card", op);
_tree = 0;
}
void Myst::o_treeEntry_exit(uint16 op, uint16 var, uint16 argc, uint16 *argv) {
debugC(kDebugScript, "Opcode %d: Exit tree card with entry", op);
_treeAlcove = 0;
}
void Myst::o_boiler_exit(uint16 op, uint16 var, uint16 argc, uint16 *argv) {
debugC(kDebugScript, "Opcode %d: Exit boiler card", op);
_cabinGaugeMovie = NULL_VID_HANDLE;
_cabinFireMovie = NULL_VID_HANDLE;
}
void Myst::o_generatorControlRoom_exit(uint16 op, uint16 var, uint16 argc, uint16 *argv) {
debugC(kDebugScript, "Opcode %d: Generator room exit", op);
_generatorVoltage = _state.generatorVoltage;
}
} // End of namespace MystStacks
} // End of namespace Mohawk