mirror of
https://github.com/libretro/scummvm.git
synced 2024-12-05 00:36:57 +00:00
61fa4b6253
There was a nasty bug in the fuel tower room, when the cops arrive at the tower and the player regains control, in which the camera would be brought up and then down again. While I was there, since this is the same domain, I rechecked the v7-8 camera code from the disasm, made some corrections, and properly fixed #1195 and #1579. Another workaround bites the dust :)
367 lines
9.7 KiB
C++
367 lines
9.7 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 "scumm/scumm.h"
|
|
#include "scumm/actor.h"
|
|
#include "scumm/charset.h"
|
|
#include "scumm/scumm_v7.h"
|
|
|
|
#include "common/util.h"
|
|
|
|
namespace Scumm {
|
|
|
|
void ScummEngine::setCameraAtEx(int at) {
|
|
if (_game.version < 7) {
|
|
camera._mode = kNormalCameraMode;
|
|
camera._cur.x = at;
|
|
setCameraAt(at, 0);
|
|
camera._movingToActor = false;
|
|
}
|
|
}
|
|
|
|
void ScummEngine::setCameraAt(int pos_x, int pos_y) {
|
|
if (camera._mode != kFollowActorCameraMode || ABS(pos_x - camera._cur.x) > (_screenWidth / 2)) {
|
|
camera._cur.x = pos_x;
|
|
}
|
|
camera._dest.x = pos_x;
|
|
|
|
if (VAR_CAMERA_MIN_X != 0xFF && camera._cur.x < VAR(VAR_CAMERA_MIN_X))
|
|
camera._cur.x = (short) VAR(VAR_CAMERA_MIN_X);
|
|
|
|
if (VAR_CAMERA_MAX_X != 0xFF && camera._cur.x > VAR(VAR_CAMERA_MAX_X))
|
|
camera._cur.x = (short) VAR(VAR_CAMERA_MAX_X);
|
|
|
|
if (VAR_SCROLL_SCRIPT != 0xFF && VAR(VAR_SCROLL_SCRIPT)) {
|
|
VAR(VAR_CAMERA_POS_X) = camera._cur.x;
|
|
runScript(VAR(VAR_SCROLL_SCRIPT), 0, 0, nullptr);
|
|
}
|
|
|
|
// If the camera moved and text is visible, remove it
|
|
if (camera._cur.x != camera._last.x && _charset->_hasMask && _game.version > 3)
|
|
stopTalk();
|
|
}
|
|
|
|
void ScummEngine::setCameraFollows(Actor *a, bool setCamera) {
|
|
|
|
int t, i;
|
|
|
|
camera._mode = kFollowActorCameraMode;
|
|
camera._follows = a->_number;
|
|
|
|
if (!a->isInCurrentRoom()) {
|
|
startScene(a->getRoom(), nullptr, 0);
|
|
camera._mode = kFollowActorCameraMode;
|
|
camera._cur.x = a->getPos().x;
|
|
setCameraAt(camera._cur.x, 0);
|
|
}
|
|
|
|
t = a->getPos().x / 8 - _screenStartStrip;
|
|
|
|
if (t < camera._leftTrigger || t > camera._rightTrigger || setCamera == true)
|
|
setCameraAt(a->getPos().x, 0);
|
|
|
|
for (i = 1; i < _numActors; i++) {
|
|
if (_actors[i]->isInCurrentRoom())
|
|
_actors[i]->_needRedraw = true;
|
|
}
|
|
runInventoryScript(0);
|
|
}
|
|
|
|
void ScummEngine::clampCameraPos(Common::Point *pt) {
|
|
pt->x = CLIP<short>(pt->x, VAR(VAR_CAMERA_MIN_X), VAR(VAR_CAMERA_MAX_X));
|
|
pt->y = CLIP<short>(pt->y, VAR(VAR_CAMERA_MIN_Y), VAR(VAR_CAMERA_MAX_Y));
|
|
}
|
|
|
|
void ScummEngine::moveCamera() {
|
|
int pos = camera._cur.x;
|
|
int t;
|
|
Actor *a = nullptr;
|
|
const bool snapToX = (_snapScroll || (VAR_CAMERA_FAST_X != 0xFF && VAR(VAR_CAMERA_FAST_X)));
|
|
|
|
camera._cur.x &= 0xFFF8;
|
|
|
|
if (VAR_CAMERA_MIN_X != 0xFF && camera._cur.x < VAR(VAR_CAMERA_MIN_X)) {
|
|
if (snapToX)
|
|
camera._cur.x = (short) VAR(VAR_CAMERA_MIN_X);
|
|
else
|
|
camera._cur.x += 8;
|
|
cameraMoved();
|
|
return;
|
|
}
|
|
|
|
if (VAR_CAMERA_MAX_X != 0xFF && camera._cur.x > VAR(VAR_CAMERA_MAX_X)) {
|
|
if (snapToX)
|
|
camera._cur.x = (short) VAR(VAR_CAMERA_MAX_X);
|
|
else
|
|
camera._cur.x -= 8;
|
|
cameraMoved();
|
|
return;
|
|
}
|
|
|
|
if (camera._mode == kFollowActorCameraMode) {
|
|
a = derefActor(camera._follows, "moveCamera");
|
|
|
|
int actorx = a->getPos().x;
|
|
t = actorx / 8 - _screenStartStrip;
|
|
|
|
if (t < camera._leftTrigger || t > camera._rightTrigger) {
|
|
if (snapToX) {
|
|
if (t > 40-5)
|
|
camera._dest.x = actorx + 80;
|
|
if (t < 5)
|
|
camera._dest.x = actorx - 80;
|
|
} else
|
|
camera._movingToActor = true;
|
|
}
|
|
}
|
|
|
|
if (camera._movingToActor) {
|
|
a = derefActor(camera._follows, "moveCamera(2)");
|
|
camera._dest.x = a->getPos().x;
|
|
}
|
|
|
|
if (VAR_CAMERA_MIN_X != 0xFF && camera._dest.x < VAR(VAR_CAMERA_MIN_X))
|
|
camera._dest.x = (short) VAR(VAR_CAMERA_MIN_X);
|
|
|
|
if (VAR_CAMERA_MAX_X != 0xFF && camera._dest.x > VAR(VAR_CAMERA_MAX_X))
|
|
camera._dest.x = (short) VAR(VAR_CAMERA_MAX_X);
|
|
|
|
if (snapToX) {
|
|
camera._cur.x = camera._dest.x;
|
|
} else {
|
|
if (camera._cur.x < camera._dest.x)
|
|
camera._cur.x += 8;
|
|
if (camera._cur.x > camera._dest.x)
|
|
camera._cur.x -= 8;
|
|
}
|
|
|
|
/* Actor 'a' is set a bit above */
|
|
if (camera._movingToActor && (camera._cur.x / 8) == (a->getPos().x / 8)) {
|
|
camera._movingToActor = false;
|
|
}
|
|
|
|
cameraMoved();
|
|
|
|
if (VAR_SCROLL_SCRIPT != 0xFF && VAR(VAR_SCROLL_SCRIPT) && pos != camera._cur.x) {
|
|
VAR(VAR_CAMERA_POS_X) = camera._cur.x;
|
|
runScript(VAR(VAR_SCROLL_SCRIPT), 0, 0, nullptr);
|
|
}
|
|
}
|
|
|
|
void ScummEngine::cameraMoved() {
|
|
int screenLeft;
|
|
if (_game.version >= 7) {
|
|
clampCameraPos(&camera._cur);
|
|
assert(camera._cur.x >= (_screenWidth / 2) && camera._cur.y >= (_screenHeight / 2));
|
|
} else {
|
|
if (camera._cur.x < (_screenWidth / 2)) {
|
|
camera._cur.x = (_screenWidth / 2);
|
|
} else if (camera._cur.x > _roomWidth - (_screenWidth / 2)) {
|
|
camera._cur.x = _roomWidth - (_screenWidth / 2);
|
|
}
|
|
}
|
|
|
|
_screenStartStrip = camera._cur.x / 8 - _gdi->_numStrips / 2;
|
|
_screenEndStrip = _screenStartStrip + _gdi->_numStrips - 1;
|
|
|
|
_screenTop = camera._cur.y - (_screenHeight / 2);
|
|
if (_game.version >= 7) {
|
|
screenLeft = camera._cur.x - (_screenWidth / 2);
|
|
} else {
|
|
screenLeft = _screenStartStrip * 8;
|
|
}
|
|
|
|
_virtscr[kMainVirtScreen].xstart = screenLeft;
|
|
}
|
|
|
|
void ScummEngine::panCameraTo(int x, int y) {
|
|
camera._dest.x = x;
|
|
camera._mode = kPanningCameraMode;
|
|
camera._movingToActor = false;
|
|
}
|
|
|
|
void ScummEngine::actorFollowCamera(int act) {
|
|
if (_game.version < 7) {
|
|
int old;
|
|
|
|
old = camera._follows;
|
|
setCameraFollows(derefActor(act, "actorFollowCamera"));
|
|
if (camera._follows != old)
|
|
runInventoryScript(0);
|
|
|
|
camera._movingToActor = false;
|
|
}
|
|
}
|
|
|
|
#ifdef ENABLE_SCUMM_7_8
|
|
void ScummEngine_v7::setCameraAt(int pos_x, int pos_y) {
|
|
Common::Point old;
|
|
|
|
old = camera._cur;
|
|
|
|
camera._cur.x = pos_x;
|
|
camera._cur.y = pos_y;
|
|
|
|
clampCameraPos(&camera._cur);
|
|
|
|
camera._dest = camera._cur;
|
|
|
|
assert(camera._cur.x >= (_screenWidth / 2) && camera._cur.y >= (_screenHeight / 2));
|
|
|
|
if (camera._cur.x != old.x || camera._cur.y != old.y) {
|
|
if (VAR(VAR_SCROLL_SCRIPT) && _game.version != 8) {
|
|
VAR(VAR_CAMERA_POS_X) = camera._cur.x;
|
|
VAR(VAR_CAMERA_POS_Y) = camera._cur.y;
|
|
runScript(VAR(VAR_SCROLL_SCRIPT), 0, 0, 0);
|
|
}
|
|
}
|
|
}
|
|
|
|
void ScummEngine_v7::setCameraFollows(Actor *a, bool setCamera) {
|
|
|
|
byte oldfollow = camera._follows;
|
|
int ax, ay;
|
|
|
|
camera._follows = a->_number;
|
|
|
|
if (!a->isInCurrentRoom()) {
|
|
startScene(a->getRoom(), 0, 0);
|
|
}
|
|
|
|
ax = ABS(a->getPos().x - camera._cur.x);
|
|
ay = ABS(a->getPos().y - camera._cur.y);
|
|
|
|
if (ax > VAR(VAR_CAMERA_THRESHOLD_X) || ay > VAR(VAR_CAMERA_THRESHOLD_Y) || ax > (_screenWidth / 2) || ay > (_screenHeight / 2)) {
|
|
setCameraAt(a->getPos().x, a->getPos().y);
|
|
}
|
|
|
|
if (a->_number != oldfollow)
|
|
runInventoryScript(0);
|
|
}
|
|
|
|
void ScummEngine_v7::moveCamera() {
|
|
Common::Point old = camera._cur;
|
|
Actor *a = NULL;
|
|
|
|
if (_game.version == 8 && _cameraIsFrozen) {
|
|
cameraMoved();
|
|
return;
|
|
}
|
|
|
|
if (camera._follows) {
|
|
a = derefActor(camera._follows, "moveCamera");
|
|
if (ABS(camera._cur.x - a->getPos().x) > VAR(VAR_CAMERA_THRESHOLD_X) ||
|
|
ABS(camera._cur.y - a->getPos().y) > VAR(VAR_CAMERA_THRESHOLD_Y)) {
|
|
camera._movingToActor = true;
|
|
if (VAR(VAR_CAMERA_THRESHOLD_X) == 0)
|
|
camera._cur.x = a->getPos().x;
|
|
if (VAR(VAR_CAMERA_THRESHOLD_Y) == 0)
|
|
camera._cur.y = a->getPos().y;
|
|
clampCameraPos(&camera._cur);
|
|
}
|
|
} else {
|
|
camera._movingToActor = false;
|
|
}
|
|
|
|
if (camera._movingToActor) {
|
|
VAR(VAR_CAMERA_DEST_X) = camera._dest.x = a->getPos().x;
|
|
VAR(VAR_CAMERA_DEST_Y) = camera._dest.y = a->getPos().y;
|
|
}
|
|
|
|
assert(camera._cur.x >= (_screenWidth / 2) && camera._cur.y >= (_screenHeight / 2));
|
|
|
|
clampCameraPos(&camera._dest);
|
|
|
|
if (camera._cur.x < camera._dest.x) {
|
|
camera._cur.x += (short) VAR(VAR_CAMERA_SPEED_X);
|
|
if (camera._cur.x > camera._dest.x)
|
|
camera._cur.x = camera._dest.x;
|
|
}
|
|
|
|
if (camera._cur.x > camera._dest.x) {
|
|
camera._cur.x -= (short) VAR(VAR_CAMERA_SPEED_X);
|
|
if (camera._cur.x < camera._dest.x)
|
|
camera._cur.x = camera._dest.x;
|
|
}
|
|
|
|
if (camera._cur.y < camera._dest.y) {
|
|
camera._cur.y += (short) VAR(VAR_CAMERA_SPEED_Y);
|
|
if (camera._cur.y > camera._dest.y)
|
|
camera._cur.y = camera._dest.y;
|
|
}
|
|
|
|
if (camera._cur.y > camera._dest.y) {
|
|
camera._cur.y -= (short) VAR(VAR_CAMERA_SPEED_Y);
|
|
if (camera._cur.y < camera._dest.y)
|
|
camera._cur.y = camera._dest.y;
|
|
}
|
|
|
|
if (camera._cur.x == camera._dest.x && camera._cur.y == camera._dest.y) {
|
|
|
|
camera._movingToActor = false;
|
|
camera._accel.x = camera._accel.y = 0;
|
|
VAR(VAR_CAMERA_SPEED_X) = VAR(VAR_CAMERA_SPEED_Y) = 0;
|
|
} else {
|
|
|
|
camera._accel.x += (short) VAR(VAR_CAMERA_ACCEL_X);
|
|
camera._accel.y += (short) VAR(VAR_CAMERA_ACCEL_Y);
|
|
|
|
VAR(VAR_CAMERA_SPEED_X) += camera._accel.x / 100;
|
|
VAR(VAR_CAMERA_SPEED_Y) += camera._accel.y / 100;
|
|
|
|
if (VAR(VAR_CAMERA_SPEED_X) > 8)
|
|
VAR(VAR_CAMERA_SPEED_X) = 8;
|
|
|
|
if (VAR(VAR_CAMERA_SPEED_Y) > 8)
|
|
VAR(VAR_CAMERA_SPEED_Y) = 8;
|
|
|
|
}
|
|
|
|
cameraMoved();
|
|
|
|
if (_game.id != GID_FT) {
|
|
VAR(VAR_CAMERA_POS_X) = camera._cur.x;
|
|
VAR(VAR_CAMERA_POS_Y) = camera._cur.y;
|
|
VAR(VAR_CAMERA_DEST_X) = camera._dest.x;
|
|
VAR(VAR_CAMERA_DEST_Y) = camera._dest.y;
|
|
VAR(VAR_CAMERA_FOLLOWED_ACTOR) = camera._follows;
|
|
}
|
|
|
|
if (camera._cur.x != old.x || camera._cur.y != old.y) {
|
|
if (_game.id == GID_FT) {
|
|
VAR(VAR_CAMERA_POS_X) = camera._cur.x;
|
|
VAR(VAR_CAMERA_POS_Y) = camera._cur.y;
|
|
}
|
|
|
|
if (VAR(VAR_SCROLL_SCRIPT))
|
|
runScript(VAR(VAR_SCROLL_SCRIPT), 0, 0, 0);
|
|
}
|
|
}
|
|
|
|
void ScummEngine_v7::panCameraTo(int x, int y) {
|
|
camera._follows = 0;
|
|
VAR(VAR_CAMERA_DEST_X) = camera._dest.x = x;
|
|
VAR(VAR_CAMERA_DEST_Y) = camera._dest.y = y;
|
|
}
|
|
#endif
|
|
|
|
} // End of namespace Scumm
|