Files
scummvm-cursorfix/engines/got/game/move_patterns.cpp
2026-02-02 04:50:13 +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