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