/* ScummVM - Graphic Adventure Engine * * ScummVM is the legal property of its developers, whose names * are too numerous to list here. Please refer to the COPYRIGHT * file distributed with this source distribution. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program. If not, see . * */ #include "asylum/puzzles/vcr.h" #include "asylum/resources/worldstats.h" #include "asylum/system/cursor.h" #include "asylum/system/graphics.h" #include "asylum/system/screen.h" #include "asylum/views/scene.h" #include "asylum/views/video.h" #include "asylum/asylum.h" #include "asylum/respack.h" namespace Asylum { PuzzleVCR::PuzzleVCR(AsylumEngine *engine): Puzzle(engine) { // reset all states memset(&_jacksState, 0, sizeof(_jacksState)); memset(&_holesState, 0, sizeof(_holesState)); memset(&_buttonsState, 0, sizeof(_buttonsState)); _tvScreenFrameIndex = 0; _isAccomplished = false; } PuzzleVCR::~PuzzleVCR() { } void PuzzleVCR::saveLoadWithSerializer(Common::Serializer &s) { s.syncAsUint32LE(_buttonsState[kPowerButton]); s.syncAsUint32LE(_buttonsState[kRewindButton]); s.syncAsUint32LE(_buttonsState[kPlayButton]); s.syncAsUint32LE(_buttonsState[kStopButton]); s.syncAsUint32LE(_holesState[kBlack]); s.syncAsUint32LE(_holesState[kRed]); s.syncAsUint32LE(_holesState[kYellow]); s.syncAsUint32LE(_jacksState[kBlack]); s.syncAsUint32LE(_jacksState[kRed]); s.syncAsUint32LE(_jacksState[kYellow]); s.syncAsUint32LE(_tvScreenFrameIndex); s.syncAsUint32LE(_isAccomplished); } ////////////////////////////////////////////////////////////////////////// // Event Handling ////////////////////////////////////////////////////////////////////////// bool PuzzleVCR::init(const AsylumEvent &) { // Load the graphics palette getScreen()->setPalette(getWorld()->graphicResourceIds[29]); getScreen()->setGammaLevel(getWorld()->graphicResourceIds[29]); if (_jacksState[kBlack] == kOnHand || _jacksState[kRed] == kOnHand || _jacksState[kYellow] == kOnHand) { getCursor()->hide(); getSharedData()->setFlag(kFlag1, true); } else { getCursor()->set(getWorld()->graphicResourceIds[28]); } return true; } bool PuzzleVCR::mouseLeftDown(const AsylumEvent &evt) { if (_isAccomplished) return true; ////////////////////////////////////////////////////////////////////////// // Plug-in jacks ////////////////////////////////////////////////////////////////////////// JackState state = kPluggedOnRed; if (_jacksState[kBlack] != kOnHand) { if (_jacksState[kRed] == kOnHand) state = kPluggedOnYellow; else state = (_jacksState[kYellow] != kOnHand) ? kOnTable : kPluggedOnBlack; } if (inPolygon(evt.mouse, kRedHole)) { setJackOnHole(kBlack, state, kPluggedOnRed); } else if (inPolygon(evt.mouse, kYellowHole)) { setJackOnHole(kRed, state, kPluggedOnYellow); } else if (inPolygon(evt.mouse, kBlackHole)) { setJackOnHole(kYellow, state, kPluggedOnBlack); if (_holesState[kYellow] != kPluggedOnYellow && _buttonsState[kPowerButton] == kON) { _buttonsState[kStopButton] = kOFF; _buttonsState[kPlayButton] = kOFF; _buttonsState[kRewindButton] = kOFF; _buttonsState[kPowerButton] = kOFF; } } ////////////////////////////////////////////////////////////////////////// // Put jacks on table ////////////////////////////////////////////////////////////////////////// Color jack = getJackOnHand(); if (jack != kNone) { if (evt.mouse.x >= (int32)puzzleVCRPolygons[kBlackJack][0] && evt.mouse.x <= (int32)puzzleVCRPolygons[kYellowJack][2] && evt.mouse.y >= (int32)puzzleVCRPolygons[kBlackJack][1] && evt.mouse.y <= (int32)puzzleVCRPolygons[kYellowJack][3]) { _jacksState[jack] = kOnTable; getSound()->playSound(getWorld()->graphicResourceIds[50]); getCursor()->show(); getSharedData()->setFlag(kFlag1, false); } return true; } ////////////////////////////////////////////////////////////////////////// // Get Jacks from Table ////////////////////////////////////////////////////////////////////////// getCursor()->show(); getSharedData()->setFlag(kFlag1, false); if (inPolygon(evt.mouse, kBlackJack)) pickJack(kBlack); else if (inPolygon(evt.mouse, kRedJack)) pickJack(kRed); else if (inPolygon(evt.mouse, kYellowJack)) pickJack(kYellow); ////////////////////////////////////////////////////////////////////////// // VCR button regions ////////////////////////////////////////////////////////////////////////// if (inPolygon(evt.mouse, kRewindButton)) { getSound()->playSound(getWorld()->graphicResourceIds[39]); if (!_buttonsState[kRewindButton]) _buttonsState[kRewindButton] = kDownON; else if (_buttonsState[kRewindButton] == kON) _buttonsState[kRewindButton] = kDownOFF; } else if (inPolygon(evt.mouse, kPlayButton)) { getSound()->playSound(getWorld()->graphicResourceIds[39]); if (!_buttonsState[kPlayButton]) _buttonsState[kPlayButton] = kDownON; else if (_buttonsState[kPlayButton] == kON) _buttonsState[kPlayButton] = kDownOFF; } else if (inPolygon(evt.mouse, kStopButton)) { getSound()->playSound(getWorld()->graphicResourceIds[39]); if (!_buttonsState[kStopButton]) _buttonsState[kStopButton] = kDownON; else if (_buttonsState[kStopButton] == kON) _buttonsState[kStopButton] = kDownOFF; } else if (inPolygon(evt.mouse, kPowerButton)) { getSound()->playSound(getWorld()->graphicResourceIds[39]); if (!_buttonsState[kPowerButton] && _holesState[kYellow] == kPluggedOnRed) { _buttonsState[kPowerButton] = kDownON; } else { _buttonsState[kPowerButton] = kDownOFF; } } return true; } bool PuzzleVCR::mouseLeftUp(const AsylumEvent &) { if (_isAccomplished) return true; ////////////////////////////////////////////////////////////////////////// // Power ////////////////////////////////////////////////////////////////////////// if (_buttonsState[kPowerButton] == kDownON) { if (!getSound()->isPlaying(getWorld()->graphicResourceIds[47])) getSound()->playSound(getWorld()->graphicResourceIds[47], true); _buttonsState[kPowerButton] = kON; _buttonsState[kStopButton] = kON; _buttonsState[kPlayButton] = kON; _buttonsState[kRewindButton] = kON; } else if (_buttonsState[kPowerButton] == kDownOFF) { _buttonsState[kPowerButton] = kOFF; _buttonsState[kStopButton] = kOFF; _buttonsState[kPlayButton] = kOFF; _buttonsState[kRewindButton] = kOFF; getSound()->stop(getWorld()->graphicResourceIds[47]); } ////////////////////////////////////////////////////////////////////////// // Rewind ////////////////////////////////////////////////////////////////////////// if (_buttonsState[kRewindButton] == kDownOFF) { getSound()->playSound(getWorld()->graphicResourceIds[46]); _buttonsState[kRewindButton] = kON; } else if (_buttonsState[kRewindButton] == kDownON) { _buttonsState[kRewindButton] = kOFF; } ////////////////////////////////////////////////////////////////////////// // Play ////////////////////////////////////////////////////////////////////////// if (_buttonsState[kPlayButton] == kDownOFF) { _buttonsState[kPlayButton] = kON; if (_holesState[kBlack] == kPluggedOnYellow && _holesState[kRed] == kPluggedOnBlack && _holesState[kYellow] == kPluggedOnRed) { getCursor()->hide(); _vm->setGameFlag(kGameFlagSolveVCRPuzzle); _isAccomplished = true; } } else if (_buttonsState[kPlayButton] == kDownON) { _buttonsState[kPlayButton] = kOFF; } ////////////////////////////////////////////////////////////////////////// // Stop ////////////////////////////////////////////////////////////////////////// if (_buttonsState[kStopButton] == kDownOFF) { _buttonsState[kStopButton] = kON; } else if (_buttonsState[kStopButton] == kDownON) { _buttonsState[kStopButton] = kOFF; } return true; } bool PuzzleVCR::exitPuzzle() { getSound()->stop(getWorld()->graphicResourceIds[47]); getScreen()->clearGraphicsInQueue(); getScreen()->clear(); _vm->switchEventHandler(getScene()); return true; } ////////////////////////////////////////////////////////////////////////// // Drawing ////////////////////////////////////////////////////////////////////////// void PuzzleVCR::updateScreen() { // Draw background getScreen()->clearGraphicsInQueue(); getScreen()->fillRect(0, 0, 640, 480, 252); getScreen()->draw(getWorld()->graphicResourceIds[0], 0, Common::Point(0, 0), kDrawFlagNone, true); updateBlackJack(); updateRedJack(); updateYellowJack(); updatePowerButton(); updateRewindButton(); updatePlayButton(); updateStopButton(); if (_buttonsState[kPowerButton] == kON) { getScreen()->addGraphicToQueue(getWorld()->graphicResourceIds[22], _tvScreenFrameIndex, Common::Point(0, 37), kDrawFlagNone, 0, 1); getScreen()->addGraphicToQueue(getWorld()->graphicResourceIds[23], _tvScreenFrameIndex++, Common::Point(238, 22), kDrawFlagNone, 0, 1); _tvScreenFrameIndex %= GraphicResource::getFrameCount(_vm, getWorld()->graphicResourceIds[22]); } if (_isAccomplished) { getCursor()->show(); getScreen()->draw(getWorld()->graphicResourceIds[0]); getScreen()->clearDefaultColor(); for (int16 barSize = 0; barSize < 84; barSize += 4) { getScreen()->drawWideScreenBars(barSize); _vm->_system->updateScreen(); } // Palette fade getScreen()->paletteFade(0, 25, 10); getScreen()->clear(); getScene()->updateScreen(); getScreen()->drawWideScreenBars(82); getSound()->stop(getWorld()->graphicResourceIds[47]); getSound()->playMusic(kResourceNone, 0); getScreen()->clear(); getVideo()->play(2, getScene()); if (getWorld()->musicCurrentResourceIndex != kMusicStopped) getSound()->playMusic(MAKE_RESOURCE(kResourcePackMusic, getWorld()->musicCurrentResourceIndex)); getScreen()->paletteFade(0, 2, 1); getScreen()->clear(); // setupPalette(); getScreen()->setupPalette(nullptr, 0, 0); int paletteId = _vm->checkGameVersion("Demo") ? 20 : 28; getScreen()->setPalette(MAKE_RESOURCE(kResourcePackTowerCells, paletteId)); getScreen()->setGammaLevel(MAKE_RESOURCE(kResourcePackTowerCells, paletteId)); } } void PuzzleVCR::updateCursor() { Color jack = getJackOnHand(); Common::Point mousePos = getCursor()->position(); if (mousePos.x) mousePos.x = 465; if (jack == kNone) { if (inPolygon(mousePos, kRewindButton) || inPolygon(mousePos, kStopButton) || inPolygon(mousePos, kPlayButton) || inPolygon(mousePos, kPowerButton) || inPolygon(mousePos, kBlackJack) || inPolygon(mousePos, kRedJack) || inPolygon(mousePos, kYellowJack)) { if (getCursor()->getAnimation() != kCursorAnimationMirror) getCursor()->set(getWorld()->graphicResourceIds[28]); } else if ((inPolygon(mousePos, kRedHole) && _holesState[kBlack]) || (inPolygon(mousePos, kYellowHole) && _holesState[kRed]) || (inPolygon(mousePos, kBlackHole) && _holesState[kYellow])) { if (getCursor()->getAnimation() != kCursorAnimationMirror) getCursor()->set(getWorld()->graphicResourceIds[28]); } else { if (getCursor()->getAnimation()) getCursor()->set(getWorld()->graphicResourceIds[28], kCursorAnimationNone); } } else { getCursor()->hide(); } } ////////////////////////////////////////////////////////////////////////// // Update Jack ////////////////////////////////////////////////////////////////////////// void PuzzleVCR::updateJack(Color jack, const VCRDrawInfo &onTable, const VCRDrawInfo &pluggedOnRed, const VCRDrawInfo &pluggedOnYellow, const VCRDrawInfo &pluggedOnBlack, int32 resourceOnHandIndex) { GraphicQueueItem item; Common::Point mousePos = getCursor()->position(); switch (_jacksState[jack]) { default: return; case kOnTable: item.resourceId = getWorld()->graphicResourceIds[onTable.resourceId]; item.source = onTable.point; item.priority = 3; break; case kPluggedOnRed: item.resourceId = getWorld()->graphicResourceIds[pluggedOnRed.resourceId]; item.source = Common::Point(329, 407); item.priority = 3; break; case kPluggedOnYellow: item.resourceId = getWorld()->graphicResourceIds[pluggedOnYellow.resourceId]; item.source = Common::Point(402, 413); item.priority = 3; break; case kPluggedOnBlack: item.resourceId = getWorld()->graphicResourceIds[pluggedOnBlack.resourceId]; item.source = Common::Point(477, 418); item.priority = 3; break; case kOnHand: // Jack item.resourceId = getWorld()->graphicResourceIds[resourceOnHandIndex]; item.source = Common::Point(mousePos.x - 114, mousePos.y < 356 ? 342 : mousePos.y - 14); item.priority = 1; getScreen()->addGraphicToQueue(item); // Shadow item.resourceId = getWorld()->graphicResourceIds[30]; item.source = Common::Point(mousePos.x - (mousePos.y < 356 ? 0 : (mousePos.y - 356) / 4), 450); item.priority = 2; break; } getScreen()->addGraphicToQueue(item); } void PuzzleVCR::updateBlackJack() { VCRDrawInfo onTable; onTable.resourceId = 1; onTable.point = Common::Point(0, 411); VCRDrawInfo pluggedOnRed; pluggedOnRed.resourceId = 5; VCRDrawInfo pluggedOnYellow; pluggedOnYellow.resourceId = 8; VCRDrawInfo pluggedOnBlack; pluggedOnBlack.resourceId = 11; updateJack(kBlack, onTable, pluggedOnRed, pluggedOnYellow, pluggedOnBlack, 27); } void PuzzleVCR::updateRedJack() { VCRDrawInfo onTable; onTable.resourceId = 2; onTable.point = Common::Point(76, 428); VCRDrawInfo pluggedOnRed; pluggedOnRed.resourceId = 4; VCRDrawInfo pluggedOnYellow; pluggedOnYellow.resourceId = 7; VCRDrawInfo pluggedOnBlack; pluggedOnBlack.resourceId = 10; updateJack(kRed, onTable, pluggedOnRed, pluggedOnYellow, pluggedOnBlack, 25); } void PuzzleVCR::updateYellowJack() { VCRDrawInfo onTable; onTable.resourceId = 3; onTable.point = Common::Point(187, 439); VCRDrawInfo pluggedOnRed; pluggedOnRed.resourceId = 6; VCRDrawInfo pluggedOnYellow; pluggedOnYellow.resourceId = 9; VCRDrawInfo pluggedOnBlack; pluggedOnBlack.resourceId = 12; updateJack(kYellow, onTable, pluggedOnRed, pluggedOnYellow, pluggedOnBlack, 26); } ////////////////////////////////////////////////////////////////////////// // Update Button ////////////////////////////////////////////////////////////////////////// void PuzzleVCR::updateButton(VCRRegions button, const VCRDrawInfo &btON, const VCRDrawInfo &btDown) { GraphicQueueItem item; switch (_buttonsState[button]) { default: return; case kON: item.resourceId = getWorld()->graphicResourceIds[btON.resourceId]; item.source = btON.point; item.priority = 3; break; case kDownON: case kDownOFF: item.resourceId = getWorld()->graphicResourceIds[btDown.resourceId]; item.source = btDown.point; item.priority = 3; break; } getScreen()->addGraphicToQueue(item); } void PuzzleVCR::updatePowerButton() { VCRDrawInfo btON; btON.resourceId = 17; btON.point = Common::Point(512, 347); VCRDrawInfo btDown; btDown.resourceId = 21; btDown.point = Common::Point(506, 343); updateButton(kPowerButton, btON, btDown); } void PuzzleVCR::updateRewindButton() { VCRDrawInfo btON; btON.resourceId = 14; btON.point = Common::Point(248, 347); VCRDrawInfo btDown; btDown.resourceId = 18; btDown.point = Common::Point(245, 344); updateButton(kRewindButton, btON, btDown); } void PuzzleVCR::updatePlayButton() { VCRDrawInfo btON; btON.resourceId = 16; btON.point = Common::Point(401, 359); VCRDrawInfo btDown; btDown.resourceId = 20; btDown.point = Common::Point(391, 355); updateButton(kPlayButton, btON, btDown); } void PuzzleVCR::updateStopButton() { VCRDrawInfo btON; btON.resourceId = 15; btON.point = Common::Point(330, 354); VCRDrawInfo btDown; btDown.resourceId = 19; btDown.point = Common::Point(326, 350); updateButton(kStopButton, btON, btDown); } ////////////////////////////////////////////////////////////////////////// // Helpers ////////////////////////////////////////////////////////////////////////// int PuzzleVCR::inPolygon(const Common::Point &point, int polygonIndex) const { return _vm->rectContains(&puzzleVCRPolygons[polygonIndex], point); } PuzzleVCR::Color PuzzleVCR::getJackOnHand() const { Color jack = kNone; if (_jacksState[kBlack] == kOnHand) jack = kBlack; else if (_jacksState[kRed] == kOnHand) jack = kRed; else if (_jacksState[kYellow] == kOnHand) jack = kYellow; return jack; } void PuzzleVCR::setJackOnHole(Color hole, JackState state, JackState newState) { bool isYellow = (hole == kYellow); if (_holesState[hole]) { if (isYellow) getSound()->stop(getWorld()->graphicResourceIds[47]); _jacksState[_holesState[hole] - 1] = kOnHand; _holesState[hole] = kOnTable; if (state != kOnTable) { getSound()->playSound(getWorld()->graphicResourceIds[44]); _holesState[hole] = state; if (isYellow) { if (state != kPluggedOnYellow && _buttonsState[kPowerButton] == kON) getSound()->stop(getWorld()->graphicResourceIds[47]); } _jacksState[state - 1] = newState; } else { getSound()->playSound(getWorld()->graphicResourceIds[43]); getCursor()->hide(); getSharedData()->setFlag(kFlag1, true); } } else if (state != kOnTable) { getSound()->playSound(getWorld()->graphicResourceIds[44]); _holesState[hole] = state; if (isYellow) { if (state != kPluggedOnYellow && _buttonsState[kPowerButton] == kON) getSound()->stop(getWorld()->graphicResourceIds[47]); } _jacksState[state - 1] = newState; } } void PuzzleVCR::pickJack(Color jack) { getCursor()->hide(); getSharedData()->setFlag(kFlag1, true); _jacksState[jack] = kOnHand; } } // end of namespace Asylum