scummvm/engines/bbvs/minigames/bbant.cpp

1318 lines
32 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/bbant.h"
namespace Bbvs {
static const BBPoint kPosIncrTbl1[] = {
{0, -1}, {-1, -1}, {-1, 0}, {-1, 1},
{ 0, 1}, { 1, 1}, { 1, 0}, { 1, -1}
};
static const BBPoint kPosIncrTbl2[] = {
{0, -2}, {-2, -2}, {-2, 0}, {-2, 2},
{ 0, 2}, { 2, 2}, { 2, 0}, { 2, -2}
};
static const int kScoreTbl[] = {
0, 1, 1, 3, 2, 4
};
static const char * const kSoundFilenames[] = {
"ant1.aif", "ant2.aif", "ant3.aif", "ant4.aif", "ant5.aif",
"ant6.aif", "ant7.aif", "ant8.aif", "ant9.aif", "ant10.aif",
"ant11.aif", "antmus1.aif", "fryant.aif", "stomp.aif", "bing.aif",
"bvyell.aif"
};
static const uint kSoundFilenamesCount = ARRAYSIZE(kSoundFilenames);
static const uint kSoundTbl1[] = {
2, 3, 4, 6
};
static const uint kSoundTbl2[] = {
5, 7, 11
};
static const uint kSoundTbl3[] = {
8, 10, 11
};
static const uint kSoundTbl4[] = {
2, 3, 4, 6, 8, 10, 11, 5, 7, 16
};
void MinigameBbAnt::buildDrawList0(DrawList &drawList) {
if (_titleScreenSpriteIndex)
drawList.add(_titleScreenSpriteIndex, 0, 0, 0);
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, obj->priority);
}
}
void MinigameBbAnt::buildDrawList1(DrawList &drawList) {
if (_backgroundSpriteIndex)
drawList.add(_backgroundSpriteIndex, _stompX, _stompY, 0);
for (int i = 1; i < kMaxObjectsCount; ++i) {
Obj *obj = &_objects[i];
if (obj->kind) {
drawList.add(obj->anim->frameIndices[obj->frameIndex],
_stompX + (obj->x >> 16), _stompY + (obj->y >> 16),
obj->priority);
}
}
drawList.add(getAnimation(164)->frameIndices[0], 5, 2, 2000);
drawNumber(drawList, _score, 68, 16);
drawList.add(getAnimation(166)->frameIndices[0], 230, 2, 2000);
drawNumber(drawList, _levelTimeLeft, 280, 16);
for (int i = 0; i < _stompCount; ++i)
drawList.add(getAnimation(130)->frameIndices[0], 20 + i * 30, 230, 2000);
}
void MinigameBbAnt::buildDrawList2(DrawList &drawList) {
buildDrawList1(drawList);
drawList.add(getAnimation(168)->frameIndices[0], 40, 100, 2000);
drawNumber(drawList, _counter1, 190, 112);
drawNumber(drawList, _countdown5, 258, 112);
drawList.add(getAnimation(169)->frameIndices[0], 120, 120, 2000);
drawNumber(drawList, _counter4, 192, 132);
}
void MinigameBbAnt::buildDrawList3(DrawList &drawList) {
buildDrawList1(drawList);
drawList.add(getAnimation(163)->frameIndices[0], 120, 70, 2000);
drawList.add(getAnimation(165)->frameIndices[0], 95, 95, 2000);
drawNumber(drawList, _hiScore, 208, 107);
}
void MinigameBbAnt::drawMagnifyingGlass(DrawList &drawList) {
scale2x(_objects[0].x - 28, _objects[0].y - 27);
drawList.clear();
drawList.add(_objects[0].anim->frameIndices[0], _objects[0].x, _objects[0].y, _objects[0].priority);
drawList.add(_objects[0].anim->frameIndices[1], _objects[0].x, _objects[0].y, _objects[0].priority);
drawList.add(_objects[0].anim->frameIndices[2], _objects[0].x, _objects[0].y, _objects[0].priority);
}
void MinigameBbAnt::drawSprites() {
switch (_gameState) {
case 0:
drawSprites0();
break;
case 1:
drawSprites1();
break;
case 2:
drawSprites2();
break;
case 3:
drawSprites3();
break;
}
}
void MinigameBbAnt::drawSprites0() {
DrawList drawList;
buildDrawList0(drawList);
_vm->_screen->drawDrawList(drawList, _spriteModule);
_vm->_screen->copyToScreen();
}
void MinigameBbAnt::drawSprites1() {
DrawList drawList;
buildDrawList1(drawList);
_vm->_screen->drawDrawList(drawList, _spriteModule);
drawMagnifyingGlass(drawList);
_vm->_screen->drawDrawList(drawList, _spriteModule);
_vm->_screen->copyToScreen();
}
void MinigameBbAnt::drawSprites2() {
DrawList drawList;
buildDrawList2(drawList);
_vm->_screen->drawDrawList(drawList, _spriteModule);
drawMagnifyingGlass(drawList);
_vm->_screen->drawDrawList(drawList, _spriteModule);
_vm->_screen->copyToScreen();
}
void MinigameBbAnt::drawSprites3() {
DrawList drawList;
buildDrawList3(drawList);
_vm->_screen->drawDrawList(drawList, _spriteModule);
_vm->_screen->copyToScreen();
}
MinigameBbAnt::Obj *MinigameBbAnt::getFreeObject() {
for (int i = 12; i < kMaxObjectsCount; ++i)
if (_objects[i].kind == 0)
return &_objects[i];
return 0;
}
void MinigameBbAnt::initObjects() {
switch (_gameState) {
case 0:
initObjects0();
break;
case 1:
initObjects1();
break;
case 2:
case 3:
// Nothing
break;
}
}
void MinigameBbAnt::initObjects0() {
_objects[0].anim = getAnimation(172);
_objects[0].frameIndex = 0;
_objects[0].ticks = getAnimation(172)->frameTicks[0];
_objects[0].x = 160;
_objects[0].y = 120;
_objects[0].priority = 2000;
_objects[0].kind = 1;
_objects[1].anim = getAnimation(170);
_objects[1].frameIndex = 0;
_objects[1].ticks = getAnimation(170)->frameTicks[0];
_objects[1].x = 40;
_objects[1].y = 240;
_objects[1].priority = 100;
_objects[1].kind = 2;
_objects[2].anim = getAnimation(171);
_objects[2].frameIndex = 0;
_objects[2].ticks = getAnimation(171)->frameTicks[0];
_objects[2].x = 280;
_objects[2].y = 240;
_objects[2].priority = 100;
_objects[2].kind = 2;
}
void MinigameBbAnt::initObjects1() {
_objects[0].kind = 0;
_objects[0].x = 160;
_objects[0].y = 120;
_objects[0].xIncr = 0;
_objects[0].yIncr = 0;
_objects[0].anim = getAnimation(159);
_objects[0].frameIndex = 0;
_objects[0].ticks = _objects[0].anim->frameTicks[0];
_objects[0].priority = 1000;
_objects[1].kind = 8;
_objects[1].x = 0x1E0000;
_objects[1].y = 0x280000;
_objects[1].xIncr = 0;
_objects[1].yIncr = 0;
_objects[1].anim = getAnimation(160);
_objects[1].frameIndex = 0;
_objects[1].ticks = _objects[0].anim->frameTicks[0];
_objects[1].priority = 900;
_objects[1].smokeCtr = 0;
_objects[1].hasSmoke = false;
_objects[1].status = 0;
_objects[2].kind = 8;
_objects[2].x = 0x280000;
_objects[2].y = 0x4B0000;
_objects[2].xIncr = 0;
_objects[2].yIncr = 0;
_objects[2].anim = getAnimation(161);
_objects[2].frameIndex = 0;
_objects[2].ticks = _objects[0].anim->frameTicks[0];
_objects[2].priority = 900;
_objects[2].smokeCtr = 0;
_objects[2].hasSmoke = false;
_objects[2].status = 0;
for (int i = 3; i < 12; ++i) {
const ObjInit *objInit = getObjInit(i - 3);
_objects[i].kind = 6;
_objects[i].x = objInit->x << 16;
_objects[i].y = objInit->y << 16;
_objects[i].xIncr = 0;
_objects[i].yIncr = 0;
_objects[i].anim = objInit->anim1;
_objects[i].frameIndex = 0;
_objects[i].ticks = _objects[0].anim->frameTicks[0];
_objects[i].priority = 600;
_objects[i].status = 9;
_objects[i].damageCtr = 0;
}
}
void MinigameBbAnt::initVars() {
switch (_gameState) {
case 0:
// Nothing
break;
case 1:
initVars1();
break;
case 2:
initVars2();
break;
case 3:
initVars3();
break;
}
}
void MinigameBbAnt::initVars1() {
_stompX = 0;
_stompY = 0;
_stompDelay1 = 0;
_stompCount = 1;
_stompCounter1 = 80;
_stompCounter2 = 80;
_totalBugsCount = 0;
_hasLastStompObj = false;
_counter1 = 9;
_countdown10 = 140;
_score = 0;
_counter4 = 1;
_gameTicks = 0;
_skullBugCtr = 500;
_levelTimeDelay = 58;
_levelTimeLeft = 30;
_bugsChanceByKind[0] = 0;
_bugsChanceByKind[1] = 20;
_bugsChanceByKind[2] = 20;
_bugsChanceByKind[3] = 5;
_bugsChanceByKind[4] = 7;
_bugsCountByKind[0] = 0;
_bugsCountByKind[1] = 0;
_bugsCountByKind[2] = 0;
_bugsCountByKind[3] = 0;
_bugsCountByKind[4] = 0;
_bugsCountByKind[5] = 0;
}
void MinigameBbAnt::initVars2() {
_countdown4 = 0;
_countdown3 = 0;
_levelTimeDelay = 58;
_countdown6 = 60;
_countdown5 = 50 * _counter1;
}
void MinigameBbAnt::initVars3() {
if (_score > _hiScore)
_hiScore = _score;
playSound(9);
}
bool MinigameBbAnt::updateStatus(int mouseX, int mouseY, uint mouseButtons) {
switch (_gameState) {
case 0:
return updateStatus0(mouseX, mouseY, mouseButtons);
case 1:
return updateStatus1(mouseX, mouseY, mouseButtons);
case 2:
return updateStatus2(mouseX, mouseY, mouseButtons);
case 3:
return updateStatus3(mouseX, mouseY, mouseButtons);
}
return false;
}
bool MinigameBbAnt::updateStatus0(int mouseX, int mouseY, uint mouseButtons) {
_objects[0].x = mouseX;
_objects[0].y = mouseY;
if (_objects[0].x >= 320)
_objects[0].x = 320 - 1;
if (_objects[0].y >= 240)
_objects[0].y = 240 - 1;
if (_objects[0].x < 0)
_objects[0].x = 0;
if (_objects[0].y < 0)
_objects[0].y = 0;
if ((mouseButtons & kLeftButtonDown) || (mouseButtons & kRightButtonDown)) {
_gameState = 1;
initObjects();
initVars();
_gameTicks = 0;
playSound(1);
} else {
for (int i = 0; i < kMaxObjectsCount; ++i) {
Obj *obj = &_objects[i];
if (obj->kind == 2) {
if (--obj->ticks == 0) {
++obj->frameIndex;
if (obj->frameIndex >= obj->anim->frameCount)
obj->frameIndex = 0;
obj->ticks = obj->anim->frameTicks[0];
}
}
}
}
return true;
}
bool MinigameBbAnt::updateStatus1(int mouseX, int mouseY, uint mouseButtons) {
const int kMaxBugsCount = 52;
--_levelTimeDelay;
if (!_levelTimeDelay) {
_levelTimeDelay = 58;
--_levelTimeLeft;
}
_objects[0].x = mouseX;
_objects[0].y = mouseY;
if (_objects[0].x >= 320)
_objects[0].x = 320 - 1;
if (_objects[0].y >= 240)
_objects[0].y = 240 - 1;
if (_objects[0].x < 0)
_objects[0].x = 0;
if (_objects[0].y < 0)
_objects[0].y = 0;
if (!_levelTimeLeft) {
_gameState = 2;
initVars();
initObjects();
_gameTicks = 0;
return true;
}
if (_counter1 == 0) {
_gameState = 3;
initVars();
initObjects();
_gameTicks = 0;
return true;
}
if ((mouseButtons & kRightButtonClicked) && (_stompCount > 0|| _hasLastStompObj) && !_objects[2].status) {
if (_hasLastStompObj)
removeStompObj(_lastStompObj);
--_stompCount;
_objects[2].status = 1;
}
if ((mouseButtons & kLeftButtonClicked) && _objects[2].status == 0 && isMagGlassAtBeavisLeg(2)) {
if (_vm->getRandom(10) == 1 && !isAnySoundPlaying(kSoundTbl4, 10))
playSound(16);
insertSmokeObj(_objects[0].x << 16, _objects[0].y << 16);
}
if (_skullBugCtr > 0) {
if (--_skullBugCtr == 0) {
_skullBugCtr = _vm->getRandom(150) + 500;
insertRandomBugObj(5);
}
}
if (_stompCounter2 > 0)
--_stompCounter2;
if (_totalBugsCount < kMaxBugsCount && _vm->getRandom(_stompCounter2) == 0) {
int testTbl[4];
int maxKindCount = 0, objKind = 0;
_stompCounter2 = _stompCounter1;
for (int i = 0; i < 4; ++i)
testTbl[i] = _vm->getRandom(_bugsChanceByKind[i] - _bugsCountByKind[i]);
for (int i = 0; i < 4; ++i) {
if (testTbl[i] >= maxKindCount) {
maxKindCount = testTbl[i];
objKind = i + 1;
}
}
if (objKind)
insertRandomBugObj(objKind);
}
updateObjs(mouseButtons);
updateFootObj(2);
if (--_countdown10 == 0) {
_countdown10 = 140;
if (_stompCounter1 > 20)
--_stompCounter1;
}
return true;
}
bool MinigameBbAnt::updateStatus2(int mouseX, int mouseY, uint mouseButtons) {
_objects[0].x = mouseX;
_objects[0].y = mouseY;
if (_objects[0].x >= 320)
_objects[0].x = 320 - 1;
if (_objects[0].y >= 240)
_objects[0].y = 240 - 1;
if (_objects[0].x < 0)
_objects[0].x = 0;
if (_objects[0].y < 0)
_objects[0].y = 0;
if (_countdown6 > 0) {
if (--_countdown6 == 0) {
_countdown4 = 150;
playSound(15, true);
}
} else if (_countdown4 > 0) {
if (--_countdown4 == 0) {
_countdown3 = 150;
} else if (_countdown5 > 0) {
++_countdown4;
++_score;
if (--_countdown5 == 0) {
stopSound(15);
_bugsChanceByKind[5] = 10;
_countdown7 = 40;
_countdown4 = 10 * (13 - _counter1);
return true;
}
} else {
if (--_countdown7 == 0) {
bool flag1 = false;
_countdown7 = _bugsChanceByKind[5];
for (int i = 3; i < 12 && !flag1; ++i) {
Obj *obj = &_objects[i];
if (obj->status == 13) {
const ObjInit *objInit = getObjInit(i - 3);
obj->x = objInit->x << 16;
obj->y = objInit->y << 16;
obj->anim = objInit->anim3;
obj->frameIndex = 0;
obj->ticks = _objects[0].anim->frameTicks[0];
obj->status = 9;
obj->damageCtr = 0;
obj->priority = 600;
++_counter1;
playSound(15);
flag1 = true;
}
}
}
}
} else if (_countdown3 > 0) {
if ((mouseButtons & kLeftButtonDown) || (mouseButtons & kRightButtonDown) || (--_countdown3 == 0)) {
_levelTimeDelay = 58;
_levelTimeLeft = 30;
_gameState = 1;
_gameTicks = 0;
++_counter4;
}
}
return true;
}
bool MinigameBbAnt::updateStatus3(int mouseX, int mouseY, uint mouseButtons) {
if (!isSoundPlaying(9) && _fromMainGame) {
_vm->_system->delayMillis(1000);
_gameDone = true;
}
return true;
}
void MinigameBbAnt::getRandomBugObjValues(int &x, int &y, int &animIndexIncr, int &field30) {
field30 = _vm->getRandom(4);
switch (field30) {
case 0:
y = -5;
x = _vm->getRandom(190) + 120;
animIndexIncr = 4;
break;
case 1:
x = 325;
y = _vm->getRandom(220) + 10;
animIndexIncr = 2;
break;
case 2:
y = 245;
x = _vm->getRandom(300) + 10;
animIndexIncr = 0;
break;
case 3:
x = -5;
y = _vm->getRandom(190) + 120;
animIndexIncr = 6;
break;
}
}
void MinigameBbAnt::insertBugSmokeObj(int x, int y, int bugObjIndex) {
Obj *obj = getFreeObject();
if (obj) {
Obj *bugObj = &_objects[bugObjIndex];
bugObj->hasSmoke = true;
obj->kind = 7;
obj->x = x;
obj->y = y;
obj->priority = 950;
if (bugObj->status >= 4 && (bugObj->status <= 6 || bugObj->status == 8)) {
obj->xIncr = 0;
obj->yIncr = (-1 << 16);
} else {
obj->xIncr = bugObj->xIncr / 8;
obj->yIncr = bugObj->yIncr / 8;
}
obj->anim = getAnimation(158);
obj->frameIndex = 0;
obj->ticks = obj->anim->frameTicks[0];
}
}
void MinigameBbAnt::insertSmokeObj(int x, int y) {
Obj *obj = getFreeObject();
if (obj) {
obj->kind = 7;
obj->x = x;
obj->y = y;
obj->priority = 950;
obj->xIncr = 0x2000;
obj->yIncr = -0xC000;
obj->anim = getAnimation(158);
obj->frameIndex = 0;
obj->ticks = obj->anim->frameTicks[0];
}
}
void MinigameBbAnt::resetObj(int objIndex) {
_objects[objIndex].kind = 0;
}
void MinigameBbAnt::insertStompObj(int x, int y) {
Obj *obj = getFreeObject();
if (obj) {
obj->kind = 9;
obj->x = x;
obj->y = y;
obj->priority = 2000;
obj->xIncr = (0x1E0000 * _stompCount - x + 0x140000) / 15;
obj->yIncr = (0xE60000 - y) / 15;
obj->anim = getAnimation(130);
obj->frameIndex = 0;
obj->ticks = 15;
_lastStompObj = obj;
_hasLastStompObj = true;
}
}
void MinigameBbAnt::removeStompObj(Obj *obj) {
++_stompCount;
_hasLastStompObj = false;
obj->kind = 0;
}
void MinigameBbAnt::insertBugObj(int kind, int animIndexIncr, int always0, int x, int y, int field30, int always1) {
Obj *obj = getFreeObject();
if (obj) {
const ObjAnimation * const *objKindAnimTable = getObjKindAnimTable(kind);
obj->field30 = field30;
obj->animIndexIncr = animIndexIncr;
obj->kind = kind;
obj->x = x << 16;
obj->y = y << 16;
obj->priority = 610;
obj->xIncr = kPosIncrTbl1[0].x << 16;
obj->yIncr = kPosIncrTbl1[0].y << 16;
obj->anim = objKindAnimTable[0];
obj->frameIndex = 0;
obj->ticks = obj->anim->frameTicks[0];
obj->animIndex = 0;
obj->status = 1;
obj->damageCtr = 0;
obj->hasSmoke = false;
obj->flag = 0;
++_bugsCountByKind[kind];
++_totalBugsCount;
}
}
void MinigameBbAnt::removeBugObj(int objIndex) {
Obj *obj = &_objects[objIndex];
--_totalBugsCount;
--_bugsCountByKind[obj->kind];
obj->hasSmoke = false;
obj->kind = 0;
}
void MinigameBbAnt::updateBugObjAnim(int objIndex) {
Obj *obj = &_objects[objIndex];
switch (obj->field30) {
case 0:
obj->animIndexIncr = 4;
break;
case 1:
obj->animIndexIncr = 2;
break;
case 2:
obj->animIndexIncr = 0;
break;
case 3:
obj->animIndexIncr = 6;
break;
}
const ObjAnimation * const *objKindAnimTable = getObjKindAnimTable(obj->kind);
obj->xIncr = kPosIncrTbl1[obj->animIndexIncr].x << 16;
obj->yIncr = kPosIncrTbl1[obj->animIndexIncr].y << 16;
obj->anim = objKindAnimTable[obj->animIndexIncr];
obj->frameIndex = 0;
obj->ticks = obj->anim->frameTicks[0];
}
void MinigameBbAnt::updateObjAnim2(int objIndex) {
Obj *obj = &_objects[objIndex];
obj->animIndexIncr += _vm->getRandom(3) - 1;
if (obj->animIndexIncr < 0)
obj->animIndexIncr = 7;
if (obj->animIndexIncr > 7)
obj->animIndexIncr = 0;
obj->animIndexIncr += 4;
if (obj->animIndexIncr >= 8)
obj->animIndexIncr %= 8;
const ObjAnimation * const *objKindAnimTable = getObjKindAnimTable(obj->kind);
obj->xIncr = kPosIncrTbl1[obj->animIndex + obj->animIndexIncr].x << 16;
obj->yIncr = kPosIncrTbl1[obj->animIndex + obj->animIndexIncr].y << 16;
obj->anim = objKindAnimTable[obj->animIndex + obj->animIndexIncr];
obj->frameIndex = 0;
obj->ticks = obj->anim->frameTicks[0];
obj->x += obj->xIncr;
obj->y += obj->yIncr;
}
void MinigameBbAnt::insertRandomBugObj(int kind) {
int x, y, animIndexIncr, field30;
getRandomBugObjValues(x, y, animIndexIncr, field30);
insertBugObj(kind, animIndexIncr, 0, x, y, field30, 1);
}
bool MinigameBbAnt::isBugOutOfScreen(int objIndex) {
Obj *obj = &_objects[objIndex];
return
obj->x < (-10 << 16) || obj->x > (330 << 16) ||
obj->y < (-10 << 16) || obj->y > (250 << 16);
}
void MinigameBbAnt::updateObjAnim3(int objIndex) {
Obj *obj = &_objects[objIndex];
obj->animIndexIncr += _vm->getRandom(3) - 1;
if (obj->animIndexIncr < 0)
obj->animIndexIncr = 7;
if (obj->animIndexIncr > 7)
obj->animIndexIncr = 0;
const ObjAnimation * const *objKindAnimTable = getObjKindAnimTable(obj->kind);
obj->xIncr = kPosIncrTbl1[obj->animIndexIncr].x << 16;
obj->yIncr = kPosIncrTbl1[obj->animIndexIncr].y << 16;
obj->anim = objKindAnimTable[obj->animIndexIncr];
}
void MinigameBbAnt::updateBugObj1(int objIndex) {
Obj *obj = &_objects[objIndex];
bool flag1 = false;
bool flag2 = false;
if (--obj->ticks == 0) {
++obj->frameIndex;
if (obj->anim->frameCount == obj->frameIndex) {
obj->frameIndex = 0;
obj->ticks = obj->anim->frameTicks[0];
flag1 = true;
} else {
obj->ticks = obj->anim->frameTicks[obj->frameIndex];
flag2 = true;
}
}
obj->x += obj->xIncr;
obj->y += obj->yIncr;
if (obj->status != 7) {
if (obj->damageCtr <= 5) {
obj->hasSmoke = false;
} else if (!obj->hasSmoke) {
obj->smokeCtr = 6;
insertBugSmokeObj(obj->x, obj->y, objIndex);
} else if (obj->damageCtr > 200 && obj->status != 4 && obj->status != 6) {
_score += kScoreTbl[obj->kind];
if (obj->status == 3) {
_objects[obj->otherObjIndex].status = 9;
_objects[obj->otherObjIndex].priority = 600;
if (_vm->getRandom(3) == 1 && !isAnySoundPlaying(kSoundTbl4, 10))
playSound(kSoundTbl3[_vm->getRandom(3)]);
} else {
if (_vm->getRandom(3) == 1 && !isAnySoundPlaying(kSoundTbl4, 10))
playSound(kSoundTbl2[_vm->getRandom(3)]);
}
flag1 = false;
const ObjAnimation * const *objKindAnimTable = getObjKindAnimTable(obj->kind);
obj->hasSmoke = false;
obj->status = 4;
obj->xIncr = 0;
obj->yIncr = 0;
obj->anim = objKindAnimTable[16];
obj->frameIndex = 0;
obj->ticks = obj->anim->frameTicks[0];
obj->priority = 605;
if (obj->kind == 5) {
// Skull Beetle
if (_stompCount < 10)
insertStompObj(obj->x, obj->y);
obj->kind = 4;
obj->anim = getObjAnim(70);
obj->ticks = obj->anim->frameTicks[0];
}
} else if (--obj->smokeCtr == 0) {
obj->smokeCtr = 6;
insertBugSmokeObj(obj->x, obj->y, objIndex);
}
}
switch (obj->status) {
case 1:
if (isBugOutOfScreen(objIndex))
removeBugObj(objIndex);
else if (flag1 && !obj->flag)
updateObjAnim3(objIndex);
break;
case 3:
// Bug carries candy
_objects[obj->otherObjIndex].x = obj->x;
_objects[obj->otherObjIndex].y = obj->y;
if (isBugOutOfScreen(objIndex)) {
_objects[obj->otherObjIndex].status = 13;
_objects[obj->otherObjIndex].x = (500 << 16);
_objects[obj->otherObjIndex].y = (500 << 16);
removeBugObj(objIndex);
--_counter1;
}
break;
case 4:
if (flag1) {
const ObjAnimation * const *objKindAnimTable = getObjKindAnimTable(obj->kind);
obj->status = 6;
obj->xIncr = 0;
obj->yIncr = 0;
obj->anim = objKindAnimTable[17];
obj->frameIndex = 0;
obj->ticks = obj->anim->frameTicks[0];
}
break;
case 6:
if (flag1) {
const ObjAnimation * const *objKindAnimTable = getObjKindAnimTable(obj->kind);
obj->status = 7;
obj->xIncr = kPosIncrTbl2[obj->animIndexIncr].x << 16;
obj->yIncr = kPosIncrTbl2[obj->animIndexIncr].y << 16;
obj->anim = objKindAnimTable[obj->animIndexIncr + 8];
obj->frameIndex = 0;
obj->ticks = obj->anim->frameTicks[0];
obj->animIndex = 8;
obj->priority = 610;
}
break;
case 7:
if (isBugOutOfScreen(objIndex))
removeBugObj(objIndex);
break;
case 8:
if (--obj->counter != 0) {
if (flag2 && obj->frameIndex == 13) {
obj->frameIndex = 4;
obj->ticks = obj->anim->frameTicks[4];
}
} else {
obj->status = obj->status2;
obj->anim = obj->anim2;
obj->frameIndex = obj->frameIndex2;
obj->ticks = obj->ticks2;
obj->xIncr = kPosIncrTbl1[obj->animIndex + obj->animIndexIncr].x << 16;
obj->yIncr = kPosIncrTbl1[obj->animIndex + obj->animIndexIncr].y << 16;
obj->priority = 610;
}
break;
}
}
void MinigameBbAnt::updateObjKind2(int objIndex) {
updateBugObj1(objIndex);
}
void MinigameBbAnt::updateObjKind3(int objIndex) {
updateBugObj1(objIndex);
}
void MinigameBbAnt::updateObjKind4(int objIndex) {
updateBugObj1(objIndex);
}
void MinigameBbAnt::updateObjKind5(int objIndex) {
++_skullBugCtr;
updateBugObj1(objIndex);
}
void MinigameBbAnt::updateStompObj(int objIndex) {
Obj *obj = &_objects[objIndex];
obj->x += obj->xIncr;
obj->y += obj->yIncr;
if (--obj->ticks == 0)
removeStompObj(obj);
}
void MinigameBbAnt::updateSmokeObj(int objIndex) {
Obj *obj = &_objects[objIndex];
obj->x += obj->xIncr;
obj->y += obj->yIncr;
if (--obj->ticks == 0) {
++obj->frameIndex;
if (obj->anim->frameCount == obj->frameIndex)
resetObj(objIndex);
else
obj->ticks = obj->anim->frameTicks[obj->frameIndex];
}
}
void MinigameBbAnt::updateFootObj(int objIndex) {
Obj *obj = &_objects[objIndex];
switch (obj->status) {
case 1:
obj->xIncr = -0x8000;
obj->yIncr = (-4 << 16);
obj->status = 2;
_stompCounter1 += 5;
_stompCounter2 = 100;
break;
case 2:
obj->x += obj->xIncr;
obj->y += obj->yIncr;
obj->yIncr += 0x2000;
if (obj->y < (20 << 16)) {
obj->xIncr = 0x8000;
obj->yIncr = (7 << 16);
obj->status = 3;
}
break;
case 3:
obj->x += obj->xIncr;
obj->y += obj->yIncr;
obj->yIncr += 0x2000;
if (obj->y >= 0x4B0000) {
obj->x = (40 << 16);
obj->y = (75 << 16);
obj->status = 4;
_stompDelay1 = 6;
_stompY = 0;
playSound(14);
}
break;
case 4:
if (--_stompDelay1 == 0) {
_gameTicks = 0;
if (_stompDelay1 % 2)
_stompY = _stompY < 1 ? -8 : 0;
} else {
obj->status = 0;
_stompX = 0;
_stompY = 0;
// Stun all bugs
for (int i = 12; i < kMaxObjectsCount; ++i) {
Obj *bugObj = &_objects[i];
if (bugObj->kind >= 1 && bugObj->kind <= 5) {
bugObj->counter = _vm->getRandom(200) + 360;
const ObjAnimation * const *objKindAnimTable = getObjKindAnimTable(bugObj->kind);
if (bugObj->status == 8) {
bugObj->hasSmoke = false;
bugObj->xIncr = 0;
bugObj->yIncr = 0;
bugObj->status2 = 7;
bugObj->anim2 = objKindAnimTable[bugObj->animIndexIncr + 8];
bugObj->frameIndex2 = 0;
bugObj->ticks2 = obj->anim->frameTicks[0];
bugObj->anim = objKindAnimTable[17];
bugObj->frameIndex = 0;
bugObj->ticks = _vm->getRandom(4) + obj->anim->frameTicks[0];
bugObj->animIndex = 8;
} else {
if (bugObj->status == 3) {
bugObj->priority = 610;
_objects[bugObj->otherObjIndex].status = 9;
_objects[bugObj->otherObjIndex].priority = 600;
}
bugObj->hasSmoke = false;
bugObj->xIncr = 0;
bugObj->yIncr = 0;
bugObj->status2 = 1;
bugObj->anim2 = bugObj->anim;
bugObj->frameIndex2 = bugObj->frameIndex;
bugObj->ticks2 = bugObj->ticks;
bugObj->anim = objKindAnimTable[17];
bugObj->frameIndex = 0;
bugObj->ticks = _vm->getRandom(4) + obj->anim->frameTicks[0];
}
bugObj->status = 8;
bugObj->priority = 605;
}
}
}
break;
}
}
bool MinigameBbAnt::isBugAtCandy(int objIndex, int &candyObjIndex) {
Obj *obj = &_objects[objIndex];
bool result = false;
if (obj->kind >= 1 && obj->kind <= 4) {
const BBRect &frameRect1 = obj->anim->frameRects[obj->frameIndex];
const int obj1X1 = frameRect1.x + (obj->x >> 16);
const int obj1Y1 = frameRect1.y + (obj->y >> 16);
const int obj1X2 = obj1X1 + frameRect1.width;
const int obj1Y2 = obj1Y1 + frameRect1.height;
for (int i = 3; i < 12 && !result; ++i) {
Obj *obj2 = &_objects[i];
const BBRect &frameRect2 = obj->anim->frameRects[obj2->frameIndex]; // sic
const int obj2X1 = (obj2->x >> 16) + frameRect2.x;
const int obj2Y1 = (obj2->y >> 16) + frameRect2.y;
const int obj2X2 = obj2X1 + frameRect2.width;
const int obj2Y2 = obj2Y1 + frameRect2.height;
if (obj2->status == 9 && obj1X1 <= obj2X2 && obj1X2 >= obj2X1 && obj1Y1 <= obj2Y2 && obj1Y2 >= obj2Y1) {
result = true;
candyObjIndex = i;
}
}
}
return result;
}
bool MinigameBbAnt::isMagGlassAtBug(int objIndex) {
Obj *obj = &_objects[objIndex];
Obj *obj0 = &_objects[0];
bool result = false;
if (obj->kind >= 1 && obj->kind <= 5) {
const BBRect &frameRect1 = obj0->anim->frameRects[0];
const int obj1X1 = obj0->x + frameRect1.x;
const int obj1Y1 = obj0->y + frameRect1.y;
const int obj1X2 = obj1X1 + frameRect1.width;
const int obj1Y2 = obj1Y1 + frameRect1.height;
const BBRect &frameRect2 = obj->anim->frameRects[obj->frameIndex];
const int obj2X1 = (obj->x >> 16) + frameRect2.x;
const int obj2Y1 = (obj->y >> 16) + frameRect2.y;
const int obj2X2 = obj2X1 + frameRect2.width;
const int obj2Y2 = obj2Y1 + frameRect2.height;
if (obj2X2 >= obj1X1 && obj1X2 >= obj2X1 && obj1Y1 <= obj2Y2 && obj1Y2 >= obj2Y1)
result = true;
}
return result;
}
bool MinigameBbAnt::isMagGlassAtBeavisLeg(int objIndex) {
Obj *obj = &_objects[objIndex];
Obj *magGlassObj = &_objects[0];
bool result = false;
const BBRect &frameRect1 = magGlassObj->anim->frameRects[0];
const int obj1X1 = magGlassObj->x + frameRect1.x;
const int obj1Y1 = magGlassObj->y + frameRect1.y;
const int obj1X2 = obj1X1 + frameRect1.width;
const int obj1Y2 = obj1Y1 + frameRect1.height;
const BBRect &frameRect2 = obj->anim->frameRects[obj->frameIndex];
const int obj2X1 = (obj->x >> 16) + frameRect2.x;
const int obj2Y1 = (obj->y >> 16) + frameRect2.y;
const int obj2X2 = obj2X1 + frameRect2.width;
const int obj2Y2 = obj2Y1 + frameRect2.height;
if (obj2X2 >= obj1X1 && obj1X2 >= obj2X1 && obj1Y1 <= obj2Y2 && obj1Y2 >= obj2Y1)
result = true;
return result;
}
bool MinigameBbAnt::testObj5(int objIndex) {
Obj *obj = &_objects[objIndex];
bool result = false;
if (obj->kind >= 1 && obj->kind <= 5) {
const int x = obj->x >> 16;
const int y = obj->y >> 16;
if (x < 0 || x >= 110 || y < 0 || y >= 110) {
obj->flag = 0;
} else if (!obj->flag) {
obj->flag = 1;
result = true;
}
}
return result;
}
void MinigameBbAnt::updateObjs(uint mouseButtons) {
for (int i = 12; i < kMaxObjectsCount; ++i) {
Obj *obj = &_objects[i];
if (obj->kind) {
if ((mouseButtons & kLeftButtonClicked) && isMagGlassAtBug(i))
obj->damageCtr += 100;
if (obj->status == 1) {
int candyObjIndex;
if (isBugAtCandy(i, candyObjIndex)) {
obj->status = 3;
obj->otherObjIndex = candyObjIndex;
_objects[candyObjIndex].otherObjIndex = i;
_objects[candyObjIndex].status = 10;
_objects[candyObjIndex].priority = 620;
_objects[candyObjIndex].status = 11;
_objects[candyObjIndex].anim = getObjInit(candyObjIndex - 3)->anim3;
updateBugObjAnim(i);
if (_vm->getRandom(3) == 1 && !isAnySoundPlaying(kSoundTbl4, 10))
playSound(kSoundTbl1[_vm->getRandom(4)]);
}
}
if (testObj5(i)) {
updateObjAnim2(i);
}
if (obj->damageCtr) {
--obj->damageCtr;
if (!isSoundPlaying(13))
playSound(13);
}
switch (obj->kind) {
case 1:
updateBugObj1(i);
break;
case 2:
updateObjKind2(i);
break;
case 3:
updateObjKind3(i);
break;
case 4:
updateObjKind4(i);
break;
case 5:
updateObjKind5(i);
break;
case 7:
updateSmokeObj(i);
break;
case 9:
updateStompObj(i);
break;
}
}
}
}
bool MinigameBbAnt::run(bool fromMainGame) {
memset(_objects, 0, sizeof(_objects));
_numbersAnim = getAnimation(167);
_backgroundSpriteIndex = 303;
_titleScreenSpriteIndex = 304;
_fromMainGame = fromMainGame;
_hiScore = 0;
if (!_fromMainGame)
_hiScore = loadHiscore(kMinigameBbAnt);
_gameState = 0;
_gameResult = false;
_gameDone = false;
initObjects();
initVars();
_spriteModule = new SpriteModule();
_spriteModule->load("bbant/bbant.000");
Palette palette = _spriteModule->getPalette();
_vm->_screen->setPalette(palette);
loadSounds();
_gameTicks = 0;
playSound(12, true);
while (!_vm->shouldQuit() &&!_gameDone) {
_vm->updateEvents();
update();
}
_vm->_sound->unloadSounds();
if (!_fromMainGame)
saveHiscore(kMinigameBbAnt, _hiScore);
delete _spriteModule;
return _gameResult;
}
void MinigameBbAnt::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 = true;
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 MinigameBbAnt::scale2x(int x, int y) {
Graphics::Surface *surface = _vm->_screen->_surface;
int srcX = x + 14, srcY = y + 14;
int srcW = kScaleDim, srcH = kScaleDim;
if (srcX < 0) {
srcW += srcX;
srcX = 0;
}
if (srcY < 0) {
srcH += srcY;
srcY = 0;
}
if (srcX + srcW >= 320)
srcW = 320 - srcX - 1;
if (srcY + srcH >= 240)
srcH = 240 - srcY - 1;
for (int yc = 0; yc < srcH; ++yc) {
byte *src = (byte*)surface->getBasePtr(srcX, srcY + yc);
memcpy(&_scaleBuf[yc * kScaleDim], src, srcW);
}
int dstX = x, dstY = y;
int dstW = 2 * kScaleDim, dstH = 2 * kScaleDim;
if (dstX < 0) {
dstW += dstX;
dstX = 0;
}
if (dstY < 0) {
dstH += dstY;
dstY = 0;
}
if (dstX + dstW >= 320)
dstW = 320 - dstX - 1;
if (dstY + dstH >= 240)
dstH = 240 - dstY - 1;
int w = MIN(srcW * 2, dstW), h = MIN(srcH * 2, dstH);
for (int yc = 0; yc < h; ++yc) {
byte *src = _scaleBuf + kScaleDim * (yc / 2);
byte *dst = (byte*)surface->getBasePtr(dstX, dstY + yc);
for (int xc = 0; xc < w; ++xc)
dst[xc] = src[xc / 2];
}
}
void MinigameBbAnt::loadSounds() {
for (uint i = 0; i < kSoundFilenamesCount; ++i) {
Common::String filename = Common::String::format("bbant/%s", kSoundFilenames[i]);
_vm->_sound->loadSound(filename.c_str());
}
}
} // End of namespace Bbvs