scummvm/engines/bbvs/minigames/bbairguitar.cpp
2016-04-14 13:30:14 +03:00

1316 lines
34 KiB
C++

/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*/
#include "bbvs/minigames/bbairguitar.h"
#include "common/savefile.h"
#include "common/translation.h"
#include "gui/message.h"
#include "gui/filebrowser-dialog.h"
namespace Bbvs {
static const char * const kNoteSoundFilenames[] = {
"a.aif", "a#.aif", "b.aif", "c.aif", "c#.aif",
"d.aif", "d#.aif", "e.aif", "f.aif", "f#.aif",
"g.aif", "g#.aif", "a_oct.aif"
};
static const uint kNoteSoundFilenamesCount = ARRAYSIZE(kNoteSoundFilenames);
static const char * const kPatchDirectories[] = {
"rock", "burp", "fart"
};
static const uint kPatchDirectoriesCount = ARRAYSIZE(kPatchDirectories);
static const BBPoint kPianoKeyArea1[] = {{29, 192}, {38, 192}, {38, 222}, {41, 222}, {41, 239}, {29, 239}};
static const BBPoint kPianoKeyArea2[] = {{38, 192}, {43, 192}, {43, 222}, {38, 222}};
static const BBPoint kPianoKeyArea3[] = {{43, 192}, {49, 192}, {49, 222}, {52, 222}, {52, 239}, {41, 239}, {41, 222}, {43, 222}};
static const BBPoint kPianoKeyArea4[] = {{49, 192}, {54, 192}, {54, 222}, {49, 222}};
static const BBPoint kPianoKeyArea5[] = {{54, 192}, {63, 192}, {63, 239}, {52, 239}, {52, 222}, {54, 222}};
static const BBPoint kPianoKeyArea6[] = {{63, 192}, {71, 192}, {71, 222}, {74, 222}, {74, 239}, {63, 239}};
static const BBPoint kPianoKeyArea7[] = {{71, 192}, {76, 192}, {76, 222}, {71, 222}};
static const BBPoint kPianoKeyArea8[] = {{76, 192}, {82, 192}, {82, 222}, {85, 222}, {85, 239}, {74, 239}, {74, 222}, {76, 222}};
static const BBPoint kPianoKeyArea9[] = {{82, 192}, {87, 192}, {87, 222}, {82, 222}};
static const BBPoint kPianoKeyArea10[] = {{87, 192}, {94, 192}, {94, 222}, {96, 222}, {96, 239}, {85, 239}, {85, 222}, {87, 222}};
static const BBPoint kPianoKeyArea11[] = {{94, 192}, {99, 192}, {99, 222}, {94, 222}};
static const BBPoint kPianoKeyArea12[] = {{99, 192}, {107, 192}, {107, 239}, {96, 239}, {96, 222}, {99, 222}};
static const BBPoint kPianoKeyArea13[] = {{107, 192}, {118, 192}, {118, 239}, {107, 239}};
static const BBPolygon kPianoKeyAreas[] = {
{kPianoKeyArea1, ARRAYSIZE(kPianoKeyArea1)},
{kPianoKeyArea2, ARRAYSIZE(kPianoKeyArea2)},
{kPianoKeyArea3, ARRAYSIZE(kPianoKeyArea3)},
{kPianoKeyArea4, ARRAYSIZE(kPianoKeyArea4)},
{kPianoKeyArea5, ARRAYSIZE(kPianoKeyArea5)},
{kPianoKeyArea6, ARRAYSIZE(kPianoKeyArea6)},
{kPianoKeyArea7, ARRAYSIZE(kPianoKeyArea7)},
{kPianoKeyArea8, ARRAYSIZE(kPianoKeyArea8)},
{kPianoKeyArea9, ARRAYSIZE(kPianoKeyArea9)},
{kPianoKeyArea10, ARRAYSIZE(kPianoKeyArea10)},
{kPianoKeyArea11, ARRAYSIZE(kPianoKeyArea11)},
{kPianoKeyArea12, ARRAYSIZE(kPianoKeyArea12)},
{kPianoKeyArea13, ARRAYSIZE(kPianoKeyArea13)},
};
static const BBPoint kObjPoints[] = {
{161, 189}, {269, 189}, {161, 208}, {279, 208}, {172, 208},
{141, 224}, {257, 191}, {257, 199}, {148, 223}, {124, 224},
{ 29, 192}, {182, 220}, {245, 220}, {269, 220}, {161, 220},
{203, 220}, {224, 220}, {123, 189}, {123, 199}, {123, 209},
{134, 224}, { 29, 185}, {124, 224}, {226, 127}, {226, 127},
{209, 141}, {244, 141}, {226, 127}, { 99, 107}, { 99, 107},
{ 76, 137}, {118, 136}, { 99, 107}, {195, 104}, {100, 78}
};
static const MinigameBbAirGuitar::PianoKeyInfo kPianoKeyInfos[] = {
{ 30, 192, 0},
{ 38, 192, 5},
{ 41, 192, 1},
{ 49, 192, 5},
{ 52, 192, 2},
{ 63, 192, 3},
{ 71, 192, 5},
{ 74, 192, 1},
{ 82, 192, 5},
{ 85, 192, 1},
{ 94, 192, 5},
{ 96, 192, 2},
{107, 192, 4}
};
static const Rect kRect2 = {29, 189, 290, 239};
static const Rect kPianoRect = {29, 192, 118, 239};
static const Rect kPlayerButtonRects[] = {
{123, 189, 145, 199},
{123, 199, 145, 209},
{123, 209, 145, 220},
{148, 223, 156, 236},
{161, 189, 182, 205},
{161, 208, 171, 218},
{161, 220, 182, 231},
{182, 220, 203, 231},
{203, 220, 224, 231},
{224, 220, 245, 231},
{245, 220, 266, 231},
{269, 220, 290, 231},
{269, 189, 290, 205},
{279, 208, 290, 218}
};
static const BBPoint kPointsTbl1[] = {
{196, 191}, {202, 191}, {207, 191}, {212, 191}, {217, 191},
{223, 191}, {228, 191}, {233, 191}, {238, 191}, {244, 191},
{249, 191}
};
static const BBPoint kPointsTbl2[] = {
{196, 199}, {202, 199}, {207, 199}, {212, 199}, {217, 199},
{223, 199}, {228, 199}, {233, 199}, {238, 199}, {244, 199},
{249, 199}
};
static const struct { int frameIndex; byte flag; } kNoteFrameTbl[13] = {
{2, 0}, {2, 1}, {3, 0}, {3, 1}, {4, 0},
{5, 0}, {5, 1}, {6, 0}, {6, 1}, {0, 0},
{0, 1}, {1, 0}, {2, 0}
};
const int kTrackBarMinX = 172;
const int kTrackBarMaxX = 272;
bool MinigameBbAirGuitar::ptInRect(const Rect *r, int x, int y) {
return r && Common::Rect(r->left, r->top, r->right, r->bottom).contains(x, y);
}
bool MinigameBbAirGuitar::ptInPoly(const BBPolygon *poly, int x, int y) {
if (!poly)
return false;
const BBPoint *points = poly->points;
int pointsCount = poly->pointsCount;
bool result = false;
if (pointsCount > 0)
for (int i = 0, j = pointsCount - 1; i < pointsCount; j = i++)
if (((points[i].y > y) != (points[j].y > y)) &&
(x < (points[j].x - points[i].x) * (y - points[i].y) /
(points[j].y - points[i].y) + points[i].x))
result = !result;
return result;
}
void MinigameBbAirGuitar::buildDrawList(DrawList &drawList) {
switch (_gameState) {
case 0:
buildDrawList0(drawList);
break;
case 1:
buildDrawList1(drawList);
break;
}
}
void MinigameBbAirGuitar::buildDrawList0(DrawList &drawList) {
drawList.add(_objects[0].anim->frameIndices[0], _objects[0].x, _objects[0].y, 2000);
for (int i = 1; i < kMaxObjectsCount; ++i) {
Obj *obj = &_objects[i];
if (obj->kind)
drawList.add(obj->anim->frameIndices[obj->frameIndex], obj->x, obj->y, obj->y + 16);
}
if (_titleScreenSpriteIndex> 0)
drawList.add(_titleScreenSpriteIndex, 0, 0, 0);
}
void MinigameBbAirGuitar::buildDrawList1(DrawList &drawList) {
for (int i = 0; i < kMaxObjectsCount; ++i) {
Obj *obj = &_objects[i];
if (obj->kind)
drawList.add(obj->anim->frameIndices[obj->frameIndex], obj->x, obj->y, 255 - i);
}
if (_movingTrackBar) {
_trackBarX = _trackBarMouseX;
} else if (_totalTrackLength > 0) {
_trackBarX = 100 * _currTrackPos / _totalTrackLength + kTrackBarMinX;
} else {
_trackBarX = kTrackBarMinX;
}
if (_trackBarX > kTrackBarMaxX)
_trackBarX = kTrackBarMaxX;
_trackBarThumbRect.top = 208;
_trackBarThumbRect.bottom = 218;
_trackBarThumbRect.left = _trackBarX;
_trackBarThumbRect.right = _trackBarX + 6;
drawList.add(_objects[5].anim->frameIndices[0], _trackBarX, 208, 100);
if (_playerMode != 0) {
for (int i = 36; i < _vuMeterLeft2 + 36; ++i) {
int frameIndex = 0;
if (i >= 45)
frameIndex = 3;
else if (i >= 43)
frameIndex = 2;
else if (i >= 41)
frameIndex = 1;
drawList.add(_objects[i].anim->frameIndices[frameIndex], kPointsTbl1[i - 36].x, kPointsTbl1[i - 36].y, 254);
}
for (int i = 47; i < _vuMeterRight2 + 47; ++i) {
int frameIndex = 0;
if (i >= 56)
frameIndex = 3;
else if (i >= 54)
frameIndex = 2;
else if (i >= 52)
frameIndex = 1;
drawList.add(_objects[i].anim->frameIndices[frameIndex], kPointsTbl2[i - 47].x, kPointsTbl2[i - 47].y, 254);
}
}
if (_backgroundSpriteIndex > 0)
drawList.add(_backgroundSpriteIndex, 0, 0, 0);
}
void MinigameBbAirGuitar::drawSprites() {
DrawList drawList;
buildDrawList(drawList);
_vm->_screen->drawDrawList(drawList, _spriteModule);
_vm->_screen->copyToScreen();
}
void MinigameBbAirGuitar::initObjs() {
for (int i = 0; i < kMaxObjectsCount; ++i)
_objects[i].kind = 0;
}
MinigameBbAirGuitar::Obj *MinigameBbAirGuitar::getFreeObject() {
for (int i = 0; i < kMaxObjectsCount; ++i)
if (_objects[i].kind == 0)
return &_objects[i];
return 0;
}
void MinigameBbAirGuitar::initObjects() {
switch (_gameState) {
case 0:
initObjects0();
break;
case 1:
initObjects1();
break;
}
}
void MinigameBbAirGuitar::initObjects0() {
_objects[0].anim = getAnimation(0);
_objects[0].frameIndex = 0;
_objects[0].ticks = getAnimation(0)->frameTicks[0];
_objects[0].x = 160;
_objects[0].y = 120;
_objects[0].kind = 1;
_objects[1].anim = getAnimation(37);
_objects[1].frameIndex = 0;
_objects[1].ticks = getAnimation(37)->frameTicks[0];
_objects[1].x = 40;
_objects[1].y = 240;
_objects[1].kind = 2;
_objects[2].anim = getAnimation(36);
_objects[2].frameIndex = 0;
_objects[2].ticks = getAnimation(36)->frameTicks[0];
_objects[2].x = 280;
_objects[2].y = 240;
_objects[2].kind = 2;
}
void MinigameBbAirGuitar::initObjects1() {
for (int i = 0; i < 60; ++i)
_objects[i].kind = 0;
_objects[0].kind = 0;
_objects[0].kind = 1;
_objects[0].anim = getAnimation(0);
_objects[0].ticks = getAnimation(0)->frameTicks[0];
_objects[1].anim = getAnimation(1);
_objects[1].ticks = getAnimation(1)->frameTicks[0];
_objects[2].anim = getAnimation(2);
_objects[2].ticks = getAnimation(2)->frameTicks[0];
_objects[3].anim = getAnimation(3);
_objects[3].ticks = getAnimation(3)->frameTicks[0];
_objects[4].anim = getAnimation(4);
_objects[4].ticks = getAnimation(4)->frameTicks[0];
_objects[5].anim = getAnimation(5);
_objects[5].ticks = getAnimation(5)->frameTicks[0];
_objects[6].anim = getAnimation(6);
_objects[6].ticks = getAnimation(6)->frameTicks[0];
_objects[7].anim = getAnimation(8);
_objects[7].ticks = getAnimation(8)->frameTicks[0];
_objects[8].anim = getAnimation(9);
_objects[8].ticks = getAnimation(9)->frameTicks[0];
_objects[9].anim = getAnimation(10);
_objects[9].ticks = getAnimation(10)->frameTicks[0];
_objects[10].anim = getAnimation(11);
_objects[10].ticks = getAnimation(11)->frameTicks[0];
_objects[11].anim = getAnimation(12);
_objects[11].ticks = getAnimation(12)->frameTicks[0];
_objects[12].anim = getAnimation(13);
_objects[12].ticks = getAnimation(13)->frameTicks[0];
_objects[13].anim = getAnimation(14);
_objects[13].ticks = getAnimation(14)->frameTicks[0];
_objects[14].anim = getAnimation(15);
_objects[14].ticks = getAnimation(15)->frameTicks[0];
_objects[15].anim = getAnimation(16);
_objects[15].ticks = getAnimation(16)->frameTicks[0];
_objects[16].anim = getAnimation(17);
_objects[16].ticks = getAnimation(17)->frameTicks[0];
_objects[17].anim = getAnimation(18);
_objects[17].ticks = getAnimation(18)->frameTicks[0];
_objects[18].anim = getAnimation(19);
_objects[18].ticks = getAnimation(19)->frameTicks[0];
_objects[19].anim = getAnimation(20);
_objects[19].ticks = getAnimation(20)->frameTicks[0];
_objects[20].anim = getAnimation(21);
_objects[20].ticks = getAnimation(21)->frameTicks[0];
_objects[21].anim = getAnimation(11);
_objects[21].ticks = getAnimation(11)->frameTicks[0];
_objects[22].anim = getAnimation(22);
_objects[22].ticks = getAnimation(22)->frameTicks[0];
_objects[23].anim = getAnimation(23);
_objects[23].ticks = getAnimation(23)->frameTicks[0];
_objects[24].anim = getAnimation(24);
_objects[24].ticks = getAnimation(24)->frameTicks[0];
_objects[25].anim = getAnimation(25);
_objects[25].ticks = getAnimation(25)->frameTicks[0];
_objects[26].anim = getAnimation(26);
_objects[26].ticks = getAnimation(26)->frameTicks[0];
_objects[27].anim = getAnimation(27);
_objects[27].ticks = getAnimation(27)->frameTicks[0];
_objects[28].anim = getAnimation(28);
_objects[28].ticks = getAnimation(28)->frameTicks[0];
_objects[29].anim = getAnimation(29);
_objects[29].ticks = getAnimation(29)->frameTicks[0];
_objects[30].anim = getAnimation(30);
_objects[30].ticks = getAnimation(30)->frameTicks[0];
_objects[31].anim = getAnimation(31);
_objects[31].ticks = getAnimation(31)->frameTicks[0];
_objects[32].anim = getAnimation(32);
_objects[32].ticks = getAnimation(32)->frameTicks[0];
_objects[33].anim = getAnimation(33);
_objects[33].ticks = getAnimation(33)->frameTicks[0];
_objects[34].anim = getAnimation(34);
_objects[34].ticks = getAnimation(34)->frameTicks[0];
_objects[35].anim = getAnimation(35);
_objects[35].ticks = getAnimation(35)->frameTicks[0];
for (int i = 36; i <= 57; ++i) {
_objects[i].anim = getAnimation(7);
_objects[i].ticks = getAnimation(7)->frameTicks[0];
}
for (int i = 1; i <= 35; ++i) {
_objects[i].x = kObjPoints[i - 1].x;
_objects[i].y = kObjPoints[i - 1].y;
}
_objects[22].kind = 1;
_objects[6].kind = 1;
_objects[26].kind = 1;
_objects[26].frameIndex = 3;
_objects[27].kind = 1;
_objects[27].frameIndex = 3;
_objects[31].kind = 1;
_objects[31].frameIndex = 3;
_objects[32].kind = 1;
_objects[32].frameIndex = 3;
_objects[28].kind = 1;
_objects[33].kind = 1;
_objects[34].kind = 1;
_objects[35].kind = 1;
_track[0].noteNum = -1;
stop();
changePatch(0);
}
bool MinigameBbAirGuitar::updateStatus(int mouseX, int mouseY, uint mouseButtons) {
switch (_gameState) {
case 0:
return updateStatus0(mouseX, mouseY, mouseButtons);
case 1:
return updateStatus1(mouseX, mouseY, mouseButtons);
}
return false;
}
bool MinigameBbAirGuitar::updateStatus0(int mouseX, int mouseY, uint mouseButtons) {
if (mouseButtons & kAnyButtonDown) {
stopSound(1);
_rockTunePlaying = false;
_gameState = 1;
initObjects();
_gameTicks = 0;
} else {
if (!_rockTunePlaying) {
_rockTunePlaying = true;
playSound(1, true);
}
_objects[0].x = mouseX;
_objects[0].y = mouseY;
for (int i = 1; i < kMaxObjectsCount; ++i) {
Obj *obj = &_objects[i];
if (obj->kind && --obj->ticks == 0) {
++obj->frameIndex;
if (obj->frameIndex >= obj->anim->frameCount)
obj->frameIndex = 0;
obj->ticks = obj->anim->frameTicks[obj->frameIndex];
}
}
}
return true;
}
bool MinigameBbAirGuitar::updateStatus1(int mouseX, int mouseY, uint mouseButtons) {
int currTicks = _vm->_system->getMillis();
if (_playerMode == 1 && _track[_trackIndex].ticks <= currTicks - _noteStartTime) {
noteOff(_track[_trackIndex].noteNum);
if (_trackIndex < _trackCount && _track[++_trackIndex].noteNum != -1)
noteOn(_track[_trackIndex].noteNum);
else
stop();
}
if (_vuMeterLeft1 - 2 <= _vuMeterLeft2) {
if (_vuMeterLeft1 + 1 >= _vuMeterLeft2) {
int incr = MIN(_vm->getRandom(4), 2) - 1;
if (incr < 0 && _vuMeterLeft2 == 0)
incr = -incr;
if (incr > 0 && _vuMeterLeft2 == 11)
incr = -incr;
_vuMeterLeft2 += incr;
} else {
--_vuMeterLeft2;
}
} else {
++_vuMeterLeft2;
}
if (_vuMeterRight1 - 2 <= _vuMeterRight2) {
if (_vuMeterRight1 + 1 >= _vuMeterRight2) {
int incr = MIN(_vm->getRandom(4), 2) - 1;
if (incr < 0 && _vuMeterRight2 == 0)
incr = -incr;
if (incr > 0 && _vuMeterRight2 == 11)
incr = -incr;
_vuMeterRight2 += incr;
} else {
--_vuMeterRight2;
}
} else {
++_vuMeterRight2;
}
if (_resetAnims && _vm->_system->getMillis() - _noteStartTime >= 1000)
resetObjs();
_objects[0].x = mouseX;
_objects[0].y = mouseY;
_trackBarMouseX = CLIP(mouseX, kTrackBarMinX, kTrackBarMaxX);
bool checkClick = false;
if (mouseButtons & kAnyButtonClicked) {
checkClick = true;
} else if (!(mouseButtons & kAnyButtonDown)) {
afterButtonReleased();
} else if (!_movingTrackBar && ((_currButtonNum >= 14 && ptInPoly(_currPianoKeyArea, mouseX, mouseY)) || ptInRect(_currPlayerButtonRect, mouseX, mouseY))) {
if (_currButtonNum == 5 && _trackIndex > 0) {
--_trackIndex;
calcTotalTicks2();
} else if (_currButtonNum == 13 && _trackIndex < _trackCount) {
++_trackIndex;
calcTotalTicks2();
}
} else if (!_movingTrackBar)
checkClick = true;
if (checkClick) {
afterButtonReleased();
_objects[0].frameIndex = 1;
if (ptInRect(&kRect2, mouseX, mouseY)) {
if (_playerMode != 1 && ptInRect(&kPianoRect, mouseX, mouseY)) {
for (int i = 0; i <= 12; ++i) {
if (ptInPoly(&kPianoKeyAreas[i], mouseX, mouseY)) {
_currButtonNum = i + 14;
_currPianoKeyArea = &kPianoKeyAreas[i];
_objects[11].kind = 1;
_objects[11].x = kPianoKeyInfos[i].x;
_objects[11].y = kPianoKeyInfos[i].y;
_objects[11].frameIndex = kPianoKeyInfos[i].frameIndex;
noteOn(i);
break;
}
}
} else if (_playerMode != 1 && ptInRect(&_trackBarThumbRect, mouseX, mouseY)) {
_movingTrackBar = true;
} else {
int playerButtonNum = -1;
for (int i = 0; i < 14; ++i) {
if (ptInRect(&kPlayerButtonRects[i], mouseX, mouseY)) {
playerButtonNum = i;
break;
}
}
if (playerButtonNum >= 0) {
_currButtonNum = playerButtonNum;
_currPlayerButtonRect = &kPlayerButtonRects[playerButtonNum];
switch (playerButtonNum) {
case 0:
if (_playerMode == 0) {
changePatch(0);
_currFrameIndex = &_objects[18 + 0].frameIndex;
*_currFrameIndex = 0;
}
break;
case 1:
if (_playerMode == 0) {
changePatch(1);
_currFrameIndex = &_objects[18 + 1].frameIndex;
*_currFrameIndex = 0;
}
break;
case 2:
if (_playerMode == 0) {
changePatch(2);
_currFrameIndex = &_objects[18 + 2].frameIndex;
*_currFrameIndex = 0;
}
break;
case 3:
_btn3KindToggle = !_btn3KindToggle;
_objects[9].kind = _btn3KindToggle ? 0 : 1;
_objects[22].frameIndex = _btn3KindToggle ? 0 : 1;
break;
case 4:
if (_playerMode == 0) {
_objects[1].kind = 1;
_currFrameIndex = &_objects[1].frameIndex;
_objects[1].frameIndex = 0;
}
break;
case 5:
if (_playerMode == 0) {
if (_trackIndex > 0)
--_trackIndex;
_objects[3].kind = 1;
calcTotalTicks2();
}
break;
case 6:
stop();
_currFrameIndex = &_objects[15].frameIndex;
_objects[15].frameIndex = 0;
break;
case 7:
if (_playerMode == 0) {
play();
_currFrameIndex = &_objects[12].frameIndex;
_objects[12].frameIndex = 0;
}
break;
case 8:
if (_playerMode == 0) {
_trackIndex = 0;
_objects[16].kind = 1;
calcTotalTicks2();
}
break;
case 9:
if (_playerMode == 0) {
_trackIndex = _trackCount;
_objects[17].kind = 1;
calcTotalTicks2();
}
break;
case 10:
if (_playerMode == 0) {
record();
_currFrameIndex = &_objects[13].frameIndex;
_objects[13].frameIndex = 0;
}
break;
case 11:
if (_playerMode == 0) {
setPlayerMode3();
_currFrameIndex = &_objects[14].frameIndex;
_objects[14].frameIndex = 0;
}
break;
case 12:
if (_playerMode == 0) {
_objects[2].kind = 1;
_currFrameIndex = &_objects[2].frameIndex;
_objects[2].frameIndex = 0;
}
break;
case 13:
if (_playerMode == 0) {
if (_trackIndex < _trackCount)
++_trackIndex;
_objects[4].kind = 1;
calcTotalTicks2();
}
break;
}
}
}
}
}
if (_playerMode != 0) {
_currTrackPos = currTicks + _actionStartTrackPos - _actionStartTime;
if (_currTrackPos > _actionTrackPos && _playerMode != 1) {
if (_currTrackPos >= 15000) {
_currTrackPos = 15000;
_actionTrackPos = 15000;
stop();
} else {
_actionTrackPos = currTicks + _actionStartTrackPos - _actionStartTime;
}
}
}
if (_buttonClickTicks + 1000 < currTicks)
_buttonClickTicks = currTicks;
int newKind = _buttonClickTicks + 500 < currTicks ? 1 : 0;
switch (_playerMode) {
case 1:
if (_currButtonNum == 7) {
_objects[12].kind = 1;
_objects[12].frameIndex = 0;
} else {
_objects[12].kind = newKind;
_objects[12].frameIndex = 1;
}
break;
case 2:
if (_currButtonNum == 10) {
_objects[13].kind = 1;
_objects[13].frameIndex = 0;
} else {
_objects[13].kind = newKind;
_objects[13].frameIndex = 1;
}
break;
case 3:
if (_currButtonNum == 11) {
_objects[14].kind = 1;
_objects[14].frameIndex = 0;
} else {
_objects[14].kind = newKind;
_objects[14].frameIndex = 1;
}
break;
}
updateObjs();
return true;
}
void MinigameBbAirGuitar::updateObjs() {
for (int i = 24; i <= 33; ++i) {
Obj *obj = &_objects[i];
if (obj->kind && --obj->ticks == 0) {
if (obj->frameIndex + 1 >= obj->anim->frameCount) {
obj->ticks = -1;
} else {
++obj->frameIndex;
obj->ticks = obj->anim->frameTicks[obj->frameIndex];
}
}
}
}
bool MinigameBbAirGuitar::run(bool fromMainGame) {
memset(_objects, 0, sizeof(_objects));
_modified = false;
_currPatchNum = -1;
_btn3KindToggle = 0;
_currButtonNum = 27;
_actionStartTime = 0;
_currFrameIndex = 0;
_currPlayerButtonRect = 0;
_currPianoKeyArea = 0;
_trackCount = 0;
_trackIndex = 0;
_totalTrackLength = 0;
_actionTrackPos = 0;
_noteStartTime = 0;
_actionStartTrackPos = 0;
_trackBarX = kTrackBarMinX;
_currTrackPos = 0;
_currNoteNum = -2;
_resetAnims = false;
_vuMeterLeft2 = 0;
_vuMeterRight2 = 0;
_vuMeterLeft1 = 0;
_vuMeterRight1 = 0;
_rockTunePlaying = false;
_backgroundSpriteIndex = 97;
_titleScreenSpriteIndex = 98;
_fromMainGame = fromMainGame;
_gameState = 0;
_gameTicks = 0;
_gameResult = false;
_gameDone = false;
initObjects();
_spriteModule = new SpriteModule();
_spriteModule->load("bbairg/bbairg.000");
Palette palette = _spriteModule->getPalette();
_vm->_screen->setPalette(palette);
loadSounds();
while (!_vm->shouldQuit() &&!_gameDone) {
_vm->updateEvents();
update();
}
_vm->_sound->unloadSounds();
delete _spriteModule;
return _gameResult;
}
void MinigameBbAirGuitar::update() {
int inputTicks;
if (_gameTicks > 0) {
int currTicks = _vm->_system->getMillis();
inputTicks = 3 * (currTicks - _gameTicks) / 50;
_gameTicks = currTicks - (currTicks - _gameTicks - 50 * inputTicks / 3);
} else {
inputTicks = 1;
_gameTicks = _vm->_system->getMillis();
}
if (_vm->_keyCode == Common::KEYCODE_ESCAPE) {
_gameDone = querySaveModifiedTracks();
return;
}
if (inputTicks == 0)
return;
bool done;
do {
done = !updateStatus(_vm->_mouseX, _vm->_mouseY, _vm->_mouseButtons);
_vm->_mouseButtons &= ~kLeftButtonClicked;
_vm->_mouseButtons &= ~kRightButtonClicked;
_vm->_keyCode = Common::KEYCODE_INVALID;
} while (--inputTicks && _gameTicks > 0 && !done);
drawSprites();
_vm->_system->delayMillis(10);
}
void MinigameBbAirGuitar::play() {
if (_track[_trackIndex].noteNum != -1) {
_playerMode = 1;
_objects[7].kind = 1;
_objects[8].kind = 0;
_objects[15].kind = 0;
_actionStartTime = _vm->_system->getMillis();
_actionStartTrackPos = _currTrackPos;
noteOn(_track[_trackIndex].noteNum);
}
}
void MinigameBbAirGuitar::record() {
_playerMode = 2;
_objects[7].kind = 1;
_objects[8].kind = 0;
_objects[15].kind = 0;
_totalTrackLength = 15000;
_actionStartTime = _vm->_system->getMillis();
_actionStartTrackPos = _currTrackPos;
_noteStartTime = _vm->_system->getMillis();
_actionTrackPos = _currTrackPos;
_trackCount = _trackIndex;
_vuMeterRight1 = 0;
_vuMeterRight2 = 0;
_vuMeterLeft1 = 0;
_vuMeterLeft2 = 0;
_modified = true;
_track[_trackIndex].noteNum = -2;
}
void MinigameBbAirGuitar::setPlayerMode3() {
_playerMode = 3;
_objects[7].kind = 1;
_objects[8].kind = 0;
_objects[15].kind = 0;
_totalTrackLength = 15000;
_actionStartTime = _vm->_system->getMillis();
_actionStartTrackPos = _currTrackPos;
_noteStartTime = _vm->_system->getMillis();
_actionTrackPos = _currTrackPos;
_trackCount = _trackIndex;
_vuMeterRight1 = 0;
_vuMeterRight2 = 0;
_vuMeterLeft1 = 0;
_vuMeterLeft2 = 0;
_modified = true;
_track[_trackIndex].noteNum = -2;
}
void MinigameBbAirGuitar::stop() {
noteOff(_currNoteNum);
if (_playerMode == 2 || _playerMode == 3) {
_totalTrackLength = _actionTrackPos;
_track[_trackCount].noteNum = -1;
}
_playerMode = 0;
_objects[7].kind = 0;
_objects[8].kind = 1;
_objects[15].kind = 1;
_objects[15].frameIndex = 1;
_objects[12].kind = 0;
_objects[13].kind = 0;
_objects[14].kind = 0;
resetObjs();
}
void MinigameBbAirGuitar::changePatch(int patchNum) {
resetObjs();
if (patchNum == -1 || patchNum != _currPatchNum)
_currPatchNum = -1;
_objects[20].kind = 0;
_objects[19].kind = _objects[20].kind;
_objects[18].kind = _objects[19].kind;
_objects[patchNum + 18].kind = 1;
_objects[patchNum + 18].frameIndex = 1;
_objects[6].frameIndex = patchNum;
_currPatchNum = patchNum;
}
void MinigameBbAirGuitar::afterButtonReleased() {
if (_movingTrackBar) {
_movingTrackBar = false;
_currTrackPos = _totalTrackLength * (_trackBarX - kTrackBarMinX) / 100;
calcTotalTicks1();
} else {
switch (_currButtonNum) {
case 0:
case 1:
case 2:
*_currFrameIndex = 1;
break;
case 4:
*_currFrameIndex = 1;
loadTracks();
_objects[1].kind = 0;
break;
case 5:
_objects[3].kind = 0;
break;
case 6:
*_currFrameIndex = 1;
break;
case 7:
*_currFrameIndex = 1;
break;
case 8:
_objects[16].kind = 0;
break;
case 9:
_objects[17].kind = 0;
break;
case 10:
*_currFrameIndex = 1;
break;
case 11:
*_currFrameIndex = 1;
break;
case 12:
*_currFrameIndex = 1;
saveTracks();
_objects[2].kind = 0;
break;
case 13:
_objects[4].kind = 0;
break;
case 14:
case 15:
case 16:
case 17:
case 18:
case 19:
case 20:
case 21:
case 22:
case 23:
case 24:
case 25:
case 26:
noteOff(_currButtonNum - 14);
break;
}
}
_objects->frameIndex = 0;
_currPlayerButtonRect = 0;
_currPianoKeyArea = 0;
_currButtonNum = 27;
}
void MinigameBbAirGuitar::calcTotalTicks2() {
_currTrackPos = 0;
for (int i = 0; i < _trackIndex; ++i)
_currTrackPos += _track[i].ticks;
}
void MinigameBbAirGuitar::calcTotalTicks1() {
int totalTicks = 0;
// TODO Try to clean this up
_trackIndex = 0;
if (_track[0].ticks <= _currTrackPos) {
do {
totalTicks += _track[_trackIndex].ticks;
if (_trackIndex >= _trackCount)
break;
++_trackIndex;
} while (totalTicks + _track[_trackIndex].ticks <= _currTrackPos);
}
_currTrackPos = totalTicks;
}
void MinigameBbAirGuitar::noteOn(int noteNum) {
if (_currNoteNum != -2) {
if (noteNum == _currNoteNum)
return;
noteOff(_currNoteNum);
}
if (noteNum == -2) {
_vuMeterRight1 = 0;
_vuMeterRight2 = 0;
_vuMeterLeft1 = 0;
_vuMeterLeft2 = 0;
} else {
playNote(noteNum);
_vuMeterRight1 = 10;
_vuMeterRight2 = 10;
_vuMeterLeft1 = 10;
_vuMeterLeft2 = 10;
if (_btn3KindToggle) {
_objects[23].kind = 1;
_objects[23].frameIndex = noteNum;
} else {
_objects[10].kind = 1;
_objects[10].frameIndex = kNoteFrameTbl[noteNum].frameIndex;
if (kNoteFrameTbl[noteNum].flag) {
_objects[21].kind = 1;
_objects[21].frameIndex = 7;
}
}
}
_currNoteNum = noteNum;
if (_playerMode == 2 || _playerMode == 3) {
_ticksDelta = _vm->_system->getMillis() - _noteStartTime;
_track[_trackCount].ticks = _ticksDelta;
if (_trackCount < kMaxTracks - 1)
++_trackCount;
_track[_trackCount].noteNum = noteNum;
}
_noteStartTime = _vm->_system->getMillis();
if (noteNum != -2) {
_resetAnims = false;
if (_currPatchNum == 0) {
_objects[25].kind = 1;
_objects[28].kind = 0;
_objects[25].frameIndex = 0;
_objects[25].ticks = getAnimation(25)->frameTicks[0];
_objects[26].frameIndex = 0;
_objects[26].ticks = getAnimation(26)->frameTicks[0];
_objects[27].frameIndex = 0;
_objects[27].ticks = getAnimation(27)->frameTicks[0];
_objects[30].kind = 1;
_objects[33].kind = 0;
_objects[30].frameIndex = 0;
_objects[30].ticks = getAnimation(30)->frameTicks[0];
_objects[31].frameIndex = 0;
_objects[31].ticks = getAnimation(31)->frameTicks[0];
_objects[32].frameIndex = 0;
_objects[32].ticks = getAnimation(32)->frameTicks[0];
} else if (_currPatchNum == 1) {
_objects[29].kind = 1;
_objects[33].kind = 0;
_objects[29].frameIndex = 0;
_objects[29].ticks = getAnimation(29)->frameTicks[0];
_objects[31].frameIndex = 0;
_objects[31].ticks = getAnimation(31)->frameTicks[0];
_objects[32].frameIndex = 0;
_objects[32].ticks = getAnimation(32)->frameTicks[0];
} else if (_currPatchNum == 2) {
_objects[24].kind = 1;
_objects[28].kind = 0;
_objects[24].frameIndex = 0;
_objects[24].ticks = getAnimation(24)->frameTicks[0];
_objects[26].frameIndex = 0;
_objects[26].ticks = getAnimation(26)->frameTicks[0];
_objects[27].frameIndex = 0;
_objects[27].ticks = getAnimation(27)->frameTicks[0];
}
}
}
void MinigameBbAirGuitar::noteOff(int noteNum) {
if (_currNoteNum != noteNum)
return;
if (noteNum != -2)
stopNote(noteNum);
_objects[21].kind = 0;
_objects[23].kind = _objects[21].kind;
_objects[10].kind = _objects[23].kind;
_vuMeterRight1 = 0;
_vuMeterRight2 = 0;
_vuMeterLeft1 = 0;
_vuMeterLeft2 = 0;
_currNoteNum = -2;
_objects[11].kind = 0;
_ticksDelta = _vm->_system->getMillis() - _noteStartTime;
if (_playerMode == 2 || _playerMode == 3) {
if (_actionTrackPos + _ticksDelta > 15000)
_ticksDelta = 15000 - _actionTrackPos;
_track[_trackCount].ticks = _ticksDelta;
if (_trackCount + 1 < 2048)
++_trackCount;
_track[_trackCount].noteNum = -2;
_noteStartTime = _vm->_system->getMillis();
}
if (noteNum != -2) {
if (_playerMode == 0) {
_resetAnims = true;
_noteStartTime = _vm->_system->getMillis();
}
if (_currPatchNum == 0) {
_objects[25].frameIndex = 3;
_objects[25].ticks = -1;
_objects[26].frameIndex = 3;
_objects[26].ticks = -1;
_objects[27].frameIndex = 3;
_objects[27].ticks = -1;
_objects[30].frameIndex = 3;
_objects[30].ticks = -1;
_objects[31].frameIndex = 3;
_objects[31].ticks = -1;
_objects[32].frameIndex = 3;
_objects[32].ticks = -1;
} else if (_currPatchNum == 1) {
_objects[29].frameIndex = 3;
_objects[29].ticks = -1;
_objects[31].frameIndex = 3;
_objects[31].ticks = -1;
_objects[32].frameIndex = 3;
_objects[32].ticks = -1;
} else if (_currPatchNum == 2) {
_objects[24].frameIndex = 2;
_objects[24].ticks = -1;
_objects[26].frameIndex = 3;
_objects[26].ticks = -1;
_objects[27].frameIndex = 3;
_objects[27].ticks = -1;
}
}
}
void MinigameBbAirGuitar::resetObjs() {
_resetAnims = false;
_objects[25].kind = 0;
_objects[24].kind = 0;
_objects[28].kind = 1;
_objects[26].frameIndex = 0;
_objects[26].ticks = -1;
_objects[27].frameIndex = 0;
_objects[27].ticks = -1;
_objects[30].kind = 0;
_objects[29].kind = 0;
_objects[33].kind = 1;
_objects[31].frameIndex = 0;
_objects[31].ticks = -1;
_objects[32].frameIndex = 0;
_objects[32].ticks = -1;
}
void MinigameBbAirGuitar::loadSounds() {
_vm->_sound->loadSound("bbairg/audio/rocktune.aif");
for (uint i = 0; i < kPatchDirectoriesCount; ++i) {
const char *patchDirectory = kPatchDirectories[i];
for (uint j = 0; j < kNoteSoundFilenamesCount; ++j) {
Common::String filename = Common::String::format("bbairg/audio/%s/%s", patchDirectory, kNoteSoundFilenames[j]);
_vm->_sound->loadSound(filename.c_str());
}
}
}
void MinigameBbAirGuitar::playNote(int noteNum) {
if (noteNum >= 0 && _currPatchNum >= 0)
playSound(2 + _currPatchNum * kNoteSoundFilenamesCount + noteNum);
}
void MinigameBbAirGuitar::stopNote(int noteNum) {
if (noteNum >= 0 && _currPatchNum >= 0)
stopSound(2 + _currPatchNum * kNoteSoundFilenamesCount + noteNum);
}
bool MinigameBbAirGuitar::getLoadFilename(Common::String &filename) {
GUI::FileBrowserDialog browser(0, "air", GUI::kFBModeLoad);
if (browser.runModal() > 0) {
filename = browser.getResult();
return true;
}
return false;
}
bool MinigameBbAirGuitar::getSaveFilename(Common::String &filename) {
GUI::FileBrowserDialog browser(0, "air", GUI::kFBModeSave);
if (browser.runModal() > 0) {
filename = browser.getResult();
return true;
}
return false;
}
bool MinigameBbAirGuitar::querySaveModifiedDialog() {
/* NOTE The original button captions don't fit so shortened variants are used
Original ok button caption: "Yeah, heh, heh, save it!"
Original discard button caption: "Who cares? It sucked!"
*/
GUI::MessageDialog query(_("Hey Beavis - you didn't save that last Jam!"),
_("Save it!"),
_("It sucked!"));
return query.runModal() == GUI::kMessageOK;
}
bool MinigameBbAirGuitar::querySaveModifiedTracks() {
if (_modified && querySaveModifiedDialog()) {
if (!saveTracks())
return false;
}
return true;
}
bool MinigameBbAirGuitar::loadTracks() {
if (_playerMode != 0)
return false;
if (!querySaveModifiedTracks())
return false;
Common::String filename;
if (!getLoadFilename(filename))
return false;
Common::SaveFileManager *saveFileMan = g_system->getSavefileManager();
Common::InSaveFile *stream = saveFileMan->openForLoading(filename);
if (!loadFromStream(stream)) {
Common::String msg = Common::String::format("%s is not a valid Air Guitar file", filename.c_str());
GUI::MessageDialog dialog(msg);
dialog.runModal();
}
delete stream;
return true;
}
bool MinigameBbAirGuitar::saveTracks() {
if (_playerMode != 0)
return false;
Common::String filename;
if (!getSaveFilename(filename))
return false;
Common::SaveFileManager *saveFileMan = g_system->getSavefileManager();
Common::OutSaveFile *stream = saveFileMan->openForSaving(filename);
saveToStream(stream);
delete stream;
_modified = false;
return true;
}
bool MinigameBbAirGuitar::loadFromStream(Common::ReadStream *stream) {
uint32 magic = stream->readUint32BE();
if (magic != MKTAG('A', 'I', 'R', 'G'))
return false;
for (uint i = 0; i < kMaxTracks; ++i) {
_track[i].noteNum = stream->readByte();
_track[i].ticks = stream->readUint16LE();
}
_trackCount = 0;
_actionTrackPos = 0;
while (_track[_trackCount].noteNum != -1) {
_actionTrackPos += _track[_trackCount].ticks;
++_trackCount;
}
_totalTrackLength = _actionTrackPos;
_trackIndex = 0;
_currTrackPos = 0;
return true;
}
void MinigameBbAirGuitar::saveToStream(Common::WriteStream *stream) {
stream->writeUint32BE(MKTAG('A', 'I', 'R', 'G'));
for (uint i = 0; i < kMaxTracks; ++i) {
stream->writeByte(_track[i].noteNum);
stream->writeUint16LE(_track[i].ticks);
}
}
} // End of namespace Bbvs