1 /* ScummVM - Graphic Adventure Engine
2 *
3 * ScummVM is the legal property of its developers, whose names
4 * are too numerous to list here. Please refer to the COPYRIGHT
5 * file distributed with this source distribution.
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 2
10 * of the License, or (at your option) any later version.
11
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20 *
21 */
22
23 #include "engines/nancy/graphics.h"
24 #include "engines/nancy/resource.h"
25 #include "engines/nancy/nancy.h"
26 #include "engines/nancy/sound.h"
27 #include "engines/nancy/input.h"
28 #include "engines/nancy/util.h"
29
30 #include "engines/nancy/action/leverpuzzle.h"
31
32 #include "engines/nancy/state/scene.h"
33
34 namespace Nancy {
35 namespace Action {
36
init()37 void LeverPuzzle::init() {
38 _drawSurface.create(_screenPosition.width(), _screenPosition.height(), g_nancy->_graphicsManager->getInputPixelFormat());
39 _drawSurface.clear(g_nancy->_graphicsManager->getTransColor());
40
41 setTransparent(true);
42
43 g_nancy->_resource->loadImage(_imageName, _image);
44 }
45
readData(Common::SeekableReadStream & stream)46 void LeverPuzzle::readData(Common::SeekableReadStream &stream) {
47 readFilename(stream, _imageName);
48
49 _srcRects.reserve(3);
50 for (uint leverID = 0; leverID < 3; ++leverID) {
51 _srcRects.push_back(Common::Array<Common::Rect>());
52 _srcRects.back().reserve(3);
53 for (uint i = 0; i < 4; ++i) {
54 _srcRects.back().push_back(Common::Rect());
55 readRect(stream, _srcRects.back().back());
56 }
57 }
58
59 _destRects.reserve(3);
60 for (uint leverID = 0; leverID < 3; ++leverID) {
61 _destRects.push_back(Common::Rect());
62 readRect(stream, _destRects.back());
63
64 if (leverID == 0) {
65 _screenPosition = _destRects.back();
66 } else {
67 _screenPosition.extend(_destRects.back());
68 }
69 }
70
71 _playerSequence.reserve(3);
72 _leverDirection.reserve(3);
73 for (uint leverID = 0; leverID < 3; ++leverID) {
74 _playerSequence.push_back(stream.readByte());
75 _leverDirection.push_back(true);
76 }
77
78 _correctSequence.reserve(3);
79 for (uint leverID = 0; leverID < 3; ++leverID) {
80 _correctSequence.push_back(stream.readByte());
81 }
82
83 _moveSound.read(stream, SoundDescription::kNormal);
84 _noMoveSound.read(stream, SoundDescription::kNormal);
85 _solveExitScene.readData(stream);
86 stream.skip(2);
87 _flagOnSolve.label = stream.readSint16LE();
88 _flagOnSolve.flag = (NancyFlag)stream.readByte();
89 _solveSoundDelay = stream.readUint16LE();
90 _solveSound.read(stream, SoundDescription::kNormal);
91 _exitScene.readData(stream);
92 stream.skip(2);
93 _flagOnExit.label = stream.readSint16LE();
94 _flagOnExit.flag = (NancyFlag)stream.readByte();
95 readRect(stream, _exitHotspot);
96 }
97
execute()98 void LeverPuzzle::execute() {
99 switch (_state) {
100 case kBegin:
101 init();
102 registerGraphics();
103 g_nancy->_sound->loadSound(_moveSound);
104 g_nancy->_sound->loadSound(_noMoveSound);
105
106 for (uint i = 0; i < 3; ++i) {
107 drawLever(i);
108 }
109
110 _state = kRun;
111 // fall through
112 case kRun:
113 switch (_solveState) {
114 case kNotSolved:
115 for (uint i = 0; i < 3; ++i) {
116 if (_playerSequence[i] != _correctSequence[i]) {
117 return;
118 }
119 }
120
121 NancySceneState.setEventFlag(_flagOnSolve);
122 _solveSoundPlayTime = g_nancy->getTotalPlayTime() + _solveSoundDelay * 1000;
123 _solveState = kPlaySound;
124 break;
125 case kPlaySound:
126 if (g_nancy->getTotalPlayTime() <= _solveSoundPlayTime) {
127 break;
128 }
129
130 g_nancy->_sound->loadSound(_solveSound);
131 g_nancy->_sound->playSound(_solveSound);
132 _solveState = kWaitForSound;
133 break;
134 case kWaitForSound:
135 if (!g_nancy->_sound->isSoundPlaying(_solveSound)) {
136 g_nancy->_sound->stopSound(_solveSound);
137 _state = kActionTrigger;
138 }
139
140 break;
141 }
142
143 break;
144 case kActionTrigger:
145 g_nancy->_sound->stopSound(_moveSound);
146 g_nancy->_sound->stopSound(_noMoveSound);
147
148 if (_solveState == kNotSolved) {
149 NancySceneState.changeScene(_exitScene);
150 NancySceneState.setEventFlag(_flagOnExit);
151 } else {
152 NancySceneState.changeScene(_solveExitScene);
153 }
154
155 finishExecution();
156 }
157 }
158
handleInput(NancyInput & input)159 void LeverPuzzle::handleInput(NancyInput &input) {
160 if (_solveState != kNotSolved) {
161 return;
162 }
163
164 if (NancySceneState.getViewport().convertViewportToScreen(_exitHotspot).contains(input.mousePos)) {
165 g_nancy->_cursorManager->setCursorType(CursorManager::kExit);
166
167 if (input.input & NancyInput::kLeftMouseButtonUp) {
168 _state = kActionTrigger;
169 }
170 return;
171 }
172
173 for (uint i = 0; i < 3; ++i) {
174 if (NancySceneState.getViewport().convertViewportToScreen(_destRects[i]).contains(input.mousePos)) {
175 g_nancy->_cursorManager->setCursorType(CursorManager::kHotspot);
176
177 if (input.input & NancyInput::kLeftMouseButtonUp) {
178 bool isMoving = false;
179 // Hardcoded by the original engine
180 switch (i) {
181 case 0:
182 isMoving = true;
183 break;
184 case 1:
185 if (_playerSequence[0] == 1) {
186 isMoving = true;
187 }
188
189 break;
190 case 2:
191 if (_playerSequence[0] == 2) {
192 isMoving = true;
193 }
194
195 break;
196 }
197
198 if (isMoving) {
199 g_nancy->_sound->playSound(_moveSound);
200
201 if (_leverDirection[i]) {
202 // Moving down
203 if (_playerSequence[i] == 3) {
204 --_playerSequence[i];
205 _leverDirection[i] = false;
206 } else {
207 ++_playerSequence[i];
208 }
209 } else {
210 // Moving up
211 if (_playerSequence[i] == 0) {
212 ++_playerSequence[i];
213 _leverDirection[i] = true;
214 } else {
215 --_playerSequence[i];
216 }
217 }
218
219 drawLever(i);
220 } else {
221 g_nancy->_sound->playSound(_noMoveSound);
222 return;
223 }
224 }
225 }
226 }
227 }
228
onPause(bool pause)229 void LeverPuzzle::onPause(bool pause) {
230 if (!pause) {
231 registerGraphics();
232 }
233 }
234
drawLever(uint id)235 void LeverPuzzle::drawLever(uint id) {
236 Common::Point destPoint(_destRects[id].left - _screenPosition.left, _destRects[id].top - _screenPosition.top);
237 _drawSurface.blitFrom(_image, _srcRects[id][_playerSequence[id]], destPoint);
238
239 _needsRedraw = true;
240 }
241
242 } // End of namespace Action
243 } // End of namespace Nancy
244