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 "bbvs/minigames/bbairguitar.h"
24 
25 #include "common/savefile.h"
26 
27 #include "gui/message.h"
28 #include "gui/filebrowser-dialog.h"
29 
30 namespace Bbvs {
31 
32 static const char * const kNoteSoundFilenames[] = {
33 	"a.aif", "a#.aif", "b.aif", "c.aif", "c#.aif",
34 	"d.aif", "d#.aif", "e.aif", "f.aif", "f#.aif",
35 	"g.aif", "g#.aif", "a_oct.aif"
36 };
37 
38 static const uint kNoteSoundFilenamesCount = ARRAYSIZE(kNoteSoundFilenames);
39 
40 static const char * const kPatchDirectories[] = {
41 	"rock", "burp", "fart"
42 };
43 
44 static const uint kPatchDirectoriesCount = ARRAYSIZE(kPatchDirectories);
45 
46 static const BBPoint kPianoKeyArea1[] = {{29, 192}, {38, 192}, {38, 222}, {41, 222}, {41, 239}, {29, 239}};
47 static const BBPoint kPianoKeyArea2[] = {{38, 192}, {43, 192}, {43, 222}, {38, 222}};
48 static const BBPoint kPianoKeyArea3[] = {{43, 192}, {49, 192}, {49, 222}, {52, 222}, {52, 239}, {41, 239}, {41, 222}, {43, 222}};
49 static const BBPoint kPianoKeyArea4[] = {{49, 192}, {54, 192}, {54, 222}, {49, 222}};
50 static const BBPoint kPianoKeyArea5[] = {{54, 192}, {63, 192}, {63, 239}, {52, 239}, {52, 222}, {54, 222}};
51 static const BBPoint kPianoKeyArea6[] = {{63, 192}, {71, 192}, {71, 222}, {74, 222}, {74, 239}, {63, 239}};
52 static const BBPoint kPianoKeyArea7[] = {{71, 192}, {76, 192}, {76, 222}, {71, 222}};
53 static const BBPoint kPianoKeyArea8[] = {{76, 192}, {82, 192}, {82, 222}, {85, 222}, {85, 239}, {74, 239}, {74, 222}, {76, 222}};
54 static const BBPoint kPianoKeyArea9[] = {{82, 192}, {87, 192}, {87, 222}, {82, 222}};
55 static const BBPoint kPianoKeyArea10[] = {{87, 192}, {94, 192}, {94, 222}, {96, 222}, {96, 239}, {85, 239}, {85, 222}, {87, 222}};
56 static const BBPoint kPianoKeyArea11[] = {{94, 192}, {99, 192}, {99, 222}, {94, 222}};
57 static const BBPoint kPianoKeyArea12[] = {{99, 192}, {107, 192}, {107, 239}, {96, 239}, {96, 222}, {99, 222}};
58 static const BBPoint kPianoKeyArea13[] = {{107, 192}, {118, 192}, {118, 239}, {107, 239}};
59 
60 static const BBPolygon kPianoKeyAreas[] = {
61 	{kPianoKeyArea1, ARRAYSIZE(kPianoKeyArea1)},
62 	{kPianoKeyArea2, ARRAYSIZE(kPianoKeyArea2)},
63 	{kPianoKeyArea3, ARRAYSIZE(kPianoKeyArea3)},
64 	{kPianoKeyArea4, ARRAYSIZE(kPianoKeyArea4)},
65 	{kPianoKeyArea5, ARRAYSIZE(kPianoKeyArea5)},
66 	{kPianoKeyArea6, ARRAYSIZE(kPianoKeyArea6)},
67 	{kPianoKeyArea7, ARRAYSIZE(kPianoKeyArea7)},
68 	{kPianoKeyArea8, ARRAYSIZE(kPianoKeyArea8)},
69 	{kPianoKeyArea9, ARRAYSIZE(kPianoKeyArea9)},
70 	{kPianoKeyArea10, ARRAYSIZE(kPianoKeyArea10)},
71 	{kPianoKeyArea11, ARRAYSIZE(kPianoKeyArea11)},
72 	{kPianoKeyArea12, ARRAYSIZE(kPianoKeyArea12)},
73 	{kPianoKeyArea13, ARRAYSIZE(kPianoKeyArea13)},
74 };
75 
76 static const BBPoint kObjPoints[] = {
77 	{161, 189}, {269, 189}, {161, 208}, {279, 208}, {172, 208},
78 	{141, 224}, {257, 191}, {257, 199}, {148, 223}, {124, 224},
79 	{ 29, 192}, {182, 220}, {245, 220}, {269, 220}, {161, 220},
80 	{203, 220}, {224, 220}, {123, 189}, {123, 199}, {123, 209},
81 	{134, 224}, { 29, 185}, {124, 224}, {226, 127}, {226, 127},
82 	{209, 141}, {244, 141}, {226, 127}, { 99, 107}, { 99, 107},
83 	{ 76, 137}, {118, 136}, { 99, 107}, {195, 104}, {100,  78}
84 };
85 
86 static const MinigameBbAirGuitar::PianoKeyInfo kPianoKeyInfos[] = {
87 	{ 30, 192, 0},
88 	{ 38, 192, 5},
89 	{ 41, 192, 1},
90 	{ 49, 192, 5},
91 	{ 52, 192, 2},
92 	{ 63, 192, 3},
93 	{ 71, 192, 5},
94 	{ 74, 192, 1},
95 	{ 82, 192, 5},
96 	{ 85, 192, 1},
97 	{ 94, 192, 5},
98 	{ 96, 192, 2},
99 	{107, 192, 4}
100 };
101 
102 static const Rect kRect2 = {29, 189, 290, 239};
103 static const Rect kPianoRect = {29, 192, 118, 239};
104 
105 static const Rect kPlayerButtonRects[] = {
106 	{123, 189, 145, 199},
107 	{123, 199, 145, 209},
108 	{123, 209, 145, 220},
109 	{148, 223, 156, 236},
110 	{161, 189, 182, 205},
111 	{161, 208, 171, 218},
112 	{161, 220, 182, 231},
113 	{182, 220, 203, 231},
114 	{203, 220, 224, 231},
115 	{224, 220, 245, 231},
116 	{245, 220, 266, 231},
117 	{269, 220, 290, 231},
118 	{269, 189, 290, 205},
119 	{279, 208, 290, 218}
120 };
121 
122 static const BBPoint kPointsTbl1[] = {
123 	{196, 191},	{202, 191}, {207, 191}, {212, 191}, {217, 191},
124 	{223, 191}, {228, 191}, {233, 191}, {238, 191}, {244, 191},
125 	{249, 191}
126 };
127 
128 static const BBPoint kPointsTbl2[] = {
129 	{196, 199}, {202, 199}, {207, 199}, {212, 199}, {217, 199},
130 	{223, 199}, {228, 199}, {233, 199}, {238, 199}, {244, 199},
131 	{249, 199}
132 };
133 
134 static const struct { int frameIndex; byte flag; } kNoteFrameTbl[13] = {
135 	{2, 0}, {2, 1}, {3, 0}, {3, 1}, {4, 0},
136 	{5, 0}, {5, 1}, {6, 0}, {6, 1}, {0, 0},
137 	{0, 1}, {1, 0}, {2, 0}
138 };
139 
140 const int kTrackBarMinX = 172;
141 const int kTrackBarMaxX = 272;
142 
ptInRect(const Rect * r,int x,int y)143 bool MinigameBbAirGuitar::ptInRect(const Rect *r, int x, int y) {
144 	return r && Common::Rect(r->left, r->top, r->right, r->bottom).contains(x, y);
145 }
146 
ptInPoly(const BBPolygon * poly,int x,int y)147 bool MinigameBbAirGuitar::ptInPoly(const BBPolygon *poly, int x, int y) {
148 	if (!poly)
149 		return false;
150 	const BBPoint *points = poly->points;
151 	int pointsCount = poly->pointsCount;
152 	bool result = false;
153 	if (pointsCount > 0)
154 		for (int i = 0, j = pointsCount - 1; i < pointsCount; j = i++)
155 			if (((points[i].y > y) != (points[j].y > y)) &&
156 				(x < (points[j].x - points[i].x) * (y - points[i].y) /
157 				(points[j].y - points[i].y) + points[i].x))
158 				result = !result;
159 	return result;
160 }
161 
buildDrawList(DrawList & drawList)162 void MinigameBbAirGuitar::buildDrawList(DrawList &drawList) {
163 	switch (_gameState) {
164 	case 0:
165 		buildDrawList0(drawList);
166 		break;
167 	case 1:
168 		buildDrawList1(drawList);
169 		break;
170 	default:
171 		break;
172 	}
173 }
174 
buildDrawList0(DrawList & drawList)175 void MinigameBbAirGuitar::buildDrawList0(DrawList &drawList) {
176 
177 	drawList.add(_objects[0].anim->frameIndices[0], _objects[0].x, _objects[0].y, 2000);
178 
179 	for (int i = 1; i < kMaxObjectsCount; ++i) {
180 		Obj *obj = &_objects[i];
181 		if (obj->kind)
182 			drawList.add(obj->anim->frameIndices[obj->frameIndex], obj->x, obj->y, obj->y + 16);
183 	}
184 
185 	if (_titleScreenSpriteIndex> 0)
186 		drawList.add(_titleScreenSpriteIndex, 0, 0, 0);
187 
188 }
189 
buildDrawList1(DrawList & drawList)190 void MinigameBbAirGuitar::buildDrawList1(DrawList &drawList) {
191 
192 	for (int i = 0; i < kMaxObjectsCount; ++i) {
193 		Obj *obj = &_objects[i];
194 		if (obj->kind)
195 			drawList.add(obj->anim->frameIndices[obj->frameIndex], obj->x, obj->y, 255 - i);
196 	}
197 
198 	if (_movingTrackBar) {
199 		_trackBarX = _trackBarMouseX;
200 	} else if (_totalTrackLength > 0) {
201 		_trackBarX = 100 * _currTrackPos / _totalTrackLength + kTrackBarMinX;
202 	} else {
203 		_trackBarX = kTrackBarMinX;
204 	}
205 
206 	if (_trackBarX > kTrackBarMaxX)
207 		_trackBarX = kTrackBarMaxX;
208 
209 	_trackBarThumbRect.top = 208;
210 	_trackBarThumbRect.bottom = 218;
211 	_trackBarThumbRect.left = _trackBarX;
212 	_trackBarThumbRect.right = _trackBarX + 6;
213 
214 	drawList.add(_objects[5].anim->frameIndices[0], _trackBarX, 208, 100);
215 
216 	if (_playerMode != 0) {
217 		for (int i = 36; i < _vuMeterLeft2 + 36; ++i) {
218 			int frameIndex = 0;
219 			if (i >= 45)
220 				frameIndex = 3;
221 			else if (i >= 43)
222 				frameIndex = 2;
223 			else if (i >= 41)
224 				frameIndex = 1;
225 			drawList.add(_objects[i].anim->frameIndices[frameIndex], kPointsTbl1[i - 36].x, kPointsTbl1[i - 36].y, 254);
226 		}
227 		for (int i = 47; i < _vuMeterRight2 + 47; ++i) {
228 			int frameIndex = 0;
229 			if (i >= 56)
230 				frameIndex = 3;
231 			else if (i >= 54)
232 				frameIndex = 2;
233 			else if (i >= 52)
234 				frameIndex = 1;
235 			drawList.add(_objects[i].anim->frameIndices[frameIndex], kPointsTbl2[i - 47].x, kPointsTbl2[i - 47].y, 254);
236 		}
237 	}
238 
239 	if (_backgroundSpriteIndex > 0)
240 		drawList.add(_backgroundSpriteIndex, 0, 0, 0);
241 
242 }
243 
drawSprites()244 void MinigameBbAirGuitar::drawSprites() {
245 	DrawList drawList;
246 	buildDrawList(drawList);
247 	_vm->_screen->drawDrawList(drawList, _spriteModule);
248 	_vm->_screen->copyToScreen();
249 }
250 
initObjs()251 void MinigameBbAirGuitar::initObjs() {
252 	for (int i = 0; i < kMaxObjectsCount; ++i)
253 		_objects[i].kind = 0;
254 }
255 
getFreeObject()256 MinigameBbAirGuitar::Obj *MinigameBbAirGuitar::getFreeObject() {
257 	for (int i = 0; i < kMaxObjectsCount; ++i)
258 		if (_objects[i].kind == 0)
259 			return &_objects[i];
260 	return 0;
261 }
262 
initObjects()263 void MinigameBbAirGuitar::initObjects() {
264 	switch (_gameState) {
265 	case 0:
266 		initObjects0();
267 		break;
268 	case 1:
269 		initObjects1();
270 		break;
271 	default:
272 		break;
273 	}
274 }
275 
initObjects0()276 void MinigameBbAirGuitar::initObjects0() {
277 	_objects[0].anim = getAnimation(0);
278 	_objects[0].frameIndex = 0;
279 	_objects[0].ticks = getAnimation(0)->frameTicks[0];
280 	_objects[0].x = 160;
281 	_objects[0].y = 120;
282 	_objects[0].kind = 1;
283 	_objects[1].anim = getAnimation(37);
284 	_objects[1].frameIndex = 0;
285 	_objects[1].ticks = getAnimation(37)->frameTicks[0];
286 	_objects[1].x = 40;
287 	_objects[1].y = 240;
288 	_objects[1].kind = 2;
289 	_objects[2].anim = getAnimation(36);
290 	_objects[2].frameIndex = 0;
291 	_objects[2].ticks = getAnimation(36)->frameTicks[0];
292 	_objects[2].x = 280;
293 	_objects[2].y = 240;
294 	_objects[2].kind = 2;
295 
296 }
297 
initObjects1()298 void MinigameBbAirGuitar::initObjects1() {
299 
300 	for (int i = 0; i < 60; ++i)
301 		_objects[i].kind = 0;
302 
303 	_objects[0].kind = 0;
304 	_objects[0].kind = 1;
305 	_objects[0].anim = getAnimation(0);
306 	_objects[0].ticks = getAnimation(0)->frameTicks[0];
307 	_objects[1].anim = getAnimation(1);
308 	_objects[1].ticks = getAnimation(1)->frameTicks[0];
309 	_objects[2].anim = getAnimation(2);
310 	_objects[2].ticks = getAnimation(2)->frameTicks[0];
311 	_objects[3].anim = getAnimation(3);
312 	_objects[3].ticks = getAnimation(3)->frameTicks[0];
313 	_objects[4].anim = getAnimation(4);
314 	_objects[4].ticks = getAnimation(4)->frameTicks[0];
315 	_objects[5].anim = getAnimation(5);
316 	_objects[5].ticks = getAnimation(5)->frameTicks[0];
317 	_objects[6].anim = getAnimation(6);
318 	_objects[6].ticks = getAnimation(6)->frameTicks[0];
319 	_objects[7].anim = getAnimation(8);
320 	_objects[7].ticks = getAnimation(8)->frameTicks[0];
321 	_objects[8].anim = getAnimation(9);
322 	_objects[8].ticks = getAnimation(9)->frameTicks[0];
323 	_objects[9].anim = getAnimation(10);
324 	_objects[9].ticks = getAnimation(10)->frameTicks[0];
325 	_objects[10].anim = getAnimation(11);
326 	_objects[10].ticks = getAnimation(11)->frameTicks[0];
327 	_objects[11].anim = getAnimation(12);
328 	_objects[11].ticks = getAnimation(12)->frameTicks[0];
329 	_objects[12].anim = getAnimation(13);
330 	_objects[12].ticks = getAnimation(13)->frameTicks[0];
331 	_objects[13].anim = getAnimation(14);
332 	_objects[13].ticks = getAnimation(14)->frameTicks[0];
333 	_objects[14].anim = getAnimation(15);
334 	_objects[14].ticks = getAnimation(15)->frameTicks[0];
335 	_objects[15].anim = getAnimation(16);
336 	_objects[15].ticks = getAnimation(16)->frameTicks[0];
337 	_objects[16].anim = getAnimation(17);
338 	_objects[16].ticks = getAnimation(17)->frameTicks[0];
339 	_objects[17].anim = getAnimation(18);
340 	_objects[17].ticks = getAnimation(18)->frameTicks[0];
341 	_objects[18].anim = getAnimation(19);
342 	_objects[18].ticks = getAnimation(19)->frameTicks[0];
343 	_objects[19].anim = getAnimation(20);
344 	_objects[19].ticks = getAnimation(20)->frameTicks[0];
345 	_objects[20].anim = getAnimation(21);
346 	_objects[20].ticks = getAnimation(21)->frameTicks[0];
347 	_objects[21].anim = getAnimation(11);
348 	_objects[21].ticks = getAnimation(11)->frameTicks[0];
349 	_objects[22].anim = getAnimation(22);
350 	_objects[22].ticks = getAnimation(22)->frameTicks[0];
351 	_objects[23].anim = getAnimation(23);
352 	_objects[23].ticks = getAnimation(23)->frameTicks[0];
353 	_objects[24].anim = getAnimation(24);
354 	_objects[24].ticks = getAnimation(24)->frameTicks[0];
355 	_objects[25].anim = getAnimation(25);
356 	_objects[25].ticks = getAnimation(25)->frameTicks[0];
357 	_objects[26].anim = getAnimation(26);
358 	_objects[26].ticks = getAnimation(26)->frameTicks[0];
359 	_objects[27].anim = getAnimation(27);
360 	_objects[27].ticks = getAnimation(27)->frameTicks[0];
361 	_objects[28].anim = getAnimation(28);
362 	_objects[28].ticks = getAnimation(28)->frameTicks[0];
363 	_objects[29].anim = getAnimation(29);
364 	_objects[29].ticks = getAnimation(29)->frameTicks[0];
365 	_objects[30].anim = getAnimation(30);
366 	_objects[30].ticks = getAnimation(30)->frameTicks[0];
367 	_objects[31].anim = getAnimation(31);
368 	_objects[31].ticks = getAnimation(31)->frameTicks[0];
369 	_objects[32].anim = getAnimation(32);
370 	_objects[32].ticks = getAnimation(32)->frameTicks[0];
371 	_objects[33].anim = getAnimation(33);
372 	_objects[33].ticks = getAnimation(33)->frameTicks[0];
373 	_objects[34].anim = getAnimation(34);
374 	_objects[34].ticks = getAnimation(34)->frameTicks[0];
375 	_objects[35].anim = getAnimation(35);
376 	_objects[35].ticks = getAnimation(35)->frameTicks[0];
377 
378 	for (int i = 36; i <= 57; ++i) {
379 		_objects[i].anim = getAnimation(7);
380 		_objects[i].ticks = getAnimation(7)->frameTicks[0];
381 	}
382 
383 	for (int i = 1; i <= 35; ++i) {
384 		_objects[i].x = kObjPoints[i - 1].x;
385 		_objects[i].y = kObjPoints[i - 1].y;
386 	}
387 
388 	_objects[22].kind = 1;
389 	_objects[6].kind = 1;
390 	_objects[26].kind = 1;
391 	_objects[26].frameIndex = 3;
392 	_objects[27].kind = 1;
393 	_objects[27].frameIndex = 3;
394 	_objects[31].kind = 1;
395 	_objects[31].frameIndex = 3;
396 	_objects[32].kind = 1;
397 	_objects[32].frameIndex = 3;
398 	_objects[28].kind = 1;
399 	_objects[33].kind = 1;
400 	_objects[34].kind = 1;
401 	_objects[35].kind = 1;
402 
403 	_track[0].noteNum = -1;
404 	stop();
405 	changePatch(0);
406 
407 }
408 
updateStatus(int mouseX,int mouseY,uint mouseButtons)409 bool MinigameBbAirGuitar::updateStatus(int mouseX, int mouseY, uint mouseButtons) {
410 	switch (_gameState) {
411 	case 0:
412 		return updateStatus0(mouseX, mouseY, mouseButtons);
413 	case 1:
414 		return updateStatus1(mouseX, mouseY, mouseButtons);
415 	default:
416 		break;
417 	}
418 	return false;
419 }
420 
updateStatus0(int mouseX,int mouseY,uint mouseButtons)421 bool MinigameBbAirGuitar::updateStatus0(int mouseX, int mouseY, uint mouseButtons) {
422 
423 	if (mouseButtons & kAnyButtonDown) {
424 		stopSound(1);
425 		_rockTunePlaying = false;
426 		_gameState = 1;
427 		initObjects();
428 		_gameTicks = 0;
429 	} else {
430 
431 		if (!_rockTunePlaying) {
432 			_rockTunePlaying = true;
433 			playSound(1, true);
434 		}
435 
436 		_objects[0].x = mouseX;
437 		_objects[0].y = mouseY;
438 
439 		for (int i = 1; i < kMaxObjectsCount; ++i) {
440 			Obj *obj = &_objects[i];
441 			if (obj->kind && --obj->ticks == 0) {
442 				++obj->frameIndex;
443 				if (obj->frameIndex >= obj->anim->frameCount)
444 					obj->frameIndex = 0;
445 				obj->ticks = obj->anim->frameTicks[obj->frameIndex];
446 			}
447 		}
448 
449 	}
450 
451   	return true;
452 }
453 
updateStatus1(int mouseX,int mouseY,uint mouseButtons)454 bool MinigameBbAirGuitar::updateStatus1(int mouseX, int mouseY, uint mouseButtons) {
455 
456 	int currTicks = _vm->_system->getMillis();
457 
458 	if (_playerMode == 1 && _track[_trackIndex].ticks <= currTicks - _noteStartTime) {
459 		noteOff(_track[_trackIndex].noteNum);
460 		if (_trackIndex < _trackCount && _track[++_trackIndex].noteNum != -1)
461 			noteOn(_track[_trackIndex].noteNum);
462 		else
463 			stop();
464 	}
465 
466 	if (_vuMeterLeft1 - 2 <= _vuMeterLeft2) {
467 		if (_vuMeterLeft1 + 1 >= _vuMeterLeft2) {
468 			int incr = MIN(_vm->getRandom(4), 2) - 1;
469 			if (incr < 0 && _vuMeterLeft2 == 0)
470 				incr = -incr;
471 			if (incr > 0 && _vuMeterLeft2 == 11)
472 				incr = -incr;
473 			_vuMeterLeft2 += incr;
474 		} else {
475 			--_vuMeterLeft2;
476 		}
477 	} else {
478 		++_vuMeterLeft2;
479 	}
480 
481 	if (_vuMeterRight1 - 2 <= _vuMeterRight2) {
482 		if (_vuMeterRight1 + 1 >= _vuMeterRight2) {
483 			int incr = MIN(_vm->getRandom(4), 2) - 1;
484 			if (incr < 0 && _vuMeterRight2 == 0)
485 				incr = -incr;
486 			if (incr > 0 && _vuMeterRight2 == 11)
487 				incr = -incr;
488 			_vuMeterRight2 += incr;
489 		} else {
490 			--_vuMeterRight2;
491 		}
492 	} else {
493 		++_vuMeterRight2;
494 	}
495 
496 	if (_resetAnims && _vm->_system->getMillis() - _noteStartTime >= 1000)
497 		resetObjs();
498 
499 	_objects[0].x = mouseX;
500 	_objects[0].y = mouseY;
501 
502 	_trackBarMouseX = CLIP(mouseX, kTrackBarMinX, kTrackBarMaxX);
503 
504 	bool checkClick = false;
505 
506 	if (mouseButtons & kAnyButtonClicked) {
507 		checkClick = true;
508 	} else if (!(mouseButtons & kAnyButtonDown)) {
509 		afterButtonReleased();
510 	} else if (!_movingTrackBar && ((_currButtonNum >= 14 && ptInPoly(_currPianoKeyArea, mouseX, mouseY)) || ptInRect(_currPlayerButtonRect, mouseX, mouseY))) {
511 		if (_currButtonNum == 5 && _trackIndex > 0) {
512 			--_trackIndex;
513 			calcTotalTicks2();
514 		} else if (_currButtonNum == 13 && _trackIndex < _trackCount) {
515 			++_trackIndex;
516 			calcTotalTicks2();
517 		}
518 	} else if (!_movingTrackBar)
519 		checkClick = true;
520 
521 	if (checkClick) {
522 
523 		afterButtonReleased();
524 		_objects[0].frameIndex = 1;
525 
526 		if (ptInRect(&kRect2, mouseX, mouseY)) {
527 
528 			if (_playerMode != 1 && ptInRect(&kPianoRect, mouseX, mouseY)) {
529 				for (int i = 0; i <= 12; ++i) {
530 					if (ptInPoly(&kPianoKeyAreas[i], mouseX, mouseY)) {
531 						_currButtonNum = i + 14;
532 						_currPianoKeyArea = &kPianoKeyAreas[i];
533 						_objects[11].kind = 1;
534 						_objects[11].x = kPianoKeyInfos[i].x;
535 						_objects[11].y = kPianoKeyInfos[i].y;
536 						_objects[11].frameIndex = kPianoKeyInfos[i].frameIndex;
537 						noteOn(i);
538 						break;
539 					}
540 				}
541 			} else if (_playerMode != 1 && ptInRect(&_trackBarThumbRect, mouseX, mouseY)) {
542 				_movingTrackBar = true;
543 			} else {
544 
545 				int playerButtonNum = -1;
546 				for (int i = 0; i < 14; ++i) {
547 					if (ptInRect(&kPlayerButtonRects[i], mouseX, mouseY)) {
548 						playerButtonNum = i;
549 						break;
550 					}
551 				}
552 
553 				if (playerButtonNum >= 0) {
554 					_currButtonNum = playerButtonNum;
555 					_currPlayerButtonRect = &kPlayerButtonRects[playerButtonNum];
556 
557 					switch (playerButtonNum) {
558 
559 					case 0:
560 						if (_playerMode == 0) {
561 							changePatch(0);
562 							_currFrameIndex = &_objects[18 + 0].frameIndex;
563 							*_currFrameIndex = 0;
564 						}
565 						break;
566 
567 					case 1:
568 						if (_playerMode == 0) {
569 							changePatch(1);
570 							_currFrameIndex = &_objects[18 + 1].frameIndex;
571 							*_currFrameIndex = 0;
572 						}
573 						break;
574 
575 					case 2:
576 						if (_playerMode == 0) {
577 							changePatch(2);
578 							_currFrameIndex = &_objects[18 + 2].frameIndex;
579 							*_currFrameIndex = 0;
580 						}
581 						break;
582 
583 					case 3:
584 						_btn3KindToggle = !_btn3KindToggle;
585 						_objects[9].kind = _btn3KindToggle ? 0 : 1;
586 						_objects[22].frameIndex = _btn3KindToggle ? 0 : 1;
587 						break;
588 
589 					case 4:
590 						if (_playerMode == 0) {
591 							_objects[1].kind = 1;
592 							_currFrameIndex = &_objects[1].frameIndex;
593 							_objects[1].frameIndex = 0;
594 						}
595 						break;
596 
597 					case 5:
598 						if (_playerMode == 0) {
599 							if (_trackIndex > 0)
600 								--_trackIndex;
601 							_objects[3].kind = 1;
602 							calcTotalTicks2();
603 						}
604 						break;
605 
606 					case 6:
607 						stop();
608 						_currFrameIndex = &_objects[15].frameIndex;
609 						_objects[15].frameIndex = 0;
610 						break;
611 
612 					case 7:
613 						if (_playerMode == 0) {
614 							play();
615 							_currFrameIndex = &_objects[12].frameIndex;
616 							_objects[12].frameIndex = 0;
617 						}
618 						break;
619 
620 					case 8:
621 						if (_playerMode == 0) {
622 							_trackIndex = 0;
623 							_objects[16].kind = 1;
624 							calcTotalTicks2();
625 						}
626 						break;
627 
628 					case 9:
629 						if (_playerMode == 0) {
630 							_trackIndex = _trackCount;
631 							_objects[17].kind = 1;
632 							calcTotalTicks2();
633 						}
634 						break;
635 
636 					case 10:
637 						if (_playerMode == 0) {
638 							record();
639 							_currFrameIndex = &_objects[13].frameIndex;
640 							_objects[13].frameIndex = 0;
641 						}
642 						break;
643 
644 					case 11:
645 						if (_playerMode == 0) {
646 							setPlayerMode3();
647 							_currFrameIndex = &_objects[14].frameIndex;
648 							_objects[14].frameIndex = 0;
649 						}
650 						break;
651 
652 					case 12:
653 						if (_playerMode == 0) {
654 							_objects[2].kind = 1;
655 							_currFrameIndex = &_objects[2].frameIndex;
656 							_objects[2].frameIndex = 0;
657 						}
658 						break;
659 
660 					case 13:
661 						if (_playerMode == 0) {
662 							if (_trackIndex < _trackCount)
663 								++_trackIndex;
664 							_objects[4].kind = 1;
665 							calcTotalTicks2();
666 						}
667 						break;
668 
669 					default:
670 						break;
671 					}
672 				}
673 			}
674 		}
675 	}
676 
677 	if (_playerMode != 0) {
678 		_currTrackPos = currTicks + _actionStartTrackPos - _actionStartTime;
679 		if (_currTrackPos > _actionTrackPos && _playerMode != 1) {
680 			if (_currTrackPos >= 15000) {
681 				_currTrackPos = 15000;
682 				_actionTrackPos = 15000;
683 				stop();
684 			} else {
685 				_actionTrackPos = currTicks + _actionStartTrackPos - _actionStartTime;
686 			}
687 		}
688 	}
689 
690 	if (_buttonClickTicks + 1000 < currTicks)
691 		_buttonClickTicks = currTicks;
692 
693 	int newKind = _buttonClickTicks + 500 < currTicks ? 1 : 0;
694 
695 	switch (_playerMode) {
696 
697 	case 1:
698 		if (_currButtonNum == 7) {
699 			_objects[12].kind = 1;
700 			_objects[12].frameIndex = 0;
701 		} else {
702 			_objects[12].kind = newKind;
703 			_objects[12].frameIndex = 1;
704 		}
705 		break;
706 
707 	case 2:
708 		if (_currButtonNum == 10) {
709 			_objects[13].kind = 1;
710 			_objects[13].frameIndex = 0;
711 		} else {
712 			_objects[13].kind = newKind;
713 			_objects[13].frameIndex = 1;
714 		}
715 		break;
716 
717 	case 3:
718 		if (_currButtonNum == 11) {
719 			_objects[14].kind = 1;
720 			_objects[14].frameIndex = 0;
721 		} else {
722 			_objects[14].kind = newKind;
723 			_objects[14].frameIndex = 1;
724 		}
725 		break;
726 
727 	default:
728 		break;
729 	}
730 
731 	updateObjs();
732 
733 	return true;
734 }
735 
updateObjs()736 void MinigameBbAirGuitar::updateObjs() {
737 	for (int i = 24; i <= 33; ++i) {
738 		Obj *obj = &_objects[i];
739 		if (obj->kind && --obj->ticks == 0) {
740 			if (obj->frameIndex + 1 >= obj->anim->frameCount) {
741 				obj->ticks = -1;
742 			} else {
743 				++obj->frameIndex;
744 				obj->ticks = obj->anim->frameTicks[obj->frameIndex];
745 			}
746 		}
747 	}
748 }
749 
run(bool fromMainGame)750 bool MinigameBbAirGuitar::run(bool fromMainGame) {
751 
752 	memset(_objects, 0, sizeof(_objects));
753 
754 	_modified = false;
755 	_currPatchNum = -1;
756 	_btn3KindToggle = 0;
757 	_currButtonNum = 27;
758 	_actionStartTime = 0;
759 	_currFrameIndex = 0;
760 	_currPlayerButtonRect = 0;
761 	_currPianoKeyArea = 0;
762 	_trackCount = 0;
763 	_trackIndex = 0;
764 	_totalTrackLength = 0;
765 	_actionTrackPos = 0;
766 	_noteStartTime = 0;
767 	_actionStartTrackPos = 0;
768 	_trackBarX = kTrackBarMinX;
769 	_currTrackPos = 0;
770 	_currNoteNum = -2;
771 	_resetAnims = false;
772 	_vuMeterLeft2 = 0;
773 	_vuMeterRight2 = 0;
774 	_vuMeterLeft1 = 0;
775 	_vuMeterRight1 = 0;
776 	_rockTunePlaying = false;
777 
778 	_backgroundSpriteIndex = 97;
779 	_titleScreenSpriteIndex = 98;
780 
781 	_fromMainGame = fromMainGame;
782 
783 	_gameState = 0;
784 	_gameTicks = 0;
785 	_gameResult = false;
786 	_gameDone = false;
787 	initObjects();
788 
789 	_spriteModule = new SpriteModule();
790 	_spriteModule->load("bbairg/bbairg.000");
791 
792 	Palette palette = _spriteModule->getPalette();
793 	_vm->_screen->setPalette(palette);
794 
795 	loadSounds();
796 
797 	while (!_vm->shouldQuit() &&!_gameDone) {
798 		_vm->updateEvents();
799 		update();
800 	}
801 
802 	_vm->_sound->unloadSounds();
803 
804 	delete _spriteModule;
805 
806 	return _gameResult;
807 }
808 
update()809 void MinigameBbAirGuitar::update() {
810 
811 	int inputTicks;
812 
813 	if (_gameTicks > 0) {
814 		int currTicks = _vm->_system->getMillis();
815 		inputTicks = 3 * (currTicks - _gameTicks) / 50;
816 		_gameTicks = currTicks - (currTicks - _gameTicks - 50 * inputTicks / 3);
817 	} else {
818 		inputTicks = 1;
819 		_gameTicks = _vm->_system->getMillis();
820 	}
821 
822 	if (_vm->_keyCode == Common::KEYCODE_ESCAPE) {
823 		_gameDone = querySaveModifiedTracks();
824 		return;
825 	}
826 
827 	if (inputTicks == 0)
828 		return;
829 
830 	bool done;
831 
832 	do {
833 		done = !updateStatus(_vm->_mouseX, _vm->_mouseY, _vm->_mouseButtons);
834 		_vm->_mouseButtons &= ~kLeftButtonClicked;
835 		_vm->_mouseButtons &= ~kRightButtonClicked;
836 		_vm->_keyCode = Common::KEYCODE_INVALID;
837 	} while (--inputTicks && _gameTicks > 0 && !done);
838 
839 	drawSprites();
840 
841 	_vm->_system->delayMillis(10);
842 
843 }
844 
play()845 void MinigameBbAirGuitar::play() {
846 	if (_track[_trackIndex].noteNum != -1) {
847 		_playerMode = 1;
848 		_objects[7].kind = 1;
849 		_objects[8].kind = 0;
850 		_objects[15].kind = 0;
851 		_actionStartTime = _vm->_system->getMillis();
852 		_actionStartTrackPos = _currTrackPos;
853 		noteOn(_track[_trackIndex].noteNum);
854 	}
855 }
856 
857 
record()858 void MinigameBbAirGuitar::record() {
859 	_playerMode = 2;
860 	_objects[7].kind = 1;
861 	_objects[8].kind = 0;
862 	_objects[15].kind = 0;
863 	_totalTrackLength = 15000;
864 	_actionStartTime = _vm->_system->getMillis();
865 	_actionStartTrackPos = _currTrackPos;
866 	_noteStartTime = _vm->_system->getMillis();
867 	_actionTrackPos = _currTrackPos;
868 	_trackCount = _trackIndex;
869 	_vuMeterRight1 = 0;
870 	_vuMeterRight2 = 0;
871 	_vuMeterLeft1 = 0;
872 	_vuMeterLeft2 = 0;
873 	_modified = true;
874 	_track[_trackIndex].noteNum = -2;
875 }
876 
setPlayerMode3()877 void MinigameBbAirGuitar::setPlayerMode3() {
878 	_playerMode = 3;
879 	_objects[7].kind = 1;
880 	_objects[8].kind = 0;
881 	_objects[15].kind = 0;
882 	_totalTrackLength = 15000;
883 	_actionStartTime = _vm->_system->getMillis();
884 	_actionStartTrackPos = _currTrackPos;
885 	_noteStartTime = _vm->_system->getMillis();
886 	_actionTrackPos = _currTrackPos;
887 	_trackCount = _trackIndex;
888 	_vuMeterRight1 = 0;
889 	_vuMeterRight2 = 0;
890 	_vuMeterLeft1 = 0;
891 	_vuMeterLeft2 = 0;
892 	_modified = true;
893 	_track[_trackIndex].noteNum = -2;
894 }
895 
stop()896 void MinigameBbAirGuitar::stop() {
897 	noteOff(_currNoteNum);
898 	if (_playerMode == 2 || _playerMode == 3) {
899 		_totalTrackLength = _actionTrackPos;
900 		_track[_trackCount].noteNum = -1;
901 	}
902 	_playerMode = 0;
903 	_objects[7].kind = 0;
904 	_objects[8].kind = 1;
905 	_objects[15].kind = 1;
906 	_objects[15].frameIndex = 1;
907 	_objects[12].kind = 0;
908 	_objects[13].kind = 0;
909 	_objects[14].kind = 0;
910 	resetObjs();
911 }
912 
changePatch(int patchNum)913 void MinigameBbAirGuitar::changePatch(int patchNum) {
914 
915 	resetObjs();
916 
917 	if (patchNum == -1 || patchNum != _currPatchNum)
918 		_currPatchNum = -1;
919 
920 	_objects[20].kind = 0;
921 	_objects[19].kind = _objects[20].kind;
922 	_objects[18].kind = _objects[19].kind;
923 	_objects[patchNum + 18].kind = 1;
924 	_objects[patchNum + 18].frameIndex = 1;
925 	_objects[6].frameIndex = patchNum;
926 	_currPatchNum = patchNum;
927 }
928 
afterButtonReleased()929 void MinigameBbAirGuitar::afterButtonReleased() {
930 	if (_movingTrackBar) {
931 		_movingTrackBar = false;
932 		_currTrackPos = _totalTrackLength * (_trackBarX - kTrackBarMinX) / 100;
933 		calcTotalTicks1();
934 	} else {
935 		switch (_currButtonNum) {
936 		case 0:
937 		case 1:
938 		case 2:
939 			*_currFrameIndex = 1;
940 			break;
941 		case 3:
942 			break;
943 		case 4:
944 			*_currFrameIndex = 1;
945 			loadTracks();
946 			_objects[1].kind = 0;
947 			break;
948 		case 5:
949 			_objects[3].kind = 0;
950 			break;
951 		case 6:
952 			*_currFrameIndex = 1;
953 			break;
954 		case 7:
955 			*_currFrameIndex = 1;
956 			break;
957 		case 8:
958 			_objects[16].kind = 0;
959 			break;
960 		case 9:
961 			_objects[17].kind = 0;
962 			break;
963 		case 10:
964 			*_currFrameIndex = 1;
965 			break;
966 		case 11:
967 			*_currFrameIndex = 1;
968 			break;
969 		case 12:
970 			*_currFrameIndex = 1;
971 			saveTracks();
972 			_objects[2].kind = 0;
973 			break;
974 		case 13:
975 			_objects[4].kind = 0;
976 			break;
977 		case 14:
978 		case 15:
979 		case 16:
980 		case 17:
981 		case 18:
982 		case 19:
983 		case 20:
984 		case 21:
985 		case 22:
986 		case 23:
987 		case 24:
988 		case 25:
989 		case 26:
990 			noteOff(_currButtonNum - 14);
991 			break;
992 		default:
993 			break;
994 		}
995 	}
996 
997 	_objects->frameIndex = 0;
998 	_currPlayerButtonRect = 0;
999 	_currPianoKeyArea = 0;
1000 	_currButtonNum = 27;
1001 }
1002 
calcTotalTicks2()1003 void MinigameBbAirGuitar::calcTotalTicks2() {
1004 	_currTrackPos = 0;
1005 	for (int i = 0; i < _trackIndex; ++i)
1006 		_currTrackPos += _track[i].ticks;
1007 }
1008 
calcTotalTicks1()1009 void MinigameBbAirGuitar::calcTotalTicks1() {
1010 	int totalTicks = 0;
1011 	// TODO Try to clean this up
1012 	_trackIndex = 0;
1013 	if (_track[0].ticks <= _currTrackPos) {
1014 		do {
1015 			totalTicks += _track[_trackIndex].ticks;
1016 			if (_trackIndex >= _trackCount)
1017 				break;
1018 			++_trackIndex;
1019 		} while (totalTicks + _track[_trackIndex].ticks <= _currTrackPos);
1020 	}
1021 	_currTrackPos = totalTicks;
1022 }
1023 
noteOn(int noteNum)1024 void MinigameBbAirGuitar::noteOn(int noteNum) {
1025 
1026 	if (_currNoteNum != -2) {
1027 		if (noteNum == _currNoteNum)
1028 			return;
1029 		noteOff(_currNoteNum);
1030 	}
1031 
1032 	if (noteNum == -2) {
1033 		_vuMeterRight1 = 0;
1034 		_vuMeterRight2 = 0;
1035 		_vuMeterLeft1 = 0;
1036 		_vuMeterLeft2 = 0;
1037 	} else {
1038 		playNote(noteNum);
1039 		_vuMeterRight1 = 10;
1040 		_vuMeterRight2 = 10;
1041 		_vuMeterLeft1 = 10;
1042 		_vuMeterLeft2 = 10;
1043 		if (_btn3KindToggle) {
1044 			_objects[23].kind = 1;
1045 			_objects[23].frameIndex = noteNum;
1046 		} else {
1047 			_objects[10].kind = 1;
1048 			_objects[10].frameIndex = kNoteFrameTbl[noteNum].frameIndex;
1049 			if (kNoteFrameTbl[noteNum].flag) {
1050 				_objects[21].kind = 1;
1051 				_objects[21].frameIndex = 7;
1052 			}
1053 		}
1054 	}
1055 
1056 	_currNoteNum = noteNum;
1057 
1058 	if (_playerMode == 2 || _playerMode == 3) {
1059 		_ticksDelta = _vm->_system->getMillis() - _noteStartTime;
1060 		_track[_trackCount].ticks = _ticksDelta;
1061 		if (_trackCount < kMaxTracks - 1)
1062 			++_trackCount;
1063 		_track[_trackCount].noteNum = noteNum;
1064 	}
1065 
1066 	_noteStartTime = _vm->_system->getMillis();
1067 
1068 	if (noteNum != -2) {
1069 		_resetAnims = false;
1070 		if (_currPatchNum == 0) {
1071 			_objects[25].kind = 1;
1072 			_objects[28].kind = 0;
1073 			_objects[25].frameIndex = 0;
1074 			_objects[25].ticks = getAnimation(25)->frameTicks[0];
1075 			_objects[26].frameIndex = 0;
1076 			_objects[26].ticks = getAnimation(26)->frameTicks[0];
1077 			_objects[27].frameIndex = 0;
1078 			_objects[27].ticks = getAnimation(27)->frameTicks[0];
1079 			_objects[30].kind = 1;
1080 			_objects[33].kind = 0;
1081 			_objects[30].frameIndex = 0;
1082 			_objects[30].ticks = getAnimation(30)->frameTicks[0];
1083 			_objects[31].frameIndex = 0;
1084 			_objects[31].ticks = getAnimation(31)->frameTicks[0];
1085 			_objects[32].frameIndex = 0;
1086 			_objects[32].ticks = getAnimation(32)->frameTicks[0];
1087 		} else if (_currPatchNum == 1) {
1088 			_objects[29].kind = 1;
1089 			_objects[33].kind = 0;
1090 			_objects[29].frameIndex = 0;
1091 			_objects[29].ticks = getAnimation(29)->frameTicks[0];
1092 			_objects[31].frameIndex = 0;
1093 			_objects[31].ticks = getAnimation(31)->frameTicks[0];
1094 			_objects[32].frameIndex = 0;
1095 			_objects[32].ticks = getAnimation(32)->frameTicks[0];
1096 		} else if (_currPatchNum == 2) {
1097 			_objects[24].kind = 1;
1098 			_objects[28].kind = 0;
1099 			_objects[24].frameIndex = 0;
1100 			_objects[24].ticks = getAnimation(24)->frameTicks[0];
1101 			_objects[26].frameIndex = 0;
1102 			_objects[26].ticks = getAnimation(26)->frameTicks[0];
1103 			_objects[27].frameIndex = 0;
1104 			_objects[27].ticks = getAnimation(27)->frameTicks[0];
1105 		}
1106 	}
1107 
1108 }
1109 
noteOff(int noteNum)1110 void MinigameBbAirGuitar::noteOff(int noteNum) {
1111 
1112 	if (_currNoteNum != noteNum)
1113 		return;
1114 
1115 	if (noteNum != -2)
1116 		stopNote(noteNum);
1117 
1118 	_objects[21].kind = 0;
1119 	_objects[23].kind = _objects[21].kind;
1120 	_objects[10].kind = _objects[23].kind;
1121 
1122 	_vuMeterRight1 = 0;
1123 	_vuMeterRight2 = 0;
1124 	_vuMeterLeft1 = 0;
1125 	_vuMeterLeft2 = 0;
1126 
1127 	_currNoteNum = -2;
1128 
1129 	_objects[11].kind = 0;
1130 
1131 	_ticksDelta = _vm->_system->getMillis() - _noteStartTime;
1132 
1133 	if (_playerMode == 2 || _playerMode == 3) {
1134 		if (_actionTrackPos + _ticksDelta > 15000)
1135 			_ticksDelta = 15000 - _actionTrackPos;
1136 		_track[_trackCount].ticks = _ticksDelta;
1137 		if (_trackCount + 1 < 2048)
1138 			++_trackCount;
1139 		_track[_trackCount].noteNum = -2;
1140 		_noteStartTime = _vm->_system->getMillis();
1141 	}
1142 
1143 	if (noteNum != -2) {
1144 		if (_playerMode == 0) {
1145 			_resetAnims = true;
1146 			_noteStartTime = _vm->_system->getMillis();
1147 		}
1148 		if (_currPatchNum == 0) {
1149 			_objects[25].frameIndex = 3;
1150 			_objects[25].ticks = -1;
1151 			_objects[26].frameIndex = 3;
1152 			_objects[26].ticks = -1;
1153 			_objects[27].frameIndex = 3;
1154 			_objects[27].ticks = -1;
1155 			_objects[30].frameIndex = 3;
1156 			_objects[30].ticks = -1;
1157 			_objects[31].frameIndex = 3;
1158 			_objects[31].ticks = -1;
1159 			_objects[32].frameIndex = 3;
1160 			_objects[32].ticks = -1;
1161 		} else if (_currPatchNum == 1) {
1162 			_objects[29].frameIndex = 3;
1163 			_objects[29].ticks = -1;
1164 			_objects[31].frameIndex = 3;
1165 			_objects[31].ticks = -1;
1166 			_objects[32].frameIndex = 3;
1167 			_objects[32].ticks = -1;
1168 		} else if (_currPatchNum == 2) {
1169 			_objects[24].frameIndex = 2;
1170 			_objects[24].ticks = -1;
1171 			_objects[26].frameIndex = 3;
1172 			_objects[26].ticks = -1;
1173 			_objects[27].frameIndex = 3;
1174 			_objects[27].ticks = -1;
1175 		}
1176 	}
1177 
1178 }
1179 
resetObjs()1180 void MinigameBbAirGuitar::resetObjs() {
1181 	_resetAnims = false;
1182 	_objects[25].kind = 0;
1183 	_objects[24].kind = 0;
1184 	_objects[28].kind = 1;
1185 	_objects[26].frameIndex = 0;
1186 	_objects[26].ticks = -1;
1187 	_objects[27].frameIndex = 0;
1188 	_objects[27].ticks = -1;
1189 	_objects[30].kind = 0;
1190 	_objects[29].kind = 0;
1191 	_objects[33].kind = 1;
1192 	_objects[31].frameIndex = 0;
1193 	_objects[31].ticks = -1;
1194 	_objects[32].frameIndex = 0;
1195 	_objects[32].ticks = -1;
1196 }
1197 
loadSounds()1198 void MinigameBbAirGuitar::loadSounds() {
1199 	_vm->_sound->loadSound("bbairg/audio/rocktune.aif");
1200 	for (uint i = 0; i < kPatchDirectoriesCount; ++i) {
1201 		const char *patchDirectory = kPatchDirectories[i];
1202 		for (uint j = 0; j < kNoteSoundFilenamesCount; ++j) {
1203 			Common::String filename = Common::String::format("bbairg/audio/%s/%s", patchDirectory, kNoteSoundFilenames[j]);
1204 			_vm->_sound->loadSound(filename.c_str());
1205 		}
1206 	}
1207 }
1208 
playNote(int noteNum)1209 void MinigameBbAirGuitar::playNote(int noteNum) {
1210 	if (noteNum >= 0 && _currPatchNum >= 0)
1211 		playSound(2 + _currPatchNum * kNoteSoundFilenamesCount + noteNum);
1212 }
1213 
stopNote(int noteNum)1214 void MinigameBbAirGuitar::stopNote(int noteNum) {
1215 	if (noteNum >= 0 && _currPatchNum >= 0)
1216 		stopSound(2 + _currPatchNum * kNoteSoundFilenamesCount + noteNum);
1217 }
1218 
getLoadFilename(Common::String & filename)1219 bool MinigameBbAirGuitar::getLoadFilename(Common::String &filename) {
1220 	GUI::FileBrowserDialog browser(0, "air", GUI::kFBModeLoad);
1221 
1222 	if (browser.runModal() > 0) {
1223 		filename = browser.getResult();
1224 		return true;
1225 	}
1226 
1227 	return false;
1228 }
1229 
getSaveFilename(Common::String & filename)1230 bool MinigameBbAirGuitar::getSaveFilename(Common::String &filename) {
1231 	GUI::FileBrowserDialog browser(0, "air", GUI::kFBModeSave);
1232 
1233 	if (browser.runModal() > 0) {
1234 		filename = browser.getResult();
1235 		return true;
1236 	}
1237 
1238 	return false;
1239 }
1240 
querySaveModifiedDialog()1241 bool MinigameBbAirGuitar::querySaveModifiedDialog() {
1242 	/* NOTE The original button captions don't fit so shortened variants are used
1243 		Original ok button caption: "Yeah, heh, heh, save it!"
1244 		Original discard button caption: "Who cares?  It sucked!"
1245 	*/
1246 	GUI::MessageDialog query("Hey Beavis - you didn't save that last Jam!",
1247 		"Save it!",
1248 		"It sucked!");
1249 	return query.runModal() == GUI::kMessageOK;
1250 }
1251 
querySaveModifiedTracks()1252 bool MinigameBbAirGuitar::querySaveModifiedTracks() {
1253 	if (_modified && querySaveModifiedDialog()) {
1254 		if (!saveTracks())
1255 			return false;
1256 	}
1257 	return true;
1258 }
1259 
loadTracks()1260 bool MinigameBbAirGuitar::loadTracks() {
1261 	if (_playerMode != 0)
1262 		return false;
1263 
1264 	if (!querySaveModifiedTracks())
1265 		return false;
1266 
1267 	Common::String filename;
1268 	if (!getLoadFilename(filename))
1269 		return false;
1270 
1271 	Common::SaveFileManager *saveFileMan = g_system->getSavefileManager();
1272 	Common::InSaveFile *stream = saveFileMan->openForLoading(filename);
1273 	if (!loadFromStream(stream)) {
1274 		Common::String msg = Common::String::format("%s is not a valid Air Guitar file", filename.c_str());
1275 		GUI::MessageDialog dialog(msg);
1276 		dialog.runModal();
1277 	}
1278 	delete stream;
1279 
1280 	return true;
1281 }
1282 
saveTracks()1283 bool MinigameBbAirGuitar::saveTracks() {
1284 	if (_playerMode != 0)
1285 		return false;
1286 
1287 	Common::String filename;
1288 	if (!getSaveFilename(filename))
1289 		return false;
1290 
1291 	Common::SaveFileManager *saveFileMan = g_system->getSavefileManager();
1292 	Common::OutSaveFile *stream = saveFileMan->openForSaving(filename);
1293 	saveToStream(stream);
1294 	delete stream;
1295 	_modified = false;
1296 
1297 	return true;
1298 }
1299 
loadFromStream(Common::ReadStream * stream)1300 bool MinigameBbAirGuitar::loadFromStream(Common::ReadStream *stream) {
1301 	uint32 magic = stream->readUint32BE();
1302 	if (magic != MKTAG('A', 'I', 'R', 'G'))
1303 		return false;
1304 	for (uint i = 0; i < kMaxTracks; ++i) {
1305 		_track[i].noteNum = stream->readByte();
1306 		_track[i].ticks = stream->readUint16LE();
1307 	}
1308 	_trackCount = 0;
1309 	_actionTrackPos = 0;
1310 	while (_track[_trackCount].noteNum != -1) {
1311 		_actionTrackPos += _track[_trackCount].ticks;
1312 		++_trackCount;
1313 	}
1314 	_totalTrackLength = _actionTrackPos;
1315 	_trackIndex = 0;
1316 	_currTrackPos = 0;
1317 	return true;
1318 }
1319 
saveToStream(Common::WriteStream * stream)1320 void MinigameBbAirGuitar::saveToStream(Common::WriteStream *stream) {
1321 	stream->writeUint32BE(MKTAG('A', 'I', 'R', 'G'));
1322 	for (uint i = 0; i < kMaxTracks; ++i) {
1323 		stream->writeByte(_track[i].noteNum);
1324 		stream->writeUint16LE(_track[i].ticks);
1325 	}
1326 }
1327 
1328 } // End of namespace Bbvs
1329