mirror of
https://github.com/scummvm/scummvm.git
synced 2025-04-02 10:52:32 -04:00
479 lines
15 KiB
C++
479 lines
15 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 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/riven_stacks/aspit.h"
|
||
|
||
#include "mohawk/riven.h"
|
||
#include "mohawk/riven_card.h"
|
||
#include "mohawk/riven_graphics.h"
|
||
#include "mohawk/riven_inventory.h"
|
||
#include "mohawk/riven_sound.h"
|
||
#include "mohawk/riven_video.h"
|
||
|
||
#include "common/translation.h"
|
||
|
||
#include "graphics/fonts/ttf.h"
|
||
#include "graphics/font.h"
|
||
#include "graphics/fontman.h"
|
||
|
||
#include "gui/message.h"
|
||
|
||
namespace Mohawk {
|
||
namespace RivenStacks {
|
||
|
||
ASpit::ASpit(MohawkEngine_Riven *vm) :
|
||
RivenStack(vm, kStackAspit) {
|
||
|
||
REGISTER_COMMAND(ASpit, xastartupbtnhide);
|
||
REGISTER_COMMAND(ASpit, xasetupcomplete);
|
||
REGISTER_COMMAND(ASpit, xaatrusopenbook);
|
||
REGISTER_COMMAND(ASpit, xaatrusbookback);
|
||
REGISTER_COMMAND(ASpit, xaatrusbookprevpage);
|
||
REGISTER_COMMAND(ASpit, xaatrusbooknextpage);
|
||
REGISTER_COMMAND(ASpit, xacathopenbook);
|
||
REGISTER_COMMAND(ASpit, xacathbookback);
|
||
REGISTER_COMMAND(ASpit, xacathbookprevpage);
|
||
REGISTER_COMMAND(ASpit, xacathbooknextpage);
|
||
REGISTER_COMMAND(ASpit, xtrapbookback);
|
||
REGISTER_COMMAND(ASpit, xatrapbookclose);
|
||
REGISTER_COMMAND(ASpit, xatrapbookopen);
|
||
REGISTER_COMMAND(ASpit, xarestoregame);
|
||
REGISTER_COMMAND(ASpit, xadisablemenureturn);
|
||
REGISTER_COMMAND(ASpit, xaenablemenureturn);
|
||
REGISTER_COMMAND(ASpit, xalaunchbrowser);
|
||
REGISTER_COMMAND(ASpit, xadisablemenuintro);
|
||
REGISTER_COMMAND(ASpit, xaenablemenuintro);
|
||
REGISTER_COMMAND(ASpit, xademoquit);
|
||
REGISTER_COMMAND(ASpit, xaexittomain);
|
||
|
||
REGISTER_COMMAND(ASpit, xaSaveGame);
|
||
REGISTER_COMMAND(ASpit, xaResumeGame);
|
||
REGISTER_COMMAND(ASpit, xaOptions);
|
||
REGISTER_COMMAND(ASpit, xaNewGame);
|
||
}
|
||
|
||
struct MenuItemText {
|
||
int language;
|
||
const char *items[7];
|
||
} static const menuItems[] = {
|
||
{ Common::EN_ANY, { "SETUP", "START NEW GAME", "START SAVED GAME", "SAVE GAME", "RESUME", "OPTIONS", "QUIT" } },
|
||
{ Common::DE_DEU, { "SETUP", "SPIELEN", "SPIELSTAND LADEN", "SPIEL SPEICHERN", "FORTSETZEN", "OPTIONEN", "BEENDEN" } },
|
||
{ Common::ES_ESP, { "IMAGEN", "IR A RIVEN", "CARGAR JUEGO", "GUARDAR JUEGO", "CONTINUAR", "OPCIONES", "SALIR" } },
|
||
{ Common::FR_FRA, { "CONFIG", "NOUVELLE PARTIE", "CHARGER", "ENREGISTRER", "REPRENDRE", "OPTIONS", "QUITTER" } },
|
||
{ Common::IT_ITA, { "CONF.", "GIOCA", "CARICA GIOCO", "SALVA IL GIOCO", "SEGUITARE", "OPZIONI", "ESCI" } },
|
||
{ Common::RU_RUS, { "УСТАНОВКИ", "СТАРТ", "ПРОДОЛЖИТЬ ИГРУ", "СОХРАНИТЬ ИГРУ", "ПРОДОЛЖИТЬ", "ОПЦИИ", "ВЫЙТИ" } },
|
||
{ Common::JA_JPN, { "セットアップ", "RIVENを演奏する", "保存したゲームを開始する", "ゲームを保存する", "持続する", "オプション","やめる" } },
|
||
{ Common::PL_POL, { "USTAWIENIA", "GRAJ W RIVEN", "ZAŁADUJ GRĘ", "ZAPISZ GRĘ", "POWRÓT", "OPCJE", "WYJŚCIE" } },
|
||
{ -1, { 0 } }
|
||
};
|
||
|
||
void ASpit::xastartupbtnhide(const ArgumentArray &args) {
|
||
// The original game hides the start/setup buttons depending on an ini entry.
|
||
// It's safe to ignore this command.
|
||
|
||
if (!_vm->isGameVariant(GF_25TH))
|
||
return;
|
||
|
||
int lang = -1;
|
||
for (int i = 0; menuItems[i].language != -1; i++) {
|
||
if (menuItems[i].language == _vm->getLanguage()) {
|
||
lang = i;
|
||
break;
|
||
}
|
||
}
|
||
|
||
if (lang == -1) {
|
||
warning("Unsupported menu language, falling back to English");
|
||
lang = 0;
|
||
}
|
||
|
||
struct MenuItem {
|
||
uint16 blstId;
|
||
bool requiresStartedGame;
|
||
};
|
||
|
||
MenuItem items[] = {
|
||
{ 22, false }, // Setup
|
||
{ 16, false }, // New game
|
||
{ 23, false }, // Load game
|
||
{ 24, true }, // Save game
|
||
{ 25, true }, // Resume
|
||
{ 26, false }, // Options
|
||
{ 27, false } // Quit
|
||
};
|
||
|
||
for (uint i = 0; i < ARRAYSIZE(items); i++) {
|
||
RivenHotspot *hotspot = _vm->getCard()->getHotspotByBlstId(items[i].blstId);
|
||
|
||
if (!hotspot) {
|
||
warning("Missing hotspot %d", items[i].blstId);
|
||
continue;
|
||
}
|
||
|
||
bool enabled = !items[i].requiresStartedGame || _vm->isGameStarted();
|
||
hotspot->enable(enabled);
|
||
|
||
Common::U32String str = Common::convertUtf8ToUtf32(menuItems[lang].items[i]);
|
||
Common::Rect hotspotRect = hotspot->getRect();
|
||
uint8 greyLevel = enabled ? 164 : 96;
|
||
|
||
_vm->_gfx->drawText(str, hotspotRect, greyLevel);
|
||
}
|
||
}
|
||
|
||
void ASpit::xasetupcomplete(const ArgumentArray &args) {
|
||
// 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.
|
||
uint16 menuCardId = getCardStackId(0xE2E);
|
||
RivenScriptPtr goToMenuScript = _vm->_scriptMan->createScriptFromData(1, kRivenCommandChangeCard, 1, menuCardId);
|
||
_vm->_scriptMan->runScript(goToMenuScript, false);
|
||
}
|
||
|
||
void ASpit::xaatrusopenbook(const ArgumentArray &args) {
|
||
// Get the variable
|
||
uint32 &page = _vm->_vars["aatrusbook"];
|
||
|
||
// Set hotspots depending on the page
|
||
RivenHotspot *openBook = _vm->getCard()->getHotspotByName("openBook");
|
||
RivenHotspot *nextPage = _vm->getCard()->getHotspotByName("nextpage");
|
||
RivenHotspot *prevPage = _vm->getCard()->getHotspotByName("prevpage");
|
||
if (page == 1) {
|
||
prevPage->enable(false);
|
||
nextPage->enable(false);
|
||
openBook->enable(true);
|
||
} else {
|
||
prevPage->enable(true);
|
||
nextPage->enable(true);
|
||
openBook->enable(false);
|
||
}
|
||
|
||
// Draw the image of the page
|
||
_vm->getCard()->drawPicture(page);
|
||
}
|
||
|
||
void ASpit::xaatrusbookback(const ArgumentArray &args) {
|
||
_vm->_inventory->backFromItemScript();
|
||
}
|
||
|
||
void ASpit::xaatrusbookprevpage(const ArgumentArray &args) {
|
||
// Get the page variable
|
||
uint32 &page = _vm->_vars["aatrusbook"];
|
||
|
||
// Keep turning pages while the mouse is pressed
|
||
while (keepTurningPages()) {
|
||
// Check for the first page
|
||
if (page == 1)
|
||
return;
|
||
|
||
// Update the page number
|
||
page--;
|
||
|
||
pageTurn(kRivenTransitionWipeRight);
|
||
_vm->getCard()->drawPicture(page);
|
||
_vm->doFrame();
|
||
|
||
waitForPageTurnSound();
|
||
}
|
||
}
|
||
|
||
void ASpit::xaatrusbooknextpage(const ArgumentArray &args) {
|
||
// Get the page variable
|
||
uint32 &page = _vm->_vars["aatrusbook"];
|
||
|
||
// Keep turning pages while the mouse is pressed
|
||
while (keepTurningPages()) {
|
||
// Check for the last page
|
||
if ((_vm->isGameVariant(GF_DEMO) && page == 6) || page == 10)
|
||
return;
|
||
|
||
// Update the page number
|
||
page++;
|
||
|
||
pageTurn(kRivenTransitionWipeLeft);
|
||
_vm->getCard()->drawPicture(page);
|
||
_vm->doFrame();
|
||
|
||
// Wait until the previous page turn sound completes
|
||
waitForPageTurnSound();
|
||
}
|
||
}
|
||
|
||
void ASpit::xacathopenbook(const ArgumentArray &args) {
|
||
// Get the variable
|
||
uint32 page = _vm->_vars["acathbook"];
|
||
|
||
// Set hotspots depending on the page
|
||
RivenHotspot *openBook = _vm->getCard()->getHotspotByName("openBook");
|
||
RivenHotspot *nextPage = _vm->getCard()->getHotspotByName("nextpage");
|
||
RivenHotspot *prevPage = _vm->getCard()->getHotspotByName("prevpage");
|
||
if (page == 1) {
|
||
prevPage->enable(false);
|
||
nextPage->enable(false);
|
||
openBook->enable(true);
|
||
} else {
|
||
prevPage->enable(true);
|
||
nextPage->enable(true);
|
||
openBook->enable(false);
|
||
}
|
||
|
||
cathBookDrawPage(page);
|
||
}
|
||
|
||
void ASpit::cathBookDrawPage(uint32 page) {// Draw the image of the page
|
||
_vm->getCard()->drawPicture(page);
|
||
|
||
// Draw the white page edges
|
||
if (page > 1 && page < 5)
|
||
_vm->getCard()->drawPicture(50);
|
||
else if (page > 5)
|
||
_vm->getCard()->drawPicture(51);
|
||
|
||
if (page == 28) {
|
||
cathBookDrawTelescopeCombination();
|
||
}
|
||
}
|
||
|
||
void ASpit::cathBookDrawTelescopeCombination() {// 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->_vars["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 ASpit::xacathbookback(const ArgumentArray &args) {
|
||
_vm->_inventory->backFromItemScript();
|
||
}
|
||
|
||
void ASpit::xacathbookprevpage(const ArgumentArray &args) {
|
||
// Get the variable
|
||
uint32 &page = _vm->_vars["acathbook"];
|
||
|
||
// Keep turning pages while the mouse is pressed
|
||
while (keepTurningPages()) {
|
||
// Check for the first page
|
||
if (page == 1)
|
||
return;
|
||
|
||
// Update the page number
|
||
page--;
|
||
|
||
pageTurn(kRivenTransitionWipeDown);
|
||
cathBookDrawPage(page);
|
||
_vm->doFrame();
|
||
|
||
waitForPageTurnSound();
|
||
}
|
||
}
|
||
|
||
void ASpit::xacathbooknextpage(const ArgumentArray &args) {
|
||
// Get the variable
|
||
uint32 &page = _vm->_vars["acathbook"];
|
||
|
||
// Keep turning pages while the mouse is pressed
|
||
while (keepTurningPages()) {
|
||
// Check for the last page
|
||
if (page == 49)
|
||
return;
|
||
|
||
// Update the page number
|
||
page++;
|
||
|
||
pageTurn(kRivenTransitionWipeUp);
|
||
cathBookDrawPage(page);
|
||
_vm->doFrame();
|
||
|
||
waitForPageTurnSound();
|
||
}
|
||
}
|
||
|
||
void ASpit::xtrapbookback(const ArgumentArray &args) {
|
||
// Return to where we were before entering the book
|
||
_vm->_vars["atrap"] = 0;
|
||
_vm->_inventory->backFromItemScript();
|
||
}
|
||
|
||
void ASpit::xatrapbookclose(const ArgumentArray &args) {
|
||
// Close the trap book
|
||
_vm->_vars["atrap"] = 0;
|
||
|
||
pageTurn(kRivenTransitionWipeRight);
|
||
|
||
// Stop the flyby movie to prevent a glitch where the book does not actually
|
||
// close because the movie continues to draw over the closed book picture.
|
||
// This glitch also happened in the original engine with transitions disabled.
|
||
RivenVideo *flyby = _vm->_video->getSlot(1);
|
||
flyby->close();
|
||
|
||
_vm->getCard()->enter(false);
|
||
}
|
||
|
||
void ASpit::xatrapbookopen(const ArgumentArray &args) {
|
||
// Open the trap book
|
||
_vm->_vars["atrap"] = 1;
|
||
|
||
pageTurn(kRivenTransitionWipeLeft);
|
||
|
||
_vm->getCard()->enter(false);
|
||
}
|
||
|
||
void ASpit::xarestoregame(const ArgumentArray &args) {
|
||
if (!showConfirmationDialog(_("Are you sure you want to load a saved game? All unsaved progress will be lost."),
|
||
_("Load game"), _("Cancel"))) {
|
||
return;
|
||
}
|
||
|
||
// Launch the load game dialog
|
||
_vm->loadGameDialog();
|
||
}
|
||
|
||
void ASpit::xaSaveGame(const ArgumentArray &args) {
|
||
_vm->saveGameDialog();
|
||
}
|
||
|
||
void ASpit::xaResumeGame(const ArgumentArray &args) {
|
||
_vm->resumeFromMainMenu();
|
||
}
|
||
|
||
void ASpit::xaOptions(const ArgumentArray &args) {
|
||
_vm->runOptionsDialog();
|
||
}
|
||
|
||
void ASpit::xaNewGame(const ArgumentArray &args) {
|
||
if (!showConfirmationDialog(_("Are you sure you want to start a new game? All unsaved progress will be lost."),
|
||
_("New game"), _("Cancel"))) {
|
||
return;
|
||
}
|
||
|
||
_vm->startNewGame();
|
||
|
||
RivenScriptPtr script = _vm->_scriptMan->createScriptFromData(2,
|
||
kRivenCommandTransition, 1, kRivenTransitionBlend,
|
||
kRivenCommandChangeCard, 1, 2);
|
||
|
||
script->addCommand(RivenCommandPtr(new RivenStackChangeCommand(_vm, 0, 0x6E9A, false, false)));
|
||
|
||
script += _vm->_scriptMan->createScriptFromData(1,
|
||
kRivenCommandStopSound, 1, 2);
|
||
|
||
_vm->_scriptMan->runScript(script, false);
|
||
}
|
||
|
||
bool ASpit::showConfirmationDialog(const Common::U32String &message, const Common::U32String &confirmButton, const Common::U32String &cancelButton) {
|
||
if (!_vm->isGameStarted()) {
|
||
return true;
|
||
}
|
||
|
||
GUI::MessageDialog dialog(message, confirmButton, cancelButton);
|
||
|
||
return dialog.runModal() == GUI::kMessageOK;
|
||
}
|
||
|
||
void ASpit::xadisablemenureturn(const ArgumentArray &args) {
|
||
// 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 ASpit::xaenablemenureturn(const ArgumentArray &args) {
|
||
// 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 ASpit::xalaunchbrowser(const ArgumentArray &args) {
|
||
// 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 ASpit::xadisablemenuintro(const ArgumentArray &args) {
|
||
// 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.
|
||
|
||
_vm->_inventory->forceHidden(true);
|
||
}
|
||
|
||
void ASpit::xaenablemenuintro(const ArgumentArray &args) {
|
||
// 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->_inventory->forceHidden(false);
|
||
}
|
||
|
||
void ASpit::xademoquit(const ArgumentArray &args) {
|
||
if (!showConfirmationDialog(_("Are you sure you want to quit? All unsaved progress will be lost."), _("Quit"),
|
||
_("Cancel"))) {
|
||
return;
|
||
}
|
||
|
||
// Exactly as it says on the tin. In the demo, this function quits.
|
||
_vm->setGameEnded();
|
||
}
|
||
|
||
void ASpit::xaexittomain(const ArgumentArray &args) {
|
||
// One could potentially implement this function, but there would be no
|
||
// point. This function is only used in the demo's aspit card 9 update
|
||
// screen script. However, card 9 is not accessible from the game without
|
||
// jumping to the card and there's nothing going on in the card so it
|
||
// never gets called. There's also no card 9 in the full game, so the
|
||
// functionality of this card was likely removed before release. The
|
||
// demo executable references some other external commands relating to
|
||
// setting and getting the volume, as well as drawing the volume. I'd
|
||
// venture to guess that this would have been some sort of options card
|
||
// replaced with the Windows/Mac API in the final product.
|
||
//
|
||
// Yeah, this function is just dummied and holds a big comment ;)
|
||
}
|
||
|
||
} // End of namespace RivenStacks
|
||
} // End of namespace Mohawk
|