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