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 "asylum/puzzles/board.h"
24 
25 #include "asylum/resources/worldstats.h"
26 
27 #include "asylum/system/cursor.h"
28 #include "asylum/system/screen.h"
29 #include "asylum/system/text.h"
30 
31 #include "asylum/views/scene.h"
32 
33 #include "asylum/asylum.h"
34 
35 namespace Asylum {
36 
PuzzleBoard(AsylumEngine * engine,const PuzzleData & data)37 PuzzleBoard::PuzzleBoard(AsylumEngine *engine, const PuzzleData &data) : Puzzle(engine) {
38 	_data = data;
39 
40 	// Init board
41 	_solved = false;
42 	memset(&_charUsed,   false, sizeof(_charUsed));
43 	memset(&_solvedText, 0,     sizeof(_solvedText));
44 	_rectIndex = -2;
45 	_soundResourceId = kResourceNone;
46 	_selectedSlot = -1;
47 	_position = 0;
48 }
49 
reset()50 void PuzzleBoard::reset() {
51 	memset(&_charUsed, false, sizeof(_charUsed));
52 }
53 
54 //////////////////////////////////////////////////////////////////////////
55 // Event Handling
56 //////////////////////////////////////////////////////////////////////////
init(const AsylumEvent &)57 bool PuzzleBoard::init(const AsylumEvent &)  {
58 	_rectIndex = -2;
59 	_selectedSlot = -1;
60 	_solved = false;
61 	_soundResourceId = 0;
62 
63 	getScreen()->setPalette(getWorld()->graphicResourceIds[32]);
64 	getScreen()->setGammaLevel(getWorld()->graphicResourceIds[32]);
65 	getText()->loadFont(getWorld()->graphicResourceIds[35]);
66 
67 	// Prepare text to draw
68 	_text.clear();
69 
70 	for (uint32 i = 0; i < _data.soundResourceSize; i++) {
71 		_data.soundResources[i].played = false;
72 		_text += getText()->get(MAKE_RESOURCE(kResourcePackText, 1068 + _data.soundResources[i].index));
73 		_text += ' ';
74 	}
75 
76 	updateScreen();
77 
78 	getCursor()->show();
79 
80 	return true;
81 }
82 
updateScreen()83 void PuzzleBoard::updateScreen()  {
84 	getScreen()->clearGraphicsInQueue();
85 
86 	getScreen()->draw(getWorld()->graphicResourceIds[_data.backgroundIndex]);
87 	drawText();
88 
89 	getScreen()->drawGraphicsInQueue();
90 	getScreen()->copyBackBufferToScreen();
91 }
92 
update(const AsylumEvent &)93 bool PuzzleBoard::update(const AsylumEvent &) {
94 	updateCursor();
95 
96 	if (!_solved)
97 		playSound();
98 
99 	if (_vm->isGameFlagNotSet(_data.gameFlag)) {
100 		if (strcmp(_solvedText, _data.solvedText))
101 			return true;
102 
103 		if (_solved) {
104 			if (!getSound()->isPlaying(MAKE_RESOURCE(kResourcePackSpeech, 1))) {
105 				_vm->setGameFlag(_data.gameFlag);
106 				getCursor()->show();
107 				getScreen()->clear();
108 				_vm->switchEventHandler(getScene());
109 			}
110 		} else {
111 			_solved = true;
112 			getCursor()->hide();
113 			stopSound();
114 			getSound()->playSound(MAKE_RESOURCE(kResourcePackSpeech, 1), false, Config.voiceVolume);
115 		}
116 	}
117 
118 	return true;
119 }
120 
mouseRightDown(const AsylumEvent &)121 bool PuzzleBoard::mouseRightDown(const AsylumEvent &) {
122 	if (!stopSound()) {
123 		getScreen()->clear();
124 		_vm->switchEventHandler(getScene());
125 	}
126 
127 	return true;
128 }
129 
130 //////////////////////////////////////////////////////////////////////////
131 // Helpers
132 //////////////////////////////////////////////////////////////////////////
stopSound()133 bool PuzzleBoard::stopSound() {
134 	if (_soundResourceId && getSound()->isPlaying(_soundResourceId)) {
135 		getSound()->stopAll(_soundResourceId);
136 
137 		return true;
138 	}
139 
140 	return false;
141 }
142 
drawText()143 void PuzzleBoard::drawText() {
144 	getText()->loadFont(getWorld()->graphicResourceIds[35]);
145 	getText()->draw(0, 99, kTextCenter, Common::Point(25, 50), 16, 590, _text.c_str());
146 
147 	int32 index = 0;
148 	for (int16 x = 215; x < (int16)_data.maxWidth; x += 24) {
149 		if (!_solvedText[index])
150 			break;
151 
152 		getText()->setPosition(Common::Point(x, _selectedSlot != index ? 360 : 370));
153 		getText()->drawChar(_solvedText[index]);
154 
155 		index += 2;
156 	}
157 }
158 
playSound()159 void PuzzleBoard::playSound() {
160 	uint32 index;
161 	for (index = 0; index < _data.soundResourceSize; index++) {
162 		if (!_data.soundResources[index].played)
163 			break;
164 	}
165 
166 	if (index >= _data.soundResourceSize)
167 		return;
168 
169 	if (!_soundResourceId || !getSound()->isPlaying(_soundResourceId)) {
170 		_soundResourceId = MAKE_RESOURCE(kResourcePackSharedSound, 2401 + _data.soundResources[index].index);
171 		getSound()->playSound(_soundResourceId, false, Config.voiceVolume);
172 		_data.soundResources[index].played = true;
173 	}
174 }
175 
findRect()176 int32 PuzzleBoard::findRect() {
177 	Common::Point mousePos = getCursor()->position();
178 
179 	for (uint32 i = 0; i < _data.charMapSize; i++) {
180 		if (mousePos.x >= _data.charMap[i].posX && mousePos.x < _data.charMap[i].posX + 12
181 		 && mousePos.y >= _data.charMap[i].posY && mousePos.y < _data.charMap[i].posY + 18)
182 			if (!_charUsed[i])
183 				return i;
184 	}
185 
186 	return -1;
187 }
188 
checkMouse()189 int32 PuzzleBoard::checkMouse() {
190 	Common::Point mousePos = getCursor()->position();
191 
192 	if (mousePos.x >= 215 && mousePos.x < (int16)_data.maxWidth && mousePos.y >= 360 && mousePos.y < 376) {
193 		int16 index = (mousePos.x - 215) / 12;
194 
195 		if (index < 0 || index >= ARRAYSIZE(_solvedText))
196 			return -1;
197 
198 		if (_solvedText[index] != 0 && _solvedText[index] != ' ')
199 			return -3;
200 	}
201 
202 	return -1;
203 }
204 
updateCursor()205 void PuzzleBoard::updateCursor() {
206 	Common::Point mousePos = getCursor()->position();
207 
208 	if (mousePos.y <= 350) {
209 		int32 index = findRect();
210 
211 		if (index == -1) {
212 			if (getCursor()->getResourceId() == getWorld()->graphicResourceIds[34])
213 				return;
214 
215 			_rectIndex = index;
216 
217 			getCursor()->set(getWorld()->graphicResourceIds[34]);
218 		} else {
219 			if (getCursor()->getResourceId() == getWorld()->graphicResourceIds[33])
220 				return;
221 
222 			if (index == _rectIndex)
223 				return;
224 
225 			_rectIndex = index;
226 
227 			getCursor()->set(getWorld()->graphicResourceIds[33]);
228 		}
229 	} else {
230 		if (_vm->isGameFlagSet(_data.gameFlag)) {
231 			if (getCursor()->getResourceId() == getWorld()->graphicResourceIds[34])
232 				return;
233 
234 			getCursor()->set(getWorld()->graphicResourceIds[34]);
235 		} else {
236 			int32 index = checkMouse();
237 
238 			if (getCursor()->getResourceId() == getWorld()->graphicResourceIds[33])
239 				return;
240 
241 			if (index == _rectIndex)
242 				return;
243 
244 			if (index == -1)
245 				getCursor()->set(getWorld()->graphicResourceIds[33], 0, kCursorAnimationNone);
246 			else
247 				getCursor()->set(getWorld()->graphicResourceIds[33]);
248 		}
249 	}
250 }
251 
checkSlots()252 void PuzzleBoard::checkSlots() {
253 	Common::Point mousePos = getCursor()->position();
254 
255 	if (mousePos.x >= 215 && mousePos.x < (int16)_data.maxWidth && mousePos.y >= 360 && mousePos.y < 376) {
256 		int32 index = (mousePos.x - 215) / 12;
257 
258 		if (_solvedText[index]) {
259 			if (_solvedText[index] == ' ')
260 				return;
261 
262 			if (_selectedSlot == -1) {
263 				_selectedSlot = index;
264 			} else {
265 				SWAP(_solvedText[index], _solvedText[_selectedSlot]);
266 				_selectedSlot = -1;
267 			}
268 
269 			updateScreen();
270 		}
271 	}
272 }
273 
274 } // End of namespace Asylum
275