scummvm/engines/mohawk/riven_external.cpp
Matthew Hoops bb5db4aa3b MOHAWK: Finish implementation of the Riven Marble Puzzle
You can now place the marbles and pressing the button will now only set the power to on if the marbles are in the correct positions.

svn-id: r52735
2010-09-15 20:28:42 +00:00

2173 lines
67 KiB
C++

/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* $URL$
* $Id$
*
*/
#include "mohawk/graphics.h"
#include "mohawk/riven.h"
#include "mohawk/riven_external.h"
#include "mohawk/sound.h"
#include "mohawk/video.h"
#include "gui/message.h"
#include "common/events.h"
namespace Mohawk {
static const uint32 kDomeSliderDefaultState = 0x01F00000;
static const uint32 kDomeSliderSlotCount = 25;
RivenExternal::RivenExternal(MohawkEngine_Riven *vm) : _vm(vm) {
setupCommands();
_sliderState = kDomeSliderDefaultState;
}
RivenExternal::~RivenExternal() {
for (uint32 i = 0; i < _externalCommands.size(); i++)
delete _externalCommands[i];
_externalCommands.clear();
}
void RivenExternal::setupCommands() {
// aspit (Main Menu, Books, Setup) external commands
COMMAND(xastartupbtnhide);
COMMAND(xasetupcomplete);
COMMAND(xaatrusopenbook);
COMMAND(xaatrusbookback);
COMMAND(xaatrusbookprevpage);
COMMAND(xaatrusbooknextpage);
COMMAND(xacathopenbook);
COMMAND(xacathbookback);
COMMAND(xacathbookprevpage);
COMMAND(xacathbooknextpage);
COMMAND(xtrapbookback);
COMMAND(xatrapbookclose);
COMMAND(xatrapbookopen);
COMMAND(xarestoregame);
COMMAND(xadisablemenureturn);
COMMAND(xaenablemenureturn);
COMMAND(xalaunchbrowser);
COMMAND(xadisablemenuintro);
COMMAND(xaenablemenuintro);
// bspit (Bookmaking Island) external commands
COMMAND(xblabopenbook);
COMMAND(xblabbookprevpage);
COMMAND(xblabbooknextpage);
COMMAND(xsoundplug);
COMMAND(xbchangeboiler);
COMMAND(xbupdateboiler);
COMMAND(xbsettrap);
COMMAND(xbcheckcatch);
COMMAND(xbait);
COMMAND(xbfreeytram);
COMMAND(xbaitplate);
COMMAND(xbisland190_opencard);
COMMAND(xbisland190_resetsliders);
COMMAND(xbisland190_slidermd);
COMMAND(xbisland190_slidermw);
COMMAND(xbscpbtn);
COMMAND(xbisland_domecheck);
COMMAND(xvalvecontrol);
COMMAND(xbchipper);
// gspit (Garden Island) external commands
COMMAND(xgresetpins);
COMMAND(xgrotatepins);
COMMAND(xgpincontrols);
COMMAND(xgisland25_opencard);
COMMAND(xgisland25_resetsliders);
COMMAND(xgisland25_slidermd);
COMMAND(xgisland25_slidermw);
COMMAND(xgscpbtn);
COMMAND(xgisland1490_domecheck);
COMMAND(xgplateau3160_dopools);
COMMAND(xgwt200_scribetime);
COMMAND(xgwt900_scribe);
COMMAND(xgplaywhark);
COMMAND(xgrviewer);
COMMAND(xgwharksnd);
COMMAND(xglview_prisonoff);
COMMAND(xglview_villageoff);
COMMAND(xglviewer);
COMMAND(xglview_prisonon);
COMMAND(xglview_villageon);
// jspit (Jungle Island) external commands
COMMAND(xreseticons);
COMMAND(xicon);
COMMAND(xcheckicons);
COMMAND(xtoggleicon);
COMMAND(xjtunnel103_pictfix);
COMMAND(xjtunnel104_pictfix);
COMMAND(xjtunnel105_pictfix);
COMMAND(xjtunnel106_pictfix);
COMMAND(xvga1300_carriage);
COMMAND(xjdome25_resetsliders);
COMMAND(xjdome25_slidermd);
COMMAND(xjdome25_slidermw);
COMMAND(xjscpbtn);
COMMAND(xjisland3500_domecheck);
COMMAND(xhandlecontroldown);
COMMAND(xhandlecontrolmid);
COMMAND(xhandlecontrolup);
COMMAND(xjplaybeetle_550);
COMMAND(xjplaybeetle_600);
COMMAND(xjplaybeetle_950);
COMMAND(xjplaybeetle_1050);
COMMAND(xjplaybeetle_1450);
COMMAND(xjlagoon700_alert);
COMMAND(xjlagoon800_alert);
COMMAND(xjlagoon1500_alert);
COMMAND(xschool280_playwhark);
COMMAND(xjatboundary);
// ospit (Gehn's Office) external commands
COMMAND(xorollcredittime);
COMMAND(xbookclick);
COMMAND(xooffice30_closebook);
COMMAND(xobedroom5_closedrawer);
COMMAND(xogehnopenbook);
COMMAND(xogehnbookprevpage);
COMMAND(xogehnbooknextpage);
COMMAND(xgwatch);
// pspit (Prison Island) external commands
COMMAND(xpisland990_elevcombo);
COMMAND(xpscpbtn);
COMMAND(xpisland290_domecheck);
COMMAND(xpisland25_opencard);
COMMAND(xpisland25_resetsliders);
COMMAND(xpisland25_slidermd);
COMMAND(xpisland25_slidermw);
// rspit (Rebel Age) external commands
COMMAND(xrshowinventory);
COMMAND(xrhideinventory);
COMMAND(xrcredittime);
COMMAND(xrwindowsetup);
// tspit (Temple Island) external commands
COMMAND(xtexterior300_telescopedown);
COMMAND(xtexterior300_telescopeup);
COMMAND(xtisland390_covercombo);
COMMAND(xtatrusgivesbooks);
COMMAND(xtchotakesbook);
COMMAND(xthideinventory);
COMMAND(xt7500_checkmarbles);
COMMAND(xt7600_setupmarbles);
COMMAND(xt7800_setup);
COMMAND(xdrawmarbles);
COMMAND(xtakeit);
COMMAND(xtscpbtn);
COMMAND(xtisland4990_domecheck);
COMMAND(xtisland5056_opencard);
COMMAND(xtisland5056_resetsliders);
COMMAND(xtisland5056_slidermd);
COMMAND(xtisland5056_slidermw);
COMMAND(xtatboundary);
// Common external commands
COMMAND(xflies);
}
void RivenExternal::runCommand(uint16 argc, uint16 *argv) {
Common::String externalCommandName = _vm->getName(ExternalCommandNames, argv[0]);
for (uint16 i = 0; i < _externalCommands.size(); i++)
if (externalCommandName == _externalCommands[i]->desc) {
debug(0, "Running Riven External Command \'%s\'", externalCommandName.c_str());
(this->*(_externalCommands[i]->proc)) (argv[1], argv[1] ? argv + 2 : NULL);
return;
}
error("Unknown external command \'%s\'", externalCommandName.c_str());
}
void RivenExternal::runDemoBoundaryDialog() {
GUI::MessageDialog dialog("Exploration beyond this point available only within the full version of\n"
"the game.");
dialog.runModal();
}
void RivenExternal::runEndGame(uint16 video) {
_vm->_sound->stopAllSLST();
_vm->_video->playMovie(video);
runCredits(video);
}
void RivenExternal::runCredits(uint16 video) {
// TODO: Play until the last frame and then run the credits
VideoHandle videoHandle = _vm->_video->findVideoHandle(video);
while (!_vm->_video->endOfVideo(videoHandle) && !_vm->shouldQuit()) {
if (_vm->_video->updateBackgroundMovies())
_vm->_system->updateScreen();
Common::Event event;
while (_vm->_system->getEventManager()->pollEvent(event))
;
_vm->_system->delayMillis(10);
}
_vm->setGameOver();
}
void RivenExternal::runDomeButtonMovie() {
// This command just plays the video of the button moving down and up.
_vm->_video->playMovieBlocking(2);
}
void RivenExternal::runDomeCheck() {
// Check if we clicked while the golden frame was showing
VideoHandle video = _vm->_video->findVideoHandle(1);
assert(video != NULL_VID_HANDLE);
int32 curFrame = _vm->_video->getCurFrame(video);
int32 frameCount = _vm->_video->getFrameCount(video);
// The final frame of the video is the 'golden' frame (double meaning: the
// frame that is the magic one is the one with the golden symbol) but we
// give a 3 frame leeway in either direction.
if (frameCount - curFrame < 3 || curFrame < 3)
*_vm->getVar("domecheck") = 1;
}
void RivenExternal::resetDomeSliders(uint16 bitmapId, uint16 soundId, uint16 startHotspot) {
// The rightmost slider should move left until it finds the next slider,
// then those two continue until they find the third slider. This continues
// until all five sliders have returned their starting slots.
byte slidersFound = 0;
for (uint32 i = 0; i < kDomeSliderSlotCount; i++) {
if (_sliderState & (1 << i)) {
// A slider occupies this spot. Increase the number of sliders we
// have found, but we're not doing any moving this iteration.
slidersFound++;
} else {
// Move all the sliders we have found over one slot
for (byte j = 0; j < slidersFound; j++) {
_sliderState &= ~(1 << (i - j - 1));
_sliderState |= 1 << (i - j);
}
// If we have at least one found slider, it has now moved
// so we should redraw and play a tick sound
if (slidersFound) {
_vm->_sound->playSound(soundId);
drawDomeSliders(bitmapId, startHotspot);
_vm->_system->delayMillis(10);
}
}
}
// Sanity checks - the slider count should always be 5 and we should end up at
// the default state after moving them all over.
assert(slidersFound == 5);
assert(_sliderState == kDomeSliderDefaultState);
}
void RivenExternal::checkDomeSliders(uint16 resetSlidersHotspot, uint16 openDomeHotspot) {
// Let's see if we're all matched up...
if (*_vm->getVar("adomecombo") == _sliderState) {
// Set the button hotspot to the open dome hotspot
_vm->_hotspots[resetSlidersHotspot].enabled = false;
_vm->_hotspots[openDomeHotspot].enabled = true;
} else {
// Set the button hotspot to the reset sliders hotspot
_vm->_hotspots[resetSlidersHotspot].enabled = true;
_vm->_hotspots[openDomeHotspot].enabled = false;
}
}
void RivenExternal::checkSliderCursorChange(uint16 startHotspot) {
// Set the cursor based on _sliderState and what hotspot we're over
for (uint16 i = 0; i < kDomeSliderSlotCount; i++) {
if (_vm->_hotspots[i + startHotspot].rect.contains(_vm->_system->getEventManager()->getMousePos())) {
if (_sliderState & (1 << (24 - i)))
_vm->_gfx->changeCursor(kRivenOpenHandCursor);
else
_vm->_gfx->changeCursor(kRivenMainCursor);
break;
}
}
}
void RivenExternal::dragDomeSlider(uint16 bitmapId, uint16 soundId, uint16 resetSlidersHotspot, uint16 openDomeHotspot, uint16 startHotspot) {
int16 foundSlider = -1;
for (uint16 i = 0; i < kDomeSliderSlotCount; i++) {
if (_vm->_hotspots[i + startHotspot].rect.contains(_vm->_system->getEventManager()->getMousePos())) {
// If the slider is not at this hotspot, we can't do anything else
if (!(_sliderState & (1 << (24 - i))))
return;
foundSlider = i;
break;
}
}
// We're not over any slider
if (foundSlider < 0)
return;
// We've clicked down, so show the closed hand cursor
_vm->_gfx->changeCursor(kRivenClosedHandCursor);
bool done = false;
while (!done) {
Common::Event event;
while (_vm->_system->getEventManager()->pollEvent(event)) {
switch (event.type) {
case Common::EVENT_MOUSEMOVE:
if (foundSlider < 24 && !(_sliderState & (1 << (23 - foundSlider))) && _vm->_hotspots[foundSlider + startHotspot + 1].rect.contains(event.mouse)) {
// We've moved the slider right one space
_sliderState &= ~(_sliderState & (1 << (24 - foundSlider)));
foundSlider++;
_sliderState |= 1 << (24 - foundSlider);
// Now play a click sound and redraw
_vm->_sound->playSound(soundId);
drawDomeSliders(bitmapId, startHotspot);
} else if (foundSlider > 0 && !(_sliderState & (1 << (25 - foundSlider))) && _vm->_hotspots[foundSlider + startHotspot - 1].rect.contains(event.mouse)) {
// We've moved the slider left one space
_sliderState &= ~(_sliderState & (1 << (24 - foundSlider)));
foundSlider--;
_sliderState |= 1 << (24 - foundSlider);
// Now play a click sound and redraw
_vm->_sound->playSound(soundId);
drawDomeSliders(bitmapId, startHotspot);
} else
_vm->_system->updateScreen(); // A normal update for the cursor
break;
case Common::EVENT_LBUTTONUP:
done = true;
break;
default:
break;
}
}
_vm->_system->delayMillis(10);
}
// Check to see if we have the right combination
checkDomeSliders(resetSlidersHotspot, openDomeHotspot);
}
void RivenExternal::drawDomeSliders(uint16 bitmapId, uint16 startHotspot) {
Common::Rect dstAreaRect = Common::Rect(200, 250, 420, 319);
// On pspit, the rect is different by two pixels
// (alternatively, we could just use hotspot 3 here, but only on pspit is there a hotspot for this)
if (_vm->getCurStack() == pspit)
dstAreaRect.translate(-2, 0);
for (uint16 i = 0; i < kDomeSliderSlotCount; i++) {
Common::Rect srcRect = _vm->_hotspots[startHotspot + i].rect;
srcRect.translate(-dstAreaRect.left, -dstAreaRect.top); // Adjust the rect so it's in the destination area
Common::Rect dstRect = _vm->_hotspots[startHotspot + i].rect;
if (_sliderState & (1 << (24 - i)))
_vm->_gfx->drawImageRect(bitmapId, srcRect, dstRect);
else
_vm->_gfx->drawImageRect(bitmapId + 1, srcRect, dstRect);
}
_vm->_gfx->updateScreen();
}
// ------------------------------------------------------------------------------------
// aspit (Main Menu, Books, Setup) external commands
// ------------------------------------------------------------------------------------
void RivenExternal::xastartupbtnhide(uint16 argc, uint16 *argv) {
// The original game hides the start/setup buttons depending on an ini entry.
// It's safe to ignore this command.
}
void RivenExternal::xasetupcomplete(uint16 argc, uint16 *argv) {
// The original game sets an ini entry to disable the setup button and use the
// start button only. It's safe to ignore this part of the command.
_vm->_sound->stopSound();
_vm->changeToCard(1);
}
void RivenExternal::xaatrusopenbook(uint16 argc, uint16 *argv) {
// Get the variable
uint32 page = *_vm->getVar("aatruspage");
// Set hotspots depending on the page
if (page == 1) {
_vm->_hotspots[1].enabled = false;
_vm->_hotspots[2].enabled = false;
_vm->_hotspots[3].enabled = true;
} else {
_vm->_hotspots[1].enabled = true;
_vm->_hotspots[2].enabled = true;
_vm->_hotspots[3].enabled = false;
}
// Draw the image of the page
_vm->_gfx->drawPLST(page);
}
void RivenExternal::xaatrusbookback(uint16 argc, uint16 *argv) {
// Return to where we were before entering the book
_vm->changeToStack(*_vm->getVar("returnstackid"));
_vm->changeToCard(*_vm->getVar("returncardid"));
}
void RivenExternal::xaatrusbookprevpage(uint16 argc, uint16 *argv) {
// Get the page variable
uint32 *page = _vm->getVar("aatruspage");
// Decrement the page if it's not the first page
if (*page == 1)
return;
(*page)--;
// Play the page turning sound
if (_vm->getFeatures() & GF_DEMO)
_vm->_sound->playSound(4);
else
_vm->_sound->playSound(3);
// Now update the screen :)
_vm->_gfx->scheduleTransition(1);
_vm->_gfx->updateScreen();
}
void RivenExternal::xaatrusbooknextpage(uint16 argc, uint16 *argv) {
// Get the page variable
uint32 *page = _vm->getVar("aatruspage");
// Increment the page if it's not the last page
if (((_vm->getFeatures() & GF_DEMO) && *page == 6) || *page == 10)
return;
(*page)++;
// Play the page turning sound
if (_vm->getFeatures() & GF_DEMO)
_vm->_sound->playSound(5);
else
_vm->_sound->playSound(4);
// Now update the screen :)
_vm->_gfx->scheduleTransition(0);
_vm->_gfx->updateScreen();
}
void RivenExternal::xacathopenbook(uint16 argc, uint16 *argv) {
// Get the variable
uint32 page = *_vm->getVar("acathpage");
// Set hotspots depending on the page
if (page == 1) {
_vm->_hotspots[1].enabled = false;
_vm->_hotspots[2].enabled = false;
_vm->_hotspots[3].enabled = true;
} else {
_vm->_hotspots[1].enabled = true;
_vm->_hotspots[2].enabled = true;
_vm->_hotspots[3].enabled = false;
}
// Draw the image of the page
_vm->_gfx->drawPLST(page);
// Draw the white page edges
if (page > 1 && page < 5)
_vm->_gfx->drawPLST(50);
else if (page > 5)
_vm->_gfx->drawPLST(51);
if (page == 28) {
// Draw the telescope combination
// The images for the numbers are tBMP's 13 through 17.
// The start point is at (156, 247)
uint32 teleCombo = *_vm->getVar("tcorrectorder");
static const uint16 kNumberWidth = 32;
static const uint16 kNumberHeight = 25;
static const uint16 kDstX = 156;
static const uint16 kDstY = 247;
for (byte i = 0; i < 5; i++) {
uint16 offset = (getComboDigit(teleCombo, i) - 1) * kNumberWidth;
Common::Rect srcRect = Common::Rect(offset, 0, offset + kNumberWidth, kNumberHeight);
Common::Rect dstRect = Common::Rect(i * kNumberWidth + kDstX, kDstY, (i + 1) * kNumberWidth + kDstX, kDstY + kNumberHeight);
_vm->_gfx->drawImageRect(i + 13, srcRect, dstRect);
}
}
}
void RivenExternal::xacathbookback(uint16 argc, uint16 *argv) {
// Return to where we were before entering the book
_vm->changeToStack(*_vm->getVar("returnstackid"));
_vm->changeToCard(*_vm->getVar("returncardid"));
}
void RivenExternal::xacathbookprevpage(uint16 argc, uint16 *argv) {
// Get the variable
uint32 *page = _vm->getVar("acathpage");
// Increment the page if it's not the first page
if (*page == 1)
return;
(*page)--;
// Play the page turning sound
_vm->_sound->playSound(5);
// Now update the screen :)
_vm->_gfx->scheduleTransition(3);
_vm->_gfx->updateScreen();
}
void RivenExternal::xacathbooknextpage(uint16 argc, uint16 *argv) {
// Get the variable
uint32 *page = _vm->getVar("acathpage");
// Increment the page if it's not the last page
if (*page == 49)
return;
(*page)++;
// Play the page turning sound
_vm->_sound->playSound(6);
// Now update the screen :)
_vm->_gfx->scheduleTransition(2);
_vm->_gfx->updateScreen();
}
void RivenExternal::xtrapbookback(uint16 argc, uint16 *argv) {
// Return to where we were before entering the book
*_vm->getVar("atrap") = 0;
_vm->changeToStack(*_vm->getVar("returnstackid"));
_vm->changeToCard(*_vm->getVar("returncardid"));
}
void RivenExternal::xatrapbookclose(uint16 argc, uint16 *argv) {
// Close the trap book
*_vm->getVar("atrap") = 0;
// Play the page turning sound
_vm->_sound->playSound(8);
_vm->refreshCard();
}
void RivenExternal::xatrapbookopen(uint16 argc, uint16 *argv) {
// Open the trap book
*_vm->getVar("atrap") = 1;
// Play the page turning sound
_vm->_sound->playSound(9);
_vm->refreshCard();
}
void RivenExternal::xarestoregame(uint16 argc, uint16 *argv) {
// Launch the load game dialog
_vm->runLoadDialog();
}
void RivenExternal::xadisablemenureturn(uint16 argc, uint16 *argv) {
// This function would normally enable the Windows menu item for
// returning to the main menu. Ctrl+r will do this instead.
// The original also had this shortcut.
}
void RivenExternal::xaenablemenureturn(uint16 argc, uint16 *argv) {
// This function would normally enable the Windows menu item for
// returning to the main menu. Ctrl+r will do this instead.
// The original also had this shortcut.
}
void RivenExternal::xalaunchbrowser(uint16 argc, uint16 *argv) {
// Well, we can't launch a browser for obvious reasons ;)
// The original text is as follows (for reference):
// If you have an auto-dial configured connection to the Internet,
// please select YES below.
//
// America Online and CompuServe users may experience difficulty. If
// you find that you are unable to connect, please quit the Riven
// Demo, launch your browser and type in the following URL:
//
// www.redorb.com/buyriven
//
// Would you like to attempt to make the connection?
//
// [YES] [NO]
GUI::MessageDialog dialog("At this point, the Riven Demo would\n"
"ask if you would like to open a web browser\n"
"to bring you to the Red Orb store to buy\n"
"the game. ScummVM cannot do that and\n"
"the site no longer exists.");
dialog.runModal();
}
void RivenExternal::xadisablemenuintro(uint16 argc, uint16 *argv) {
// This function would normally enable the Windows menu item for
// playing the intro. Ctrl+p will play the intro movies instead.
// The original also had this shortcut.
// Hide the "exit" button here
_vm->_gfx->hideInventory();
}
void RivenExternal::xaenablemenuintro(uint16 argc, uint16 *argv) {
// This function would normally enable the Windows menu item for
// playing the intro. Ctrl+p will play the intro movies instead.
// The original also had this shortcut.
// Show the "exit" button here
_vm->_gfx->showInventory();
}
// ------------------------------------------------------------------------------------
// bspit (Bookmaking Island) external commands
// ------------------------------------------------------------------------------------
void RivenExternal::xblabopenbook(uint16 argc, uint16 *argv) {
// Get the variable
uint32 page = *_vm->getVar("blabbook");
// Draw the image of the page based on the blabbook variable
_vm->_gfx->drawPLST(page);
if (page == 14) {
// Draw the dome combination
// The images for the numbers are tBMP's 364 through 368
// The start point is at (240, 82)
uint32 domeCombo = *_vm->getVar("adomecombo");
static const uint16 kNumberWidth = 32;
static const uint16 kNumberHeight = 24;
static const uint16 kDstX = 240;
static const uint16 kDstY = 82;
byte numCount = 0;
for (int bitPos = 24; bitPos >= 0; bitPos--) {
if (domeCombo & (1 << bitPos)) {
uint16 offset = (24 - bitPos) * kNumberWidth;
Common::Rect srcRect = Common::Rect(offset, 0, offset + kNumberWidth, kNumberHeight);
Common::Rect dstRect = Common::Rect(numCount * kNumberWidth + kDstX, kDstY, (numCount + 1) * kNumberWidth + kDstX, kDstY + kNumberHeight);
_vm->_gfx->drawImageRect(numCount + 364, srcRect, dstRect);
numCount++;
}
}
assert(numCount == 5); // Sanity check
}
}
void RivenExternal::xblabbookprevpage(uint16 argc, uint16 *argv) {
// Get the page variable
uint32 *page = _vm->getVar("blabbook");
// Decrement the page if it's not the first page
if (*page == 1)
return;
(*page)--;
// Play the page turning sound
_vm->_sound->playSound(22);
// Now update the screen :)
_vm->_gfx->scheduleTransition(1);
_vm->_gfx->updateScreen();
}
void RivenExternal::xblabbooknextpage(uint16 argc, uint16 *argv) {
// Get the page variable
uint32 *page = _vm->getVar("blabbook");
// Increment the page if it's not the last page
if (*page == 22)
return;
(*page)++;
// Play the page turning sound
_vm->_sound->playSound(23);
// Now update the screen :)
_vm->_gfx->scheduleTransition(0);
_vm->_gfx->updateScreen();
}
void RivenExternal::xsoundplug(uint16 argc, uint16 *argv) {
uint32 heat = *_vm->getVar("bheat");
uint32 boilerInactive = *_vm->getVar("bcratergg");
if (heat != 0)
_vm->_sound->playSLST(1, _vm->getCurCard());
else if (boilerInactive != 0)
_vm->_sound->playSLST(2, _vm->getCurCard());
else
_vm->_sound->playSLST(3, _vm->getCurCard());
}
void RivenExternal::xbchangeboiler(uint16 argc, uint16 *argv) {
uint32 heat = *_vm->getVar("bheat");
uint32 water = *_vm->getVar("bblrwtr");
uint32 platform = *_vm->getVar("bblrgrt");
// Stop any background videos
_vm->_video->stopVideos();
if (argv[0] == 1) {
// Water is filling/draining from the boiler
if (water == 0) {
if (platform == 1)
_vm->_video->activateMLST(12, _vm->getCurCard());
else
_vm->_video->activateMLST(10, _vm->getCurCard());
} else if (heat == 1) {
if (platform == 1)
_vm->_video->activateMLST(22, _vm->getCurCard());
else
_vm->_video->activateMLST(19, _vm->getCurCard());
} else {
if (platform == 1)
_vm->_video->activateMLST(16, _vm->getCurCard());
else
_vm->_video->activateMLST(13, _vm->getCurCard());
}
} else if (argv[0] == 2 && water != 0) {
if (heat == 1) {
// Turning on the heat
if (platform == 1)
_vm->_video->activateMLST(23, _vm->getCurCard());
else
_vm->_video->activateMLST(20, _vm->getCurCard());
} else {
// Turning off the heat
if (platform == 1)
_vm->_video->activateMLST(18, _vm->getCurCard());
else
_vm->_video->activateMLST(15, _vm->getCurCard());
}
} else if (argv[0] == 3) {
if (platform == 1) {
// Lowering the platform
if (water == 1) {
if (heat == 1)
_vm->_video->activateMLST(24, _vm->getCurCard());
else
_vm->_video->activateMLST(17, _vm->getCurCard());
} else
_vm->_video->activateMLST(11, _vm->getCurCard());
} else {
// Raising the platform
if (water == 1) {
if (heat == 1)
_vm->_video->activateMLST(21, _vm->getCurCard());
else
_vm->_video->activateMLST(14, _vm->getCurCard());
} else
_vm->_video->activateMLST(9, _vm->getCurCard());
}
}
if (argc > 1)
_vm->_sound->playSLST(argv[1], _vm->getCurCard());
else if (argv[0] == 2)
_vm->_sound->playSLST(1, _vm->getCurCard());
_vm->_gfx->changeCursor(kRivenHideCursor);
_vm->_video->playMovieBlocking(11);
}
void RivenExternal::xbupdateboiler(uint16 argc, uint16 *argv) {
uint32 heat = *_vm->getVar("bheat");
uint32 platform = *_vm->getVar("bblrgrt");
if (heat) {
if (platform == 0) {
_vm->_video->activateMLST(8, _vm->getCurCard());
_vm->_video->playMovie(8);
} else {
_vm->_video->activateMLST(7, _vm->getCurCard());
_vm->_video->playMovie(7);
}
} else {
_vm->_video->disableMovie(7);
_vm->_video->disableMovie(8);
}
}
void RivenExternal::xbsettrap(uint16 argc, uint16 *argv) {
// TODO: Set the Ytram trap
}
void RivenExternal::xbcheckcatch(uint16 argc, uint16 *argv) {
// TODO: Check if we've caught a Ytram
}
void RivenExternal::xbait(uint16 argc, uint16 *argv) {
// Set the cursor to the pellet
_vm->_gfx->changeCursor(kRivenPelletCursor);
// Loop until the player lets go (or quits)
Common::Event event;
bool mouseDown = true;
while (mouseDown) {
while (_vm->_system->getEventManager()->pollEvent(event)) {
if (event.type == Common::EVENT_LBUTTONUP)
mouseDown = false;
else if (event.type == Common::EVENT_MOUSEMOVE)
_vm->_system->updateScreen();
else if (event.type == Common::EVENT_QUIT || event.type == Common::EVENT_RTL)
return;
}
_vm->_system->delayMillis(10); // Take it easy on the CPU
}
// Set back the cursor
_vm->_gfx->changeCursor(kRivenMainCursor);
// Set the bait if we put it on the plate
if (_vm->_hotspots[9].rect.contains(_vm->_system->getEventManager()->getMousePos())) {
*_vm->getVar("bbait") = 1;
_vm->_gfx->drawPLST(4);
_vm->_gfx->updateScreen();
_vm->_hotspots[3].enabled = false; // Disable bait hotspot
_vm->_hotspots[9].enabled = true; // Enable baitplate hotspot
}
}
void RivenExternal::xbfreeytram(uint16 argc, uint16 *argv) {
// TODO: Play a random Ytram movie
}
void RivenExternal::xbaitplate(uint16 argc, uint16 *argv) {
// Remove the pellet from the plate and put it in your hand
_vm->_gfx->drawPLST(3);
_vm->_gfx->updateScreen();
_vm->_gfx->changeCursor(kRivenPelletCursor);
// Loop until the player lets go (or quits)
Common::Event event;
bool mouseDown = true;
while (mouseDown) {
while (_vm->_system->getEventManager()->pollEvent(event)) {
if (event.type == Common::EVENT_LBUTTONUP)
mouseDown = false;
else if (event.type == Common::EVENT_MOUSEMOVE)
_vm->_system->updateScreen();
else if (event.type == Common::EVENT_QUIT || event.type == Common::EVENT_RTL)
return;
}
_vm->_system->delayMillis(10); // Take it easy on the CPU
}
// Set back the cursor
_vm->_gfx->changeCursor(kRivenMainCursor);
// Set the bait if we put it on the plate, remove otherwise
if (_vm->_hotspots[9].rect.contains(_vm->_system->getEventManager()->getMousePos())) {
*_vm->getVar("bbait") = 1;
_vm->_gfx->drawPLST(4);
_vm->_gfx->updateScreen();
_vm->_hotspots[3].enabled = false; // Disable bait hotspot
_vm->_hotspots[9].enabled = true; // Enable baitplate hotspot
} else {
*_vm->getVar("bbait") = 0;
_vm->_hotspots[3].enabled = true; // Enable bait hotspot
_vm->_hotspots[9].enabled = false; // Disable baitplate hotspot
}
}
void RivenExternal::xbisland190_opencard(uint16 argc, uint16 *argv) {
checkDomeSliders(27, 28);
}
void RivenExternal::xbisland190_resetsliders(uint16 argc, uint16 *argv) {
resetDomeSliders(701, 41, 2);
}
void RivenExternal::xbisland190_slidermd(uint16 argc, uint16 *argv) {
dragDomeSlider(701, 41, 27, 28, 2);
}
void RivenExternal::xbisland190_slidermw(uint16 argc, uint16 *argv) {
checkSliderCursorChange(2);
}
void RivenExternal::xbscpbtn(uint16 argc, uint16 *argv) {
runDomeButtonMovie();
}
void RivenExternal::xbisland_domecheck(uint16 argc, uint16 *argv) {
runDomeCheck();
}
void RivenExternal::xvalvecontrol(uint16 argc, uint16 *argv) {
Common::Point startPos = _vm->_system->getEventManager()->getMousePos();
// Get the variable for the valve
uint32 *valve = _vm->getVar("bvalve");
int changeX = 0;
int changeY = 0;
bool done = false;
// Set the cursor to the closed position
_vm->_gfx->changeCursor(kRivenClosedHandCursor);
_vm->_system->updateScreen();
while (!done) {
Common::Event event;
while (_vm->_system->getEventManager()->pollEvent(event)) {
switch (event.type) {
case Common::EVENT_MOUSEMOVE:
changeX = event.mouse.x - startPos.x;
changeY = startPos.y - event.mouse.y;
_vm->_system->updateScreen();
break;
case Common::EVENT_LBUTTONUP:
// FIXME: These values for changes in x/y could be tweaked.
if (*valve == 0 && changeY <= -10) {
*valve = 1;
_vm->_gfx->changeCursor(kRivenHideCursor);
_vm->_video->playMovieBlocking(2);
_vm->refreshCard();
} else if (*valve == 1) {
if (changeX >= 0 && changeY >= 10) {
*valve = 0;
_vm->_gfx->changeCursor(kRivenHideCursor);
_vm->_video->playMovieBlocking(3);
_vm->refreshCard();
} else if (changeX <= -10 && changeY <= 10) {
*valve = 2;
_vm->_gfx->changeCursor(kRivenHideCursor);
_vm->_video->playMovieBlocking(1);
_vm->refreshCard();
}
} else if (*valve == 2 && changeX >= 10) {
*valve = 1;
_vm->_gfx->changeCursor(kRivenHideCursor);
_vm->_video->playMovieBlocking(4);
_vm->refreshCard();
}
done = true;
default:
break;
}
}
_vm->_system->delayMillis(10);
}
// If we changed state and the new state is that the valve is flowing to
// the boiler, we need to update the boiler state.
if (*valve == 1) {
if (*_vm->getVar("bidvlv") == 1) { // Check which way the water is going at the boiler
if (*_vm->getVar("bblrarm") == 1) {
// If the pipe is open, make sure the water is drained out
*_vm->getVar("bheat") = 0;
*_vm->getVar("bblrwtr") = 0;
} else {
// If the pipe is closed, fill the boiler again
*_vm->getVar("bheat") = *_vm->getVar("bblrvalve");
*_vm->getVar("bblrwtr") = 1;
}
} else {
// Have the grating inside the boiler match the switch outside
*_vm->getVar("bblrgrt") = (*_vm->getVar("bblrsw") == 1) ? 0 : 1;
}
}
}
void RivenExternal::xbchipper(uint16 argc, uint16 *argv) {
// Why is this an external command....?
if (*_vm->getVar("bvalve") == 2)
_vm->_video->playMovieBlocking(2);
}
// ------------------------------------------------------------------------------------
// gspit (Garden Island) external commands
// ------------------------------------------------------------------------------------
void RivenExternal::xgresetpins(uint16 argc, uint16 *argv) {
// TODO: Map related
}
void RivenExternal::xgrotatepins(uint16 argc, uint16 *argv) {
// TODO: Map related
}
void RivenExternal::xgpincontrols(uint16 argc, uint16 *argv) {
// TODO: Map related
}
void RivenExternal::xgisland25_opencard(uint16 argc, uint16 *argv) {
checkDomeSliders(29, 30);
}
void RivenExternal::xgisland25_resetsliders(uint16 argc, uint16 *argv) {
resetDomeSliders(161, 16, 2);
}
void RivenExternal::xgisland25_slidermd(uint16 argc, uint16 *argv) {
dragDomeSlider(161, 16, 29, 30, 2);
}
void RivenExternal::xgisland25_slidermw(uint16 argc, uint16 *argv) {
checkSliderCursorChange(2);
}
void RivenExternal::xgscpbtn(uint16 argc, uint16 *argv) {
runDomeButtonMovie();
}
void RivenExternal::xgisland1490_domecheck(uint16 argc, uint16 *argv) {
runDomeCheck();
}
void RivenExternal::xgplateau3160_dopools(uint16 argc, uint16 *argv) {
// Play the deactivation of a pool if one is active and a different one is activated
_vm->_gfx->changeCursor(kRivenHideCursor);
_vm->_video->playMovieBlocking(*_vm->getVar("glkbtns") * 2);
}
void RivenExternal::xgwt200_scribetime(uint16 argc, uint16 *argv) {
// Get the current time
*_vm->getVar("gscribetime") = _vm->_system->getMillis();
}
void RivenExternal::xgwt900_scribe(uint16 argc, uint16 *argv) {
uint32 *scribeVar = _vm->getVar("gscribe");
if (*scribeVar == 1 && _vm->_system->getMillis() > *_vm->getVar("gscribetime") + 40000)
*scribeVar = 2;
}
void RivenExternal::xgplaywhark(uint16 argc, uint16 *argv) {
// TODO: Whark response to using the lights
}
void RivenExternal::xgrviewer(uint16 argc, uint16 *argv) {
// TODO: Image viewer related
}
void RivenExternal::xgwharksnd(uint16 argc, uint16 *argv) {
// TODO: Image viewer related
}
void RivenExternal::xglview_prisonoff(uint16 argc, uint16 *argv) {
// TODO: Image viewer related
}
void RivenExternal::xglview_villageoff(uint16 argc, uint16 *argv) {
// TODO: Image viewer related
}
void RivenExternal::xglviewer(uint16 argc, uint16 *argv) {
// TODO: Image viewer related
}
void RivenExternal::xglview_prisonon(uint16 argc, uint16 *argv) {
// TODO: Image viewer related
}
void RivenExternal::xglview_villageon(uint16 argc, uint16 *argv) {
// TODO: Image viewer related
}
// ------------------------------------------------------------------------------------
// jspit (Jungle Island) external commands
// ------------------------------------------------------------------------------------
void RivenExternal::xreseticons(uint16 argc, uint16 *argv) {
// Reset the icons when going to Tay (rspit)
*_vm->getVar("jicons") = 0;
*_vm->getVar("jiconorder") = 0;
*_vm->getVar("jrbook") = 0;
}
// Count up how many icons are pressed
static byte countDepressedIcons(uint32 iconOrderVar) {
if (iconOrderVar >= (1 << 20))
return 5;
else if (iconOrderVar >= (1 << 15))
return 4;
else if (iconOrderVar >= (1 << 10))
return 3;
else if (iconOrderVar >= (1 << 5))
return 2;
else if (iconOrderVar >= (1 << 1))
return 1;
else
return 0;
}
void RivenExternal::xicon(uint16 argc, uint16 *argv) {
// Set atemp as the status of whether or not the icon can be depressed.
if (*_vm->getVar("jicons") & (1 << (argv[0] - 1))) {
// This icon is depressed. Allow depression only if the last depressed icon was this one.
if ((*_vm->getVar("jiconorder") & 0x1f) == argv[0])
*_vm->getVar("atemp") = 1;
else
*_vm->getVar("atemp") = 2;
} else
*_vm->getVar("atemp") = 0;
}
void RivenExternal::xcheckicons(uint16 argc, uint16 *argv) {
// Reset the icons if this is the sixth icon
uint32 *iconOrderVar = _vm->getVar("jiconorder");
if (countDepressedIcons(*iconOrderVar) == 5) {
*iconOrderVar = 0;
*_vm->getVar("jicons") = 0;
_vm->_sound->playSound(46);
}
}
void RivenExternal::xtoggleicon(uint16 argc, uint16 *argv) {
// Get the variables
uint32 *iconsDepressed = _vm->getVar("jicons");
uint32 *iconOrderVar = _vm->getVar("jiconorder");
if (*iconsDepressed & (1 << (argv[0] - 1))) {
// The icon is depressed, now unpress it
*iconsDepressed &= ~(1 << (argv[0] - 1));
*iconOrderVar >>= 5;
} else {
// The icon is not depressed, now depress it
*iconsDepressed |= 1 << (argv[0] - 1);
*iconOrderVar = (*iconOrderVar << 5) + argv[0];
}
// Check if the puzzle is complete now and assign 1 to jrbook if the puzzle is complete.
if (*iconOrderVar == *_vm->getVar("jiconcorrectorder"))
*_vm->getVar("jrbook") = 1;
}
void RivenExternal::xjtunnel103_pictfix(uint16 argc, uint16 *argv) {
// Get the jicons variable which contains which of the stones are depressed in the rebel tunnel puzzle
uint32 iconsDepressed = *_vm->getVar("jicons");
// Now, draw which icons are depressed based on the bits of the variable
if (iconsDepressed & (1 << 0))
_vm->_gfx->drawPLST(2);
if (iconsDepressed & (1 << 1))
_vm->_gfx->drawPLST(3);
if (iconsDepressed & (1 << 2))
_vm->_gfx->drawPLST(4);
if (iconsDepressed & (1 << 3))
_vm->_gfx->drawPLST(5);
if (iconsDepressed & (1 << 22))
_vm->_gfx->drawPLST(6);
if (iconsDepressed & (1 << 23))
_vm->_gfx->drawPLST(7);
if (iconsDepressed & (1 << 24))
_vm->_gfx->drawPLST(8);
}
void RivenExternal::xjtunnel104_pictfix(uint16 argc, uint16 *argv) {
// Get the jicons variable which contains which of the stones are depressed in the rebel tunnel puzzle
uint32 iconsDepressed = *_vm->getVar("jicons");
// Now, draw which icons are depressed based on the bits of the variable
if (iconsDepressed & (1 << 9))
_vm->_gfx->drawPLST(2);
if (iconsDepressed & (1 << 10))
_vm->_gfx->drawPLST(3);
if (iconsDepressed & (1 << 11))
_vm->_gfx->drawPLST(4);
if (iconsDepressed & (1 << 12))
_vm->_gfx->drawPLST(5);
if (iconsDepressed & (1 << 13))
_vm->_gfx->drawPLST(6);
if (iconsDepressed & (1 << 14))
_vm->_gfx->drawPLST(7);
if (iconsDepressed & (1 << 15))
_vm->_gfx->drawPLST(8);
if (iconsDepressed & (1 << 16))
_vm->_gfx->drawPLST(9);
}
void RivenExternal::xjtunnel105_pictfix(uint16 argc, uint16 *argv) {
// Get the jicons variable which contains which of the stones are depressed in the rebel tunnel puzzle
uint32 iconsDepressed = *_vm->getVar("jicons");
// Now, draw which icons are depressed based on the bits of the variable
if (iconsDepressed & (1 << 3))
_vm->_gfx->drawPLST(2);
if (iconsDepressed & (1 << 4))
_vm->_gfx->drawPLST(3);
if (iconsDepressed & (1 << 5))
_vm->_gfx->drawPLST(4);
if (iconsDepressed & (1 << 6))
_vm->_gfx->drawPLST(5);
if (iconsDepressed & (1 << 7))
_vm->_gfx->drawPLST(6);
if (iconsDepressed & (1 << 8))
_vm->_gfx->drawPLST(7);
if (iconsDepressed & (1 << 9))
_vm->_gfx->drawPLST(8);
}
void RivenExternal::xjtunnel106_pictfix(uint16 argc, uint16 *argv) {
// Get the jicons variable which contains which of the stones are depressed in the rebel tunnel puzzle
uint32 iconsDepressed = *_vm->getVar("jicons");
// Now, draw which icons are depressed based on the bits of the variable
if (iconsDepressed & (1 << 16))
_vm->_gfx->drawPLST(2);
if (iconsDepressed & (1 << 17))
_vm->_gfx->drawPLST(3);
if (iconsDepressed & (1 << 18))
_vm->_gfx->drawPLST(4);
if (iconsDepressed & (1 << 19))
_vm->_gfx->drawPLST(5);
if (iconsDepressed & (1 << 20))
_vm->_gfx->drawPLST(6);
if (iconsDepressed & (1 << 21))
_vm->_gfx->drawPLST(7);
if (iconsDepressed & (1 << 22))
_vm->_gfx->drawPLST(8);
if (iconsDepressed & (1 << 23))
_vm->_gfx->drawPLST(9);
}
void RivenExternal::xvga1300_carriage(uint16 argc, uint16 *argv) {
// Run the gallows's carriage
_vm->_gfx->changeCursor(kRivenHideCursor); // Hide the cursor
_vm->_video->playMovieBlocking(1); // Play handle movie
_vm->_gfx->scheduleTransition(15); // Set pan down transition
_vm->changeToCard(_vm->matchRMAPToCard(0x18e77)); // Change to card facing up
_vm->_gfx->changeCursor(kRivenHideCursor); // Hide the cursor (again)
_vm->_video->playMovieBlocking(4); // Play carriage beginning to drop
_vm->_gfx->scheduleTransition(14); // Set pan up transition
_vm->changeToCard(_vm->matchRMAPToCard(0x183a9)); // Change to card looking straight again
_vm->_video->playMovieBlocking(2);
uint32 *gallows = _vm->getVar("jgallows");
if (*gallows == 1) {
// If the gallows is open, play the up movie and return
_vm->_video->playMovieBlocking(3);
return;
}
// Give the player 5 seconds to click (anywhere)
uint32 startTime = _vm->_system->getMillis();
bool gotClick = false;
while (_vm->_system->getMillis() - startTime <= 5000 && !gotClick) {
Common::Event event;
while (_vm->_system->getEventManager()->pollEvent(event)) {
switch (event.type) {
case Common::EVENT_MOUSEMOVE:
_vm->_system->updateScreen();
break;
case Common::EVENT_LBUTTONUP:
gotClick = true;
break;
default:
break;
}
}
_vm->_system->delayMillis(10);
}
_vm->_gfx->changeCursor(kRivenHideCursor); // Hide the cursor
if (gotClick) {
_vm->_gfx->scheduleTransition(16); // Schedule dissolve transition
_vm->changeToCard(_vm->matchRMAPToCard(0x18d4d)); // Move forward
_vm->_gfx->changeCursor(kRivenHideCursor); // Hide the cursor
_vm->_system->delayMillis(500); // Delay a half second before changing again
_vm->_gfx->scheduleTransition(12); // Schedule pan left transition
_vm->changeToCard(_vm->matchRMAPToCard(0x18ab5)); // Turn right
_vm->_gfx->changeCursor(kRivenHideCursor); // Hide the cursor
_vm->_video->playMovieBlocking(1); // Play carriage ride movie
_vm->changeToCard(_vm->matchRMAPToCard(0x17167)); // We have arrived at the top
} else
_vm->_video->playMovieBlocking(3); // Too slow!
}
void RivenExternal::xjdome25_resetsliders(uint16 argc, uint16 *argv) {
resetDomeSliders(_vm->getFeatures() & GF_DVD ? 547 : 548, 81, 2);
}
void RivenExternal::xjdome25_slidermd(uint16 argc, uint16 *argv) {
dragDomeSlider(_vm->getFeatures() & GF_DVD ? 547: 548, 81, 29, 28, 2);
}
void RivenExternal::xjdome25_slidermw(uint16 argc, uint16 *argv) {
checkSliderCursorChange(2);
}
void RivenExternal::xjscpbtn(uint16 argc, uint16 *argv) {
runDomeButtonMovie();
}
void RivenExternal::xjisland3500_domecheck(uint16 argc, uint16 *argv) {
runDomeCheck();
}
int RivenExternal::jspitElevatorLoop() {
Common::Point startPos = _vm->_system->getEventManager()->getMousePos();
Common::Event event;
int changeLevel = 0;
_vm->_gfx->changeCursor(kRivenClosedHandCursor);
_vm->_system->updateScreen();
for (;;) {
while (_vm->_system->getEventManager()->pollEvent(event)) {
switch (event.type) {
case Common::EVENT_MOUSEMOVE:
if (event.mouse.y > (startPos.y + 10)) {
changeLevel = -1;
} else if (event.mouse.y < (startPos.y - 10)) {
changeLevel = 1;
} else {
changeLevel = 0;
}
_vm->_system->updateScreen();
break;
case Common::EVENT_LBUTTONUP:
_vm->_gfx->changeCursor(kRivenMainCursor);
_vm->_system->updateScreen();
return changeLevel;
default:
break;
}
}
_vm->_system->delayMillis(10);
}
}
void RivenExternal::xhandlecontrolup(uint16 argc, uint16 *argv) {
int changeLevel = jspitElevatorLoop();
// If we've moved the handle down, go down a floor
if (changeLevel == -1) {
_vm->_video->playMovieBlocking(1);
_vm->_video->playMovieBlocking(2);
_vm->changeToCard(_vm->matchRMAPToCard(0x1e374));
}
}
void RivenExternal::xhandlecontroldown(uint16 argc, uint16 *argv) {
int changeLevel = jspitElevatorLoop();
// If we've moved the handle up, go up a floor
if (changeLevel == 1) {
_vm->_video->playMovieBlocking(1);
_vm->_video->playMovieBlocking(2);
_vm->changeToCard(_vm->matchRMAPToCard(0x1e374));
}
}
void RivenExternal::xhandlecontrolmid(uint16 argc, uint16 *argv) {
int changeLevel = jspitElevatorLoop();
if (changeLevel == 0)
return;
// Play the handle moving video
if (changeLevel == 1)
_vm->_video->playMovieBlocking(7);
else
_vm->_video->playMovieBlocking(6);
// If the whark's mouth is open, close it
uint32 *mouthVar = _vm->getVar("jwmouth");
if (*mouthVar == 1) {
_vm->_video->playMovieBlocking(3);
_vm->_video->playMovieBlocking(8);
*mouthVar = 0;
}
// Play the elevator video and then change the card
if (changeLevel == 1) {
_vm->_video->playMovieBlocking(5);
_vm->changeToCard(_vm->matchRMAPToCard(0x1e597));
} else {
_vm->_video->playMovieBlocking(4);
_vm->changeToCard(_vm->matchRMAPToCard(0x1e29c));
}
}
void RivenExternal::xjplaybeetle_550(uint16 argc, uint16 *argv) {
// Play a beetle animation 25% of the time
*_vm->getVar("jplaybeetle") = (_vm->_rnd->getRandomNumberRng(0, 3) == 0) ? 1 : 0;
}
void RivenExternal::xjplaybeetle_600(uint16 argc, uint16 *argv) {
// Play a beetle animation 25% of the time
*_vm->getVar("jplaybeetle") = (_vm->_rnd->getRandomNumberRng(0, 3) == 0) ? 1 : 0;
}
void RivenExternal::xjplaybeetle_950(uint16 argc, uint16 *argv) {
// Play a beetle animation 25% of the time
*_vm->getVar("jplaybeetle") = (_vm->_rnd->getRandomNumberRng(0, 3) == 0) ? 1 : 0;
}
void RivenExternal::xjplaybeetle_1050(uint16 argc, uint16 *argv) {
// Play a beetle animation 25% of the time
*_vm->getVar("jplaybeetle") = (_vm->_rnd->getRandomNumberRng(0, 3) == 0) ? 1 : 0;
}
void RivenExternal::xjplaybeetle_1450(uint16 argc, uint16 *argv) {
// Play a beetle animation 25% of the time as long as the girl is not present
*_vm->getVar("jplaybeetle") = (_vm->_rnd->getRandomNumberRng(0, 3) == 0 && *_vm->getVar("jgirl") != 1) ? 1 : 0;
}
void RivenExternal::xjlagoon700_alert(uint16 argc, uint16 *argv) {
// TODO: Sunner related
}
void RivenExternal::xjlagoon800_alert(uint16 argc, uint16 *argv) {
// TODO: Sunner related
}
void RivenExternal::xjlagoon1500_alert(uint16 argc, uint16 *argv) {
// Have the sunners move a bit as you get closer ;)
uint32 *sunners = _vm->getVar("jsunners");
if (*sunners == 0) {
_vm->_video->playMovieBlocking(3);
} else if (*sunners == 1) {
_vm->_video->playMovieBlocking(2);
*sunners = 2;
}
}
void RivenExternal::xschool280_playwhark(uint16 argc, uint16 *argv) {
// TODO: The "monstrous" whark puzzle that teaches the number system
}
void RivenExternal::xjatboundary(uint16 argc, uint16 *argv) {
runDemoBoundaryDialog();
}
// ------------------------------------------------------------------------------------
// ospit (Gehn's Office) external commands
// ------------------------------------------------------------------------------------
void RivenExternal::xorollcredittime(uint16 argc, uint16 *argv) {
// WORKAROUND: The special change stuff only handles one destination and it would
// be messy to modify the way that currently works. If we use the trap book on Tay,
// we should be using the Tay end game sequences.
if (*_vm->getVar("returnstackid") == rspit) {
_vm->changeToStack(rspit);
_vm->changeToCard(2);
return;
}
// You used the trap book... why? What were you thinking?
uint32 *gehnState = _vm->getVar("agehn");
if (*gehnState == 0) // Gehn who?
runEndGame(1);
else if (*gehnState == 4) // You freed him? Are you kidding me?
runEndGame(2);
else // You already spoke with Gehn. What were you thinking?
runEndGame(3);
}
void RivenExternal::xbookclick(uint16 argc, uint16 *argv) {
// Hide the cursor
_vm->_gfx->changeCursor(kRivenHideCursor);
// Let's hook onto our video
VideoHandle video = _vm->_video->findVideoHandle(argv[0]);
// Convert from the standard QuickTime base time to milliseconds
// The values are in terms of 1/600 of a second.
// Have I said how much I just *love* QuickTime? </sarcasm>
uint32 startTime = argv[1] * 1000 / 600;
uint32 endTime = argv[2] * 1000 / 600;
// Track down our hotspot
// Of course, they're not in any sane order...
static const uint16 hotspotMap[] = { 1, 3, 2, 0 };
Common::Rect hotspotRect = _vm->_hotspots[hotspotMap[argv[3] - 1]].rect;
debug(0, "xbookclick:");
debug(0, "\tVideo Code = %d", argv[0]);
debug(0, "\tStart Time = %dms", startTime);
debug(0, "\tEnd Time = %dms", endTime);
debug(0, "\tHotspot = %d -> %d", argv[3], hotspotMap[argv[3] - 1]);
// Just let the video play while we wait until Gehn opens the trap book for us
while (_vm->_video->getElapsedTime(video) < startTime && !_vm->shouldQuit()) {
if (_vm->_video->updateBackgroundMovies())
_vm->_system->updateScreen();
Common::Event event;
while (_vm->_system->getEventManager()->pollEvent(event))
;
_vm->_system->delayMillis(10);
}
// Break out if we're quitting
if (_vm->shouldQuit())
return;
// Update our hotspot stuff
if (hotspotRect.contains(_vm->_system->getEventManager()->getMousePos()))
_vm->_gfx->changeCursor(kRivenOpenHandCursor);
else
_vm->_gfx->changeCursor(kRivenMainCursor);
// OK, Gehn has opened the trap book and has asked us to go in. Let's watch
// and see what the player will do...
while (_vm->_video->getElapsedTime(video) < endTime && !_vm->shouldQuit()) {
bool updateScreen = _vm->_video->updateBackgroundMovies();
Common::Event event;
while (_vm->_system->getEventManager()->pollEvent(event)) {
switch (event.type) {
case Common::EVENT_MOUSEMOVE:
if (hotspotRect.contains(_vm->_system->getEventManager()->getMousePos()))
_vm->_gfx->changeCursor(kRivenOpenHandCursor);
else
_vm->_gfx->changeCursor(kRivenMainCursor);
updateScreen = false; // Don't update twice, changing the cursor already updates the screen
break;
case Common::EVENT_LBUTTONUP:
if (hotspotRect.contains(_vm->_system->getEventManager()->getMousePos())) {
// OK, we've used the trap book! We go for ride lady!
_vm->_scriptMan->stopAllScripts(); // Stop all running scripts (so we don't remain in the cage)
_vm->_video->stopVideos(); // Stop all videos
_vm->_gfx->changeCursor(kRivenHideCursor); // Hide the cursor
_vm->_gfx->drawPLST(3); // Black out the screen
_vm->_gfx->updateScreen(); // Update the screen
_vm->_sound->playSound(0); // Play the link sound
_vm->_video->activateMLST(7, _vm->getCurCard()); // Activate Gehn Link Video
_vm->_video->playMovieBlocking(1); // Play Gehn Link Video
*_vm->getVar("agehn") = 4; // Set Gehn to the trapped state
*_vm->getVar("atrapbook") = 1; // We've got the trap book again
_vm->_sound->playSound(0); // Play the link sound again
_vm->changeToCard(_vm->matchRMAPToCard(0x2885)); // Link out! (TODO: Shouldn't this card change?)
return;
}
break;
default:
break;
}
}
if (updateScreen && !_vm->shouldQuit())
_vm->_system->updateScreen();
_vm->_system->delayMillis(10);
}
// Break out if we're quitting
if (_vm->shouldQuit())
return;
// Hide the cursor again
_vm->_gfx->changeCursor(kRivenHideCursor);
// If there was no click and this is the third time Gehn asks us to
// use the trap book, he will shoot the player. Dead on arrival.
// Run the credits from here.
if (*_vm->getVar("agehn") == 3) {
_vm->_scriptMan->stopAllScripts();
runCredits(argv[0]);
return;
}
// There was no click, so just play the rest of the video.
while (!_vm->_video->endOfVideo(video) && !_vm->shouldQuit()) {
if (_vm->_video->updateBackgroundMovies())
_vm->_system->updateScreen();
Common::Event event;
while (_vm->_system->getEventManager()->pollEvent(event))
;
_vm->_system->delayMillis(10);
}
}
void RivenExternal::xooffice30_closebook(uint16 argc, uint16 *argv) {
// Close the blank linking book if it's open
uint32 *book = _vm->getVar("odeskbook");
if (*book != 1)
return;
// Set the variable to be "closed"
*book = 0;
// Play the movie
_vm->_video->playMovieBlocking(1);
// Set the hotspots into their correct states
_vm->_hotspots[2].enabled = false;
_vm->_hotspots[5].enabled = false;
_vm->_hotspots[6].enabled = true;
// We now need to draw PLST 1 and refresh, but PLST 1 is
// drawn when refreshing anyway, so don't worry about that.
_vm->refreshCard();
}
void RivenExternal::xobedroom5_closedrawer(uint16 argc, uint16 *argv) {
// Close the drawer if open when clicking on the journal.
_vm->_video->playMovieBlocking(2);
*_vm->getVar("ostanddrawer") = 0;
}
void RivenExternal::xogehnopenbook(uint16 argc, uint16 *argv) {
_vm->_gfx->drawPLST(*_vm->getVar("ogehnpage"));
}
void RivenExternal::xogehnbookprevpage(uint16 argc, uint16 *argv) {
// Get the page variable
uint32 *page = _vm->getVar("ogehnpage");
// Decrement the page if it's not the first page
if (*page == 1)
return;
(*page)--;
// Play the page turning sound
_vm->_sound->playSound(12);
// Now update the screen :)
_vm->_gfx->scheduleTransition(1);
_vm->_gfx->updateScreen();
}
void RivenExternal::xogehnbooknextpage(uint16 argc, uint16 *argv) {
// Get the page variable
uint32 *page = _vm->getVar("ogehnpage");
// Increment the page if it's not the last page
if (*page == 13)
return;
(*page)++;
// Play the page turning sound
_vm->_sound->playSound(13);
// Now update the screen :)
_vm->_gfx->scheduleTransition(0);
_vm->_gfx->updateScreen();
}
uint16 RivenExternal::getComboDigit(uint32 correctCombo, uint32 digit) {
static const uint32 powers[] = { 100000, 10000, 1000, 100, 10, 1 };
return (correctCombo % powers[digit]) / powers[digit + 1];
}
void RivenExternal::xgwatch(uint16 argc, uint16 *argv) {
// Hide the cursor
_vm->_gfx->changeCursor(kRivenHideCursor);
uint32 *prisonCombo = _vm->getVar("pcorrectorder");
uint32 soundTime = _vm->_system->getMillis() - 500; // Start the first sound instantly
byte curSound = 0;
while (!_vm->shouldQuit()) {
// Play the next sound every half second
if (_vm->_system->getMillis() - soundTime >= 500) {
if (curSound == 5) // Break out after the last sound is done
break;
_vm->_sound->playSound(getComboDigit(*prisonCombo, curSound) + 13);
curSound++;
soundTime = _vm->_system->getMillis();
}
// Poll events just to check for quitting
Common::Event event;
while (_vm->_system->getEventManager()->pollEvent(event)) {}
// Cut down on CPU usage
_vm->_system->delayMillis(10);
}
// Now play the video for the watch
_vm->_video->activateMLST(1, _vm->getCurCard());
_vm->_video->playMovieBlocking(1);
// And, finally, refresh
_vm->refreshCard();
}
// ------------------------------------------------------------------------------------
// pspit (Prison Island) external commands
// ------------------------------------------------------------------------------------
void RivenExternal::xpisland990_elevcombo(uint16 argc, uint16 *argv) {
// Play button sound based on argv[0]
_vm->_sound->playSound(argv[0] + 5);
// It is impossible to get here if Gehn is not trapped. However,
// the original also disallows brute forcing the ending if you have
// not yet trapped Gehn.
if (*_vm->getVar("agehn") != 4)
return;
uint32 *correctDigits = _vm->getVar("pelevcombo");
// pelevcombo keeps count of how many buttons we have pressed in the correct order.
// When pelevcombo is 5, clicking the handle will show the video freeing Catherine.
if (*correctDigits < 5 && argv[0] == getComboDigit(*_vm->getVar("pcorrectorder"), *correctDigits))
*correctDigits += 1;
else
*correctDigits = 0;
}
void RivenExternal::xpscpbtn(uint16 argc, uint16 *argv) {
runDomeButtonMovie();
}
void RivenExternal::xpisland290_domecheck(uint16 argc, uint16 *argv) {
runDomeCheck();
}
void RivenExternal::xpisland25_opencard(uint16 argc, uint16 *argv) {
checkDomeSliders(31, 5);
}
void RivenExternal::xpisland25_resetsliders(uint16 argc, uint16 *argv) {
resetDomeSliders(58, 10, 6);
}
void RivenExternal::xpisland25_slidermd(uint16 argc, uint16 *argv) {
dragDomeSlider(58, 10, 31, 5, 6);
}
void RivenExternal::xpisland25_slidermw(uint16 argc, uint16 *argv) {
checkSliderCursorChange(6);
}
// ------------------------------------------------------------------------------------
// rspit (Rebel Age) external commands
// ------------------------------------------------------------------------------------
void RivenExternal::xrcredittime(uint16 argc, uint16 *argv) {
// Nice going, you used the trap book on Tay.
// The game chooses what ending based on agehn for us,
// so we just have to play the video and credits.
// For the record, when agehn == 4, Gehn will thank you for
// showing him the rebel age and then leave you to die.
// Otherwise, the rebels burn the book. Epic fail either way.
runEndGame(1);
}
void RivenExternal::xrshowinventory(uint16 argc, uint16 *argv) {
// Give the trap book and Catherine's journal to the player
*_vm->getVar("atrapbook") = 1;
*_vm->getVar("acathbook") = 1;
_vm->_gfx->showInventory();
}
void RivenExternal::xrhideinventory(uint16 argc, uint16 *argv) {
_vm->_gfx->hideInventory();
}
void RivenExternal::xrwindowsetup(uint16 argc, uint16 *argv) {
// TODO: Randomizing what effect happens when you look out into the middle of Tay (useless! :P)
}
// ------------------------------------------------------------------------------------
// tspit (Temple Island) external commands
// ------------------------------------------------------------------------------------
void RivenExternal::xtexterior300_telescopedown(uint16 argc, uint16 *argv) {
// First, show the button movie
_vm->_video->playMovieBlocking(3);
// Don't do anything else if the telescope power is off
if (*_vm->getVar("ttelevalve") == 0)
return;
uint32 *telescopePos = _vm->getVar("ttelescope");
uint32 *telescopeCover = _vm->getVar("ttelecover");
if (*telescopePos == 1) {
// We're at the bottom, which means one of two things can happen...
if (*telescopeCover == 1 && *_vm->getVar("ttelepin") == 1) {
// ...if the cover is open and the pin is up, the game is now over.
if (*_vm->getVar("pcage") == 2) {
// The best ending: Catherine is free, Gehn is trapped, Atrus comes to rescue you.
// And now we fall back to Earth... all the way...
warning("xtexterior300_telescopedown: Good ending");
_vm->_video->activateMLST(8, _vm->getCurCard());
runEndGame(8);
} else if (*_vm->getVar("agehn") == 4) {
// The ok ending: Catherine is still trapped, Gehn is trapped, Atrus comes to rescue you.
// Nice going! Catherine and the islanders are all dead now! Just go back to your home...
warning("xtexterior300_telescopedown: OK ending");
_vm->_video->activateMLST(9, _vm->getCurCard());
runEndGame(9);
} else if (*_vm->getVar("atrapbook") == 1) {
// The bad ending: Catherine is trapped, Gehn is free, Atrus gets shot by Gehn,
// And then you get shot by Cho. Nice going! Catherine and the islanders are dead
// and you have just set Gehn free from Riven, not to mention you're dead.
warning("xtexterior300_telescopedown: Bad ending");
_vm->_video->activateMLST(10, _vm->getCurCard());
runEndGame(10);
} else {
// The impossible ending: You don't have Catherine's journal and yet you were somehow
// able to open the hatch on the telescope. The game provides an ending for those who
// cheat, load a saved game with the combo, or just guess the telescope combo. Atrus
// doesn't come and you just fall into the fissure.
warning("xtexterior300_telescopedown: Wtf ending");
_vm->_video->activateMLST(11, _vm->getCurCard());
runEndGame(11);
}
} else {
// ...the telescope can't move down anymore.
// Play the sound of not being able to move
_vm->_gfx->changeCursor(kRivenHideCursor);
_vm->_sound->playSoundBlocking(13);
}
} else {
// We're not at the bottom, and we can move down again
// TODO: Down movie, it involves playing a chunk of a movie
// Now move the telescope down a position and refresh
*telescopePos -= 1;
_vm->refreshCard();
}
}
void RivenExternal::xtexterior300_telescopeup(uint16 argc, uint16 *argv) {
// First, show the button movie
_vm->_video->playMovieBlocking(3);
// Don't do anything else if the telescope power is off
if (*_vm->getVar("ttelevalve") == 0)
return;
uint32 *telescopePos = _vm->getVar("ttelescope");
// Check if we can't move up anymore
if (*telescopePos == 5) {
// Play the sound of not being able to move
_vm->_gfx->changeCursor(kRivenHideCursor);
_vm->_sound->playSoundBlocking(13);
return;
}
// TODO: Up movie, it involves playing a chunk of a movie
// Now move the telescope up a position and refresh
*telescopePos += 1;
_vm->refreshCard();
}
void RivenExternal::xtisland390_covercombo(uint16 argc, uint16 *argv) {
// Called when clicking the telescope cover buttons. argv[0] is the button number (1...5).
uint32 *correctDigits = _vm->getVar("tcovercombo");
if (*correctDigits < 5 && argv[0] == getComboDigit(*_vm->getVar("tcorrectorder"), *correctDigits))
*correctDigits += 1;
else
*correctDigits = 0;
// If we have hit the correct 5 buttons in a row, activate the hotspot to open up the
// telescope cover.
if (*correctDigits == 5)
_vm->_hotspots[9].enabled = true;
else
_vm->_hotspots[9].enabled = false;
}
// Atrus' Journal and Trap Book are added to inventory
void RivenExternal::xtatrusgivesbooks(uint16 argc, uint16 *argv) {
// Give the player Atrus' Journal and the Trap book
*_vm->getVar("aatrusbook") = 1;
*_vm->getVar("atrapbook") = 1;
}
// Trap Book is removed from inventory
void RivenExternal::xtchotakesbook(uint16 argc, uint16 *argv) {
// And now Cho takes the trap book. Sure, this isn't strictly
// necessary to add and them remove the trap book... but it
// seems better to do this ;)
*_vm->getVar("atrapbook") = 0;
}
void RivenExternal::xthideinventory(uint16 argc, uint16 *argv) {
_vm->_gfx->hideInventory();
}
// Marble Puzzle related constants
static const uint32 kMarbleCount = 6;
static const int kSmallMarbleWidth = 4;
static const int kSmallMarbleHeight = 2;
static const int kLargeMarbleSize = 8;
static const int kMarbleHotspotSize = 13;
static const char *s_marbleNames[] = { "tred", "torange", "tyellow", "tgreen", "tblue", "tviolet" };
// Marble Puzzle helper functions
// The y portion takes the upper 16 bits, while the x portion takes the lower 16 bits
static void setMarbleX(uint32 *var, byte x) {
*var = (*var & 0xff00) | (x + 1);
}
static void setMarbleY(uint32 *var, byte y) {
*var = ((y + 1) << 16) | (*var & 0xff);
}
static byte getMarbleX(uint32 *var) {
return (*var & 0xff) - 1;
}
static byte getMarbleY(uint32 *var) { // Give that that Y you old hag! </bad Seinfeld reference>
return ((*var >> 16) & 0xff) - 1;
}
static Common::Rect generateMarbleGridRect(uint16 x, uint16 y) {
// x/y in terms of 0!
static const int marbleGridOffsetX[] = { 134, 202, 270, 338, 406 };
static const int marbleGridOffsetY[] = { 24, 92, 159, 227, 295 };
uint16 offsetX = marbleGridOffsetX[x / 5] + (x % 5) * kMarbleHotspotSize;
uint16 offsetY = marbleGridOffsetY[y / 5] + (y % 5) * kMarbleHotspotSize;
return Common::Rect(offsetX, offsetY, offsetX + kMarbleHotspotSize, offsetY + kMarbleHotspotSize);
}
void RivenExternal::xt7500_checkmarbles(uint16 argc, uint16 *argv) {
// Set apower if the marbles are in their correct spot.
bool valid = true;
static const uint32 marbleFinalValues[] = { 1114121, 1441798, 0, 65552, 65558, 262146 };
for (uint16 i = 0; i < kMarbleCount; i++)
if (*_vm->getVar(s_marbleNames[i]) != marbleFinalValues[i]) {
valid = false;
break;
}
// If we have the correct combo, activate the power and reset the marble positions
// Otherwise, make sure the power is off
if (valid) {
*_vm->getVar("apower") = 1;
for (uint16 i = 0; i < kMarbleCount; i++)
*_vm->getVar(s_marbleNames[i]) = 0;
} else
*_vm->getVar("apower") = 0;
}
void RivenExternal::xt7600_setupmarbles(uint16 argc, uint16 *argv) {
// Draw the small marbles when we're a step away from the waffle
uint16 baseBitmapId = (_vm->getFeatures() & GF_DVD) ? 539 : 526;
bool waffleDown = *_vm->getVar("twaffle") != 0;
// Note that each of the small marble images is exactly 4x2
for (uint16 i = 0; i < kMarbleCount; i++) {
uint32 *var = _vm->getVar(s_marbleNames[i]);
if (*var == 0) {
// The marble is still in its initial place
// (Note that this is still drawn even if the waffle is down)
int marbleX = 376 + i * 2;
int marbleY = 253 + i * 4;
_vm->_gfx->copyImageToScreen(baseBitmapId + i, marbleX, marbleY, marbleX + kSmallMarbleWidth, marbleY + kSmallMarbleHeight);
} else if (waffleDown) {
// The marble is on the grid and the waffle is down
// (Nothing to draw here)
} else {
// The marble is on the grid and the waffle is up
// TODO: Draw them onto the grid
}
}
}
void RivenExternal::setMarbleHotspots() {
// Set the hotspots
for (uint16 i = 0; i < kMarbleCount; i++) {
uint32 *marblePos = _vm->getVar(s_marbleNames[i]);
if (*marblePos == 0) // In the receptacle
_vm->_hotspots[i + 3].rect = _marbleBaseHotspots[i];
else // On the grid
_vm->_hotspots[i + 3].rect = generateMarbleGridRect(getMarbleX(marblePos), getMarbleY(marblePos));
}
}
void RivenExternal::xt7800_setup(uint16 argc, uint16 *argv) {
// First, let's store the base receptacle hotspots for the marbles
if (_marbleBaseHotspots.empty())
for (uint16 i = 0; i < kMarbleCount; i++)
_marbleBaseHotspots.push_back(_vm->_hotspots[i + 3].rect);
// Move the marble hotspots based on their position variables
setMarbleHotspots();
*_vm->getVar("themarble") = 0;
}
void RivenExternal::drawMarbles() {
for (uint32 i = 0; i < kMarbleCount; i++) {
// Don't draw the marble if we're holding it
if (*_vm->getVar("themarble") - 1 == i)
continue;
Common::Rect rect = _vm->_hotspots[i + 3].rect;
// Trim the rect down a bit
rect.left += 3;
rect.top += 3;
rect.right -= 2;
rect.bottom -= 2;
_vm->_gfx->drawExtrasImage(i + 200, rect);
}
}
void RivenExternal::xdrawmarbles(uint16 argc, uint16 *argv) {
// Draw marbles in the closeup
drawMarbles();
// We have to re-enable the updates here
// Would be really nice if the scripts did this for us, but alas...
_vm->_gfx->_updatesEnabled = true;
}
void RivenExternal::xtakeit(uint16 argc, uint16 *argv) {
// Pick up and move a marble
// First, let's figure out what marble we're now holding
uint32 *marble = _vm->getVar("themarble");
*marble = 0;
for (uint32 i = 0; i < kMarbleCount; i++)
if (_vm->_hotspots[i + 3].rect.contains(_vm->_system->getEventManager()->getMousePos())) {
*marble = i + 1;
break;
}
// xtakeit() shouldn't be called if we're not on a marble hotspot
assert(*marble);
// Redraw the background
_vm->_gfx->drawPLST(1);
_vm->_gfx->updateScreen();
// Loop until the player lets go (or quits)
Common::Event event;
bool mouseDown = true;
while (mouseDown) {
while (_vm->_system->getEventManager()->pollEvent(event)) {
if (event.type == Common::EVENT_LBUTTONUP)
mouseDown = false;
else if (event.type == Common::EVENT_MOUSEMOVE)
_vm->_system->updateScreen();
else if (event.type == Common::EVENT_QUIT || event.type == Common::EVENT_RTL)
return;
}
_vm->_system->delayMillis(10); // Take it easy on the CPU
}
// Check if we landed in a valid location and no other marble has that location
uint32 *marblePos = _vm->getVar(s_marbleNames[*marble - 1]);
bool foundMatch = false;
for (int y = 0; y < 25 && !foundMatch; y++) {
for (int x = 0; x < 25 && !foundMatch; x++) {
Common::Rect testHotspot = generateMarbleGridRect(x, y);
// Let's try to place the marble!
if (testHotspot.contains(_vm->_system->getEventManager()->getMousePos())) {
// Set this as the position
setMarbleX(marblePos, x);
setMarbleY(marblePos, y);
// Let's make sure no other marble is in this spot...
for (uint16 i = 0; i < kMarbleCount; i++)
if (i != *marble - 1 && *_vm->getVar(s_marbleNames[i]) == *marblePos)
*marblePos = 0;
// We have a match
foundMatch = true;
}
}
}
// If we still don't have a match, reset it to the original location
if (!foundMatch)
*marblePos = 0;
// Check the new hotspots and refresh everything
*marble = 0;
setMarbleHotspots();
_vm->_curHotspot = -1;
_vm->checkHotspotChange();
_vm->_gfx->updateScreen();
}
void RivenExternal::xtscpbtn(uint16 argc, uint16 *argv) {
runDomeButtonMovie();
}
void RivenExternal::xtisland4990_domecheck(uint16 argc, uint16 *argv) {
runDomeCheck();
}
void RivenExternal::xtisland5056_opencard(uint16 argc, uint16 *argv) {
checkDomeSliders(29, 30);
}
void RivenExternal::xtisland5056_resetsliders(uint16 argc, uint16 *argv) {
resetDomeSliders(_vm->getFeatures() & GF_DVD ? 813 : 798, 37, 3);
}
void RivenExternal::xtisland5056_slidermd(uint16 argc, uint16 *argv) {
dragDomeSlider(_vm->getFeatures() & GF_DVD ? 813 : 798, 37, 29, 30, 3);
}
void RivenExternal::xtisland5056_slidermw(uint16 argc, uint16 *argv) {
checkSliderCursorChange(3);
}
void RivenExternal::xtatboundary(uint16 argc, uint16 *argv) {
runDemoBoundaryDialog();
}
// ------------------------------------------------------------------------------------
// Common external commands
// ------------------------------------------------------------------------------------
void RivenExternal::xflies(uint16 argc, uint16 *argv) {
// TODO: Activate the "flies" effect
}
} // End of namespace Mohawk