/* 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 3 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, see . * */ #include "got/game/boss3.h" #include "got/events.h" #include "got/game/back.h" #include "got/game/move.h" #include "got/game/move_patterns.h" #include "got/game/status.h" #include "got/sound.h" #include "got/vars.h" namespace Got { #define LFC 10 static const byte EXPLOSION[4][8] = { {126, 127, 128, 129, 130, 131, 132, 133}, {146, 147, 148, 149, 150, 151, 152, 153}, {166, 167, 168, 169, 170, 171, 172, 173}, {186, 187, 188, 189, 190, 191, 192, 193} }; static int bossMode; static int numPods1; static byte podSpeed; static bool explosionFlag[4][8]; static byte explosionCounter; static int bossDie(); static void boss3CheckHit(); static void bossChangeMode(); static void setBoss(Actor *actor) { _G(actor[4])._nextFrame = actor->_nextFrame; _G(actor[5])._nextFrame = actor->_nextFrame; _G(actor[6])._nextFrame = actor->_nextFrame; _G(actor[4])._lastDir = actor->_dir; _G(actor[5])._lastDir = actor->_dir; _G(actor[6])._lastDir = actor->_dir; _G(actor[4])._dir = actor->_dir; _G(actor[5])._dir = actor->_dir; _G(actor[6])._dir = actor->_dir; _G(actor[4])._x = actor->_x + 16; _G(actor[4])._y = actor->_y; _G(actor[5])._x = actor->_x; _G(actor[5])._y = actor->_y + 16; _G(actor[6])._x = actor->_x + 16; _G(actor[6])._y = actor->_y + 16; } // Boss - Loki-2 static int boss3Movement1(Actor *actor) { int rx, ry, i, numPods = 0; int fcount; actor->_numMoves = 2; podSpeed = 2; switch (_G(setup)._difficultyLevel) { case 0: numPods = 3; break; case 1: numPods = 5; break; case 2: numPods = 8; break; default: break; } if (!actor->_temp1) { // Disappear actor->_dir = 1; actor->_frameCount = LFC; actor->_nextFrame = 0; actor->_temp1 = 1; actor->_i6 = 1; actor->_solid |= 128; _G(actor[4])._solid |= 128; _G(actor[5])._solid |= 128; _G(actor[6])._solid |= 128; playSound(EXPLODE, true); goto done; } if (actor->_i6) { // Fade out fcount = actor->_frameCount - 1; if (fcount <= 0) { actor->_nextFrame++; if (actor->_nextFrame > 2) { actor->_i6 = 0; actor->_temp3 = 160; } actor->_frameCount = 3; } else actor->_frameCount = fcount; goto done1; } if (actor->_temp3 > 1) { actor->_temp3--; goto done1; } if (actor->_temp3) { for (i = 0; i < numPods1; i++) if (_G(actor[19 + i])._active) goto done1; while (true) { rx = g_events->getRandomNumber(255) + 16; ry = g_events->getRandomNumber(143); if (!overlap(rx, ry, rx + 32, ry + 32, _G(thorX1), _G(thorY1), _G(thorX2), _G(thorY2))) break; } actor->_x = rx; actor->_y = ry; actor->_frameCount = LFC; actor->_temp4 = 40; actor->_temp3 = 0; playSound(EXPLODE, true); goto done1; } if (actor->_temp4) { // Fade in fcount = actor->_frameCount - 1; if (fcount <= 0) { actor->_nextFrame--; if (actor->_nextFrame > 254) { actor->_nextFrame = 0; actor->_dir = 0; actor->_temp4 = 0; actor->_temp5 = 80; actor->_solid &= 0x7f; _G(actor[4])._solid &= 0x7f; _G(actor[5])._solid &= 0x7f; _G(actor[6])._solid &= 0x7f; } actor->_frameCount = 3; } else actor->_frameCount = fcount; goto done1; } if (actor->_temp5) { // Shoot actor->_temp5--; if (actor->_temp5 == 20) { actor->_nextFrame = 3; goto done1; } if (!actor->_temp5) { if (_G(actor[4])._currNumShots < _G(actor[4])._numShotsAllowed) { actorAlwaysShoots(&_G(actor[4]), 0); const byte shot_actor = _G(actor[4])._shotActor; _G(actor[shot_actor])._numMoves = podSpeed; _G(actor[shot_actor])._x = actor->_x + 8; _G(actor[shot_actor])._y = actor->_y + 16; _G(actor[shot_actor])._temp5 = 0; for (i = 0; i < numPods; i++) _G(actor[20 + i]) = _G(actor[19]); numPods1 = numPods; actor->_temp1 = 0; } } if (actor->_temp5 < 31) goto done1; } done: fcount = actor->_frameCount - 1; if (fcount <= 0) { actor->_nextFrame++; if (actor->_nextFrame > 2) actor->_nextFrame = 0; actor->_frameCount = LFC; } else actor->_frameCount = fcount; done1: setBoss(actor); return actor->_dir; } // Boss - Loki-1 int boss3Movement(Actor *actor) { int x1, y1, ox, oy; int fcount; if (actor->_temp2) actor->_temp2--; if (_G(bossDead)) return bossDie(); boss3CheckHit(); if (!bossMode) return boss3Movement1(actor); numPods1 = 10; switch (_G(setup)._difficultyLevel) { case 0: actor->_numMoves = 3; actor->_speed = 2; break; case 1: actor->_numMoves = 2; actor->_speed = 1; break; case 2: actor->_numMoves = 5; actor->_speed = 2; break; default: break; } int d = actor->_lastDir; actor->_temp3++; int f = 0; if (actor->_temp4) { actor->_temp4--; if (!actor->_temp4) { actor->_temp3 = 0; _G(actor[3])._frameSpeed = 4; _G(actor[3])._dir = 0; _G(actor[3])._lastDir = 0; _G(actor[3])._nextFrame = 3; _G(actor[4])._dir = 0; _G(actor[4])._lastDir = 0; _G(actor[4])._nextFrame = 3; } goto skip_move; } if (actor->_edgeCounter) actor->_edgeCounter--; else goto new_dir; if (overlap(actor->_x + 2, actor->_y + 8, actor->_x + 30, actor->_y + 30, _G(thor)->_x, _G(thor)->_y + 4, _G(thor)->_x + 15, _G(thor)->_y + 15)) thorDamaged(actor); ox = actor->_x; oy = actor->_y; switch (actor->_temp5) { case 0: x1 = _G(actor[3])._x; y1 = _G(actor[3])._y - 2; if (!checkMove2(x1, y1, &_G(actor[3]))) { f = 1; break; } if (!checkMove2(x1 + 16, y1, &_G(actor[4]))) f = 1; actor->_y = oy - 2; break; case 1: x1 = _G(actor[5])._x; y1 = _G(actor[5])._y + 2; if (!checkMove2(x1, y1, &_G(actor[5]))) { f = 1; break; } if (!checkMove2(x1 + 16, y1, &_G(actor[6]))) f = 1; actor->_y = oy + 2; break; case 2: x1 = _G(actor[3])._x - 2; y1 = _G(actor[3])._y; if (!checkMove2(x1, y1, &_G(actor[3]))) { f = 1; break; } if (!checkMove2(x1, y1 + 16, &_G(actor[5]))) f = 1; actor->_x = ox - 2; break; case 3: x1 = _G(actor[4])._x + 2; y1 = _G(actor[4])._y; if (!checkMove2(x1, y1, &_G(actor[4]))) { f = 1; break; } if (!checkMove2(x1, y1 + 16, &_G(actor[6]))) f = 1; actor->_x = ox + 2; break; case 4: //ul x1 = _G(actor[3])._x - 2; y1 = _G(actor[3])._y - 2; if (!checkMove2(x1, y1, &_G(actor[3]))) { f = 1; break; } actor->_x = ox - 2; actor->_y = oy - 2; break; case 5: x1 = _G(actor[4])._x + 2; y1 = _G(actor[4])._y - 2; if (!checkMove2(x1, y1, &_G(actor[4]))) { f = 1; break; } actor->_x = ox + 2; actor->_y = oy - 2; break; case 6: x1 = _G(actor[6])._x + 2; y1 = _G(actor[6])._y + 2; if (!checkMove2(x1, y1, &_G(actor[6]))) { f = 1; break; } actor->_x = ox + 2; actor->_y = oy + 2; break; case 7: x1 = _G(actor[5])._x - 2; y1 = _G(actor[5])._y + 2; if (!checkMove2(x1, y1, &_G(actor[5]))) { f = 1; break; } actor->_x = ox - 2; actor->_y = oy + 2; break; default: break; } fcount = actor->_frameCount - 1; if (fcount) { actor->_nextFrame++; if (actor->_nextFrame > 2) actor->_nextFrame = 0; actor->_frameCount = 30; } else actor->_frameCount = fcount; skip_move: setBoss(actor); if (!f) goto done; new_dir: if (actor->_temp3 < 120) goto new_dir1; _G(actor[3])._frameSpeed = 8; _G(actor[3])._nextFrame = 3; _G(actor[4])._nextFrame = 3; actor->_temp4 = 120; actorAlwaysShoots(actor, 0); _G(actor[actor->_shotActor])._x = actor->_x + 8; _G(actor[actor->_shotActor])._y = actor->_y - 8; _G(actor[actor->_shotActor])._temp1 = g_events->getRandomNumber(90, 189); _G(actor[actor->_shotActor])._temp5 = 30; _G(actor[actor->_shotActor])._speed = 2; playSound(BOSS12, true); new_dir1: actor->_temp5 = _G(rand1) % 8; actor->_edgeCounter = _G(rand2) + 60; done: if (actor->_directions == 1) return 0; return d; } static void boss3CheckHit() { if (_G(actor[3])._solid & 128) { for (int rep = 3; rep < 7; rep++) _G(actor[rep])._magicHit = 0; return; } if (_G(actor[3])._magicHit || _G(actor[4])._magicHit || _G(actor[5])._magicHit || _G(actor[6])._magicHit) { if (!_G(actor[3])._temp2) { actorDamaged(&_G(actor[3]), 10); if (_G(cheat) && _G(keyFlag[GOT_Z])) _G(actor[3])._health -= 50; else _G(actor[3])._health -= 10; _G(actor[3])._moveCountdown = 50; _G(actor[3])._vulnerableCountdown = 50; playSound(BOSS13, true); for (int rep = 4; rep < 7; rep++) { _G(actor[rep])._magicHit = 0; _G(actor[rep])._nextFrame = 1; _G(actor[rep])._moveCountdown = 50; } if (_G(actor[3])._health == 0) { _G(bossDead) = true; for (int rep = 7; rep < MAX_ACTORS; rep++) { if (_G(actor[rep])._active) actorDestroyed(&_G(actor[rep])); } } if (_G(actor[3])._health == 50) { bossChangeMode(); _G(actor[3])._temp1 = 0; _G(actor[3])._temp2 = 0; _G(actor[3])._temp3 = 0; _G(actor[3])._temp4 = 0; _G(actor[3])._temp5 = 0; _G(actor[3])._i6 = 0; _G(actor[3])._moveCountdown = 2; } else { _G(actor[3])._temp2 = 40; } } for (int rep = 3; rep < 7; rep++) _G(actor[rep])._magicHit = 0; } } static void bossChangeMode() { if (!_G(bossIntro2)) { Gfx::Pics loki("FACE18", 262); executeScript(1003, loki); _G(bossIntro2) = true; } bossMode = 0; } void boss3SetupLevel() { setupBoss(3); _G(bossActive) = true; musicPause(); playSound(BOSS11, true); g_events->send("Game", GameMessage("PAUSE", 40)); if (!_G(bossIntro1)) { Gfx::Pics loki("FACE18", 262); executeScript(1002, loki); _G(bossIntro1) = true; } musicPlay(7, true); _G(appleDropCounter) = 0; bossMode = 1; } static int bossDie() { if (_G(bossDead)) { for (int rep = 0; rep < 4; rep++) { const int x1 = _G(actor[3 + rep])._lastX[_G(pge)]; const int y1 = _G(actor[3 + rep])._lastY[_G(pge)]; const int x = _G(actor[3 + rep])._x; const int y = _G(actor[3 + rep])._y; const int n = _G(actor[3 + rep])._actorNum; const int r = _G(actor[3 + rep])._dropRating; _G(actor[3 + rep]) = _G(explosion); _G(actor[3 + rep])._actorNum = n; _G(actor[3 + rep])._dropRating = r; _G(actor[3 + rep])._x = x; _G(actor[3 + rep])._y = y; _G(actor[3 + rep])._lastX[_G(pge)] = x1; _G(actor[3 + rep])._lastX[_G(pge) ^ 1] = x; _G(actor[3 + rep])._lastY[_G(pge)] = y1; _G(actor[3 + rep])._lastY[_G(pge) ^ 1] = y; _G(actor[3 + rep])._active = true; _G(actor[3 + rep])._vulnerableCountdown = 255; _G(actor[3 + rep])._moveType = 6; _G(actor[3 + rep])._nextFrame = rep; _G(actor[3 + rep])._speed = g_events->getRandomNumber(6, 8); _G(actor[3 + rep])._currNumShots = (10 - _G(actor[3 + rep])._speed) * 10; _G(actor[3 + rep])._moveCountdown = _G(actor[3 + rep])._speed; } playSound(EXPLODE, true); _G(bossDead) = true; } return _G(actor[3])._lastDir; } void boss3ClosingSequence1() { musicPlay(6, true); odinSpeaks(1001, 0, "CLOSING"); } void boss3ClosingSequence2() { fillScore(20, "CLOSING"); } void boss3ClosingSequence3() { fillHealth(); fillMagic(); for (int rep = 0; rep < 16; rep++) _G(scrn)._actorType[rep] = 0; _G(bossDead) = false; _G(setup)._bossDead[2] = true; _G(gameOver) = true; _G(bossActive) = false; _G(scrn)._music = 6; showLevel(BOSS_LEVEL3); #ifdef USE_TTS _G(thorInfo)._previousScore = -1; #endif _G(exitFlag) = 0; musicPause(); _G(newLevel) = ENDING_SCREEN; _G(thor)->_x = 152; _G(thor)->_y = 160; _G(thor)->_dir = 1; } void endingScreen() { for (int i = 3; i < MAX_ACTORS; i++) _G(actor[i])._moveType = 1; musicPlay(6, true); memset(explosionFlag, 0, sizeof(explosionFlag)); _G(endGame) = 1; _G(explosionRow) = 0; explosionCounter = 0; _G(actor[34]) = _G(explosion); _G(actor[34])._active = false; _G(actor[34])._speed = 2; _G(actor[34])._moveCountdown = _G(actor[34])._speed; _G(actor[34])._currNumShots = 3; // Used to reverse explosion _G(actor[34])._vulnerableCountdown = 255; _G(actor[34])._i2 = 6; } // Explode int endgame_one() { if (_G(actor[34])._i2) { _G(actor[34])._i2--; return 0; } _G(actor[34])._i2 = 6; playSound(EXPLODE, true); int r = _G(rand1) % 32; while (explosionFlag[r / 8][r % 8]) { r++; if (r > 31) r = 0; } explosionFlag[r / 8][r % 8] = true; int x = (EXPLOSION[r / 8][r % 8] % 20) * 16; int y = (EXPLOSION[r / 8][r % 8] / 20) * 16; _G(actor[34])._x = x; _G(actor[34])._y = y; _G(actor[34])._active = true; _G(actor[34])._nextFrame = 0; _G(actor[34])._currNumShots = 3; _G(scrn)._iconGrid[y / 16][x / 16] = _G(scrn)._backgroundColor; _G(endGame++); if (_G(endGame) > 32) { _G(actor[34])._active = false; _G(endGame) = 0; } return 1; } // Explode int endGameMovement() { if (!_G(endGame)) return 0; if (explosionCounter > 3) { endgame_one(); return 0; } if (_G(actor[34])._i2) { _G(actor[34])._i2--; return 0; } _G(actor[34])._i2 = 6; playSound(EXPLODE, true); int r = _G(rand1) % 8; while (explosionFlag[_G(explosionRow)][r]) { r++; if (r > 7) r = 0; } explosionFlag[_G(explosionRow)][r] = true; const int x = (EXPLOSION[_G(explosionRow)][r] % 20) * 16; const int y = (EXPLOSION[_G(explosionRow)][r] / 20) * 16; _G(actor[34])._x = x; _G(actor[34])._y = y; _G(actor[34])._active = true; _G(actor[34])._nextFrame = 0; _G(actor[34])._currNumShots = 3; _G(scrn)._iconGrid[y / 16][x / 16] = _G(scrn)._backgroundColor; _G(scrn)._iconGrid[(y / 16) - 4][x / 16] = _G(scrn)._backgroundColor; _G(endGame++); if (_G(endGame) > 8) { _G(endGame) = 1; _G(explosionRow++); explosionCounter++; if (explosionCounter > 3) { memset(explosionFlag, 0, sizeof(explosionFlag)); } } return 1; } } // namespace Got