Initial commit

This commit is contained in:
2026-02-02 04:50:13 +01:00
commit 5b11698731
22592 changed files with 7677434 additions and 0 deletions

View File

@@ -0,0 +1,721 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include "mohawk/cursors.h"
#include "mohawk/myst.h"
#include "mohawk/myst_areas.h"
#include "mohawk/myst_card.h"
#include "mohawk/myst_graphics.h"
#include "mohawk/myst_state.h"
#include "mohawk/myst_sound.h"
#include "mohawk/video.h"
#include "mohawk/myst_stacks/channelwood.h"
#include "common/events.h"
#include "common/system.h"
#include "common/textconsole.h"
namespace Mohawk {
namespace MystStacks {
Channelwood::Channelwood(MohawkEngine_Myst *vm) :
MystScriptParser(vm, kChannelwoodStack),
_state(vm->_gameState->_channelwood),
_valveVar(0),
_siriusDrawerState(0),
_doorOpened(0),
_leverPulled(false),
_leverAction(nullptr) {
setupOpcodes();
}
Channelwood::~Channelwood() {
}
void Channelwood::setupOpcodes() {
// "Stack-Specific" Opcodes
REGISTER_OPCODE(100, Channelwood, o_bridgeToggle);
REGISTER_OPCODE(101, Channelwood, o_pipeExtend);
REGISTER_OPCODE(102, Channelwood, o_drawImageChangeCardAndVolume);
REGISTER_OPCODE(104, Channelwood, o_waterTankValveOpen);
REGISTER_OPCODE(105, Channelwood, o_leverStartMove);
REGISTER_OPCODE(106, Channelwood, o_leverEndMove);
REGISTER_OPCODE(107, Channelwood, o_leverMoveFail);
REGISTER_OPCODE(108, Channelwood, o_leverMove);
REGISTER_OPCODE(109, Channelwood, o_stairsDoorToggle);
REGISTER_OPCODE(110, Channelwood, o_valveHandleMove1);
REGISTER_OPCODE(111, Channelwood, o_valveHandleMoveStart1);
REGISTER_OPCODE(112, Channelwood, o_valveHandleMoveStop);
REGISTER_OPCODE(113, Channelwood, o_valveHandleMove2);
REGISTER_OPCODE(114, Channelwood, o_valveHandleMoveStart2);
REGISTER_OPCODE(115, Channelwood, o_valveHandleMove3);
REGISTER_OPCODE(116, Channelwood, o_valveHandleMoveStart3);
REGISTER_OPCODE(117, Channelwood, o_hologramMonitor);
REGISTER_OPCODE(118, Channelwood, o_drawerOpen);
REGISTER_OPCODE(119, Channelwood, o_hologramTemple);
REGISTER_OPCODE(120, Channelwood, o_leverElev3StartMove);
REGISTER_OPCODE(121, Channelwood, o_leverElev3EndMove);
REGISTER_OPCODE(122, Channelwood, o_waterTankValveClose);
REGISTER_OPCODE(123, Channelwood, o_executeMouseUp);
REGISTER_OPCODE(124, Channelwood, o_leverEndMoveWithSound);
REGISTER_OPCODE(125, Channelwood, o_pumpLeverMove);
REGISTER_OPCODE(126, Channelwood, o_pumpLeverEndMove);
REGISTER_OPCODE(127, Channelwood, o_elevatorMovies);
REGISTER_OPCODE(128, Channelwood, o_leverEndMoveResumeBackground);
REGISTER_OPCODE(129, Channelwood, o_soundReplace);
// "Init" Opcodes
REGISTER_OPCODE(201, Channelwood, o_lever_init);
REGISTER_OPCODE(202, Channelwood, o_pipeValve_init);
REGISTER_OPCODE(203, Channelwood, o_drawer_init);
// "Exit" Opcodes
REGISTER_OPCODE(300, Channelwood, NOP);
}
void Channelwood::disablePersistentScripts() {
}
void Channelwood::runPersistentScripts() {
}
uint16 Channelwood::getVar(uint16 var) {
switch(var) {
case 1: // Water Pump Bridge Raised
return _state.waterPumpBridgeState;
case 2: // Lower Walkway to Upper Walkway Elevator Raised
return _state.elevatorState;
case 3: // Water Flowing To Lower Walkway To Upper Walkway Elevator
return (_state.waterValveStates & 0xc0) == 0xc0;
case 4: // Water Flowing To Book Room Elevator
return ((_state.waterValveStates & 0xf8) == 0xb0 && _state.pipeState) ? 1 : 0;
case 5: // Lower Walkway to Upper Walkway Spiral Stair Lower Door State
return _state.stairsLowerDoorState;
case 6: // Pipe Bridge Extended
return _state.pipeState;
case 7: // Water Flowing To Water Pump For Bridge
return ((_state.waterValveStates & 0xe2) == 0x82 || (_state.waterValveStates & 0xf4) == 0xa0) ? 1 : 0;
case 8: // Water Tank Valve
return (_state.waterValveStates & 0x80) ? 1 : 0;
case 9: // State of First Water Valve
return (_state.waterValveStates & 0x40) ? 1 : 0;
case 10: // State of Second Water Valve
return (_state.waterValveStates & 0x20) ? 1 : 0;
case 11: // State of Right Third Water Valve
return (_state.waterValveStates & 0x10) ? 1 : 0;
case 12: // State of Right-Right Fourth Water Valve
return (_state.waterValveStates & 0x08) ? 1 : 0;
case 13: // State of Right-Left Fourth Water Valve
return (_state.waterValveStates & 0x04) ? 1 : 0;
case 14: // State of Left Third Water Valve
return (_state.waterValveStates & 0x02) ? 1 : 0;
case 15: // Water Flowing To Lower Walkway To Upper Walkway Elevator
return ((_state.waterValveStates & 0xf8) == 0xb8) ? 1 : 0;
case 16: // Channelwood Lower Walkway to Upper Walkway Spiral Stair Upper Door State
return _state.stairsUpperDoorState;
case 17: // Achenar's Holoprojector Selection
return _state.holoprojectorSelection;
case 18: // Sirrus's Room Bed Drawer Open
return _siriusDrawerState;
case 19: // Sound - Water Tank Valve
return (_state.waterValveStates & 0x80) ? 1 : 0;
case 20: // Sound - First Water Valve Water Flowing To Left
return ((_state.waterValveStates & 0xc0) == 0x80) ? 1 : 0;
case 21: // Sound - Second Water Valve Water Flowing To Right
return ((_state.waterValveStates & 0xe0) == 0xa0) ? 1 : 0;
case 22: // Sound - Right Third Water Valve Water Flowing To Right
return ((_state.waterValveStates & 0xf0) == 0xb0) ? 1 : 0;
case 23: // Sound - Right Third Water Valve Water Flowing To Left
return ((_state.waterValveStates & 0xf0) == 0xa0) ? 1 : 0;
case 24: // Sound - Second Water Valve Water Flowing To Left
return ((_state.waterValveStates & 0xe0) == 0x80) ? 1 : 0;
case 25: // Sound - Right-Right Fourth Valve Water Flowing To Left (To Pipe Bridge)
return ((_state.waterValveStates & 0xf8) == 0xb0) ? 1 : 0;
case 26: // Sound - Right-Left Fourth Valve Water Flowing To Right (To Pipe Down Tree)
return ((_state.waterValveStates & 0xf4) == 0xa4) ? 1 : 0;
case 27: // Sound - Right-Left Fourth Valve Water Flowing To Left (To Pipe Fork)
return ((_state.waterValveStates & 0xf4) == 0xa0) ? 1 : 0;
case 28: // Sound - Left Third Water Valve Flowing To Right (To Pipe Fork)
return ((_state.waterValveStates & 0xe2) == 0x82) ? 1 : 0;
case 29: // Sound - Left Third Water Valve Flowing To Left (To Pipe In Water)
return ((_state.waterValveStates & 0xe2) == 0x80) ? 1 : 0;
case 30: // Door State
return _doorOpened;
case 31: // Water flowing in pipe fork ?
// 0 -> keep sound.
// 1 -> not flowing.
// 2 --> flowing.
if ((_state.waterValveStates & 0xe2) == 0x82) // From left.
return 2;
if ((_state.waterValveStates & 0xf4) == 0xa0) // From right.
return 1;
return 0;
case 32: // Sound - Water Flowing in Pipe to Book Room Elevator
if ((_state.waterValveStates & 0xf8) == 0xb0)
return _state.pipeState ? 2 : 1;
return 0;
case 33: // Channelwood Lower Walkway to Upper Walkway Spiral Stair Upper Door State
if (_state.stairsUpperDoorState) {
if (_tempVar == 1)
return 2;
else
return 1;
} else {
return 0;
}
case 102: // Sirrus's Desk Drawer / Red Page State
if (_siriusDrawerState) {
if(!(_globals.redPagesInBook & 16) && (_globals.heldPage != kRedChannelwoodPage))
return 2; // Drawer Open, Red Page Present
else
return 1; // Drawer Open, Red Page Taken
} else {
return 0; // Drawer Closed
}
case 103: // Blue Page Present
return !(_globals.bluePagesInBook & 16) && (_globals.heldPage != kBlueChannelwoodPage);
default:
return MystScriptParser::getVar(var);
}
}
void Channelwood::toggleVar(uint16 var) {
switch(var) {
case 1: // Water Pump Bridge Raised
_state.waterPumpBridgeState ^= 1;
break;
case 6: // Pipe Bridge Extended
_state.pipeState ^= 1;
break;
case 16: // Channelwood Lower Walkway to Upper Walkway Spiral Stair Upper Door State
_state.stairsUpperDoorState ^= 1;
break;
case 102: // Red page
if (!(_globals.redPagesInBook & 16)) {
if (_globals.heldPage == kRedChannelwoodPage)
_globals.heldPage = kNoPage;
else
_globals.heldPage = kRedChannelwoodPage;
}
break;
case 103: // Blue page
if (!(_globals.bluePagesInBook & 16)) {
if (_globals.heldPage == kBlueChannelwoodPage)
_globals.heldPage = kNoPage;
else
_globals.heldPage = kBlueChannelwoodPage;
}
break;
default:
MystScriptParser::toggleVar(var);
break;
}
}
bool Channelwood::setVarValue(uint16 var, uint16 value) {
bool refresh = false;
switch (var) {
case 2: // Lower Walkway to Upper Walkway Elevator Raised
if (_state.elevatorState != value) {
_state.elevatorState = value;
refresh = true;
}
break;
case 5: // Lower Walkway to Upper Walkway Spiral Stair Lower Door State
if (_state.stairsLowerDoorState != value) {
_state.stairsLowerDoorState = value;
refresh = true;
}
break;
case 9:
refresh = pipeChangeValve(value, 0x40);
break;
case 10:
refresh = pipeChangeValve(value, 0x20);
break;
case 11:
refresh = pipeChangeValve(value, 0x10);
break;
case 12:
refresh = pipeChangeValve(value, 0x08);
break;
case 13:
refresh = pipeChangeValve(value, 0x04);
break;
case 14:
refresh = pipeChangeValve(value, 0x02);
break;
case 18: // Sirrus's Room Bed Drawer Open
if (_siriusDrawerState != value) {
_siriusDrawerState = value;
refresh = true;
}
break;
case 30: // Door opened
_doorOpened = value;
break;
default:
refresh = MystScriptParser::setVarValue(var, value);
break;
}
return refresh;
}
bool Channelwood::pipeChangeValve(bool open, uint16 mask) {
if (open) {
if (!(_state.waterValveStates & mask)) {
_state.waterValveStates |= mask;
return true;
}
} else {
if (_state.waterValveStates & mask) {
_state.waterValveStates &= ~mask;
return true;
}
}
return false;
}
void Channelwood::o_bridgeToggle(uint16 var, const ArgumentsArray &args) {
VideoEntryPtr bridge = _vm->playMovie("bridge", kChannelwoodStack);
bridge->moveTo(292, 203);
// Toggle bridge state
if (_state.waterPumpBridgeState)
bridge->setBounds(Audio::Timestamp(0, 3050, 600), Audio::Timestamp(0, 6100, 600));
else
bridge->setBounds(Audio::Timestamp(0, 0, 600), Audio::Timestamp(0, 3050, 600));
_vm->waitUntilMovieEnds(bridge);
}
void Channelwood::o_pipeExtend(uint16 var, const ArgumentsArray &args) {
uint16 soundId = args[0];
debugC(kDebugScript, "\tsoundId: %d", soundId);
_vm->_sound->playEffect(soundId);
VideoEntryPtr pipe = _vm->playMovie("pipebrid", kChannelwoodStack);
pipe->moveTo(267, 170);
// Toggle pipe state
if (_state.pipeState)
pipe->setBounds(Audio::Timestamp(0, 3040, 600), Audio::Timestamp(0, 6080, 600));
else
pipe->setBounds(Audio::Timestamp(0, 0, 600), Audio::Timestamp(0, 3040, 600));
_vm->waitUntilMovieEnds(pipe);
_vm->_sound->resumeBackground();
}
void Channelwood::o_drawImageChangeCardAndVolume(uint16 var, const ArgumentsArray &args) {
uint16 imageId = args[0];
uint16 cardId = args[1];
uint16 volume = args.size() == 3 ? args[2] : 0;
debugC(kDebugScript, "\timageId: %d", imageId);
debugC(kDebugScript, "\tcardId: %d", cardId);
_vm->_gfx->copyImageToScreen(imageId, Common::Rect(0, 0, 544, 333));
_vm->wait(200);
_vm->changeToCard(cardId, kTransitionPartToLeft);
if (volume) {
_vm->_sound->changeBackgroundVolume(volume);
}
}
void Channelwood::o_waterTankValveOpen(uint16 var, const ArgumentsArray &args) {
Common::Rect rect = getInvokingResource<MystArea>()->getRect();
for (uint i = 0; i < 2; i++)
for (uint16 imageId = 3601; imageId >= 3595; imageId--) {
_vm->_gfx->copyImageToScreen(imageId, rect);
_vm->doFrame();
}
pipeChangeValve(true, 0x80);
}
void Channelwood::o_leverStartMove(uint16 var, const ArgumentsArray &args) {
MystVideoInfo *lever = getInvokingResource<MystVideoInfo>();
lever->drawFrame(0);
_vm->_cursor->setCursor(700);
_leverPulled = false;
}
void Channelwood::o_leverMove(uint16 var, const ArgumentsArray &args) {
MystVideoInfo *lever = getInvokingResource<MystVideoInfo>();
if (lever->pullLeverV()) {
if (!_leverPulled) {
_leverPulled = true;
_leverAction->handleMouseUp();
}
} else {
_leverPulled = false;
}
}
void Channelwood::o_leverMoveFail(uint16 var, const ArgumentsArray &args) {
MystVideoInfo *lever = getInvokingResource<MystVideoInfo>();
if (lever->pullLeverV()) {
if (!_leverPulled) {
_leverPulled = true;
uint16 soundId = lever->getList2(0);
if (soundId)
_vm->_sound->playEffect(soundId);
}
} else {
_leverPulled = false;
}
}
void Channelwood::o_leverEndMove(uint16 var, const ArgumentsArray &args) {
// Get current lever frame
MystVideoInfo *lever = getInvokingResource<MystVideoInfo>();
// Release lever
lever->releaseLeverV();
uint16 soundId = lever->getList3(0);
if (soundId)
_vm->_sound->playEffect(soundId);
_vm->refreshCursor();
}
void Channelwood::o_leverEndMoveResumeBackground(uint16 var, const ArgumentsArray &args) {
_vm->_sound->resumeBackground();
o_leverEndMove(var, args);
}
void Channelwood::o_leverEndMoveWithSound(uint16 var, const ArgumentsArray &args) {
o_leverEndMove(var, args);
MystVideoInfo *lever = getInvokingResource<MystVideoInfo>();
uint16 soundId = lever->getList3(0);
if (soundId)
_vm->_sound->playEffect(soundId);
}
void Channelwood::o_leverElev3StartMove(uint16 var, const ArgumentsArray &args) {
_vm->_gfx->copyImageToScreen(3970, Common::Rect(544, 333));
_vm->doFrame();
o_leverStartMove(var, args);
}
void Channelwood::o_leverElev3EndMove(uint16 var, const ArgumentsArray &args) {
o_leverEndMove(var, args);
_vm->_gfx->copyImageToScreen(3265, Common::Rect(544, 333));
_vm->doFrame();
_vm->_sound->playEffect(5265);
}
void Channelwood::o_pumpLeverMove(uint16 var, const ArgumentsArray &args) {
MystVideoInfo *lever = getInvokingResource<MystVideoInfo>();
if (lever->pullLeverV()) {
uint16 soundId = lever->getList2(0);
_vm->_sound->playBackground(soundId, 38400);
} else {
uint16 soundId = lever->getList2(1);
_vm->_sound->playBackground(soundId, 36864);
}
}
void Channelwood::o_pumpLeverEndMove(uint16 var, const ArgumentsArray &args) {
o_leverEndMove(var, args);
MystVideoInfo *lever = getInvokingResource<MystVideoInfo>();
uint16 soundId = lever->getList3(0);
if (soundId)
_vm->_sound->playBackground(soundId, 36864);
}
void Channelwood::o_stairsDoorToggle(uint16 var, const ArgumentsArray &args) {
MystAreaVideo *movie = getInvokingResource<MystAreaVideo>();
if (_state.stairsUpperDoorState) {
// Close door, play the open movie backwards
movie->setDirection(-1);
movie->playMovie();
} else {
// Open door
movie->setDirection(1);
movie->playMovie();
}
}
void Channelwood::o_valveHandleMove1(uint16 var, const ArgumentsArray &args) {
MystVideoInfo *handle = getInvokingResource<MystVideoInfo>();
const Common::Point &mouse = _vm->_system->getEventManager()->getMousePos();
if (handle->getRect().contains(mouse)) {
// Compute frame to draw
_tempVar = (mouse.x - 250) / 4;
_tempVar = CLIP<int16>(_tempVar, 1, handle->getStepsH() - 2);
// Draw frame
handle->drawFrame(_tempVar);
}
}
void Channelwood::o_valveHandleMoveStart1(uint16 var, const ArgumentsArray &args) {
MystVideoInfo *handle = getInvokingResource<MystVideoInfo>();
uint16 soundId = handle->getList1(0);
if (soundId)
_vm->_sound->playEffect(soundId);
_vm->_cursor->setCursor(700);
o_valveHandleMove1(var, args);
}
void Channelwood::o_valveHandleMoveStop(uint16 var, const ArgumentsArray &args) {
MystVideoInfo *handle = getInvokingResource<MystVideoInfo>();
// Update state with valve position
if (_tempVar <= 5)
setVarValue(_valveVar, 1);
else
setVarValue(_valveVar, 0);
// Play release sound
uint16 soundId = handle->getList3(0);
if (soundId)
_vm->_sound->playEffect(soundId);
// Redraw valve
_vm->getCard()->redrawArea(_valveVar);
// Restore cursor
_vm->refreshCursor();
}
void Channelwood::o_valveHandleMove2(uint16 var, const ArgumentsArray &args) {
MystVideoInfo *handle = getInvokingResource<MystVideoInfo>();
const Common::Point &mouse = _vm->_system->getEventManager()->getMousePos();
if (handle->getRect().contains(mouse)) {
// Compute frame to draw
_tempVar = handle->getStepsH() - (mouse.x - 234) / 4;
_tempVar = CLIP<int16>(_tempVar, 1, handle->getStepsH() - 2);
// Draw frame
handle->drawFrame(_tempVar);
}
}
void Channelwood::o_valveHandleMoveStart2(uint16 var, const ArgumentsArray &args) {
MystVideoInfo *handle = getInvokingResource<MystVideoInfo>();
uint16 soundId = handle->getList1(0);
if (soundId)
_vm->_sound->playEffect(soundId);
_vm->_cursor->setCursor(700);
o_valveHandleMove2(var, args);
}
void Channelwood::o_valveHandleMove3(uint16 var, const ArgumentsArray &args) {
MystVideoInfo *handle = getInvokingResource<MystVideoInfo>();
const Common::Point &mouse = _vm->_system->getEventManager()->getMousePos();
if (handle->getRect().contains(mouse)) {
// Compute frame to draw
_tempVar = handle->getStepsH() - (mouse.x - 250) / 4;
_tempVar = CLIP<int16>(_tempVar, 1, handle->getStepsH() - 2);
// Draw frame
handle->drawFrame(_tempVar);
}
}
void Channelwood::o_valveHandleMoveStart3(uint16 var, const ArgumentsArray &args) {
MystVideoInfo *handle = getInvokingResource<MystVideoInfo>();
uint16 soundId = handle->getList1(0);
if (soundId)
_vm->_sound->playEffect(soundId);
_vm->_cursor->setCursor(700);
o_valveHandleMove3(var, args);
}
void Channelwood::o_hologramMonitor(uint16 var, const ArgumentsArray &args) {
// Used on Card 3012 (Temple Hologram Monitor)
uint16 button = args[0]; // 0 to 3
if (_state.holoprojectorSelection != button || !_vm->_video->isVideoPlaying()) {
_state.holoprojectorSelection = button;
_vm->getCard()->redrawArea(17);
_vm->_video->stopVideos();
VideoEntryPtr video;
switch (button) {
case 0:
video = _vm->playMovie("monalgh", kChannelwoodStack);
video->moveTo(227, 70);
break;
case 1:
video = _vm->playMovie("monamth", kChannelwoodStack);
video->moveTo(227, 70);
break;
case 2:
video = _vm->playMovie("monasirs", kChannelwoodStack);
video->moveTo(227, 70);
break;
case 3:
video = _vm->playMovie("monsmsg", kChannelwoodStack);
video->moveTo(226, 68);
break;
default:
warning("Opcode o_hologramMonitor Control Variable Out of Range");
break;
}
}
}
void Channelwood::o_drawerOpen(uint16 var, const ArgumentsArray &args) {
_siriusDrawerState = 1;
_vm->getCard()->redrawArea(18, false);
_vm->getCard()->redrawArea(102, false);
}
void Channelwood::o_hologramTemple(uint16 var, const ArgumentsArray &args) {
_vm->_sound->pauseBackground();
// Used on Card 3333 (Temple Hologram)
switch (_state.holoprojectorSelection) {
case 0:
_vm->playMovieBlocking("holoalgh", kChannelwoodStack, 139, 64);
break;
case 1:
_vm->playMovieBlocking("holoamth", kChannelwoodStack, 127, 73);
break;
case 2:
_vm->playMovieBlocking("holoasir", kChannelwoodStack, 139, 64);
break;
case 3:
_vm->playMovieBlocking("holosmsg", kChannelwoodStack, 127, 45);
break;
default:
warning("Opcode o_hologramTemple Control Variable Out of Range");
break;
}
_vm->_sound->resumeBackground();
}
void Channelwood::o_executeMouseUp(uint16 var, const ArgumentsArray &args) {
// Clear the clicked resource so the mouse up event is not called a second time.
_vm->getCard()->resetClickedResource();
MystArea *resource = _vm->getCard()->getResource<MystArea>(args[0]);
resource->handleMouseUp();
}
void Channelwood::o_waterTankValveClose(uint16 var, const ArgumentsArray &args) {
Common::Rect rect = getInvokingResource<MystArea>()->getRect();
for (uint i = 0; i < 2; i++)
for (uint16 imageId = 3595; imageId <= 3601; imageId++) {
_vm->_gfx->copyImageToScreen(imageId, rect);
_vm->doFrame();
}
pipeChangeValve(false, 0x80);
}
void Channelwood::o_elevatorMovies(uint16 var, const ArgumentsArray &args) {
// Used by Card 3262 (Elevator)
uint16 elevator = args[0];
uint16 direction = args[1];
Common::String movie;
uint16 x;
uint16 y;
switch (elevator) {
case 1:
x = 214;
y = 106;
if (direction == 1)
movie = "welev1up";
else
movie = "welev1dn";
break;
case 2:
x = 215;
y = 117;
if (direction == 1)
movie = "welev2up";
else
movie = "welev2dn";
break;
case 3:
x = 213;
y = 98;
if (direction == 1)
movie = "welev3up";
else
movie = "welev3dn";
break;
default:
error("Unknown elevator state %d in o_elevatorMovies", elevator);
}
_vm->_sound->pauseBackground();
_vm->playMovieBlocking(movie, kChannelwoodStack, x, y);
_vm->_sound->resumeBackground();
}
void Channelwood::o_soundReplace(uint16 var, const ArgumentsArray &args) {
uint16 soundId = args[0];
if (!_vm->_sound->isEffectPlaying()) {
_vm->_sound->playEffect(soundId);
}
}
void Channelwood::o_lever_init(uint16 var, const ArgumentsArray &args) {
_leverAction = getInvokingResource<MystArea>();
}
void Channelwood::o_pipeValve_init(uint16 var, const ArgumentsArray &args) {
_valveVar = var;
}
void Channelwood::o_drawer_init(uint16 var, const ArgumentsArray &args) {
_siriusDrawerState = 0;
}
} // End of namespace MystStacks
} // End of namespace Mohawk

View File

@@ -0,0 +1,106 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef MYST_SCRIPTS_CHANNELWOOD_H
#define MYST_SCRIPTS_CHANNELWOOD_H
#include "common/scummsys.h"
#include "common/util.h"
#include "mohawk/myst_scripts.h"
namespace Mohawk {
struct MystScriptEntry;
namespace MystStacks {
#define DECLARE_OPCODE(x) void x(uint16 var, const ArgumentsArray &args)
class Channelwood : public MystScriptParser {
public:
explicit Channelwood(MohawkEngine_Myst *vm);
~Channelwood() override;
void disablePersistentScripts() override;
void runPersistentScripts() override;
private:
void setupOpcodes();
uint16 getVar(uint16 var) override;
void toggleVar(uint16 var) override;
bool setVarValue(uint16 var, uint16 value) override;
uint16 getMap() override { return 9932; }
DECLARE_OPCODE(o_bridgeToggle);
DECLARE_OPCODE(o_pipeExtend);
DECLARE_OPCODE(o_drawImageChangeCardAndVolume);
DECLARE_OPCODE(o_waterTankValveOpen);
DECLARE_OPCODE(o_leverStartMove);
DECLARE_OPCODE(o_leverMove);
DECLARE_OPCODE(o_leverMoveFail);
DECLARE_OPCODE(o_leverEndMove);
DECLARE_OPCODE(o_leverEndMoveResumeBackground);
DECLARE_OPCODE(o_leverEndMoveWithSound);
DECLARE_OPCODE(o_leverElev3StartMove);
DECLARE_OPCODE(o_leverElev3EndMove);
DECLARE_OPCODE(o_pumpLeverMove);
DECLARE_OPCODE(o_pumpLeverEndMove);
DECLARE_OPCODE(o_stairsDoorToggle);
DECLARE_OPCODE(o_valveHandleMove1);
DECLARE_OPCODE(o_valveHandleMoveStart1);
DECLARE_OPCODE(o_valveHandleMoveStop);
DECLARE_OPCODE(o_valveHandleMove2);
DECLARE_OPCODE(o_valveHandleMoveStart2);
DECLARE_OPCODE(o_valveHandleMove3);
DECLARE_OPCODE(o_valveHandleMoveStart3);
DECLARE_OPCODE(o_hologramMonitor);
DECLARE_OPCODE(o_drawerOpen);
DECLARE_OPCODE(o_hologramTemple);
DECLARE_OPCODE(o_executeMouseUp);
DECLARE_OPCODE(o_waterTankValveClose);
DECLARE_OPCODE(o_elevatorMovies);
DECLARE_OPCODE(o_soundReplace);
DECLARE_OPCODE(o_lever_init);
DECLARE_OPCODE(o_pipeValve_init);
DECLARE_OPCODE(o_drawer_init);
MystGameState::Channelwood &_state;
uint16 _valveVar; // 64
uint16 _siriusDrawerState; // 66
uint16 _doorOpened; // 68
bool _leverPulled;
MystArea *_leverAction; // 72
bool pipeChangeValve(bool open, uint16 mask);
};
} // End of namespace MystStacks
} // End of namespace Mohawk
#undef DECLARE_OPCODE
#endif

View File

@@ -0,0 +1,104 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include "mohawk/myst.h"
#include "mohawk/myst_areas.h"
#include "mohawk/myst_card.h"
#include "mohawk/myst_graphics.h"
#include "mohawk/cursors.h"
#include "mohawk/sound.h"
#include "mohawk/video.h"
#include "mohawk/myst_stacks/credits.h"
#include "common/system.h"
namespace Mohawk {
namespace MystStacks {
// NOTE: Credits Start Card is 10000
Credits::Credits(MohawkEngine_Myst *vm) :
MystScriptParser(vm, kCreditsStack),
_creditsRunning(false),
_curImage(0) {
setupOpcodes();
}
Credits::~Credits() {
}
void Credits::setupOpcodes() {
// "Stack-Specific" Opcodes
REGISTER_OPCODE(100, Credits, o_quit);
// "Init" Opcodes
REGISTER_OPCODE(200, Credits, o_runCredits);
}
void Credits::disablePersistentScripts() {
_creditsRunning = false;
}
void Credits::runPersistentScripts() {
if (!_creditsRunning)
return;
if (_vm->getTotalPlayTime() - _startTime >= 7 * 1000) {
_curImage++;
// After the 6th image has shown, it's time to quit
if (_curImage == 7) {
_vm->quitGame();
return;
}
// Draw next image
_vm->getCard()->drawBackground();
_vm->_gfx->copyBackBufferToScreen(Common::Rect(544, 333));
_startTime = _vm->getTotalPlayTime();
}
}
uint16 Credits::getVar(uint16 var) {
switch(var) {
case 0: // Credits Image Control
return _curImage;
case 1: // Credits Music Control (Good / bad ending)
return _globals.ending != kBooksDestroyed;
default:
return MystScriptParser::getVar(var);
}
}
void Credits::o_runCredits(uint16 var, const ArgumentsArray &args) {
// The credits stack does not have all the cursors, reset to the default cursor.
_globals.heldPage = kNoPage;
_vm->setMainCursor(kDefaultMystCursor);
// Activate the credits
_creditsRunning = true;
_curImage = 0;
_startTime = _vm->getTotalPlayTime();
}
} // End of namespace MystStacks
} // End of namespace Mohawk

View File

@@ -0,0 +1,60 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef MYST_SCRIPTS_CREDITS_H
#define MYST_SCRIPTS_CREDITS_H
#include "common/scummsys.h"
#include "common/util.h"
#include "mohawk/myst_scripts.h"
namespace Mohawk {
struct MystScriptEntry;
namespace MystStacks {
#define DECLARE_OPCODE(x) void x(uint16 var, const ArgumentsArray &args)
class Credits : public MystScriptParser {
public:
explicit Credits(MohawkEngine_Myst *vm);
~Credits() override;
void disablePersistentScripts() override;
void runPersistentScripts() override;
private:
void setupOpcodes();
uint16 getVar(uint16 var) override;
DECLARE_OPCODE(o_runCredits);
bool _creditsRunning;
uint16 _curImage; // 56
};
} // End of namespace MystStacks
} // End of namespace Mohawk
#undef DECLARE_OPCODE
#endif

View File

@@ -0,0 +1,116 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include "mohawk/cursors.h"
#include "mohawk/myst.h"
#include "mohawk/myst_graphics.h"
#include "mohawk/myst_stacks/demo.h"
#include "common/system.h"
namespace Mohawk {
namespace MystStacks {
Demo::Demo(MohawkEngine_Myst *vm) :
Intro(vm, kDemoStack),
_returnToMenuRunning(false),
_returnToMenuStep(0),
_returnToMenuNextTime(0) {
setupOpcodes();
}
Demo::~Demo() {
}
void Demo::setupOpcodes() {
// "Stack-Specific" Opcodes
OVERRIDE_OPCODE(100, Demo, o_stopIntro);
REGISTER_OPCODE(101, Demo, o_fadeFromBlack);
REGISTER_OPCODE(102, Demo, o_fadeToBlack);
// "Init" Opcodes
OVERRIDE_OPCODE(201, Demo, o_returnToMenu_init);
}
void Demo::disablePersistentScripts() {
Intro::disablePersistentScripts();
_returnToMenuRunning = false;
}
void Demo::runPersistentScripts() {
Intro::runPersistentScripts();
if (_returnToMenuRunning) {
returnToMenu_run();
}
}
void Demo::o_stopIntro(uint16 var, const ArgumentsArray &args) {
// The original also seems to stop the movies. Not needed with this engine.
_vm->_gfx->fadeToBlack();
}
void Demo::o_fadeFromBlack(uint16 var, const ArgumentsArray &args) {
// FIXME: This glitches when enabled. The backbuffer is drawn to screen,
// and then the fading occurs, causing the background to appear for one frame.
// _vm->_gfx->fadeFromBlack();
}
void Demo::o_fadeToBlack(uint16 var, const ArgumentsArray &args) {
_vm->_gfx->fadeToBlack();
}
void Demo::returnToMenu_run() {
uint32 time = _vm->getTotalPlayTime();
if (time < _returnToMenuNextTime)
return;
switch (_returnToMenuStep) {
case 0:
_vm->_gfx->fadeToBlack();
_vm->changeToCard(2003, kNoTransition);
_vm->_gfx->fadeFromBlack();
_returnToMenuStep++;
break;
case 1:
_vm->_gfx->fadeToBlack();
_vm->changeToCard(2001, kNoTransition);
_vm->_gfx->fadeFromBlack();
_vm->_cursor->showCursor();
_returnToMenuStep++;
break;
default:
break;
}
}
void Demo::o_returnToMenu_init(uint16 var, const ArgumentsArray &args) {
// Used on Card 2001, 2002 and 2003
_returnToMenuNextTime = _vm->getTotalPlayTime() + 5000;
_returnToMenuRunning = true;
}
} // End of namespace MystStacks
} // End of namespace Mohawk

View File

@@ -0,0 +1,66 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef MYST_SCRIPTS_DEMO_H
#define MYST_SCRIPTS_DEMO_H
#include "common/scummsys.h"
#include "common/util.h"
#include "mohawk/myst_stacks/intro.h"
namespace Mohawk {
struct MystScriptEntry;
namespace MystStacks {
#define DECLARE_OPCODE(x) void x(uint16 var, const ArgumentsArray &args)
class Demo : public Intro {
public:
explicit Demo(MohawkEngine_Myst *vm);
~Demo() override;
void disablePersistentScripts() override;
void runPersistentScripts() override;
private:
void setupOpcodes();
DECLARE_OPCODE(o_stopIntro);
DECLARE_OPCODE(o_fadeFromBlack);
DECLARE_OPCODE(o_fadeToBlack);
DECLARE_OPCODE(o_returnToMenu_init);
bool _returnToMenuRunning;
uint16 _returnToMenuStep; // 42
uint32 _returnToMenuNextTime; // 6
void returnToMenu_run();
};
} // End of namespace MystStacks
} // End of namespace Mohawk
#undef DECLARE_OPCODE
#endif

View File

@@ -0,0 +1,210 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include "mohawk/myst.h"
#include "mohawk/cursors.h"
#include "mohawk/graphics.h"
#include "mohawk/myst_areas.h"
#include "mohawk/sound.h"
#include "mohawk/video.h"
#include "mohawk/myst_stacks/dni.h"
#include "common/system.h"
namespace Mohawk {
namespace MystStacks {
Dni::Dni(MohawkEngine_Myst *vm) :
MystScriptParser(vm, kDniStack),
_notSeenAtrus(true),
_atrusRunning(false),
_waitForLoop(false),
_atrusLeft(false),
_atrusLeftTime(0),
_loopStart(0),
_loopEnd(0) {
setupOpcodes();
}
Dni::~Dni() {
}
void Dni::setupOpcodes() {
// "Stack-Specific" Opcodes
REGISTER_OPCODE(100, Dni, NOP);
REGISTER_OPCODE(101, Dni, o_handPage);
// "Init" Opcodes
REGISTER_OPCODE(200, Dni, o_atrus_init);
// "Exit" Opcodes
REGISTER_OPCODE(300, Dni, NOP);
}
void Dni::disablePersistentScripts() {
_atrusRunning = false;
_waitForLoop = false;
_atrusLeft = false;
}
void Dni::runPersistentScripts() {
if (_atrusRunning)
atrus_run();
if (_waitForLoop)
loopVideo_run();
if (_atrusLeft)
atrusLeft_run();
}
uint16 Dni::getVar(uint16 var) {
switch(var) {
case 0: // Atrus Gone (from across room)
return _globals.ending == kAtrusLeaves;
case 1: // Myst Book Status
if (_globals.ending != kBooksDestroyed)
return _globals.ending == kForgotPage;
else
return 2; // Linkable
case 2: // Music Type
if (_notSeenAtrus) {
_notSeenAtrus = false;
return _globals.ending != kBooksDestroyed && _globals.heldPage != kWhitePage;
} else
return 2;
default:
return MystScriptParser::getVar(var);
}
}
void Dni::o_handPage(uint16 var, const ArgumentsArray &args) {
// Used in Card 5014 (Atrus)
// Find Atrus movie
VideoEntryPtr atrus = _vm->findVideo(_video, kDniStack);
// Good ending and Atrus asked to give page
if (_globals.ending == kAtrusWantsPage && atrus && atrus->getTime() > (uint)Audio::Timestamp(0, 6801, 600).msecs()) {
_globals.ending = kAtrusLeaves;
_globals.heldPage = kNoPage;
_vm->setMainCursor(kDefaultMystCursor);
// Play movie end (atrus leaving)
atrus->setBounds(Audio::Timestamp(0, 14813, 600), atrus->getDuration());
atrus->setLooping(false);
_atrusLeft = true;
_waitForLoop = false;
_atrusLeftTime = _vm->getTotalPlayTime();
}
}
void Dni::atrusLeft_run() {
if (_vm->getTotalPlayTime() > _atrusLeftTime + 63333) {
_video = "atrus2";
_videoPos = Common::Point(215, 77);
VideoEntryPtr atrus = _vm->playMovie(_video, kDniStack);
atrus->moveTo(_videoPos.x, _videoPos.y);
atrus->setBounds(Audio::Timestamp(0, 0, 600), Audio::Timestamp(0, 98000, 600));
_atrusRunning = false;
_waitForLoop = true;
_loopStart = 73095;
_loopEnd = 98000;
// Good ending
_globals.ending = kBooksDestroyed;
_globals.bluePagesInBook = 63;
_globals.redPagesInBook = 63;
_atrusLeft = false;
}
}
void Dni::loopVideo_run() {
if (!_vm->_video->isVideoPlaying()) {
VideoEntryPtr atrus = _vm->playMovie(_video, kDniStack);
atrus->moveTo(_videoPos.x, _videoPos.y);
atrus->setBounds(Audio::Timestamp(0, _loopStart, 600), Audio::Timestamp(0, _loopEnd, 600));
atrus->setLooping(true);
_waitForLoop = false;
}
}
void Dni::atrus_run() {
if (_globals.ending == kAtrusLeaves) {
// Wait for atrus to come back
_atrusLeft = true;
} else if (_globals.ending == kAtrusWantsPage) {
// Atrus asking for page
if (!_vm->_video->isVideoPlaying()) {
_video = "atr1page";
_videoPos = Common::Point(215, 76);
VideoEntryPtr atrus = _vm->playMovie(_video, kDniStack);
atrus->moveTo(_videoPos.x, _videoPos.y);
atrus->setLooping(true);
atrus->setBounds(Audio::Timestamp(0, 7388, 600), Audio::Timestamp(0, 14700, 600));
}
} else if (_globals.ending != kForgotPage && _globals.ending != kBooksDestroyed) {
if (_globals.heldPage == kWhitePage) {
_video = "atr1page";
_videoPos = Common::Point(215, 76);
VideoEntryPtr atrus = _vm->playMovie(_video, kDniStack);
atrus->moveTo(_videoPos.x, _videoPos.y);
atrus->setBounds(Audio::Timestamp(0, 0, 600), Audio::Timestamp(0, 14700, 600));
_waitForLoop = true;
_loopStart = 7388;
_loopEnd = 14700;
// Wait for page
_globals.ending = kAtrusWantsPage;
} else {
_video = "atr1nopg";
_videoPos = Common::Point(215, 77);
VideoEntryPtr atrus = _vm->playMovie(_video, kDniStack);
atrus->moveTo(_videoPos.x, _videoPos.y);
atrus->setBounds(Audio::Timestamp(0, 0, 600), Audio::Timestamp(0, 46175, 600));
_atrusRunning = false;
_waitForLoop = true;
_loopStart = 30656;
_loopEnd = 46175;
// Bad ending
_globals.ending = kForgotPage;
}
} else if (!_vm->_video->isVideoPlaying()) {
VideoEntryPtr atrus = _vm->playMovie("atrwrite", kDniStack);
atrus->moveTo(215, 77);
atrus->setLooping(true);
}
}
void Dni::o_atrus_init(uint16 var, const ArgumentsArray &args) {
_atrusRunning = true;
}
} // End of namespace MystStacks
} // End of namespace Mohawk

View File

@@ -0,0 +1,75 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef MYST_SCRIPTS_DNI_H
#define MYST_SCRIPTS_DNI_H
#include "common/scummsys.h"
#include "common/util.h"
#include "mohawk/myst_scripts.h"
namespace Mohawk {
struct MystScriptEntry;
namespace MystStacks {
#define DECLARE_OPCODE(x) void x(uint16 var, const ArgumentsArray &args)
class Dni : public MystScriptParser {
public:
explicit Dni(MohawkEngine_Myst *vm);
~Dni() override;
void disablePersistentScripts() override;
void runPersistentScripts() override;
private:
void setupOpcodes();
uint16 getVar(uint16 var) override;
void atrus_run();
void loopVideo_run();
void atrusLeft_run();
DECLARE_OPCODE(o_handPage);
DECLARE_OPCODE(o_atrus_init);
bool _atrusRunning;
bool _notSeenAtrus; // 56
uint32 _atrusLeftTime; // 60
Common::String _video; // 64
Common::Point _videoPos;
bool _waitForLoop;
uint32 _loopStart; // 72
uint32 _loopEnd; // 76
bool _atrusLeft; // 80
};
} // End of namespace MystStacks
} // End of namespace Mohawk
#undef DECLARE_OPCODE
#endif

View File

@@ -0,0 +1,167 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#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/intro.h"
namespace Mohawk {
namespace MystStacks {
Intro::Intro(MohawkEngine_Myst *vm, MystStack stackId) :
MystScriptParser(vm, stackId),
_introMoviesRunning(false),
_introStep(0),
_linkBookRunning(false),
_linkBookMovie(nullptr) {
setupOpcodes();
}
Intro::~Intro() {
}
void Intro::setupOpcodes() {
// "Stack-Specific" Opcodes
REGISTER_OPCODE(100, Intro, o_useLinkBook);
// "Init" Opcodes
REGISTER_OPCODE(200, Intro, o_playIntroMovies);
REGISTER_OPCODE(201, Intro, o_mystLinkBook_init);
// "Exit" Opcodes
REGISTER_OPCODE(300, Intro, NOP);
}
void Intro::disablePersistentScripts() {
_introMoviesRunning = false;
_linkBookRunning = false;
}
void Intro::runPersistentScripts() {
if (_introMoviesRunning)
introMovies_run();
if (_linkBookRunning)
mystLinkBook_run();
}
uint16 Intro::getVar(uint16 var) {
switch(var) {
case 0:
if (_globals.currentAge == kSirrusEnding || _globals.currentAge == kAchenarEnding)
return 2;
else
return _globals.currentAge;
default:
return MystScriptParser::getVar(var);
}
}
void Intro::o_useLinkBook(uint16 var, const ArgumentsArray &args) {
// Hard coded SoundId valid only for Intro Stack.
// Other stacks use Opcode 40, which takes SoundId values as arguments.
const uint16 soundIdLinkSrc = 5;
const uint16 soundIdLinkDst[] = { 2282, 3029, 6396, 7122, 3137, 0, 9038, 5134, 0, 4739, 4741 };
// Change to dest stack
_vm->changeToStack(_stackMap[_globals.currentAge], _startCard[_globals.currentAge], soundIdLinkSrc, soundIdLinkDst[_globals.currentAge]);
}
void Intro::introMovies_run() {
// Play Intro Movies
// This is all quite messy...
VideoEntryPtr video;
switch (_introStep) {
case 0:
_introStep = 1;
video = _vm->playMovieFullscreen("broder", kIntroStack);
break;
case 1:
if (!_vm->_video->isVideoPlaying())
_introStep = 2;
break;
case 2:
_introStep = 3;
video = _vm->playMovieFullscreen("cyanlogo", kIntroStack);
break;
case 3:
if (!_vm->_video->isVideoPlaying())
_introStep = 4;
break;
case 4:
_introStep = 5;
if (!_vm->isGameVariant(GF_DEMO)) { // The demo doesn't have the intro video
video = _vm->playMovieFullscreen("intro", kIntroStack);
}
break;
case 5:
if (!_vm->_video->isVideoPlaying())
_introStep = 6;
break;
default:
if (_vm->isGameVariant(GF_DEMO))
_vm->changeToCard(2001, kTransitionRightToLeft);
else
_vm->changeToCard(2, kTransitionRightToLeft);
}
}
void Intro::o_playIntroMovies(uint16 var, const ArgumentsArray &args) {
_introMoviesRunning = true;
if (_vm->isGameVariant(GF_25TH)) {
// In the 25th anniversary version, the Broderbund / Cyan Logo were already shown
// before the main menu. No need to play them again here.
_introStep = 4;
} else {
_introStep = 0;
}
}
void Intro::mystLinkBook_run() {
if (_startTime == 1) {
_startTime = 0;
if (!_vm->wait(5000, true)) {
_linkBookMovie->playMovie();
_vm->_gfx->copyImageToBackBuffer(4, Common::Rect(544, 333));
_vm->_gfx->copyBackBufferToScreen(Common::Rect(544, 333));
}
} else if (!_linkBookMovie->isPlaying()) {
_vm->changeToCard(5, kTransitionRightToLeft);
}
}
void Intro::o_mystLinkBook_init(uint16 var, const ArgumentsArray &args) {
_linkBookMovie = getInvokingResource<MystAreaVideo>();
_startTime = 1;
_linkBookRunning = true;
}
} // End of namespace MystStacks
} // End of namespace Mohawk

View File

@@ -0,0 +1,70 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef MYST_SCRIPTS_INTRO_H
#define MYST_SCRIPTS_INTRO_H
#include "common/scummsys.h"
#include "common/util.h"
#include "mohawk/myst_scripts.h"
namespace Mohawk {
class MystAreaVideo;
struct MystScriptEntry;
namespace MystStacks {
#define DECLARE_OPCODE(x) void x(uint16 var, const ArgumentsArray &args)
class Intro : public MystScriptParser {
public:
explicit Intro(MohawkEngine_Myst *vm, MystStack stackId = kIntroStack);
~Intro() override;
void disablePersistentScripts() override;
void runPersistentScripts() override;
private:
void setupOpcodes();
uint16 getVar(uint16 var) override;
DECLARE_OPCODE(o_useLinkBook);
DECLARE_OPCODE(o_playIntroMovies);
DECLARE_OPCODE(o_mystLinkBook_init);
void introMovies_run();
void mystLinkBook_run();
bool _introMoviesRunning;
uint16 _introStep;
bool _linkBookRunning;
MystAreaVideo *_linkBookMovie;
};
} // End of namespace MystStacks
} // End of namespace Mohawk
#undef DECLARE_OPCODE
#endif

View File

@@ -0,0 +1,52 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include "mohawk/myst.h"
#include "mohawk/graphics.h"
#include "mohawk/myst_areas.h"
#include "mohawk/sound.h"
#include "mohawk/video.h"
#include "mohawk/myst_stacks/makingof.h"
namespace Mohawk {
namespace MystStacks {
MakingOf::MakingOf(MohawkEngine_Myst *vm) :
MystScriptParser(vm, kMakingOfStack) {
setupOpcodes();
}
MakingOf::~MakingOf() {
}
void MakingOf::setupOpcodes() {
// "Stack-Specific" Opcodes
REGISTER_OPCODE(100, MakingOf, o_quit);
}
void MakingOf::disablePersistentScripts() {
}
void MakingOf::runPersistentScripts() {
}
} // End of namespace MystStacks
} // End of namespace Mohawk

View File

@@ -0,0 +1,54 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef MYST_SCRIPTS_MAKINGOF_H
#define MYST_SCRIPTS_MAKINGOF_H
#include "common/scummsys.h"
#include "common/util.h"
#include "mohawk/myst_scripts.h"
namespace Mohawk {
struct MystScriptEntry;
namespace MystStacks {
#define DECLARE_OPCODE(x) void x(uint16 var, const ArgumentsArray &args)
class MakingOf : public MystScriptParser {
public:
explicit MakingOf(MohawkEngine_Myst *vm);
~MakingOf() override;
void disablePersistentScripts() override;
void runPersistentScripts() override;
private:
void setupOpcodes();
};
} // End of namespace MystStacks
} // End of namespace Mohawk
#undef DECLARE_OPCODE
#endif

View File

@@ -0,0 +1,989 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include "mohawk/cursors.h"
#include "mohawk/myst.h"
#include "mohawk/myst_areas.h"
#include "mohawk/myst_card.h"
#include "mohawk/myst_graphics.h"
#include "mohawk/myst_state.h"
#include "mohawk/myst_sound.h"
#include "mohawk/video.h"
#include "mohawk/myst_stacks/mechanical.h"
#include "common/events.h"
#include "common/system.h"
namespace Mohawk {
namespace MystStacks {
Mechanical::Mechanical(MohawkEngine_Myst *vm) :
MystScriptParser(vm, kMechanicalStack),
_state(vm->_gameState->_mechanical) {
setupOpcodes();
_elevatorGoingMiddle = false;
_elevatorPosition = 0;
_elevatorGoingDown = 0;
_elevatorRotationSpeed = 0;
_elevatorRotationGearPosition = 0;
_elevatorRotationSoundId = 0;
_elevatorRotationLeverMoving = false;
_elevatorTooLate = false;
_elevatorInCabin = false;
_elevatorTopCounter = 0;
_elevatorNextTime = 0;
_crystalLit = 0;
_mystStaircaseState = false;
_fortressDirection = kSouth;
_gearsWereRunning = false;
_fortressRotationShortMovieWorkaround = false;
_fortressRotationShortMovieCount = 0;
_fortressRotationShortMovieLast = 0;
_fortressRotationRunning = false;
_fortressRotationSpeed = 0;
_fortressRotationBrake = 0;
_fortressRotationGears = nullptr;
_fortressSimulationRunning = false;
_fortressSimulationInit = false;
_fortressSimulationSpeed = 0;
_fortressSimulationBrake = 0;
_fortressSimulationStartSound1 = 0;
_fortressSimulationStartSound2 = 0;
_fortressSimulationHolo = nullptr;
_fortressSimulationStartup = nullptr;
_fortressSimulationHoloRate = 0;
_birdSinging = false;
_birdCrankStartTime = 0;
_birdSingEndTime = 0;
_bird = nullptr;
_snakeBox = nullptr;
}
Mechanical::~Mechanical() {
}
void Mechanical::setupOpcodes() {
// "Stack-Specific" Opcodes
REGISTER_OPCODE(100, Mechanical, o_throneEnablePassage);
REGISTER_OPCODE(101, Mechanical, o_birdCrankStart);
REGISTER_OPCODE(102, Mechanical, NOP);
REGISTER_OPCODE(103, Mechanical, o_birdCrankStop);
REGISTER_OPCODE(104, Mechanical, o_snakeBoxTrigger);
REGISTER_OPCODE(105, Mechanical, o_fortressStaircaseMovie);
REGISTER_OPCODE(106, Mechanical, o_elevatorRotationStart);
REGISTER_OPCODE(107, Mechanical, o_elevatorRotationMove);
REGISTER_OPCODE(108, Mechanical, o_elevatorRotationStop);
REGISTER_OPCODE(109, Mechanical, o_fortressRotationSpeedStart);
REGISTER_OPCODE(110, Mechanical, o_fortressRotationSpeedMove);
REGISTER_OPCODE(111, Mechanical, o_fortressRotationSpeedStop);
REGISTER_OPCODE(112, Mechanical, o_fortressRotationBrakeStart);
REGISTER_OPCODE(113, Mechanical, o_fortressRotationBrakeMove);
REGISTER_OPCODE(114, Mechanical, o_fortressRotationBrakeStop);
REGISTER_OPCODE(115, Mechanical, o_fortressSimulationSpeedStart);
REGISTER_OPCODE(116, Mechanical, o_fortressSimulationSpeedMove);
REGISTER_OPCODE(117, Mechanical, o_fortressSimulationSpeedStop);
REGISTER_OPCODE(118, Mechanical, o_fortressSimulationBrakeStart);
REGISTER_OPCODE(119, Mechanical, o_fortressSimulationBrakeMove);
REGISTER_OPCODE(120, Mechanical, o_fortressSimulationBrakeStop);
REGISTER_OPCODE(121, Mechanical, o_elevatorWindowMovie);
REGISTER_OPCODE(122, Mechanical, o_elevatorGoMiddle);
REGISTER_OPCODE(123, Mechanical, o_elevatorTopMovie);
REGISTER_OPCODE(124, Mechanical, o_fortressRotationSetPosition);
REGISTER_OPCODE(125, Mechanical, o_mystStaircaseMovie);
REGISTER_OPCODE(126, Mechanical, o_elevatorWaitTimeout);
REGISTER_OPCODE(127, Mechanical, o_crystalEnterYellow);
REGISTER_OPCODE(128, Mechanical, o_crystalLeaveYellow);
REGISTER_OPCODE(129, Mechanical, o_crystalEnterGreen);
REGISTER_OPCODE(130, Mechanical, o_crystalLeaveGreen);
REGISTER_OPCODE(131, Mechanical, o_crystalEnterRed);
REGISTER_OPCODE(132, Mechanical, o_crystalLeaveRed);
// "Init" Opcodes
REGISTER_OPCODE(200, Mechanical, o_throne_init);
REGISTER_OPCODE(201, Mechanical, o_fortressStaircase_init);
REGISTER_OPCODE(202, Mechanical, o_bird_init);
REGISTER_OPCODE(203, Mechanical, o_snakeBox_init);
REGISTER_OPCODE(204, Mechanical, o_elevatorRotation_init);
REGISTER_OPCODE(205, Mechanical, o_fortressRotation_init);
REGISTER_OPCODE(206, Mechanical, o_fortressSimulation_init);
REGISTER_OPCODE(209, Mechanical, o_fortressSimulationStartup_init);
// "Exit" Opcodes
REGISTER_OPCODE(300, Mechanical, NOP);
}
void Mechanical::disablePersistentScripts() {
_fortressSimulationRunning = false;
_elevatorRotationLeverMoving = false;
_birdSinging = false;
_fortressRotationRunning = false;
}
void Mechanical::runPersistentScripts() {
if (_birdSinging)
birdSing_run();
if (_elevatorRotationLeverMoving)
elevatorRotation_run();
if (_elevatorGoingMiddle)
elevatorGoMiddle_run();
if (_fortressRotationRunning)
fortressRotation_run();
if (_fortressSimulationRunning)
fortressSimulation_run();
}
uint16 Mechanical::getVar(uint16 var) {
switch(var) {
case 0: // Achenar's Secret Panel State
return _state.achenarPanelState;
case 1: // Sirrus's Secret Panel State
return _state.sirrusPanelState;
case 2: // Achenar's Secret Room Crate Lid Open and Blue Page Present
if (_state.achenarCrateOpened) {
if (_globals.bluePagesInBook & 4 || _globals.heldPage == kBlueMechanicalPage)
return 2;
else
return 3;
} else {
return _globals.bluePagesInBook & 4 || _globals.heldPage == kBlueMechanicalPage;
}
case 3: // Achenar's Secret Room Crate State
return _state.achenarCrateOpened;
case 4: // Myst Book Room Staircase State
return _mystStaircaseState;
case 5: // Fortress Position
return _fortressDirection;
case 6: // Fortress Position - Big Cog Visible Through Doorway
return _fortressDirection == kSouth;
case 7: // Fortress Elevator Open
if (_state.elevatorRotation == 4)
return 1; // Open
else
return 0; // Closed
case 10: // Fortress Staircase State
return _state.staircaseState;
case 11: // Fortress Elevator Rotation Position
return _state.elevatorRotation;
case 12: // Fortress Elevator Rotation Cog Position
return 5 - (uint16)(_elevatorRotationGearPosition + 0.5) % 6;
case 13: // Elevator position
return _elevatorPosition;
case 14: // Elevator going down when at top
if (_elevatorGoingDown && _elevatorTooLate)
return 2;
else
return _elevatorGoingDown;
case 15: // Code Lock Execute Button Script
if (_mystStaircaseState)
return 0;
else if (_state.codeShape[0] == 2 && _state.codeShape[1] == 8
&& _state.codeShape[2] == 5 && _state.codeShape[3] == 1)
return 1;
else
return 2;
case 16: // Code Lock Shape #1 - Left
case 17: // Code Lock Shape #2
case 18: // Code Lock Shape #3
case 19: // Code Lock Shape #4 - Right
return _state.codeShape[var - 16];
case 20: // Crystal Lit Flag - Yellow
return _crystalLit == 3;
case 21: // Crystal Lit Flag - Green
return _crystalLit == 1;
case 22: // Crystal Lit Flag - Red
return _crystalLit == 2;
case 102: // Red page
return !(_globals.redPagesInBook & 4) && (_globals.heldPage != kRedMechanicalPage);
case 103: // Blue page
return !(_globals.bluePagesInBook & 4) && (_globals.heldPage != kBlueMechanicalPage);
default:
return MystScriptParser::getVar(var);
}
}
void Mechanical::toggleVar(uint16 var) {
switch(var) {
case 0: // Achenar's Secret Panel State
_state.achenarPanelState ^= 1;
break;
case 1: // Sirrus's Secret Panel State
_state.sirrusPanelState ^= 1;
break;
case 3: // Achenar's Secret Room Crate State
_state.achenarCrateOpened ^= 1;
break;
case 4: // Myst Book Room Staircase State
_mystStaircaseState ^= 1;
break;
case 10: // Fortress Staircase State
_state.staircaseState ^= 1;
break;
case 16: // Code Lock Shape #1 - Left
case 17: // Code Lock Shape #2
case 18: // Code Lock Shape #3
case 19: // Code Lock Shape #4 - Right
_state.codeShape[var - 16] = (_state.codeShape[var - 16] + 1) % 10;
break;
case 23: // Elevator player is in cabin
_elevatorInCabin = false;
break;
case 102: // Red page
if (!(_globals.redPagesInBook & 4)) {
if (_globals.heldPage == kRedMechanicalPage)
_globals.heldPage = kNoPage;
else
_globals.heldPage = kRedMechanicalPage;
}
break;
case 103: // Blue page
if (!(_globals.bluePagesInBook & 4)) {
if (_globals.heldPage == kBlueMechanicalPage)
_globals.heldPage = kNoPage;
else
_globals.heldPage = kBlueMechanicalPage;
}
break;
default:
MystScriptParser::toggleVar(var);
break;
}
}
bool Mechanical::setVarValue(uint16 var, uint16 value) {
bool refresh = false;
switch (var) {
case 13:
_elevatorPosition = value;
break;
case 14: // Elevator going down when at top
_elevatorGoingDown = value;
break;
default:
refresh = MystScriptParser::setVarValue(var, value);
break;
}
return refresh;
}
void Mechanical::o_throneEnablePassage(uint16 var, const ArgumentsArray &args) {
_vm->getCard()->getResource<MystArea>(args[0])->setEnabled(getVar(var));
}
void Mechanical::o_birdCrankStart(uint16 var, const ArgumentsArray &args) {
MystAreaDrag *crank = getInvokingResource<MystAreaDrag>();
uint16 crankSoundId = crank->getList2(0);
_vm->_sound->playEffect(crankSoundId, true);
_birdSingEndTime = 0;
_birdCrankStartTime = _vm->getTotalPlayTime();
MystAreaVideo *crankMovie = static_cast<MystAreaVideo *>(crank->getSubResource(0));
crankMovie->playMovie();
}
void Mechanical::o_birdCrankStop(uint16 var, const ArgumentsArray &args) {
MystAreaDrag *crank = getInvokingResource<MystAreaDrag>();
MystAreaVideo *crankMovie = static_cast<MystAreaVideo *>(crank->getSubResource(0));
crankMovie->pauseMovie(true);
uint16 crankSoundId = crank->getList2(1);
_vm->_sound->playEffect(crankSoundId);
_birdSingEndTime = 2 * _vm->getTotalPlayTime() - _birdCrankStartTime;
_birdSinging = true;
_bird->playMovie();
}
void Mechanical::o_snakeBoxTrigger(uint16 var, const ArgumentsArray &args) {
// Used on Mechanical Card 6043 (Weapons Rack with Snake Box)
_snakeBox->playMovie();
}
void Mechanical::o_fortressStaircaseMovie(uint16 var, const ArgumentsArray &args) {
VideoEntryPtr staircase = _vm->playMovie("hhstairs", kMechanicalStack);
staircase->moveTo(174, 222);
if (_state.staircaseState) {
staircase->setBounds(Audio::Timestamp(0, 840, 600), Audio::Timestamp(0, 1680, 600));
} else {
staircase->setBounds(Audio::Timestamp(0, 0, 600), Audio::Timestamp(0, 840, 600));
}
_vm->waitUntilMovieEnds(staircase);
}
void Mechanical::o_elevatorRotationStart(uint16 var, const ArgumentsArray &args) {
MystVideoInfo *lever = getInvokingResource<MystVideoInfo>();
lever->drawFrame(0);
_elevatorRotationLeverMoving = true;
_elevatorRotationSpeed = 0;
_vm->_sound->stopBackground();
_vm->_cursor->setCursor(700);
}
void Mechanical::o_elevatorRotationMove(uint16 var, const ArgumentsArray &args) {
const Common::Point &mouse = _vm->_system->getEventManager()->getMousePos();
MystVideoInfo *lever = getInvokingResource<MystVideoInfo>();
// Make the handle follow the mouse
int16 maxStep = lever->getNumFrames() - 1;
Common::Rect rect = lever->getRect();
int16 step = ((rect.bottom - mouse.y) * lever->getNumFrames()) / rect.height();
step = CLIP<int16>(step, 0, maxStep);
_elevatorRotationSpeed = step * 0.1f;
// Draw current frame
lever->drawFrame(step);
}
void Mechanical::o_elevatorRotationStop(uint16 var, const ArgumentsArray &args) {
const Common::Point &mouse = _vm->_system->getEventManager()->getMousePos();
MystVideoInfo *lever = getInvokingResource<MystVideoInfo>();
// Get current lever frame
int16 maxStep = lever->getNumFrames() - 1;
Common::Rect rect = lever->getRect();
int16 step = ((rect.bottom - mouse.y) * lever->getNumFrames()) / rect.height();
step = CLIP<int16>(step, 0, maxStep);
// Release lever
for (int i = step; i >= 0; i--) {
lever->drawFrame(i);
_vm->doFrame();
}
// Stop persistent script
_elevatorRotationLeverMoving = false;
float speed = _elevatorRotationSpeed * 10;
if (speed > 0) {
// Decrease speed
while (speed > 2) {
speed -= 0.5f;
_elevatorRotationGearPosition += speed * 0.1f;
if (_elevatorRotationGearPosition > 12)
break;
_vm->getCard()->redrawArea(12);
_vm->wait(100);
}
// Increment position
_state.elevatorRotation = (_state.elevatorRotation + 1) % 10;
_vm->_sound->playEffect(_elevatorRotationSoundId);
_vm->getCard()->redrawArea(11);
}
_vm->refreshCursor();
}
void Mechanical::o_fortressRotationSpeedStart(uint16 var, const ArgumentsArray &args) {
_vm->_cursor->setCursor(700);
MystVideoInfo *lever = getInvokingResource<MystVideoInfo>();
lever->drawFrame(0);
}
void Mechanical::o_fortressRotationSpeedMove(uint16 var, const ArgumentsArray &args) {
const Common::Point &mouse = _vm->_system->getEventManager()->getMousePos();
MystVideoInfo *lever = getInvokingResource<MystVideoInfo>();
// Make the handle follow the mouse
int16 maxStep = lever->getNumFrames() - 1;
Common::Rect rect = lever->getRect();
int16 step = ((rect.top + 65 - mouse.y) * lever->getNumFrames()) / 65;
step = CLIP<int16>(step, 0, maxStep);
_fortressRotationSpeed = step;
// Draw current frame
lever->drawFrame(step);
}
void Mechanical::o_fortressRotationSpeedStop(uint16 var, const ArgumentsArray &args) {
MystVideoInfo *lever = getInvokingResource<MystVideoInfo>();
// Release lever
for (int i = _fortressRotationSpeed; i >= 0; i--) {
lever->drawFrame(i);
_vm->doFrame();
}
_fortressRotationSpeed = 0;
_vm->refreshCursor();
}
void Mechanical::o_fortressRotationBrakeStart(uint16 var, const ArgumentsArray &args) {
_vm->_cursor->setCursor(700);
MystVideoInfo *lever = getInvokingResource<MystVideoInfo>();
lever->drawFrame(_fortressRotationBrake);
}
void Mechanical::o_fortressRotationBrakeMove(uint16 var, const ArgumentsArray &args) {
const Common::Point &mouse = _vm->_system->getEventManager()->getMousePos();
MystVideoInfo *lever = getInvokingResource<MystVideoInfo>();
// Make the handle follow the mouse
int16 maxStep = lever->getNumFrames() - 1;
Common::Rect rect = lever->getRect();
int16 step = ((rect.top + 65 - mouse.y) * lever->getNumFrames()) / 65;
step = CLIP<int16>(step, 0, maxStep);
_fortressRotationBrake = step;
// Draw current frame
lever->drawFrame(step);
}
void Mechanical::o_fortressRotationBrakeStop(uint16 var, const ArgumentsArray &args) {
MystVideoInfo *lever = getInvokingResource<MystVideoInfo>();
lever->drawFrame(_fortressRotationBrake);
_vm->refreshCursor();
}
void Mechanical::o_fortressSimulationSpeedStart(uint16 var, const ArgumentsArray &args) {
_vm->_cursor->setCursor(700);
MystVideoInfo *lever = getInvokingResource<MystVideoInfo>();
lever->drawFrame(0);
}
void Mechanical::o_fortressSimulationSpeedMove(uint16 var, const ArgumentsArray &args) {
const Common::Point &mouse = _vm->_system->getEventManager()->getMousePos();
MystVideoInfo *lever = getInvokingResource<MystVideoInfo>();
// Make the handle follow the mouse
int16 maxStep = lever->getNumFrames() - 1;
Common::Rect rect = lever->getRect();
int16 step = ((rect.bottom - mouse.y) * lever->getNumFrames()) / rect.height();
step = CLIP<int16>(step, 0, maxStep);
_fortressSimulationSpeed = step;
// Draw current frame
lever->drawFrame(step);
}
void Mechanical::o_fortressSimulationSpeedStop(uint16 var, const ArgumentsArray &args) {
MystVideoInfo *lever = getInvokingResource<MystVideoInfo>();
// Release lever
for (int i = _fortressSimulationSpeed; i >= 0; i--) {
lever->drawFrame(i);
_vm->doFrame();
}
_fortressSimulationSpeed = 0;
_vm->refreshCursor();
}
void Mechanical::o_fortressSimulationBrakeStart(uint16 var, const ArgumentsArray &args) {
_vm->_cursor->setCursor(700);
MystVideoInfo *lever = getInvokingResource<MystVideoInfo>();
lever->drawFrame(_fortressSimulationBrake);
}
void Mechanical::o_fortressSimulationBrakeMove(uint16 var, const ArgumentsArray &args) {
const Common::Point &mouse = _vm->_system->getEventManager()->getMousePos();
MystVideoInfo *lever = getInvokingResource<MystVideoInfo>();
// Make the handle follow the mouse
int16 maxStep = lever->getNumFrames() - 1;
Common::Rect rect = lever->getRect();
int16 step = ((rect.bottom - mouse.y) * lever->getNumFrames()) / rect.height();
step = CLIP<int16>(step, 0, maxStep);
_fortressSimulationBrake = step;
// Draw current frame
lever->drawFrame(step);
}
void Mechanical::o_fortressSimulationBrakeStop(uint16 var, const ArgumentsArray &args) {
MystVideoInfo *lever = getInvokingResource<MystVideoInfo>();
lever->drawFrame(_fortressSimulationBrake);
_vm->refreshCursor();
}
void Mechanical::o_elevatorWindowMovie(uint16 var, const ArgumentsArray &args) {
uint16 startTime = args[0];
uint16 endTime = args[1];
VideoEntryPtr window = _vm->playMovie("ewindow", kMechanicalStack);
window->moveTo(253, 0);
window->setBounds(Audio::Timestamp(0, startTime, 600), Audio::Timestamp(0, endTime, 600));
_vm->waitUntilMovieEnds(window);
}
void Mechanical::o_elevatorGoMiddle(uint16 var, const ArgumentsArray &args) {
_elevatorTooLate = false;
_elevatorTopCounter = 5;
_elevatorGoingMiddle = true;
_elevatorInCabin = true;
_elevatorNextTime = _vm->getTotalPlayTime() + 1000;
}
void Mechanical::elevatorGoMiddle_run() {
uint32 time = _vm->getTotalPlayTime();
if (_elevatorNextTime < time) {
_elevatorNextTime = time + 1000;
_elevatorTopCounter--;
if (_elevatorTopCounter > 0) {
// Draw button pressed
if (_elevatorInCabin) {
_vm->_gfx->copyImageSectionToScreen(6332, Common::Rect(0, 35, 51, 63), Common::Rect(10, 137, 61, 165));
}
// Blip
_vm->playSoundBlocking(14120);
// Restore button
if (_elevatorInCabin) {
_vm->_gfx->copyBackBufferToScreen(Common::Rect(10, 137, 61, 165));
}
} else {
_elevatorTooLate = true;
_elevatorGoingMiddle = false;
if (_elevatorInCabin) {
// Elevator going to middle animation
_vm->_cursor->hideCursor();
_vm->playSoundBlocking(11120);
_vm->_gfx->copyImageToBackBuffer(6118, Common::Rect(544, 333));
_vm->_sound->playEffect(12120);
_vm->_gfx->runTransition(kTransitionSlideToLeft, Common::Rect(177, 0, 370, 333), 25, 0);
_vm->playSoundBlocking(13120);
_vm->_sound->playEffect(8120);
_vm->_gfx->copyImageToBackBuffer(6327, Common::Rect(544, 333));
_vm->wait(500);
_vm->_sound->playEffect(9120);
static uint16 moviePos[2] = { 3540, 5380 };
o_elevatorWindowMovie(0, ArgumentsArray(moviePos, ARRAYSIZE(moviePos)));
_vm->_gfx->copyBackBufferToScreen(Common::Rect(544, 333));
_vm->_sound->playEffect(10120);
_vm->_cursor->showCursor();
_elevatorPosition = 1;
_vm->changeToCard(6327, kTransitionRightToLeft);
}
}
}
}
void Mechanical::o_elevatorTopMovie(uint16 var, const ArgumentsArray &args) {
uint16 startTime = args[0];
uint16 endTime = args[1];
VideoEntryPtr window = _vm->playMovie("hcelev", kMechanicalStack);
window->moveTo(206, 38);
window->setBounds(Audio::Timestamp(0, startTime, 600), Audio::Timestamp(0, endTime, 600));
_vm->waitUntilMovieEnds(window);
}
void Mechanical::o_fortressRotationSetPosition(uint16 var, const ArgumentsArray &args) {
// The fortress direction is already set in fortressRotation_run() so we don't do it here
// Stop the gears video so that it does not play while the elevator is going up
_fortressRotationGears->getVideo()->stop();
}
void Mechanical::o_mystStaircaseMovie(uint16 var, const ArgumentsArray &args) {
_vm->playMovieBlocking("sstairs", kMechanicalStack, 199, 108);
}
void Mechanical::o_elevatorWaitTimeout(uint16 var, const ArgumentsArray &args) {
// Wait while the elevator times out
while (_elevatorGoingMiddle) {
runPersistentScripts();
_vm->doFrame();
}
}
void Mechanical::o_crystalEnterYellow(uint16 var, const ArgumentsArray &args) {
_crystalLit = 3;
_vm->getCard()->redrawArea(20);
}
void Mechanical::o_crystalEnterGreen(uint16 var, const ArgumentsArray &args) {
_crystalLit = 1;
_vm->getCard()->redrawArea(21);
}
void Mechanical::o_crystalEnterRed(uint16 var, const ArgumentsArray &args) {
_crystalLit = 2;
_vm->getCard()->redrawArea(22);
}
void Mechanical::o_crystalLeaveYellow(uint16 var, const ArgumentsArray &args) {
_crystalLit = 0;
_vm->getCard()->redrawArea(20);
}
void Mechanical::o_crystalLeaveGreen(uint16 var, const ArgumentsArray &args) {
_crystalLit = 0;
_vm->getCard()->redrawArea(21);
}
void Mechanical::o_crystalLeaveRed(uint16 var, const ArgumentsArray &args) {
_crystalLit = 0;
_vm->getCard()->redrawArea(22);
}
void Mechanical::o_throne_init(uint16 var, const ArgumentsArray &args) {
// Used on Card 6238 (Sirrus' Throne) and Card 6027 (Achenar's Throne)
getInvokingResource<MystArea>()->setEnabled(getVar(var));
}
void Mechanical::o_fortressStaircase_init(uint16 var, const ArgumentsArray &args) {
_vm->getCard()->getResource<MystArea>(args[0])->setEnabled(!_state.staircaseState);
_vm->getCard()->getResource<MystArea>(args[1])->setEnabled(!_state.staircaseState);
_vm->getCard()->getResource<MystArea>(args[2])->setEnabled(_state.staircaseState);
}
void Mechanical::birdSing_run() {
// Used for Card 6220 (Sirrus' Mechanical Bird)
uint32 time = _vm->getTotalPlayTime();
if (_birdSingEndTime < time) {
_bird->pauseMovie(true);
_vm->_sound->stopEffect();
_birdSinging = false;
}
}
void Mechanical::o_bird_init(uint16 var, const ArgumentsArray &args) {
_birdSinging = false;
_birdSingEndTime = 0;
_bird = getInvokingResource<MystAreaVideo>();
}
void Mechanical::o_snakeBox_init(uint16 var, const ArgumentsArray &args) {
_snakeBox = getInvokingResource<MystAreaVideo>();
}
void Mechanical::elevatorRotation_run() {
_vm->getCard()->redrawArea(12);
_elevatorRotationGearPosition += _elevatorRotationSpeed;
if (_elevatorRotationGearPosition > 12) {
uint16 position = (uint16)_elevatorRotationGearPosition;
_elevatorRotationGearPosition = _elevatorRotationGearPosition - position + position % 6;
_state.elevatorRotation = (_state.elevatorRotation + 1) % 10;
_vm->_sound->playEffect(_elevatorRotationSoundId);
_vm->getCard()->redrawArea(11);
_vm->wait(100);
}
}
void Mechanical::o_elevatorRotation_init(uint16 var, const ArgumentsArray &args) {
_elevatorRotationSoundId = args[0];
_elevatorRotationGearPosition = 0;
_elevatorRotationLeverMoving = false;
}
void Mechanical::fortressRotation_run() {
VideoEntryPtr gears = _fortressRotationGears->getVideo();
double oldRate = gears->getRate().toDouble();
uint32 moviePosition = Audio::Timestamp(gears->getTime(), 600).totalNumberOfFrames();
// Myst ME short movie workaround, explained in o_fortressRotation_init
if (_fortressRotationShortMovieWorkaround) {
// Detect if we just looped
if (ABS<int32>(_fortressRotationShortMovieLast - 3680) < 50
&& ABS<int32>(moviePosition) < 50) {
_fortressRotationShortMovieCount++;
}
_fortressRotationShortMovieLast = moviePosition;
// Simulate longer movie
moviePosition += 3600 * _fortressRotationShortMovieCount;
}
int32 positionInQuarter = 900 - (moviePosition + 900) % 1800;
// Are the gears moving?
if (oldRate >= 0.1 || ABS<int32>(positionInQuarter) >= 30 || _fortressRotationBrake) {
double newRate = oldRate;
if (_fortressRotationBrake && (double)_fortressRotationBrake * 0.2 > oldRate) {
newRate += 0.1;
}
// Don't let the gears get stuck between two fortress positions
if (ABS<double>(oldRate) <= 0.05) {
if (oldRate <= 0.0) {
newRate += oldRate;
} else {
newRate -= oldRate;
}
} else {
if (oldRate <= 0.0) {
newRate += 0.05;
} else {
newRate -= 0.05;
}
}
// Adjust speed accordingly to acceleration lever
newRate += (double) (positionInQuarter / 1500.0)
* (double) (9 - _fortressRotationSpeed) / 9.0;
newRate = CLIP<double>(newRate, -2.5, 2.5);
gears->setRate(Common::Rational((int)(newRate * 1000.0), 1000));
_gearsWereRunning = true;
} else if (_gearsWereRunning) {
// The fortress has stopped. Set its new position
_fortressDirection = (moviePosition + 900) / 1800 % 4;
gears->setRate(0);
if (!_fortressRotationShortMovieWorkaround) {
gears->seek(Audio::Timestamp(0, 1800 * _fortressDirection, 600));
} else {
gears->seek(Audio::Timestamp(0, 1800 * (_fortressDirection % 2), 600));
}
_vm->playSoundBlocking(_fortressRotationSounds[_fortressDirection]);
_gearsWereRunning = false;
}
}
void Mechanical::o_fortressRotation_init(uint16 var, const ArgumentsArray &args) {
_fortressRotationGears = getInvokingResource<MystAreaVideo>();
VideoEntryPtr gears = _fortressRotationGears->playMovie();
gears->setLooping(true);
// WORKAROUND for the tower rotation bug in Myst ME.
// The original engine only allowed to visit two out of the three small islands,
// preventing the game from being fully completable.
// The fortress rotation is computed from the current position in the movie
// hcgears.mov. The version of this movie that shipped with the ME edition is
// too short to allow to visit all the islands.
// ScummVM simulates a longer movie by counting the number of times the movie
// looped and adding that time to the current movie position.
// Hence allowing the fortress position to be properly computed.
uint32 movieDuration = gears->getDuration().convertToFramerate(600).totalNumberOfFrames();
_fortressRotationShortMovieWorkaround = movieDuration == 3680;
if (!_fortressRotationShortMovieWorkaround) {
gears->seek(Audio::Timestamp(0, 1800 * _fortressDirection, 600));
} else {
_fortressRotationShortMovieLast = 1800 * (_fortressDirection % 2);
_fortressRotationShortMovieCount = _fortressDirection >= 2 ? 1 : 0;
gears->seek(Audio::Timestamp(0, _fortressRotationShortMovieLast, 600));
}
gears->setRate(0);
_fortressRotationSounds[0] = args[0];
_fortressRotationSounds[1] = args[1];
_fortressRotationSounds[2] = args[2];
_fortressRotationSounds[3] = args[3];
_fortressRotationBrake = 0;
_fortressRotationRunning = true;
_gearsWereRunning = false;
}
void Mechanical::fortressSimulation_run() {
if (_fortressSimulationInit) {
// Init sequence
_vm->_sound->playBackground(_fortressSimulationStartSound1, 65535);
_vm->wait(5000, true);
VideoEntryPtr startup = _fortressSimulationStartup->playMovie();
_vm->playSoundBlocking(_fortressSimulationStartSound2);
_vm->_sound->playBackground(_fortressSimulationStartSound1, 65535);
_vm->waitUntilMovieEnds(startup);
_vm->_sound->stopBackground();
_vm->_sound->playEffect(_fortressSimulationStartSound2);
Common::Rect src = Common::Rect(0, 0, 176, 176);
Common::Rect dst = Common::Rect(187, 3, 363, 179);
_vm->_gfx->copyImageSectionToBackBuffer(6046, src, dst);
_vm->_gfx->copyBackBufferToScreen(dst);
_fortressSimulationStartup->pauseMovie(true);
VideoEntryPtr holo = _fortressSimulationHolo->playMovie();
holo->setLooping(true);
holo->setRate(0);
// HACK: Support negative rates with edit lists
_fortressSimulationHoloRate = 0;
// END HACK
_vm->_cursor->showCursor();
_fortressSimulationInit = false;
} else {
VideoEntryPtr holo = _fortressSimulationHolo->getVideo();
double oldRate = holo->getRate().toDouble();
// HACK: Support negative rates with edit lists
oldRate = _fortressSimulationHoloRate;
// END HACK
uint32 moviePosition = Audio::Timestamp(holo->getTime(), 600).totalNumberOfFrames();
int32 positionInQuarter = 900 - (moviePosition + 900) % 1800;
// Are the gears moving?
if (oldRate >= 0.1 || ABS<int32>(positionInQuarter) >= 30 || _fortressSimulationBrake) {
double newRate = oldRate;
if (_fortressSimulationBrake && (double)_fortressSimulationBrake * 0.2 > oldRate) {
newRate += 0.1;
}
// Don't let the gears get stuck between two fortress positions
if (ABS<double>(oldRate) <= 0.05) {
if (oldRate <= 0.0) {
newRate += oldRate;
} else {
newRate -= oldRate;
}
} else {
if (oldRate <= 0.0) {
newRate += 0.05;
} else {
newRate -= 0.05;
}
}
// Adjust speed accordingly to acceleration lever
newRate += (double) (positionInQuarter / 1500.0)
* (double) (9 - _fortressSimulationSpeed) / 9.0;
newRate = CLIP<double>(newRate, -2.5, 2.5);
// HACK: Support negative rates with edit lists
// Our current QuickTime implementation does not support negative
// playback rates for movies using edit lists.
// The fortress rotation simulator movie this code handles is the
// only movie in the game requiring that feature.
// This hack approximates the next frame to display when the rate
// is negative, and seeks to it. It's not intended to be precise.
_fortressSimulationHoloRate = newRate;
if (_fortressSimulationHoloRate < 0) {
double newMoviePosition = moviePosition + _fortressSimulationHoloRate * 10;
holo->setRate(0);
holo->seek(Audio::Timestamp(0, (uint)newMoviePosition, 600));
} else {
holo->setRate(Common::Rational((int)(newRate * 1000.0), 1000));
}
// END HACK
_gearsWereRunning = true;
} else if (_gearsWereRunning) {
// The fortress has stopped. Set its new position
uint16 simulationPosition = (moviePosition + 900) / 1800 % 4;
holo->setRate(0);
// HACK: Support negative rates with edit lists
_fortressSimulationHoloRate = 0;
// END HACK
holo->seek(Audio::Timestamp(0, 1800 * simulationPosition, 600));
_vm->playSoundBlocking( _fortressRotationSounds[simulationPosition]);
_gearsWereRunning = false;
}
}
}
void Mechanical::o_fortressSimulation_init(uint16 var, const ArgumentsArray &args) {
_fortressSimulationHolo = getInvokingResource<MystAreaVideo>();
_fortressSimulationStartSound1 = args[0];
_fortressSimulationStartSound2 = args[1];
_fortressRotationSounds[0] = args[2];
_fortressRotationSounds[1] = args[3];
_fortressRotationSounds[2] = args[4];
_fortressRotationSounds[3] = args[5];
_fortressSimulationBrake = 0;
_fortressSimulationRunning = true;
_gearsWereRunning = false;
_fortressSimulationInit = true;
_vm->_cursor->hideCursor();
}
void Mechanical::o_fortressSimulationStartup_init(uint16 var, const ArgumentsArray &args) {
_fortressSimulationStartup = getInvokingResource<MystAreaVideo>();
}
} // End of namespace MystStacks
} // End of namespace Mohawk

View File

@@ -0,0 +1,167 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef MYST_SCRIPTS_MECHANICAL_H
#define MYST_SCRIPTS_MECHANICAL_H
#include "common/scummsys.h"
#include "common/util.h"
#include "mohawk/myst_scripts.h"
namespace Mohawk {
struct MystScriptEntry;
namespace MystStacks {
#define DECLARE_OPCODE(x) void x(uint16 var, const ArgumentsArray &args)
class Mechanical : public MystScriptParser {
public:
explicit Mechanical(MohawkEngine_Myst *vm);
~Mechanical() override;
void disablePersistentScripts() override;
void runPersistentScripts() override;
private:
void setupOpcodes();
uint16 getVar(uint16 var) override;
void toggleVar(uint16 var) override;
bool setVarValue(uint16 var, uint16 value) override;
uint16 getMap() override { return 9931; }
void birdSing_run();
void elevatorRotation_run();
void elevatorGoMiddle_run();
void fortressRotation_run();
void fortressSimulation_run();
enum Direction {
kSouth = 0, // Starting Island with Myst linking book
kEast = 1, // Island with right half of code
kNorth = 2, // Island with left half of code
kWest = 3 // No island, just water
};
DECLARE_OPCODE(o_throneEnablePassage);
DECLARE_OPCODE(o_birdCrankStart);
DECLARE_OPCODE(o_birdCrankStop);
DECLARE_OPCODE(o_snakeBoxTrigger);
DECLARE_OPCODE(o_fortressStaircaseMovie);
DECLARE_OPCODE(o_elevatorRotationStart);
DECLARE_OPCODE(o_elevatorRotationMove);
DECLARE_OPCODE(o_elevatorRotationStop);
DECLARE_OPCODE(o_fortressRotationSpeedStart);
DECLARE_OPCODE(o_fortressRotationSpeedMove);
DECLARE_OPCODE(o_fortressRotationSpeedStop);
DECLARE_OPCODE(o_fortressRotationBrakeStart);
DECLARE_OPCODE(o_fortressRotationBrakeMove);
DECLARE_OPCODE(o_fortressRotationBrakeStop);
DECLARE_OPCODE(o_fortressSimulationSpeedStart);
DECLARE_OPCODE(o_fortressSimulationSpeedMove);
DECLARE_OPCODE(o_fortressSimulationSpeedStop);
DECLARE_OPCODE(o_fortressSimulationBrakeStart);
DECLARE_OPCODE(o_fortressSimulationBrakeMove);
DECLARE_OPCODE(o_fortressSimulationBrakeStop);
DECLARE_OPCODE(o_elevatorWindowMovie);
DECLARE_OPCODE(o_elevatorGoMiddle);
DECLARE_OPCODE(o_elevatorTopMovie);
DECLARE_OPCODE(o_fortressRotationSetPosition); // Rotator control button (above elevator) has been pressed
DECLARE_OPCODE(o_mystStaircaseMovie);
DECLARE_OPCODE(o_elevatorWaitTimeout);
DECLARE_OPCODE(o_crystalEnterYellow);
DECLARE_OPCODE(o_crystalEnterGreen);
DECLARE_OPCODE(o_crystalEnterRed);
DECLARE_OPCODE(o_crystalLeaveYellow);
DECLARE_OPCODE(o_crystalLeaveGreen);
DECLARE_OPCODE(o_crystalLeaveRed);
DECLARE_OPCODE(o_throne_init);
DECLARE_OPCODE(o_fortressStaircase_init);
DECLARE_OPCODE(o_bird_init);
DECLARE_OPCODE(o_snakeBox_init);
DECLARE_OPCODE(o_elevatorRotation_init);
DECLARE_OPCODE(o_fortressRotation_init);
DECLARE_OPCODE(o_fortressSimulation_init);
DECLARE_OPCODE(o_fortressSimulationStartup_init);
MystGameState::Mechanical &_state;
bool _mystStaircaseState; // 76
bool _fortressRotationRunning;
bool _gearsWereRunning;
uint16 _fortressRotationSpeed; // 78
uint16 _fortressRotationBrake; // 80
uint16 _fortressDirection; // 82
uint16 _fortressRotationSounds[4]; // 86 to 92
MystAreaVideo *_fortressRotationGears; // 172
bool _fortressRotationShortMovieWorkaround;
uint32 _fortressRotationShortMovieCount;
uint32 _fortressRotationShortMovieLast;
bool _fortressSimulationRunning;
bool _fortressSimulationInit; // 94
uint16 _fortressSimulationSpeed; // 96
uint16 _fortressSimulationBrake; // 98
uint16 _fortressSimulationStartSound1; // 102
uint16 _fortressSimulationStartSound2; // 100
MystAreaVideo *_fortressSimulationHolo; // 160
MystAreaVideo *_fortressSimulationStartup; // 164
// HACK: Support negative rates with edit lists
double _fortressSimulationHoloRate;
// END HACK
uint16 _elevatorGoingDown; // 112
float _elevatorRotationSpeed; // 120
float _elevatorRotationGearPosition; // 124
uint16 _elevatorRotationSoundId; // 128
bool _elevatorRotationLeverMoving; // 184
bool _elevatorGoingMiddle; // 148
bool _elevatorTooLate;
uint16 _elevatorPosition; // 104
bool _elevatorInCabin; // 108
uint16 _elevatorTopCounter;
uint32 _elevatorNextTime;
uint16 _crystalLit; // 130
bool _birdSinging; // 144
uint32 _birdCrankStartTime; // 136
uint32 _birdSingEndTime; // 140
MystAreaVideo *_bird; // 152
MystAreaVideo *_snakeBox; // 156
};
} // End of namespace MystStacks
} // End of namespace Mohawk
#undef DECLARE_OPCODE
#endif

View File

@@ -0,0 +1,391 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include "mohawk/myst.h"
#include "mohawk/myst_areas.h"
#include "mohawk/myst_card.h"
#include "mohawk/myst_graphics.h"
#include "mohawk/myst_state.h"
#include "mohawk/cursors.h"
#include "mohawk/sound.h"
#include "mohawk/video.h"
#include "mohawk/myst_stacks/menu.h"
#include "common/translation.h"
#include "graphics/cursorman.h"
#include "gui/message.h"
namespace Mohawk {
namespace MystStacks {
Menu::Menu(MohawkEngine_Myst *vm) :
MystScriptParser(vm, kMenuStack),
_inGame(false),
_canSave(false),
_wasCursorVisible(true),
_introMoviesRunning(false) {
for (uint i = 0; i < ARRAYSIZE(_menuItemHovered); i++) {
_menuItemHovered[i] = false;
}
setupOpcodes();
}
Menu::~Menu() {
}
void Menu::setupOpcodes() {
// "Stack-Specific" Opcodes
REGISTER_OPCODE(150, Menu, o_menuItemEnter);
REGISTER_OPCODE(151, Menu, o_menuItemLeave);
REGISTER_OPCODE(152, Menu, o_menuResume);
REGISTER_OPCODE(153, Menu, o_menuLoad);
REGISTER_OPCODE(154, Menu, o_menuSave);
REGISTER_OPCODE(155, Menu, o_menuNew);
REGISTER_OPCODE(156, Menu, o_menuOptions);
REGISTER_OPCODE(157, Menu, o_menuQuit);
// "Init" Opcodes
REGISTER_OPCODE(200, Menu, o_playIntroMovies);
REGISTER_OPCODE(201, Menu, o_menuInit);
// "Exit" Opcodes
REGISTER_OPCODE(300, Menu, NOP);
REGISTER_OPCODE(301, Menu, o_menuExit);
}
void Menu::disablePersistentScripts() {
_introMoviesRunning = false;
}
void Menu::runPersistentScripts() {
if (_introMoviesRunning)
introMovies_run();
}
uint16 Menu::getVar(uint16 var) {
switch (var) {
case 1000: // New game
case 1001: // Load
case 1004: // Quit
case 1005: // Options
return _menuItemHovered[var - 1000] ? 1 : 0;
case 1002: // Save
if (_canSave) {
return _menuItemHovered[var - 1000] ? 1 : 0;
} else {
return 2;
}
case 1003: // Resume
if (_inGame) {
return _menuItemHovered[var - 1000] ? 1 : 0;
} else {
return 2;
}
default:
return MystScriptParser::getVar(var);
}
}
void Menu::o_menuInit(uint16 var, const ArgumentsArray &args) {
_pauseToken = _vm->pauseEngine();
if (_inGame) {
_wasCursorVisible = CursorMan.isVisible();
}
if (!_wasCursorVisible) {
CursorMan.showMouse(true);
}
struct MenuButton {
uint16 highlightedIndex;
uint16 disabledIndex;
Graphics::TextAlign align;
};
static const MenuButton buttons[] = {
{ 1, 0, Graphics::kTextAlignRight },
{ 1, 0, Graphics::kTextAlignRight },
{ 1, 2, Graphics::kTextAlignRight },
{ 1, 2, Graphics::kTextAlignRight },
{ 1, 0, Graphics::kTextAlignRight },
{ 1, 0, Graphics::kTextAlignLeft }
};
const char **buttonCaptions = getButtonCaptions();
for (uint i = 0; i < ARRAYSIZE(buttons); i++) {
MystAreaImageSwitch *image = _vm->getCard()->getResource<MystAreaImageSwitch>(2 * i + 0);
MystAreaHover *hover = _vm->getCard()->getResource<MystAreaHover> (2 * i + 1);
Common::U32String str = Common::convertUtf8ToUtf32(buttonCaptions[i]);
drawButtonImages(str, image, buttons[i].align, buttons[i].highlightedIndex, buttons[i].disabledIndex);
hover->setRect(image->getRect());
}
}
const char **Menu::getButtonCaptions() const {
static const char *buttonCaptionsEnglish[] = {
"NEW GAME",
"LOAD GAME",
"SAVE GAME",
"RESUME",
"QUIT",
"OPTIONS"
};
static const char *buttonCaptionsFrench[] = {
"NOUVEAU",
"CHARGER",
"SAUVER",
"REPRENDRE",
"QUITTER",
"OPTIONS"
};
static const char *buttonCaptionsGerman[] = {
"NEUES SPIEL",
"SPIEL LADEN",
"SPIEL SPEICHERN",
"FORTSETZEN",
"BEENDEN",
"OPTIONEN"
};
static const char *buttonCaptionsSpanish[] = {
"JUEGO NUEVO",
"CARGAR JUEGO",
"GUARDAR JUEGO",
"CONTINUAR",
"SALIR",
"OPCIONES"
};
static const char *buttonCaptionsPolish[] = {
"NOWA GRA",
"ZAŁADUJ GRĘ",
"ZAPISZ GRĘ",
"POWRÓT",
"WYJŚCIE",
"OPCJE"
};
switch (_vm->getLanguage()) {
case Common::FR_FRA:
return buttonCaptionsFrench;
case Common::DE_DEU:
return buttonCaptionsGerman;
case Common::ES_ESP:
return buttonCaptionsSpanish;
case Common::PL_POL:
return buttonCaptionsPolish;
case Common::EN_ANY:
default:
return buttonCaptionsEnglish;
}
}
void Menu::drawButtonImages(const Common::U32String &text, MystAreaImageSwitch *area, Graphics::TextAlign align, uint16 highlightedIndex, uint16 disabledIndex) const {
Common::Rect backgroundRect = area->getRect();
Common::Rect textBoundingBox = _vm->_gfx->getTextBoundingBox(text, backgroundRect, align);
// Restrict the rectangle to the portion were the text will be drawn
if (align == Graphics::kTextAlignLeft) {
backgroundRect.right = textBoundingBox.right;
} else if (align == Graphics::kTextAlignRight) {
backgroundRect.left = textBoundingBox.left;
} else {
error("Unexpected align: %d", align);
}
// Update the area with the new background rect
area->setRect(backgroundRect);
MystAreaImageSwitch::SubImage idle = area->getSubImage(0);
area->setSubImageRect(0, Common::Rect(backgroundRect.left, idle.rect.top, backgroundRect.right, idle.rect.bottom));
// Align the text to the top of the destination rectangles
int16 deltaY;
if (_vm->getLanguage() == Common::PL_POL) {
deltaY = -2;
} else {
deltaY = backgroundRect.top - textBoundingBox.top;
}
if (highlightedIndex) {
replaceButtonSubImageWithText(text, align, area, highlightedIndex, backgroundRect, deltaY, 215, 216, 219);
}
if (disabledIndex) {
replaceButtonSubImageWithText(text, align, area, disabledIndex, backgroundRect, deltaY, 136, 140, 145);
}
uint16 cardBackground = _vm->getCard()->getBackgroundImageId();
_vm->_gfx->drawText(cardBackground, text, backgroundRect, 181, 184, 189, align, deltaY);
}
void Menu::replaceButtonSubImageWithText(const Common::U32String &text, const Graphics::TextAlign &align, MystAreaImageSwitch *area,
uint16 subimageIndex, const Common::Rect &backgroundRect, int16 deltaY,
uint8 r, uint8 g, uint8 b) const {
uint16 cardBackground = _vm->getCard()->getBackgroundImageId();
MystAreaImageSwitch::SubImage highlighted = area->getSubImage(subimageIndex);
Common::Rect subImageRect(0, 0, backgroundRect.width(), backgroundRect.height());
// Create an image exactly the size of the rendered text with the backdrop as a background
_vm->_gfx->replaceImageWithRect(highlighted.wdib, cardBackground, backgroundRect);
area->setSubImageRect(subimageIndex, subImageRect);
// Draw the text in the subimage
_vm->_gfx->drawText(highlighted.wdib, text, subImageRect, r, g, b, align, deltaY);
}
void Menu::o_menuItemEnter(uint16 var, const ArgumentsArray &args) {
_menuItemHovered[var - 1000] = true;
_vm->getCard()->redrawArea(var);
}
void Menu::o_menuItemLeave(uint16 var, const ArgumentsArray &args) {
_menuItemHovered[var - 1000] = false;
_vm->getCard()->redrawArea(var);
}
void Menu::o_menuResume(uint16 var, const ArgumentsArray &args) {
if (!_inGame) {
return;
}
_vm->resumeFromMainMenu();
}
void Menu::o_menuLoad(uint16 var, const ArgumentsArray &args) {
if (!showConfirmationDialog(_("Are you sure you want to load a saved game? All unsaved progress will be lost."),
_("Load game"), _("Cancel"))) {
return;
}
_vm->loadGameDialog();
}
void Menu::o_menuSave(uint16 var, const ArgumentsArray &args) {
if (!_canSave) {
return;
}
_vm->saveGameDialog();
}
void Menu::o_menuNew(uint16 var, const ArgumentsArray &args) {
if (!showConfirmationDialog(_("Are you sure you want to start a new game? All unsaved progress will be lost."),
_("New game"), _("Cancel"))) {
return;
}
_vm->_gameState->reset();
_vm->setTotalPlayTime(0);
_vm->setMainCursor(kDefaultMystCursor);
_vm->changeToStack(kIntroStack, 1, 0, 0);
}
void Menu::o_menuOptions(uint16 var, const ArgumentsArray &args) {
resetButtons();
_vm->runOptionsDialog();
}
void Menu::o_menuQuit(uint16 var, const ArgumentsArray &args) {
if (!showConfirmationDialog(_("Are you sure you want to quit? All unsaved progress will be lost."), _("Quit"),
_("Cancel"))) {
return;
}
_vm->changeToStack(kCreditsStack, 10000, 0, 0);
}
void Menu::o_menuExit(uint16 var, const ArgumentsArray &args) {
if (_inGame) {
_vm->_gfx->restoreStateForMainMenu();
}
CursorMan.showMouse(_wasCursorVisible);
_pauseToken.clear();
}
void Menu::o_playIntroMovies(uint16 var, const ArgumentsArray &args) {
_introMoviesRunning = true;
_introStep = 0;
}
void Menu::introMovies_run() {
// Play Intro Movies
// This is all quite messy...
VideoEntryPtr video;
switch (_introStep) {
case 0:
_introStep = 1;
video = _vm->playMovieFullscreen("broder", kIntroStack);
break;
case 1:
if (!_vm->_video->isVideoPlaying())
_introStep = 2;
break;
case 2:
_introStep = 3;
video = _vm->playMovieFullscreen("cyanlogo", kIntroStack);
break;
case 3:
if (!_vm->_video->isVideoPlaying())
_introStep = 4;
break;
default:
_vm->changeToCard(1000, kTransitionCopy);
}
}
bool Menu::showConfirmationDialog(const Common::U32String &message, const Common::U32String &confirmButton, const Common::U32String &cancelButton) {
if (!_inGame) {
return true;
}
resetButtons();
GUI::MessageDialog dialog(message, confirmButton, cancelButton);
return dialog.runModal() == GUI::kMessageOK;
}
void Menu::resetButtons() {
for (uint i = 0; i < ARRAYSIZE(_menuItemHovered); i++) {
_menuItemHovered[i] = false;
_vm->getCard()->redrawArea(1000 + i);
}
_vm->doFrame();
}
} // End of namespace MystStacks
} // End of namespace Mohawk

View File

@@ -0,0 +1,100 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef MYST_SCRIPTS_MENU_H
#define MYST_SCRIPTS_MENU_H
#include "mohawk/myst_scripts.h"
#include "common/scummsys.h"
#include "common/util.h"
#include "graphics/font.h"
namespace Mohawk {
class MystAreaVideo;
struct MystScriptEntry;
namespace MystStacks {
#define DECLARE_OPCODE(x) void x(uint16 var, const ArgumentsArray &args)
class Menu : public MystScriptParser {
public:
explicit Menu(MohawkEngine_Myst *vm);
~Menu() override;
void setInGame(bool inGame) {
_inGame = inGame;
}
void setCanSave(bool canSave) {
_canSave = canSave;
}
void disablePersistentScripts() override;
void runPersistentScripts() override;
private:
void setupOpcodes();
uint16 getVar(uint16 var) override;
DECLARE_OPCODE(o_playIntroMovies);
DECLARE_OPCODE(o_menuItemEnter);
DECLARE_OPCODE(o_menuItemLeave);
DECLARE_OPCODE(o_menuResume);
DECLARE_OPCODE(o_menuLoad);
DECLARE_OPCODE(o_menuSave);
DECLARE_OPCODE(o_menuNew);
DECLARE_OPCODE(o_menuOptions);
DECLARE_OPCODE(o_menuQuit);
DECLARE_OPCODE(o_menuInit);
DECLARE_OPCODE(o_menuExit);
bool _inGame;
bool _canSave;
bool _menuItemHovered[6];
bool _wasCursorVisible;
bool _introMoviesRunning;
int _introStep;
void introMovies_run();
bool showConfirmationDialog(const Common::U32String &message, const Common::U32String &confirmButton, const Common::U32String &cancelButton);
void drawButtonImages(const Common::U32String &text, MystAreaImageSwitch *area, Graphics::TextAlign align, uint16 highlightedIndex, uint16 disabledIndex) const;
void replaceButtonSubImageWithText(const Common::U32String &text, const Graphics::TextAlign &align, MystAreaImageSwitch *area,
uint16 subimageIndex, const Common::Rect &backgroundRect, int16 deltaY,
uint8 r, uint8 g, uint8 b) const;
const char **getButtonCaptions() const;
void resetButtons();
PauseToken _pauseToken;
};
} // End of namespace MystStacks
} // End of namespace Mohawk
#undef DECLARE_OPCODE
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,373 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef MYST_SCRIPTS_MYST_H
#define MYST_SCRIPTS_MYST_H
#include "common/scummsys.h"
#include "common/util.h"
#include "mohawk/myst_scripts.h"
namespace Mohawk {
struct MystScriptEntry;
namespace MystStacks {
#define DECLARE_OPCODE(x) void x(uint16 var, const ArgumentsArray &args)
class Myst : public MystScriptParser {
public:
explicit Myst(MohawkEngine_Myst *vm, MystStack stackId = kMystStack);
~Myst() override;
void disablePersistentScripts() override;
void runPersistentScripts() override;
protected:
void setupOpcodes();
uint16 getVar(uint16 var) override;
void toggleVar(uint16 var) override;
bool setVarValue(uint16 var, uint16 value) override;
uint16 getMap() override { return 9934; }
void towerRotationMap_run();
virtual void libraryBookcaseTransform_run();
void generatorControlRoom_run();
void libraryCombinationBook_run();
void libraryBook_run();
void clockWheel_run();
void matchBurn_run();
void boilerPressureIncrease_run();
void boilerPressureDecrease_run();
void basementPressureIncrease_run();
void basementPressureDecrease_run();
void tree_run();
void imagerValidation_run();
void imager_run();
void observatory_run();
void observatoryMonthChange_run();
void observatoryDayChange_run();
void observatoryYearChange_run();
void observatoryTimeChange_run();
void greenBook_run();
void clockGears_run();
void gullsFly1_run();
void gullsFly2_run();
void gullsFly3_run();
DECLARE_OPCODE(o_libraryBookPageTurnLeft);
DECLARE_OPCODE(o_libraryBookPageTurnRight);
DECLARE_OPCODE(o_fireplaceToggleButton);
DECLARE_OPCODE(o_fireplaceRotation);
DECLARE_OPCODE(o_courtyardBoxesCheckSolution);
DECLARE_OPCODE(o_towerRotationStart);
DECLARE_OPCODE(o_towerRotationEnd);
DECLARE_OPCODE(o_imagerChangeSelection);
DECLARE_OPCODE(o_dockVaultOpen);
DECLARE_OPCODE(o_dockVaultClose);
DECLARE_OPCODE(o_bookGivePage);
DECLARE_OPCODE(o_clockWheelsExecute);
DECLARE_OPCODE(o_imagerPlayButton);
DECLARE_OPCODE(o_imagerEraseButton);
DECLARE_OPCODE(o_towerElevatorAnimation);
DECLARE_OPCODE(o_generatorButtonPressed);
DECLARE_OPCODE(o_cabinSafeChangeDigit);
DECLARE_OPCODE(o_cabinSafeHandleStartMove);
DECLARE_OPCODE(o_cabinSafeHandleMove);
DECLARE_OPCODE(o_cabinSafeHandleEndMove);
DECLARE_OPCODE(o_treePressureReleaseStart);
DECLARE_OPCODE(o_observatoryMonthChangeStartIncrease);
DECLARE_OPCODE(o_observatoryMonthChangeStartDecrease);
DECLARE_OPCODE(o_observatoryDayChangeStartIncrease);
DECLARE_OPCODE(o_observatoryDayChangeStartDecrease);
DECLARE_OPCODE(o_observatoryGoButton);
DECLARE_OPCODE(o_observatoryMonthSliderMove);
DECLARE_OPCODE(o_observatoryDaySliderMove);
DECLARE_OPCODE(o_observatoryYearSliderMove);
DECLARE_OPCODE(o_observatoryTimeSliderMove);
DECLARE_OPCODE(o_circuitBreakerStartMove);
DECLARE_OPCODE(o_circuitBreakerMove);
DECLARE_OPCODE(o_circuitBreakerEndMove);
DECLARE_OPCODE(o_boilerIncreasePressureStart);
DECLARE_OPCODE(o_boilerLightPilot);
DECLARE_OPCODE(o_boilerIncreasePressureStop);
DECLARE_OPCODE(o_boilerDecreasePressureStart);
DECLARE_OPCODE(o_boilerDecreasePressureStop);
DECLARE_OPCODE(o_basementIncreasePressureStart);
DECLARE_OPCODE(o_basementIncreasePressureStop);
DECLARE_OPCODE(o_basementDecreasePressureStart);
DECLARE_OPCODE(o_basementDecreasePressureStop);
DECLARE_OPCODE(o_rocketPianoStart);
DECLARE_OPCODE(o_rocketPianoMove);
DECLARE_OPCODE(o_rocketPianoStop);
DECLARE_OPCODE(o_rocketSoundSliderStartMove);
DECLARE_OPCODE(o_rocketSoundSliderMove);
DECLARE_OPCODE(o_rocketSoundSliderEndMove);
DECLARE_OPCODE(o_rocketLeverStartMove);
DECLARE_OPCODE(o_rocketOpenBook);
DECLARE_OPCODE(o_rocketLeverMove);
DECLARE_OPCODE(o_rocketLeverEndMove);
DECLARE_OPCODE(o_cabinLeave);
DECLARE_OPCODE(o_treePressureReleaseStop);
DECLARE_OPCODE(o_observatoryMonthSliderStartMove);
DECLARE_OPCODE(o_observatoryMonthSliderEndMove);
DECLARE_OPCODE(o_observatoryDaySliderStartMove);
DECLARE_OPCODE(o_observatoryDaySliderEndMove);
DECLARE_OPCODE(o_observatoryYearSliderStartMove);
DECLARE_OPCODE(o_observatoryYearSliderEndMove);
DECLARE_OPCODE(o_observatoryTimeSliderStartMove);
DECLARE_OPCODE(o_observatoryTimeSliderEndMove);
DECLARE_OPCODE(o_libraryBookPageTurnStartLeft);
DECLARE_OPCODE(o_libraryBookPageTurnStartRight);
DECLARE_OPCODE(o_libraryCombinationBookStop);
DECLARE_OPCODE(o_cabinMatchLight);
DECLARE_OPCODE(o_courtyardBoxEnter);
DECLARE_OPCODE(o_courtyardBoxLeave);
DECLARE_OPCODE(o_clockMinuteWheelStartTurn);
DECLARE_OPCODE(o_clockWheelEndTurn);
DECLARE_OPCODE(o_clockHourWheelStartTurn);
DECLARE_OPCODE(o_clockLeverStartMove);
DECLARE_OPCODE(o_clockLeverMoveLeft);
DECLARE_OPCODE(o_clockLeverMoveRight);
DECLARE_OPCODE(o_clockLeverEndMove);
DECLARE_OPCODE(o_clockResetLeverStartMove);
DECLARE_OPCODE(o_clockResetLeverMove);
DECLARE_OPCODE(o_clockResetLeverEndMove);
DECLARE_OPCODE(o_libraryCombinationBookStartRight);
DECLARE_OPCODE(o_libraryCombinationBookStartLeft);
DECLARE_OPCODE(o_observatoryTimeChangeStartIncrease);
DECLARE_OPCODE(o_observatoryTimeChangeStartDecrease);
DECLARE_OPCODE(o_observatoryChangeSettingStop);
DECLARE_OPCODE(o_observatoryYearChangeStartIncrease);
DECLARE_OPCODE(o_observatoryYearChangeStartDecrease);
DECLARE_OPCODE(o_dockVaultForceClose);
DECLARE_OPCODE(o_imagerEraseStop);
DECLARE_OPCODE(o_libraryBook_init);
DECLARE_OPCODE(o_courtyardBox_init);
DECLARE_OPCODE(o_towerRotationMap_init);
DECLARE_OPCODE(o_forechamberDoor_init);
DECLARE_OPCODE(o_shipAccess_init);
DECLARE_OPCODE(o_butterflies_init);
DECLARE_OPCODE(o_imager_init);
DECLARE_OPCODE(o_libraryBookcaseTransform_init);
DECLARE_OPCODE(o_generatorControlRoom_init);
DECLARE_OPCODE(o_fireplace_init);
DECLARE_OPCODE(o_clockGears_init);
DECLARE_OPCODE(o_gulls1_init);
DECLARE_OPCODE(o_observatory_init);
DECLARE_OPCODE(o_gulls2_init);
DECLARE_OPCODE(o_treeCard_init);
DECLARE_OPCODE(o_treeEntry_init);
DECLARE_OPCODE(o_boilerMovies_init);
DECLARE_OPCODE(o_rocketSliders_init);
DECLARE_OPCODE(o_rocketLinkVideo_init);
DECLARE_OPCODE(o_greenBook_init);
DECLARE_OPCODE(o_gulls3_init);
DECLARE_OPCODE(o_bookAddSpecialPage_exit);
DECLARE_OPCODE(o_treeCard_exit);
DECLARE_OPCODE(o_treeEntry_exit);
DECLARE_OPCODE(o_boiler_exit);
DECLARE_OPCODE(o_generatorControlRoom_exit);
DECLARE_OPCODE(o_rocketSliders_exit);
MystGameState::Myst &_state;
bool _generatorControlRoomRunning;
uint16 _generatorVoltage; // 58
uint16 _rocketPianoSound; // 292
MystAreaSlider *_rocketSlider1; // 248
MystAreaSlider *_rocketSlider2; // 252
MystAreaSlider *_rocketSlider3; // 256
MystAreaSlider *_rocketSlider4; // 260
MystAreaSlider *_rocketSlider5; // 264
uint16 _rocketSliderSound; // 294
uint16 _rocketLeverPosition; // 296
VideoEntryPtr _rocketLinkBook; // 268
bool _libraryBookPagesTurning;
bool _libraryCombinationBookPagesTurning;
int16 _libraryBookPage; // 86
uint16 _libraryBookNumPages; // 88
uint16 _libraryBookBaseImage; // 90
bool _butterfliesMoviePlayed; // 100
bool _gullsFlying1;
bool _gullsFlying2;
bool _gullsFlying3;
uint32 _gullsNextTime; // 216
bool _libraryBookcaseMoving;
MystAreaVideo *_libraryBookcaseMovie; // 104
uint16 _libraryBookcaseSoundId; // 284
bool _libraryBookcaseChanged; // 288
uint16 _libraryBookSound1; // 298
uint16 _libraryBookSound2; // 300
uint16 _courtyardBoxSound; // 302
bool _imagerValidationRunning;
MystAreaImageSwitch *_imagerRedButton; // 304
uint16 _imagerSound[4]; // 308 to 314
uint16 _imagerValidationCard; // 316
uint16 _imagerValidationStep; // 318
bool _imagerRunning;
MystAreaVideo *_imagerMovie; // 64
uint16 _fireplaceLines[6]; // 74 to 84
uint16 _clockTurningWheel;
VideoEntryPtr _clockGearsVideos[3]; // 148 to 156
VideoEntryPtr _clockWeightVideo; // 160
uint16 _clockGearsPositions[3]; // 164 to 168
uint16 _clockWeightPosition; // 172
bool _clockMiddleGearMovedAlone; // 176
bool _clockLeverPulled; // 328
uint16 _dockVaultState; // 92
bool _towerRotationMapRunning;
bool _towerRotationBlinkLabel;
uint16 _towerRotationBlinkLabelCount;
uint16 _towerRotationMapInitialized; // 292
MystAreaImageSwitch *_towerRotationMapTower; // 108
MystAreaImageSwitch *_towerRotationMapLabel; // 112
uint16 _towerRotationSpeed; // 124
bool _towerRotationMapClicked; // 132
bool _towerRotationOverSpot; // 136
const Common::Point _towerRotationCenter;
bool _matchBurning;
uint16 _matchGoOutCnt;
uint16 _cabinDoorOpened; // 56
uint16 _cabinHandleDown; // 344
uint16 _cabinMatchState; // 60
uint32 _matchGoOutTime; // 144
VideoEntryPtr _cabinFireMovie; // 240
bool _cabinGaugeMovieEnabled;
VideoEntryPtr _cabinGaugeMovie; // 244
bool _boilerPressureIncreasing;
bool _boilerPressureDecreasing;
bool _basementPressureIncreasing;
bool _basementPressureDecreasing;
bool _treeStopped; // 236
MystAreaImageSwitch *_tree; // 220
MystArea *_treeAlcove; // 224
uint16 _treeMinPosition; // 228
uint16 _treeMinAccessiblePosition; // 230
uint16 _treeMaxAccessiblePosition; // 232
bool _observatoryRunning;
bool _observatoryMonthChanging;
bool _observatoryDayChanging;
bool _observatoryYearChanging;
bool _observatoryTimeChanging;
MystAreaImageSwitch *_observatoryVisualizer; // 184
MystAreaImageSwitch *_observatoryGoButton; // 188
MystAreaSlider *_observatoryDaySlider; // 192
MystAreaSlider *_observatoryMonthSlider; // 196
MystAreaSlider *_observatoryYearSlider; // 200
MystAreaSlider *_observatoryTimeSlider; // 204
uint32 _observatoryLastTime; // 208
bool _observatoryNotInitialized; // 212
int16 _observatoryIncrement; // 346
MystAreaSlider *_observatoryCurrentSlider; // 348
bool _greenBookRunning;
void generatorRedrawRocket();
void generatorButtonValue(MystArea *button, uint16 &offset, uint16 &value);
void rocketSliderMove();
uint16 rocketSliderGetSound(uint16 pos);
uint16 rocketCheckIfSoundMatches(uint16 sound1, uint16 sound2);
void rocketCheckSolution();
void libraryBookPageTurnLeft();
void libraryBookPageTurnRight();
void libraryCombinationBookTurnRight();
void libraryCombinationBookTurnLeft();
uint16 bookCountPages(uint16 var);
void clockWheelStartTurn(uint16 wheel);
void clockWheelTurn(uint16 var);
void clockLeverMove(bool leftLever);
void clockGearForwardOneStep(uint16 gear);
void clockWeightDownOneStep();
void clockGearsCheckSolution();
void clockReset();
void clockResetWeight();
void clockResetGear(uint16 gear);
void towerRotationMapRotate();
void towerRotationMapRedraw();
void towerRotationDrawBuildings();
uint16 towerRotationMapComputeAngle();
Common::Point towerRotationMapComputeCoords(uint16 angle);
void towerRotationMapDrawLine(const Common::Point &end, bool rotationLabelVisible);
void boilerFireInit();
void boilerFireUpdate(bool init);
void boilerGaugeInit();
Common::Rational boilerComputeGaugeRate(uint16 pressure, uint32 delay);
void boilerResetGauge(const Common::Rational &rate);
void treeSetAlcoveAccessible();
uint32 treeNextMoveDelay(uint16 pressure);
bool observatoryIsDDMMYYYY2400();
void observatorySetTargetToSetting();
void observatoryUpdateVisualizer(uint16 x, uint16 y);
void observatoryMonthChangeStart(bool increase);
void observatoryDayChangeStart(bool increase);
void observatoryYearChangeStart(bool increase);
void observatoryTimeChangeStart(bool increase);
void observatoryIncrementMonth(int16 increment);
void observatoryIncrementDay(int16 increment);
void observatoryIncrementYear(int16 increment);
void observatoryIncrementTime(int16 increment);
void observatoryUpdateMonth();
void observatoryUpdateDay();
void observatoryUpdateYear();
void observatoryUpdateTime();
};
} // End of namespace MystStacks
} // End of namespace Mohawk
#undef DECLARE_OPCODE
#endif

View File

@@ -0,0 +1,247 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include "mohawk/cursors.h"
#include "mohawk/myst.h"
#include "mohawk/myst_areas.h"
#include "mohawk/myst_graphics.h"
#include "mohawk/myst_sound.h"
#include "mohawk/video.h"
#include "mohawk/myst_stacks/preview.h"
#include "common/system.h"
#include "common/translation.h"
#include "gui/message.h"
namespace Mohawk {
namespace MystStacks {
Preview::Preview(MohawkEngine_Myst *vm) :
Myst(vm, kDemoPreviewStack) {
setupOpcodes();
_vm->_cursor->hideCursor();
_libraryState = 0;
_library = nullptr;
_speechRunning = false;
_speechStep = 0;
_currentCue = 0;
_speechNextTime = 0;
}
Preview::~Preview() {
}
void Preview::setupOpcodes() {
// "Stack-Specific" Opcodes
OVERRIDE_OPCODE(196, Preview, o_fadeToBlack);
OVERRIDE_OPCODE(197, Preview, o_fadeFromBlack);
OVERRIDE_OPCODE(198, Preview, o_stayHere);
OVERRIDE_OPCODE(199, Preview, o_speechStop);
// "Init" Opcodes
OVERRIDE_OPCODE(209, Preview, o_libraryBookcaseTransformDemo_init);
REGISTER_OPCODE(298, Preview, o_speech_init);
REGISTER_OPCODE(299, Preview, o_library_init);
}
void Preview::disablePersistentScripts() {
Myst::disablePersistentScripts();
}
void Preview::runPersistentScripts() {
Myst::runPersistentScripts();
if (_speechRunning)
speech_run();
}
void Preview::o_fadeToBlack(uint16 var, const ArgumentsArray &args) {
_vm->_gfx->fadeToBlack();
}
void Preview::o_fadeFromBlack(uint16 var, const ArgumentsArray &args) {
_vm->_gfx->fadeFromBlack();
}
void Preview::o_stayHere(uint16 var, const ArgumentsArray &args) {
// Nuh-uh! No leaving the library in the demo!
GUI::MessageDialog dialog(_("You can't leave the library in the demo."));
dialog.runModal();
}
void Preview::o_speechStop(uint16 var, const ArgumentsArray &args) {
_vm->_sound->stopSpeech();
_speechRunning = false;
_globals.currentAge = kMystLibrary;
}
void Preview::speechUpdateCue() {
// This is a callback in the original, handling audio events.
if (!_vm->_sound->isSpeechPlaying()) {
return;
}
uint samples = _vm->_sound->getSpeechNumSamplesPlayed();
for (int16 i = 0; i < _cueList.pointCount; i++) {
if (_cueList.points[i].sampleFrame > samples)
return;
if (i > _currentCue - 1) {
_currentCue++;
debugC(kDebugScript, "Sneak speech advanced to cue %d", _currentCue);
}
}
}
void Preview::speech_run() {
uint32 time = _vm->getTotalPlayTime();
// Update current speech sound cue
speechUpdateCue();
switch (_speechStep) {
case 0: // Start Voice Over... which controls book opening
_currentCue = 0;
_vm->_sound->playSpeech(3001, &_cueList);
_speechStep++;
break;
case 1: // Open book
if (_currentCue >= 1) {
_vm->changeToCard(3001, kTransitionDissolve);
_speechStep++;
}
break;
case 2: // Go to Myst
if (_currentCue >= 2) {
_vm->_gfx->fadeToBlack();
_vm->changeToCard(3002, kNoTransition);
_vm->_gfx->fadeFromBlack();
_speechStep++;
}
break;
case 3: // Start blinking the library
if (_currentCue >= 3) {
_libraryState = 1;
_speechNextTime = 0;
_speechStep++;
}
break;
case 4: // Library blinking, zoom in library
if (_currentCue >= 4) {
_library->drawConditionalDataToScreen(0);
_vm->changeToCard(3003, kTransitionDissolve);
_speechNextTime = time + 2000;
_speechStep++;
} else {
if (time < _speechNextTime)
break;
_library->drawConditionalDataToScreen(_libraryState);
_libraryState = (_libraryState + 1) % 2;
_speechNextTime = time + 500;
}
break;
case 5: // Go to library near view
if (time < _speechNextTime)
break;
_vm->changeToCard(3004, kTransitionDissolve);
_speechNextTime = time + 2000;
_speechStep++;
break;
case 6: // Fade to courtyard
if (time < _speechNextTime)
break;
_vm->_gfx->fadeToBlack();
_vm->changeToCard(3005, kNoTransition);
_vm->_gfx->fadeFromBlack();
_speechNextTime = time + 1000;
_speechStep++;
break;
case 7: // Walk to library
case 8:
case 9:
case 10:
case 11:
case 12:
case 13:
if (time < _speechNextTime)
break;
_vm->changeToCard(3006 + _speechStep - 7, kTransitionDissolve);
_speechNextTime = time + 2000;
_speechStep++;
break;
case 14: // Go to playable library card
if (time < _speechNextTime)
break;
_vm->changeToCard(4329, kTransitionDissolve);
_speechRunning = false;
_globals.currentAge = kMystLibrary;
_vm->_cursor->showCursor();
break;
default:
warning("Unknown speech step");
break;
}
}
void Preview::o_speech_init(uint16 var, const ArgumentsArray &args) {
// Used for Card 3000 (Closed Myst Book)
_speechStep = 0;
_speechRunning = true;
}
void Preview::o_library_init(uint16 var, const ArgumentsArray &args) {
// Used for Card 3002 (Myst Island Overview)
_library = getInvokingResource<MystAreaImageSwitch>();
}
void Preview::o_libraryBookcaseTransformDemo_init(uint16 var, const ArgumentsArray &args) {
if (_libraryBookcaseChanged) {
MystAreaActionSwitch *resource = getInvokingResource<MystAreaActionSwitch>();
_libraryBookcaseMovie = static_cast<MystAreaVideo *>(resource->getSubResource(getVar(303)));
_libraryBookcaseSoundId = args[0];
_libraryBookcaseMoving = true;
}
}
void Preview::libraryBookcaseTransform_run() {
if (_libraryBookcaseChanged)
_state.libraryBookcaseDoor = !_state.libraryBookcaseDoor;
Myst::libraryBookcaseTransform_run();
}
} // End of namespace MystStacks
} // End of namespace Mohawk

View File

@@ -0,0 +1,79 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef MYST_SCRIPTS_PREVIEW_H
#define MYST_SCRIPTS_PREVIEW_H
#include "mohawk/sound.h"
#include "mohawk/myst_stacks/myst.h"
#include "common/scummsys.h"
#include "common/util.h"
namespace Mohawk {
struct MystScriptEntry;
namespace MystStacks {
#define DECLARE_OPCODE(x) void x(uint16 var, const ArgumentsArray &args)
class Preview : public Myst {
public:
explicit Preview(MohawkEngine_Myst *vm);
~Preview() override;
void disablePersistentScripts() override;
void runPersistentScripts() override;
private:
void setupOpcodes();
DECLARE_OPCODE(o_fadeToBlack);
DECLARE_OPCODE(o_fadeFromBlack);
DECLARE_OPCODE(o_stayHere);
DECLARE_OPCODE(o_speechStop);
DECLARE_OPCODE(o_libraryBookcaseTransformDemo_init);
DECLARE_OPCODE(o_speech_init);
DECLARE_OPCODE(o_library_init);
uint16 _libraryState; // 4
MystAreaImageSwitch *_library; // 32
bool _speechRunning;
uint _speechStep;
CueList _cueList;
int16 _currentCue;
uint32 _speechNextTime; // 6
void speech_run();
void speechUpdateCue();
void libraryBookcaseTransform_run() override;
};
} // End of namespace MystStacks
} // End of namespace Mohawk
#undef DECLARE_OPCODE
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,152 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef MYST_SCRIPTS_SELENITIC_H
#define MYST_SCRIPTS_SELENITIC_H
#include "common/scummsys.h"
#include "common/util.h"
#include "mohawk/myst_scripts.h"
namespace Mohawk {
class MystAreaImageSwitch;
struct MystScriptEntry;
namespace MystStacks {
#define DECLARE_OPCODE(x) void x(uint16 var, const ArgumentsArray &args)
class Selenitic : public MystScriptParser {
public:
explicit Selenitic(MohawkEngine_Myst *vm);
~Selenitic() override;
void disablePersistentScripts() override;
void runPersistentScripts() override;
private:
void setupOpcodes();
uint16 getVar(uint16 var) override;
void toggleVar(uint16 var) override;
bool setVarValue(uint16 var, uint16 value) override;
uint16 getMap() override { return 9930; }
DECLARE_OPCODE(o_mazeRunnerMove);
DECLARE_OPCODE(o_mazeRunnerSoundRepeat);
DECLARE_OPCODE(o_soundReceiverSigma);
DECLARE_OPCODE(o_soundReceiverRight);
DECLARE_OPCODE(o_soundReceiverLeft);
DECLARE_OPCODE(o_soundReceiverSource);
DECLARE_OPCODE(o_mazeRunnerDoorButton);
DECLARE_OPCODE(o_soundReceiverUpdateSound);
DECLARE_OPCODE(o_soundLockMove);
DECLARE_OPCODE(o_soundLockStartMove);
DECLARE_OPCODE(o_soundLockEndMove);
DECLARE_OPCODE(o_soundLockButton);
DECLARE_OPCODE(o_soundReceiverEndMove);
DECLARE_OPCODE(o_mazeRunnerCompass_init);
DECLARE_OPCODE(o_mazeRunnerWindow_init);
DECLARE_OPCODE(o_mazeRunnerLight_init);
DECLARE_OPCODE(o_soundReceiver_init);
DECLARE_OPCODE(o_soundLock_init);
DECLARE_OPCODE(o_mazeRunnerRight_init);
DECLARE_OPCODE(o_mazeRunnerLeft_init);
enum SoundReceiverSpeed {
kSoundReceiverSpeedStill = 0,
kSoundReceiverSpeedSlow = 1,
kSoundReceiverSpeedNormal = 5, // The original has this at 10
kSoundReceiverSpeedFast = 10, // The original has this at 50 too fast!
kSoundReceiverSpeedFaster = 13 // The original has this at 100, way too fast!
};
void soundReceiver_run();
MystGameState::Selenitic &_state;
bool _soundReceiverRunning;
bool _soundReceiverSigmaPressed; // 6
MystAreaImageSwitch *_soundReceiverSources[5]; // 92 -> 108
MystAreaImageSwitch *_soundReceiverCurrentSource; // 112
uint16 *_soundReceiverPosition; // 116
uint16 _soundReceiverDirection; // 120
SoundReceiverSpeed _soundReceiverSpeed; // 122
uint32 _soundReceiverStartTime; //124
uint _soundReceiverNearBlinkCounter;
MystAreaImageSwitch *_soundReceiverViewer; // 128
MystAreaImageSwitch *_soundReceiverRightButton; // 132
MystAreaImageSwitch *_soundReceiverLeftButton; // 136
MystAreaImageSwitch *_soundReceiverAngle1; // 140
MystAreaImageSwitch *_soundReceiverAngle2; // 144
MystAreaImageSwitch *_soundReceiverAngle3; // 148
MystAreaImageSwitch *_soundReceiverAngle4; // 152
MystAreaImageSwitch *_soundReceiverSigmaButton; // 156
static const uint16 _mazeRunnerMap[300][4];
static const uint8 _mazeRunnerVideos[300][4];
uint16 _mazeRunnerPosition; // 56
uint16 _mazeRunnerDirection; // 58
MystAreaImageSwitch *_mazeRunnerWindow; // 68
MystAreaImageSwitch *_mazeRunnerCompass; // 72
MystAreaImageSwitch *_mazeRunnerLight; // 76
MystAreaImageSwitch *_mazeRunnerRightButton; // 80
MystAreaImageSwitch *_mazeRunnerLeftButton; // 84
bool _mazeRunnerDoorOpened; // 160
uint16 _soundLockSoundId;
MystAreaSlider *_soundLockSlider1; // 164
MystAreaSlider *_soundLockSlider2; // 168
MystAreaSlider *_soundLockSlider3; // 172
MystAreaSlider *_soundLockSlider4; // 176
MystAreaSlider *_soundLockSlider5; // 180
MystAreaImageSwitch *_soundLockButton; // 184
void soundReceiverLeftRight(uint direction);
void soundReceiverUpdate();
void soundReceiverSetSubimageRect() const;
void soundReceiverDrawView();
void soundReceiverDrawAngle();
void soundReceiverIncreaseSpeed();
void soundReceiverUpdateSound();
uint16 soundReceiverCurrentSound(uint16 source, uint16 position);
void soundReceiverSolution(uint16 source, uint16 &solution, bool &enabled);
uint16 soundLockCurrentSound(uint16 position, bool pixels);
MystAreaSlider *soundLockSliderFromVar(uint16 var);
void soundLockCheckSolution(MystAreaSlider *slider, uint16 value, uint16 solution, bool &solved);
bool mazeRunnerForwardAllowed(uint16 position);
void mazeRunnerUpdateCompass();
void mazeRunnerPlaySoundHelp();
void mazeRunnerPlayVideo(uint16 video, uint16 pos);
void mazeRunnerBacktrack(uint16 &oldPosition);
};
} // End of namespace MystStacks
}
#undef DECLARE_OPCODE
#endif

View File

@@ -0,0 +1,85 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include "mohawk/cursors.h"
#include "mohawk/myst.h"
#include "mohawk/myst_areas.h"
#include "mohawk/myst_graphics.h"
#include "mohawk/sound.h"
#include "mohawk/video.h"
#include "mohawk/myst_stacks/slides.h"
#include "common/system.h"
namespace Mohawk {
namespace MystStacks {
Slides::Slides(MohawkEngine_Myst *vm) :
MystScriptParser(vm, kDemoSlidesStack) {
setupOpcodes();
_vm->_cursor->hideCursor();
_cardSwapEnabled = false;
_nextCardID = 0;
_nextCardTime = 0;
}
Slides::~Slides() {
}
void Slides::setupOpcodes() {
// "Stack-Specific" Opcodes
REGISTER_OPCODE(100, Slides, o_returnToMenu);
// "Init" Opcodes
REGISTER_OPCODE(200, Slides, o_setCardSwap);
}
void Slides::disablePersistentScripts() {
_cardSwapEnabled = false;
}
void Slides::runPersistentScripts() {
if (_cardSwapEnabled) {
// Used on Cards...
if (_vm->getTotalPlayTime() > _nextCardTime) {
_vm->_gfx->fadeToBlack();
_vm->changeToCard(_nextCardID, kNoTransition);
_vm->_gfx->fadeFromBlack();
}
}
}
void Slides::o_returnToMenu(uint16 var, const ArgumentsArray &args) {
// Go to the information screens of the menu
_vm->changeToStack(kDemoStack, 2002, 0, 0);
}
void Slides::o_setCardSwap(uint16 var, const ArgumentsArray &args) {
_nextCardID = args[0];
_nextCardTime = _vm->getTotalPlayTime() + 5000;
_cardSwapEnabled = true;
}
} // End of namespace MystStacks
} // End of namespace Mohawk

View File

@@ -0,0 +1,62 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef MYST_SCRIPTS_SLIDES_H
#define MYST_SCRIPTS_SLIDES_H
#include "common/scummsys.h"
#include "common/util.h"
#include "mohawk/myst_scripts.h"
namespace Mohawk {
struct MystScriptEntry;
namespace MystStacks {
#define DECLARE_OPCODE(x) void x(uint16 var, const ArgumentsArray &args)
class Slides : public MystScriptParser {
public:
explicit Slides(MohawkEngine_Myst *vm);
~Slides() override;
void disablePersistentScripts() override;
void runPersistentScripts() override;
private:
void setupOpcodes();
DECLARE_OPCODE(o_returnToMenu);
DECLARE_OPCODE(o_setCardSwap);
bool _cardSwapEnabled;
uint16 _nextCardID;
uint32 _nextCardTime;
};
} // End of namespace MystStacks
} // End of namespace Mohawk
#undef DECLARE_OPCODE
#endif

View File

@@ -0,0 +1,966 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include "mohawk/cursors.h"
#include "mohawk/myst.h"
#include "mohawk/myst_areas.h"
#include "mohawk/myst_card.h"
#include "mohawk/myst_graphics.h"
#include "mohawk/myst_state.h"
#include "mohawk/myst_sound.h"
#include "mohawk/video.h"
#include "mohawk/myst_stacks/stoneship.h"
#include "common/events.h"
#include "common/system.h"
#include "common/textconsole.h"
namespace Mohawk {
namespace MystStacks {
Stoneship::Stoneship(MohawkEngine_Myst *vm) :
MystScriptParser(vm, kStoneshipStack),
_state(vm->_gameState->_stoneship) {
setupOpcodes();
_tunnelRunning = false;
_tunnelNextTime = 0;
_tunnelAlarmSound = 0;
_tunnelImagesCount = 0;
_state.lightState = 0;
_state.generatorDepletionTime = 0;
_state.generatorDuration = 0;
_cabinMystBookPresent = 0;
_siriusDrawerDrugsOpen = 0;
_chestDrawersOpen = 0;
_chestAchenarBottomDrawerClosed = 1;
_brotherDoorOpen = 0;
// Drop key
if (_state.trapdoorKeyState == 1)
_state.trapdoorKeyState = 2;
// Power is not available when loading
if (_state.sideDoorOpened)
_state.generatorPowerAvailable = 2;
else
_state.generatorPowerAvailable = 0;
_batteryCharging = false;
_batteryDepleting = false;
_batteryNextTime = 0;
_batteryLastCharge = 0;
_batteryGaugeRunning = false;
_batteryGauge = nullptr;
_hologramTurnedOn = 0;
_hologramDisplay = nullptr;
_hologramSelection = nullptr;
_hologramDisplayPos = 0;
_telescopeRunning = false;
_telescopePosition = 0;
_telescopePanorama = 0;
_telescopeOldMouse = 0;
_telescopeLighthouseOff = 0;
_telescopeLighthouseOn = 0;
_telescopeLighthouseState = false;
_telescopeNexTime = 0;
_cloudOrbMovie = nullptr;
_cloudOrbSound = 0;
_cloudOrbStopSound = 0;
}
Stoneship::~Stoneship() {
}
void Stoneship::setupOpcodes() {
// "Stack-Specific" Opcodes
REGISTER_OPCODE(100, Stoneship, o_pumpTurnOff);
REGISTER_OPCODE(101, Stoneship, o_brotherDoorOpen);
REGISTER_OPCODE(102, Stoneship, o_cabinBookMovie);
REGISTER_OPCODE(103, Stoneship, o_drawerOpenSirius);
REGISTER_OPCODE(104, Stoneship, o_drawerClose);
REGISTER_OPCODE(105, Stoneship, o_telescopeStart);
REGISTER_OPCODE(106, Stoneship, o_telescopeMove);
REGISTER_OPCODE(107, Stoneship, o_telescopeStop);
REGISTER_OPCODE(108, Stoneship, o_generatorStart);
REGISTER_OPCODE(109, Stoneship, NOP);
REGISTER_OPCODE(110, Stoneship, o_generatorStop);
REGISTER_OPCODE(111, Stoneship, o_drawerOpenAchenar);
REGISTER_OPCODE(112, Stoneship, o_hologramPlayback);
REGISTER_OPCODE(113, Stoneship, o_hologramSelectionStart);
REGISTER_OPCODE(114, Stoneship, o_hologramSelectionMove);
REGISTER_OPCODE(115, Stoneship, o_hologramSelectionStop);
REGISTER_OPCODE(116, Stoneship, o_compassButton);
REGISTER_OPCODE(117, Stoneship, o_chestValveVideos);
REGISTER_OPCODE(118, Stoneship, o_chestDropKey);
REGISTER_OPCODE(119, Stoneship, o_trapLockOpen);
REGISTER_OPCODE(120, Stoneship, o_sideDoorsMovies);
REGISTER_OPCODE(121, Stoneship, o_cloudOrbEnter);
REGISTER_OPCODE(122, Stoneship, o_cloudOrbLeave);
REGISTER_OPCODE(125, Stoneship, o_drawerCloseOpened);
// "Init" Opcodes
REGISTER_OPCODE(200, Stoneship, o_hologramDisplay_init);
REGISTER_OPCODE(201, Stoneship, o_hologramSelection_init);
REGISTER_OPCODE(202, Stoneship, o_battery_init);
REGISTER_OPCODE(203, Stoneship, o_tunnelEnter_init);
REGISTER_OPCODE(204, Stoneship, o_batteryGauge_init);
REGISTER_OPCODE(205, Stoneship, o_tunnel_init);
REGISTER_OPCODE(206, Stoneship, o_tunnelLeave_init);
REGISTER_OPCODE(207, Stoneship, o_chest_init);
REGISTER_OPCODE(208, Stoneship, o_telescope_init);
REGISTER_OPCODE(209, Stoneship, o_achenarDrawers_init);
REGISTER_OPCODE(210, Stoneship, o_cloudOrb_init);
// "Exit" Opcodes
REGISTER_OPCODE(300, Stoneship, NOP);
}
void Stoneship::disablePersistentScripts() {
_batteryCharging = false;
_batteryDepleting = false;
_batteryGaugeRunning = false;
_telescopeRunning = false;
}
void Stoneship::runPersistentScripts() {
if (_batteryCharging)
chargeBattery_run();
if (_telescopeRunning)
telescope_run();
if (_batteryGaugeRunning)
batteryGauge_run();
if (_batteryDepleting)
batteryDeplete_run();
if (_tunnelRunning)
tunnel_run();
}
uint16 Stoneship::getVar(uint16 var) {
switch(var) {
case 0: // Water Drained From Lighthouse / Right Button Of Pump
return _state.pumpState == 4;
case 1: // Water Drained From Tunnels To Brothers' Rooms / Middle Button Of Pump
return _state.pumpState == 2;
case 2: // Water Drained From Ship Cabin Tunnel / Left Button Of Pump
return _state.pumpState == 1;
case 3: // Lighthouse Chest Floating
return _state.pumpState != 4 && !_state.chestValveState && !_state.chestWaterState;
case 4: // Lighthouse State - Close Up
if (_state.pumpState == 4) {
return 1; // Drained
} else {
if (_state.chestValveState || _state.chestWaterState)
return 0; // Flooded
else
return 2; // Flooded, Chest Floating
}
case 5: // Lighthouse Trapdoor State
return _state.trapdoorState;
case 6: // Chest valve state
return _state.chestValveState;
case 7: // Lighthouse Chest Unlocked
return _state.chestOpenState;
case 8: // Lighthouse Chest Key Position
return _state.trapdoorKeyState;
case 11: // Lighthouse Key State
if (_state.chestOpenState) {
if (_state.trapdoorKeyState == 1)
return 1;
else if (_state.trapdoorKeyState == 2)
return 2;
else
return 3;
} else {
return 0;
}
case 12: // Trapdoor can be unlocked
return _state.trapdoorKeyState == 1 && _state.trapdoorState == 2;
case 13: // State Of Tunnels To Brothers' Rooms - Close Up
if (_state.generatorPowerAvailable != 1) {
if (_state.pumpState != 2)
return 0; // Dark, Flooded
else
return 1; // Dark, Drained
} else {
if (_state.pumpState != 2)
return 2; // Lit, Flooded
else
return 3; // Lit, Drained
}
case 14: // State Of Tunnels lights To Brothers' Rooms - Far
return _state.generatorPowerAvailable;
case 15: // Side Door in Tunnels To Brother's Rooms Open
if (_state.generatorPowerAvailable == 1)
return _state.sideDoorOpened;
else
return 0;
case 16: // Ship Chamber Light State
return _state.lightState;
case 17: // Sirrus' Room Drawer with Drugs Open
return _siriusDrawerDrugsOpen;
case 18: // Brother Room Door Open
return _brotherDoorOpen;
case 19: // Brother Room Door State
if (_brotherDoorOpen) {
if (_state.lightState)
return 2; // Open, Light On
else
return 1; // Open, Light Off
} else {
return 0; // Closed
}
case 20: // Ship Chamber Table/Book State
return _cabinMystBookPresent;
case 21: // Brothers Rooms' Chest Of Drawers Drawer State
return _chestDrawersOpen;
case 28: // Telescope Angle Position
return 0;
case 29: // Achenar's Room Rose/Skull Hologram Button Lit
return _hologramTurnedOn;
case 30: // Light State in Tunnel to Compass Rose Room
if (_state.generatorPowerAvailable == 1) {
if (_state.lightState)
return 0;
else
return 1;
} else {
return 2;
}
case 31: // Lighthouse Lamp Room Battery Pack Indicator Light
return batteryRemainingCharge() >= 10;
case 32: // Lighthouse Lamp Room Battery Pack Meter Level
return 0;
case 33: // State of Side Door in Tunnels to Compass Rose Room
if (_state.sideDoorOpened)
return 2;
else
return _state.generatorPowerAvailable == 1;
case 34: // Achenar's Room Drawer with Torn Note Closed
return _chestAchenarBottomDrawerClosed;
case 35: // Sirrus' Room Drawer #4 (Bottom) Open and Red Page State
if (_chestDrawersOpen == 4)
return getVar(102);
else
return 2;
case 36: // Ship Chamber Door State
if (_tempVar) {
if (_state.lightState)
return 2; // Open, Light On
else
return 1; // Open, Light Off
} else {
return 0; // Closed
}
case 102: // Red page
return !(_globals.redPagesInBook & 8) && (_globals.heldPage != kRedStoneshipPage);
case 103: // Blue page
return !(_globals.bluePagesInBook & 8) && (_globals.heldPage != kBlueStoneshipPage);
default:
return MystScriptParser::getVar(var);
}
}
void Stoneship::toggleVar(uint16 var) {
switch(var) {
case 0: // Water Drained From Lighthouse / Right Button Of Pump
if (_state.pumpState == 4)
_state.pumpState = 0;
else
_state.pumpState = 4;
break;
case 1: // Water Drained From Tunnels To Brothers' Rooms / Middle Button Of Pump
if (_state.pumpState == 2)
_state.pumpState = 0;
else
_state.pumpState = 2;
break;
case 2: // Water Drained From Ship Cabin Tunnel / Left Button Of Pump
if (_state.pumpState == 1)
_state.pumpState = 0;
else
_state.pumpState = 1;
break;
case 6: // Chest valve state
_state.chestValveState = (_state.chestValveState + 1) % 2;
break;
case 8: // Lighthouse Chest Key Position
if (_state.trapdoorKeyState) {
if (_state.trapdoorKeyState == 1)
_state.trapdoorKeyState = 2;
else
_state.trapdoorKeyState = 1;
}
break;
case 10: // Chest water state
_state.chestWaterState = 0;
break;
case 11:
if (_state.chestOpenState)
_state.trapdoorKeyState = _state.trapdoorKeyState != 1;
break;
case 20: // Ship Chamber Table/Book State
_cabinMystBookPresent = (_cabinMystBookPresent + 1) % 2;
break;
case 29: // Achenar's Room Rose/Skull Hologram Button Lit
_hologramTurnedOn = (_hologramTurnedOn + 1) % 2;
break;
case 102: // Red page
if (!(_globals.redPagesInBook & 8)) {
if (_globals.heldPage == kRedStoneshipPage)
_globals.heldPage = kNoPage;
else
_globals.heldPage = kRedStoneshipPage;
}
break;
case 103: // Blue page
if (!(_globals.bluePagesInBook & 8)) {
if (_globals.heldPage == kBlueStoneshipPage)
_globals.heldPage = kNoPage;
else
_globals.heldPage = kBlueStoneshipPage;
}
break;
default:
MystScriptParser::toggleVar(var);
break;
}
}
bool Stoneship::setVarValue(uint16 var, uint16 value) {
bool refresh = false;
switch (var) {
case 5: // Lighthouse Trapdoor State
_state.trapdoorState = value;
break;
case 7:
if (_state.chestOpenState != value)
_state.chestOpenState = value;
break;
case 8: // Lighthouse Chest Key Position
_state.trapdoorKeyState = value;
break;
case 15: // Side Door in Tunnels To Brother's Rooms Open
if (_state.sideDoorOpened != value) {
if (!value && _state.generatorPowerAvailable == 2)
_state.generatorPowerAvailable = 0;
_state.sideDoorOpened = value;
refresh = true;
}
break;
case 17: // Sirrus' Room Drawer with Drugs Open
if (_siriusDrawerDrugsOpen != value) {
_siriusDrawerDrugsOpen = value;
refresh = true;
}
break;
case 18: // Brother Room Door Open
if (_brotherDoorOpen != value) {
_brotherDoorOpen = value;
refresh = true;
}
break;
case 21: // Brothers Rooms' Chest Of Drawers Drawer State
if (_chestDrawersOpen != value) {
_chestDrawersOpen = value;
refresh = true;
}
break;
case 29: // Achenar's Room Rose/Skull Hologram Button Lit
_hologramTurnedOn = value;
break;
case 34: // Achenar's Room Drawer with Torn Note Closed
_chestAchenarBottomDrawerClosed = value;
break;
default:
refresh = MystScriptParser::setVarValue(var, value);
break;
}
return refresh;
}
void Stoneship::o_pumpTurnOff(uint16 var, const ArgumentsArray &args) {
if (_state.pumpState) {
uint16 buttonVar = 0;
switch (_state.pumpState) {
case 1:
buttonVar = 2;
break;
case 2:
buttonVar = 1;
break;
case 4:
buttonVar = 0;
break;
default:
warning("Incorrect pump state");
}
for (uint i = 0; i < _vm->getCard()->_resources.size(); i++) {
MystArea *resource = _vm->getCard()->_resources[i];
if (resource->hasType(kMystAreaImageSwitch) && resource->getImageSwitchVar() == buttonVar) {
static_cast<MystAreaImageSwitch *>(resource)->drawConditionalDataToScreen(0, true);
break;
}
}
}
}
void Stoneship::o_brotherDoorOpen(uint16 var, const ArgumentsArray &args) {
_brotherDoorOpen = 1;
_vm->getCard()->redrawArea(19, 0);
animatedUpdate(args, 5);
}
void Stoneship::o_cabinBookMovie(uint16 var, const ArgumentsArray &args) {
uint16 startTime = args[0];
uint16 endTime = args[1];
VideoEntryPtr book = _vm->playMovie("bkroom", kStoneshipStack);
book->moveTo(159, 99);
book->setBounds(Audio::Timestamp(0, startTime, 600), Audio::Timestamp(0, endTime, 600));
_vm->waitUntilMovieEnds(book);
}
void Stoneship::o_drawerOpenSirius(uint16 var, const ArgumentsArray &args) {
MystAreaImageSwitch *drawer = _vm->getCard()->getResource<MystAreaImageSwitch>(args[0]);
if (drawer->getImageSwitchVar() == 35) {
drawer->drawConditionalDataToScreen(getVar(102), 0);
} else {
drawer->drawConditionalDataToScreen(0, 0);
}
TransitionType transition = kTransitionTopToBottom;
if (args.size() == 2 && args[1])
transition = kTransitionCopy;
_vm->_gfx->runTransition(transition, drawer->getRect(), 25, 5);
}
void Stoneship::o_drawerClose(uint16 var, const ArgumentsArray &args) {
drawerClose(args[0]);
}
void Stoneship::o_telescopeStart(uint16 var, const ArgumentsArray &args) {
const Common::Point &mouse = _vm->_system->getEventManager()->getMousePos();
_telescopeOldMouse = mouse.x;
_vm->_cursor->setCursor(700);
}
void Stoneship::o_telescopeMove(uint16 var, const ArgumentsArray &args) {
MystAreaDrag *display = getInvokingResource<MystAreaDrag>();
const Common::Point &mouse = _vm->_system->getEventManager()->getMousePos();
// Compute telescope position
_telescopePosition = (_telescopePosition - (mouse.x - _telescopeOldMouse) / 2 + 3240) % 3240;
_telescopeOldMouse = mouse.x;
// Copy image to screen
Common::Rect src = Common::Rect(_telescopePosition, 0, _telescopePosition + 112, 112);
_vm->_gfx->copyImageSectionToScreen(_telescopePanorama, src, display->getRect());
// Draw lighthouse
telescopeLighthouseDraw();
}
void Stoneship::o_telescopeStop(uint16 var, const ArgumentsArray &args) {
_vm->refreshCursor();
}
void Stoneship::o_generatorStart(uint16 var, const ArgumentsArray &args) {
MystAreaDrag *handle = getInvokingResource<MystAreaDrag>();
uint16 soundId = handle->getList1(0);
if (soundId)
_vm->_sound->playEffect(soundId);
if (_state.generatorDuration)
_state.generatorDuration -= _vm->getTotalPlayTime() - _state.generatorDepletionTime;
// Start charging the battery
_batteryDepleting = false;
_batteryCharging = true;
_batteryNextTime = _vm->getTotalPlayTime() + 1000;
// Start handle movie
MystAreaVideo *movie = static_cast<MystAreaVideo *>(handle->getSubResource(0));
movie->playMovie();
soundId = handle->getList2(0);
if (soundId)
_vm->_sound->playEffect(soundId, true);
}
void Stoneship::o_generatorStop(uint16 var, const ArgumentsArray &args) {
_batteryCharging = false;
if (_state.generatorDuration) {
// Clip battery power
if (_state.generatorDuration > 600000)
_state.generatorDuration = 600000;
// Start depleting power
_state.generatorDepletionTime = _vm->getTotalPlayTime() + _state.generatorDuration;
_state.generatorPowerAvailable = 1;
_batteryDepleting = true;
_batteryNextTime = _vm->getTotalPlayTime() + 60000;
}
// Pause handle movie
MystAreaDrag *handle = getInvokingResource<MystAreaDrag>();
MystAreaVideo *movie = static_cast<MystAreaVideo *>(handle->getSubResource(0));
movie->pauseMovie(true);
uint16 soundId = handle->getList3(0);
if (soundId)
_vm->_sound->playEffect(soundId);
}
void Stoneship::chargeBattery_run() {
uint32 time = _vm->getTotalPlayTime();
if (time > _batteryNextTime) {
_batteryNextTime = time + 1000;
_state.generatorDuration += 30000;
}
}
uint16 Stoneship::batteryRemainingCharge() {
uint32 time = _vm->getTotalPlayTime();
if (_state.generatorDepletionTime > time) {
return (_state.generatorDepletionTime - time) / 7500;
} else {
return 0;
}
}
void Stoneship::batteryDeplete_run() {
uint32 time = _vm->getTotalPlayTime();
if (time > _batteryNextTime) {
if (_state.generatorDuration > 60000) {
_state.generatorDuration -= 60000;
_batteryNextTime = time + 60000;
} else { // Battery depleted
_state.generatorDuration = 0;
_state.generatorDepletionTime = 0;
if (_state.sideDoorOpened)
_state.generatorPowerAvailable = 2;
else
_state.generatorPowerAvailable = 0;
_batteryDepleting = false;
}
}
}
void Stoneship::o_drawerOpenAchenar(uint16 var, const ArgumentsArray &args) {
MystAreaImageSwitch *drawer = _vm->getCard()->getResource<MystAreaImageSwitch>(args[0]);
drawer->drawConditionalDataToScreen(0, 0);
_vm->_gfx->runTransition(kTransitionTopToBottom, drawer->getRect(), 25, 5);
}
void Stoneship::o_hologramPlayback(uint16 var, const ArgumentsArray &args) {
// Used for Card 2013 (Achenar's Rose-Skull Hologram)
uint16 startPoint = args[0];
uint16 endPoint = args[1];
// uint16 direction = args[2];
_hologramDisplay->setBlocking(false);
VideoEntryPtr displayMovie = _hologramDisplay->playMovie();
if (_hologramTurnedOn) {
if (_hologramDisplayPos)
endPoint = _hologramDisplayPos;
displayMovie->setBounds(Audio::Timestamp(0, startPoint, 600), Audio::Timestamp(0, endPoint, 600));
} else {
displayMovie->setBounds(Audio::Timestamp(0, startPoint, 600), Audio::Timestamp(0, endPoint, 600));
}
_vm->waitUntilMovieEnds(displayMovie);
}
void Stoneship::o_hologramSelectionStart(uint16 var, const ArgumentsArray &args) {
//_vm->_cursor->setCursor(0);
}
void Stoneship::o_hologramSelectionMove(uint16 var, const ArgumentsArray &args) {
MystAreaDrag *handle = getInvokingResource<MystAreaDrag>();
const Common::Point &mouse = _vm->_system->getEventManager()->getMousePos();
if (handle->getRect().contains(mouse)) {
int16 position = mouse.x - 143;
position = CLIP<int16>(position, 0, 242);
// Draw handle movie frame
uint16 selectionPos = position * 1500 / 243;
VideoEntryPtr handleMovie = _hologramSelection->playMovie();
_vm->_video->drawVideoFrame(handleMovie, Audio::Timestamp(0, selectionPos, 600));
_hologramDisplayPos = position * 1450 / 243 + 350;
// Draw display movie frame
if (_hologramTurnedOn) {
_hologramDisplay->setBlocking(false);
VideoEntryPtr displayMovie = _hologramDisplay->playMovie();
_vm->_video->drawVideoFrame(displayMovie, Audio::Timestamp(0, _hologramDisplayPos, 600));
}
}
}
void Stoneship::o_hologramSelectionStop(uint16 var, const ArgumentsArray &args) {
_vm->refreshCursor();
}
void Stoneship::o_compassButton(uint16 var, const ArgumentsArray &args) {
// Used on Card 2111 (Compass Rose)
// Called when Button Clicked.
uint16 correctButton = args[0];
if (correctButton) {
// Correct Button -> Light On Logic
_state.lightState = 1;
} else {
// Wrong Button -> Power Failure Logic
_state.generatorPowerAvailable = 2;
_state.lightState = 0;
_state.generatorDepletionTime = 0;
_state.generatorDuration = 0;
_batteryDepleting = false;
}
o_redrawCard(var, args);
}
void Stoneship::o_chestValveVideos(uint16 var, const ArgumentsArray &args) {
_vm->_sound->playEffect(2132);
if (_state.chestValveState) {
// Valve closing
VideoEntryPtr valve = _vm->playMovie("ligspig", kStoneshipStack);
valve->moveTo(97, 267);
valve->setBounds(Audio::Timestamp(0, 0, 600), Audio::Timestamp(0, 350, 600));
_vm->waitUntilMovieEnds(valve);
} else if (_state.chestWaterState) {
// Valve opening, spilling water
VideoEntryPtr valve = _vm->playMovie("ligspig", kStoneshipStack);
valve->moveTo(97, 267);
valve->setBounds(Audio::Timestamp(0, 350, 600), Audio::Timestamp(0, 650, 600));
_vm->waitUntilMovieEnds(valve);
_vm->_sound->playEffect(3132);
for (uint i = 0; i < 25; i++) {
valve = _vm->playMovie("ligspig", kStoneshipStack);
valve->moveTo(97, 267);
valve->setBounds(Audio::Timestamp(0, 650, 600), Audio::Timestamp(0, 750, 600));
_vm->waitUntilMovieEnds(valve);
}
_vm->_sound->resumeBackground();
} else {
// Valve opening
VideoEntryPtr valve = _vm->playMovie("ligspig", kStoneshipStack);
valve->moveTo(97, 267);
valve->seek(Audio::Timestamp(0, 350, 600));
valve->setRate(-1);
_vm->waitUntilMovieEnds(valve);
}
}
void Stoneship::o_chestDropKey(uint16 var, const ArgumentsArray &args) {
// If holding Key to Lamp Room Trapdoor, drop to bottom of
// Lighthouse...
if (_state.trapdoorKeyState == 1) {
_vm->setMainCursor(_savedCursorId);
_state.trapdoorKeyState = 2;
}
}
void Stoneship::o_trapLockOpen(uint16 var, const ArgumentsArray &args) {
VideoEntryPtr lock = _vm->playMovie("openloc", kStoneshipStack);
lock->moveTo(187, 71);
lock->setBounds(Audio::Timestamp(0, 0, 600), Audio::Timestamp(0, 750, 600));
_vm->waitUntilMovieEnds(lock);
_vm->_sound->playEffect(2143);
lock = _vm->playMovie("openloc", kStoneshipStack);
lock->moveTo(187, 71);
lock->setBounds(Audio::Timestamp(0, 750, 600), Audio::Timestamp(0, 10000, 600));
_vm->waitUntilMovieEnds(lock);
if (_state.pumpState != 4)
_vm->_sound->playEffect(4143);
}
void Stoneship::o_sideDoorsMovies(uint16 var, const ArgumentsArray &args) {
// Used for Cards 2285, 2289, 2247, 2251 (Side Doors in Tunnels Down To Brothers Rooms)
uint16 movieId = args[0];
_vm->_cursor->hideCursor();
_vm->_sound->pauseBackground();
switch (movieId) {
case 0:
// Card 2251
_vm->playMovieBlocking("tunaup", kStoneshipStack, 149, 161);
break;
case 1:
// Card 2247
_vm->playMovieBlocking("tunadown", kStoneshipStack, 218, 150);
break;
case 2:
// Card 2289
_vm->playMovieBlocking("tuncup", kStoneshipStack, 259, 161);
break;
case 3:
// Card 2285
_vm->playMovieBlocking("tuncdown", kStoneshipStack, 166, 150);
break;
default:
warning("Opcode 120 MovieId Out Of Range");
break;
}
_vm->_sound->resumeBackground();
_vm->_cursor->showCursor();
}
void Stoneship::o_cloudOrbEnter(uint16 var, const ArgumentsArray &args) {
_vm->_sound->playEffect(_cloudOrbSound, true);
_cloudOrbMovie->playMovie();
}
void Stoneship::o_cloudOrbLeave(uint16 var, const ArgumentsArray &args) {
_cloudOrbMovie->pauseMovie(true);
_vm->_sound->playEffect(_cloudOrbStopSound);
_vm->_gfx->runTransition(kTransitionTopToBottom, getInvokingResource<MystArea>()->getRect(), 4, 0);
}
void Stoneship::o_drawerCloseOpened(uint16 var, const ArgumentsArray &args) {
uint16 drawerOpen = getVar(var);
if (drawerOpen)
drawerClose(args[0] + drawerOpen - 1);
}
void Stoneship::drawerClose(uint16 drawer) {
_chestDrawersOpen = 0;
_vm->getCard()->drawBackground();
_vm->getCard()->drawResourceImages();
MystArea *res = _vm->getCard()->getResource<MystArea>(drawer);
_vm->_gfx->runTransition(kTransitionBottomToTop, res->getRect(), 25, 5);
}
void Stoneship::o_hologramDisplay_init(uint16 var, const ArgumentsArray &args) {
_hologramDisplay = getInvokingResource<MystAreaVideo>();
_hologramDisplayPos = 0;
}
void Stoneship::o_hologramSelection_init(uint16 var, const ArgumentsArray &args) {
_hologramSelection = getInvokingResource<MystAreaVideo>();
}
void Stoneship::batteryGaugeUpdate() {
uint16 charge = 0;
if (_state.generatorDepletionTime) {
charge = batteryRemainingCharge();
}
Common::Rect rect = _batteryGauge->getRect();
rect.top = rect.bottom - charge;
_batteryGauge->setRect(rect);
}
void Stoneship::o_battery_init(uint16 var, const ArgumentsArray &args) {
// Used for Card 2160 (Lighthouse Battery Pack Closeup)
_batteryGauge = getInvokingResource<MystAreaImageSwitch>();
batteryGaugeUpdate();
}
void Stoneship::o_tunnelEnter_init(uint16 var, const ArgumentsArray &args) {
o_tunnel_init(var, args);
_tunnelRunning = true;
_tunnelNextTime = _vm->getTotalPlayTime() + 1500;
}
void Stoneship::o_batteryGauge_init(uint16 var, const ArgumentsArray &args) {
_batteryLastCharge = batteryRemainingCharge();
_batteryGaugeRunning = true;
}
void Stoneship::batteryGauge_run() {
uint16 batteryCharge = batteryRemainingCharge();
if (batteryCharge != _batteryLastCharge) {
batteryGaugeUpdate();
_batteryLastCharge = batteryCharge;
// Redraw card
_vm->getCard()->drawBackground();
_vm->getCard()->drawResourceImages();
_vm->_gfx->copyBackBufferToScreen(Common::Rect(544, 333));
}
}
void Stoneship::o_tunnel_init(uint16 var, const ArgumentsArray &args) {
_tunnelImagesCount = args[0];
assert(_tunnelImagesCount <= 2 && "Too many images");
for (uint i = 0; i < _tunnelImagesCount; i++) {
_tunnelImages[i] = args[i + 1];
}
_tunnelAlarmSound = args[args.size() - 1];
debugC(kDebugScript, "\timage count: %d", _tunnelImagesCount);
debugC(kDebugScript, "\tsoundIdAlarm: %d", _tunnelAlarmSound);
}
void Stoneship::tunnel_run() {
uint32 time = _vm->getTotalPlayTime();
if (time > _tunnelNextTime) {
_tunnelNextTime = time + 1500;
if (_state.generatorPowerAvailable == 2) {
// Draw tunnel black
if (_tunnelImagesCount) {
_vm->_gfx->copyImageToScreen(_tunnelImages[1], Common::Rect(544, 333));
}
_vm->_sound->playEffect(_tunnelAlarmSound);
// Draw tunnel dark
if (_tunnelImagesCount) {
_vm->_gfx->copyImageToScreen(_tunnelImages[0], Common::Rect(544, 333));
}
}
}
}
void Stoneship::o_tunnelLeave_init(uint16 var, const ArgumentsArray &args) {
_tunnelRunning = false;
}
void Stoneship::o_chest_init(uint16 var, const ArgumentsArray &args) {
_state.chestOpenState = 0;
}
void Stoneship::o_telescope_init(uint16 var, const ArgumentsArray &args) {
// Used in Card 2218 (Telescope view)
_telescopePanorama = args[0];
_telescopeLighthouseOff = args[1];
_telescopeLighthouseOn = args[2];
_telescopePosition = 0;
_telescopeRunning = true;
_telescopeLighthouseState = false;
_telescopeNexTime = _vm->getTotalPlayTime() + 1000;
}
void Stoneship::telescope_run() {
uint32 time = _vm->getTotalPlayTime();
if (time > _telescopeNexTime) {
_telescopeNexTime = time + 1000;
_telescopeLighthouseState = !_telescopeLighthouseState;
telescopeLighthouseDraw();
}
}
void Stoneship::telescopeLighthouseDraw() {
if (_telescopePosition > 1137 && _telescopePosition < 1294) {
uint16 imageId = _telescopeLighthouseOff;
if (_state.generatorPowerAvailable == 1 && _telescopeLighthouseState)
imageId = _telescopeLighthouseOn;
Common::Rect src(1205, 0, 1205 + 131, 112);
src.clip(Common::Rect(_telescopePosition, 0, _telescopePosition + 112, 112));
src.translate(-1205, 0);
src.clip(131, 112);
Common::Rect dest(_telescopePosition, 0, _telescopePosition + 112, 112);
dest.clip(Common::Rect(1205, 0, 1205 + 131, 112));
dest.translate(-_telescopePosition, 0);
dest.clip(112, 112);
dest.translate(222, 112);
_vm->_gfx->copyImageSectionToScreen(imageId, src, dest);
}
}
void Stoneship::o_achenarDrawers_init(uint16 var, const ArgumentsArray &args) {
// Used for Card 2004 (Achenar's Room Drawers)
if (!_chestAchenarBottomDrawerClosed) {
uint16 count1 = args[0];
for (uint16 i = 0; i < count1; i++) {
debugC(kDebugScript, "Disable hotspot index %d", args[i + 1]);
_vm->getCard()->setResourceEnabled(args[i + 1], false);
}
uint16 count2 = args[count1 + 1];
for (uint16 i = 0; i < count2; i++) {
debugC(kDebugScript, "Enable hotspot index %d", args[i + count1 + 2]);
_vm->getCard()->setResourceEnabled(args[i + count1 + 2], true);
}
}
}
void Stoneship::o_cloudOrb_init(uint16 var, const ArgumentsArray &args) {
_cloudOrbMovie = getInvokingResource<MystAreaVideo>();
_cloudOrbSound = args[0];
_cloudOrbStopSound = args[1];
}
} // End of namespace MystStacks
} // End of namespace Mohawk

View File

@@ -0,0 +1,149 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef MYST_SCRIPTS_STONESHIP_H
#define MYST_SCRIPTS_STONESHIP_H
#include "common/scummsys.h"
#include "common/util.h"
#include "mohawk/myst_scripts.h"
namespace Mohawk {
struct MystScriptEntry;
namespace MystStacks {
#define DECLARE_OPCODE(x) void x(uint16 var, const ArgumentsArray &args)
class Stoneship : public MystScriptParser {
public:
explicit Stoneship(MohawkEngine_Myst *vm);
~Stoneship() override;
void disablePersistentScripts() override;
void runPersistentScripts() override;
private:
void setupOpcodes();
uint16 getVar(uint16 var) override;
void toggleVar(uint16 var) override;
bool setVarValue(uint16 var, uint16 value) override;
uint16 getMap() override { return 9933; }
DECLARE_OPCODE(o_pumpTurnOff);
DECLARE_OPCODE(o_brotherDoorOpen);
DECLARE_OPCODE(o_cabinBookMovie);
DECLARE_OPCODE(o_drawerOpenSirius);
DECLARE_OPCODE(o_drawerClose);
DECLARE_OPCODE(o_telescopeStart);
DECLARE_OPCODE(o_telescopeMove);
DECLARE_OPCODE(o_telescopeStop);
DECLARE_OPCODE(o_generatorStart);
DECLARE_OPCODE(o_generatorStop);
DECLARE_OPCODE(o_drawerOpenAchenar);
DECLARE_OPCODE(o_hologramPlayback);
DECLARE_OPCODE(o_hologramSelectionStart);
DECLARE_OPCODE(o_hologramSelectionMove);
DECLARE_OPCODE(o_hologramSelectionStop);
DECLARE_OPCODE(o_compassButton);
DECLARE_OPCODE(o_chestValveVideos);
DECLARE_OPCODE(o_chestDropKey);
DECLARE_OPCODE(o_trapLockOpen);
DECLARE_OPCODE(o_sideDoorsMovies);
DECLARE_OPCODE(o_cloudOrbEnter);
DECLARE_OPCODE(o_cloudOrbLeave);
DECLARE_OPCODE(o_drawerCloseOpened);
DECLARE_OPCODE(o_hologramDisplay_init);
DECLARE_OPCODE(o_hologramSelection_init);
DECLARE_OPCODE(o_battery_init);
DECLARE_OPCODE(o_tunnelEnter_init);
DECLARE_OPCODE(o_batteryGauge_init);
DECLARE_OPCODE(o_tunnel_init);
DECLARE_OPCODE(o_tunnelLeave_init);
DECLARE_OPCODE(o_chest_init);
DECLARE_OPCODE(o_telescope_init);
DECLARE_OPCODE(o_achenarDrawers_init);
DECLARE_OPCODE(o_cloudOrb_init);
void chargeBattery_run();
void batteryDeplete_run();
MystGameState::Stoneship &_state;
bool _batteryCharging;
bool _batteryDepleting;
uint32 _batteryNextTime;
bool _batteryGaugeRunning;
uint16 _batteryLastCharge; // 92
MystAreaImageSwitch *_batteryGauge; // 96
void batteryGaugeUpdate();
void batteryGauge_run();
uint16 _cabinMystBookPresent; // 64
uint16 _siriusDrawerDrugsOpen; // 72
uint16 _brotherDoorOpen; // 76
uint16 _chestDrawersOpen; // 78
uint16 _chestAchenarBottomDrawerClosed; // 144
void drawerClose(uint16 drawer);
uint16 _hologramTurnedOn; // 80
MystAreaVideo *_hologramDisplay; // 84
MystAreaVideo *_hologramSelection; // 88
uint16 _hologramDisplayPos;
bool _tunnelRunning;
uint32 _tunnelNextTime;
uint16 _tunnelAlarmSound; // 100
uint16 _tunnelImagesCount; // 22
uint16 _tunnelImages[2]; // 32
void tunnel_run();
uint16 _telescopePosition; // 112
uint16 _telescopePanorama;
uint16 _telescopeOldMouse;
uint16 _telescopeLighthouseOff; // 130
uint16 _telescopeLighthouseOn; // 128
bool _telescopeLighthouseState; // 124
bool _telescopeRunning;
uint32 _telescopeNexTime;
void telescope_run();
void telescopeLighthouseDraw();
MystAreaVideo *_cloudOrbMovie; // 136
uint16 _cloudOrbSound; // 140
uint16 _cloudOrbStopSound; // 142
uint16 batteryRemainingCharge();
};
} // End of namespace MystStacks
}
#undef DECLARE_OPCODE
#endif