Initial commit

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

View File

@@ -0,0 +1,293 @@
/* 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 "common/language.h"
#include "asylum/puzzles/board.h"
#include "asylum/resources/worldstats.h"
#include "asylum/system/cursor.h"
#include "asylum/system/screen.h"
#include "asylum/system/text.h"
#include "asylum/views/scene.h"
#include "asylum/asylum.h"
namespace Asylum {
PuzzleBoard::PuzzleBoard(AsylumEngine *engine, const PuzzleData *data) : Puzzle(engine) {
int i = 0;
switch (_vm->getLanguage()) {
default:
case Common::EN_ANY:
case Common::RU_RUS:
i = 0;
break;
case Common::DE_DEU:
i = 1;
break;
case Common::FR_FRA:
i = 2;
break;
case Common::HE_ISR:
i = 3;
break;
case Common::EU_ESP:
i = 4;
break;
}
memcpy(&_data, &data[i], sizeof(PuzzleData));
// Init board
_solved = false;
memset(&_charUsed, false, sizeof(_charUsed));
memset(&_solvedText, 0, sizeof(_solvedText));
_rectIndex = -2;
_soundResourceId = kResourceNone;
_selectedSlot = -1;
_position = 0;
}
void PuzzleBoard::reset() {
memset(&_charUsed, false, sizeof(_charUsed));
}
//////////////////////////////////////////////////////////////////////////
// Event Handling
//////////////////////////////////////////////////////////////////////////
bool PuzzleBoard::init(const AsylumEvent &) {
_rectIndex = -2;
_selectedSlot = -1;
_solved = false;
_soundResourceId = 0;
getScreen()->setPalette(getWorld()->graphicResourceIds[32]);
getScreen()->setGammaLevel(getWorld()->graphicResourceIds[32]);
getText()->loadFont(getWorld()->graphicResourceIds[35]);
// Prepare text to draw
_text.clear();
for (uint32 i = 0; i < _data.soundResourceSize; i++) {
_data.soundResources[i].played = false;
_text += getText()->get(MAKE_RESOURCE(kResourcePackText, 1068 + _data.soundResources[i].index));
_text += ' ';
}
updateScreen();
getCursor()->show();
return true;
}
void PuzzleBoard::updateScreen() {
getScreen()->clearGraphicsInQueue();
getScreen()->draw(getWorld()->graphicResourceIds[_data.backgroundIndex]);
drawText();
if (!_solved)
playSound();
if (_vm->isGameFlagNotSet(_data.gameFlag)) {
if (strcmp(_solvedText, _data.solvedText))
return;
if (_solved) {
if (!getSound()->isPlaying(MAKE_RESOURCE(kResourcePackSpeech, 1))) {
_vm->setGameFlag(_data.gameFlag);
getCursor()->show();
getScreen()->clear();
_vm->switchEventHandler(getScene());
}
} else {
_solved = true;
getCursor()->hide();
stopSound();
getSound()->playSound(MAKE_RESOURCE(kResourcePackSpeech, 1), false, Config.voiceVolume);
}
}
}
bool PuzzleBoard::exitPuzzle() {
if (!stopSound()) {
getScreen()->clear();
_vm->switchEventHandler(getScene());
}
return true;
}
//////////////////////////////////////////////////////////////////////////
// Helpers
//////////////////////////////////////////////////////////////////////////
bool PuzzleBoard::stopSound() {
if (_soundResourceId && getSound()->isPlaying(_soundResourceId)) {
getSound()->stopAll(_soundResourceId);
return true;
}
return false;
}
void PuzzleBoard::drawText() {
getText()->loadFont(getWorld()->graphicResourceIds[35]);
getText()->draw(0, 99, kTextCenter, Common::Point(25, 50), 16, 590, _text.c_str());
int32 index = 0;
for (int16 x = 215; x < (int16)_data.maxWidth; x += 24) {
if (!_solvedText[index])
break;
getText()->setPosition(Common::Point(x, _selectedSlot != index ? 360 : 370));
// TODO: Check this for Chinese
getText()->drawASCII(_solvedText[index]);
index += 2;
}
}
void PuzzleBoard::playSound() {
uint32 index;
for (index = 0; index < _data.soundResourceSize; index++) {
if (!_data.soundResources[index].played)
break;
}
if (index >= _data.soundResourceSize)
return;
if (!_soundResourceId || !getSound()->isPlaying(_soundResourceId)) {
_soundResourceId = MAKE_RESOURCE(kResourcePackSharedSound, 2401 + _data.soundResources[index].index);
getSound()->playSound(_soundResourceId, false, Config.voiceVolume);
_data.soundResources[index].played = true;
}
}
int32 PuzzleBoard::findRect() {
Common::Point mousePos = getCursor()->position();
for (uint32 i = 0; i < _data.charMapSize; i++) {
if (mousePos.x >= _data.charMap[i].posX && mousePos.x < _data.charMap[i].posX + 12
&& mousePos.y >= _data.charMap[i].posY && mousePos.y < _data.charMap[i].posY + 18)
if (!_charUsed[i])
return i;
}
return -1;
}
int32 PuzzleBoard::checkMouse() {
Common::Point mousePos = getCursor()->position();
if (mousePos.x >= 215 && mousePos.x < (int16)_data.maxWidth && mousePos.y >= 360 && mousePos.y < 376) {
int16 index = (mousePos.x - 215) / 12;
if (index < 0 || index >= ARRAYSIZE(_solvedText))
return -1;
if (_solvedText[index] != 0 && _solvedText[index] != ' ')
return -3;
}
return -1;
}
void PuzzleBoard::updateCursor() {
Common::Point mousePos = getCursor()->position();
if (mousePos.y <= 350) {
int32 index = findRect();
if (index == -1) {
if (getCursor()->getResourceId() == getWorld()->graphicResourceIds[34])
return;
_rectIndex = index;
getCursor()->set(getWorld()->graphicResourceIds[34]);
} else {
if (getCursor()->getResourceId() == getWorld()->graphicResourceIds[33])
return;
if (index == _rectIndex)
return;
_rectIndex = index;
getCursor()->set(getWorld()->graphicResourceIds[33]);
}
} else {
if (_vm->isGameFlagSet(_data.gameFlag)) {
if (getCursor()->getResourceId() == getWorld()->graphicResourceIds[34])
return;
getCursor()->set(getWorld()->graphicResourceIds[34]);
} else {
int32 index = checkMouse();
if (getCursor()->getResourceId() == getWorld()->graphicResourceIds[33])
return;
if (index == _rectIndex)
return;
if (index == -1)
getCursor()->set(getWorld()->graphicResourceIds[33], 0, kCursorAnimationNone);
else
getCursor()->set(getWorld()->graphicResourceIds[33]);
}
}
}
void PuzzleBoard::checkSlots() {
Common::Point mousePos = getCursor()->position();
if (mousePos.x >= 215 && mousePos.x < (int16)_data.maxWidth && mousePos.y >= 360 && mousePos.y < 376) {
int32 index = (mousePos.x - 215) / 12;
if (_solvedText[index]) {
if (_solvedText[index] == ' ')
return;
if (_selectedSlot == -1) {
_selectedSlot = index;
} else {
SWAP(_solvedText[index], _solvedText[_selectedSlot]);
_selectedSlot = -1;
}
updateScreen();
}
}
}
} // End of namespace Asylum

View File

@@ -0,0 +1,100 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef ASYLUM_PUZZLES_BOARD_H
#define ASYLUM_PUZZLES_BOARD_H
#include "asylum/puzzles/puzzle.h"
#include "asylum/shared.h"
namespace Asylum {
class AsylumEngine;
class PuzzleBoard : public Puzzle {
public:
struct SoundResource {
int32 index;
bool played;
};
struct CharMap {
char character;
int16 posX, posY;
};
struct PuzzleData {
uint32 backgroundIndex;
GameFlag gameFlag;
uint32 maxWidth;
uint32 soundResourceSize;
SoundResource soundResources[3];
uint32 charMapSize;
CharMap charMap[11];
bool checkForSpace;
uint32 space1Pos, space2Pos;
char solvedText[28];
};
PuzzleBoard(AsylumEngine *engine, const PuzzleData *data);
void reset();
protected:
PuzzleData _data;
bool _solved;
Common::String _text;
bool _charUsed[20];
char _solvedText[28]; // KeyHidesTo uses 28 chars, the other puzzles 20
uint32 _position;
int32 _rectIndex;
int32 _selectedSlot;
ResourceId _soundResourceId;
//////////////////////////////////////////////////////////////////////////
// Helpers
//////////////////////////////////////////////////////////////////////////
void updateScreen();
int32 findRect();
bool stopSound();
void checkSlots();
//////////////////////////////////////////////////////////////////////////
// Event Handling
//////////////////////////////////////////////////////////////////////////
bool init(const AsylumEvent &evt);
bool activate(const AsylumEvent &evt) { return updateScreen(), true; }
bool exitPuzzle();
private:
//////////////////////////////////////////////////////////////////////////
// Helpers
//////////////////////////////////////////////////////////////////////////
void drawText();
void playSound();
int32 checkMouse();
void updateCursor();
};
} // End of namespace Asylum
#endif // ASYLUM_PUZZLES_BOARD_H

View File

@@ -0,0 +1,200 @@
/* 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 "asylum/puzzles/boardkeyhidesto.h"
#include "asylum/system/cursor.h"
#include "asylum/asylum.h"
namespace Asylum {
static const PuzzleBoard::PuzzleData puzzleKeyHidesToData[] = {
// English
{
56,
kGameFlag283,
503,
3,
{{5, false}, {6, false}, {7, false}},
10,
{
{'I', 30, 53},
{'E', 212, 71},
{'D', 31, 103},
{'H', 447, 134},
{'S', 240, 151},
{'E', 95, 167},
{'O', 372, 182},
{'K', 210, 215},
{'Y', 440, 247},
{'T', 479, 262},
{'\0', 0, 0},
},
true,
6, 18,
"K E Y H I D E S T O "
},
// German
{
56,
kGameFlag283,
503,
3,
{{5, false}, {6, false}, {7, false}},
9,
{
{'U', 52, 50},
{'R', 28, 66},
{'Z', 254, 66},
{'E', 40, 82},
{'W', 209, 130},
{'G', 61, 146},
{'T', 33, 162},
{'I', 527, 162},
{'S', 233, 210},
{'\0', 0, 0},
{'\0', 0, 0}
},
true,
6, 14,
"W E G I S T Z U R "
},
// French
{
56,
kGameFlag283,
431,
3,
{{5, false}, {6, false}, {7, false}},
6,
{
{'L', 357, 66},
{'A', 128, 98},
{'C', 367, 114},
{'L', 237, 130},
{'E', 25, 162},
{'F', 47, 194},
{'\0', 0, 0},
{'\0', 0, 0},
{'\0', 0, 0},
{'\0', 0, 0},
{'\0', 0, 0}
},
true,
4, 0,
"L A C L E F "
},
// Hebrew
{
56,
kGameFlag283,
503,
3,
{{5, false}, {6, false}, {7, false}},
10,
{
{'\xE7', 593, 58},
{'\xEE', 65, 59},
{'\xF4', 591, 91},
{'\xE0', 203, 106},
{'\xE4', 466, 122},
{'\xE1', 62, 123},
{'\xE9', 468, 155},
{'\xFA', 201, 170},
{'\xEE', 253, 203},
{'\xE7', 210, 218},
{'\0', 0, 0},
},
true,
10, 0,
"\xE7 \xFA \xF4 \xEE \xE4 \xE0 \xE9 \xE1 \xE7 \xEE "
},
// Basque
{
56,
kGameFlag283,
503,
3,
{{5, false}, {6, false}, {7, false}},
11,
{
{'A', 45, 56},
{'K', 199, 74},
{'A', 538, 88},
{'D', 276, 121},
{'L', 276, 137},
{'Z', 170, 152},
{'T', 536, 151},
{'A', 279, 185},
{'I', 494, 200},
{'G', 101, 248},
{'U', 546, 247}
},
true,
10, 0,
"D A U K A G I L T Z A "
}
};
PuzzleBoardKeyHidesTo::PuzzleBoardKeyHidesTo(AsylumEngine *engine) : PuzzleBoard(engine, puzzleKeyHidesToData) {
}
void PuzzleBoardKeyHidesTo::saveLoadWithSerializer(Common::Serializer &s) {
for (int32 i = 0; i < 12; i++)
s.syncAsUint32LE(_charUsed[i]);
s.syncBytes((byte *)&_solvedText, 28);
s.syncAsUint32LE(_position);
}
//////////////////////////////////////////////////////////////////////////
// Event Handling
//////////////////////////////////////////////////////////////////////////
bool PuzzleBoardKeyHidesTo::mouseLeftDown(const AsylumEvent &) {
Common::Point mousePos = getCursor()->position();
if (mousePos.y <= 350) {
int32 index = findRect();
if (index != -1 && _position < strlen(_data.solvedText)) {
_charUsed[index] = true;
_selectedSlot = -1;
_solvedText[_position++] = _data.charMap[index].character;
_solvedText[_position++] = ' ';
if (_position == _data.space1Pos || _position == _data.space2Pos) {
_solvedText[_position++] = ' ';
_solvedText[_position++] = ' ';
}
updateScreen();
}
} else if (_vm->isGameFlagNotSet(kGameFlag283)) {
checkSlots();
}
return true;
}
} // End of namespace Asylum

View File

@@ -0,0 +1,47 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef ASYLUM_PUZZLES_BOARDKEYHIDESTO_H
#define ASYLUM_PUZZLES_BOARDKEYHIDESTO_H
#include "asylum/puzzles/board.h"
namespace Asylum {
class AsylumEngine;
class PuzzleBoardKeyHidesTo : public PuzzleBoard {
public:
PuzzleBoardKeyHidesTo(AsylumEngine *engine);
// Serializable
virtual void saveLoadWithSerializer(Common::Serializer &s);
private:
//////////////////////////////////////////////////////////////////////////
// Event Handling
//////////////////////////////////////////////////////////////////////////
bool mouseLeftDown(const AsylumEvent &evt);
};
} // End of namespace Asylum
#endif // ASYLUM_PUZZLES_BOARDKEYHIDESTO_H

View File

@@ -0,0 +1,223 @@
/* 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 "asylum/puzzles/boardsalvation.h"
#include "asylum/system/cursor.h"
#include "asylum/system/screen.h"
#include "asylum/system/sound.h"
#include "asylum/views/scene.h"
#include "asylum/asylum.h"
namespace Asylum {
static const PuzzleBoard::PuzzleData puzzleSalvationData[] = {
// English
{
31,
kGameFlag281,
431,
3,
{{0, false}, {1, false}, {2, false}},
9,
{
{'I', 61, 53},
{'S', 322, 53},
{'A', 529, 86},
{'L', 256, 117},
{'V', 251, 151},
{'A', 66, 199},
{'T', 436, 229},
{'O', 172, 262},
{'N', 393, 296},
{'\0', 0, 0},
{'\0', 0, 0}
},
false,
0, 0,
"S A L V A T I O N "
},
// German
{
31,
kGameFlag281,
431,
3,
{{0, false}, {1, false}, {2, false}},
8,
{
{'L', 46, 50},
{'O', 133, 82},
{'R', 356, 98},
{'E', 99, 130},
{'N', 120, 146},
{'G', 161, 178},
{'S', 289, 210},
{'U', 371, 226},
{'\0', 0, 0},
{'\0', 0, 0},
{'\0', 0, 0}
},
false,
0, 0,
"E R L O S U N G "
},
// French
{
31,
kGameFlag281,
431,
3,
{{0, false}, {1, false}, {2, false}},
7,
{
{'D', 54, 50},
{'U', 266, 66},
{'S', 540, 82},
{'A', 49, 130},
{'L', 199, 162},
{'U', 442, 178},
{'T', 369, 210},
{'\0', 0, 0},
{'\0', 0, 0},
{'\0', 0, 0},
{'\0', 0, 0}
},
true,
4, 0,
"D U S A L U T "
},
// Hebrew
{
31,
kGameFlag281,
431,
3,
{{0, false}, {1, false}, {2, false}},
9,
{
{'\xE5', 585, 58},
{'\xE4', 218, 58},
{'\xEC', 134, 87},
{'\xE4', 465, 138},
{'\xE0', 64, 154},
{'\xF2', 523, 203},
{'\xE9', 511, 219},
{'\xF9', 91, 234},
{'\0', 0, 0},
{'\0', 0, 0},
{'\0', 0, 0}
},
false,
12, 0,
"\xE4 \xF2 \xE5 \xF9 \xE9 \xE4 \xEC \xE0 "
},
// Basque
{
31,
kGameFlag281,
455,
3,
{{0, false}, {1, false}, {2, false}},
10,
{
{'B', 49, 56},
{'A', 317, 56},
{'O', 546, 85},
{'L', 267, 122},
{'Z', 157, 152},
{'R', 264, 184},
{'A', 564, 216},
{'I', 452, 231},
{'S', 251, 247},
{'A', 485, 279},
{'\0', 0, 0}
},
false,
0, 0,
"S A L B A Z I O R A "
},
};
static const uint32 puzzleSalvationSoundResourceIndex[11] = {5, 6, 7, 10, 11, 28, 29, 30, 31, 32, 36};
PuzzleBoardSalvation::PuzzleBoardSalvation(AsylumEngine *engine) : PuzzleBoard(engine, puzzleSalvationData) {
}
void PuzzleBoardSalvation::saveLoadWithSerializer(Common::Serializer &s) {
for (int32 i = 0; i < 9; i++)
s.syncAsUint32LE(_charUsed[i]);
s.syncBytes((byte *)&_solvedText, 20);
s.syncAsUint32LE(_position);
}
//////////////////////////////////////////////////////////////////////////
// Event Handling
//////////////////////////////////////////////////////////////////////////
bool PuzzleBoardSalvation::mouseLeftDown(const AsylumEvent &) {
Common::Point mousePos = getCursor()->position();
if (mousePos.y <= 350) {
int32 index = findRect();
if (index != -1 && _position < strlen(_data.solvedText)) {
_charUsed[index] = true;
_selectedSlot = -1;
_solvedText[_position++] = _data.charMap[index].character;
_solvedText[_position++] = ' ';
if (_position == _data.space1Pos) {
_solvedText[_position++] = ' ';
_solvedText[_position++] = ' ';
}
updateScreen();
}
} else if (_vm->isGameFlagNotSet(kGameFlag281)) {
checkSlots();
}
return true;
}
bool PuzzleBoardSalvation::exitPuzzle() {
if (!stopSound()) {
checkANALText();
return PuzzleBoard::exitPuzzle();
}
return true;
}
//////////////////////////////////////////////////////////////////////////
// Helpers
//////////////////////////////////////////////////////////////////////////
void PuzzleBoardSalvation::checkANALText() {
if (!strcmp(_solvedText, "A N A L "))
getSound()->playSound(MAKE_RESOURCE(kResourcePackSpeech, puzzleSalvationSoundResourceIndex[rnd(11)]), false, Config.voiceVolume);
}
} // End of namespace Asylum

View File

@@ -0,0 +1,53 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef ASYLUM_PUZZLES_BOARDSALVATION_H
#define ASYLUM_PUZZLES_BOARDSALVATION_H
#include "asylum/puzzles/board.h"
namespace Asylum {
class AsylumEngine;
class PuzzleBoardSalvation : public PuzzleBoard {
public:
PuzzleBoardSalvation(AsylumEngine *engine);
// Serializable
virtual void saveLoadWithSerializer(Common::Serializer &s);
private:
//////////////////////////////////////////////////////////////////////////
// Event Handling
//////////////////////////////////////////////////////////////////////////
bool mouseLeftDown(const AsylumEvent &evt);
bool exitPuzzle();
//////////////////////////////////////////////////////////////////////////
// Helpers
//////////////////////////////////////////////////////////////////////////
void checkANALText();
};
} // End of namespace Asylum
#endif // ASYLUM_PUZZLES_BOARDSALVATION_H

View File

@@ -0,0 +1,200 @@
/* 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 "asylum/puzzles/boardyouth.h"
#include "asylum/system/cursor.h"
#include "asylum/asylum.h"
namespace Asylum {
static const PuzzleBoard::PuzzleData puzzleYouthData[] = {
// English
{
55,
kGameFlag282,
431,
2,
{{3, false}, {4, false}, {0, false}},
8,
{
{'E', 64, 55},
{'U', 26, 69},
{'T', 135, 102},
{'O', 57, 134},
{'H', 417, 152},
{'T', 223, 181},
{'H', 497, 198},
{'Y', 435, 231},
{'\0', 0, 0},
{'\0', 0, 0},
{'\0', 0, 0}
},
true,
6, 0,
"T H E Y O U T H "
},
// German
{
55,
kGameFlag282,
503,
2,
{{3, false}, {4, false}, {0, false}},
9,
{
{'G', 25, 50},
{'E', 60, 66},
{'D', 471, 82},
{'N', 340, 114},
{'J', 102, 146},
{'U', 311, 162},
{'R', 261, 194},
{'E', 390, 210},
{'D', 470, 226},
{'\0', 0, 0},
{'\0', 0, 0}
},
true,
12, 0,
"J U G E N D D E R "
},
// French
{
55,
kGameFlag282,
503,
2,
{{3, false}, {4, false}, {0, false}},
11,
{
{'E', 64, 50},
{'S', 514, 50},
{'T', 192, 98},
{'J', 297, 114},
{'E', 595, 130},
{'S', 62, 146},
{'U', 376, 146},
{'N', 281, 162},
{'E', 482, 178},
{'E', 66, 194},
{'S', 133, 210},
},
true,
6, 0,
"E S T J E U N E S S E "
},
// Hebrew
{
55,
kGameFlag282,
431,
2,
{{3, false}, {4, false}, {0, false}},
8,
{
{'\xF0', 596, 59},
{'\xE5', 226, 58},
{'\xE4', 113, 74},
{'\xE0', 494, 106},
{'\xF8', 461, 122},
{'\xF2', 76, 155},
{'\xFA', 141, 186},
{'\0', 0, 0},
{'\0', 0, 0},
{'\0', 0, 0},
{'\0', 0, 0}
},
true,
10, 0,
"\xF8 \xF2 \xE5 \xF0 \xE4 \xFA \xE0 "
},
// Basque
{
55,
kGameFlag282,
431,
2,
{{3, false}, {4, false}, {0, false}},
9,
{
{'A', 32, 56},
{'T', 81, 68},
{'K', 124, 102},
{'A', 554, 118},
{'G', 331, 149},
{'Z', 152, 182},
{'E', 581, 182},
{'I', 304, 198},
{'D', 445, 231},
{'\0', 0, 0},
{'\0', 0, 0}
},
false,
0, 0,
"G A Z T E D I A K "
},
};
PuzzleBoardYouth::PuzzleBoardYouth(AsylumEngine *engine) : PuzzleBoard(engine, puzzleYouthData) {
}
void PuzzleBoardYouth::saveLoadWithSerializer(Common::Serializer &s) {
for (int32 i = 0; i < 9; i++)
s.syncAsUint32LE(_charUsed[i]);
s.syncBytes((byte *)&_solvedText, 20);
s.syncAsUint32LE(_position);
}
//////////////////////////////////////////////////////////////////////////
// Event Handling
//////////////////////////////////////////////////////////////////////////
bool PuzzleBoardYouth::mouseLeftDown(const AsylumEvent &) {
Common::Point mousePos = getCursor()->position();
if (mousePos.y <= 350) {
int32 index = findRect();
if (index != -1 && _position < strlen(_data.solvedText)) {
_charUsed[index] = true;
_selectedSlot = -1;
_solvedText[_position++] = _data.charMap[index].character;
_solvedText[_position++] = ' ';
if (_position == _data.space1Pos) {
_solvedText[_position++] = ' ';
_solvedText[_position++] = ' ';
}
updateScreen();
}
} else if (_vm->isGameFlagNotSet(kGameFlag282)) {
checkSlots();
}
return true;
}
} // End of namespace Asylum

View File

@@ -0,0 +1,47 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef ASYLUM_PUZZLES_BOARDYOUTH_H
#define ASYLUM_PUZZLES_BOARDYOUTH_H
#include "asylum/puzzles/board.h"
namespace Asylum {
class AsylumEngine;
class PuzzleBoardYouth : public PuzzleBoard {
public:
PuzzleBoardYouth(AsylumEngine *engine);
// Serializable
virtual void saveLoadWithSerializer(Common::Serializer &s);
private:
//////////////////////////////////////////////////////////////////////////
// Event Handling
//////////////////////////////////////////////////////////////////////////
bool mouseLeftDown(const AsylumEvent &evt);
};
} // End of namespace Asylum
#endif // ASYLUM_PUZZLES_BOARDYOUTH_H

View File

@@ -0,0 +1,173 @@
/* 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 "asylum/puzzles/clock.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/asylum.h"
namespace Asylum {
const uint32 puzzleClockFrameIndexes[28] = {
2, 4, 6, 8, 10, 11, 13, 15, 17, 19,
21, 0, 19, 21, 0, 2, 4, 6, 8, 9,
11, 13, 15, 17, 0, 0, 182, 0
};
const int16 puzzleClockRects[12][4] = {
{354, 121, 373, 142}, {384, 119, 405, 146}, {405, 135, 424, 160},
{404, 168, 425, 193}, {389, 205, 410, 236}, {359, 240, 383, 270},
{325, 255, 341, 284}, {294, 253, 313, 284}, {277, 237, 294, 264},
{273, 201, 301, 235}, {290, 168, 315, 195}, {315, 133, 344, 162}
};
PuzzleClock::PuzzleClock(AsylumEngine *engine) : Puzzle(engine) {
memset(&_frameIndexes, 0, sizeof(_frameIndexes));
_showCursor = false;
_rightButtonClicked = false;
_currentRect = 0;
_currentFrameIndex = 0;
}
PuzzleClock::~PuzzleClock() {
}
void PuzzleClock::saveLoadWithSerializer(Common::Serializer &s) {
s.syncAsSint32LE(_frameIndexes[2]);
s.syncAsSint32LE(_frameIndexes[1]);
}
//////////////////////////////////////////////////////////////////////////
// Event Handling
//////////////////////////////////////////////////////////////////////////
bool PuzzleClock::init(const AsylumEvent &) {
_currentRect = -2;
updateCursor();
getScreen()->setPalette(getWorld()->graphicResourceIds[6]);
getScreen()->setGammaLevel(getWorld()->graphicResourceIds[6]);
getCursor()->show();
_frameIndexes[1] = 6;
_frameIndexes[2] = 10;
_currentFrameIndex = 10;
_showCursor = false;
_rightButtonClicked = false;
return true;
}
void PuzzleClock::updateScreen() {
// Draw elements
getScreen()->clearGraphicsInQueue();
getScreen()->draw(getWorld()->graphicResourceIds[5]);
getScreen()->draw(getWorld()->graphicResourceIds[2], _frameIndexes[0], Common::Point(322, 187));
_frameIndexes[0]++;
_frameIndexes[0] %= GraphicResource::getFrameCount(_vm, getWorld()->graphicResourceIds[2]);
getScreen()->draw(getWorld()->graphicResourceIds[4], _frameIndexes[1], Common::Point(267, 109));
getScreen()->draw(getWorld()->graphicResourceIds[3], _frameIndexes[2], Common::Point(274, 124));
if (_currentFrameIndex == _frameIndexes[2]) {
if (_showCursor) {
_showCursor = false;
getCursor()->show();
setFlag();
}
} else {
++_frameIndexes[2];
_frameIndexes[2] %= GraphicResource::getFrameCount(_vm, getWorld()->graphicResourceIds[3]);
}
if (_rightButtonClicked) {
getScreen()->clear();
_vm->switchEventHandler(getScene());
} else {
if (_vm->isGameFlagSet(kGameFlag511)) {
exitPuzzle();
}
}
}
bool PuzzleClock::mouseLeftDown(const AsylumEvent &) {
int32 index = findRect();
if (index == -1)
return false;
_currentFrameIndex = puzzleClockFrameIndexes[index];
++_frameIndexes[2];
_frameIndexes[2] %= GraphicResource::getFrameCount(_vm, getWorld()->graphicResourceIds[3]);
_showCursor = true;
getCursor()->hide();
return true;
}
bool PuzzleClock::exitPuzzle() {
setFlag();
_rightButtonClicked = true;
return true;
}
//////////////////////////////////////////////////////////////////////////
// Helpers
//////////////////////////////////////////////////////////////////////////
void PuzzleClock::updateCursor() {
int32 index = findRect();
if (index != _currentRect) {
_currentRect = index;
if (index == -1)
getCursor()->set(getWorld()->graphicResourceIds[7], -1, kCursorAnimationNone);
else
getCursor()->set(getWorld()->graphicResourceIds[7], -1, kCursorAnimationMirror);
}
}
int32 PuzzleClock::findRect() {
for (uint32 i = 0; i < ARRAYSIZE(puzzleClockRects); i++) {
if (_vm->rectContains(&puzzleClockRects[i], getCursor()->position()))
return i;
}
return -1;
}
void PuzzleClock::setFlag() {
if (_frameIndexes[2] == puzzleClockFrameIndexes[11])
_vm->setGameFlag(kGameFlag511);
}
} // End of namespace Asylum

View File

@@ -0,0 +1,64 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef ASYLUM_PUZZLES_CLOCK_H
#define ASYLUM_PUZZLES_CLOCK_H
#include "asylum/puzzles/puzzle.h"
namespace Asylum {
class AsylumEngine;
class PuzzleClock : public Puzzle {
public:
PuzzleClock(AsylumEngine *engine);
~PuzzleClock();
// Serializable
virtual void saveLoadWithSerializer(Common::Serializer &s);
private:
uint32 _frameIndexes[3];
bool _showCursor;
bool _rightButtonClicked;
int32 _currentRect;
uint32 _currentFrameIndex;
//////////////////////////////////////////////////////////////////////////
// Event Handling
//////////////////////////////////////////////////////////////////////////
bool init(const AsylumEvent &evt);
void updateScreen();
bool mouseLeftDown(const AsylumEvent &evt);
bool exitPuzzle();
//////////////////////////////////////////////////////////////////////////
// Helpers
//////////////////////////////////////////////////////////////////////////
void updateCursor();
int32 findRect();
void setFlag();
};
} // End of namespace Asylum
#endif // ASYLUM_PUZZLES_CLOCK_H

View File

@@ -0,0 +1,255 @@
/* 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 "asylum/puzzles/fisherman.h"
#include "asylum/resources/worldstats.h"
#include "asylum/system/cursor.h"
#include "asylum/system/screen.h"
#include "asylum/views/scene.h"
#include "asylum/asylum.h"
namespace Asylum {
const int16 puzzleFishermanPolygons[31][2] = {
{ 10, 53}, {113, 52}, {222, 46}, {328, 51},
{426, 51}, {523, 49}, {277, 398}, { 30, 44},
{112, 44}, { 93, 400}, { 0, 400}, {130, 44},
{210, 44}, {201, 400}, {112, 400}, {224, 44},
{315, 44}, {309, 400}, {219, 400}, {326, 44},
{411, 44}, {415, 400}, {326, 400}, {422, 44},
{506, 44}, {526, 400}, {434, 400}, {523, 44},
{607, 44}, {640, 400}, {545, 400}
};
PuzzleFisherman::PuzzleFisherman(AsylumEngine *engine) : Puzzle(engine) {
memset(&_state, 0, sizeof(_state));
_resetPressed = false;
_counter = 0;
_pauseTimer = 0;
_allowClick = false;
}
PuzzleFisherman::~PuzzleFisherman() {
}
void PuzzleFisherman::saveLoadWithSerializer(Common::Serializer &s) {
for (int i = 0; i < ARRAYSIZE(_state); i++)
s.syncAsSint32LE(_state[i]);
s.syncAsSint32LE(_resetPressed);
s.syncAsSint32LE(_counter);
}
//////////////////////////////////////////////////////////////////////////
// Event Handling
//////////////////////////////////////////////////////////////////////////
bool PuzzleFisherman::init(const AsylumEvent &evt) {
getCursor()->set(getWorld()->graphicResourceIds[47], -1, kCursorAnimationMirror, 7);
for (uint32 i = 0; i < ARRAYSIZE(_state); i++)
if (_vm->isGameFlagNotSet((GameFlag)(kGameFlag801 + i)))
_state[i] = false;
if (_counter == 6) {
_vm->clearGameFlag(kGameFlag619);
_counter = 0;
}
_allowClick = false;
getScreen()->setPalette(getWorld()->graphicResourceIds[39]);
getScreen()->setGammaLevel(getWorld()->graphicResourceIds[39]);
return mouseLeftDown(evt);
}
void PuzzleFisherman::updateScreen() {
// Draw background
getScreen()->clearGraphicsInQueue();
getScreen()->fillRect(0, 0, 640, 480, 251);
getScreen()->draw(getWorld()->graphicResourceIds[38], 0, Common::Point(0, 0), kDrawFlagNone, true);
// Draw 7 graphics
for (uint32 i = 0; i < 6; i++) {
if (_state[i])
getScreen()->addGraphicToQueue(getWorld()->graphicResourceIds[40 + i], 0, &puzzleFishermanPolygons[i], kDrawFlagNone, 0, 1);
}
_allowClick = true;
if (_resetPressed) {
++_pauseTimer;
if (_pauseTimer > 5) {
// Reset state
memset(&_state, 0, sizeof(_state));
for (uint32 i = 0; i < 6; i++)
_vm->clearGameFlag((GameFlag)(kGameFlag801 + i));
_resetPressed = false;
_allowClick = true;
_pauseTimer = 0;
// Original bug: if the Sun button was pressed last,
// the correct order of buttons wouldn't work until another reset
_counter = 0;
}
}
if (_counter == 6) {
++_pauseTimer;
if (_pauseTimer > 10) {
_pauseTimer = 0;
_vm->setGameFlag(kGameFlag619);
getScreen()->setPalette(getWorld()->currentPaletteId);
_vm->switchEventHandler(getScene());
}
}
}
bool PuzzleFisherman::mouseLeftDown(const AsylumEvent &evt) {
if (!_allowClick)
return false;
for (uint32 i = 0; i < 6; i++) {
if (hitTest(&puzzleFishermanPolygons[i * 4 + 7], evt.mouse)) {
if (!_state[i]) {
getSound()->playSound(getWorld()->soundResourceIds[9], false, Config.sfxVolume - 10);
_state[i] = true;
setFlags(i);
}
}
}
if (puzzleFishermanPolygons[6][0] < evt.mouse.x
&& puzzleFishermanPolygons[6][1] < evt.mouse.y
&& puzzleFishermanPolygons[6][0] + 70 > evt.mouse.x
&& puzzleFishermanPolygons[6][1] + 30 > evt.mouse.y) {
getSound()->playSound(getWorld()->soundResourceIds[10], false, Config.sfxVolume - 10);
for (uint32 i = 0; i < 6; i++)
_vm->clearGameFlag((GameFlag)(kGameFlag801 + i));
_resetPressed = true;
}
if (_resetPressed)
_allowClick = false;
return true;
}
bool PuzzleFisherman::exitPuzzle() {
getCursor()->hide();
getSharedData()->setFlag(kFlag1, true);
getScreen()->stopPaletteFade(0, 0, 0);
_vm->switchEventHandler(getScene());
return false;
}
//////////////////////////////////////////////////////////////////////////
// Helpers
//////////////////////////////////////////////////////////////////////////
void PuzzleFisherman::updateCursor() {
bool found = false;
Common::Point mousePos = getCursor()->position();
for (uint32 i = 0; i < 6; i++) {
if (found)
break;
if (hitTest(&puzzleFishermanPolygons[i * 4 + 7], mousePos)) {
if (!_state[i]) {
found = true;
if (getCursor()->getAnimation() != kCursorAnimationMirror)
getCursor()->set(getWorld()->graphicResourceIds[47], -1, kCursorAnimationMirror, 7);
}
}
}
if (found)
return;
if (puzzleFishermanPolygons[6][0] >= mousePos.x
|| puzzleFishermanPolygons[6][1] >= mousePos.y
|| puzzleFishermanPolygons[6][0] + 70 <= mousePos.x
|| puzzleFishermanPolygons[6][1] + 30 <= mousePos.y) {
if (getCursor()->getAnimation() != kCursorAnimationNone)
getCursor()->set(getWorld()->graphicResourceIds[47], -1, kCursorAnimationNone, 7);
else if (getCursor()->getAnimation() != kCursorAnimationMirror)
getCursor()->set(getWorld()->graphicResourceIds[47], -1, kCursorAnimationMirror, 7);
}
}
void PuzzleFisherman::setFlags(uint32 index) {
switch (index) {
default:
break;
case 0:
_vm->setGameFlag(kGameFlag801);
_counter = (_counter == 2) ? 3 : 0;
break;
case 1:
_vm->setGameFlag(kGameFlag802);
_counter = (_counter == 3) ? 4 : 0;
break;
case 2:
_vm->setGameFlag(kGameFlag803);
_counter = (_counter == 1) ? 2 : 0;
break;
case 3:
_vm->setGameFlag(kGameFlag804);
if (_counter == 5) {
_allowClick = false;
_counter = 6;
} else {
_counter = 0;
}
break;
case 4:
_vm->setGameFlag(kGameFlag805);
_counter = (_counter == 0) ? 1 : 0;
break;
case 5:
_vm->setGameFlag(kGameFlag806);
_counter = (_counter == 4) ? 5 : 0;
break;
}
}
} // End of namespace Asylum

View File

@@ -0,0 +1,64 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef ASYLUM_PUZZLES_FISHERMAN_H
#define ASYLUM_PUZZLES_FISHERMAN_H
#include "asylum/puzzles/puzzle.h"
namespace Asylum {
class AsylumEngine;
class PuzzleFisherman : public Puzzle {
public:
PuzzleFisherman(AsylumEngine *engine);
~PuzzleFisherman();
// Serializable
virtual void saveLoadWithSerializer(Common::Serializer &s);
private:
bool _state[6];
int32 _counter;
int32 _pauseTimer;
bool _allowClick;
bool _resetPressed;
//////////////////////////////////////////////////////////////////////////
// Event Handling
//////////////////////////////////////////////////////////////////////////
bool init(const AsylumEvent &evt);
void updateScreen();
bool mouseLeftDown(const AsylumEvent &evt);
bool exitPuzzle();
//////////////////////////////////////////////////////////////////////////
// Helpers
//////////////////////////////////////////////////////////////////////////
void updateCursor();
void setFlags(uint32 index);
};
} // End of namespace Asylum
#endif // ASYLUM_PUZZLES_FISHERMAN_H

View File

@@ -0,0 +1,482 @@
/* 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 "asylum/puzzles/hivecontrol.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/asylum.h"
namespace Asylum {
const Control puzzleHiveControlIntToControl[] = {
kControlWingsButton1,
kControlWingsButton2,
kControlWingsButton3,
kControlReset,
kControlWheelLeft,
kControlWheelRight,
kControlButtonRight,
kControlButtonLeft,
kControlGlyph1,
kControlGlyph2,
kControlGlyph3,
kControlGlyph4,
kControlGlyph5,
kControlGlyph6
};
PuzzleHiveControl::PuzzleHiveControl(AsylumEngine *engine) : Puzzle(engine) {
_rectIndex = 0;
_soundVolume = 0;
_counter = 0;
_data_457260 = 0;
_data_457264 = 0;
_prevLeverPosition = 3;
_resetFlag = false;
memset(&_frameIndexes, 0, sizeof(_frameIndexes));
reset();
}
PuzzleHiveControl::~PuzzleHiveControl() {
}
void PuzzleHiveControl::saveLoadWithSerializer(Common::Serializer &s) {
// TODO
s.skip(6 * 4 * 2);
debugC(kDebugLevelSavegame, "[PuzzleHiveControl::saveLoadWithSerializer] Not implemented");
s.syncAsSint32LE(_soundVolume);
}
void PuzzleHiveControl::reset() {
_leverPosition = 3;
_leverDelta = 0;
_currentControl = kControlNone;
_colorL = _colorR = 0;
_frameIndexOffset = 0;
memset(&_glyphFlags, false, sizeof(_glyphFlags));
memset(&_wingsState, false, sizeof(_wingsState));
_frameIndexes[kElementSwirlRim] = 0;
if (_leverPosition != _prevLeverPosition) {
_leverDelta = (uint32)abs((double)_leverPosition - (double)_prevLeverPosition) * 16 / 5;
_currentControl = kControlGlyph4;
}
}
//////////////////////////////////////////////////////////////////////////
// Event Handling
//////////////////////////////////////////////////////////////////////////
bool PuzzleHiveControl::init(const AsylumEvent &) {
_controlPoints[kControlWingsButton1] = Common::Point(338, 139);
_controlPoints[kControlWingsButton2] = Common::Point(376, 151);
_controlPoints[kControlWingsButton3] = Common::Point(403, 162);
_controlPoints[kControlReset] = Common::Point(219, 86);
_controlPoints[kControlWheelRight] = Common::Point(204, 263);
_controlPoints[kControlWheelLeft] = Common::Point(164, 310);
_controlPoints[kControlButtonLeft] = Common::Point(320, 375);
_controlPoints[kControlButtonRight] = Common::Point(363, 337);
_controlPoints[kControlGlyph1] = Common::Point(102, 201);
_controlPoints[kControlGlyph2] = Common::Point(101, 171);
_controlPoints[kControlGlyph3] = Common::Point(108, 140);
_controlPoints[kControlGlyph4] = Common::Point(126, 111);
_controlPoints[kControlGlyph5] = Common::Point(140, 85);
_controlPoints[kControlGlyph6] = Common::Point(161, 54);
_rectIndex = -2;
_frameIndexes[kElementLever] = (5 - _leverPosition) * (GraphicResource::getFrameCount(_vm, getWorld()->graphicResourceIds[kElementLever]) - 1) / 5;
getScreen()->setPalette(getWorld()->graphicResourceIds[29]);
getScreen()->setGammaLevel(getWorld()->graphicResourceIds[29]);
getCursor()->show();
getScreen()->setupTransTables(1, getWorld()->graphicResourceIds[70]);
getScreen()->selectTransTable(0);
getSound()->playSound(getWorld()->graphicResourceIds[73], true, _soundVolume);
getSound()->playSound(getWorld()->graphicResourceIds[74], true, Config.ambientVolume);
return true;
}
bool PuzzleHiveControl::mouseLeftDown(const AsylumEvent &) {
if (_currentControl != kControlNone)
return true;
_currentControl = findControl();
switch (_currentControl) {
case kControlNone:
break;
case kControlWingsButton1:
getCursor()->hide();
getSound()->playSound(getWorld()->graphicResourceIds[81], false, Config.sfxVolume - 10);
if (_wingsState[1] != _wingsState[2]) {
if (_wingsState[0])
--_frameIndexOffset;
else
++_frameIndexOffset;
}
_frameIndexOffset += _wingsState[0] ? -1 : 1;
_wingsState[0] = !_wingsState[0];
_frameIndexes[kElementLensLeft] = _colorL * 8 + _frameIndexOffset;
_frameIndexes[kElementLensRight] = _colorR * 8 + _frameIndexOffset;
break;
case kControlWingsButton2:
getCursor()->hide();
getSound()->playSound(getWorld()->graphicResourceIds[81], false, Config.sfxVolume - 10);
if (_wingsState[0] != _wingsState[2]) {
if (_wingsState[1])
--_frameIndexOffset;
else
++_frameIndexOffset;
}
_frameIndexOffset += _wingsState[1] ? -2 : 2;
_wingsState[1] = !_wingsState[1];
_frameIndexes[kElementLensLeft] = _colorL * 8 + _frameIndexOffset;
_frameIndexes[kElementLensRight] = _colorR * 8 + _frameIndexOffset;
break;
case kControlWingsButton3:
getCursor()->hide();
getSound()->playSound(getWorld()->graphicResourceIds[81], false, Config.sfxVolume - 10);
if (_wingsState[0] != _wingsState[1]) {
if (_wingsState[2])
--_frameIndexOffset;
else
++_frameIndexOffset;
}
_frameIndexOffset += (_wingsState[2] ? -3 : 3);
_wingsState[2] = !_wingsState[2];
_frameIndexes[kElementLensLeft] = _colorL * 8 + _frameIndexOffset;
_frameIndexes[kElementLensRight] = _colorR * 8 + _frameIndexOffset;
break;
case kControlReset:
getCursor()->hide();
getSound()->playSound(getWorld()->graphicResourceIds[78], false, Config.sfxVolume - 10);
getSound()->playSound(getWorld()->graphicResourceIds[79], false, Config.sfxVolume - 10);
_resetFlag = true;
reset();
break;
case kControlWheelLeft:
getCursor()->hide();
getSound()->playSound(getWorld()->graphicResourceIds[80], false, Config.sfxVolume - 10);
_colorL = (_colorL + 1) % 3;
break;
case kControlWheelRight:
getCursor()->hide();
getSound()->playSound(getWorld()->graphicResourceIds[80], false, Config.sfxVolume - 10);
_colorR = (_colorR + 1) % 3;
break;
case kControlButtonLeft:
getCursor()->hide();
getSound()->playSound(getWorld()->graphicResourceIds[77], false, Config.sfxVolume - 10);
if (!_glyphFlags[0][_leverPosition]) {
_glyphFlags[0][_leverPosition] = puzzleHiveControlHieroglyphs[0][_leverPosition] == _frameIndexes[kElementLensLeft];
if (_glyphFlags[0][_leverPosition]) {
getSound()->playSound(getWorld()->graphicResourceIds[83], false, Config.sfxVolume - 10);
++_frameIndexes[kElementSwirlRim];
// Check for puzzle completion
if (_frameIndexes[kElementSwirlRim] == 12) {
getSound()->stop(getWorld()->graphicResourceIds[73]);
getSound()->stop(getWorld()->graphicResourceIds[74]);
getScreen()->clear();
getScreen()->setupTransTables(3, getWorld()->cellShadeMask1, getWorld()->cellShadeMask2, getWorld()->cellShadeMask3);
getScreen()->selectTransTable(1);
_vm->setGameFlag(kGameFlagSolveHiveControl);
_vm->switchEventHandler(getScene());
}
}
}
break;
case kControlButtonRight:
getCursor()->hide();
getSound()->playSound(getWorld()->graphicResourceIds[77], false, Config.sfxVolume - 10);
if (!_glyphFlags[1][_leverPosition]) {
_glyphFlags[1][_leverPosition] = puzzleHiveControlHieroglyphs[1][_leverPosition] == _frameIndexes[kElementLensRight];
if (_glyphFlags[1][_leverPosition]) {
getSound()->playSound(getWorld()->graphicResourceIds[83], false, Config.sfxVolume - 10);
++_frameIndexes[kElementSwirlRim];
// Check for puzzle completion
if (_frameIndexes[kElementSwirlRim] == 12) {
getSound()->stop(getWorld()->graphicResourceIds[73]);
getSound()->stop(getWorld()->graphicResourceIds[74]);
getScreen()->clear();
getScreen()->setupTransTables(3, getWorld()->cellShadeMask1, getWorld()->cellShadeMask2, getWorld()->cellShadeMask3);
getScreen()->selectTransTable(1);
_vm->setGameFlag(kGameFlagSolveHiveControl);
_vm->switchEventHandler(getScene());
}
}
}
break;
case kControlGlyph1:
case kControlGlyph2:
case kControlGlyph3:
case kControlGlyph4:
case kControlGlyph5:
case kControlGlyph6:
_leverPosition = _currentControl - 49;
_leverDelta = (uint32)abs((double)_leverPosition - (double)_prevLeverPosition) * (GraphicResource::getFrameCount(_vm, getWorld()->graphicResourceIds[kElementLever]) - 1) / 5;
if (_leverDelta)
getSound()->playSound(getWorld()->graphicResourceIds[76], false, Config.sfxVolume - 10);
}
return true;
}
bool PuzzleHiveControl::exitPuzzle() {
if (_leverDelta) {
_leverDelta = 0;
_prevLeverPosition = _leverPosition;
_currentControl = kControlNone;
}
getSound()->stop(getWorld()->graphicResourceIds[73]);
getSound()->stop(getWorld()->graphicResourceIds[74]);
getScreen()->clear();
getScreen()->setupTransTables(3, getWorld()->cellShadeMask1, getWorld()->cellShadeMask2, getWorld()->cellShadeMask3);
getScreen()->selectTransTable(1);
_vm->switchEventHandler(getScene());
return true;
}
//////////////////////////////////////////////////////////////////////////
// Helpers
//////////////////////////////////////////////////////////////////////////
void PuzzleHiveControl::updateCursor() {
int32 index = findControl();
if (_rectIndex == index)
return;
_rectIndex = index;
if (index == -1)
getCursor()->set(getWorld()->graphicResourceIds[30], -1, kCursorAnimationNone);
else
getCursor()->set(getWorld()->graphicResourceIds[30], -1);
}
Control PuzzleHiveControl::findControl() {
for (uint32 i = 0; i < ARRAYSIZE(puzzleHiveControlIntToControl); ++i)
if (hitTest1(puzzleHiveControlIntToControl[i], getCursor()->position(), _controlPoints[puzzleHiveControlIntToControl[i]]))
return puzzleHiveControlIntToControl[i];
return kControlNone;
}
void PuzzleHiveControl::updateScreen() {
getScreen()->clearGraphicsInQueue();
getScreen()->addGraphicToQueue(getWorld()->graphicResourceIds[28], 0, Common::Point(0, 0), kDrawFlagNone, 0, 3);
switch (_currentControl) {
case kControlNone:
break;
case kControlGlyph1:
case kControlGlyph2:
case kControlGlyph3:
case kControlGlyph4:
case kControlGlyph5:
case kControlGlyph6:
if (_leverDelta) {
if (_leverPosition > _prevLeverPosition)
--_frameIndexes[kElementLever];
else
++_frameIndexes[kElementLever];
--_leverDelta;
if (_leverDelta == 0) {
_prevLeverPosition = _leverPosition;
_currentControl = kControlNone;
}
} else
_currentControl = kControlNone;
break;
default:
_frameIndexes[_currentControl] = (_frameIndexes[_currentControl] + 1) % GraphicResource::getFrameCount(_vm, getWorld()->graphicResourceIds[_currentControl]);
if (_frameIndexes[_currentControl] == 0) {
getCursor()->show();
if (_currentControl == kControlWheelLeft || _currentControl == kControlWheelRight) {
getSound()->playSound(getWorld()->graphicResourceIds[75], false, Config.sfxVolume - 10);
if (_currentControl == kControlWheelLeft)
_frameIndexes[kElementLensLeft] = (_frameIndexes[kElementLensLeft] + 8) % GraphicResource::getFrameCount(_vm, getWorld()->graphicResourceIds[kElementLensLeft]);
else
_frameIndexes[kElementLensRight] = (_frameIndexes[kElementLensRight] + 8) % GraphicResource::getFrameCount(_vm, getWorld()->graphicResourceIds[kElementLensRight]);
}
_currentControl = kControlNone;
}
}
getScreen()->addGraphicToQueue(getWorld()->graphicResourceIds[kElementSwirl], _frameIndexes[kElementSwirl], Common::Point(486, 291), kDrawFlagNone, 0, 2);
_frameIndexes[kElementSwirl] = (_frameIndexes[kElementSwirl] + 1) % GraphicResource::getFrameCount(_vm, getWorld()->graphicResourceIds[kElementSwirl]);
if (_resetFlag) {
getScreen()->addGraphicToQueue(getWorld()->graphicResourceIds[kElementResetDynamic], _frameIndexes[kElementResetDynamic], Common::Point(211, 77), kDrawFlagNone, 0, 2);
_frameIndexes[kElementResetDynamic] = (_frameIndexes[kElementResetDynamic] + 1) % GraphicResource::getFrameCount(_vm, getWorld()->graphicResourceIds[kElementResetDynamic]);
if (_frameIndexes[kElementResetDynamic] == 0) {
_resetFlag = false;
getCursor()->show();
if (!(_wingsState[0] || _wingsState[1] || _wingsState[2])) {
_frameIndexes[kElementLensLeft] = 0;
_frameIndexes[kElementLensRight] = 0;
}
}
} else {
getScreen()->addGraphicToQueue(getWorld()->graphicResourceIds[kElementFlyHead], _frameIndexes[kElementFlyHead], Common::Point(258, 86), kDrawFlagNone, 0, 2);
getScreen()->addGraphicToQueue(getWorld()->graphicResourceIds[kElementResetStatic], _frameIndexes[kElementResetStatic], Common::Point(232, 77), kDrawFlagNone, 0, 2);
_frameIndexes[kElementFlyHead] = (_frameIndexes[kElementFlyHead] + 1) % GraphicResource::getFrameCount(_vm, getWorld()->graphicResourceIds[kElementFlyHead]);
}
getScreen()->addGraphicToQueue(getWorld()->graphicResourceIds[kControlWingsButton1], _frameIndexes[kControlWingsButton1], _controlPoints[kControlWingsButton1], kDrawFlagNone, 0, 2);
getScreen()->addGraphicToQueue(getWorld()->graphicResourceIds[kControlWingsButton2], _frameIndexes[kControlWingsButton2], _controlPoints[kControlWingsButton2], kDrawFlagNone, 0, 2);
getScreen()->addGraphicToQueue(getWorld()->graphicResourceIds[kControlWingsButton3], _frameIndexes[kControlWingsButton3], _controlPoints[kControlWingsButton3], kDrawFlagNone, 0, 2);
getScreen()->addGraphicToQueue(getWorld()->graphicResourceIds[kElementLever], _frameIndexes[kElementLever], Common::Point(9, 40), kDrawFlagNone, 0, 2);
getScreen()->addGraphicToQueue(getWorld()->graphicResourceIds[kControlReset], _frameIndexes[kControlReset], _controlPoints[kControlReset], kDrawFlagNone, 0, 2);
getScreen()->addGraphicToQueue(getWorld()->graphicResourceIds[kControlWheelRight], _frameIndexes[kControlWheelRight], _controlPoints[kControlWheelRight], kDrawFlagNone, 0, 2);
getScreen()->addGraphicToQueue(getWorld()->graphicResourceIds[kControlWheelLeft], _frameIndexes[kControlWheelLeft], _controlPoints[kControlWheelLeft], kDrawFlagNone, 0, 2);
getScreen()->addGraphicToQueue(getWorld()->graphicResourceIds[kControlButtonLeft], _frameIndexes[kControlButtonLeft], _controlPoints[kControlButtonLeft], kDrawFlagNone, 0, 2);
getScreen()->addGraphicToQueue(getWorld()->graphicResourceIds[kControlButtonRight], _frameIndexes[kControlButtonRight], _controlPoints[kControlButtonRight], kDrawFlagNone, 0, 2);
getScreen()->addGraphicToQueue(getWorld()->graphicResourceIds[kElementWingLeft1], _frameIndexes[kElementWingLeft1], Common::Point(326, 162), kDrawFlagNone, 1, 1);
getScreen()->addGraphicToQueue(getWorld()->graphicResourceIds[kElementWingRight1], _frameIndexes[kElementWingRight1], Common::Point(374, 86), kDrawFlagNone, 1, 1);
getScreen()->addGraphicToQueue(getWorld()->graphicResourceIds[kElementWingLeft2], _frameIndexes[kElementWingLeft2], Common::Point(275, 186), kDrawFlagNone, 1, 1);
getScreen()->addGraphicToQueue(getWorld()->graphicResourceIds[kElementWingRight2], _frameIndexes[kElementWingRight2], Common::Point(419, 59), kDrawFlagNone, 1, 1);
getScreen()->addGraphicToQueue(getWorld()->graphicResourceIds[kElementWingLeft3], _frameIndexes[kElementWingLeft3], Common::Point(386, 196), kDrawFlagNone, 1, 1);
getScreen()->addGraphicToQueue(getWorld()->graphicResourceIds[kElementWingRight3], _frameIndexes[kElementWingRight3], Common::Point(433, 111), kDrawFlagNone, 1, 1);
getScreen()->addGraphicToQueue(getWorld()->graphicResourceIds[kControlGlyph1], _frameIndexes[kControlGlyph1], _controlPoints[kControlGlyph1], kDrawFlagNone, 0, 2);
getScreen()->addGraphicToQueue(getWorld()->graphicResourceIds[kControlGlyph2], _frameIndexes[kControlGlyph2], _controlPoints[kControlGlyph2], kDrawFlagNone, 0, 2);
getScreen()->addGraphicToQueue(getWorld()->graphicResourceIds[kControlGlyph3], _frameIndexes[kControlGlyph3], _controlPoints[kControlGlyph3], kDrawFlagNone, 0, 2);
getScreen()->addGraphicToQueue(getWorld()->graphicResourceIds[kControlGlyph4], _frameIndexes[kControlGlyph4], _controlPoints[kControlGlyph4], kDrawFlagNone, 0, 2);
getScreen()->addGraphicToQueue(getWorld()->graphicResourceIds[kControlGlyph5], _frameIndexes[kControlGlyph5], _controlPoints[kControlGlyph5], kDrawFlagNone, 0, 2);
getScreen()->addGraphicToQueue(getWorld()->graphicResourceIds[kControlGlyph6], _frameIndexes[kControlGlyph6], _controlPoints[kControlGlyph6], kDrawFlagNone, 0, 2);
bool reseted = false;
for (uint32 i = 0; i < 3; ++i) {
if (_wingsState[i]) {
if (_frameIndexes[kElementWingLeft1 + 2*i] != GraphicResource::getFrameCount(_vm, getWorld()->graphicResourceIds[kElementWingLeft1 + 2*i]) - 1)
_frameIndexes[kElementWingLeft1 + 2*i] = (_frameIndexes[kElementWingLeft1 + 2*i] + 1) % GraphicResource::getFrameCount(_vm, getWorld()->graphicResourceIds[kElementWingLeft1 + 2*i]);
if (_frameIndexes[kElementWingRight1 + 2*i] != GraphicResource::getFrameCount(_vm, getWorld()->graphicResourceIds[kElementWingRight1 + 2*i]) - 1)
_frameIndexes[kElementWingRight1 + 2*i] = (_frameIndexes[kElementWingRight1 + 2*i] + 1) % GraphicResource::getFrameCount(_vm, getWorld()->graphicResourceIds[kElementWingRight1 + 2*i]);
} else {
if (_frameIndexes[kElementWingLeft1 + 2*i] > 0) {
--_frameIndexes[kElementWingLeft1 + 2*i];
if (_resetFlag && _frameIndexes[kElementWingLeft1 + 2*i] == 0 && !reseted) {
_frameIndexes[kElementLensLeft] = 0;
reseted = true;
}
}
if (_frameIndexes[kElementWingRight1 + 2*i ] > 0) {
--_frameIndexes[kElementWingRight1 + 2*i];
if (_resetFlag && _frameIndexes[kElementWingRight1 + 2*i] == 0 && !reseted) {
_frameIndexes[kElementLensRight] = 0;
reseted = true;
}
}
}
}
getScreen()->addGraphicToQueue(getWorld()->graphicResourceIds[kElementLensLeft], _frameIndexes[kElementLensLeft], Common::Point(305, 216), kDrawFlagNone, 0, 2);
getScreen()->addGraphicToQueue(getWorld()->graphicResourceIds[kElementLensRight], _frameIndexes[kElementLensRight], Common::Point(411, 65), kDrawFlagNone, 0, 2);
getScreen()->addGraphicToQueue(getWorld()->graphicResourceIds[kElementIndicator], _frameIndexes[kElementSwirlRim], Common::Point(158, 148), kDrawFlagNone, 0, 2);
for (uint32 i = 0; i < 6; ++i) {
if (_glyphFlags[0][i])
getScreen()->addGraphicToQueue(getWorld()->graphicResourceIds[58 + i], 0, Common::Point(104, 58), kDrawFlagNone, 0, 1);
if (_glyphFlags[1][i])
getScreen()->addGraphicToQueue(getWorld()->graphicResourceIds[64 + i], 0, Common::Point(133, 70), kDrawFlagNone, 0, 1);
}
getScreen()->addGraphicToQueue(getWorld()->graphicResourceIds[kElementSwirlRim], _frameIndexes[kElementSwirlRim], Common::Point(458, 278), kDrawFlagNone, 0, 2);
if (!_data_457260 && !_data_457264)
playSound();
if (_counter) {
if (_counter < 30 || getSound()->isPlaying(getWorld()->graphicResourceIds[83])) {
++_counter;
} else {
exitPuzzle();
getCursor()->show();
}
}
}
void PuzzleHiveControl::playSound() {
// TODO
}
bool PuzzleHiveControl::hitTest1(Control control, const Common::Point &point, const Common::Point &location) {
if (control == kControlNone)
error("[PuzzleHiveControl::hitTest1] Invalid control");
GraphicResource resource(_vm);
resource.load(getWorld()->graphicResourceIds[control]);
GraphicFrame *frame = resource.getFrame(0);
Common::Point point1(point.x - location.x, point.y - location.y);
if (!frame->getRect().contains(point1)) {
return false;
} else {
point1.x -= frame->x;
point1.y -= frame->y;
return *((byte *)frame->surface.getPixels() + point1.x + frame->surface.pitch * point1.y) != 0;
}
}
} // End of namespace Asylum

View File

@@ -0,0 +1,121 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef ASYLUM_PUZZLES_HIVECONTROL_H
#define ASYLUM_PUZZLES_HIVECONTROL_H
#include "common/hashmap.h"
#include "asylum/puzzles/puzzle.h"
namespace Asylum {
class AsylumEngine;
enum Control {
kControlNone = -1,
kControlWingsButton1 = 34,
kControlWingsButton2 = 35,
kControlWingsButton3 = 36,
kControlReset = 38,
kControlWheelLeft = 39,
kControlWheelRight = 40,
kControlButtonRight = 41,
kControlButtonLeft = 42,
kControlGlyph1 = 49,
kControlGlyph2 = 50,
kControlGlyph3 = 51,
kControlGlyph4 = 52,
kControlGlyph5 = 53,
kControlGlyph6 = 54
};
static const uint32 puzzleHiveControlHieroglyphs[2][6] = {
{5, 12, 22, 13, 20, 6},
{21, 4, 14, 13, 20, 6}
};
class PuzzleHiveControl : public Puzzle {
public:
PuzzleHiveControl(AsylumEngine *engine);
~PuzzleHiveControl();
// Serializable
virtual void saveLoadWithSerializer(Common::Serializer &s);
private:
enum Element {
kElementSwirl = 31,
kElementFlyHead = 32,
kElementResetDynamic = 33,
kElementLever = 37,
kElementWingLeft1 = 43,
kElementWingRight1 = 44,
kElementWingLeft2 = 45,
kElementWingRight2 = 46,
kElementWingLeft3 = 47,
kElementWingRight3 = 48,
kElementLensLeft = 55,
kElementLensRight = 56,
kElementIndicator = 57,
kElementSwirlRim = 71,
kElementResetStatic = 72
};
int32 _soundVolume;
int32 _rectIndex;
uint32 _counter;
int32 _data_457260;
int32 _data_457264;
uint32 _frameIndexes[73];
Common::HashMap<uint32, Common::Point> _controlPoints;
bool _resetFlag;
bool _wingsState[3];
bool _glyphFlags[2][6];
Control _currentControl;
uint32 _colorL, _colorR;
uint32 _frameIndexOffset;
uint32 _leverPosition, _prevLeverPosition, _leverDelta;
//////////////////////////////////////////////////////////////////////////
// Event Handling
//////////////////////////////////////////////////////////////////////////
bool init(const AsylumEvent &evt);
void updateScreen();
bool mouseLeftDown(const AsylumEvent &evt);
bool exitPuzzle();
//////////////////////////////////////////////////////////////////////////
// Helpers
//////////////////////////////////////////////////////////////////////////
void updateCursor();
Control findControl();
void playSound();
void reset();
bool hitTest1(Control control, const Common::Point &point, const Common::Point &location);
};
} // End of namespace Asylum
#endif // ASYLUM_PUZZLES_HIVECONTROL_H

View File

@@ -0,0 +1,199 @@
/* 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 "asylum/puzzles/hivemachine.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/asylum.h"
namespace Asylum {
const int16 keyPoints[5][2] = {
{246, 106}, {377, 171}, {319, 250}, {220, 249}, {167, 154}
};
const int16 indicatorPoints[6][2] = {
{260, 410}, {279, 411}, {298, 411}, {318, 412}, {338, 413}, {358, 413}
};
PuzzleHiveMachine::PuzzleHiveMachine(AsylumEngine *engine) : Puzzle(engine) {
_counterRed = _counterGreen = _counterKey = 0;
_rectIndex = -2;
_frameIndex = 0;
_frameIndex1 = 0;
_soundingNote = kMusicalNoteNone;
_notesNumber = 0;
_ok = false;
}
PuzzleHiveMachine::~PuzzleHiveMachine() {
}
//////////////////////////////////////////////////////////////////////////
// Event Handling
//////////////////////////////////////////////////////////////////////////
bool PuzzleHiveMachine::init(const AsylumEvent &) {
getScreen()->setPalette(getWorld()->graphicResourceIds[9]);
getScreen()->setGammaLevel(getWorld()->graphicResourceIds[9]);
_rectIndex = -2;
getCursor()->show();
return true;
}
bool PuzzleHiveMachine::mouseLeftDown(const AsylumEvent &) {
if (_rectIndex != -1 && _counterRed == 0) {
_soundingNote = MusicalNote(_rectIndex);
_melody.push_back(_soundingNote);
_notesNumber = (_notesNumber + 1) % 7;
_counterKey = 10;
_frameIndex1 = 0;
playSound();
if (_melody.size() == 6) {
_ok = (_melody[0] == kMusicalNoteB) &&
(_melody[1] == kMusicalNoteD) &&
(_melody[2] == kMusicalNoteD) &&
(_melody[3] == kMusicalNoteA) &&
(_melody[4] == kMusicalNoteF) &&
(_melody[5] == kMusicalNoteE);
if (!_ok) {
_melody.clear();
_counterRed = 30;
} else
_counterGreen = 10;
}
}
return true;
}
bool PuzzleHiveMachine::exitPuzzle() {
_notesNumber = 0;
_melody.clear();
getScreen()->clear();
_vm->switchEventHandler(getScene());
return true;
}
//////////////////////////////////////////////////////////////////////////
// Helpers
//////////////////////////////////////////////////////////////////////////
void PuzzleHiveMachine::updateCursor() {
int32 index = findRect();
if (_rectIndex == index)
return;
_rectIndex = index;
if (index == -1)
getCursor()->set(getWorld()->graphicResourceIds[12], -1, kCursorAnimationNone);
else
getCursor()->set(getWorld()->graphicResourceIds[12], -1);
}
int32 PuzzleHiveMachine::findRect() {
Common::Point mouse = getCursor()->position();
GraphicResource resource(_vm);
for (uint32 i = 0; i < 5; ++i) {
resource.load(getWorld()->graphicResourceIds[i + 13]);
GraphicFrame *frame = resource.getFrame(0);
Common::Point point(mouse.x - keyPoints[i][0], mouse.y - keyPoints[i][1]);
if (frame->getRect().contains(point)) {
point.x -= frame->x;
point.y -= frame->y;
if (frame->surface.getPixel(point.x, point.y))
return i;
}
}
return -1;
}
void PuzzleHiveMachine::updateScreen() {
getScreen()->clearGraphicsInQueue();
getScreen()->addGraphicToQueue(getWorld()->graphicResourceIds[8], 0, Common::Point(0, 0), kDrawFlagNone, 0, 2);
if (_ok) {
if (_counterGreen > 1)
--_counterGreen;
else if (_counterGreen-- == 1) {
getSound()->playSound(getWorld()->graphicResourceIds[86], false, Config.sfxVolume - 10);
_vm->setGameFlag(kGameFlagSolveHiveMachine);
_vm->switchEventHandler(getScene());
}
getScreen()->addGraphicToQueue(getWorld()->graphicResourceIds[11], 0, Common::Point(271, 369), kDrawFlagNone, 0, 1);
} else if (_counterRed) {
if (_counterRed == 1)
_notesNumber = 0;
else if (_counterRed == 30)
getSound()->playSound(getWorld()->graphicResourceIds[85], false, Config.sfxVolume - 10);
getScreen()->addGraphicToQueue(getWorld()->graphicResourceIds[10], 0, Common::Point(318, 372), kDrawFlagNone, 0, 1);
--_counterRed;
}
for (uint32 i = 0; i < 5; ++i) {
uint32 resourceId = i + 13, frameIndex;
if (_soundingNote == MusicalNote(i)) {
resourceId += 5;
frameIndex = _frameIndex1;
} else
frameIndex = _frameIndex;
getScreen()->addGraphicToQueue(getWorld()->graphicResourceIds[resourceId], frameIndex, &keyPoints[i], kDrawFlagNone, 0, 1);
}
if (_counterKey)
--_counterKey;
else {
_soundingNote = kMusicalNoteNone;
_frameIndex1 = 0;
}
for (uint32 i = 0; i < _notesNumber; ++i)
getScreen()->addGraphicToQueue(getWorld()->graphicResourceIds[84], 0, &indicatorPoints[i], kDrawFlagNone, 0, 1);
_frameIndex = (_frameIndex + 1) % GraphicResource::getFrameCount(_vm, getWorld()->graphicResourceIds[13]);
if (_counterKey)
_frameIndex1 = (_frameIndex1 + 1) % GraphicResource::getFrameCount(_vm, getWorld()->graphicResourceIds[18]);
}
void PuzzleHiveMachine::playSound() {
if (_soundingNote == kMusicalNoteNone)
error("[PuzzleHiveMachine::playSound] Invalid sound resource id");
uint32 soundMap[] = {4, 2, 3, 0, 1};
getSound()->playSound(getWorld()->graphicResourceIds[soundMap[_soundingNote] + 23], false, Config.sfxVolume - 10);
}
} // End of namespace Asylum

View File

@@ -0,0 +1,74 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef ASYLUM_PUZZLES_HIVEMACHINE_H
#define ASYLUM_PUZZLES_HIVEMACHINE_H
#include "common/array.h"
#include "asylum/puzzles/puzzle.h"
namespace Asylum {
class AsylumEngine;
class PuzzleHiveMachine : public Puzzle {
public:
PuzzleHiveMachine(AsylumEngine *engine);
~PuzzleHiveMachine();
private:
enum MusicalNote {
kMusicalNoteNone = -1,
kMusicalNoteF,
kMusicalNoteD,
kMusicalNoteE,
kMusicalNoteA,
kMusicalNoteB
};
uint32 _counterRed, _counterGreen, _counterKey;
int32 _rectIndex;
uint32 _frameIndex, _frameIndex1;
Common::Array<MusicalNote> _melody;
MusicalNote _soundingNote;
uint32 _notesNumber;
bool _ok;
//////////////////////////////////////////////////////////////////////////
// Event Handling
//////////////////////////////////////////////////////////////////////////
bool init(const AsylumEvent &evt);
bool mouseLeftDown(const AsylumEvent &evt);
bool exitPuzzle();
//////////////////////////////////////////////////////////////////////////
// Helpers
//////////////////////////////////////////////////////////////////////////
void updateCursor();
int32 findRect();
void updateScreen();
void playSound();
};
} // End of namespace Asylum
#endif // ASYLUM_PUZZLES_HIVEMACHINE_H

View File

@@ -0,0 +1,250 @@
/* 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 "asylum/puzzles/lock.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/asylum.h"
namespace Asylum {
const int16 puzzleLockPolygons[16][2] = {
{159, 293}, {151, 318}, {179, 322}, {185, 298},
{212, 303}, {207, 327}, {234, 332}, {239, 308},
{149, 333}, {146, 365}, {172, 369}, {176, 338},
{202, 345}, {200, 375}, {226, 379}, {231, 347}
};
PuzzleLock::PuzzleLock(AsylumEngine *engine) : Puzzle(engine) {
memset(&_frameIndexes, 0, sizeof(_frameIndexes));
_frameIndexes[0] = _frameIndexes[1] = _frameIndexes[2] = 4;
_incrementLock = false;
_counter = 0;
memset(&_ticks, 0, sizeof(_ticks));
}
PuzzleLock::~PuzzleLock() {
}
void PuzzleLock::saveLoadWithSerializer(Common::Serializer &s) {
s.syncAsSint32LE(_frameIndexes[0]);
s.syncAsSint32LE(_frameIndexes[1]);
s.syncAsSint32LE(_frameIndexes[2]);
}
//////////////////////////////////////////////////////////////////////////
// Event Handling
//////////////////////////////////////////////////////////////////////////
bool PuzzleLock::init(const AsylumEvent &) {
getScreen()->clear();
getScreen()->setPalette(getWorld()->graphicResourceIds[14]);
getScreen()->setGammaLevel(getWorld()->graphicResourceIds[14]);
_vm->setGameFlag(kGameFlag115);
getCursor()->set(getWorld()->graphicResourceIds[41], 0, kCursorAnimationNone);
return true;
}
bool PuzzleLock::update(const AsylumEvent &) {
updateCursor();
// Draw screen
getScreen()->clearGraphicsInQueue();
getScreen()->fillRect(0, 0, 640, 480, 252);
getScreen()->draw(getWorld()->graphicResourceIds[13], 0, Common::Point(0, 0), kDrawFlagNone, true);
if (_frameIndexes[0] != 32 || _frameIndexes[1] != 28 || _frameIndexes[2] != 0) {
getScreen()->addGraphicToQueue(getWorld()->graphicResourceIds[15], (uint32)_frameIndexes[0], Common::Point(145, 292), kDrawFlagNone, 0, 1);
getScreen()->addGraphicToQueue(getWorld()->graphicResourceIds[15], (uint32)_frameIndexes[1], Common::Point(173, 297), kDrawFlagNone, 0, 1);
getScreen()->addGraphicToQueue(getWorld()->graphicResourceIds[15], (uint32)_frameIndexes[2], Common::Point(201, 302), kDrawFlagNone, 0, 1);
getScreen()->addGraphicToQueue(getWorld()->graphicResourceIds[40], (uint32)_frameIndexes[3], Common::Point(337, 127), kDrawFlagNone, 0, 1);
if (_frameIndexes[4] != -1)
getScreen()->addGraphicToQueue(getWorld()->graphicResourceIds[42], (uint32)_frameIndexes[4], Common::Point(318, 102), kDrawFlagNone, 0, 1);
if (_frameIndexes[5] != -1)
getScreen()->addGraphicToQueue(getWorld()->graphicResourceIds[43], (uint32)_frameIndexes[5], Common::Point(318, 99), kDrawFlagNone, 0, 1);
getScreen()->drawGraphicsInQueue();
getScreen()->copyBackBufferToScreen();
} else {
if (_frameIndexes[6] == 5)
getSound()->playSound(getWorld()->soundResourceIds[15], false, Config.sfxVolume - 10);
getScreen()->addGraphicToQueue(getWorld()->graphicResourceIds[16], (uint32)_frameIndexes[6], Common::Point(0, 264), kDrawFlagNone, 0, 1);
++_counter;
if (_counter > 9) {
++_frameIndexes[6];
if (_frameIndexes[6] > 7) {
getCursor()->hide();
getSharedData()->setFlag(kFlag1, true);
_vm->setGameFlag(kGameFlag52);
getSound()->playSound(getWorld()->soundResourceIds[16], false, Config.sfxVolume - 10);
_frameIndexes[6] = 0;
_counter = 0;
getSharedData()->reset();
exitPuzzle();
} else {
getScreen()->drawGraphicsInQueue();
getScreen()->copyBackBufferToScreen();
_counter = 0;
}
}
}
// Update frame indexes
for (uint32 i = 0; i < 3; i++) {
if (_frameIndexes[i] % ~3 && _frameIndexes[i]) {
++_counter;
if (_counter > 3) {
if (_incrementLock)
++_frameIndexes[i];
else
--_frameIndexes[i];
if (_frameIndexes[i] < 0)
_frameIndexes[i] = 43;
if (_frameIndexes[i] > 43)
_frameIndexes[i] = 0;
_counter = 0;
}
}
}
for (uint32 i = 0; i < 2; i++) {
if (_frameIndexes[i + 4] == -1) {
_ticks[i] = _vm->getTick();
if (rnd(1000) < 10)
_frameIndexes[i + 4] = 0;
} else {
if (_vm->getTick() > _ticks[i] + 200) {
++_frameIndexes[i + 4];
if (_frameIndexes[i + 4] > 24)
_frameIndexes[i + 4] = -1;
_ticks[i] = _vm->getTick();
}
}
}
if (_frameIndexes[3]) {
if (_vm->getTick() > _ticks[2] + 100) {
++_frameIndexes[3];
if (_frameIndexes[3] > 15)
_frameIndexes[3] = 0;
_ticks[2] = _vm->getTick();
}
} else {
_ticks[2] = _vm->getTick();
if (rnd(1000) < 10)
_frameIndexes[3] = 1;
}
return true;
}
bool PuzzleLock::mouseLeftDown(const AsylumEvent &evt) {
if (_frameIndexes[6])
return false;
Common::Point mousePos = evt.mouse;
for (uint32 i = 0; i < 3; i++) {
if (hitTest(&puzzleLockPolygons[0], mousePos, 8 + 2 * i)) {
if (!(_frameIndexes[i] % ~3))
getSound()->playSound(getWorld()->soundResourceIds[14], false, Config.sfxVolume - 10);
_incrementLock = true;
++_frameIndexes[i];
if (_frameIndexes[i] > 43)
_frameIndexes[i] = 0;
}
}
for (uint32 i = 0; i < 3; i++) {
if (hitTest(&puzzleLockPolygons[0], mousePos, 2 * i)) {
if (!(_frameIndexes[i] % ~3))
getSound()->playSound(getWorld()->soundResourceIds[14], false, Config.sfxVolume - 10);
_incrementLock = false;
--_frameIndexes[i];
if (_frameIndexes[i] < 0)
_frameIndexes[i] = 43;
}
}
return true;
}
bool PuzzleLock::exitPuzzle() {
getScreen()->clear();
_vm->switchEventHandler(getScene());
return true;
}
//////////////////////////////////////////////////////////////////////////
// Helpers
//////////////////////////////////////////////////////////////////////////
void PuzzleLock::updateCursor() {
Common::Point mousePos = getCursor()->position();
for (uint32 i = 0; i < 6; i++) {
if (hitTest(&puzzleLockPolygons[0], mousePos, 2 * i)) {
if (getCursor()->getAnimation() != kCursorAnimationMirror)
getCursor()->set(getWorld()->graphicResourceIds[41]);
return ;
}
}
if (getCursor()->getAnimation() == kCursorAnimationMirror)
getCursor()->set(getWorld()->graphicResourceIds[41], 0, kCursorAnimationNone);
}
} // End of namespace Asylum

View File

@@ -0,0 +1,61 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef ASYLUM_PUZZLES_LOCK_H
#define ASYLUM_PUZZLES_LOCK_H
#include "asylum/puzzles/puzzle.h"
namespace Asylum {
class AsylumEngine;
class PuzzleLock : public Puzzle {
public:
PuzzleLock(AsylumEngine *engine);
~PuzzleLock();
// Serializable
virtual void saveLoadWithSerializer(Common::Serializer &s);
private:
int32 _frameIndexes[7];
bool _incrementLock;
uint32 _counter;
uint32 _ticks[3];
//////////////////////////////////////////////////////////////////////////
// Event Handling
//////////////////////////////////////////////////////////////////////////
bool init(const AsylumEvent &evt);
bool update(const AsylumEvent &evt);
bool mouseLeftDown(const AsylumEvent &evt);
bool exitPuzzle();
//////////////////////////////////////////////////////////////////////////
// Helpers
//////////////////////////////////////////////////////////////////////////
void updateCursor();
};
} // End of namespace Asylum
#endif // ASYLUM_PUZZLES_LOCK_H

View File

@@ -0,0 +1,601 @@
/* 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 "asylum/puzzles/morguedoor.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/asylum.h"
namespace Asylum {
PuzzleMorgueDoor::PuzzleMorgueDoor(AsylumEngine *engine) : Puzzle(engine) {
memset(&_frameCounts, 0, sizeof(_frameCounts));
memset(&_frameIndexes, 0, sizeof(_frameIndexes));
_data_4572A4 = false;
_data_4572A8 = false;
_data_4572AC = false;
_data_4572B0 = false;
_data_45A9D8 = 0;
_data_45A9DC = 0;
_topLeverOpen = false;
_bottomLeverOpen = false;
_moveTopGear = false;
_moveBottomGear = false;
_flag5 = false;
_flag6 = false;
_flag7 = false;
}
PuzzleMorgueDoor::~PuzzleMorgueDoor() {
}
void PuzzleMorgueDoor::saveLoadWithSerializer(Common::Serializer &s) {
s.syncAsSint32LE(_frameIndexes[kTopLeverOpened]);
s.syncAsSint32LE(_frameIndexes[kBottomLeverOpened]);
s.syncAsSint32LE(_frameIndexes[kBottomGear]);
s.syncAsSint32LE(_frameIndexes[kTopLever]);
s.syncAsSint32LE(_frameIndexes[kBottomLever]);
s.syncAsSint32LE(_frameIndexes[kTopRightLever]);
s.syncAsSint32LE(_frameIndexes[kTopSmallLever]);
s.syncAsSint32LE(_frameIndexes[kBottomSmallLever]);
s.syncAsSint32LE(_frameIndexes[kRightGear]);
s.syncAsSint32LE(_frameIndexes[kTopGear]);
s.syncAsSint32LE(_frameIndexes[kTopRightValve]);
s.syncAsSint32LE(_frameIndexes[kCenterValve]);
s.syncAsSint32LE(_data_45A9D8);
s.syncAsSint32LE(_data_45A9DC);
s.syncAsSint32LE(_flag6);
s.syncAsSint32LE(_flag7);
s.syncAsSint32LE(_topLeverOpen);
s.syncAsSint32LE(_bottomLeverOpen);
}
//////////////////////////////////////////////////////////////////////////
// Event Handling
//////////////////////////////////////////////////////////////////////////
bool PuzzleMorgueDoor::init(const AsylumEvent &evt) {
getCursor()->set(getWorld()->graphicResourceIds[33], -1, kCursorAnimationNone, 7);
_frameCounts[kTopLever] = GraphicResource::getFrameCount(_vm, getWorld()->graphicResourceIds[21]);
_frameCounts[kBottomLever] = GraphicResource::getFrameCount(_vm, getWorld()->graphicResourceIds[22]);
_frameCounts[kTopLeverOpened] = GraphicResource::getFrameCount(_vm, getWorld()->graphicResourceIds[23]);
_frameCounts[kBottomLeverOpened] = GraphicResource::getFrameCount(_vm, getWorld()->graphicResourceIds[24]);
_frameCounts[kTopRightValve] = GraphicResource::getFrameCount(_vm, getWorld()->graphicResourceIds[25]);
_frameCounts[kCenterValve] = GraphicResource::getFrameCount(_vm, getWorld()->graphicResourceIds[26]);
_frameCounts[kRightGear] = GraphicResource::getFrameCount(_vm, getWorld()->graphicResourceIds[27]);
_frameCounts[kTopRightLever] = GraphicResource::getFrameCount(_vm, getWorld()->graphicResourceIds[28]);
_frameCounts[kTopGear] = GraphicResource::getFrameCount(_vm, getWorld()->graphicResourceIds[31]);
_frameCounts[kBottomGear] = GraphicResource::getFrameCount(_vm, getWorld()->graphicResourceIds[32]);
getScreen()->setPalette(getWorld()->graphicResourceIds[20]);
getScreen()->setGammaLevel(getWorld()->graphicResourceIds[20]);
return mouseLeftDown(evt);
}
void PuzzleMorgueDoor::updateScreen() {
// Draw elements
getScreen()->clearGraphicsInQueue();
getScreen()->fillRect(0, 0, 640, 480, 252);
getScreen()->draw(getWorld()->graphicResourceIds[19], 0, Common::Point(0, 0), kDrawFlagNone, true);
getScreen()->addGraphicToQueue(getWorld()->graphicResourceIds[21], (uint32)_frameIndexes[kTopLever], Common::Point(47, 0), kDrawFlagNone, 0, 1);
getScreen()->addGraphicToQueue(getWorld()->graphicResourceIds[22], (uint32)_frameIndexes[kBottomLever], Common::Point(51, 236), kDrawFlagNone, 0, 1);
if (_topLeverOpen)
getScreen()->addGraphicToQueue(getWorld()->graphicResourceIds[23], (uint32)_frameIndexes[kTopLeverOpened], Common::Point(80, 0), kDrawFlagNone, 0, 1);
if (_bottomLeverOpen)
getScreen()->addGraphicToQueue(getWorld()->graphicResourceIds[24], (uint32)_frameIndexes[kBottomLeverOpened], Common::Point(89, 230), kDrawFlagNone, 0, 1);
getScreen()->addGraphicToQueue(getWorld()->graphicResourceIds[25], (uint32)_frameIndexes[kTopRightValve], Common::Point(515, 41), kDrawFlagNone, 0, 1);
getScreen()->addGraphicToQueue(getWorld()->graphicResourceIds[26], (uint32)_frameIndexes[kCenterValve], Common::Point(267, 190), kDrawFlagNone, 0, 1);
getScreen()->addGraphicToQueue(getWorld()->graphicResourceIds[27], (uint32)_frameIndexes[kRightGear], Common::Point(388, 105), kDrawFlagNone, 0, 1);
getScreen()->addGraphicToQueue(getWorld()->graphicResourceIds[28], (uint32)_frameIndexes[kTopRightLever], Common::Point(491, 143), kDrawFlagNone, 0, 1);
getScreen()->addGraphicToQueue(getWorld()->graphicResourceIds[29], (uint32)_frameIndexes[kTopSmallLever], Common::Point(347, 124), kDrawFlagNone, 0, 1);
getScreen()->addGraphicToQueue(getWorld()->graphicResourceIds[30], (uint32)_frameIndexes[kBottomSmallLever], Common::Point(346, 339), kDrawFlagNone, 0, 1);
getScreen()->addGraphicToQueue(getWorld()->graphicResourceIds[31], (uint32)_frameIndexes[kTopGear], Common::Point(276, 67), kDrawFlagNone, 0, 1);
getScreen()->addGraphicToQueue(getWorld()->graphicResourceIds[32], (uint32)_frameIndexes[kBottomGear], Common::Point(278, 378), kDrawFlagNone, 0, 1);
updateState();
}
bool PuzzleMorgueDoor::mouseLeftDown(const AsylumEvent &evt) {
Common::Point mousePos = evt.mouse;
// Top small lever
if (mousePos.x > 347 && mousePos.x < 357
&& mousePos.y > 124 && mousePos.y < 154) {
_frameIndexes[kTopSmallLever] = 1;
getSound()->playSound(getWorld()->soundResourceIds[6], false, Config.sfxVolume - 10);
}
// Bottom small lever
if (mousePos.x > 346 && mousePos.x < 356
&& mousePos.y > 339 && mousePos.y < 386) {
_frameIndexes[kBottomSmallLever] = 1;
getSound()->playSound(getWorld()->soundResourceIds[6], false, Config.sfxVolume - 10);
}
// Top Right Valve
if (mousePos.x > 515 && mousePos.x < 605
&& mousePos.y > 41 && mousePos.y < 120) {
if (_frameIndexes[kTopRightValve] == 0) {
_frameIndexes[kTopRightValve] = 1;
getSound()->playSound(getWorld()->soundResourceIds[1], false, Config.sfxVolume - 10);
}
return true;
}
// Center Valve turning left
if (mousePos.x > 267 && mousePos.x < 325
&& mousePos.y > 190 && mousePos.y < 320) {
if (_frameIndexes[kCenterValve] == 0) {
_frameIndexes[kCenterValve] = 1;
getSound()->playSound(getWorld()->soundResourceIds[0], false, Config.sfxVolume - 10);
_data_4572B0 = true;
}
return true;
}
// Center Valve turning right
if (mousePos.x > 325 && mousePos.x < 383
&& mousePos.y > 190 && mousePos.y < 320) {
if (_frameIndexes[kCenterValve] == 0) {
_frameIndexes[kCenterValve] = 14;
getSound()->playSound(getWorld()->soundResourceIds[0], false, Config.sfxVolume - 10);
_data_4572B0 = false;
}
return true;
}
// Top right lever moving left
if (mousePos.x > 507 && mousePos.x < 556
&& mousePos.y > 124 && mousePos.y < 177) {
if (_frameIndexes[kTopRightLever] == 4) {
getSound()->playSound(getWorld()->soundResourceIds[2], false, Config.sfxVolume - 10);
_data_4572A4 = true;
_data_4572AC = true;
}
return true;
}
// Top right lever moving right
if (mousePos.x > 556 && mousePos.x < 605
&& mousePos.y > 124 && mousePos.y < 177) {
if (_frameIndexes[kTopRightLever] == 4) {
getSound()->playSound(getWorld()->soundResourceIds[2], false, Config.sfxVolume - 10);
_data_4572A8 = true;
_data_4572AC = false;
}
}
return true;
}
bool PuzzleMorgueDoor::exitPuzzle() {
getCursor()->hide();
getSharedData()->setFlag(kFlag1, true);
getScreen()->stopPaletteFade(0, 0, 0);
_vm->switchEventHandler(getScene());
return false;
}
//////////////////////////////////////////////////////////////////////////
// Helpers
//////////////////////////////////////////////////////////////////////////
void PuzzleMorgueDoor::updateCursor() {
bool animate = false;
Common::Point mousePos = getCursor()->position();
if (mousePos.x > 347 && mousePos.x < 357 && mousePos.y > 124 && mousePos.y < 154)
animate = true;
if (mousePos.x > 346 && mousePos.x < 356 && mousePos.y > 339 && mousePos.y < 386)
animate = true;
if (mousePos.x > 515 && mousePos.x < 605 && mousePos.y > 41 && mousePos.y < 120)
animate = true;
if (mousePos.x > 267 && mousePos.x < 325 && mousePos.y > 190 && mousePos.y < 320)
animate = true;
if (mousePos.x > 325 && mousePos.x < 383 && mousePos.y > 190 && mousePos.y < 320)
animate = true;
if (mousePos.x > 507 && mousePos.x < 556 && mousePos.y > 124 && mousePos.y < 177)
animate = true;
if (mousePos.x > 556 && mousePos.x < 605 && mousePos.y > 124 && mousePos.y < 177)
animate = true;
// Default cursor
if (animate) {
if (getCursor()->getAnimation() != kCursorAnimationMirror) {
getCursor()->set(getWorld()->graphicResourceIds[33], -1, kCursorAnimationMirror, 7);
}
} else if (getCursor()->getAnimation() != kCursorAnimationNone) {
getCursor()->set(getWorld()->graphicResourceIds[33], -1, kCursorAnimationNone, 7);
}
}
void PuzzleMorgueDoor::updateState() {
// Move top gear
if (_moveTopGear) {
switch (_data_45A9D8) {
default:
break;
case 1:
--_frameIndexes[kTopGear];
if (_frameIndexes[kTopGear] < 0) {
_data_45A9D8 = 0;
_moveTopGear = false;
_frameIndexes[kTopGear] = 0;
getSound()->stop(getWorld()->soundResourceIds[8]);
}
break;
case 2:
--_frameIndexes[kTopGear];
if (_frameIndexes[kTopGear] < 0) {
_data_45A9D8 = 1;
_frameIndexes[kTopGear] = 10;
}
break;
case 3:
--_frameIndexes[kTopGear];
if (_frameIndexes[kTopGear] < 0) {
_data_45A9D8 = 2;
_frameIndexes[kTopGear] = 10;
}
break;
}
if (!_flag6 || _data_45A9D8 < 3)
_frameIndexes[kTopLever] = 5 * _data_45A9D8;
}
// Move bottom gear
if (_moveBottomGear) {
switch (_data_45A9DC) {
default:
break;
case 1:
--_frameIndexes[kBottomGear];
if (_frameIndexes[kBottomGear] < 0) {
_data_45A9DC = 0;
_frameIndexes[kBottomGear] = 0;
_moveBottomGear = false;
getSound()->stop(getWorld()->soundResourceIds[8]);
}
break;
case 2:
--_frameIndexes[kBottomGear];
if (_frameIndexes[kBottomGear] < 0) {
_data_45A9DC = 1;
_frameIndexes[kBottomGear] = 10;
}
break;
case 3:
--_frameIndexes[kBottomGear];
if (_frameIndexes[kBottomGear] < 0) {
_data_45A9DC = 2;
_frameIndexes[kBottomGear] = 10;
}
break;
}
if (!_flag7 || _data_45A9DC < 3)
_frameIndexes[kBottomLever] = 5 * _data_45A9DC;
}
// Update gears
if (_flag5) {
--_frameIndexes[kRightGear];
if (_data_4572AC) {
if (_data_45A9D8 < 3)
_frameIndexes[kTopGear] = 10 * (14 - _frameIndexes[kRightGear]) / 14;
} else {
if (_data_45A9DC < 3)
_frameIndexes[kBottomGear] = 10 * (14 - _frameIndexes[kRightGear]) / 14;
}
if (!_frameIndexes[kRightGear]) {
_flag5 = false;
if (_data_4572AC) {
if (_frameIndexes[kTopLever] < 15)
_frameIndexes[kTopLever] += 5;
if (_data_45A9D8 < 3)
++_data_45A9D8;
if (_data_45A9D8 == 3 && _flag6)
_frameIndexes[kTopLever] = _frameCounts[kTopLever] - 1;
} else {
if (_frameIndexes[kBottomLever] < 15)
_frameIndexes[kBottomLever] += 5;
if (_data_45A9DC < 3)
++_data_45A9DC;
if (_data_45A9DC == 3 && _flag7)
_frameIndexes[kBottomLever] = _frameCounts[kBottomLever] - 1;
}
}
}
//////////////////////////////////////////////////////////////////////////
// Update levers & gears
if (_frameIndexes[kTopRightValve] % 3 == 1 || (_frameIndexes[kTopRightValve] == 15 && _frameIndexes[kRightGear] > 13))
if (_frameIndexes[kRightGear] < 14)
++_frameIndexes[kRightGear];
if (_frameIndexes[kRightGear] > 14 && _frameIndexes[kTopRightValve] == 4)
_frameIndexes[kRightGear] = 14;
if (_data_4572A4) {
--_frameIndexes[kTopRightLever];
if (_frameIndexes[kTopRightLever] < 0) {
_frameIndexes[kTopRightLever] = 0;
_data_4572A4 = false;
if (_frameIndexes[kRightGear] == 14) {
if (_data_45A9D8 < 3)
getSound()->playSound(getWorld()->soundResourceIds[7], false, Config.sfxVolume, getWorld()->reverseStereo ? 2000 : -2000);
getSound()->playSound(getWorld()->soundResourceIds[5], false, Config.sfxVolume - 100, getWorld()->reverseStereo ? -3000 : 3000);
_flag5 = true;
}
}
} else {
if (_data_4572A8) {
++_frameIndexes[kTopRightLever];
if (_frameIndexes[kTopRightLever] > 7) {
_frameIndexes[kTopRightLever] = 7;
_data_4572A8 = false;
if (_frameIndexes[kRightGear] == 14) {
if (_data_45A9D8 < 3)
getSound()->playSound(getWorld()->soundResourceIds[7], false, Config.sfxVolume, getWorld()->reverseStereo ? 2000 : -2000);
getSound()->playSound(getWorld()->soundResourceIds[5], false, Config.sfxVolume - 100, getWorld()->reverseStereo ? -3000 : 3000);
_flag5 = true;
}
}
} else {
if (_frameIndexes[kTopRightLever] > 4)
--_frameIndexes[kTopRightLever];
else if (_frameIndexes[kTopRightLever] < 4)
++_frameIndexes[kTopRightLever];
}
}
// Left valve
if (_frameIndexes[kTopRightValve])
++_frameIndexes[kTopRightValve];
if (_frameIndexes[kCenterValve]) {
if (_data_4572B0) {
if (!_flag6 || _frameIndexes[kTopLever] < 15) {
if (_flag7 && _frameIndexes[kBottomLever] >= 15) {
_frameIndexes[kCenterValve] = 0;
getSound()->stop(getWorld()->soundResourceIds[0]);
} else {
++_frameIndexes[kCenterValve];
// Update top lever
if (_frameIndexes[kTopLever] >= 15) {
if (_frameIndexes[kTopLever] == 15)
getSound()->playSound(getWorld()->soundResourceIds[4], false, Config.sfxVolume - 10);
if (_frameIndexes[kTopLever] >= _frameCounts[kTopLever] - 1) {
_frameIndexes[kCenterValve] = 0;
_topLeverOpen = true;
_flag6 = true;
} else {
++_frameIndexes[kTopLever];
}
} else {
if (_frameIndexes[kCenterValve] >= 14)
_frameIndexes[kTopLever] = 5 * _data_45A9D8;
else
_frameIndexes[kTopLever] = _frameIndexes[kCenterValve] / 3 + 5 * _data_45A9D8;
}
// Update bottom lever
if (_frameIndexes[kBottomLever] >= 15) {
if (_frameIndexes[kBottomLever] == 15)
getSound()->playSound(getWorld()->soundResourceIds[4], false, Config.sfxVolume - 10);
if (_frameIndexes[kBottomLever] >= _frameCounts[kBottomLever] - 1) {
_frameIndexes[kCenterValve] = 0;
_bottomLeverOpen = true;
_flag7 = true;
} else {
++_frameIndexes[kBottomLever];
}
} else {
if (_frameIndexes[kCenterValve] >= 14)
_frameIndexes[kBottomLever] = 5 * _data_45A9DC;
else
_frameIndexes[kBottomLever] = _frameIndexes[kCenterValve] / 3 + 5 * _data_45A9DC;
}
}
} else {
_frameIndexes[kCenterValve] = 0;
getSound()->stop(getWorld()->soundResourceIds[0]);
}
goto updateIndices;
}
if ((!_flag6 && _frameIndexes[kTopLever] >= 15)
|| (!_flag7 && _frameIndexes[kBottomLever] >= 15)) {
_frameIndexes[kCenterValve] = 0;
getSound()->stop(getWorld()->soundResourceIds[0]);
} else {
--_frameIndexes[kCenterValve];
// Top lever
if (_frameIndexes[kTopLever] >= 15) {
if (_frameIndexes[kTopLever] == 20)
getSound()->playSound(getWorld()->soundResourceIds[3], false, Config.sfxVolume - 10);
if (_frameIndexes[kTopLever] <= 15) {
_frameIndexes[kCenterValve] = 0;
_flag6 = false;
} else {
--_frameIndexes[kTopLever];
}
_topLeverOpen = false;
} else {
_frameIndexes[kTopLever] = _frameIndexes[kCenterValve] / 3 + 5 * _data_45A9D8;
}
// Bottom lever
if (_frameIndexes[kBottomLever] >= 15) {
if (_frameIndexes[kBottomLever] == 20)
getSound()->playSound(getWorld()->soundResourceIds[3], false, Config.sfxVolume - 10);
if (_frameIndexes[kBottomLever] <= 15) {
_frameIndexes[kCenterValve] = 0;
_flag7 = false;
} else {
--_frameIndexes[kBottomLever];
}
_bottomLeverOpen = false;
} else {
_frameIndexes[kBottomLever] = _frameIndexes[kCenterValve] / 3 + 5 * _data_45A9DC;
}
}
}
//////////////////////////////////////////////////////////////////////////
// Adjust frame indexes
//////////////////////////////////////////////////////////////////////////
updateIndices:
if (_frameIndexes[kTopGear] > _frameCounts[kTopGear] - 1)
_frameIndexes[kTopGear] = 0;
if (_frameIndexes[kBottomGear] > _frameCounts[kBottomGear] - 1)
_frameIndexes[kBottomGear] = 0;
if (_frameIndexes[kBottomLever] > _frameCounts[kBottomLever] - 1)
_frameIndexes[kBottomLever] = 0;
if (_frameIndexes[kTopLeverOpened] > _frameCounts[kTopLeverOpened] - 1 || _frameIndexes[kTopLeverOpened] < 0)
_frameIndexes[kTopLeverOpened] = 0;
if (_frameIndexes[kBottomLeverOpened] > _frameCounts[kBottomLeverOpened] - 1 || _frameIndexes[kBottomLeverOpened] < 0)
_frameIndexes[kBottomLeverOpened] = 0;
if (_frameIndexes[kTopRightValve] > _frameCounts[kTopRightValve] - 1 || _frameIndexes[kTopRightValve] < 0)
_frameIndexes[kTopRightValve] = 0;
if (_frameIndexes[kCenterValve] > _frameCounts[kCenterValve] - 1)
_frameIndexes[kCenterValve] = 0;
if (_frameIndexes[kRightGear] > _frameCounts[kRightGear] - 1)
_frameIndexes[kRightGear] = 0;
if (_frameIndexes[kTopRightLever] > _frameCounts[kTopRightLever] - 1)
_frameIndexes[kTopRightLever] = 0;
// Top small lever
if (_frameIndexes[kTopSmallLever] != 0) {
++_frameIndexes[kTopSmallLever];
if (_frameIndexes[kTopSmallLever] > 5) {
_frameIndexes[kTopSmallLever] = 0;
if (_data_45A9D8 > 0) {
getSound()->playSound(getWorld()->soundResourceIds[8], false, Config.sfxVolume - 10);
_moveTopGear = true;
}
_frameIndexes[kTopGear] = 10;
}
}
// Bottom small lever
if (_frameIndexes[kBottomSmallLever] != 0) {
++_frameIndexes[kBottomSmallLever];
if (_frameIndexes[kBottomSmallLever] > 5) {
_frameIndexes[kBottomSmallLever] = 0;
if (_data_45A9DC > 0) {
getSound()->playSound(getWorld()->soundResourceIds[8], false, Config.sfxVolume - 10);
_moveBottomGear = true;
}
}
}
if (_flag6 && _flag7) {
_vm->setGameFlag(kGameFlag608);
_vm->setGameFlag(kGameFlag384);
_vm->setGameFlag(kGameFlag391);
// Original waits for 2000 ticks
g_system->delayMillis(2000);
getCursor()->hide();
getSharedData()->setFlag(kFlag1, true);
getScreen()->stopPaletteFade(0, 0, 0);
_vm->switchEventHandler(getScene());
}
}
} // End of namespace Asylum

View File

@@ -0,0 +1,90 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef ASYLUM_PUZZLES_MORGUEDOOR_H
#define ASYLUM_PUZZLES_MORGUEDOOR_H
#include "asylum/puzzles/puzzle.h"
namespace Asylum {
class AsylumEngine;
class PuzzleMorgueDoor : public Puzzle {
public:
PuzzleMorgueDoor(AsylumEngine *engine);
~PuzzleMorgueDoor();
// Serializable
virtual void saveLoadWithSerializer(Common::Serializer &s);
private:
enum PuzzleObject {
kTopLever = 0,
kBottomLever = 1,
kTopLeverOpened = 2,
kBottomLeverOpened = 3,
kTopRightValve = 4,
kCenterValve = 5,
kRightGear = 6,
kTopRightLever = 7,
kTopSmallLever = 8,
kBottomSmallLever = 9,
kTopGear = 10,
kBottomGear = 11
};
int32 _frameCounts[12]; // indexes 8 & 9 aren't used
int32 _frameIndexes[12];
bool _data_4572A4;
bool _data_4572A8;
bool _data_4572AC;
bool _data_4572B0;
int32 _data_45A9D8;
int32 _data_45A9DC;
bool _topLeverOpen;
bool _bottomLeverOpen;
bool _moveTopGear;
bool _moveBottomGear;
bool _flag5;
bool _flag6;
bool _flag7;
//////////////////////////////////////////////////////////////////////////
// Event Handling
//////////////////////////////////////////////////////////////////////////
bool init(const AsylumEvent &evt);
void updateScreen();
bool mouseLeftDown(const AsylumEvent &evt);
bool exitPuzzle();
//////////////////////////////////////////////////////////////////////////
// Helpers
//////////////////////////////////////////////////////////////////////////
void updateCursor();
void updateState();
};
} // End of namespace Asylum
#endif // ASYLUM_PUZZLES_MORGUEDOOR_H

View File

@@ -0,0 +1,616 @@
/* 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 "common/intrinsics.h"
#include "asylum/puzzles/pipes.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/asylum.h"
namespace Asylum {
const int16 connectorPoints[21][2] = {
{158, 59}, {163, 172}, {168, 272},
{202, 59}, {205, 132}, {206, 172},
{271, 60}, {272, 131}, {273, 262},
{318, 169}, {319, 206}, {318, 261},
{380, 72}, {360, 171}, {360, 206},
{428, 172}, {401, 242}, {399, 295},
{469, 119}, {466, 171}, {460, 294},
};
static const int16 peepholePoints[37][2] = {
{140, 65}, {311, 44}, {387, 48}, {475, 72},
{189, 67}, {246, 66}, {169, 113}, {215, 106},
{280, 105}, {336, 95}, {434, 80}, {248, 136},
{303, 154}, {407, 125}, {470, 151}, {193, 180},
{347, 176}, {401, 177}, {245, 201}, {325, 196},
{347, 212}, {406, 213}, {431, 218}, {174, 228},
{217, 234}, {280, 227}, {325, 239}, {370, 244},
{467, 239}, {303, 267}, {405, 273}, {356, 293},
{436, 294}, {182, 317}, {277, 299}, {324, 291},
{461, 323}
};
const uint32 peepholeResources[] = {15, 15, 15, 15, 32, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 32, 32, 15,
15, 32, 32, 15, 15, 15, 15, 15, 15, 15, 15, 32, 15, 15, 15, 15, 15, 15, 15};
static BinNum calcStateFromPosition(ConnectorType type, uint32 position) {
assert(position);
position--;
uint32 shift = !!position + !!(position >> 1) + !!(position >> 2);
return BinNum((type >> shift | type << (4 - shift)) & 0xF);
}
//////////////////////////////////////////////////////////////////////////
// Peephole
//////////////////////////////////////////////////////////////////////////
bool Peephole::marks[peepholesCount];
void Peephole::startUpWater(bool flag) {
if (flag)
memset(marks, false, sizeof(marks));
marks[_id] = true;
for (auto &connector : _connectors) {
for (auto &connectedNode : connector->_connectedNodes) {
if (!marks[connectedNode->getId()]) {
for (uint32 i = 0; i < 4; ++i) {
if (isConnected(i) && connectedNode->getId() > 3)
connectedNode->_flowValues[i] += _flowValues[i];
}
connectedNode->startUpWater();
}
}
}
}
//////////////////////////////////////////////////////////////////////////
// Connector
//////////////////////////////////////////////////////////////////////////
Connector::Connector() :
_id(0),
_position(nullptr),
_state(kBinNum0000),
_isConnected(false),
_nextConnector(nullptr),
_type(kConnectorTypeI),
_nextConnectorPosition(kDirectionNowhere) {
memset(_nodes, 0, sizeof(_nodes));
}
void Connector::init(Peephole *n, Peephole *e, Peephole *s, Peephole *w, uint32 pos, ConnectorType type, Connector *nextConnector, Direction nextConnectorPosition) {
_nodes[0] = n;
_nodes[1] = e;
_nodes[2] = s;
_nodes[3] = w;
*_position = pos;
_type = type;
_state = calcStateFromPosition(_type, *_position);
_nextConnector = nextConnector;
_nextConnectorPosition = nextConnectorPosition;
_isConnected = false;
for (uint32 i = 0; i < 4; ++i) {
if (_state & ((uint32)1 << i) && _nodes[i]) {
_nodes[i]->connect(this);
_connectedNodes.push_back(_nodes[i]);
}
}
}
void Connector::initGroup() {
if (!_isConnected && isReadyForConnection() && _nextConnector->isReadyForConnection())
connect(_nextConnector);
}
void Connector::turn(bool updpos) {
if (updpos)
*_position = (*_position == 8) ? 1 : *_position << 1;
BinNum newState = BinNum(_state >> 1 | (_state & 1) << 3);
uint32 delta = _state ^ newState;
uint32 newIndex[2], oldIndex[2];
if (delta == kBinNum1111) {
if (newState == kBinNum0101) {
newIndex[0] = 0;
newIndex[1] = 2;
oldIndex[0] = 1;
oldIndex[1] = 3;
} else {
newIndex[0] = 1;
newIndex[1] = 3;
oldIndex[0] = 0;
oldIndex[1] = 2;
}
} else {
newIndex[0] = (uint32)Common::intLog2(newState & delta);
oldIndex[0] = (uint32)Common::intLog2(_state & delta);
}
for (uint32 i = 0; i < (uint32)(delta == kBinNum1111 ? 2 : 1); ++i) {
if (_nodes[oldIndex[i]]) {
_nodes[oldIndex[i]]->disconnect(this);
_connectedNodes.remove(_nodes[oldIndex[i]]);
}
if (_nodes[newIndex[i]]) {
_nodes[newIndex[i]]->connect(this);
_connectedNodes.push_back(_nodes[newIndex[i]]);
}
}
_state = newState;
if (_nextConnector) {
if (_isConnected) {
if (!(_nextConnectorPosition & _state))
disconnect(_nextConnector);
} else if (_nextConnectorPosition & _state && _nextConnector->isReadyForConnection()) {
connect(_nextConnector);
}
}
}
void Connector::connect(Connector *connector) {
for (auto &connectedNode : _connectedNodes) {
connectedNode->connect(connector);
connector->_connectedNodes.push_back(connectedNode);
}
for (auto &connectedNode : connector->_connectedNodes) {
connectedNode->connect(this);
_connectedNodes.push_back(connectedNode);
}
_isConnected = connector->_isConnected = true;
}
void Connector::disconnect(Connector *connector) {
uint32 i;
Common::List<Common::List<Peephole *>::iterator> markedForDeletion;
bool flag;
for (i = 0; i < 4; ++i)
if (_nodes[i]) {
_nodes[i]->disconnect(connector);
connector->_connectedNodes.remove(_nodes[i]);
}
for (Common::List<Peephole *>::iterator iter = _connectedNodes.begin(); iter != _connectedNodes.end(); ++iter) {
flag = true;
for (i = 0; i < 4; ++i) {
if (*iter == _nodes[i]) {
flag = false;
break;
}
}
if (flag)
markedForDeletion.push_back(iter);
}
for (Common::List<Common::List<Peephole *>::iterator>::iterator iter1 = markedForDeletion.begin(); iter1 != markedForDeletion.end(); ++iter1) {
(*(*iter1))->disconnect(this);
_connectedNodes.remove(*(*iter1));
}
_isConnected = connector->_isConnected = false;
}
//////////////////////////////////////////////////////////////////////////
// Spider
//////////////////////////////////////////////////////////////////////////
Spider::Spider(AsylumEngine *engine, const Common::Rect &rect) : _vm(engine) {
_boundingBox = rect;
_isAlive = true;
_location.x = (int16)rnd((uint16)(_boundingBox.right - _boundingBox.left + 1)) + _boundingBox.left;
_location.y = (int16)rnd((uint16)(_boundingBox.bottom - _boundingBox.top + 1)) + _boundingBox.top;
_direction = Direction((uint32)1 << rnd(4));
_stepsNumber = 0;
_steps = 0;
randomize();
}
void Spider::randomize(Direction excluded) {
if (rnd(6) == 5)
_delta = Common::Point(0, 0);
else {
while (_direction == excluded)
_direction = Direction((uint32)1 << rnd(4));
_delta = Common::Point((_direction & kBinNum0010 ? 1 : 0) - (_direction & kBinNum1000 ? 1 : 0), (_direction & kBinNum0100 ? 1 : 0) - (_direction & kBinNum0001 ? 1 : 0));
}
_stepsNumber = rnd(maxStepsNumber - minStepsNumber + 1) + minStepsNumber;
_steps = 0;
}
Common::Point Spider::move() {
Common::Point previousLocation(_location);
if (_isAlive) {
if (_steps++ > _stepsNumber)
randomize();
if (!_boundingBox.contains(_location + _delta))
randomize(_direction);
else
_location += _delta;
}
return previousLocation;
}
//////////////////////////////////////////////////////////////////////////
// PuzzlePipes
//////////////////////////////////////////////////////////////////////////
PuzzlePipes::PuzzlePipes(AsylumEngine *engine) : Puzzle(engine) {
_previousMusicVolume = 0;
_rectIndex = -2;
_frameIndex = _frameIndexLever = 0;
memset(&_levelFlags, false, sizeof(_levelFlags));
_levelFlags[4] = true;
memset(&_levelValues, 0, sizeof(_levelValues));
memset(&_previousLevels, 0, sizeof(_previousLevels));
_isLeverReady = false;
memset(&_sinks, 0, sizeof(_sinks));
memset(&_sources, 0, sizeof(_sources));
_frameIndexSpider = nullptr;
initResources();
setup();
}
PuzzlePipes::~PuzzlePipes() {
for (uint32 i = 0; i < _spiders.size(); ++i)
delete _spiders[i];
if (_frameIndexSpider)
delete[] _frameIndexSpider;
}
void PuzzlePipes::saveLoadWithSerializer(Common::Serializer &s) {
s.skip(16);
for (uint32 i = 0; i < connectorsCount; i++) {
s.syncAsUint32LE(_positions[i]);
}
s.skip(16);
}
//////////////////////////////////////////////////////////////////////////
// Event Handling
//////////////////////////////////////////////////////////////////////////
bool PuzzlePipes::init(const AsylumEvent &) {
_previousMusicVolume = getSound()->getMusicVolume();
if (_previousMusicVolume >= -1000)
getSound()->setMusicVolume(-1000);
getSound()->playSound(getWorld()->graphicResourceIds[41], true, Config.ambientVolume);
getScreen()->setPalette(getWorld()->graphicResourceIds[0]);
getScreen()->setGammaLevel(getWorld()->graphicResourceIds[0]);
_rectIndex = -2;
checkConnections();
startUpWater();
(void)checkFlags();
getCursor()->show();
return true;
}
void PuzzlePipes::updateScreen() {
getScreen()->clearGraphicsInQueue();
getScreen()->addGraphicToQueue(getWorld()->graphicResourceIds[1], 0, Common::Point(0, 0), kDrawFlagNone, 0, 4);
for (uint32 i = 0; i < ARRAYSIZE(_connectors); ++i)
getScreen()->addGraphicToQueue(getWorld()->graphicResourceIds[_connectorResources[_connectors[i].getState()]], 0, &connectorPoints[i], kDrawFlagNone, 0, 1);
uint32 filled = 0;
for (uint32 i = 0; i < 4; ++i) {
if (fabs(_levelValues[i] - _previousLevels[i]) > 0.005)
_previousLevels[i] += _levelValues[i] > _previousLevels[i] ? 0.01f : -0.01f;
else
++filled;
}
getScreen()->addGraphicToQueue(getWorld()->graphicResourceIds[18], 0, Common::Point(210, 444 - int16(_previousLevels[0] * 52)), kDrawFlagNone, 0, 3);
getScreen()->addGraphicToQueue(getWorld()->graphicResourceIds[18], 0, Common::Point(276, 455 - int16(_previousLevels[1] * 52)), kDrawFlagNone, 0, 3);
getScreen()->addGraphicToQueue(getWorld()->graphicResourceIds[18], 0, Common::Point(376, 448 - int16(_previousLevels[2] * 52)), kDrawFlagNone, 0, 3);
getScreen()->addGraphicToQueue(getWorld()->graphicResourceIds[18], 0, Common::Point(458, 442 - int16(_previousLevels[3] * 52)), kDrawFlagNone, 0, 3);
getScreen()->addGraphicToQueue(getWorld()->graphicResourceIds[33], 0, Common::Point(204, 377), kDrawFlagNone, 0, 1);
_frameIndex = (_frameIndex + 1) % GraphicResource::getFrameCount(_vm, getWorld()->graphicResourceIds[15]);
for (uint32 i = 0; i < ARRAYSIZE(_peepholes); ++i)
if (_peepholes[i].isConnected())
getScreen()->addGraphicToQueue(getWorld()->graphicResourceIds[peepholeResources[i]], _frameIndex, &peepholePoints[i], kDrawFlagNone, 0, 1);
getScreen()->addGraphicToQueue(getWorld()->graphicResourceIds[2], _frameIndexLever, Common::Point(540, 90), kDrawFlagNone, 0, 1);
_isLeverReady = false;
if (_frameIndexLever) {
_frameIndexLever = (_frameIndexLever + 1) % GraphicResource::getFrameCount(_vm, getWorld()->graphicResourceIds[2]);
if (!_frameIndexLever) {
_isLeverReady = true;
getCursor()->show();
}
}
if (filled == 4) {
if (_levelFlags[0])
getScreen()->addGraphicToQueue(getWorld()->graphicResourceIds[40], 0, Common::Point(233, 416), kDrawFlagNone, 0, 1);
else if (_levelFlags[1])
getScreen()->addGraphicToQueue(getWorld()->graphicResourceIds[40], 0, Common::Point(299, 431), kDrawFlagNone, 0, 1);
else if (_levelFlags[2])
getScreen()->addGraphicToQueue(getWorld()->graphicResourceIds[40], 0, Common::Point(398, 421), kDrawFlagNone, 0, 1);
else if (_levelFlags[3])
getScreen()->addGraphicToQueue(getWorld()->graphicResourceIds[40], 0, Common::Point(481, 417), kDrawFlagNone, 0, 1);
if (!_levelFlags[4])
getScreen()->addGraphicToQueue(getWorld()->graphicResourceIds[45], 0, Common::Point(518, 108), kDrawFlagNone, 0, 2);
}
for (uint32 i = 0; i < _spiders.size(); ++i) {
uint32 spiderResourceId = 0;
switch (_spiders[i]->getDirection()) {
default:
error("[PuzzlePipes::update] Invalid spider direction (%d)", _spiders[i]->getDirection());
case kDirectionNh:
spiderResourceId = _spiders[i]->isAlive() ? 34 : 37;
break;
case kDirectionEt:
spiderResourceId = _spiders[i]->isAlive() ? 35 : 38; // FIXME
break;
case kDirectionSh:
spiderResourceId = _spiders[i]->isAlive() ? 36 : 39;
break;
case kDirectionWt:
spiderResourceId = _spiders[i]->isAlive() ? 35 : 38;
break;
}
if (_spiders[i]->isVisible(Common::Rect(-10, -10, 650, 490))) {
uint32 frameCountSpider = GraphicResource::getFrameCount(_vm, getWorld()->graphicResourceIds[spiderResourceId]);
_frameIndexSpider[i] = _spiders[i]->isActive() ? (_frameIndexSpider[i] + 1) % frameCountSpider : 0;
getScreen()->addGraphicToQueue(getWorld()->graphicResourceIds[spiderResourceId], _frameIndexSpider[i], _spiders[i]->move(), kDrawFlagNone, 0, 1);
}
}
if (_isLeverReady) {
_vm->clearGameFlag(kGameFlagBrokenPipeSpraying);
_vm->clearGameFlag(kGameFlagSmFtnOverflows);
_vm->clearGameFlag(kGameFlagFountainFilling);
_vm->clearGameFlag(kGameFlagSewerExplodes);
if (!_levelFlags[4])
_vm->setGameFlag((GameFlag)(96 + checkFlags()));
getScreen()->clear();
getSound()->stop(getWorld()->graphicResourceIds[41]);
getSound()->setMusicVolume(_previousMusicVolume);
_vm->switchEventHandler(getScene());
}
}
bool PuzzlePipes::mouseLeftDown(const AsylumEvent &) {
Common::Point mousePos = getCursor()->position();
if (Common::Rect(540, 90, 590, 250).contains(mousePos)) {
if (!_frameIndexLever)
++_frameIndexLever;
getCursor()->hide();
getSound()->playSound(getWorld()->graphicResourceIds[43], false, Config.sfxVolume - 10);
} else {
if (_rectIndex != -1) {
if (_rectIndex < ARRAYSIZE(connectorPoints)) {
getSound()->playSound(getWorld()->graphicResourceIds[42], false, Config.sfxVolume - 10);
_connectors[_rectIndex].turn();
startUpWater();
memset(_levelFlags, false, sizeof(_levelFlags));
_levelFlags[checkFlags()] = true;
} else {
getSound()->playSound(getWorld()->graphicResourceIds[44], false, Config.sfxVolume - 10);
_spiders[_rectIndex - ARRAYSIZE(connectorPoints)]->smash();
_frameIndexSpider[_rectIndex - ARRAYSIZE(connectorPoints)] = 0;
}
}
}
return true;
}
bool PuzzlePipes::exitPuzzle() {
getScreen()->clear();
getSound()->stop(getWorld()->graphicResourceIds[41]);
getSound()->setMusicVolume(_previousMusicVolume);
_vm->switchEventHandler(getScene());
return true;
}
//////////////////////////////////////////////////////////////////////////
// Helpers
//////////////////////////////////////////////////////////////////////////
void PuzzlePipes::initResources() {
_connectorResources[kBinNum0011] = 4;
_connectorResources[kBinNum0110] = 3;
_connectorResources[kBinNum1100] = 6;
_connectorResources[kBinNum1001] = 5;
_connectorResources[kBinNum0111] = 7;
_connectorResources[kBinNum1110] = 10;
_connectorResources[kBinNum1101] = 9;
_connectorResources[kBinNum1011] = 8;
_connectorResources[kBinNum0101] = 11;
_connectorResources[kBinNum1010] = 12;
}
void PuzzlePipes::setup() {
memset(&_levelValues, 0, sizeof(_levelValues));
for (uint32 i = 0; i < peepholesCount; ++i)
_peepholes[i].setId(i);
for (uint32 i = 0; i < connectorsCount; ++i) {
_connectors[i].setId(i);
_connectors[i].setPos(&_positions[i]);
}
for (uint32 i = 0; i < 4; ++i) {
_sinks[i] = &_peepholes[(peepholesCount - 4) + i];
_sources[i] = &_peepholes[i];
memset(&_sources[i]->_flowValues, 0, sizeof(_sources[i]->_flowValues));
_sources[i]->_flowValues[i] = 1;
}
_connectors[ 0].init( nullptr, _peepholes + 4, _peepholes + 6, _peepholes + 0, 1, kConnectorTypeL);
_connectors[ 1].init(_peepholes + 6, _peepholes + 15, _peepholes + 23, nullptr, 1, kConnectorTypeL);
_connectors[ 2].init(_peepholes + 23, _peepholes + 24, _peepholes + 33, nullptr, 2, kConnectorTypeL);
_connectors[ 3].init( nullptr, _peepholes + 5, _peepholes + 7, _peepholes + 4, 1, kConnectorTypeL);
_connectors[ 4].init(_peepholes + 7, _peepholes + 11, nullptr, nullptr, 2, kConnectorTypeL, _connectors + 5, kDirectionSh);
_connectors[ 5].init( nullptr, _peepholes + 18, _peepholes + 24, _peepholes + 15, 1, kConnectorTypeT, _connectors + 4, kDirectionNh);
_connectors[ 6].init( nullptr, _peepholes + 1, _peepholes + 8, _peepholes + 5, 1, kConnectorTypeL);
_connectors[ 7].init(_peepholes + 8, _peepholes + 12, _peepholes + 25, _peepholes + 11, 1, kConnectorTypeT);
_connectors[ 8].init(_peepholes + 25, _peepholes + 29, _peepholes + 34, _peepholes + 18, 2, kConnectorTypeT);
_connectors[ 9].init(_peepholes + 9, _peepholes + 16, _peepholes + 19, _peepholes + 12, 8, kConnectorTypeT);
_connectors[10].init(_peepholes + 19, _peepholes + 20, _peepholes + 26, nullptr, 2, kConnectorTypeL);
_connectors[11].init(_peepholes + 26, _peepholes + 31, _peepholes + 35, _peepholes + 29, 2, kConnectorTypeT);
_connectors[12].init(_peepholes + 2, _peepholes + 10, nullptr, _peepholes + 9, 2, kConnectorTypeL);
_connectors[13].init(_peepholes + 13, _peepholes + 17, nullptr, _peepholes + 16, 1, kConnectorTypeT, _connectors + 14, kDirectionSh);
_connectors[14].init( nullptr, _peepholes + 21, _peepholes + 27, _peepholes + 20, 8, kConnectorTypeT, _connectors + 13, kDirectionNh);
_connectors[15].init(_peepholes + 10, nullptr, _peepholes + 22, _peepholes + 17, 1, kConnectorTypeI, _connectors + 19, kDirectionEt);
_connectors[16].init(_peepholes + 21, _peepholes + 22, _peepholes + 30, _peepholes + 27, 2, kConnectorTypeT);
_connectors[17].init(_peepholes + 30, _peepholes + 32, nullptr, _peepholes + 31, 2, kConnectorTypeL);
_connectors[18].init(_peepholes + 3, nullptr, _peepholes + 14, _peepholes + 13, 8, kConnectorTypeL);
_connectors[19].init(_peepholes + 14, nullptr, _peepholes + 28, nullptr, 4, kConnectorTypeL, _connectors + 15, kDirectionWt);
_connectors[20].init(_peepholes + 28, nullptr, _peepholes + 36, _peepholes + 32, 4, kConnectorTypeL);
_connectors[ 4].initGroup();
_connectors[13].initGroup();
_connectors[15].initGroup();
uint32 i = rnd(kBinNum1000);
if (i & kBinNum0001)
_spiders.push_back(new Spider(_vm, Common::Rect(-10, 45, 92, 315)));
if (i & kBinNum0010)
_spiders.push_back(new Spider(_vm, Common::Rect(-10, 389, 149, 476)));
if (i & kBinNum0100)
_spiders.push_back(new Spider(_vm, Common::Rect(544, 225, 650, 490)));
if (i) {
_frameIndexSpider = new uint32[_spiders.size()]();
}
}
void PuzzlePipes::updateCursor() {
int32 index = findRect();
if (_rectIndex == index)
return;
_rectIndex = index;
// FIXME
if (index > -1 || Common::Rect(540, 90, 590, 250).contains(getCursor()->position()))
getCursor()->set(getWorld()->graphicResourceIds[16]);
else
getCursor()->set(getWorld()->graphicResourceIds[16], 0, kCursorAnimationNone);
}
int32 PuzzlePipes::findRect() {
for (uint32 i = 0; i < ARRAYSIZE(connectorPoints); ++i)
if (Common::Rect(connectorPoints[i][0] - 5, connectorPoints[i][1] - 5, connectorPoints[i][0] + 30, connectorPoints[i][1] + 30).contains(getCursor()->position()))
return i;
for (uint32 i = 0; i < _spiders.size(); ++i)
if (_spiders[i]->getPolygon(Common::Rect(10, 10, 30, 30)).contains(getCursor()->position()))
return ARRAYSIZE(connectorPoints) + i;
return -1;
}
uint32 PuzzlePipes::checkFlags() {
uint32 total = _sinks[0]->getLevel1() + _sinks[1]->getLevel1() +_sinks[2]->getLevel1() + _sinks[3]->getLevel1();
float temp;
uint32 val = 4;
if (total)
for (uint32 i = 0; i < 4; ++i) {
temp = _sinks[i]->getLevel1() / float(total);
_levelValues[i] = temp * _sinks[i]->getLevel() / 4;
if (_levelValues[i] == 1.0)
val = i;
}
else
memset(_levelValues, 0, sizeof(_levelValues));
return val;
}
void PuzzlePipes::checkConnections() {
for (uint32 i = 0; i < connectorsCount; i++) {
BinNum oldState = _connectors[i].getState(),
newState = calcStateFromPosition(_connectors[i].getType(), _positions[i]);
if (oldState != newState) {
do {
_connectors[i].turn(false);
} while (_connectors[i].getState() != newState);
}
}
}
void PuzzlePipes::startUpWater() {
for (uint32 i = 4; i < peepholesCount; ++i)
memset(_peepholes[i]._flowValues, 0, sizeof(_peepholes[i]._flowValues));
_sources[0]->startUpWater(true);
_sources[1]->startUpWater(true);
_sources[2]->startUpWater(true);
_sources[3]->startUpWater(true);
}
} // End of namespace Asylum

View File

@@ -0,0 +1,206 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef ASYLUM_PUZZLES_PIPES_H
#define ASYLUM_PUZZLES_PIPES_H
#include "common/list.h"
#include "common/hashmap.h"
#include "common/array.h"
#include "common/random.h"
#include "common/str.h"
#include "asylum/puzzles/puzzle.h"
namespace Asylum {
class AsylumEngine;
class Connector;
static const uint32 connectorsCount = 21, peepholesCount = 37;
enum BinNum {
kBinNum0000,
kBinNum0001,
kBinNum0010,
kBinNum0011,
kBinNum0100,
kBinNum0101,
kBinNum0110,
kBinNum0111,
kBinNum1000,
kBinNum1001,
kBinNum1010,
kBinNum1011,
kBinNum1100,
kBinNum1101,
kBinNum1110,
kBinNum1111
};
enum ConnectorType {
kConnectorTypeI = kBinNum0101,
kConnectorTypeL = kBinNum0110,
kConnectorTypeT = kBinNum0111
};
enum Direction {
kDirectionNowhere = kBinNum0000,
kDirectionNh = kBinNum0001,
kDirectionEt = kBinNum0010,
kDirectionSh = kBinNum0100,
kDirectionWt = kBinNum1000
};
class Peephole {
public:
Peephole() : _id(0) {}
~Peephole() {}
static bool marks[peepholesCount];
uint32 _flowValues[4];
uint32 getId() { return _id; }
void setId(uint32 id) { _id = id; }
uint32 getLevel() { return (_flowValues[0] > 0) + (_flowValues[1] > 0) + (_flowValues[2] > 0) + (_flowValues[3] > 0); }
uint32 getLevel1() { return _flowValues[0] + _flowValues[1] + _flowValues[2] + _flowValues[3]; }
bool isConnected() { return isConnected(0) || isConnected(1) || isConnected(2) || isConnected(3); }
void connect(Connector *connector) { _connectors.push_back(connector); }
void disconnect(Connector *connector) { _connectors.remove(connector); }
void startUpWater(bool flag = false);
private:
uint32 _id;
Common::List<Connector *> _connectors;
bool isConnected(uint32 val) { return _flowValues[val]; }
};
class Connector {
public:
Connector();
~Connector() {}
uint32 getId() { return _id; }
void setId(uint32 id) { _id = id; }
void setPos(uint32 *pos) { _position = pos; }
BinNum getState() { return _state; }
ConnectorType getType() { return _type; }
void init(Peephole *n, Peephole *e, Peephole *s, Peephole *w, uint32 pos, ConnectorType type, Connector *nextConnector = NULL, Direction nextConnectorPosition = kDirectionNowhere);
void initGroup();
void turn(bool updpos = true);
private:
uint32 _id;
BinNum _state;
ConnectorType _type;
uint32 *_position;
Peephole *_nodes[4];
Common::List<Peephole *> _connectedNodes;
Connector *_nextConnector;
Direction _nextConnectorPosition;
bool _isConnected;
void connect(Connector *connector);
void disconnect(Connector *connector);
bool isReadyForConnection() { return _state & _nextConnectorPosition; }
friend void Peephole::startUpWater(bool);
};
class Spider {
public:
Spider(AsylumEngine *engine, const Common::Rect &rect);
~Spider() {}
bool isAlive() const { return _isAlive; }
bool isActive() const { return _delta != Common::Point(0, 0); }
bool isVisible(Common::Rect rect) const { return rect.contains(_location); }
Direction getDirection() const { return _direction; }
Common::Rect getPolygon(Common::Rect frame) const { return Common::Rect(_location.x - frame.left, _location.y - frame.top, _location.x + frame.right, _location.y + frame.bottom); }
Common::Point move();
void smash() { _isAlive = false; }
private:
static const uint32 minStepsNumber = 20, maxStepsNumber = 200;
AsylumEngine *_vm;
bool _isAlive;
Common::Point _location;
Common::Point _delta;
Common::Rect _boundingBox;
Direction _direction;
uint32 _stepsNumber;
uint32 _steps;
void randomize(Direction excluded = kDirectionNowhere);
};
class PuzzlePipes : public Puzzle {
public:
PuzzlePipes(AsylumEngine *engine);
~PuzzlePipes();
// Serializable
virtual void saveLoadWithSerializer(Common::Serializer &s);
private:
int32 _previousMusicVolume;
int32 _rectIndex;
uint32 _frameIndex, _frameIndexLever;
bool _levelFlags[5];
float _levelValues[4], _previousLevels[4];
bool _isLeverReady;
Common::HashMap<uint32, uint32> _connectorResources;
Connector _connectors[connectorsCount];
uint32 _positions[connectorsCount];
Peephole _peepholes[peepholesCount];
Peephole *_sinks[4], *_sources[4];
Common::Array<Spider *> _spiders;
uint32 *_frameIndexSpider;
//////////////////////////////////////////////////////////////////////////
// Event Handling
//////////////////////////////////////////////////////////////////////////
bool init(const AsylumEvent &evt);
void updateScreen();
bool mouseLeftDown(const AsylumEvent &evt);
bool exitPuzzle();
//////////////////////////////////////////////////////////////////////////
// Helpers
//////////////////////////////////////////////////////////////////////////
void initResources();
void setup();
void updateCursor();
int32 findRect();
uint32 checkFlags();
void startUpWater();
void checkConnections();
};
} // End of namespace Asylum
#endif // ASYLUM_PUZZLES_PIPES_H

View File

@@ -0,0 +1,121 @@
/* 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 "asylum/puzzles/puzzle.h"
#include "asylum/resources/polygons.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/asylum.h"
namespace Asylum {
Puzzle::Puzzle(AsylumEngine *engine): _vm(engine) {
}
void Puzzle::saveLoadWithSerializer(Common::Serializer &) {
// By default, we do not save any data
}
//////////////////////////////////////////////////////////////////////////
// Event Handling
//////////////////////////////////////////////////////////////////////////
bool Puzzle::handleEvent(const AsylumEvent &evt) {
switch ((int32)evt.type) {
default:
break;
case EVENT_ASYLUM_INIT:
return init(evt);
case EVENT_ASYLUM_ACTIVATE:
return activate(evt);
case EVENT_ASYLUM_UPDATE:
return update(evt);
case Common::EVENT_LBUTTONDOWN:
return mouseLeftDown(evt);
case Common::EVENT_LBUTTONUP:
return mouseLeftUp(evt);
case Common::EVENT_RBUTTONDOWN:
case Common::EVENT_CUSTOM_ENGINE_ACTION_START:
return exitPuzzle();
}
return false;
}
bool Puzzle::update(const AsylumEvent &evt) {
uint32 ticks = _vm->getTick();
updateCursor();
if (!getSharedData()->getFlag(kFlagRedraw)) {
updateScreen();
getSharedData()->setFlag(kFlagRedraw, true);
}
if (ticks > getSharedData()->getNextScreenUpdate()) {
if (getSharedData()->getFlag(kFlagRedraw)) {
if (!getScreen()->isGraphicQueueEmpty())
getScreen()->drawGraphicsInQueue();
getScreen()->copyBackBufferToScreen();
getSharedData()->setEventUpdate(getSharedData()->getEventUpdate() ^ 1);
getSharedData()->setFlag(kFlagRedraw, false);
getSharedData()->setNextScreenUpdate(ticks + 40);
}
}
return true;
}
//////////////////////////////////////////////////////////////////////////
// Hit test functions
//////////////////////////////////////////////////////////////////////////
bool Puzzle::hitTest(const int16 (*polygonPoint)[2], const Common::Point &point, uint32 index) const {
Common::Point p1(polygonPoint[index + 0][0], polygonPoint[index + 0][1]),
p2(polygonPoint[index + 1][0], polygonPoint[index + 1][1]),
p3(polygonPoint[index + 2][0], polygonPoint[index + 2][1]),
p4(polygonPoint[index + 3][0], polygonPoint[index + 3][1]);
Polygon polygon(p1, p2, p3, p4);
return polygon.contains(point);
}
bool Puzzle::hitTest(const int16 (*polygonPoint)[2], const Common::Point &point) const {
return hitTest(polygonPoint, point, 0);
}
} // end of namespace Asylum

View File

@@ -0,0 +1,76 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef ASYLUM_PUZZLES_PUZZLE_H
#define ASYLUM_PUZZLES_PUZZLE_H
#include "common/rect.h"
#include "common/serializer.h"
#include "asylum/eventhandler.h"
#include "asylum/shared.h"
namespace Asylum {
class AsylumEngine;
class Screen;
class Sound;
class VideoPlayer;
class Cursor;
class GraphicResource;
struct GraphicQueueItem;
class Puzzle : public EventHandler, public Common::Serializable {
public:
Puzzle(AsylumEngine *engine);
virtual ~Puzzle() {};
bool handleEvent(const AsylumEvent &evt);
// Serializable
virtual void saveLoadWithSerializer(Common::Serializer &s);
protected:
AsylumEngine *_vm;
//////////////////////////////////////////////////////////////////////////
// Event Handling
//////////////////////////////////////////////////////////////////////////
virtual bool init(const AsylumEvent &evt) = 0;
virtual bool update(const AsylumEvent &evt);
virtual void updateScreen() {};
virtual void updateCursor() {};
virtual bool activate(const AsylumEvent &evt) { return true; }
virtual bool mouseLeftUp(const AsylumEvent &evt) { return true; }
virtual bool mouseLeftDown(const AsylumEvent &evt) { return true; }
virtual bool exitPuzzle() = 0;
//////////////////////////////////////////////////////////////////////////
// Hit test functions
//////////////////////////////////////////////////////////////////////////
bool hitTest(const int16 (*polygonPoint)[2], const Common::Point &point, uint32 index) const;
bool hitTest(const int16 (*polygonPoint)[2], const Common::Point &point) const;
};
} // End of namespace Asylum
#endif // ASYLUM_PUZZLES_PUZZLE_H

View File

@@ -0,0 +1,109 @@
/* 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 "asylum/puzzles/puzzles.h"
#include "asylum/puzzles/boardkeyhidesto.h"
#include "asylum/puzzles/boardsalvation.h"
#include "asylum/puzzles/boardyouth.h"
#include "asylum/puzzles/clock.h"
#include "asylum/puzzles/fisherman.h"
#include "asylum/puzzles/hivecontrol.h"
#include "asylum/puzzles/hivemachine.h"
#include "asylum/puzzles/lock.h"
#include "asylum/puzzles/morguedoor.h"
#include "asylum/puzzles/pipes.h"
#include "asylum/puzzles/tictactoe.h"
#include "asylum/puzzles/timemachine.h"
#include "asylum/puzzles/vcr.h"
#include "asylum/puzzles/wheel.h"
#include "asylum/puzzles/writings.h"
#include "asylum/asylum.h"
namespace Asylum {
Puzzles::Puzzles(AsylumEngine *engine) : _vm(engine) {
memset(&_puzzles, 0, sizeof(_puzzles));
}
Puzzles::~Puzzles() {
// Cleanup puzzles
for (uint i = 0; i < ARRAYSIZE(_puzzles); i++)
delete _puzzles[i];
}
void Puzzles::reset() {
for (uint i = 0; i < ARRAYSIZE(_puzzles); i++)
delete _puzzles[i];
initPuzzles();
}
EventHandler *Puzzles::getPuzzle(uint32 index) const {
if (index >= ARRAYSIZE(_puzzles))
error("[AsylumEngine::getPuzzleEventHandler] Invalid index (was: %d - max: %d)", index, ARRAYSIZE(_puzzles));
if (_puzzles[index] == nullptr)
error("[AsylumEngine::getPuzzleEventHandler] This puzzle doesn't have an event handler! (index: %d)", index);
return (EventHandler *)_puzzles[index];
}
void Puzzles::initPuzzles() {
_puzzles[kPuzzleVCR] = new PuzzleVCR(_vm);
_puzzles[kPuzzlePipes] = new PuzzlePipes(_vm);
_puzzles[kPuzzleTicTacToe] = new PuzzleTicTacToe(_vm);
_puzzles[kPuzzleLock] = new PuzzleLock(_vm);
_puzzles[kPuzzle4] = nullptr; // No event handler for Puzzle 5
_puzzles[kPuzzleWheel] = new PuzzleWheel(_vm);
_puzzles[kPuzzleBoardSalvation] = new PuzzleBoardSalvation(_vm);
_puzzles[kPuzzleBoardYouth] = new PuzzleBoardYouth(_vm);
_puzzles[kPuzzleBoardKeyHidesTo] = new PuzzleBoardKeyHidesTo(_vm);
_puzzles[kPuzzleWritings] = new PuzzleWritings(_vm);
_puzzles[kPuzzle11] = nullptr;
_puzzles[kPuzzleMorgueDoor] = new PuzzleMorgueDoor(_vm);
_puzzles[kPuzzleClock] = new PuzzleClock(_vm);
_puzzles[kPuzzleTimeMachine] = new PuzzleTimeMachine(_vm);
_puzzles[kPuzzleFisherman] = new PuzzleFisherman(_vm);
_puzzles[kPuzzleHiveMachine] = new PuzzleHiveMachine(_vm);
_puzzles[kPuzzleHiveControl] = new PuzzleHiveControl(_vm);
}
void Puzzles::saveLoadWithSerializer(Common::Serializer &s) {
_puzzles[kPuzzleVCR]->saveLoadWithSerializer(s);
s.skip(4);
_puzzles[kPuzzleLock]->saveLoadWithSerializer(s);
_puzzles[kPuzzlePipes]->saveLoadWithSerializer(s);
_puzzles[kPuzzleWheel]->saveLoadWithSerializer(s);
_puzzles[kPuzzleBoardSalvation]->saveLoadWithSerializer(s);
_puzzles[kPuzzleBoardYouth]->saveLoadWithSerializer(s);
s.skip(8);
_puzzles[kPuzzleBoardKeyHidesTo]->saveLoadWithSerializer(s);
_puzzles[kPuzzleMorgueDoor]->saveLoadWithSerializer(s);
s.skip(80); // skip Puzzle 11
_puzzles[kPuzzleTimeMachine]->saveLoadWithSerializer(s);
_puzzles[kPuzzleClock]->saveLoadWithSerializer(s);
_puzzles[kPuzzleFisherman]->saveLoadWithSerializer(s);
_puzzles[kPuzzleHiveControl]->saveLoadWithSerializer(s);
}
} // End of namespace Asylum

View File

@@ -0,0 +1,72 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef ASYLUM_PUZZLES_PUZZLES_H
#define ASYLUM_PUZZLES_PUZZLES_H
#include "common/serializer.h"
#include "asylum/shared.h"
namespace Asylum {
class AsylumEngine;
class EventHandler;
class Puzzle;
class Puzzles : public Common::Serializable {
public:
Puzzles(AsylumEngine *engine);
~Puzzles();
/**
* Resets puzzles
*/
void reset();
/**
* Gets a message handler.
*
* @param index Zero-based index of the message handler
*
* @return The message handler.
*/
EventHandler *getPuzzle(uint32 index) const;
// Serializable
void saveLoadWithSerializer(Common::Serializer &s);
private:
AsylumEngine *_vm;
Puzzle *_puzzles[17];
/**
* Initializes the puzzles
*/
void initPuzzles();
// Debug
friend class Console;
};
} // End of namespace Asylum
#endif // ASYLUM_PUZZLES_PUZZLES_H

View File

@@ -0,0 +1,581 @@
/* 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 "asylum/puzzles/tictactoe.h"
#include "asylum/resources/worldstats.h"
#include "asylum/system/cursor.h"
#include "asylum/system/screen.h"
#include "asylum/views/scene.h"
#include "asylum/asylum.h"
namespace Asylum {
extern int g_debugPolygons;
const int16 puzzleTicTacToePolygons[36][2] = {
{ 27, 381}, {172, 368}, {190, 474}, { 36, 476},
{176, 362}, {294, 328}, {331, 456}, {191, 472},
{304, 327}, {426, 306}, {457, 440}, {340, 460},
{ 26, 257}, {151, 238}, {169, 356}, { 27, 373},
{162, 234}, {275, 214}, {299, 321}, {173, 355},
{283, 210}, {403, 173}, {437, 294}, {305, 317},
{ 22, 120}, {132, 126}, {146, 223}, { 25, 247},
{144, 119}, {247, 87}, {268, 205}, {159, 222},
{259, 84}, {380, 73}, {405, 169}, {281, 201}
};
const int16 puzzleTicTacToePositions[9][2] = {
{ 62, 367}, {193, 343}, {329, 319},
{ 38, 247}, {167, 217}, {296, 193},
{ 19, 121}, {147, 98}, {269, 70}
};
static const struct {
uint32 field1;
uint32 field2;
uint32 field3;
uint32 winLineX;
uint32 winLineO;
uint32 frameCount;
} puzzleTicTacToeFieldsToCheck[8] = {
{0, 1, 2, 1, 9, 14},
{3, 4, 5, 2, 10, 14},
{6, 7, 8, 3, 11, 14},
{0, 3, 6, 4, 12, 10},
{8, 5, 2, 6, 14, 10},
{0, 4, 8, 8, 16, 4},
{4, 1, 7, 5, 13, 10},
{4, 6, 2, 7, 15, 4}
};
PuzzleTicTacToe::PuzzleTicTacToe(AsylumEngine *engine) : Puzzle(engine) {
_ticker = 0;
_frameIndex = 0;
_frameCount = 0;
_currentPos = 0;
_gameOver = false;
_winLine = 0;
// Field
memset(&_board, 0, sizeof(_board));
memset(&_moveList, 0, sizeof(_moveList));
_numberOfPossibleMoves = 0;
_solveDelay = 0;
_brokenLines = 0;
}
PuzzleTicTacToe::~PuzzleTicTacToe() {
}
//////////////////////////////////////////////////////////////////////////
// Event Handling
//////////////////////////////////////////////////////////////////////////
bool PuzzleTicTacToe::init(const AsylumEvent &) {
_ticker = 0;
_vm->clearGameFlag(kGameFlag114);
_vm->clearGameFlag(kGameFlag215);
_frameIndex = 0;
_currentPos = -1;
_gameOver = false;
_winLine = -1;
getScreen()->setPalette(getWorld()->graphicResourceIds[3]);
getScreen()->setGammaLevel(getWorld()->graphicResourceIds[3]);
getCursor()->show();
getCursor()->set(getWorld()->graphicResourceIds[12], 4, kCursorAnimationLinear, 4);
clearBoard();
return true;
}
void PuzzleTicTacToe::updateScreen() {
if (_ticker) {
++_ticker;
if (_ticker <= 25) {
if (_ticker > 20) {
if (computerThinks())
computerMoves();
_ticker = 0;
}
} else {
if (_ticker > 40) {
getSound()->playSound(getWorld()->soundResourceIds[13], false, Config.sfxVolume - 100);
_ticker = 0;
}
}
}
getScreen()->draw(getWorld()->graphicResourceIds[0]);
drawField();
getScene()->updateAmbientSounds();
}
bool PuzzleTicTacToe::mouseLeftDown(const AsylumEvent &evt) {
if (!_vm->isGameFlagNotSet(kGameFlag215) || !_vm->isGameFlagNotSet(kGameFlag114)) {
getCursor()->show();
exitPuzzle();
return true;
}
if (_gameOver) {
_gameOver = false;
_frameIndex = 0;
_currentPos = -1;
_winLine = -1;
clearBoard();
return true;
}
for (uint32 i = 0; i < ARRAYSIZE(_board); i++) {
if (hitTest(&puzzleTicTacToePolygons[i * 4], evt.mouse, 0)) {
if (_board[i] == ' ') {
getSound()->playSound(getWorld()->soundResourceIds[11], false, Config.sfxVolume - 100);
_board[i] = 'X';
_currentPos = i;
_frameIndex = 0;
getCursor()->hide();
}
}
}
return true;
}
bool PuzzleTicTacToe::exitPuzzle() {
getScreen()->clear();
_vm->switchEventHandler(getScene());
return true;
}
//////////////////////////////////////////////////////////////////////////
// Init & update
//////////////////////////////////////////////////////////////////////////
void PuzzleTicTacToe::clearBoard() {
_brokenLines = 0;
memset(&_board, ' ', sizeof(_board));
}
void PuzzleTicTacToe::drawField() {
if (_solveDelay > 0) {
--_solveDelay;
if (_solveDelay < 2) {
getCursor()->show();
exitPuzzle();
_solveDelay = 0;
return;
}
}
if (g_debugPolygons) {
for (uint32 p = 0; p < ARRAYSIZE(puzzleTicTacToePolygons) - 4; p += 4) {
getScreen()->drawLine(&puzzleTicTacToePolygons[p], &puzzleTicTacToePolygons[p + 1]);
getScreen()->drawLine(&puzzleTicTacToePolygons[p + 1], &puzzleTicTacToePolygons[p + 2]);
getScreen()->drawLine(&puzzleTicTacToePolygons[p + 2], &puzzleTicTacToePolygons[p + 3]);
getScreen()->drawLine(&puzzleTicTacToePolygons[p + 3], &puzzleTicTacToePolygons[p]);
}
}
// Draw X & O
for (int32 i = 0; i < ARRAYSIZE(puzzleTicTacToePositions); i++) {
char mark = _board[i];
Common::Point point = Common::Point(puzzleTicTacToePositions[i][0], puzzleTicTacToePositions[i][1]);
if (_currentPos == i) {
if (mark == 'O')
getScreen()->draw(getWorld()->graphicResourceIds[2], _frameIndex, point);
else if (mark == 'X')
getScreen()->draw(getWorld()->graphicResourceIds[1], _frameIndex, point);
// Update _frameIndex
++_frameIndex;
if (_frameIndex > 14 && mark == 'X') {
_currentPos = -1;
_frameIndex = 0;
_ticker = 1;
if (checkWin())
_gameOver = true;
}
if (_frameIndex > 12 && mark == 'O') {
_currentPos = -1;
_frameIndex = 0;
if (!checkWin() || !lookForAWinner())
getCursor()->show();
}
} else {
if (mark == 'O')
getScreen()->draw(getWorld()->graphicResourceIds[2], 12, point);
else if (mark == 'X')
getScreen()->draw(getWorld()->graphicResourceIds[1], 14, point);
}
}
if (_currentPos == -1 && checkWin())
_gameOver = true;
// Draw win line
if (_winLine > 0 && !_ticker) {
switch (_winLine) {
default:
break;
case 1:
getScreen()->draw(getWorld()->graphicResourceIds[5], _frameIndex, Common::Point(38, 345));
break;
case 2:
getScreen()->draw(getWorld()->graphicResourceIds[5], _frameIndex, Common::Point(17, 226));
break;
case 3:
getScreen()->draw(getWorld()->graphicResourceIds[5], _frameIndex, Common::Point(1, 104));
break;
case 4:
getScreen()->draw(getWorld()->graphicResourceIds[6], _frameIndex, Common::Point(43, 117));
break;
case 5:
getScreen()->draw(getWorld()->graphicResourceIds[6], _frameIndex, Common::Point(176, 104));
break;
case 6:
getScreen()->draw(getWorld()->graphicResourceIds[6], _frameIndex, Common::Point(299, 85));
break;
case 7:
if (_brokenLines == 0)
getScreen()->draw(getWorld()->graphicResourceIds[8], _frameIndex, Common::Point(30, 149));
else if (_brokenLines == 1)
getScreen()->draw(getWorld()->graphicResourceIds[8], _frameIndex, Common::Point(180, 249));
else {
getScreen()->draw(getWorld()->graphicResourceIds[8], 6, Common::Point(30, 149));
getScreen()->draw(getWorld()->graphicResourceIds[8], 6, Common::Point(180, 249));
getScreen()->draw(getWorld()->graphicResourceIds[8], _frameIndex, Common::Point(330, 349));
}
break;
case 8:
if (_brokenLines == 0)
getScreen()->draw(getWorld()->graphicResourceIds[10], _frameIndex, Common::Point(69, 66));
else if (_brokenLines == 1)
getScreen()->draw(getWorld()->graphicResourceIds[10], _frameIndex, Common::Point(-22, 220));
else {
getScreen()->draw(getWorld()->graphicResourceIds[10], 6, Common::Point( 69, 66));
getScreen()->draw(getWorld()->graphicResourceIds[10], 6, Common::Point(-22, 220));
getScreen()->draw(getWorld()->graphicResourceIds[10], _frameIndex, Common::Point(-110, 370));
}
break;
case 9:
getScreen()->draw(getWorld()->graphicResourceIds[4], _frameIndex, Common::Point(38, 345));
break;
case 10:
getScreen()->draw(getWorld()->graphicResourceIds[4], _frameIndex, Common::Point(17, 226));
break;
case 11:
getScreen()->draw(getWorld()->graphicResourceIds[4], _frameIndex, Common::Point(1, 104));
break;
case 12:
getScreen()->draw(getWorld()->graphicResourceIds[11], _frameIndex, Common::Point(43, 117));
break;
case 13:
getScreen()->draw(getWorld()->graphicResourceIds[11], _frameIndex, Common::Point(176, 104));
break;
case 14:
getScreen()->draw(getWorld()->graphicResourceIds[11], _frameIndex, Common::Point(299, 85));
break;
case 15:
if (_brokenLines == 0)
getScreen()->draw(getWorld()->graphicResourceIds[7], _frameIndex, Common::Point(30, 149));
else if (_brokenLines == 1)
getScreen()->draw(getWorld()->graphicResourceIds[7], _frameIndex, Common::Point(180, 249));
else {
getScreen()->draw(getWorld()->graphicResourceIds[7], 6, Common::Point(30, 149));
getScreen()->draw(getWorld()->graphicResourceIds[7], 6, Common::Point(180, 249));
getScreen()->draw(getWorld()->graphicResourceIds[7], _frameIndex, Common::Point(330, 349));
}
break;
case 16:
if (_brokenLines == 0)
getScreen()->draw(getWorld()->graphicResourceIds[9], _frameIndex, Common::Point(69, 66));
else if (_brokenLines == 1)
getScreen()->draw(getWorld()->graphicResourceIds[9], _frameIndex, Common::Point(-22, 220));
else {
getScreen()->draw(getWorld()->graphicResourceIds[9], 6, Common::Point(69, 66));
getScreen()->draw(getWorld()->graphicResourceIds[9], 6, Common::Point(-22, 220));
getScreen()->draw(getWorld()->graphicResourceIds[9], _frameIndex, Common::Point(-110, 370));
}
break;
}
if (_frameIndex >= _frameCount) {
if (_winLine == 7 || _winLine == 8 || _winLine == 15 || _winLine == 16) {
if (_brokenLines < 2) {
_frameIndex = 0;
++_brokenLines;
}
}
} else {
++_frameIndex;
}
if (!_solveDelay)
_solveDelay = 30;
}
getScreen()->draw(getWorld()->graphicResourceIds[17], 0, Common::Point(0, 0));
}
void PuzzleTicTacToe::getTwoEmpty(uint32 field1, uint32 field2, uint32 field3) {
if (_board[field1] != ' ') {
_moveList[_numberOfPossibleMoves] = field3;
_moveList[_numberOfPossibleMoves + 1] = field2;
_numberOfPossibleMoves += 2;
}
if (_board[field3] != ' ') {
_moveList[_numberOfPossibleMoves] = field1;
_moveList[_numberOfPossibleMoves + 1] = field2;
_numberOfPossibleMoves += 2;
}
if (_board[field2] != ' ') {
_moveList[_numberOfPossibleMoves] = field3;
_moveList[_numberOfPossibleMoves + 1] = field1;
_numberOfPossibleMoves += 2;
}
}
//////////////////////////////////////////////////////////////////////////
// Game
//////////////////////////////////////////////////////////////////////////
bool PuzzleTicTacToe::computerThinks() {
if (_gameOver)
return false;
if (!tryToWin()
&& !tryNotToLose()
&& !expandLine()
&& !tryNewLine()
&& !arbitraryPlacement()) {
if (!_solveDelay)
getCursor()->show();
_gameOver = true;
return false;
}
return true;
}
PuzzleTicTacToe::GameStatus PuzzleTicTacToe::returnLineData(uint32 field1, uint32 field2, uint32 field3, char mark, uint32 *counterX, uint32 *counterO) const {
*counterX = 0;
*counterO = 0;
GameStatus status = kStatus0;
if (_board[field1] == 'X')
++*counterX;
if (_board[field2] == 'X')
++*counterX;
if (_board[field3] == 'X')
++*counterX;
if (_board[field1] == 'O')
++*counterO;
if (_board[field2] == 'O')
++*counterO;
if (_board[field3] == 'O')
++*counterO;
if (mark == 'O') {
if (*counterO == 1 && !*counterX)
status = kStatusFree;
} else if (mark == 'X') {
if (!*counterO && *counterX == 1)
status = kStatusFree;
}
if (mark == 'O') {
if (!*counterO && *counterX == 2)
status = kStatusNeedBlocking;
} else if (mark == 'X') {
if (*counterO == 2 && !*counterX)
status = kStatusNeedBlocking;
}
return status;
}
bool PuzzleTicTacToe::expandLine() {
uint32 counterX = 0;
uint32 counterO = 0;
for (uint32 i = 0; i < ARRAYSIZE(puzzleTicTacToeFieldsToCheck); i++)
if (returnLineData(puzzleTicTacToeFieldsToCheck[i].field1, puzzleTicTacToeFieldsToCheck[i].field2, puzzleTicTacToeFieldsToCheck[i].field3, 'O', &counterX, &counterO) == kStatusFree)
getTwoEmpty(puzzleTicTacToeFieldsToCheck[i].field1, puzzleTicTacToeFieldsToCheck[i].field2, puzzleTicTacToeFieldsToCheck[i].field3);
return (_numberOfPossibleMoves != 0);
}
bool PuzzleTicTacToe::tryNewLine() {
uint32 counterX = 0;
uint32 counterO = 0;
for (uint32 i = 0; i < ARRAYSIZE(puzzleTicTacToeFieldsToCheck); i++) {
returnLineData(puzzleTicTacToeFieldsToCheck[i].field1, puzzleTicTacToeFieldsToCheck[i].field2, puzzleTicTacToeFieldsToCheck[i].field3, 'O', &counterX, &counterO);
if (counterX || counterO)
continue;
_moveList[_numberOfPossibleMoves] = puzzleTicTacToeFieldsToCheck[i].field1;
_moveList[_numberOfPossibleMoves + 1] = puzzleTicTacToeFieldsToCheck[i].field2;
_moveList[_numberOfPossibleMoves + 2] = puzzleTicTacToeFieldsToCheck[i].field3;
_numberOfPossibleMoves += 3;
}
return (_numberOfPossibleMoves != 0);
}
uint32 PuzzleTicTacToe::returnEmptySlot(uint32 position1, uint32 position2, uint position3) const {
if (_board[position1] == ' ')
return position1;
if (_board[position2] == ' ')
return position2;
return position3;
}
bool PuzzleTicTacToe::checkWin() {
if (_gameOver)
return true;
if (lookForAWinner() == 1) {
_vm->setGameFlag(kGameFlag114);
_ticker = 30;
return true;
}
if (lookForAWinner() == -1) {
_vm->setGameFlag(kGameFlag215);
_ticker = 30;
return true;
}
return false;
}
int32 PuzzleTicTacToe::lookForAWinner() {
uint32 counterX = 0;
uint32 counterO = 0;
for (uint32 i = 0; i < ARRAYSIZE(puzzleTicTacToeFieldsToCheck); i++) {
returnLineData(puzzleTicTacToeFieldsToCheck[i].field1, puzzleTicTacToeFieldsToCheck[i].field2, puzzleTicTacToeFieldsToCheck[i].field3, 'O', &counterX, &counterO);
if (counterX == 3) {
_winLine = puzzleTicTacToeFieldsToCheck[i].winLineX;
_frameCount = puzzleTicTacToeFieldsToCheck[i].frameCount;
_frameIndex = 0;
return 1;
}
if (counterO == 3) {
_winLine = puzzleTicTacToeFieldsToCheck[i].winLineO;
_frameCount = puzzleTicTacToeFieldsToCheck[i].frameCount;
_frameIndex = 0;
return -1;
}
}
return 0;
}
bool PuzzleTicTacToe::strategy(char mark) {
uint32 counterX = 0;
uint32 counterO = 0;
_numberOfPossibleMoves = 0;
for (uint32 i = 0; i < ARRAYSIZE(puzzleTicTacToeFieldsToCheck); i++) {
if (returnLineData(puzzleTicTacToeFieldsToCheck[i].field1, puzzleTicTacToeFieldsToCheck[i].field2, puzzleTicTacToeFieldsToCheck[i].field3, mark, &counterX, &counterO) == kStatusNeedBlocking) {
_moveList[_numberOfPossibleMoves] = returnEmptySlot(puzzleTicTacToeFieldsToCheck[i].field1, puzzleTicTacToeFieldsToCheck[i].field2, puzzleTicTacToeFieldsToCheck[i].field3);
++_numberOfPossibleMoves;
}
}
return (_numberOfPossibleMoves != 0);
}
bool PuzzleTicTacToe::arbitraryPlacement() {
_numberOfPossibleMoves = 0;
for (uint32 i = 0; i < ARRAYSIZE(_board); i++) {
if (_board[i] == ' ') {
_moveList[_numberOfPossibleMoves] = i;
++_numberOfPossibleMoves;
}
}
return (_numberOfPossibleMoves != 0);
}
void PuzzleTicTacToe::computerMoves() {
_frameIndex = 0;
_currentPos = _moveList[rnd(_numberOfPossibleMoves)];
if (_board[_currentPos] != ' ')
error("[PuzzleTicTacToe::computerMoves] Field is already occupied (%d)!", _currentPos);
_board[_currentPos] = 'O';
getSound()->playSound(getWorld()->soundResourceIds[12], false, Config.sfxVolume - 100);
}
} // End of namespace Asylum

View File

@@ -0,0 +1,91 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef ASYLUM_PUZZLES_TICTACTOE_H
#define ASYLUM_PUZZLES_TICTACTOE_H
#include "asylum/puzzles/puzzle.h"
namespace Asylum {
class AsylumEngine;
class PuzzleTicTacToe : public Puzzle {
public:
PuzzleTicTacToe(AsylumEngine *engine);
~PuzzleTicTacToe();
private:
enum GameStatus {
kStatus0,
kStatusFree,
kStatusNeedBlocking
};
uint32 _ticker;
uint32 _frameIndex;
uint32 _frameCount;
int32 _currentPos;
bool _gameOver;
int32 _winLine;
uint32 _solveDelay;
uint32 _brokenLines;
char _board[9];
uint32 _moveList[40];
uint32 _numberOfPossibleMoves;
//////////////////////////////////////////////////////////////////////////
// Event Handling
//////////////////////////////////////////////////////////////////////////
bool init(const AsylumEvent &evt);
void updateScreen();
bool mouseLeftDown(const AsylumEvent &evt);
bool exitPuzzle();
//////////////////////////////////////////////////////////////////////////
// Init & update
//////////////////////////////////////////////////////////////////////////
void clearBoard();
void drawField();
void getTwoEmpty(uint32 field1, uint32 field2, uint32 field3);
//////////////////////////////////////////////////////////////////////////
// Game
//////////////////////////////////////////////////////////////////////////
bool computerThinks();
GameStatus returnLineData(uint32 field1, uint32 field2, uint32 field3, char mark, uint32 *counterX, uint32 *counterO) const;
bool expandLine();
bool tryNewLine();
uint32 returnEmptySlot(uint32 position1, uint32 position2, uint position3) const;
bool checkWin();
int32 lookForAWinner();
bool strategy(char mark);
bool tryToWin() { return strategy('X'); }
bool tryNotToLose() { return strategy('O'); }
bool arbitraryPlacement();
void computerMoves();
};
} // End of namespace Asylum
#endif // ASYLUM_PUZZLES_TICTACTOE_H

View File

@@ -0,0 +1,260 @@
/* 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 "asylum/puzzles/timemachine.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/asylum.h"
namespace Asylum {
const int16 puzzleTimeMachineRects[10][4] = {
{ 0, 241, 20, 276}, { 0, 285, 20, 320},
{117, 245, 137, 280}, {117, 284, 137, 319},
{236, 246, 256, 281}, {236, 290, 256, 325},
{356, 245, 376, 280}, {356, 287, 376, 322},
{476, 248, 496, 283}, {475, 290, 495, 325}
};
const int16 puzzleTimeMachinePoints[5][2] = {
{-65, -30}, {-20, -68}, { 25, -106}, { 70, -144}, {115, -182}
};
PuzzleTimeMachine::PuzzleTimeMachine(AsylumEngine *engine) : Puzzle(engine) {
_leftButtonClicked = true;
_counter = 0;
memset(&_frameIndexes, 0, sizeof(_frameIndexes));
memset(&_frameCounts, 0, sizeof(_frameCounts));
memset(&_frameIncrements, 0, sizeof(_frameIncrements));
memset(&_state, 0, sizeof(_state));
_data_45AAA8 = _data_45AAAC = 0;
_currentFrameIndex = 0;
reset();
}
PuzzleTimeMachine::~PuzzleTimeMachine() {
}
void PuzzleTimeMachine::saveLoadWithSerializer(Common::Serializer &s) {
s.syncAsSint32LE(_frameIndexes[0]);
s.syncAsSint32LE(_frameIndexes[1]);
s.syncAsSint32LE(_frameIndexes[2]);
s.syncAsSint32LE(_frameIndexes[3]);
s.syncAsSint32LE(_frameIndexes[4]);
s.skip(4); // Unused
s.syncBytes((byte *)&_state, sizeof(_state));
s.skip(3); // We only use 5 elements i the state array
s.skip(5 * 4 * 2); // The original saves 4 points that are static data
s.syncAsSint32LE(_point.x);
s.syncAsSint32LE(_point.y);
for (int i = 0; i < 5; i++)
s.syncAsSint32LE(_frameIncrements[i]);
s.syncAsSint32LE(_currentFrameIndex);
s.syncAsSint32LE(_data_45AAA8);
s.syncAsSint32LE(_data_45AAAC);
s.syncAsSint32LE(_frameIndexes[5]);
}
void PuzzleTimeMachine::reset() {
_frameIndexes[0] = 0;
_frameIndexes[1] = 4;
_frameIndexes[2] = 20;
_frameIndexes[3] = 16;
_frameIndexes[4] = 20;
_index = -1;
_index2 = 0;
_point.x = _newPoint.x = puzzleTimeMachinePoints[0][0];
_point.y = _newPoint.y = puzzleTimeMachinePoints[0][1];
}
//////////////////////////////////////////////////////////////////////////
// Event Handling
//////////////////////////////////////////////////////////////////////////
bool PuzzleTimeMachine::init(const AsylumEvent &evt) {
getCursor()->set(getWorld()->graphicResourceIds[62], -1, kCursorAnimationMirror, 7);
_frameCounts[0] = GraphicResource::getFrameCount(_vm, getWorld()->graphicResourceIds[35]);
_frameCounts[1] = GraphicResource::getFrameCount(_vm, getWorld()->graphicResourceIds[36]);
_frameCounts[2] = GraphicResource::getFrameCount(_vm, getWorld()->graphicResourceIds[37]);
_frameCounts[3] = GraphicResource::getFrameCount(_vm, getWorld()->graphicResourceIds[38]);
_frameCounts[4] = GraphicResource::getFrameCount(_vm, getWorld()->graphicResourceIds[39]);
_frameCounts[5] = GraphicResource::getFrameCount(_vm, getWorld()->graphicResourceIds[40]);
getScreen()->setPalette(getWorld()->graphicResourceIds[41]);
getScreen()->setGammaLevel(getWorld()->graphicResourceIds[41]);
return true;
}
void PuzzleTimeMachine::updateScreen() {
// Draw screen elements
getScreen()->clearGraphicsInQueue();
getScreen()->fillRect(0, 0, 640, 480, 115);
getScreen()->draw(getWorld()->graphicResourceIds[34], 0, Common::Point(0, 0), kDrawFlagNone, true);
getScreen()->addGraphicToQueue(getWorld()->graphicResourceIds[35], _frameIndexes[0], Common::Point( 23, 215), kDrawFlagNone, 0, 3);
getScreen()->addGraphicToQueue(getWorld()->graphicResourceIds[36], _frameIndexes[1], Common::Point( 70, 217), kDrawFlagNone, 0, 3);
getScreen()->addGraphicToQueue(getWorld()->graphicResourceIds[37], _frameIndexes[2], Common::Point(189, 217), kDrawFlagNone, 0, 3);
getScreen()->addGraphicToQueue(getWorld()->graphicResourceIds[38], _frameIndexes[3], Common::Point(309, 218), kDrawFlagNone, 0, 3);
getScreen()->addGraphicToQueue(getWorld()->graphicResourceIds[39], _frameIndexes[4], Common::Point(429, 212), kDrawFlagNone, 0, 3);
getScreen()->addGraphicToQueue(getWorld()->graphicResourceIds[40], _frameIndexes[5], _point, kDrawFlagNone, 0, 1);
if (_point.x < _newPoint.x)
_point += Common::Point(15, -12 - (abs((double)(_point.x - _newPoint.x)) > 15 ? 1 : 0));
else if (_point.x > _newPoint.x)
_point -= Common::Point(15, -12 - (abs((double)(_point.x - _newPoint.x)) > 15 ? 1 : 0));
if (_frameIndexes[0] != 28 || _frameIndexes[1] || _frameIndexes[2] || _frameIndexes[3] || _frameIndexes[4]) {
getScreen()->addGraphicToQueue(getWorld()->graphicResourceIds[43], 0, Common::Point(599, 220), kDrawFlagNone, 0, 2);
} else {
getSound()->stop(getWorld()->soundResourceIds[17]);
getSound()->stop(getWorld()->soundResourceIds[16]);
if (_vm->isGameFlagNotSet(kGameFlag925))
getSound()->playSound(getWorld()->soundResourceIds[18]);
_vm->setGameFlag(kGameFlag925);
++_counter;
}
//////////////////////////////////////////////////////////////////////////
// Show all buttons
for (uint32 i = 0; i < ARRAYSIZE(puzzleTimeMachineRects); i += 2) {
if ((uint32)_index != i || _leftButtonClicked)
getScreen()->addGraphicToQueue(getWorld()->graphicResourceIds[44 + i], 0, Common::Point(puzzleTimeMachineRects[i][0], puzzleTimeMachineRects[i][1]), kDrawFlagNone, 0, 5);
}
for (uint32 i = 1; i < ARRAYSIZE(puzzleTimeMachineRects); i += 2) {
if ((uint32)_index != i || _leftButtonClicked)
getScreen()->addGraphicToQueue(getWorld()->graphicResourceIds[44 + i], 0, Common::Point(puzzleTimeMachineRects[i][0], puzzleTimeMachineRects[i][1]), kDrawFlagNone, 0, 5);
}
_leftButtonClicked = true;
// Check for puzzle completion
if (_counter > 30 && _vm->isGameFlagSet(kGameFlag925)) {
getCursor()->hide();
getSharedData()->setFlag(kFlag1, true);
getScreen()->stopPaletteFade(0, 0, 0);
_vm->switchEventHandler(getScene());
}
// Update frame indexes & increments
if (_index != -1) {
_frameIndexes[_index / 2] += _frameIncrements[_index / 2];
if (_frameIndexes[_index / 2] < 0) {
_frameIndexes[_index / 2] = _frameCounts[_index / 2] - 1;
} else if (_frameIndexes[_index / 2] > (int32)_frameCounts[_index / 2] - 1) {
_frameIndexes[_index / 2] = 0;
_frameIncrements[_index / 2] = 0;
} else if (!(_frameIndexes[_index / 2] % 4)) {
getSound()->playSound(getWorld()->soundResourceIds[15]);
_frameIncrements[_index / 2] = 0;
_index = -1;
}
_frameIndexes[5] = (_frameIndexes[5] + 1) % _frameCounts[5];
}
}
bool PuzzleTimeMachine::mouseLeftDown(const AsylumEvent &evt) {
if (_vm->isGameFlagSet(kGameFlag925))
return true;
_leftButtonClicked = false;
int32 index = -1;
for (uint32 i = 0; i < ARRAYSIZE(puzzleTimeMachineRects); i++) {
if (_vm->rectContains(&puzzleTimeMachineRects[i], evt.mouse)) {
index = i;
break;
}
}
if (index == -1)
return true;
getSound()->playSound(getWorld()->soundResourceIds[14]);
if ((_index2 / 2) != (uint32)index / 2) {
getSound()->playSound(getWorld()->soundResourceIds[16]);
_newPoint.x = puzzleTimeMachinePoints[index / 2][0];
_newPoint.y = puzzleTimeMachinePoints[index / 2][1];
}
if (index % 2)
_frameIncrements[index / 2] = 1;
else
_frameIncrements[index / 2] = -1;
_index = _index2 = index;
return true;
}
bool PuzzleTimeMachine::exitPuzzle() {
getCursor()->hide();
getSharedData()->setFlag(kFlag1, true);
getScreen()->stopPaletteFade(0, 0, 0);
_vm->switchEventHandler(getScene());
return true;
}
//////////////////////////////////////////////////////////////////////////
// Helpers
//////////////////////////////////////////////////////////////////////////
void PuzzleTimeMachine::updateCursor() {
for (uint32 i = 0; i < ARRAYSIZE(puzzleTimeMachineRects); i++) {
if (_vm->rectContains(&puzzleTimeMachineRects[i], getCursor()->position())) {
if (getCursor()->getAnimation() != kCursorAnimationMirror)
getCursor()->set(getWorld()->graphicResourceIds[62], -1, kCursorAnimationMirror, 7);
return;
}
}
if (getCursor()->getAnimation())
getCursor()->set(getWorld()->graphicResourceIds[62], -1, kCursorAnimationNone, 7);
}
} // End of namespace Asylum

View File

@@ -0,0 +1,75 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef ASYLUM_PUZZLES_TIMEMACHINE_H
#define ASYLUM_PUZZLES_TIMEMACHINE_H
#include "asylum/puzzles/puzzle.h"
namespace Asylum {
class AsylumEngine;
class PuzzleTimeMachine : public Puzzle {
public:
PuzzleTimeMachine(AsylumEngine *engine);
~PuzzleTimeMachine();
// Serializable
virtual void saveLoadWithSerializer(Common::Serializer &s);
private:
bool _leftButtonClicked;
uint32 _counter;
int32 _frameIndexes[6];
uint32 _frameCounts[6];
int32 _frameIncrements[5];
int32 _index;
uint32 _index2;
Common::Point _point;
Common::Point _newPoint;
// Unused puzzle variables
int8 _state[5];
//bool _data_4572BC;
//bool _data_4572CC;
uint32 _data_45AAA8;
uint32 _data_45AAAC;
uint32 _currentFrameIndex;
//////////////////////////////////////////////////////////////////////////
// Event Handling
//////////////////////////////////////////////////////////////////////////
bool init(const AsylumEvent &evt);
void updateScreen();
bool mouseLeftDown(const AsylumEvent &evt);
bool exitPuzzle();
//////////////////////////////////////////////////////////////////////////
// Helpers
//////////////////////////////////////////////////////////////////////////
void updateCursor();
void reset();
};
} // End of namespace Asylum
#endif // ASYLUM_PUZZLES_TIMEMACHINE_H

View File

@@ -0,0 +1,596 @@
/* 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 "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

View File

@@ -0,0 +1,146 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef ASYLUM_PUZZLES_VCR_H
#define ASYLUM_PUZZLES_VCR_H
#include "asylum/puzzles/puzzle.h"
#include "asylum/shared.h"
namespace Asylum {
class AsylumEngine;
typedef struct VCRDrawInfo {
int32 resourceId;
Common::Point point;
} VCRDrawInfo;
const int16 puzzleVCRPolygons[10][4] = {
{0x0F7, 0x157, 0x13A, 0x183}, // rewind button region
{0x14B, 0x15C, 0x17B, 0x18B}, // stop button region
{0x18C, 0x161, 0x1D2, 0x18F}, // play button region
{0x1FB, 0x156, 0x233, 0x185}, // rec button region
{0x154, 0x196, 0x173, 0x1AF}, // red jack hole region
{0x19A, 0x19B, 0x1B9, 0x1B3}, // yellow jack hole region
{0x1E3, 0x1A0, 0x202, 0x1BC}, // black jack hole region
{0x0, 0x19B, 0x3C, 0x1E0}, // black jack on table region
{0x4C, 0x1AC, 0x0A0, 0x1E0}, // red jack on table region
{0x0BB, 0x1B7, 0x0F0, 0x1E0} // yellow jack on table region
};
//////////////////////////////////////////////////////////////////////////
// Puzzle 1
//////////////////////////////////////////////////////////////////////////
class PuzzleVCR : public Puzzle {
public:
PuzzleVCR(AsylumEngine *engine);
~PuzzleVCR();
// Serializable
virtual void saveLoadWithSerializer(Common::Serializer &s);
private:
enum Color {
kNone = -1,
kBlack = 0,
kRed = 1,
kYellow = 2
};
enum JackState {
kOnTable = 0,
kPluggedOnRed = 1,
kPluggedOnYellow = 2,
kPluggedOnBlack = 3,
kOnHand = 4
};
enum VCRRegions {
kRewindButton = 0,
kStopButton = 1,
kPlayButton = 2,
kPowerButton = 3,
kRedHole = 4,
kYellowHole = 5,
kBlackHole = 6,
kBlackJack = 7,
kRedJack = 8,
kYellowJack = 9
};
enum ButtonState {
kOFF = 0,
kON = 1,
kDownON = 2,
kDownOFF = 3
};
JackState _jacksState[3];
JackState _holesState[3];
ButtonState _buttonsState[4];
uint32 _tvScreenFrameIndex;
bool _isAccomplished;
//////////////////////////////////////////////////////////////////////////
// Event Handling
//////////////////////////////////////////////////////////////////////////
bool init(const AsylumEvent &evt);
bool mouseLeftDown(const AsylumEvent &evt);
bool mouseLeftUp(const AsylumEvent &evt);
bool exitPuzzle();
//////////////////////////////////////////////////////////////////////////
// Drawing
//////////////////////////////////////////////////////////////////////////
void updateScreen();
void updateCursor();
//////////////////////////////////////////////////////////////////////////
// Updates
//////////////////////////////////////////////////////////////////////////
void updateJack(Color jack, const VCRDrawInfo &onTable, const VCRDrawInfo &pluggedOnRed, const VCRDrawInfo &pluggedOnYellow, const VCRDrawInfo &pluggedOnBlack, int32 resourceOnHandIndex);
void updateBlackJack();
void updateRedJack();
void updateYellowJack();
void updateButton(VCRRegions button, const VCRDrawInfo &btON, const VCRDrawInfo &btDown);
void updatePowerButton();
void updateRewindButton();
void updatePlayButton();
void updateStopButton();
void updateTVSync();
//////////////////////////////////////////////////////////////////////////
// Helpers
//////////////////////////////////////////////////////////////////////////
int inPolygon(const Common::Point &point, int polyIdx) const;
Color getJackOnHand() const;
void setJackOnHole(Color hole, JackState state, JackState newState);
void pickJack(Color jack);
};
} // end of namespace Asylum
#endif // ASYLUM_PUZZLES_VCR_H

View File

@@ -0,0 +1,369 @@
/* 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 "asylum/puzzles/wheel.h"
#include "asylum/resources/special.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/asylum.h"
namespace Asylum {
const GameFlag puzzleWheelFlags[32] = {
kGameFlag253, kGameFlag257, kGameFlag259, kGameFlag254, kGameFlag258,
kGameFlag260, kGameFlag253, kGameFlag255, kGameFlag259, kGameFlag254,
kGameFlag256, kGameFlag260, kGameFlag253, kGameFlag255, kGameFlag257,
kGameFlag254, kGameFlag256, kGameFlag258, kGameFlag255, kGameFlag257,
kGameFlag259, kGameFlag256, kGameFlag258, kGameFlag260, kGameFlag253,
kGameFlag254, kGameFlag255, kGameFlag256, kGameFlag257, kGameFlag258,
kGameFlag259, kGameFlag260
};
const uint32 puzzleWheelContacts[24] = {
1, 5, 7, 2, 6,
8, 1, 3, 7, 2,
4, 8, 1, 3, 5,
2, 4, 6, 3, 5,
7, 4, 6, 8
};
const uint32 puzzleWheelSparks[8] = {
0, 6, 5, 4, 1, 3, 7, 2
};
const uint32 puzzleWheelClockResourceIndexes[16] = {
39, 40, 42, 44, 46,
48, 50, 52, 38, 41,
43, 45, 47, 49, 51,
53
};
const int16 puzzleWheelPoints[56][2] = {
{ 0, 0}, { 0, 0}, { 0, 0}, {250, 254}, {122, 24}, {208, 68}, {238, 160},
{218, 234}, {162, 228}, { 71, 222}, { 22, 165}, { 35, 70}, {278, 0}, {536, 146},
{122, 24}, {208, 68}, {238, 160}, {218, 234}, {162, 228}, { 71, 222}, { 22, 165},
{ 35, 70}, {342, 87}, {342, 87}, {342, 87}, {342, 87}, {342, 87}, {342, 87},
{342, 87}, {342, 87}, {358, 268}, {342, 87}, {342, 87}, {342, 87}, {342, 87},
{342, 87}, {342, 87}, {342, 87}, {342, 87}, {342, 87}, {342, 87}, {342, 87},
{342, 87}, {342, 87}, {342, 87}, {342, 87}, {342, 87}, {536, 146}, {406, 106},
{402, 217}, {369, 128}, {368, 197}, {452, 184}, {470, 144}, {442, 116}, {347, 166}
};
const int16 puzzleWheelRects[4][4] = {
{425, 268, 491, 407}, {358, 268, 424, 407}, {561, 251, 594, 324}, {280, 276, 310, 400}
};
PuzzleWheel::PuzzleWheel(AsylumEngine *engine) : Puzzle(engine) {
_currentRect = -1;
_resourceIndex = 0;
_resourceIndexClock = 0;
_resourceIndexLever = 13;
_frameIndexWheel = 0;
memset(&_frameIndexes, 0, sizeof(_frameIndexes));
memset(&_frameIndexesSparks, -1, sizeof(_frameIndexesSparks));
_showTurnedClock = false;
_turnWheelRight = false;
_moveLever = false;
_moveChain = false;
}
PuzzleWheel::~PuzzleWheel() {
}
void PuzzleWheel::saveLoadWithSerializer(Common::Serializer &s) {
s.syncAsSint32LE(_resourceIndex);
}
//////////////////////////////////////////////////////////////////////////
// Event Handling
//////////////////////////////////////////////////////////////////////////
bool PuzzleWheel::init(const AsylumEvent &) {
getSpecial()->reset(false);
getScreen()->setPalette(getWorld()->graphicResourceIds[1]);
getScreen()->setGammaLevel(getWorld()->graphicResourceIds[1]);
updateCursor();
getCursor()->show();
_currentRect = -2;
memset(&_frameIndexesSparks, -1, sizeof(_frameIndexesSparks));
for (uint32 i = 0; i < 8; i++) {
if (_vm->isGameFlagSet((GameFlag)(kGameFlag253 + i)))
_frameIndexes[i + 1] = GraphicResource::getFrameCount(_vm, getWorld()->graphicResourceIds[i + 14]) - 1;
else
_frameIndexes[i + 1] = GraphicResource::getFrameCount(_vm, getWorld()->graphicResourceIds[i + 4]) - 1;
}
return true;
}
void PuzzleWheel::updateScreen() {
getScreen()->clearGraphicsInQueue();
getScreen()->draw(getWorld()->graphicResourceIds[0]);
// Blinking red light
getScreen()->draw(getWorld()->graphicResourceIds[12], (uint32)_frameIndexes[11], &puzzleWheelPoints[12]);
_frameIndexes[11] = (_frameIndexes[11] + 1) % (int32)GraphicResource::getFrameCount(_vm, getWorld()->graphicResourceIds[12]);
// Clock
if (_showTurnedClock)
getScreen()->draw(getWorld()->graphicResourceIds[_resourceIndexClock], (uint32)_frameIndexes[9], Common::Point(342, 87));
else
getScreen()->draw(getWorld()->graphicResourceIds[_resourceIndex + 22], 0, Common::Point(342, 87));
// Chain
getScreen()->draw(getWorld()->graphicResourceIds[3], (uint32)_frameIndexes[0], &puzzleWheelPoints[3]);
// Update chain frame index
if (_moveChain) {
if (!_frameIndexes[0]) {
getCursor()->hide();
getSound()->playSound(getWorld()->graphicResourceIds[65]);
}
_frameIndexes[0] = (_frameIndexes[0] + 1) % (int32)GraphicResource::getFrameCount(_vm, getWorld()->graphicResourceIds[3]);
if (!_frameIndexes[0]) {
closeLocks();
_moveChain = false;
getCursor()->show();
}
}
// Locks
uint32 frameIndex = 1;
for (uint32 i = 0; i < 8; i++) {
ResourceId resourceIndex = 0;
uint32 pointIndex = 0;
if (_vm->isGameFlagSet((GameFlag)(kGameFlag253 + i))) {
resourceIndex = 14 + i;
pointIndex = 10 + (4 + i);
} else {
resourceIndex = 4 + i;
pointIndex = 4 + i;
}
getScreen()->draw(getWorld()->graphicResourceIds[resourceIndex], (uint32)_frameIndexes[frameIndex], &puzzleWheelPoints[pointIndex]);
if (_frameIndexes[frameIndex] != (int32)GraphicResource::getFrameCount(_vm, getWorld()->graphicResourceIds[resourceIndex]) - 1)
++_frameIndexes[frameIndex];
++frameIndex;
}
// Sparks
for (uint32 i = 0; i < 8; i++) {
if (_frameIndexesSparks[i] >= 0) {
getScreen()->draw(getWorld()->graphicResourceIds[57 + i], (uint32)_frameIndexesSparks[i], &puzzleWheelPoints[48 + i]);
if (_frameIndexesSparks[i] == (int32)GraphicResource::getFrameCount(_vm, getWorld()->graphicResourceIds[57 + i]) - 1)
_frameIndexesSparks[i] = -1;
else
++_frameIndexesSparks[i];
}
}
// Lever
if (_resourceIndexLever == 13)
getScreen()->draw(getWorld()->graphicResourceIds[_resourceIndexLever], (uint32)_frameIndexes[10], &puzzleWheelPoints[13]);
else if (_resourceIndexLever == 54)
getScreen()->draw(getWorld()->graphicResourceIds[_resourceIndexLever], (uint32)_frameIndexes[10], &puzzleWheelPoints[47]);
// Update lever frame index
if (_moveLever) {
if (!_frameIndexes[10] && _resourceIndexLever == 13) {
getCursor()->hide();
getSound()->playSound(getWorld()->graphicResourceIds[67]);
}
_frameIndexes[10] = (_frameIndexes[10] + 1) % (int32)GraphicResource::getFrameCount(_vm, getWorld()->graphicResourceIds[_resourceIndexLever]);
if (!_frameIndexes[10]) {
if (_resourceIndexLever == 54) {
_resourceIndexLever = 13;
toggleLocks();
_moveLever = false;
getCursor()->show();
} else {
_resourceIndexLever = 54;
}
}
}
// Wheel
getScreen()->draw(getWorld()->graphicResourceIds[30], _frameIndexWheel, &puzzleWheelPoints[30]);
// Update wheel frame index
if (_showTurnedClock) {
if (!_frameIndexes[9]) {
getCursor()->hide();
getSound()->playSound(getWorld()->graphicResourceIds[66]);
}
uint32 frameCountWheel = GraphicResource::getFrameCount(_vm, getWorld()->graphicResourceIds[30]);
if (_turnWheelRight)
_frameIndexWheel = (_frameIndexWheel + 1) % frameCountWheel;
else
_frameIndexWheel = (_frameIndexWheel + frameCountWheel - 1) % frameCountWheel;
_frameIndexes[9] = (_frameIndexes[9] + 1) % (int32)GraphicResource::getFrameCount(_vm, getWorld()->graphicResourceIds[_resourceIndexClock]);
if (!_frameIndexes[9]) {
_showTurnedClock = false;
getCursor()->show();
}
}
//////////////////////////////////////////////////////////////////////////
// Show elements on screen
getScene()->drawRain();
// Check for completion
checkFlags();
}
bool PuzzleWheel::mouseLeftDown(const AsylumEvent &) {
switch (findRect()) {
default:
break;
case 0: // Wheel right
_frameIndexes[9] = 0;
_turnWheelRight = true;
_showTurnedClock = true;
updateIndex();
break;
case 1: // Wheel left
_frameIndexes[9] = 0;
_turnWheelRight = false;
_showTurnedClock = true;
updateIndex();
break;
case 2: // Lever
_moveLever = true;
break;
case 3: // Chain
_moveChain = true;
break;
}
return true;
}
bool PuzzleWheel::exitPuzzle() {
getScreen()->clear();
_vm->switchEventHandler(getScene());
return true;
}
//////////////////////////////////////////////////////////////////////////
// Helpers
//////////////////////////////////////////////////////////////////////////
void PuzzleWheel::updateCursor() {
int32 index = findRect();
if (_currentRect != index) {
_currentRect = index;
getCursor()->set(getWorld()->graphicResourceIds[2], -1, (index == -1) ? kCursorAnimationNone : kCursorAnimationMirror);
}
}
int32 PuzzleWheel::findRect() {
for (uint32 i = 0; i < ARRAYSIZE(puzzleWheelRects); i++) {
if (_vm->rectContains(&puzzleWheelRects[i], getCursor()->position()))
return i;
}
return -1;
}
void PuzzleWheel::updateIndex() {
if (_turnWheelRight) {
_resourceIndexClock = puzzleWheelClockResourceIndexes[_resourceIndex];
_resourceIndex = (_resourceIndex + 7) % ~7;
} else {
_resourceIndexClock = puzzleWheelClockResourceIndexes[_resourceIndex + 8];
_resourceIndex = (_resourceIndex + 1) % ~7;
}
}
void PuzzleWheel::checkFlags() {
for (uint32 i = 0; i < 8; i++)
if (!_vm->isGameFlagSet(puzzleWheelFlags[i]))
return;
_vm->setGameFlag(kGameFlag261);
getScreen()->clear();
_vm->switchEventHandler(getScene());
}
void PuzzleWheel::closeLocks() {
for (uint32 i = 0; i < 8; i++) {
if (!_vm->isGameFlagSet(puzzleWheelFlags[24 + i]))
continue;
getSound()->playSound(getWorld()->graphicResourceIds[69]);
_vm->clearGameFlag(puzzleWheelFlags[24 + i]);
_frameIndexes[i + 1] = 0;
}
}
void PuzzleWheel::toggleLocks() {
memset(&_frameIndexesSparks, -1, sizeof(_frameIndexesSparks));
for (int32 i = 0; i < 3; i++) {
_vm->toggleGameFlag(puzzleWheelFlags[i + 3 * _resourceIndex]);
// Update lock frame indexes
_frameIndexes[puzzleWheelContacts[i + 3 * _resourceIndex]] = 0;
// Update sparks frame indexes
_frameIndexesSparks[puzzleWheelSparks[puzzleWheelContacts[i + 3 * _resourceIndex] - 1]] = 0;
if (_vm->isGameFlagSet(puzzleWheelFlags[i]))
getSound()->playSound(getWorld()->graphicResourceIds[68]);
else
getSound()->playSound(getWorld()->graphicResourceIds[69]);
}
}
} // End of namespace Asylum

View File

@@ -0,0 +1,74 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef ASYLUM_PUZZLES_WHEEL_H
#define ASYLUM_PUZZLES_WHEEL_H
#include "asylum/puzzles/puzzle.h"
namespace Asylum {
class AsylumEngine;
class PuzzleWheel : public Puzzle {
public:
PuzzleWheel(AsylumEngine *engine);
~PuzzleWheel();
// Serializable
virtual void saveLoadWithSerializer(Common::Serializer &s);
private:
int32 _currentRect;
int32 _resourceIndex;
uint32 _resourceIndexClock;
uint32 _resourceIndexLever;
uint32 _frameIndexWheel;
int32 _frameIndexes[12];
int32 _frameIndexesSparks[8];
bool _showTurnedClock;
bool _turnWheelRight;
bool _moveLever;
bool _moveChain;
//////////////////////////////////////////////////////////////////////////
// Event Handling
//////////////////////////////////////////////////////////////////////////
bool init(const AsylumEvent &evt);
void updateScreen();
bool mouseLeftDown(const AsylumEvent &evt);
bool exitPuzzle();
//////////////////////////////////////////////////////////////////////////
// Helpers
//////////////////////////////////////////////////////////////////////////
void updateCursor();
int32 findRect();
void updateIndex();
void checkFlags();
void closeLocks();
void toggleLocks();
};
} // End of namespace Asylum
#endif // ASYLUM_PUZZLES_WHEEL_H

View File

@@ -0,0 +1,167 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include "asylum/puzzles/writings.h"
#include "asylum/resources/actor.h"
#include "asylum/resources/worldstats.h"
#include "asylum/system/cursor.h"
#include "asylum/system/graphics.h"
#include "asylum/system/screen.h"
#include "asylum/system/text.h"
#include "asylum/views/scene.h"
#include "asylum/asylum.h"
namespace Asylum {
PuzzleWritings::PuzzleWritings(AsylumEngine *engine) : Puzzle(engine) {
_frameIndex = 0;
_hasGlassMagnifier = false;
}
PuzzleWritings::~PuzzleWritings() {
_textSurface.free();
}
//////////////////////////////////////////////////////////////////////////
// Event Handling
//////////////////////////////////////////////////////////////////////////
bool PuzzleWritings::init(const AsylumEvent &) {
if (getScene()->getActor()->inventory.getSelectedItem() == 3)
_hasGlassMagnifier = true;
else
_hasGlassMagnifier = false;
getScreen()->setPalette(getWorld()->graphicResourceIds[10]);
getScreen()->setGammaLevel(getWorld()->graphicResourceIds[10]);
if (_hasGlassMagnifier) {
getCursor()->hide();
getSharedData()->setFlag(kFlag1, true);
_vm->setGameFlag(kGameFlag481);
} else {
getCursor()->set(getWorld()->graphicResourceIds[61], -1, kCursorAnimationNone, 7);
}
_textSurface.create(640, 480, Graphics::PixelFormat::createFormatCLUT8());
// Draw background
getScreen()->fillRect(0, 0, 640, 480, 253);
getScreen()->draw(getWorld()->graphicResourceIds[5], 0, Common::Point(0, 0), kDrawFlagNone, true);
// Draw all lines of text
int textId;
switch (_vm->getLanguage()) {
default:
case Common::EN_ANY:
textId = 1825;
break;
case Common::DE_DEU:
textId = 1748;
break;
case Common::FR_FRA:
textId = 1729;
break;
}
getText()->loadFont(getWorld()->graphicResourceIds[42]);
for (int i = 0; i < 10; i++, textId++)
getText()->draw(0, 99, kTextNormal, Common::Point(70 + 60 * (i & 1), 45 + 30 * i), 16, 590,
getText()->get(MAKE_RESOURCE(kResourcePackText, textId)));
getText()->drawCentered(Common::Point(10, 375), 590, getText()->get(MAKE_RESOURCE(kResourcePackText, textId++)));
getText()->drawCentered(Common::Point(10, 405), 590, getText()->get(MAKE_RESOURCE(kResourcePackText, textId)));
_textSurface.copyFrom(*getScreen()->getSurface());
return false;
}
bool PuzzleWritings::update(const AsylumEvent &) {
// Adjust palette
if (rnd(10) < 7) {
getScreen()->setPalette(getWorld()->graphicResourceIds[6]);
getScreen()->setGammaLevel(getWorld()->graphicResourceIds[6]);
} else {
getScreen()->setPalette(getWorld()->graphicResourceIds[10]);
getScreen()->setGammaLevel(getWorld()->graphicResourceIds[10]);
}
// Compute frame index
Common::Point mousePos = getCursor()->position();
if (mousePos.x > 50 && mousePos.x < 530 && mousePos.y > 20 && mousePos.y < 430) {
if (_frameIndex < 26)
++_frameIndex;
} else {
if (_frameIndex > 0)
--_frameIndex;
}
// Draw background
getScreen()->clearGraphicsInQueue();
getScreen()->fillRect(0, 0, 640, 480, 253);
getScreen()->draw(getWorld()->graphicResourceIds[4], 0, Common::Point(0, 0), kDrawFlagNone, true);
if (_hasGlassMagnifier) {
mousePos -= Common::Point(50, 50);
Common::Rect eyeBall = Common::Rect(0, 0, 640, 480).findIntersectingRect(Common::Rect(mousePos.x + 20, mousePos.y + 20,
mousePos.x + 100, mousePos.y + 100));
Graphics::Surface subArea, *subArea1;
subArea = _textSurface.getSubArea(eyeBall);
subArea1 = subArea.scale(3 * eyeBall.width() / 4, 3 * eyeBall.height() / 4);
eyeBall.left += 9;
eyeBall.top += 9;
int16 dw, dh;
dw = MAX(0, eyeBall.left + subArea1->w - 640);
dh = MAX(0, eyeBall.top + subArea1->h - 480);
getScreen()->copyToBackBuffer((byte *)subArea1->getPixels(), subArea1->pitch, eyeBall.left, eyeBall.top, subArea1->w - dw, subArea1->h - dh);
subArea1->free();
delete subArea1;
getScreen()->addGraphicToQueueMasked(getWorld()->graphicResourceIds[9], 0, mousePos, getWorld()->graphicResourceIds[8], mousePos, kDrawFlagNone, 2);
getScreen()->addGraphicToQueue(getWorld()->graphicResourceIds[7], (uint32)_frameIndex, mousePos, kDrawFlagNone, 0, 1);
}
getScreen()->drawGraphicsInQueue();
getScreen()->copyBackBufferToScreen();
return true;
}
bool PuzzleWritings::exitPuzzle() {
getCursor()->hide();
getSharedData()->setFlag(kFlag1, true);
getScreen()->stopPaletteFade(0, 0, 0);
_vm->switchEventHandler(getScene());
return false;
}
} // End of namespace Asylum

View File

@@ -0,0 +1,53 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef ASYLUM_PUZZLES_WRITINGS_H
#define ASYLUM_PUZZLES_WRITINGS_H
#include "asylum/puzzles/puzzle.h"
#include "asylum/system/graphics.h"
namespace Asylum {
class AsylumEngine;
class PuzzleWritings : public Puzzle {
public:
PuzzleWritings(AsylumEngine *engine);
~PuzzleWritings();
private:
int32 _frameIndex;
bool _hasGlassMagnifier;
Graphics::Surface _textSurface;
//////////////////////////////////////////////////////////////////////////
// Event Handling
//////////////////////////////////////////////////////////////////////////
bool init(const AsylumEvent &evt);
bool update(const AsylumEvent &evt);
bool exitPuzzle();
};
} // End of namespace Asylum
#endif // ASYLUM_PUZZLES_WRITINGS_H