758 lines
18 KiB
C++
758 lines
18 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 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 <http://www.gnu.org/licenses/>.
|
|
*
|
|
*/
|
|
|
|
#include "got/views/game_content.h"
|
|
#include "got/game/back.h"
|
|
#include "got/game/boss1.h"
|
|
#include "got/game/boss2.h"
|
|
#include "got/game/boss3.h"
|
|
#include "got/game/move.h"
|
|
#include "got/game/move_patterns.h"
|
|
#include "got/game/object.h"
|
|
#include "got/game/status.h"
|
|
#include "got/vars.h"
|
|
|
|
namespace Got {
|
|
namespace Views {
|
|
|
|
#define SPIN_INTERVAL 4
|
|
#define SPIN_COUNT 20
|
|
#define DEATH_THRESHOLD (SPIN_COUNT * SPIN_INTERVAL)
|
|
|
|
GameContent::GameContent() : View("GameContent") {
|
|
_surface.create(320, 192);
|
|
}
|
|
|
|
void GameContent::draw() {
|
|
GfxSurface s;
|
|
if (_G(gameMode) == MODE_THUNDER || _G(gameMode) == MODE_AREA_CHANGE) {
|
|
s.create(320, 192);
|
|
} else {
|
|
s = getSurface();
|
|
}
|
|
s.clear();
|
|
|
|
drawBackground(s);
|
|
drawObjects(s);
|
|
drawActors(s);
|
|
|
|
if ((GAME1 && _G(currentLevel) == BOSS_LEVEL1) ||
|
|
(GAME2 && _G(currentLevel) == BOSS_LEVEL2) ||
|
|
(GAME3 && _G(currentLevel) == BOSS_LEVEL3))
|
|
drawBossHealth(s);
|
|
|
|
// If we're shaking the screen, render the content with the shake X/Y
|
|
if (_G(gameMode) == MODE_THUNDER) {
|
|
GfxSurface win = getSurface();
|
|
win.clear();
|
|
win.simpleBlitFrom(s, _moveDelta);
|
|
} else if (_G(gameMode) == MODE_LIGHTNING) {
|
|
drawLightning(s);
|
|
|
|
} else if (_G(gameMode) == MODE_AREA_CHANGE) {
|
|
// Draw parts of the new scene along with parts of the old one
|
|
// as it's scrolled off-screen
|
|
GfxSurface win = getSurface();
|
|
|
|
switch (_G(transitionDir)) {
|
|
case DIR_LEFT:
|
|
win.simpleBlitFrom(s, Common::Rect(320 - _transitionPos, 0, 320, 192), Common::Point(0, 0));
|
|
win.simpleBlitFrom(_surface, Common::Rect(0, 0, 320 - _transitionPos, 192), Common::Point(_transitionPos, 0));
|
|
break;
|
|
case DIR_RIGHT:
|
|
win.simpleBlitFrom(_surface, Common::Rect(_transitionPos, 0, 320, 192), Common::Point(0, 0));
|
|
win.simpleBlitFrom(s, Common::Rect(0, 0, _transitionPos, 192), Common::Point(320 - _transitionPos, 0));
|
|
break;
|
|
case DIR_UP:
|
|
win.simpleBlitFrom(s, Common::Rect(0, 192 - _transitionPos, 320, 192), Common::Point(0, 0));
|
|
win.simpleBlitFrom(_surface, Common::Rect(0, 0, 320, 192 - _transitionPos), Common::Point(0, _transitionPos));
|
|
break;
|
|
case DIR_DOWN:
|
|
win.simpleBlitFrom(_surface, Common::Rect(0, _transitionPos, 320, 192), Common::Point(0, 0));
|
|
win.simpleBlitFrom(s, Common::Rect(0, 0, 320, _transitionPos), Common::Point(0, 192 - _transitionPos));
|
|
break;
|
|
case DIR_PHASED:
|
|
win.simpleBlitFrom(_surface); // Copy old surface
|
|
|
|
// Copy the randomly chosen blocks over from new scene
|
|
for (int i = 0; i < 240; ++i) {
|
|
int x = (i * 16) % 320;
|
|
int y = ((i * 16) / 320) * 16;
|
|
if (_phased[i])
|
|
win.simpleBlitFrom(s, Common::Rect(x, y, x + 16, y + 16), Common::Point(x, y));
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
#define MSG(STR, METHOD) \
|
|
else if (msg._name == STR) { \
|
|
METHOD(); \
|
|
return true; \
|
|
}
|
|
|
|
bool GameContent::msgGame(const GameMessage &msg) {
|
|
if (msg._name == "PAUSE") {
|
|
_G(gameMode) = MODE_PAUSE;
|
|
_pauseCtr = msg._value;
|
|
return true;
|
|
}
|
|
|
|
if (msg._name == "SCORE_INV") {
|
|
_G(gameMode) = MODE_SCORE_INV;
|
|
_pauseCtr = 0;
|
|
return true;
|
|
}
|
|
MSG("THROW_LIGHTNING", throwLightning)
|
|
MSG("THOR_DIES", thorDies)
|
|
MSG("CLOSING", closingSequence)
|
|
|
|
return false;
|
|
}
|
|
|
|
#undef MSG
|
|
|
|
bool GameContent::tick() {
|
|
checkThunderShake();
|
|
|
|
switch (_G(gameMode)) {
|
|
case MODE_NORMAL:
|
|
case MODE_THUNDER:
|
|
checkSwitchFlag();
|
|
checkForItem();
|
|
moveActors();
|
|
useItem();
|
|
updateActors();
|
|
checkForBossDead();
|
|
checkForCheats();
|
|
|
|
if (_G(endGame))
|
|
endGameMovement();
|
|
break;
|
|
|
|
case MODE_THOR_DIES:
|
|
if (_deathCtr < DEATH_THRESHOLD) {
|
|
spinThor();
|
|
} else if (_deathCtr < DEATH_THRESHOLD + 60) {
|
|
_G(thor)->_active = false;
|
|
++_deathCtr;
|
|
} else {
|
|
thorDead();
|
|
}
|
|
break;
|
|
|
|
case MODE_LIGHTNING:
|
|
if (--_lightningCtr == 0) {
|
|
lightningCountdownDone();
|
|
}
|
|
break;
|
|
|
|
case MODE_PAUSE:
|
|
if (--_pauseCtr == 0)
|
|
_G(gameMode) = MODE_NORMAL;
|
|
break;
|
|
|
|
case MODE_SCORE_INV:
|
|
if (--_pauseCtr <= 0) {
|
|
_pauseCtr = 2;
|
|
|
|
if (_G(thor)->_health > 0) {
|
|
_G(thor)->_health--;
|
|
playSound(WOOP, true);
|
|
addHealth(-1);
|
|
addScore(10);
|
|
|
|
} else if (_G(thorInfo)._magic > 0) {
|
|
_G(thorInfo)._magic--;
|
|
playSound(WOOP, true);
|
|
addMagic(-1);
|
|
addScore(10);
|
|
|
|
} else if (_G(thorInfo)._jewels) {
|
|
_G(thorInfo)._jewels--;
|
|
playSound(WOOP, true);
|
|
addJewels(-1);
|
|
addScore(10);
|
|
|
|
} else {
|
|
_G(gameMode) = MODE_NORMAL;
|
|
_pauseCtr = 0;
|
|
send(GameMessage("CLOSING"));
|
|
}
|
|
}
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
if (_G(eyeballs) == 1) { // eyeballs movement animation
|
|
if (!_G(setup).f25) {
|
|
_G(thor)->_dir = 0;
|
|
} else {
|
|
_G(thor)->_dir = 1;
|
|
}
|
|
}
|
|
|
|
checkForAreaChange();
|
|
|
|
// Check for end of game area
|
|
if (_G(endTile)) {
|
|
_G(endTile) = false;
|
|
Gfx::fadeOut();
|
|
|
|
// Add name to high scores list if necessary, and then show it
|
|
_G(highScores).add(_G(area), _G(playerName), _G(thorInfo)._score);
|
|
g_events->send("HighScores", GameMessage("HIGH_SCORES", _G(area)));
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
void GameContent::drawBackground(GfxSurface &s) {
|
|
const Level &screen = _G(scrn);
|
|
|
|
for (int y = 0; y < TILES_Y; y++) {
|
|
for (int x = 0; x < TILES_X; x++) {
|
|
if (screen._iconGrid[y][x] != 0) {
|
|
const Common::Point pt(x * TILE_SIZE, y * TILE_SIZE);
|
|
s.simpleBlitFrom(_G(bgPics[screen._backgroundColor]), pt);
|
|
s.simpleBlitFrom(_G(bgPics[screen._iconGrid[y][x]]), pt);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void GameContent::drawObjects(GfxSurface &s) {
|
|
for (int y = 0; y < TILES_Y; ++y) {
|
|
for (int x = 0; x < TILES_X; ++x) {
|
|
int p = (y * TILES_X) + x;
|
|
|
|
byte currObjId = _G(objectMap[p]);
|
|
if (currObjId) {
|
|
s.simpleBlitFrom(_G(objects[currObjId - 1]), Common::Point(x * TILE_SIZE, y * TILE_SIZE));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void GameContent::drawActors(GfxSurface &s) {
|
|
Actor *actor_ptr = &_G(actor[MAX_ACTORS - 1]);
|
|
Actor *actor2_storage = nullptr;
|
|
|
|
for (int actor_num = 0; actor_num <= MAX_ACTORS;) {
|
|
// Check for blinking flag
|
|
if (actor_ptr && actor_ptr->_active && !(actor_ptr->_show & 2)) {
|
|
actor_ptr->_lastX[_G(pge)] = actor_ptr->_x;
|
|
actor_ptr->_lastY[_G(pge)] = actor_ptr->_y;
|
|
|
|
const Graphics::ManagedSurface &frame = actor_ptr->pic[actor_ptr->_dir][actor_ptr->_frameSequence[actor_ptr->_nextFrame]];
|
|
s.simpleBlitFrom(frame, Common::Point(actor_ptr->_x, actor_ptr->_y));
|
|
}
|
|
|
|
// Move to the next actor
|
|
do {
|
|
--actor_ptr;
|
|
++actor_num;
|
|
|
|
if (actor_num == MAX_ACTORS)
|
|
actor_ptr = actor2_storage;
|
|
else if (actor_num == (MAX_ACTORS - 3))
|
|
actor2_storage = actor_ptr;
|
|
} while (actor_num == (MAX_ACTORS - 3));
|
|
}
|
|
|
|
if (_G(gameMode) == MODE_THOR_DIES && _deathCtr >= DEATH_THRESHOLD)
|
|
s.simpleBlitFrom(_G(objects[10]), Common::Point(_G(thor)->_x, _G(thor)->_y));
|
|
}
|
|
|
|
void GameContent::drawBossHealth(GfxSurface &s) {
|
|
int c;
|
|
|
|
int health = _G(actor[3])._health;
|
|
|
|
s.fillRect(Common::Rect(304, 2, 317, 81), 0);
|
|
s.fillRect(Common::Rect(305, 3, 316, 80), 28);
|
|
s.fillRect(Common::Rect(306, 4, 315, 79), 26);
|
|
s.fillRect(Common::Rect(307, 5, 314, 78), 24);
|
|
|
|
for (int i = 10; i > 0; i--) {
|
|
if (i * 10 > health)
|
|
c = 0;
|
|
else
|
|
c = 32;
|
|
|
|
s.fillRect(Common::Rect(308, 7 + (7 * (10 - i)), 313, 13 + (7 * (10 - i))), c);
|
|
}
|
|
}
|
|
|
|
void GameContent::checkThunderShake() {
|
|
if (_G(thunderSnakeCounter)) {
|
|
_G(gameMode) = MODE_THUNDER;
|
|
|
|
// Introduce a random screen shake by rendering screen 1 pixel offset randomly
|
|
static const int8 DELTA_X[4] = {-1, 1, 0, 0};
|
|
static const int8 DELTA_Y[4] = {0, 0, -1, 1};
|
|
int delta = g_events->getRandomNumber(3);
|
|
|
|
_moveDelta.x = DELTA_X[delta];
|
|
_moveDelta.y = DELTA_Y[delta];
|
|
|
|
_G(thunderSnakeCounter--);
|
|
if ((_G(thunderSnakeCounter) < MAX_ACTORS) && _G(thunderSnakeCounter) > 2) {
|
|
int thunderFl = _G(thunderSnakeCounter);
|
|
if (_G(actor[thunderFl])._active) {
|
|
_G(actor[thunderFl])._vulnerableCountdown = 0;
|
|
actorDamaged(&_G(actor[thunderFl]), 20);
|
|
}
|
|
}
|
|
|
|
if (!_G(thunderSnakeCounter)) {
|
|
_G(gameMode) = MODE_NORMAL;
|
|
_moveDelta = Common::Point(0, 0);
|
|
}
|
|
|
|
redraw();
|
|
}
|
|
}
|
|
|
|
void GameContent::checkSwitchFlag() {
|
|
if (!_G(switchUsed))
|
|
return;
|
|
|
|
switch (_G(switchUsed)) {
|
|
case 1:
|
|
switchIcons();
|
|
break;
|
|
case 2:
|
|
rotateArrows();
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
_G(switchUsed) = 0;
|
|
}
|
|
|
|
void GameContent::checkForItem() {
|
|
int thor_pos = _G(thor)->getPos();
|
|
if (_G(objectMap[thor_pos]))
|
|
pickUpObject(thor_pos);
|
|
}
|
|
|
|
void GameContent::moveActors() {
|
|
for (int i = 0; i < MAX_ACTORS; i++) {
|
|
if (_G(actor[i])._active) {
|
|
_G(actor[i])._moveCount = _G(actor[i])._numMoves;
|
|
while (_G(actor[i])._moveCount--)
|
|
moveActor(&_G(actor[i]));
|
|
|
|
if (i == 0)
|
|
setThorVars();
|
|
|
|
if (_G(newLevel) != _G(currentLevel))
|
|
return;
|
|
}
|
|
}
|
|
|
|
int thor_pos = _G(thor)->getPos();
|
|
_G(thor)->_centerX = thor_pos % 20;
|
|
_G(thor)->_centerY = thor_pos / 20;
|
|
}
|
|
|
|
void GameContent::updateActors() {
|
|
for (int i = 0; i < MAX_ACTORS; ++i) {
|
|
Actor *actor = &_G(actor[i]);
|
|
|
|
if (!actor->_active && actor->_dead > 0)
|
|
actor->_dead--;
|
|
}
|
|
}
|
|
|
|
void GameContent::checkForBossDead() {
|
|
if (_G(bossDead)) {
|
|
int loop;
|
|
for (loop = 3; loop < 7; loop++) {
|
|
if (_G(actor[loop])._active)
|
|
break;
|
|
}
|
|
|
|
if (loop == 7) {
|
|
_G(bossDead) = false;
|
|
|
|
_G(exitFlag) = 0;
|
|
|
|
if (_G(bossActive)) {
|
|
switch (_G(area)) {
|
|
case 1:
|
|
boss1ClosingSequence1();
|
|
break;
|
|
case 2:
|
|
boss2ClosingSequence1();
|
|
break;
|
|
case 3:
|
|
boss3ClosingSequence1();
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
_G(bossActive) = false;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void GameContent::checkForAreaChange() {
|
|
if (_G(gameMode) == MODE_AREA_CHANGE) {
|
|
// Area transition is already in progress
|
|
switch (_G(transitionDir)) {
|
|
case DIR_LEFT:
|
|
case DIR_RIGHT:
|
|
_transitionPos += 32;
|
|
if (_transitionPos == 320)
|
|
_G(gameMode) = MODE_NORMAL;
|
|
break;
|
|
case DIR_UP:
|
|
case DIR_DOWN:
|
|
_transitionPos += 16;
|
|
if (_transitionPos == 192)
|
|
_G(gameMode) = MODE_NORMAL;
|
|
break;
|
|
case DIR_PHASED:
|
|
_transitionPos += 10;
|
|
if (_transitionPos == 240) {
|
|
_G(gameMode) = MODE_NORMAL;
|
|
Common::fill(_phased, _phased + 240, false);
|
|
} else {
|
|
// The screen is subdivided into 240 16x16 blocks. Picks ones
|
|
// randomly to copy over from the new screen
|
|
for (int i = 0; i < 10; ++i) {
|
|
for (;;) {
|
|
int idx = g_events->getRandomNumber(239);
|
|
if (!_phased[idx]) {
|
|
_phased[idx] = true;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
if (_G(gameMode) == MODE_NORMAL) {
|
|
_transitionPos = 0;
|
|
showLevelDone();
|
|
}
|
|
|
|
} else if (_G(newLevel) != _G(currentLevel)) {
|
|
// Area transition beginning
|
|
_G(thor)->_show = 0;
|
|
_G(thor)->_active = false;
|
|
_G(hammer)->_active = false;
|
|
_G(tornadoUsed) = false;
|
|
|
|
// Draws the old area without Thor, and then save a copy of it.
|
|
// This will be used to scroll old area off-screen as new area scrolls in
|
|
draw();
|
|
_surface.copyFrom(getSurface());
|
|
|
|
// Set up new level
|
|
_G(thor)->_active = true;
|
|
showLevel(_G(newLevel));
|
|
}
|
|
}
|
|
|
|
void GameContent::thorDies() {
|
|
if (_G(gameMode) == MODE_SCORE_INV)
|
|
return;
|
|
|
|
// Stop any actors on-screen from moving
|
|
for (int li = 0; li < MAX_ACTORS; li++)
|
|
_G(actor[li])._show = 0;
|
|
_G(actor[2])._active = false;
|
|
|
|
// Set the state for showing death animation
|
|
_G(gameMode) = MODE_THOR_DIES;
|
|
_deathCtr = 0;
|
|
_G(shieldOn) = false;
|
|
|
|
playSound(DEAD, true);
|
|
}
|
|
|
|
void GameContent::spinThor() {
|
|
static const byte DIRS[] = {0, 2, 1, 3};
|
|
|
|
if (!_G(eyeballs)) {
|
|
_G(thor)->_dir = DIRS[(_deathCtr / SPIN_INTERVAL) % 4];
|
|
_G(thor)->_lastDir = DIRS[(_deathCtr / SPIN_INTERVAL) % 4];
|
|
}
|
|
|
|
++_deathCtr;
|
|
}
|
|
|
|
void GameContent::thorDead() {
|
|
int li = _G(thorInfo)._selectedItem;
|
|
int ln = _G(thorInfo)._inventory;
|
|
|
|
_G(newLevel) = _G(thorInfo)._lastScreen;
|
|
_G(thor)->_x = (_G(thorInfo)._lastIcon % 20) * 16;
|
|
_G(thor)->_y = ((_G(thorInfo)._lastIcon / 20) * 16) - 1;
|
|
if (_G(thor)->_x < 1)
|
|
_G(thor)->_x = 1;
|
|
if (_G(thor)->_y < 0)
|
|
_G(thor)->_y = 0;
|
|
_G(thor)->_lastX[0] = _G(thor)->_x;
|
|
_G(thor)->_lastX[1] = _G(thor)->_x;
|
|
_G(thor)->_lastY[0] = _G(thor)->_y;
|
|
_G(thor)->_lastY[1] = _G(thor)->_y;
|
|
_G(thor)->_dir = _G(thorInfo)._lastDir;
|
|
_G(thor)->_lastDir = _G(thorInfo)._lastDir;
|
|
_G(thor)->_health = _G(thorInfo)._lastHealth;
|
|
_G(thorInfo)._magic = _G(thorInfo)._lastMagic;
|
|
_G(thorInfo)._jewels = _G(thorInfo)._lastJewels;
|
|
_G(thorInfo)._keys = _G(thorInfo)._lastKeys;
|
|
_G(thorInfo)._score = _G(thorInfo)._lastScore;
|
|
_G(thorInfo)._object = _G(thorInfo)._lastObject;
|
|
_G(thorInfo)._objectName = _G(thorInfo)._lastObjectName;
|
|
|
|
if (ln == _G(thorInfo)._lastInventory) {
|
|
_G(thorInfo)._selectedItem = li;
|
|
} else {
|
|
_G(thorInfo)._selectedItem = _G(thorInfo)._lastItem;
|
|
_G(thorInfo)._inventory = _G(thorInfo)._lastInventory;
|
|
}
|
|
|
|
_G(setup) = _G(lastSetup);
|
|
|
|
_G(thor)->_numMoves = 1;
|
|
_G(thor)->_vulnerableCountdown = 60;
|
|
_G(thor)->_show = 60;
|
|
_G(appleFlag) = false;
|
|
_G(thunderSnakeCounter) = 0;
|
|
_G(tornadoUsed) = false;
|
|
_G(shieldOn) = false;
|
|
musicResume();
|
|
_G(actor[1])._active = false;
|
|
_G(actor[2])._active = false;
|
|
_G(thor)->_moveCountdown = 6;
|
|
_G(thor)->_active = true;
|
|
|
|
// Load saved data for new level back into scrn
|
|
_G(scrn).load(_G(newLevel));
|
|
|
|
_G(gameMode) = MODE_NORMAL;
|
|
_deathCtr = 0;
|
|
|
|
showLevel(_G(newLevel));
|
|
setThorVars();
|
|
}
|
|
|
|
void GameContent::checkForCheats() {
|
|
if (_G(cheats)._freezeHealth)
|
|
_G(thor)->_health = 150;
|
|
if (_G(cheats)._freezeMagic)
|
|
_G(thorInfo)._magic = 150;
|
|
if (_G(cheats)._freezeJewels)
|
|
_G(thorInfo)._jewels = 999;
|
|
}
|
|
|
|
void GameContent::placePixel(GfxSurface &s, int dir, int num) {
|
|
switch (dir) {
|
|
case 0:
|
|
_pixelY[dir][num] = _pixelY[dir][num - 1] - 1;
|
|
_pixelX[dir][num] = _pixelX[dir][num - 1] +
|
|
(1 - (g_events->getRandomNumber(2)));
|
|
break;
|
|
case 1:
|
|
if (g_events->getRandomNumber(1)) {
|
|
_pixelX[dir][num] = _pixelX[dir][num - 1] + 1;
|
|
_pixelY[dir][num] = _pixelY[dir][num - 1] + (0 - (g_events->getRandomNumber(1)));
|
|
} else {
|
|
_pixelY[dir][num] = _pixelY[dir][num - 1] - 1;
|
|
_pixelX[dir][num] = _pixelX[dir][num - 1] + (1 - (g_events->getRandomNumber(1)));
|
|
}
|
|
break;
|
|
case 2:
|
|
_pixelX[dir][num] = _pixelX[dir][num - 1] + 1;
|
|
_pixelY[dir][num] = _pixelY[dir][num - 1] + (1 - (g_events->getRandomNumber(2)));
|
|
break;
|
|
case 3:
|
|
if (g_events->getRandomNumber(1)) {
|
|
_pixelX[dir][num] = _pixelX[dir][num - 1] + 1;
|
|
_pixelY[dir][num] = _pixelY[dir][num - 1] + (1 - (g_events->getRandomNumber(1)));
|
|
} else {
|
|
_pixelY[dir][num] = _pixelY[dir][num - 1] + 1;
|
|
_pixelX[dir][num] = _pixelX[dir][num - 1] + (1 - (g_events->getRandomNumber(1)));
|
|
}
|
|
break;
|
|
case 4:
|
|
_pixelY[dir][num] = _pixelY[dir][num - 1] + 1;
|
|
_pixelX[dir][num] = _pixelX[dir][num - 1] + (1 - (g_events->getRandomNumber(2)));
|
|
break;
|
|
case 5:
|
|
if (g_events->getRandomNumber(1)) {
|
|
_pixelX[dir][num] = _pixelX[dir][num - 1] - 1;
|
|
_pixelY[dir][num] = _pixelY[dir][num - 1] + (1 - (g_events->getRandomNumber(1)));
|
|
} else {
|
|
_pixelY[dir][num] = _pixelY[dir][num - 1] + 1;
|
|
_pixelX[dir][num] = _pixelX[dir][num - 1] + (0 - (g_events->getRandomNumber(1)));
|
|
}
|
|
break;
|
|
case 6:
|
|
_pixelX[dir][num] = _pixelX[dir][num - 1] - 1;
|
|
_pixelY[dir][num] = _pixelY[dir][num - 1] + (1 - (g_events->getRandomNumber(2)));
|
|
break;
|
|
case 7:
|
|
if (g_events->getRandomNumber(1)) {
|
|
_pixelX[dir][num] = _pixelX[dir][num - 1] - 1;
|
|
_pixelY[dir][num] = _pixelY[dir][num - 1] + (0 - (g_events->getRandomNumber(1)));
|
|
} else {
|
|
_pixelY[dir][num] = _pixelY[dir][num - 1] - 1;
|
|
_pixelX[dir][num] = _pixelX[dir][num - 1] + (0 - (g_events->getRandomNumber(1)));
|
|
}
|
|
break;
|
|
default:
|
|
return;
|
|
}
|
|
|
|
if (pointWithin(_pixelX[dir][num], _pixelY[dir][num], 0, 0, 319, 191)) {
|
|
byte *pixel = (byte *)s.getBasePtr(_pixelX[dir][num],
|
|
_pixelY[dir][num]);
|
|
*pixel = _pixelC[dir];
|
|
}
|
|
}
|
|
|
|
void GameContent::throwLightning() {
|
|
_G(gameMode) = MODE_LIGHTNING;
|
|
_lightningCtr = 20;
|
|
|
|
for (int i = 0; i < MAX_ACTORS; i++)
|
|
_G(actor[i])._show = 0;
|
|
|
|
playSound(ELECTRIC, true);
|
|
}
|
|
|
|
void GameContent::drawLightning(GfxSurface &s) {
|
|
for (int i = 0; i < 8; i++) {
|
|
_pixelX[i][0] = _G(thor)->_x + 7;
|
|
_pixelY[i][0] = _G(thor)->_y + 7;
|
|
_pixelC[i] = 14 + g_events->getRandomNumber(1);
|
|
}
|
|
|
|
for (int r = 0; r < 8; r++) {
|
|
for (int i = 1; i < 25; i++) {
|
|
placePixel(s, r, i);
|
|
}
|
|
}
|
|
}
|
|
|
|
void GameContent::lightningCountdownDone() {
|
|
_G(gameMode) = MODE_NORMAL;
|
|
|
|
int x = _G(thor)->_x + 7;
|
|
int y = _G(thor)->_y + 7;
|
|
|
|
for (int i = 3; i < MAX_ACTORS; i++) {
|
|
if (!_G(actor[i])._active)
|
|
continue;
|
|
|
|
int ax = _G(actor[i])._x + (_G(actor[i])._sizeX / 2);
|
|
int ay = _G(actor[i])._y + (_G(actor[i])._sizeY / 2);
|
|
|
|
if ((ABS(ax - x) < 30) && (ABS(ay - y) < 30)) {
|
|
_G(actor[i])._magicHit = 1;
|
|
_G(actor[i])._vulnerableCountdown = 0;
|
|
actorDamaged(&_G(actor[i]), 254);
|
|
}
|
|
}
|
|
}
|
|
|
|
void GameContent::closingSequence() {
|
|
const int area = _G(area);
|
|
|
|
switch (++_closingStateCtr) {
|
|
case 1:
|
|
// Convert health/magic/jewels to score
|
|
_G(gameMode) = MODE_SCORE_INV;
|
|
break;
|
|
|
|
case 2:
|
|
switch (area) {
|
|
case 1:
|
|
boss1ClosingSequence2();
|
|
break;
|
|
case 2:
|
|
boss2ClosingSequence2();
|
|
break;
|
|
case 3:
|
|
boss3ClosingSequence2();
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case 3:
|
|
switch (area) {
|
|
case 1:
|
|
boss1ClosingSequence3();
|
|
break;
|
|
case 2:
|
|
boss2ClosingSequence3();
|
|
break;
|
|
case 3:
|
|
boss3ClosingSequence3();
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case 4:
|
|
_closingStateCtr = 0;
|
|
|
|
switch (area) {
|
|
case 1:
|
|
boss1ClosingSequence4();
|
|
break;
|
|
case 2:
|
|
boss2ClosingSequence4();
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
} // namespace Views
|
|
} // namespace Got
|