Files
scummvm/engines/got/game/move_patterns.cpp
T
blowfist 0f338b21ae GOT: Add eyeballs mode for chapter 2 shovel maze (#6451)
In chapter 2, there is a section where you enter in a pitch dark room
and Thor is replaced with eyeballs. This is all you can see while
you move around in the invisible maze to find the shovel.

This patch fully implements this mode and also adds these additional
related features :
	* bruised eye animation that happens after the shovel is
	  found, with Thor's face.
	* Saving and loading preserves the eyeball effect in
	  the room 105.
	* Thor's spinning animation takes the eyeballs mode in
	  consideration. Although the only way the user can
	  die in that room is to explicitely use the "die"
	  feature/command.

The original code was used as a guideline to implement this feature.
2025-02-23 08:46:30 +01:00

2623 lines
52 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/game/move_patterns.h"
#include "got/events.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/object.h"
#include "got/game/script.h"
#include "got/game/special_tile.h"
#include "got/vars.h"
namespace Got {
#define TILE_SOLID 80
#define TILE_FLY 140
#define TILE_SPECIAL 200
int checkSpecialMove1(int x, int y, Actor *actor);
int checkMove0(int x, int y, Actor *actor);
int checkMove1(int x, int y, Actor *actor);
int movementZero(Actor *actor);
int movementOne(Actor *actor);
int movementTwo(Actor *actor);
int movementThree(Actor *actor);
int movementFour(Actor *actor);
int movementFive(Actor *actor);
int movementSix(Actor *actor);
int movementSeven(Actor *actor);
int movementEight(Actor *actor);
int movementNine(Actor *actor);
int movementTen(Actor *actor);
int movementEleven(Actor *actor);
int movementTwelve(Actor *actor); // Horizontal straight until bump
int movementThirteen(Actor *actor); // Pause-seek (mushroom)
int movementFourteen(Actor *actor); // Move-bump-stop (boulder)
int movementFifteen(Actor *actor); // No move, no frame cycle
int movementSixteen(Actor *actor); // Tornado 1
int movementSeventeen(Actor *actor); // Tornado 2
int movementEighteen(Actor *actor); // Random-seek-bite-run
int movementNineteen(Actor *actor); // Tornado 2
int movementTwenty(Actor *actor); // Tornado 2
int movementTwentyOne(Actor *actor); // Eyeball
int movementTwentyTwo(Actor *actor); // Spear
int movementTwentyThree(Actor *actor); // Spinball cw
int movementTwentyFour(Actor *actor); // Spinball ccw
int movementTwentyFive(Actor *actor); //
int movementTwentySix(Actor *actor); //
int movementTwentySeven(Actor *actor); //
int movementTwentyEight(Actor *actor); // Tree boss
int movementTwentyNine(Actor *actor); // Horizontal or vertical (pass_val)
int movementThirty(Actor *actor); // Vertical straight
int movementThirtyOne(Actor *actor); // Drop (stalagtite)
int movementThirtyTwo(Actor *actor); // Bomb 1
int movementThirtyThree(Actor *actor); // Bomb 2
int movementThirtyFour(Actor *actor); // Gun (4-dir)
int movementThirtyFive(Actor *actor); // Gun (4-dir)
int movementThirtySix(Actor *actor); // Acid drop
int movementThirtySeven(Actor *actor); // 4-way rnd,rnd len
int movementThirtyEight(Actor *actor); // Timed darting
int movementThirtyNine(Actor *actor); // Troll 1
int movementForty(Actor *actor); // Troll 2
int (*const _movementFunc[])(Actor *actor) = {
movementZero,
movementOne,
movementTwo,
movementThree,
movementFour,
movementFive,
movementSix,
movementSeven,
movementEight,
movementNine,
movementTen,
movementEleven,
movementTwelve,
movementThirteen,
movementFourteen,
movementFifteen,
movementSixteen,
movementSeventeen,
movementEighteen,
movementNineteen,
movementTwenty,
movementTwentyOne,
movementTwentyTwo,
movementTwentyThree,
movementTwentyFour,
movementTwentyFive,
movementTwentySix,
movementTwentySeven,
movementTwentyEight,
movementTwentyNine,
movementThirty,
movementThirtyOne,
movementThirtyTwo,
movementThirtyThree,
movementThirtyFour,
movementThirtyFive,
movementThirtySix,
movementThirtySeven,
movementThirtyEight,
movementThirtyNine,
movementForty};
int specialMovementOne(Actor *actor);
int specialMovementTwo(Actor *actor);
int specialMovementThree(Actor *actor);
int specialMovementFour(Actor *actor);
int specialMovementFive(Actor *actor);
int specialMovementSix(Actor *actor);
int specialMovementSeven(Actor *actor);
int specialMovementEight(Actor *actor);
int specialMovementNine(Actor *actor);
int specialMovementTen(Actor *actor);
int specialMovementEleven(Actor *actor);
int (*specialMovementFunc[])(Actor *actor) = {
nullptr,
specialMovementOne,
specialMovementTwo,
specialMovementThree,
specialMovementFour,
specialMovementFive,
specialMovementSix,
specialMovementSeven,
specialMovementEight,
specialMovementNine,
specialMovementTen,
specialMovementEleven};
// Check Thor move
int checkMove0(const int x, const int y, Actor *actor) {
_G(thorIcon1) = 0;
_G(thorIcon2) = 0;
_G(thorIcon3) = 0;
_G(thorIcon4) = 0;
if (x < 0) {
if (_G(currentLevel) > 0) {
_G(newLevel) = _G(currentLevel) - 1;
actor->_x = 304;
actor->_lastX[0] = 304;
actor->_lastX[1] = 304;
actor->_show = 0;
actor->_moveCount = 0;
setThorVars();
return 1;
}
return 0;
}
if (x > 306) {
if (_G(currentLevel) < 119) {
_G(newLevel) = _G(currentLevel) + 1;
actor->_x = 0;
actor->_lastX[0] = 0;
actor->_lastX[1] = 0;
actor->_show = 0;
actor->_moveCount = 0;
setThorVars();
return 1;
}
return 0;
}
if (y < 0) {
if (_G(currentLevel) > 9) {
_G(newLevel) = _G(currentLevel) - 10;
actor->_y = 175;
actor->_lastY[0] = 175;
actor->_show = 0;
actor->_lastY[1] = 175;
actor->_moveCount = 0;
setThorVars();
return 1;
}
return 0;
}
if (y > 175) {
if (_G(currentLevel) < 110) {
_G(newLevel) = _G(currentLevel) + 10;
actor->_y = 0;
actor->_lastY[0] = 0;
actor->_lastY[1] = 0;
actor->_show = 0;
actor->_moveCount = 0;
setThorVars();
return 1;
}
return 0;
}
int x1 = (x + 1) >> 4;
int y1 = (y + 8) >> 4;
int x2 = (_G(thor)->_dir > 1) ? (x + 12) >> 4 : (x + 10) >> 4;
int y2 = (y + 15) >> 4;
_G(slipFlag) = false;
// Check for cheat flying mode
if (!actor->_flying) {
byte icn1 = _G(scrn)._iconGrid[y1][x1];
byte icn2 = _G(scrn)._iconGrid[y2][x1];
byte icn3 = _G(scrn)._iconGrid[y1][x2];
byte icn4 = _G(scrn)._iconGrid[y2][x2];
int ti = 0;
if (icn1 < TILE_FLY) {
_G(thorIcon1) = 1;
ti = 1;
}
if (icn2 < TILE_FLY) {
_G(thorIcon2) = 1;
ti = 1;
}
if (icn3 < TILE_FLY) {
_G(thorIcon3) = 1;
ti = 1;
}
if (icn4 < TILE_FLY) {
_G(thorIcon4) = 1;
ti = 1;
}
if (ti)
return 0;
if (icn1 > TILE_SPECIAL) {
if (!specialTileThor(y1, x1, icn1))
return 0;
icn2 = _G(scrn)._iconGrid[y2][x1];
icn3 = _G(scrn)._iconGrid[y1][x2];
icn4 = _G(scrn)._iconGrid[y2][x2];
}
if (icn2 > TILE_SPECIAL) {
if (!specialTileThor(y2, x1, icn2))
return 0;
icn3 = _G(scrn)._iconGrid[y1][x2];
icn4 = _G(scrn)._iconGrid[y2][x2];
}
if (icn3 > TILE_SPECIAL) {
if (!specialTileThor(y1, x2, icn3))
return 0;
icn4 = _G(scrn)._iconGrid[y2][x2];
}
if (icn4 > TILE_SPECIAL && !specialTileThor(y2, x2, icn4))
return 0;
}
if (!_G(slipFlag)) {
_G(slipping) = false;
_G(slipCount) = 0;
}
if (_G(slipFlag) && !_G(slipping))
_G(slipCount++);
if (_G(slipCount) > 8)
_G(slipping) = true;
_G(slipFlag) = false;
x1 = x + 1;
y1 = y + 8;
x2 = x + 12;
y2 = y + 15;
_G(thorSpecialFlag) = false;
for (int i = 3; i < MAX_ACTORS; i++) {
Actor *act = &_G(actor[i]);
if ((act->_solid & 128) || !act->_active)
continue;
const int x3 = act->_x + 1;
const int y3 = act->_y + 1;
if (ABS(x3 - x1) > 16 || ABS(y3 - y1) > 16)
continue;
const int x4 = act->_x + act->_sizeX - 1;
const int y4 = act->_y + act->_sizeY - 1;
if (overlap(x1, y1, x2, y2, x3, y3, x4, y4)) {
if (act->_funcNum > 0) { // 255=explosion
if (act->_funcNum == 255)
return 0;
act->_temp1 = x;
act->_temp2 = y;
_G(thorSpecialFlag) = true;
return specialMovementFunc[act->_funcNum](act);
}
_G(thorSpecialFlag) = false;
thorDamaged(act);
if (act->_solid < 2) {
if (!act->_vulnerableCountdown && (!(act->_type & 1)))
playSound(PUNCH1, false);
if (!_G(hammer)->_active && _G(keyFlag[key_fire]))
actorDamaged(act, _G(hammer)->_hitStrength);
else
actorDamaged(act, _G(thor)->_hitStrength);
}
return 1;
}
}
actor->_x = x;
actor->_y = y;
return 1;
}
// Check hammer move
int checkMove1(const int x, const int y, Actor *actor) {
if (x < 0 || x > 306 || y < 0 || y > 177)
return 0;
int x1 = (x + 1) >> 4;
int y1 = (y + 6) >> 4;
int x2 = (x + 10) >> 4;
int y2 = (y + 10) >> 4;
// Check for solid or fly over
int icn = TILE_FLY;
if (actor->_flying)
icn = TILE_SOLID;
const byte icn1 = _G(scrn)._iconGrid[y1][x1];
const byte icn2 = _G(scrn)._iconGrid[y2][x1];
const byte icn3 = _G(scrn)._iconGrid[y1][x2];
const byte icn4 = _G(scrn)._iconGrid[y2][x2];
if (icn1 < icn || icn2 < icn || icn3 < icn || icn4 < icn) {
if (actor->_actorNum == 1 && actor->_moveType == 2)
playSound(CLANG, false);
return 0;
}
if (icn1 > TILE_SPECIAL && !specialTile(actor, y1, x1, icn1))
return 0;
if (icn2 > TILE_SPECIAL && !specialTile(actor, y2, x1, icn2))
return 0;
if (icn3 > TILE_SPECIAL && !specialTile(actor, y1, x2, icn3))
return 0;
if (icn4 > TILE_SPECIAL && !specialTile(actor, y2, x2, icn4))
return 0;
x1 = x + 1;
y1 = y + 1;
x2 = x + 10;
y2 = y + 10;
int f = 0;
for (int i = 3; i < MAX_ACTORS; i++) {
Actor *act = &_G(actor[i]);
if (!act->_active || act->_type == 3)
continue;
const int x3 = act->_x;
const int y3 = act->_y;
if (ABS(x3 - x1) > 16 || ABS(y3 - y1) > 16)
continue;
const int x4 = act->_x + act->_sizeX - 1;
const int y4 = act->_y + act->_sizeY - 1;
if (overlap(x1, y1, x2, y2, x3, y3, x4, y4)) {
if (_G(bossActive) && !GAME3) {
switch (_G(area)) {
case 1:
boss1CheckHit(act, x1, y1, x2, y2, i);
break;
case 2:
boss2CheckHit(act);
break;
default:
// Area 3 boss Loki isn't checked here
break;
}
} else {
if (act->_solid == 2 && (actor->_moveType == 16 || actor->_moveType == 17))
return 0;
actorDamaged(act, actor->_hitStrength);
}
f++;
}
}
if (f && actor->_moveType == 2)
return 0;
actor->_x = x;
actor->_y = y;
return 1;
}
// Check enemy move
int checkMove2(const int x, const int y, Actor *actor) {
if (actor->_actorNum < 3)
return checkMove1(x, y, actor);
if (x < 0 || x > (319 - actor->_sizeX) || y < 0 || y > 175)
return 0;
int x1 = (x + 1) >> 4;
int y1;
if (!actor->_funcNum)
y1 = (y + (actor->_sizeY / 2)) >> 4;
else
y1 = (y + 1) >> 4;
int x2 = ((x + actor->_sizeX) - 1) >> 4;
int y2 = ((y + actor->_sizeY) - 1) >> 4;
// Check for solid or fly over
int icn = TILE_FLY;
if (actor->_flying)
icn = TILE_SOLID;
const byte icn1 = _G(scrn)._iconGrid[y1][x1];
const byte icn2 = _G(scrn)._iconGrid[y2][x1];
const byte icn3 = _G(scrn)._iconGrid[y1][x2];
const byte icn4 = _G(scrn)._iconGrid[y2][x2];
if (icn1 < icn || icn2 < icn || icn3 < icn || icn4 < icn)
return 0;
if (icn1 > TILE_SPECIAL)
if (!specialTile(actor, y1, x1, icn1))
return 0;
if (icn2 > TILE_SPECIAL)
if (!specialTile(actor, y2, x1, icn2))
return 0;
if (icn3 > TILE_SPECIAL)
if (!specialTile(actor, y1, x2, icn3))
return 0;
if (icn4 > TILE_SPECIAL)
if (!specialTile(actor, y2, x2, icn4))
return 0;
x1 = x + 1;
y1 = y + 1;
x2 = (x + actor->_sizeX) - 1;
y2 = (y + actor->_sizeY) - 1;
for (int i = 0; i < MAX_ACTORS; i++) {
Actor *act = &_G(actor[i]);
if (act->_actorNum == actor->_actorNum || act->_actorNum == 1 || !act->_active)
continue;
if (act->_type == 3)
continue; // Shot
if (i == 0) {
if (overlap(x1, y1, x2, y2, _G(thorX1), _G(thorY1), _G(thorX2), _G(thorY2))) {
thorDamaged(actor);
return 0;
}
} else {
const int x3 = act->_x;
const int y3 = act->_y;
if (ABS(x3 - x1) > 16 || ABS(y3 - y1) > 16)
continue;
const int x4 = act->_x + act->_sizeX;
const int y4 = act->_y + act->_sizeY;
if (overlap(x1, y1, x2, y2, x3, y3, x4, y4)) {
if (actor->_moveType == 38) {
if (act->_funcNum == 4)
_G(switchUsed) = 1;
else if (act->_funcNum == 7)
_G(switchUsed) = 2;
}
return 0;
}
}
}
actor->_x = x;
actor->_y = y;
return 1;
}
// Check enemy shot move
int checkMove3(const int x, const int y, Actor *actor) {
if (x < 0 || x > (319 - actor->_sizeX) || y < 0 || y > 175)
return 0;
int x1 = (x + 1) >> 4;
int y1 = (y + (actor->_sizeY / 2)) >> 4;
int x2 = ((x + actor->_sizeX) - 1) >> 4;
int y2 = ((y + actor->_sizeY) - 1) >> 4;
// Check for solid or fly over
int icn = TILE_FLY;
if (actor->_flying)
icn = TILE_SOLID;
const byte icn1 = _G(scrn)._iconGrid[y1][x1];
const byte icn2 = _G(scrn)._iconGrid[y2][x1];
const byte icn3 = _G(scrn)._iconGrid[y1][x2];
const byte icn4 = _G(scrn)._iconGrid[y2][x2];
if (icn1 < icn || icn2 < icn || icn3 < icn || icn4 < icn)
return 0;
if (icn1 > TILE_SPECIAL && !specialTile(actor, y1, x1, icn1))
return 0;
if (icn2 > TILE_SPECIAL && !specialTile(actor, y2, x1, icn2))
return 0;
if (icn3 > TILE_SPECIAL && !specialTile(actor, y1, x2, icn3))
return 0;
if (icn4 > TILE_SPECIAL && !specialTile(actor, y2, x2, icn4))
return 0;
// Check for solid or fly over
x1 = x + 1;
y1 = y + 1;
x2 = (x + actor->_sizeX) - 1;
y2 = (y + actor->_sizeY) - 1;
if (overlap(x1, y1, x2, y2, _G(thorX1), _G(thorRealY1), _G(thorX2), _G(thorY2))) {
thorDamaged(actor);
return 0;
}
for (int i = 3; i < MAX_ACTORS; i++) {
if (i == actor->_actorNum)
continue;
Actor *act = &_G(actor[i]);
if (!act->_active)
continue;
if (act->_solid < 2)
continue;
if (act->_type == 3)
continue; // Shot
if (act->_actorNum == actor->_creator)
continue;
const int x3 = act->_x;
const int y3 = act->_y;
if (ABS(x3 - x1) > 16 || ABS(y3 - y1) > 16)
continue;
const int x4 = x3 + 15;
const int y4 = y3 + 15;
if (overlap(x1, y1, x2, y2, x3, y3, x4, y4))
return 0;
}
actor->_x = x;
actor->_y = y;
return 1;
}
// Flying enemies
int checkMove4(const int x, const int y, Actor *actor) {
if (x < 0 || x > (319 - actor->_sizeX) || y < 0 || y > 175)
return 0;
if (overlap(x, y, x + actor->_sizeX - 1, y + actor->_sizeY - 1,
_G(thorX1), _G(thorY1), _G(thorX2), _G(thorY2))) {
if (actor->_type == 3)
thorDamaged(actor);
return 0;
}
actor->_x = x;
actor->_y = y;
return 1;
}
#define THOR_PAD1 2
#define THOR_PAD2 4
int check_thor_move(const int x, const int y, Actor *actor) {
if (checkMove0(x, y, actor))
return 1;
if (_G(diagFlag) || _G(thorSpecialFlag))
return 0;
if (_G(thorIcon1) + _G(thorIcon2) + _G(thorIcon3) + _G(thorIcon4) > 1)
return 0;
switch (actor->_dir) {
case 0:
if (_G(thorIcon1)) {
actor->_dir = 3;
if (checkMove0(x + THOR_PAD1, y + 2, actor)) {
actor->_dir = 0;
return 1;
}
} else if (_G(thorIcon3)) {
actor->_dir = 2;
if (checkMove0(x - THOR_PAD1, y + 2, actor)) {
actor->_dir = 0;
return 1;
}
}
actor->_dir = 0;
break;
case 1:
if (_G(thorIcon2)) {
actor->_dir = 3;
if (checkMove0(x + THOR_PAD1, y - 2, actor)) {
actor->_dir = 1;
return 1;
}
} else if (_G(thorIcon4)) {
actor->_dir = 2;
if (checkMove0(x - THOR_PAD1, y - 2, actor)) {
actor->_dir = 1;
return 1;
}
}
actor->_dir = 1;
break;
case 2:
if (_G(thorIcon1)) {
if (checkMove0(x + 2, y + THOR_PAD1, actor))
return 1;
} else if (_G(thorIcon2)) {
if (checkMove0(x + 2, y - THOR_PAD1, actor))
return 1;
}
break;
case 3:
if (_G(thorIcon3)) {
if (checkMove0(x - 2, y + THOR_PAD1, actor))
return 1;
} else if (_G(thorIcon4)) {
if (checkMove0(x - 2, y - THOR_PAD1, actor))
return 1;
}
break;
default:
break;
}
return 0;
}
// Player control
int movementZero(Actor *actor) {
int d = actor->_dir;
const int oldDir = d;
setThorVars();
if (_G(hammer)->_active && _G(hammer)->_moveType == 5) {
if (overlap(_G(thorX1), _G(thorY1), _G(thorX2), _G(thorY2),
_G(hammer)->_x, _G(hammer)->_y, _G(hammer)->_x + 13, _G(hammer)->_y + 13)) {
actorDestroyed(_G(hammer));
}
}
int x = actor->_x;
int y = actor->_y;
_G(diagFlag) = false;
if (actor->_moveCounter)
actor->_moveCounter--;
if (_G(slipping)) {
if (_G(slipCount) == 8)
playSound(FALL, true);
y += 2;
_G(slipCount--);
if (!_G(slipCount))
_G(slipping) = false;
check_thor_move(x, y, actor);
_G(thor)->_moveCountdown = 4;
return d;
}
if (_G(keyFlag[key_up]) && _G(keyFlag[key_left])) {
d = 2;
actor->_dir = d;
_G(diag) = 1;
_G(diagFlag) = true;
if (check_thor_move(x - 2, y - 2, actor)) {
nextFrame(actor);
return d;
}
} else if (_G(keyFlag[key_up]) && _G(keyFlag[key_right])) {
d = 3;
actor->_dir = d;
_G(diag) = 2;
_G(diagFlag) = true;
if (check_thor_move(x + 2, y - 2, actor)) {
nextFrame(actor);
return d;
}
} else if (_G(keyFlag[key_down]) && _G(keyFlag[key_left])) {
d = 2;
actor->_dir = d;
_G(diag) = 4;
_G(diagFlag) = true;
if (check_thor_move(x - 2, y + 2, actor)) {
nextFrame(actor);
return d;
}
} else if (_G(keyFlag[key_down]) && _G(keyFlag[key_right])) {
d = 3;
actor->_dir = d;
_G(diag) = 3;
_G(diagFlag) = true;
if (check_thor_move(x + 2, y + 2, actor)) {
nextFrame(actor);
return d;
}
}
_G(diag) = 0;
if (_G(keyFlag[key_right]) && !_G(keyFlag[key_left])) {
d = 3;
actor->_dir = d;
if (check_thor_move(x + 2, y, actor)) {
nextFrame(actor);
return d;
}
}
if (_G(keyFlag[key_left]) && !_G(keyFlag[key_right])) {
d = 2;
actor->_dir = d;
if (check_thor_move(x - 2, y, actor)) {
nextFrame(actor);
return d;
}
}
if (_G(keyFlag[key_down]) && !_G(keyFlag[key_up])) {
d = 1;
actor->_dir = d;
if (check_thor_move(x, y + 2, actor)) {
nextFrame(actor);
return d;
}
}
if (_G(keyFlag[key_up]) && !_G(keyFlag[key_down])) {
d = 0;
actor->_dir = d;
if (check_thor_move(x, y - 2, actor)) {
nextFrame(actor);
return d;
}
}
if (_G(eyeballs)) {
nextFrame(actor);
actor->_dir = oldDir;
return d;
}
actor->_moveCounter = 5;
actor->_nextFrame = 0;
actor->_dir = oldDir;
return d;
}
int checkSpecialMove1(const int x, const int y, Actor *actor) {
int x3, y3, x4, y4;
Actor *act;
if (actor->_actorNum < 3)
return checkMove1(x, y, actor);
if (x < 0 || x > 304 || y < 0 || y > 176)
return 0;
int x1 = x >> 4;
int y1 = y >> 4;
int x2 = (x + 15) >> 4;
int y2 = (y + 15) >> 4;
// Check for solid or fly over
int icn = TILE_FLY;
if (actor->_flying)
icn = TILE_SOLID;
const byte icn1 = _G(scrn)._iconGrid[y1][x1];
const byte icn2 = _G(scrn)._iconGrid[y2][x1];
const byte icn3 = _G(scrn)._iconGrid[y1][x2];
const byte icn4 = _G(scrn)._iconGrid[y2][x2];
if (icn1 < icn || icn2 < icn || icn3 < icn || icn4 < icn)
return 0;
if (icn1 > TILE_SPECIAL && !specialTile(actor, y1, x1, icn1))
return 0;
if (icn2 > TILE_SPECIAL && !specialTile(actor, y2, x1, icn2))
return 0;
if (icn3 > TILE_SPECIAL && !specialTile(actor, y1, x2, icn3))
return 0;
if (icn4 > TILE_SPECIAL && !specialTile(actor, y2, x2, icn4))
return 0;
x1 = x;
y1 = y;
x2 = (x + 15);
y2 = (y + 15);
for (int i = 3; i < MAX_ACTORS; i++) {
act = &_G(actor[i]);
if (act->_actorNum == actor->_actorNum)
continue;
if (!act->_active)
continue;
if (act->_type == 3)
continue; //shot
x3 = act->_x;
if ((ABS(x3 - x1)) > 16)
continue;
y3 = act->_y;
if ((ABS(y3 - y1)) > 16)
continue;
x4 = act->_x + act->_sizeX;
y4 = act->_y + 15;
if (overlap(x1, y1, x2, y2, x3, y3, x4, y4))
return 0;
}
for (int i = 3; i < MAX_ACTORS; i++) {
act = &_G(actor[i]);
if (act->_actorNum == actor->_actorNum)
continue;
if (!act->_active)
continue;
if (act->_type == 3)
continue; // Shot
x3 = act->_x;
if ((ABS(x3 - x1)) > 16)
continue;
y3 = act->_y;
if ((ABS(y3 - y1)) > 16)
continue;
x4 = act->_x + act->_sizeX;
y4 = act->_y + act->_sizeY;
if (overlap(_G(thorX1), _G(thorY1), _G(thorX2), _G(thorY2), x3, y3, x4, y4))
return 0;
}
actor->_x = x;
actor->_y = y;
return 1;
}
//*==========================================================================
// Block
int specialMovementOne(Actor *actor) {
if (_G(diagFlag))
return 0;
const int d = _G(thor)->_dir;
int x1 = actor->_x;
int y1 = actor->_y;
const int sd = actor->_lastDir;
actor->_lastDir = d;
switch (d) {
case 0:
y1 -= 2;
if (!checkSpecialMove1(x1, y1, actor)) {
actor->_lastDir = sd;
return 0;
}
break;
case 1:
y1 += 2;
if (!checkSpecialMove1(x1, y1, actor)) {
actor->_lastDir = sd;
return 0;
}
break;
case 2:
x1 -= 2;
if (!checkSpecialMove1(x1, y1, actor)) {
actor->_lastDir = sd;
return 0;
}
break;
case 3:
x1 += 2;
if (!checkSpecialMove1(x1, y1, actor)) {
actor->_lastDir = sd;
return 0;
}
break;
default:
break;
}
nextFrame(actor);
actor->_lastDir = d;
return 1;
}
// Angle
int specialMovementTwo(Actor *actor) {
const int x1 = actor->_temp1; // Calc thor pos
const int y1 = actor->_temp2;
const int x2 = x1 + 13;
const int y2 = y1 + 14;
for (int i = 3; i < MAX_ACTORS; i++) {
Actor *act = &_G(actor[i]);
if (actor->_actorNum == act->_actorNum)
continue;
if (!act->_active)
continue;
const int x3 = act->_x;
if ((ABS(x3 - x1)) > 16)
continue;
const int y3 = act->_y;
if ((ABS(y3 - y1)) > 16)
continue;
const int x4 = act->_x + act->_sizeX;
const int y4 = act->_y + act->_sizeY;
if (overlap(x1, y1, x2, y2, x3, y3, x4, y4))
return 0;
}
if (!actor->_funcPass) {
if (_G(thor)->_health < 150) {
if (!soundPlaying())
playSound(ANGEL, false);
_G(thor)->_health += 1;
}
} else if (_G(thorInfo)._magic < 150) {
if (!soundPlaying())
playSound(ANGEL, false);
_G(thorInfo)._magic += 1;
}
return 1;
}
// Yellow globe
int specialMovementThree(Actor *actor) {
if (_G(thunderSnakeCounter))
return 0;
long lind = (long)_G(currentLevel);
lind *= 1000;
lind += (long)actor->_actorNum;
executeScript(lind, _G(odin));
return 0;
}
// Peg switch
int specialMovementFour(Actor *actor) {
if (actor->_shotCountdown != 0)
return 0;
actor->_shotCountdown = 30;
_G(switchUsed) = 1;
return 0;
}
// Boulder roll
int specialMovementFive(Actor *actor) {
int d = _G(thor)->_dir;
if (_G(diagFlag)) {
switch (_G(diag)) {
case 1:
if (_G(thorX1) < (actor->_x + 15))
d = 0;
else
d = 2;
break;
case 2:
if (_G(thorX2) < actor->_x)
d = 3;
else
d = 0;
break;
case 3:
if (_G(thorX2) > (actor->_x))
d = 1;
else
d = 3;
break;
case 4:
if (_G(thorX1) > (actor->_x + 15))
d = 2;
else
d = 1;
break;
default:
break;
}
}
actor->_lastDir = d;
actor->_moveType = 14;
return 0;
}
int specialMovementSix(Actor *actor) {
thorDamaged(actor);
return 0;
}
int specialMovementSeven(Actor *actor) {
if (actor->_shotCountdown != 0)
return 0;
actor->_shotCountdown = 30;
_G(switchUsed) = 2;
return 0;
}
int specialMovementEight(Actor *actor) {
if (_G(thor)->_dir < 2 || _G(diagFlag))
return 0;
actor->_lastDir = _G(thor)->_dir;
actor->_moveType = 14;
return 0;
}
int specialMovementNine(Actor *actor) {
if (_G(thor)->_dir > 1 || _G(diagFlag))
return 0;
actor->_lastDir = _G(thor)->_dir;
actor->_moveType = 14;
return 0;
}
int specialMovementTen(Actor *actor) {
byte &actor_ctr = GAME1 ? actor->_temp6 : actor->_talkCounter;
if (actor_ctr) {
actor_ctr--;
return 0;
}
if (_G(thunderSnakeCounter))
return 0;
actor_ctr = 10;
actorSpeaks(actor, 0 - actor->_passValue, 0);
return 0;
}
// Red guard
int specialMovementEleven(Actor *actor) {
if (actor->_talkCounter) {
actor->_talkCounter--;
return 0;
}
const int oldType = actor->_type;
actor->_type = 4;
actorSpeaks(actor, 0, 0);
actor->_type = oldType;
actor->_talkCounter = 10;
return 0;
}
// No movement - frame cycle
int movementOne(Actor *actor) {
nextFrame(actor);
return actor->_dir;
}
// Hammer only
int movementTwo(Actor *actor) {
int d = actor->_lastDir;
int x1 = actor->_x;
int y1 = actor->_y;
switch (d) {
case 0:
y1 -= 2;
break;
case 1:
y1 += 2;
break;
case 2:
x1 -= 2;
break;
case 3:
x1 += 2;
break;
default:
break;
}
if (!checkMove2(x1, y1, actor)) {
if (actor->_actorNum == 1) {
_G(hammer)->_moveType = 5;
d = reverseDirection(_G(hammer));
_G(hammer)->_dir = d;
}
if (actor->_actorNum == 2) {
actor->_active = false;
actor->_dead = 2;
_G(tornadoUsed) = false;
}
}
nextFrame(actor);
actor->_lastDir = d;
if (actor->_directions == 1)
return 0;
return d;
}
// Walk-bump-random turn
int movementThree(Actor *actor) {
int d = actor->_lastDir;
int x1 = actor->_x;
int y1 = actor->_y;
switch (d) {
case 0:
y1 -= 2;
if (!checkMove2(x1, y1, actor)) {
d = g_events->getRandomNumber(3);
}
break;
case 1:
y1 += 2;
if (!checkMove2(x1, y1, actor)) {
d = g_events->getRandomNumber(3);
}
break;
case 2:
x1 -= 2;
if (!checkMove2(x1, y1, actor)) {
d = g_events->getRandomNumber(3);
}
break;
case 3:
x1 += 2;
if (!checkMove2(x1, y1, actor)) {
d = g_events->getRandomNumber(3);
}
break;
default:
break;
}
nextFrame(actor);
actor->_lastDir = d;
if (actor->_directions == 1)
return 0;
return d;
}
// Simple tracking
int movementFour(Actor *actor) {
int d = actor->_lastDir;
int x1 = actor->_x;
int y1 = actor->_y;
int f = 0;
if (x1 > _G(thorX1) - 1) {
x1 -= 2;
d = 2;
f = 1;
} else if (x1 < _G(thorX1) - 1) {
x1 += 2;
d = 3;
f = 1;
}
if (f)
f = checkMove2(x1, y1, actor);
if (!f) {
if (y1 < (_G(thorRealY1))) {
d = (_G(thorRealY1)) - y1;
if (d > 2)
d = 2;
y1 += d;
d = 1;
f = 1;
} else if (y1 > (_G(thorRealY1))) {
d = y1 - (_G(thorRealY1));
if (d > 2)
d = 2;
y1 -= d;
d = 0;
f = 1;
}
if (f)
f = checkMove2(actor->_x, y1, actor);
if (!f)
checkMove2(actor->_x, actor->_y, actor);
}
nextFrame(actor);
actor->_lastDir = d;
if (actor->_directions == 1)
return 0;
return d;
}
int movementFive(Actor *actor) {
int x1 = actor->_x;
int y1 = actor->_y;
int xd = 0;
int yd = 0;
int d = actor->_lastDir;
if (x1 > (_G(thor)->_x + 1))
xd = -2; //+1
else if (x1 < (_G(thor)->_x - 1))
xd = 2;
if (actor->_actorNum == 1) {
if (y1 < (_G(thorY1) - 6))
yd = 2;
else if (y1 > (_G(thorY1) - 6))
yd = -2;
} else {
if (y1 < (_G(thorRealY1) - 1))
yd = 2;
else if (y1 > (_G(thorRealY1) + 1))
yd = -2;
}
if (xd && yd) {
if (xd == -2 && ABS(yd) == 2)
d = 2;
else if (xd == 2 && ABS(yd) == 2)
d = 3;
x1 += xd;
y1 += yd;
if (checkMove2(x1, y1, actor)) {
nextFrame(actor);
actor->_lastDir = d;
if (actor->_directions == 1)
return 0;
return d;
}
} else {
if (xd == 0 && yd == 2)
d = 1;
else if (xd == 0 && yd == -2)
d = 0;
else if (xd == 2 && yd == 0)
d = 3;
else if (xd == -2 && yd == 0)
d = 2;
}
x1 = actor->_x;
y1 = actor->_y;
actor->_toggle ^= 1;
if (actor->_toggle) {
if (xd) {
x1 += xd;
if (checkMove2(x1, y1, actor)) {
if (xd > 0)
d = 3;
else
d = 2;
nextFrame(actor);
actor->_lastDir = d;
if (actor->_directions == 1)
return 0;
return d;
}
x1 = actor->_x;
}
if (yd) {
y1 += yd;
if (checkMove2(x1, y1, actor)) {
if (yd > 0)
d = 1;
else
d = 0;
nextFrame(actor);
actor->_lastDir = d;
if (actor->_directions == 1)
return 0;
return d;
}
}
} else {
if (yd) {
y1 += yd;
if (checkMove2(x1, y1, actor)) {
if (yd > 0)
d = 1;
else
d = 0;
nextFrame(actor);
actor->_lastDir = d;
if (actor->_directions == 1)
return 0;
return d;
}
y1 = actor->_y;
}
if (xd) {
x1 += xd;
if (checkMove2(x1, y1, actor)) {
if (xd > 0)
d = 3;
else
d = 2;
nextFrame(actor);
actor->_lastDir = d;
if (actor->_directions == 1)
return 0;
return d;
}
}
}
checkMove2(actor->_x, actor->_y, actor);
nextFrame(actor);
actor->_lastDir = d;
if (actor->_directions == 1)
return 0;
return d;
}
// Explosion only
int movementSix(Actor *actor) {
if (actor->_currNumShots > 0) {
actor->_nextFrame++;
if (actor->_nextFrame > 2) {
actor->_nextFrame = 0;
if (_G(bossDead))
playSound(EXPLODE, false);
}
actor->_currNumShots--;
} else {
actor->_dead = 2;
actor->_active = false;
if (!_G(bossDead) && !_G(endGame)) {
if (actor->_type == 2)
dropRandomObject(actor);
}
}
nextFrame(actor);
return 0;
}
// Walk-bump-random turn (pause also)
int movementSeven(Actor *actor) {
if (actor->_nextFrame == 0 && actor->_frameCount == actor->_frameSpeed) {
actor->_moveCountdown = 12;
actor->_lastDir = g_events->getRandomNumber(3);
}
return movementThree(actor);
}
// Follow thor
int movementEight(Actor *actor) {
if (_G(thor)->_x > 0)
actor->_x = _G(thor)->_x - 1;
else
actor->_x = _G(thor)->_x;
actor->_y = _G(thor)->_y;
nextFrame(actor);
return 0;
}
// 4-way straight (random length) change
int movementNine(Actor *actor) {
int d = actor->_lastDir;
int x1 = actor->_x;
int y1 = actor->_y;
int f = 0;
if (actor->_counter) {
actor->_counter--;
switch (d) {
case 0:
y1 -= 2;
if (!checkMove4(x1, y1, actor))
f = 1;
break;
case 1:
y1 += 2;
if (!checkMove4(x1, y1, actor))
f = 1;
break;
case 2:
x1 -= 2;
if (!checkMove4(x1, y1, actor))
f = 1;
break;
case 3:
x1 += 2;
if (!checkMove4(x1, y1, actor))
f = 1;
break;
default:
break;
}
} else
f = 1;
if (f == 1) {
actor->_counter = g_events->getRandomNumber(10, 99);
d = g_events->getRandomNumber(3);
}
nextFrame(actor);
actor->_lastDir = d;
if (actor->_directions == 1)
return 0;
return d;
}
// Vertical straight (random length) change
int movementTen(Actor *actor) {
int lastDir = actor->_lastDir;
const int x1 = actor->_x;
int y1 = actor->_y;
bool setRandomDirFl = false;
if (actor->_counter) {
if (actor->_passValue != 1)
actor->_counter--;
switch (lastDir) {
case 0:
case 2:
y1 -= 2;
if (!checkMove2(x1, y1, actor))
setRandomDirFl = true;
break;
case 1:
case 3:
y1 += 2;
if (!checkMove2(x1, y1, actor))
setRandomDirFl = true;
break;
default:
break;
}
} else
setRandomDirFl = true;
if (setRandomDirFl) {
actor->_counter = g_events->getRandomNumber(10, 99);
lastDir = g_events->getRandomNumber(1);
}
if (lastDir > 1)
lastDir -= 2;
nextFrame(actor);
actor->_lastDir = lastDir;
if (actor->_directions == 1)
return 0;
return lastDir;
}
// Horizontal only (bats)
int movementEleven(Actor *actor) {
int d = actor->_lastDir;
switch (d) {
case 0:
if (checkMove2(actor->_x - 2, actor->_y - 2, actor))
break;
d = 1;
if (checkMove2(actor->_x - 2, actor->_y + 2, actor))
break;
d = 2;
break;
case 1:
if (checkMove2(actor->_x - 2, actor->_y + 2, actor))
break;
d = 0;
if (checkMove2(actor->_x - 2, actor->_y - 2, actor))
break;
d = 3;
break;
case 2:
if (checkMove2(actor->_x + 2, actor->_y - 2, actor))
break;
d = 3;
if (checkMove2(actor->_x + 2, actor->_y + 2, actor))
break;
d = 0;
break;
case 3:
if (checkMove2(actor->_x + 2, actor->_y + 2, actor))
break;
d = 2;
if (checkMove2(actor->_x + 2, actor->_y - 2, actor))
break;
d = 1;
break;
default:
break;
}
nextFrame(actor);
actor->_lastDir = d;
if (actor->_directions == 1)
return 0;
return d;
}
// Horizontal straight until bump
int movementTwelve(Actor *actor) {
int d = actor->_lastDir;
switch (d) {
case 0:
case 2:
if (checkMove2(actor->_x - 2, actor->_y, actor))
break;
d = 3;
break;
case 1:
case 3:
if (checkMove2(actor->_x + 2, actor->_y, actor))
break;
d = 2;
break;
default:
break;
}
nextFrame(actor);
actor->_lastDir = d;
if (actor->_directions == 1)
return 0;
return d;
}
// Pause-seek (mushroom)
int movementThirteen(Actor *actor) {
const int d = actor->_lastDir;
if (actor->_counter == 0 && actor->_unpauseCountdown == 0) {
actor->_unpauseCountdown = 60;
return d;
}
if (actor->_unpauseCountdown > 0) {
actor->_unpauseCountdown--;
if (!actor->_unpauseCountdown)
actor->_counter = 60;
actor->_vulnerableCountdown = 5;
actor->_hitStrength = 0;
return d;
}
if (actor->_counter > 0) {
actor->_counter--;
if (!actor->_counter)
actor->_unpauseCountdown = 60;
actor->_hitStrength = 10;
return movementFive(actor);
}
return d;
}
// Move-bump-stop (boulder)
int movementFourteen(Actor *actor) {
const int d = actor->_lastDir;
actor->_dir = d;
int x1 = actor->_x;
int y1 = actor->_y;
switch (d) {
case 0:
y1 -= 2;
if (!checkMove2(x1, y1, actor)) {
actor->_moveType = 15;
return 0;
}
break;
case 1:
y1 += 2;
if (!checkMove2(x1, y1, actor)) {
actor->_moveType = 15;
return 0;
}
break;
case 2:
x1 -= 2;
if (!checkMove2(x1, y1, actor)) {
actor->_moveType = 15;
return 0;
}
break;
case 3:
x1 += 2;
if (!checkMove2(x1, y1, actor)) {
actor->_moveType = 15;
return 0;
}
break;
default:
break;
}
nextFrame(actor);
actor->_lastDir = d;
if (actor->_directions == 1)
return 0;
return d;
}
// No movement - no frame cycle
int movementFifteen(Actor *actor) {
return actor->_dir;
}
// Tornado 1
int movementSixteen(Actor *actor) {
int d = actor->_lastDir;
int x1 = actor->_x;
int y1 = actor->_y;
switch (d) {
case 0:
y1 -= 2;
break;
case 1:
y1 += 2;
break;
case 2:
x1 -= 2;
break;
case 3:
x1 += 2;
break;
default:
break;
}
if (!checkMove1(x1, y1, actor)) {
actor->_moveType = 17;
d = g_events->getRandomNumber(3);
}
nextFrame(actor);
actor->_lastDir = d;
if (actor->_directions == 1)
return 0;
return d;
}
// Tornado 2
int movementSeventeen(Actor *actor) {
int d = actor->_lastDir;
switch (d) {
case 0:
if (checkMove1(actor->_x - 2, actor->_y - 2, actor))
break;
d = 1;
if (checkMove1(actor->_x - 2, actor->_y + 2, actor))
break;
d = 2;
break;
case 1:
if (checkMove1(actor->_x - 2, actor->_y + 2, actor))
break;
d = 0;
if (checkMove1(actor->_x - 2, actor->_y - 2, actor))
break;
d = 3;
break;
case 2:
if (checkMove1(actor->_x + 2, actor->_y - 2, actor))
break;
d = 3;
if (checkMove1(actor->_x + 2, actor->_y + 2, actor))
break;
d = 0;
break;
case 3:
if (checkMove1(actor->_x + 2, actor->_y + 2, actor))
break;
d = 2;
if (checkMove1(actor->_x + 2, actor->_y - 2, actor))
break;
d = 1;
break;
default:
break;
}
nextFrame(actor);
actor->_lastDir = d;
if (actor->_directions == 1)
return 0;
return d;
}
// No movement - frame cycle
int movementEighteen(Actor *actor) {
int d;
if (actor->_temp5) {
actor->_temp5--;
if (!actor->_temp5)
actor->_numMoves = 1;
}
if (actor->_temp1) {
d = movementFive(actor);
actor->_rand--;
if (actor->_hitThor || !actor->_rand) {
if (actor->_hitThor) {
actor->_temp5 = 50;
actor->_numMoves = 2;
actor->_hitThor = false;
actor->_dir = d;
d = reverseDirection(actor);
}
actor->_temp1 = 0;
actor->_rand = g_events->getRandomNumber(50, 149);
}
} else {
d = movementThree(actor);
actor->_rand--;
if (!actor->_rand) {
actor->_temp5 = 0;
actor->_temp1 = 1;
actor->_rand = g_events->getRandomNumber(50, 149);
}
if (actor->_hitThor) {
actor->_temp5 = 50;
actor->_numMoves = 2;
actor->_hitThor = false;
actor->_dir = d;
d = reverseDirection(actor);
}
}
nextFrame(actor);
return d;
}
// No movement - frame cycle
int movementNineteen(Actor *actor) {
return movementSeven(actor);
}
int movementTwenty(Actor *actor) {
if (GAME1)
// Boss - snake
return boss1Movement(actor);
return movementOne(actor);
}
// No movement - frame cycle
int movementTwentyOne(Actor *actor) {
return movementThree(actor);
}
// Spear
int movementTwentyTwo(Actor *actor) {
int d = actor->_lastDir;
if (actor->_directions == 1)
d = 0;
redo:
switch (actor->_temp2) {
case 0:
if (backgroundTile(actor->_x, actor->_y) >= TILE_SOLID)
actor->_nextFrame = 1;
else {
actor->_temp2 = 6;
actor->_temp1 = 1;
goto redo;
}
actor->_temp2++;
break;
case 1:
actor->_nextFrame = 2;
actor->_temp2++;
break;
case 2:
actor->_nextFrame = 3;
actor->_hitStrength = 255;
actor->_temp2++;
actor->_temp1 = 10;
break;
case 3:
checkMove2(actor->_x, actor->_y, actor);
actor->_temp1--;
if (actor->_temp1)
break;
actor->_temp2++;
actor->_nextFrame = 2;
break;
case 4:
actor->_hitStrength = 0;
actor->_temp2++;
actor->_nextFrame = 1;
break;
case 5:
actor->_temp2++;
actor->_nextFrame = 0;
actor->_temp1 = 10;
break;
case 6:
actor->_temp1--;
if (actor->_temp1)
break;
actor->_temp2 = 0;
actor->_nextFrame = 0;
switch (d) {
case 0:
actor->_x += 16;
actor->_y += 16;
d = 3;
if (backgroundTile(actor->_x, actor->_y) < TILE_SOLID)
goto redo;
break;
case 1:
actor->_x -= 16;
actor->_y -= 16;
d = 2;
if (backgroundTile(actor->_x, actor->_y) < TILE_SOLID)
goto redo;
break;
case 2:
actor->_x += 16;
actor->_y -= 16;
d = 0;
if (backgroundTile(actor->_x, actor->_y) < TILE_SOLID)
goto redo;
break;
case 3:
actor->_x -= 16;
actor->_y += 16;
d = 1;
if (backgroundTile(actor->_x, actor->_y) < TILE_SOLID)
goto redo;
break;
default:
break;
}
actor->_dir = d;
actor->_lastDir = d;
break;
default:
break;
}
return d;
}
// Spinball counter-clockwise
int movementTwentyThree(Actor *actor) {
int d = actor->_lastDir;
nextFrame(actor);
if (actor->_passValue & 2)
actor->_numMoves = 2;
switch (d) {
case 0:
if (backgroundTile(actor->_x - 2, actor->_y) >= TILE_FLY &&
backgroundTile(actor->_x - 2, actor->_y + actor->_sizeY - 1) >= TILE_FLY) {
d = 2;
actor->_x -= 2;
} else {
if (backgroundTile(actor->_x, actor->_y - 2) < TILE_FLY ||
backgroundTile(actor->_x + actor->_sizeX - 1, actor->_y - 2) < TILE_FLY) {
if (backgroundTile(actor->_x + actor->_sizeX + 1, actor->_y) >= TILE_FLY &&
backgroundTile(actor->_x + actor->_sizeX + 1, actor->_y + actor->_sizeY - 1) >= TILE_FLY) {
d = 3;
actor->_x += 2;
} else {
d = 1;
break;
}
} else
actor->_y -= 2;
}
break;
case 1:
if (backgroundTile(actor->_x + actor->_sizeX + 1, actor->_y) >= TILE_FLY &&
backgroundTile(actor->_x + actor->_sizeX + 1, actor->_y + actor->_sizeY - 1) >= TILE_FLY) {
d = 3;
actor->_x += 2;
} else {
if (backgroundTile(actor->_x, actor->_y + actor->_sizeY + 1) < TILE_FLY ||
backgroundTile(actor->_x + actor->_sizeX - 1, actor->_y + actor->_sizeY + 1) < TILE_FLY) {
if (backgroundTile(actor->_x - 2, actor->_y) >= TILE_FLY &&
backgroundTile(actor->_x - 2, actor->_y + actor->_sizeY - 1) >= TILE_FLY) {
d = 2;
actor->_x -= 2;
} else {
d = 0;
break;
}
} else
actor->_y += 2;
}
break;
case 2:
if (backgroundTile(actor->_x, actor->_y + actor->_sizeY + 1) >= TILE_FLY &&
backgroundTile(actor->_x + actor->_sizeX - 1, actor->_y + actor->_sizeY + 1) >= TILE_FLY) {
d = 1;
actor->_y += 2;
} else {
if (backgroundTile(actor->_x - 2, actor->_y) < TILE_FLY ||
backgroundTile(actor->_x - 2, actor->_y + actor->_sizeY - 1) < TILE_FLY) {
if (backgroundTile(actor->_x, actor->_y - 2) >= TILE_FLY &&
backgroundTile(actor->_x + actor->_sizeX - 1, actor->_y - 2) >= TILE_FLY) {
d = 0;
actor->_y -= 2;
} else {
d = 3;
break;
}
} else
actor->_x -= 2;
}
break;
case 3:
if (backgroundTile(actor->_x, actor->_y - 2) >= TILE_FLY &&
backgroundTile(actor->_x + actor->_sizeX - 1, actor->_y - 2) >= TILE_FLY) {
d = 0;
actor->_y -= 2;
} else {
if (backgroundTile(actor->_x + actor->_sizeX + 1, actor->_y) < TILE_FLY ||
backgroundTile(actor->_x + actor->_sizeX + 1, actor->_y + actor->_sizeY - 1) < TILE_FLY) {
if (backgroundTile(actor->_x, actor->_y + actor->_sizeY + 1) >= TILE_FLY &&
backgroundTile(actor->_x + actor->_sizeX - 1, actor->_y + actor->_sizeY + 1) >= TILE_FLY) {
d = 1;
actor->_y += 2;
} else {
d = 2;
break;
}
} else
actor->_x += 2;
}
break;
default:
break;
}
checkMove2(actor->_x, actor->_y, actor);
actor->_lastDir = d;
if (actor->_directions == 1)
return 0;
return d;
}
// Spinball clockwise
int movementTwentyFour(Actor *actor) {
int d = actor->_lastDir;
nextFrame(actor);
if (actor->_passValue & 2)
actor->_numMoves = 2;
switch (d) {
case 0:
if (backgroundTile(actor->_x + actor->_sizeX + 1, actor->_y) >= TILE_FLY &&
backgroundTile(actor->_x + actor->_sizeX + 1, actor->_y + actor->_sizeY - 1) >= TILE_FLY) {
d = 3;
actor->_x += 2;
} else {
if (backgroundTile(actor->_x, actor->_y - 2) < TILE_FLY ||
backgroundTile(actor->_x + actor->_sizeX - 1, actor->_y - 2) < TILE_FLY) {
if (backgroundTile(actor->_x - 2, actor->_y) >= TILE_FLY &&
backgroundTile(actor->_x - 2, actor->_y + actor->_sizeY - 1) >= TILE_FLY) {
d = 2;
actor->_x -= 2;
} else {
d = 1;
break;
}
} else
actor->_y -= 2;
}
break;
case 1:
if (backgroundTile(actor->_x - 2, actor->_y) >= TILE_FLY &&
backgroundTile(actor->_x - 2, actor->_y + actor->_sizeY - 1) >= TILE_FLY) {
d = 2;
actor->_x -= 2;
} else {
if (backgroundTile(actor->_x, actor->_y + actor->_sizeY + 1) < TILE_FLY ||
backgroundTile(actor->_x + actor->_sizeX - 1, actor->_y + actor->_sizeY + 1) < TILE_FLY) {
if (backgroundTile(actor->_x + actor->_sizeX + 1, actor->_y) >= TILE_FLY &&
backgroundTile(actor->_x + actor->_sizeX + 1, actor->_y + actor->_sizeY - 1) >= TILE_FLY) {
d = 3;
actor->_x += 2;
} else {
d = 0;
break;
}
} else
actor->_y += 2;
}
break;
case 2:
if (backgroundTile(actor->_x, actor->_y - 2) >= TILE_FLY &&
backgroundTile(actor->_x + actor->_sizeX - 1, actor->_y - 2) >= TILE_FLY) {
d = 0;
actor->_y -= 2;
} else {
if (backgroundTile(actor->_x - 2, actor->_y) < TILE_FLY ||
backgroundTile(actor->_x - 2, actor->_y + actor->_sizeY - 1) < TILE_FLY) {
if (backgroundTile(actor->_x, actor->_y + actor->_sizeY + 1) >= TILE_FLY &&
backgroundTile(actor->_x + actor->_sizeX - 1, actor->_y + actor->_sizeY + 1) >= TILE_FLY) {
d = 1;
actor->_y += 2;
} else {
d = 3;
break;
}
} else
actor->_x -= 2;
}
break;
case 3:
if (backgroundTile(actor->_x, actor->_y + actor->_sizeY + 1) >= TILE_FLY &&
backgroundTile(actor->_x + actor->_sizeX - 1, actor->_y + actor->_sizeY + 1) >= TILE_FLY) {
d = 1;
actor->_y += 2;
} else {
if (backgroundTile(actor->_x + actor->_sizeX + 1, actor->_y) < TILE_FLY ||
backgroundTile(actor->_x + actor->_sizeX + 1, actor->_y + actor->_sizeY - 1) < TILE_FLY) {
if (backgroundTile(actor->_x, actor->_y - 2) >= TILE_FLY &&
backgroundTile(actor->_x + actor->_sizeX - 1, actor->_y - 2) >= TILE_FLY) {
d = 0;
actor->_y -= 2;
} else {
d = 2;
break;
}
} else
actor->_x += 2;
}
break;
default:
break;
}
checkMove2(actor->_x, actor->_y, actor);
actor->_lastDir = d;
if (actor->_directions == 1)
return 0;
return d;
}
// Acid puddle
int movementTwentyFive(Actor *actor) {
if (actor->_temp2) {
actor->_temp2--;
return movementOne(actor);
}
if (!actor->_temp1) {
actor->_lastDir = g_events->getRandomNumber(3);
int i = 4;
while (i--) {
int ret = movementThree(actor);
if (ret)
return ret;
actor->_lastDir++;
if (actor->_lastDir > 3)
actor->_lastDir = 0;
}
actor->_temp1 = 16;
}
actor->_temp1--;
return movementThree(actor);
}
int movementTwentySix(Actor *actor) {
if (GAME2)
return boss2Movement(actor);
if (GAME3)
return boss3Movement(actor);
return movementOne(actor);
}
int movementTwentySeven(Actor *actor) {
if (GAME2)
return boss2Movement(actor);
return movementOne(actor);
}
void setThorVars() {
_G(thorX1) = _G(thor)->_x + 1;
_G(thorY1) = _G(thor)->_y + 8;
_G(thorRealY1) = _G(thor)->_y;
_G(thorX2) = (_G(thor)->_x + 12);
_G(thorY2) = _G(thor)->_y + 15;
}
// Fish
int movementTwentyEight(Actor *actor) {
const int d = actor->_lastDir;
int x1 = actor->_x;
int y1 = actor->_y;
int ret;
if (actor->_i1)
actor->_i1--;
else {
if (!actor->_temp3) {
if (!actor->_nextFrame) {
actor->_frameCount = 1;
actor->_frameSpeed = 4;
}
nextFrame(actor);
if (actor->_nextFrame == 3) {
if (actor->_currNumShots < actor->_numShotsAllowed)
actorShoots(actor, 0);
actor->_temp3 = 1;
}
} else {
const int fcount = actor->_frameCount - 1;
if (fcount <= 0) {
actor->_nextFrame--;
actor->_frameCount = actor->_frameSpeed;
if (!actor->_nextFrame) {
actor->_temp3 = 0;
actor->_frameSpeed = 4;
actor->_i1 = g_events->getRandomNumber(60, 159);
}
} else
actor->_frameCount = fcount;
}
goto done;
}
switch (actor->_temp2) {
case 0:
y1 -= 2;
break;
case 1:
y1 += 2;
break;
case 2:
x1 -= 2;
break;
case 3:
x1 += 2;
break;
default:
break;
}
ret = backgroundTile(x1, y1);
if (ret != 100 && ret != 106 && ret != 110 && ret != 111 && ret != 113)
goto chg_dir;
ret = backgroundTile((x1 + actor->_sizeX) - 1, y1);
if (ret != 100 && ret != 106 && ret != 110 && ret != 111 && ret != 113)
goto chg_dir;
ret = backgroundTile(x1, (y1 + actor->_sizeY) - 1);
if (ret != 100 && ret != 106 && ret != 110 && ret != 111 && ret != 113)
goto chg_dir;
ret = backgroundTile((x1 + actor->_sizeX) - 1, (y1 + actor->_sizeY) - 1);
if (ret != 100 && ret != 106 && ret != 110 && ret != 111 && ret != 113)
goto chg_dir;
actor->_x = x1;
actor->_y = y1;
goto done;
chg_dir:
actor->_temp2 = _G(rand1) % 4;
done:
if (actor->_nextFrame) {
x1 = actor->_x;
y1 = actor->_y;
actor->_solid = 1;
checkMove2(x1, y1, actor);
actor->_x = x1;
actor->_y = y1;
} else
actor->_solid = 2;
if (actor->_directions == 1)
return 0;
return d;
}
// Horizontal or vertical (pass_val)
int movementTwentyNine(Actor *actor) {
if (!actor->_passValue)
return movementThirty(actor);
return movementTwelve(actor);
}
// Vertical straight
int movementThirty(Actor *actor) {
int d = actor->_lastDir;
const int x1 = actor->_x;
int y1 = actor->_y;
switch (d) {
case 0:
y1 -= 2;
break;
case 1:
y1 += 2;
break;
default:
break;
}
if (!checkMove2(x1, y1, actor))
d ^= 1;
nextFrame(actor);
actor->_lastDir = d;
if (actor->_directions == 1)
return 0;
return d;
}
// Drop (stalagtite)
int movementThirtyOne(Actor *actor) {
const int d = actor->_lastDir;
int x1 = actor->_x;
int y1 = actor->_y;
if (actor->_temp1) {
y1 += 2;
if (!checkMove2(x1, y1, actor))
actorDestroyed(actor);
} else if (_G(thorY1) > y1 && ABS(x1 - _G(thorX1)) < 16) {
const int cx = (actor->_x + (actor->_sizeX / 2)) >> 4;
const int cy = ((actor->_y + actor->_sizeY) - 2) >> 4;
const int ty = _G(thor)->_centerY;
for (int i = cy; i <= ty; i++)
if (_G(scrn)._iconGrid[i][cx] < TILE_SOLID)
goto done;
actor->_numMoves = actor->_passValue + 1;
actor->_temp1 = 1;
}
done:
nextFrame(actor);
actor->_lastDir = d;
if (actor->_directions == 1)
return 0;
return d;
}
// Unused
int movementThirtyTwo(Actor *actor) {
return 0;
}
// Unused
int movementThirtyThree(Actor *actor) {
return 0;
}
// Unused
int movementThirtyFour(Actor *actor) {
return 0;
}
// Gun (single)
int movementThirtyFive(Actor *actor) {
actor->_nextFrame = actor->_lastDir;
return actor->_dir;
}
// Acid drop
int movementThirtySix(Actor *actor) {
actor->_speed = actor->_passValue;
nextFrame(actor);
if (actor->_nextFrame == 0 && actor->_frameCount == actor->_frameSpeed) {
actorAlwaysShoots(actor, 1);
_G(actor[actor->_shotActor])._x -= 2;
}
return 0;
}
// 4-way straight (random length) change
int movementThirtySeven(Actor *actor) {
int d = actor->_lastDir;
int x1 = actor->_x;
int y1 = actor->_y;
bool check = false;
if (actor->_counter) {
actor->_counter--;
switch (d) {
case 0:
y1 -= 2;
if (!checkMove2(x1, y1, actor))
check = true;
break;
case 1:
y1 += 2;
if (!checkMove2(x1, y1, actor))
check = true;
break;
case 2:
x1 -= 2;
if (!checkMove2(x1, y1, actor))
check = true;
break;
case 3:
x1 += 2;
if (!checkMove2(x1, y1, actor))
check = true;
break;
default:
break;
}
} else
check = true;
if (check) {
actor->_counter = g_events->getRandomNumber(10, 99);
d = g_events->getRandomNumber(3);
}
nextFrame(actor);
actor->_lastDir = d;
if (actor->_directions == 1)
return 0;
return d;
}
// Timed darting
#define TIMER actor->_i1
#define INIT_DIR actor->_temp1
#define OTHER_DIR actor->_temp2
#define FLAG actor->_temp3
#define OX actor->_i2
#define OY actor->_i3
#define CNT actor->_i4
int movementThirtyEight(Actor *actor) {
int d = actor->_lastDir;
int x1 = actor->_x;
int y1 = actor->_y;
if (!FLAG) {
FLAG = 1;
if (actor->_passValue)
TIMER = actor->_passValue * 15;
else
TIMER = g_events->getRandomNumber(5, 364);
INIT_DIR = actor->_lastDir;
OX = x1;
OY = y1;
CNT = 0;
switch (INIT_DIR) {
case 0:
OTHER_DIR = 1;
break;
case 1:
OTHER_DIR = 0;
break;
case 2:
OTHER_DIR = 3;
break;
case 3:
OTHER_DIR = 2;
break;
default:
break;
}
}
if (TIMER) {
TIMER--;
goto done;
}
switch (d) {
case 0:
y1 -= 2;
break;
case 1:
y1 += 2;
break;
case 2:
x1 -= 2;
break;
case 3:
x1 += 2;
break;
default:
break;
}
switch (FLAG) {
case 1:
if (!checkMove2(x1, y1, actor)) {
if (CNT) {
d = OTHER_DIR;
actor->_lastDir = d;
FLAG = 2;
} else {
actor->_nextFrame = 0;
FLAG = 0;
goto done;
}
} else
CNT++;
break;
case 2:
checkMove2(x1, y1, actor);
if (x1 == OX && y1 == OY) {
FLAG = 0;
d = INIT_DIR;
actor->_lastDir = d;
actor->_nextFrame = 0;
goto done;
}
break;
default:
break;
}
nextFrame(actor);
done:
actor->_lastDir = d;
if (actor->_directions == 1)
return 0;
return d;
}
// Troll 1
int movementThirtyNine(Actor *actor) {
if (_G(setup)._difficultyLevel == 0) {
actor->_speed = 3;
actor->_numMoves = 1;
} else if (_G(setup)._difficultyLevel == 1) {
actor->_speed = 2;
actor->_numMoves = 1;
} else if (_G(setup)._difficultyLevel == 2) {
actor->_speed = 1;
actor->_numMoves = 1;
}
if (actor->_passValue < 5)
return movementForty(actor);
if (actor->_passValue == 10) {
if (overlap(actor->_x + 1, actor->_y + 1, actor->_x + actor->_sizeX - 1,
actor->_y + actor->_sizeY - 1, _G(thorX1), _G(thorY1), _G(thorX2), _G(thorY2))) {
actor->_hitStrength = 255;
thorDamaged(actor);
}
return actor->_dir;
}
if (actor->_actorNum != 3)
return actor->_dir;
if (actor->_i1) {
actor->_i1--;
actor->_x -= 2;
checkMove2(actor->_x, actor->_y, actor);
_G(actor[4])._x -= 2;
_G(actor[5])._x -= 2;
_G(actor[6])._x -= 2;
}
nextFrame(actor);
if (actor->_nextFrame == 3)
actor->_nextFrame = 0;
_G(actor[4])._nextFrame = _G(actor[3])._nextFrame;
_G(actor[5])._nextFrame = 0;
_G(actor[6])._nextFrame = 0;
return actor->_dir;
}
// Troll 2
int movementForty(Actor *actor) {
if (overlap(actor->_x + 1, actor->_y + 1, actor->_x + actor->_sizeX + 3,
actor->_y + actor->_sizeY - 1, _G(thorX1), _G(thorY1), _G(thorX2), _G(thorY2))) {
actor->_hitStrength = 150;
thorDamaged(actor);
}
int a = 5 + (actor->_passValue * 4);
const int x1 = actor->_x;
int d = actor->_lastDir;
if (actor->_lastDir == 2) {
if (backgroundTile(x1 - 2, actor->_y) >= TILE_SOLID) {
_G(actor[a]._x) -= 2;
_G(actor[a - 1])._x -= 2;
_G(actor[a - 2])._x -= 2;
_G(actor[a + 1])._x -= 2;
} else
d = 3;
} else if (backgroundTile(_G(actor[a + 1])._x + 14, _G(actor[a + 1])._y) >= TILE_SOLID) {
_G(actor[a])._x += 2;
_G(actor[a - 1])._x += 2;
_G(actor[a - 2])._x += 2;
_G(actor[a + 1])._x += 2;
} else
d = 2;
if (actor->_nextFrame == 3 && !actor->_currNumShots && actor->_frameCount == actor->_frameSpeed) {
actorAlwaysShoots(actor, 1);
_G(actor[actor->_shotActor])._x += 6;
}
nextFrame(actor);
_G(actor[a - 2])._nextFrame = actor->_nextFrame;
_G(actor[a - 1])._nextFrame = actor->_nextFrame;
_G(actor[a + 1])._nextFrame = actor->_nextFrame;
_G(actor[a - 2])._lastDir = d;
_G(actor[a - 1])._lastDir = d;
_G(actor[a + 1])._lastDir = d;
actor->_lastDir = d;
if (actor->_directions == 1)
return 0;
return d;
}
} // namespace Got