[Scummvm-git-logs] scummvm master -> 461eeec147ba2265a1eb8874817d88a721a32759
Helco
noreply at scummvm.org
Sun Feb 8 18:16:20 UTC 2026
This automated email contains information about 4 new commits which have been
pushed to the 'scummvm' repo located at https://api.github.com/repos/scummvm/scummvm .
Summary:
c73f1744e2 ALCACHOFA: Reduce public API of Camera
1cbaff76f4 ALCACHOFA: Split Camera into base class and V3
8ade46170b ALCACHOFA: TERROR: Fix outro
461eeec147 ALCACHOFA: Add CameraV1
Commit: c73f1744e2fe7c20990799f0877054887daa03df
https://github.com/scummvm/scummvm/commit/c73f1744e2fe7c20990799f0877054887daa03df
Author: Helco (hermann.noll at hotmail.com)
Date: 2026-02-08T19:01:39+01:00
Commit Message:
ALCACHOFA: Reduce public API of Camera
Changed paths:
engines/alcachofa/alcachofa.cpp
engines/alcachofa/camera.cpp
engines/alcachofa/camera.h
engines/alcachofa/global-ui.cpp
engines/alcachofa/menu.cpp
engines/alcachofa/player.cpp
engines/alcachofa/rooms.cpp
engines/alcachofa/script.cpp
diff --git a/engines/alcachofa/alcachofa.cpp b/engines/alcachofa/alcachofa.cpp
index 530b908c736..2206e8ad439 100644
--- a/engines/alcachofa/alcachofa.cpp
+++ b/engines/alcachofa/alcachofa.cpp
@@ -113,7 +113,7 @@ Common::Error AlcachofaEngine::run() {
_sounds.update();
_renderer->begin();
_drawQueue->clear();
- _camera.shake() = Vector2d();
+ _camera.preUpdate();
_player->preUpdate();
if (_player->currentRoom() != nullptr)
_player->currentRoom()->update();
diff --git a/engines/alcachofa/camera.cpp b/engines/alcachofa/camera.cpp
index 00f2530dfcd..da2e5831f31 100644
--- a/engines/alcachofa/camera.cpp
+++ b/engines/alcachofa/camera.cpp
@@ -21,7 +21,7 @@
#include "alcachofa/camera.h"
#include "alcachofa/alcachofa.h"
-#include "alcachofa/script.h"
+#include "alcachofa/graphics.h"
#include "common/system.h"
#include "math/vector4d.h"
@@ -31,28 +31,35 @@ using namespace Math;
namespace Alcachofa {
-void Camera::resetRotationAndScale() {
- _cur._scale = 1;
- _cur._rotation = 0;
- _cur._usedCenter.z() = 0;
+void Camera::preUpdate() {
+ _shake = {};
}
-void Camera::setRoomBounds(Point min, Point size) {
- Point screenSize(g_system->getWidth(), g_system->getHeight());
- _roomMin = as2D(min + screenSize / 2);
- _roomMax = _roomMin + as2D(size - screenSize);
- _roomScale = 0;
-}
-
-void Camera::setRoomBounds(Point bgSize, int16 bgScale) {
- float scaleFactor = 1 - bgScale * kInvBaseScale;
- _roomMin = Vector2d(
- g_system->getWidth() / 2 * scaleFactor,
- g_system->getHeight() / 2 * scaleFactor);
- _roomMax = _roomMin + Vector2d(
- bgSize.x * bgScale * kInvBaseScale,
- bgSize.y * bgScale * kInvBaseScale);
- _roomScale = bgScale;
+void Camera::setRoomBounds(Graphic &background) {
+ auto bgSize = background.animation().imageSize(0);
+ if (g_engine->isV1()) {
+ Point screenSize(g_system->getWidth(), g_system->getHeight());
+ _roomMin = as2D(background.topLeft() + screenSize / 2);
+ _roomMax = _roomMin + as2D(bgSize - screenSize);
+ _roomScale = 0;
+ } else {
+ /* The fallback fixes a bug where if the background image is invalid the original engine
+ * would not update the background size. This would be around 1024,768 due to
+ * previous rooms in the bug instances I found.
+ */
+ if (bgSize == Point(0, 0))
+ bgSize = Point(1024, 768);
+
+ const auto bgScale = background.scale();
+ float scaleFactor = 1 - bgScale * kInvBaseScale;
+ _roomMin = Vector2d(
+ g_system->getWidth() / 2 * scaleFactor,
+ g_system->getHeight() / 2 * scaleFactor);
+ _roomMax = _roomMin + Vector2d(
+ bgSize.x * bgScale * kInvBaseScale,
+ bgSize.y * bgScale * kInvBaseScale);
+ _roomScale = bgScale;
+ }
}
void Camera::setFollow(WalkingCharacter *target, bool catchUp) {
@@ -64,6 +71,49 @@ void Camera::setFollow(WalkingCharacter *target, bool catchUp) {
_isChanging = false;
}
+void Camera::onChangedRoom(bool resetCamera) {
+ if (resetCamera)
+ resetRotationAndScale();
+ if (_followTarget != nullptr)
+ setFollow(_followTarget, true);
+}
+
+void Camera::onTriggeredDoor(WalkingCharacter *target) {
+ setFollow(target, true);
+}
+
+void Camera::onTriggeredDoor(Point fixedPosition) {
+ setPosition(as2D(fixedPosition));
+}
+
+void Camera::onScriptChangedCharacter(MainCharacterKind kind) {
+ resetRotationAndScale();
+ if (kind != MainCharacterKind::None)
+ setFollow(g_engine->player().activeCharacter());
+ backup(0);
+}
+
+void Camera::onUserChangedCharacter() {
+ setFollow(g_engine->player().activeCharacter());
+ restore(0);
+}
+
+void Camera::onOpenMenu() {
+ backup(1);
+ setPosition(Math::Vector3d(
+ g_system->getWidth() / 2.0f, g_system->getHeight() / 2.0f, 0.0f));
+}
+
+void Camera::onCloseMenu() {
+ restore(1);
+}
+
+void Camera::resetRotationAndScale() {
+ _cur._scale = 1;
+ _cur._rotation = 0;
+ _cur._usedCenter.z() = 0;
+}
+
void Camera::setPosition(Vector2d v) {
setPosition({ v.getX(), v.getY(), _cur._usedCenter.z() });
}
@@ -487,7 +537,7 @@ protected:
void update(float t) override {
const Vector2d phase = _frequency * t * (float)M_PI * 2.0f;
const float amplTimeFactor = 1.0f / expf(t * 5.0f); // a curve starting at 1, depreciating towards 0
- _camera.shake() = {
+ _camera._shake = {
sinf(phase.getX()) * _amplitude.getX() * amplTimeFactor,
sinf(phase.getY()) * _amplitude.getY() * amplTimeFactor
};
@@ -692,7 +742,7 @@ struct CamDisguiseTask final : public Task {
TaskReturn run() override {
if (_startTime == 0) {
- _startPosition = { _camera.usedCenter().x(), _camera.usedCenter().y() };
+ _startPosition = { _camera._cur._usedCenter.x(), _camera._cur._usedCenter.y() };
_startTime = g_engine->getMillis();
}
if (_durationMs <= 0 || g_engine->getMillis() - _startTime >= (uint32)_durationMs)
diff --git a/engines/alcachofa/camera.h b/engines/alcachofa/camera.h
index c6774da47bf..e7424587f51 100644
--- a/engines/alcachofa/camera.h
+++ b/engines/alcachofa/camera.h
@@ -27,6 +27,7 @@
namespace Alcachofa {
+class Graphic;
class WalkingCharacter;
class Process;
struct Task;
@@ -36,24 +37,24 @@ static constexpr const float kInvBaseScale = 1.0f / kBaseScale;
class Camera {
public:
- inline Math::Vector3d usedCenter() const { return _cur._usedCenter; }
inline Math::Angle rotation() const { return _cur._rotation; }
- inline Math::Vector2d &shake() { return _shake; }
- inline WalkingCharacter *followTarget() { return _followTarget; }
+ void preUpdate();
void update();
+ void setRoomBounds(Graphic &background);
+ void setFollow(WalkingCharacter *target, bool catchUp = false);
+ void onChangedRoom(bool resetCamera);
+ void onTriggeredDoor(WalkingCharacter *target);
+ void onTriggeredDoor(Common::Point fixedPosition);
+ void onScriptChangedCharacter(MainCharacterKind kind);
+ void onUserChangedCharacter();
+ void onOpenMenu();
+ void onCloseMenu();
+ void syncGame(Common::Serializer &s);
+
Math::Vector3d transform2Dto3D(Math::Vector3d v) const;
Math::Vector3d transform3Dto2D(Math::Vector3d v) const;
Common::Point transform3Dto2D(Common::Point p) const;
- void resetRotationAndScale();
- void setRoomBounds(Common::Point min, Common::Point size); ///< Used in V1
- void setRoomBounds(Common::Point bgSize, int16 bgScale); ///< Used in V3
- void setFollow(WalkingCharacter *target, bool catchUp = false);
- void setPosition(Math::Vector2d v);
- void setPosition(Math::Vector3d v);
- void backup(uint slot);
- void restore(uint slot);
- void syncGame(Common::Serializer &s);
Task *lerpPos(Process &process,
Math::Vector2d targetPos,
@@ -78,6 +79,12 @@ public:
Task *disguise(Process &process, int32 duration);
private:
+ void resetRotationAndScale();
+ void setPosition(Math::Vector2d v);
+ void setPosition(Math::Vector3d v);
+ void backup(uint slot);
+ void restore(uint slot);
+
friend struct CamLerpTask;
friend struct CamLerpPosTask;
friend struct CamLerpScaleTask;
@@ -86,6 +93,7 @@ private:
friend struct CamShakeTask;
friend struct CamWaitToStopTask;
friend struct CamSetInactiveAttributeTask;
+ friend struct CamDisguiseTask;
Math::Vector3d setAppliedCenter(Math::Vector3d center);
void setupMatricesAround(Math::Vector3d center);
void updateFollowing(float deltaTime);
diff --git a/engines/alcachofa/global-ui.cpp b/engines/alcachofa/global-ui.cpp
index 044ee034d62..1c9d8aedd26 100644
--- a/engines/alcachofa/global-ui.cpp
+++ b/engines/alcachofa/global-ui.cpp
@@ -143,8 +143,7 @@ bool GlobalUI::updateChangingCharacter() {
player.setActiveCharacter(player.inactiveCharacter()->kind());
player.heldItem() = nullptr;
- g_engine->camera().setFollow(player.activeCharacter());
- g_engine->camera().restore(0);
+ g_engine->camera().onUserChangedCharacter();
player.changeRoom(player.activeCharacter()->room()->name(), false);
g_engine->game().onUserChangedCharacter();
diff --git a/engines/alcachofa/menu.cpp b/engines/alcachofa/menu.cpp
index 5576f6fac1d..a211ffdad47 100644
--- a/engines/alcachofa/menu.cpp
+++ b/engines/alcachofa/menu.cpp
@@ -100,9 +100,7 @@ void Menu::updateOpeningMenu() {
g_engine->player().heldItem() = nullptr;
g_engine->scheduler().backupContext();
- g_engine->camera().backup(1);
- g_engine->camera().setPosition(Math::Vector3d(
- g_system->getWidth() / 2.0f, g_system->getHeight() / 2.0f, 0.0f));
+ g_engine->camera().onOpenMenu();
}
void MenuV1::updateOpeningMenu() {
@@ -193,7 +191,7 @@ void Menu::continueGame() {
g_engine->input().nextFrame(); // presumably to clear all was* flags
g_engine->player().changeRoom(_previousRoom->name(), true);
g_engine->sounds().pauseAll(false);
- g_engine->camera().restore(1);
+ g_engine->camera().onCloseMenu();
g_engine->scheduler().restoreContext();
g_engine->setMillis(_millisBeforeMenu);
}
diff --git a/engines/alcachofa/player.cpp b/engines/alcachofa/player.cpp
index 1f19b7e3070..e4cdc817d84 100644
--- a/engines/alcachofa/player.cpp
+++ b/engines/alcachofa/player.cpp
@@ -162,11 +162,7 @@ void Player::changeRoom(const Common::String &targetRoomName, bool resetCamera,
}
_currentRoom->loadResources(); // if we kept resources we loop over a couple noops, that is fine.
- if (resetCamera)
- g_engine->camera().resetRotationAndScale();
- WalkingCharacter *followTarget = g_engine->camera().followTarget();
- if (followTarget != nullptr)
- g_engine->camera().setFollow(followTarget, true);
+ g_engine->camera().onChangedRoom(resetCamera);
_pressedObject = _selectedObject = nullptr;
}
@@ -257,12 +253,12 @@ struct DoorTask final : public Task {
_player.changeRoom(_targetRoom->name(), true); //-V779
if (_targetRoom->fixedCameraOnEntering())
- g_engine->camera().setPosition(as2D(_targetObject->interactionPoint()));
+ g_engine->camera().onTriggeredDoor(_targetObject->interactionPoint());
else {
_character->room() = _targetRoom;
_character->setPosition(_targetObject->interactionPoint());
_character->stopWalking(_targetDirection);
- g_engine->camera().setFollow(_character, true);
+ g_engine->camera().onTriggeredDoor(_character);
}
g_engine->sounds().setMusicToRoom(_targetRoom->musicID());
diff --git a/engines/alcachofa/rooms.cpp b/engines/alcachofa/rooms.cpp
index 4de14e1ce0f..7dbba1a9f1c 100644
--- a/engines/alcachofa/rooms.cpp
+++ b/engines/alcachofa/rooms.cpp
@@ -272,20 +272,8 @@ void Room::updateInteraction() {
void Room::updateRoomBounds() {
auto graphic = _backgroundObject == nullptr ? nullptr : _backgroundObject->graphic();
- if (graphic != nullptr) {
- auto bgSize = graphic->animation().imageSize(0);
- if (g_engine->isV1()) {
- g_engine->camera().setRoomBounds(graphic->topLeft(), bgSize);
- } else {
- /* The fallback fixes a bug where if the background image is invalid the original engine
- * would not update the background size. This would be around 1024,768 due to
- * previous rooms in the bug instances I found.
- */
- if (bgSize == Point(0, 0))
- bgSize = Point(1024, 768);
- g_engine->camera().setRoomBounds(bgSize, graphic->scale());
- }
- }
+ if (graphic != nullptr)
+ g_engine->camera().setRoomBounds(*graphic);
}
void Room::updateObjects() {
@@ -533,13 +521,13 @@ void Inventory::drawAsOverlay(int32 scrollY) {
}
void Inventory::open() {
- g_engine->camera().backup(1);
+ g_engine->camera().onOpenMenu();
g_engine->player().changeRoom(name(), true);
updateItemsByActiveCharacter();
}
void Inventory::close() {
- g_engine->camera().restore(1);
+ g_engine->camera().onCloseMenu();
g_engine->globalUI().startClosingInventory();
}
diff --git a/engines/alcachofa/script.cpp b/engines/alcachofa/script.cpp
index 99dfe140878..578ea0f23cb 100644
--- a/engines/alcachofa/script.cpp
+++ b/engines/alcachofa/script.cpp
@@ -702,16 +702,12 @@ private:
// player/world state changes
case ScriptKernelTask::ChangeCharacter: {
MainCharacterKind kind = getMainCharacterKindArg(0);
- auto &camera = g_engine->camera();
auto &player = g_engine->player();
- camera.resetRotationAndScale();
- camera.backup(0);
if (kind != MainCharacterKind::None) {
player.setActiveCharacter(kind);
player.heldItem() = nullptr;
- camera.setFollow(player.activeCharacter());
- camera.backup(0);
}
+ g_engine->camera().onScriptChangedCharacter(kind);
if (g_engine->game().shouldChangeCharacterUseGameLock()) {
killProcessesFor(MainCharacterKind::None); // yes, kill for all characters
Commit: 1cbaff76f400e24b12ef6b5482119df8b2c3c509
https://github.com/scummvm/scummvm/commit/1cbaff76f400e24b12ef6b5482119df8b2c3c509
Author: Helco (hermann.noll at hotmail.com)
Date: 2026-02-08T19:01:39+01:00
Commit Message:
ALCACHOFA: Split Camera into base class and V3
Changed paths:
engines/alcachofa/alcachofa.cpp
engines/alcachofa/alcachofa.h
engines/alcachofa/camera.cpp
engines/alcachofa/camera.h
engines/alcachofa/script.cpp
diff --git a/engines/alcachofa/alcachofa.cpp b/engines/alcachofa/alcachofa.cpp
index 2206e8ad439..a921d76c421 100644
--- a/engines/alcachofa/alcachofa.cpp
+++ b/engines/alcachofa/alcachofa.cpp
@@ -84,6 +84,7 @@ Common::Error AlcachofaEngine::run() {
_world.load();
_renderer.reset(IRenderer::createOpenGLRenderer(game().getResolution()));
_drawQueue.reset(new DrawQueue(_renderer.get()));
+ _camera.reset(new CameraV3());
_script.reset(new Script());
_player.reset(new Player());
_globalUI.reset(isV1() ? static_cast<GlobalUI *>(new GlobalUIV1()) : new GlobalUIV3());
@@ -113,7 +114,7 @@ Common::Error AlcachofaEngine::run() {
_sounds.update();
_renderer->begin();
_drawQueue->clear();
- _camera.preUpdate();
+ _camera->preUpdate();
_player->preUpdate();
if (_player->currentRoom() != nullptr)
_player->currentRoom()->update();
diff --git a/engines/alcachofa/alcachofa.h b/engines/alcachofa/alcachofa.h
index 45b2ca5b27f..a75acdf8673 100644
--- a/engines/alcachofa/alcachofa.h
+++ b/engines/alcachofa/alcachofa.h
@@ -119,7 +119,7 @@ public:
inline const AlcachofaGameDescription &gameDescription() const { return *_gameDescription; }
inline IRenderer &renderer() { return *_renderer; }
inline DrawQueue &drawQueue() { return *_drawQueue; }
- inline Camera &camera() { return _camera; }
+ inline Camera &camera() { return *_camera; }
inline Input &input() { return _input; }
inline Sounds &sounds() { return _sounds; }
inline Player &player() { return *_player; }
@@ -133,6 +133,12 @@ public:
inline Config &config() { return _config; }
inline bool isDebugModeActive() const { return _debugHandler != nullptr; }
+ inline CameraV3 &cameraV3() {
+ auto result = dynamic_cast<CameraV3 *>(_camera.get());
+ scumm_assert(result != nullptr);
+ return *result;
+ }
+
uint32 getMillis() const;
void setMillis(uint32 newMillis);
void pauseEngineIntern(bool pause) override;
@@ -183,8 +189,8 @@ private:
Common::ScopedPtr<GlobalUI> _globalUI;
Common::ScopedPtr<Menu> _menu;
Common::ScopedPtr<Game> _game;
+ Common::ScopedPtr<Camera> _camera;
World _world;
- Camera _camera;
Input _input;
Sounds _sounds;
Scheduler _scheduler;
diff --git a/engines/alcachofa/camera.cpp b/engines/alcachofa/camera.cpp
index da2e5831f31..46db22db5ba 100644
--- a/engines/alcachofa/camera.cpp
+++ b/engines/alcachofa/camera.cpp
@@ -31,11 +31,110 @@ using namespace Math;
namespace Alcachofa {
-void Camera::preUpdate() {
+//
+// Base camera
+//
+Camera::~Camera() {}
+
+static Matrix4 scale2DMatrix(float scale) {
+ Matrix4 m;
+ m(0, 0) = scale;
+ m(1, 1) = scale;
+ return m;
+}
+
+void Camera::setupMatricesAround(Vector3d center) {
+ Matrix4 matTemp;
+ matTemp.buildAroundZ(rotation());
+ _mat3Dto2D.setToIdentity();
+ _mat3Dto2D.translate(-center);
+ _mat3Dto2D = matTemp * _mat3Dto2D;
+ _mat3Dto2D = scale2DMatrix(scale()) * _mat3Dto2D;
+
+ _mat2Dto3D.setToIdentity();
+ _mat2Dto3D.translate(center);
+ matTemp.buildAroundZ(-rotation());
+ matTemp = matTemp * scale2DMatrix(1 / scale());
+ _mat2Dto3D = _mat2Dto3D * matTemp;
+}
+
+void minmax(Vector3d &min, Vector3d &max, Vector3d val) {
+ min.set(
+ MIN(min.x(), val.x()),
+ MIN(min.y(), val.y()),
+ MIN(min.z(), val.z()));
+ max.set(
+ MAX(max.x(), val.x()),
+ MAX(max.y(), val.y()),
+ MAX(max.z(), val.z()));
+}
+
+Vector3d Camera::setAppliedCenter(Vector3d center) {
+ setupMatricesAround(center);
+ if (g_engine->game().shouldClipCamera()) {
+ const float screenW = g_system->getWidth(), screenH = g_system->getHeight();
+ Vector3d min, max;
+ min = max = transform2Dto3D(Vector3d(0, 0, _roomScale));
+ minmax(min, max, transform2Dto3D(Vector3d(screenW, 0, _roomScale)));
+ minmax(min, max, transform2Dto3D(Vector3d(screenW, screenH, _roomScale)));
+ minmax(min, max, transform2Dto3D(Vector3d(0, screenH, _roomScale)));
+ center.x() += MAX(0.0f, _roomMin.getX() - min.x());
+ center.y() += MAX(0.0f, _roomMin.getY() - min.y());
+ center.x() -= MAX(0.0f, max.x() - _roomMax.getX());
+ center.y() -= MAX(0.0f, max.y() - _roomMax.getY());
+ setupMatricesAround(center);
+ }
+ return _appliedCenter = center;
+}
+
+Vector3d Camera::transform2Dto3D(Vector3d v2d) const {
+ // if this looks like normal 3D math to *someone* please contact.
+ Vector4d vh;
+ vh.w() = 1.0f;
+ vh.z() = v2d.z() - _appliedCenter.z();
+ vh.y() = (v2d.y() - g_system->getHeight() * 0.5f) * vh.z() * kInvBaseScale;
+ vh.x() = (v2d.x() - g_system->getWidth() * 0.5f) * vh.z() * kInvBaseScale;
+ vh = _mat2Dto3D * vh;
+ return Vector3d(vh.x(), vh.y(), 0.0f);
+}
+
+Vector3d Camera::transform3Dto2D(Vector3d v3d) const {
+ // I swear there is a better way than this. This is stupid. But it is original.
+ float depthScale = v3d.z() * kInvBaseScale;
+ Vector4d vh;
+ vh.x() = v3d.x() * depthScale + (1 - depthScale) * g_system->getWidth() * 0.5f;
+ vh.y() = v3d.y() * depthScale + (1 - depthScale) * g_system->getHeight() * 0.5f;
+ vh.z() = v3d.z();
+ vh.w() = 1.0f;
+ vh = _mat3Dto2D * vh;
+ return Vector3d(
+ g_system->getWidth() * 0.5f + vh.x() * kBaseScale / vh.z(),
+ g_system->getHeight() * 0.5f + vh.y() * kBaseScale / vh.z(),
+ scale() * kBaseScale / vh.z());
+}
+
+Point Camera::transform3Dto2D(Point p3d) const {
+ auto v2d = transform3Dto2D({ (float)p3d.x, (float)p3d.y, kBaseScale });
+ return { (int16)v2d.x(), (int16)v2d.y() };
+}
+
+//
+// CameraV3
+//
+
+Angle CameraV3::rotation() const {
+ return _cur._rotation;
+}
+
+float CameraV3::scale() const {
+ return _cur._scale;
+}
+
+void CameraV3::preUpdate() {
_shake = {};
}
-void Camera::setRoomBounds(Graphic &background) {
+void CameraV3::setRoomBounds(Graphic &background) {
auto bgSize = background.animation().imageSize(0);
if (g_engine->isV1()) {
Point screenSize(g_system->getWidth(), g_system->getHeight());
@@ -62,7 +161,7 @@ void Camera::setRoomBounds(Graphic &background) {
}
}
-void Camera::setFollow(WalkingCharacter *target, bool catchUp) {
+void CameraV3::setFollow(WalkingCharacter *target, bool catchUp) {
_cur._isFollowingTarget = target != nullptr;
_followTarget = target;
_lastUpdateTime = g_engine->getMillis();
@@ -71,153 +170,71 @@ void Camera::setFollow(WalkingCharacter *target, bool catchUp) {
_isChanging = false;
}
-void Camera::onChangedRoom(bool resetCamera) {
+void CameraV3::onChangedRoom(bool resetCamera) {
if (resetCamera)
resetRotationAndScale();
if (_followTarget != nullptr)
setFollow(_followTarget, true);
}
-void Camera::onTriggeredDoor(WalkingCharacter *target) {
+void CameraV3::onTriggeredDoor(WalkingCharacter *target) {
setFollow(target, true);
}
-void Camera::onTriggeredDoor(Point fixedPosition) {
+void CameraV3::onTriggeredDoor(Point fixedPosition) {
setPosition(as2D(fixedPosition));
}
-void Camera::onScriptChangedCharacter(MainCharacterKind kind) {
+void CameraV3::onScriptChangedCharacter(MainCharacterKind kind) {
resetRotationAndScale();
if (kind != MainCharacterKind::None)
setFollow(g_engine->player().activeCharacter());
backup(0);
}
-void Camera::onUserChangedCharacter() {
+void CameraV3::onUserChangedCharacter() {
setFollow(g_engine->player().activeCharacter());
restore(0);
}
-void Camera::onOpenMenu() {
+void CameraV3::onOpenMenu() {
backup(1);
setPosition(Math::Vector3d(
g_system->getWidth() / 2.0f, g_system->getHeight() / 2.0f, 0.0f));
}
-void Camera::onCloseMenu() {
+void CameraV3::onCloseMenu() {
restore(1);
}
-void Camera::resetRotationAndScale() {
+void CameraV3::resetRotationAndScale() {
_cur._scale = 1;
_cur._rotation = 0;
_cur._usedCenter.z() = 0;
}
-void Camera::setPosition(Vector2d v) {
+void CameraV3::setPosition(Vector2d v) {
setPosition({ v.getX(), v.getY(), _cur._usedCenter.z() });
}
-void Camera::setPosition(Vector3d v) {
+void CameraV3::setPosition(Vector3d v) {
_cur._usedCenter = v;
setFollow(nullptr);
}
-void Camera::backup(uint slot) {
+void CameraV3::backup(uint slot) {
assert(slot < kStateBackupCount);
_backups[slot] = _cur;
}
-void Camera::restore(uint slot) {
+void CameraV3::restore(uint slot) {
assert(slot < kStateBackupCount);
auto backupState = _backups[slot];
_backups[slot] = _cur;
_cur = backupState;
}
-static Matrix4 scale2DMatrix(float scale) {
- Matrix4 m;
- m(0, 0) = scale;
- m(1, 1) = scale;
- return m;
-}
-
-void Camera::setupMatricesAround(Vector3d center) {
- Matrix4 matTemp;
- matTemp.buildAroundZ(_cur._rotation);
- _mat3Dto2D.setToIdentity();
- _mat3Dto2D.translate(-center);
- _mat3Dto2D = matTemp * _mat3Dto2D;
- _mat3Dto2D = scale2DMatrix(_cur._scale) * _mat3Dto2D;
-
- _mat2Dto3D.setToIdentity();
- _mat2Dto3D.translate(center);
- matTemp.buildAroundZ(-_cur._rotation);
- matTemp = matTemp * scale2DMatrix(1 / _cur._scale);
- _mat2Dto3D = _mat2Dto3D * matTemp;
-}
-
-void minmax(Vector3d &min, Vector3d &max, Vector3d val) {
- min.set(
- MIN(min.x(), val.x()),
- MIN(min.y(), val.y()),
- MIN(min.z(), val.z()));
- max.set(
- MAX(max.x(), val.x()),
- MAX(max.y(), val.y()),
- MAX(max.z(), val.z()));
-}
-
-Vector3d Camera::setAppliedCenter(Vector3d center) {
- setupMatricesAround(center);
- if (g_engine->game().shouldClipCamera()) {
- const float screenW = g_system->getWidth(), screenH = g_system->getHeight();
- Vector3d min, max;
- min = max = transform2Dto3D(Vector3d(0, 0, _roomScale));
- minmax(min, max, transform2Dto3D(Vector3d(screenW, 0, _roomScale)));
- minmax(min, max, transform2Dto3D(Vector3d(screenW, screenH, _roomScale)));
- minmax(min, max, transform2Dto3D(Vector3d(0, screenH, _roomScale)));
- center.x() += MAX(0.0f, _roomMin.getX() - min.x());
- center.y() += MAX(0.0f, _roomMin.getY() - min.y());
- center.x() -= MAX(0.0f, max.x() - _roomMax.getX());
- center.y() -= MAX(0.0f, max.y() - _roomMax.getY());
- setupMatricesAround(center);
- }
- return _appliedCenter = center;
-}
-
-Vector3d Camera::transform2Dto3D(Vector3d v2d) const {
- // if this looks like normal 3D math to *someone* please contact.
- Vector4d vh;
- vh.w() = 1.0f;
- vh.z() = v2d.z() - _cur._usedCenter.z();
- vh.y() = (v2d.y() - g_system->getHeight() * 0.5f) * vh.z() * kInvBaseScale;
- vh.x() = (v2d.x() - g_system->getWidth() * 0.5f) * vh.z() * kInvBaseScale;
- vh = _mat2Dto3D * vh;
- return Vector3d(vh.x(), vh.y(), 0.0f);
-}
-
-Vector3d Camera::transform3Dto2D(Vector3d v3d) const {
- // I swear there is a better way than this. This is stupid. But it is original.
- float depthScale = v3d.z() * kInvBaseScale;
- Vector4d vh;
- vh.x() = v3d.x() * depthScale + (1 - depthScale) * g_system->getWidth() * 0.5f;
- vh.y() = v3d.y() * depthScale + (1 - depthScale) * g_system->getHeight() * 0.5f;
- vh.z() = v3d.z();
- vh.w() = 1.0f;
- vh = _mat3Dto2D * vh;
- return Vector3d(
- g_system->getWidth() * 0.5f + vh.x() * kBaseScale / vh.z(),
- g_system->getHeight() * 0.5f + vh.y() * kBaseScale / vh.z(),
- _cur._scale * kBaseScale / vh.z());
-}
-
-Point Camera::transform3Dto2D(Point p3d) const {
- auto v2d = transform3Dto2D({ (float)p3d.x, (float)p3d.y, kBaseScale });
- return { (int16)v2d.x(), (int16)v2d.y() };
-}
-
-void Camera::update() {
+void CameraV3::update() {
// original would be some smoothing of delta times, let's not.
uint32 now = g_engine->getMillis();
float deltaTime = (now - _lastUpdateTime) / 1000.0f;
@@ -233,7 +250,7 @@ void Camera::update() {
setAppliedCenter(_cur._usedCenter + Vector3d(_shake.getX(), _shake.getY(), 0.0f));
}
-void Camera::updateFollowing(float deltaTime) {
+void CameraV3::updateFollowing(float deltaTime) {
if (!_cur._isFollowingTarget || _followTarget == nullptr)
return;
const float resolutionFactor = g_system->getWidth() * 0.00125f;
@@ -299,7 +316,7 @@ static void syncVector(Serializer &s, Vector3d &v) {
s.syncAsFloatLE(v.z());
}
-void Camera::State::syncGame(Serializer &s) {
+void CameraV3::State::syncGame(Serializer &s) {
syncVector(s, _usedCenter);
s.syncAsFloatLE(_scale);
s.syncAsFloatLE(_speed);
@@ -311,7 +328,7 @@ void Camera::State::syncGame(Serializer &s) {
s.syncAsByte(_isFollowingTarget);
}
-void Camera::syncGame(Serializer &s) {
+void CameraV3::syncGame(Serializer &s) {
syncMatrix(s, _mat3Dto2D);
syncMatrix(s, _mat2Dto3D);
syncVector(s, _appliedCenter);
@@ -344,7 +361,7 @@ void Camera::syncGame(Serializer &s) {
struct CamLerpTask : public Task {
CamLerpTask(Process &process, uint32 duration = 0, EasingType easingType = EasingType::Linear)
: Task(process)
- , _camera(g_engine->camera())
+ , _camera(g_engine->cameraV3())
, _duration(duration)
, _easingType(easingType) {}
@@ -377,7 +394,7 @@ struct CamLerpTask : public Task {
protected:
virtual void update(float t) = 0;
- Camera &_camera;
+ CameraV3 &_camera;
uint32 _startTime = 0, _duration;
EasingType _easingType;
};
@@ -550,11 +567,11 @@ DECLARE_TASK(CamShakeTask)
struct CamWaitToStopTask final : public Task {
CamWaitToStopTask(Process &process)
: Task(process)
- , _camera(g_engine->camera()) {}
+ , _camera(g_engine->cameraV3()) {}
CamWaitToStopTask(Process &process, Serializer &s)
: Task(process)
- , _camera(g_engine->camera()) {
+ , _camera(g_engine->cameraV3()) {
syncGame(s);
}
@@ -571,7 +588,7 @@ struct CamWaitToStopTask final : public Task {
const char *taskName() const override;
private:
- Camera &_camera;
+ CameraV3 &_camera;
};
DECLARE_TASK(CamWaitToStopTask)
@@ -584,14 +601,14 @@ struct CamSetInactiveAttributeTask final : public Task {
CamSetInactiveAttributeTask(Process &process, Attribute attribute, float value, int32 delay)
: Task(process)
- , _camera(g_engine->camera())
+ , _camera(g_engine->cameraV3())
, _attribute(attribute)
, _value(value)
, _delay(delay) {}
CamSetInactiveAttributeTask(Process &process, Serializer &s)
: Task(process)
- , _camera(g_engine->camera()) {
+ , _camera(g_engine->cameraV3()) {
syncGame(s);
}
@@ -649,14 +666,14 @@ struct CamSetInactiveAttributeTask final : public Task {
const char *taskName() const override;
private:
- Camera &_camera;
+ CameraV3 &_camera;
Attribute _attribute = {};
float _value = 0;
int32 _delay = 0;
};
DECLARE_TASK(CamSetInactiveAttributeTask)
-Task *Camera::lerpPos(Process &process,
+Task *CameraV3::lerpPos(Process &process,
Vector2d targetPos,
int32 duration, EasingType easingType) {
if (!process.isActiveForPlayer()) {
@@ -666,7 +683,7 @@ Task *Camera::lerpPos(Process &process,
return new CamLerpPosTask(process, targetPos3d, duration, easingType);
}
-Task *Camera::lerpPos(Process &process,
+Task *CameraV3::lerpPos(Process &process,
Vector3d targetPos,
int32 duration, EasingType easingType) {
if (!process.isActiveForPlayer()) {
@@ -676,7 +693,7 @@ Task *Camera::lerpPos(Process &process,
return new CamLerpPosTask(process, targetPos, duration, easingType);
}
-Task *Camera::lerpPosZ(Process &process,
+Task *CameraV3::lerpPosZ(Process &process,
float targetPosZ,
int32 duration, EasingType easingType) {
if (!process.isActiveForPlayer()) {
@@ -686,7 +703,7 @@ Task *Camera::lerpPosZ(Process &process,
return new CamLerpPosTask(process, targetPos, duration, easingType);
}
-Task *Camera::lerpScale(Process &process,
+Task *CameraV3::lerpScale(Process &process,
float targetScale,
int32 duration, EasingType easingType) {
if (!process.isActiveForPlayer()) {
@@ -695,7 +712,7 @@ Task *Camera::lerpScale(Process &process,
return new CamLerpScaleTask(process, targetScale, duration, easingType);
}
-Task *Camera::lerpRotation(Process &process,
+Task *CameraV3::lerpRotation(Process &process,
float targetRotation,
int32 duration, EasingType easingType) {
if (!process.isActiveForPlayer()) {
@@ -704,7 +721,7 @@ Task *Camera::lerpRotation(Process &process,
return new CamLerpRotationTask(process, targetRotation, duration, easingType);
}
-Task *Camera::lerpPosScale(Process &process,
+Task *CameraV3::lerpPosScale(Process &process,
Vector3d targetPos, float targetScale,
int32 duration,
EasingType moveEasingType, EasingType scaleEasingType) {
@@ -714,11 +731,11 @@ Task *Camera::lerpPosScale(Process &process,
return new CamLerpPosScaleTask(process, targetPos, targetScale, duration, moveEasingType, scaleEasingType);
}
-Task *Camera::waitToStop(Process &process) {
+Task *CameraV3::waitToStop(Process &process) {
return new CamWaitToStopTask(process);
}
-Task *Camera::shake(Process &process, Math::Vector2d amplitude, Math::Vector2d frequency, int32 duration) {
+Task *CameraV3::shake(Process &process, Math::Vector2d amplitude, Math::Vector2d frequency, int32 duration) {
if (!process.isActiveForPlayer()) {
return new DelayTask(process, (uint32)duration);
}
@@ -731,12 +748,12 @@ Task *Camera::shake(Process &process, Math::Vector2d amplitude, Math::Vector2d f
struct CamDisguiseTask final : public Task {
CamDisguiseTask(Process &process, int32 durationMs)
: Task(process)
- , _camera(g_engine->camera())
+ , _camera(g_engine->cameraV3())
, _durationMs(durationMs) {}
CamDisguiseTask(Process &process, Serializer &s)
: Task(process)
- , _camera(g_engine->camera()) {
+ , _camera(g_engine->cameraV3()) {
CamDisguiseTask::syncGame(s);
}
@@ -776,14 +793,14 @@ struct CamDisguiseTask final : public Task {
const char *taskName() const override;
private:
- Camera &_camera;
+ CameraV3 &_camera;
int32 _durationMs = 0;
uint32 _startTime = 0;
Vector2d _startPosition;
};
DECLARE_TASK(CamDisguiseTask)
-Task *Camera::disguise(Process &process, int32 duration) {
+Task *CameraV3::disguise(Process &process, int32 duration) {
return new CamDisguiseTask(process, duration);
}
diff --git a/engines/alcachofa/camera.h b/engines/alcachofa/camera.h
index e7424587f51..296d98d4db0 100644
--- a/engines/alcachofa/camera.h
+++ b/engines/alcachofa/camera.h
@@ -37,25 +37,59 @@ static constexpr const float kInvBaseScale = 1.0f / kBaseScale;
class Camera {
public:
- inline Math::Angle rotation() const { return _cur._rotation; }
-
- void preUpdate();
- void update();
- void setRoomBounds(Graphic &background);
- void setFollow(WalkingCharacter *target, bool catchUp = false);
- void onChangedRoom(bool resetCamera);
- void onTriggeredDoor(WalkingCharacter *target);
- void onTriggeredDoor(Common::Point fixedPosition);
- void onScriptChangedCharacter(MainCharacterKind kind);
- void onUserChangedCharacter();
- void onOpenMenu();
- void onCloseMenu();
- void syncGame(Common::Serializer &s);
+ virtual ~Camera();
+ virtual Math::Angle rotation() const = 0;
+ virtual float scale() const = 0;
+
+ virtual void preUpdate() = 0;
+ virtual void update() = 0;
+ virtual void setRoomBounds(Graphic &background) = 0;
+ virtual void setFollow(WalkingCharacter *target, bool catchUp = false) = 0;
+ virtual void onChangedRoom(bool resetCamera) = 0;
+ virtual void onTriggeredDoor(WalkingCharacter *target) = 0;
+ virtual void onTriggeredDoor(Common::Point fixedPosition) = 0;
+ virtual void onScriptChangedCharacter(MainCharacterKind kind) = 0;
+ virtual void onUserChangedCharacter() = 0;
+ virtual void onOpenMenu() = 0;
+ virtual void onCloseMenu() = 0;
+ virtual void syncGame(Common::Serializer &s) = 0;
Math::Vector3d transform2Dto3D(Math::Vector3d v) const;
Math::Vector3d transform3Dto2D(Math::Vector3d v) const;
Common::Point transform3Dto2D(Common::Point p) const;
+protected:
+ Math::Vector3d setAppliedCenter(Math::Vector3d center);
+ void setupMatricesAround(Math::Vector3d center);
+
+ float _roomScale = 1.0f;
+ Math::Vector2d
+ _roomMin = Math::Vector2d(-10000, -10000),
+ _roomMax = Math::Vector2d(10000, 10000);
+ Math::Vector3d _appliedCenter;
+ Math::Matrix4
+ _mat3Dto2D,
+ _mat2Dto3D;
+};
+
+class CameraV3 : public Camera {
+public:
+ Math::Angle rotation() const override;
+ float scale() const override;
+
+ void preUpdate() override;
+ void update() override;
+ void setRoomBounds(Graphic &background) override;
+ void setFollow(WalkingCharacter *target, bool catchUp = false) override;
+ void onChangedRoom(bool resetCamera) override;
+ void onTriggeredDoor(WalkingCharacter *target) override;
+ void onTriggeredDoor(Common::Point fixedPosition) override;
+ void onScriptChangedCharacter(MainCharacterKind kind) override;
+ void onUserChangedCharacter() override;
+ void onOpenMenu() override;
+ void onCloseMenu() override;
+ void syncGame(Common::Serializer &s) override;
+
Task *lerpPos(Process &process,
Math::Vector2d targetPos,
int32 duration, EasingType easingType);
@@ -94,8 +128,6 @@ private:
friend struct CamWaitToStopTask;
friend struct CamSetInactiveAttributeTask;
friend struct CamDisguiseTask;
- Math::Vector3d setAppliedCenter(Math::Vector3d center);
- void setupMatricesAround(Math::Vector3d center);
void updateFollowing(float deltaTime);
struct State {
@@ -117,15 +149,7 @@ private:
uint32 _lastUpdateTime = 0;
bool _isChanging = false,
_catchUp = false;
- float _roomScale = 1.0f;
- Math::Vector2d
- _roomMin = Math::Vector2d(-10000, -10000),
- _roomMax = Math::Vector2d(10000, 10000),
- _shake;
- Math::Vector3d _appliedCenter;
- Math::Matrix4
- _mat3Dto2D,
- _mat2Dto3D;
+ Math::Vector2d _shake;
};
}
diff --git a/engines/alcachofa/script.cpp b/engines/alcachofa/script.cpp
index 578ea0f23cb..6da4d7e23d6 100644
--- a/engines/alcachofa/script.cpp
+++ b/engines/alcachofa/script.cpp
@@ -932,7 +932,7 @@ private:
// Camera tasks
case ScriptKernelTask::WaitCamStopping:
- return TaskReturn::waitFor(g_engine->camera().waitToStop(process()));
+ return TaskReturn::waitFor(g_engine->cameraV3().waitToStop(process()));
case ScriptKernelTask::CamFollow: {
WalkingCharacter *target = nullptr;
auto kind = getMainCharacterKindArg(0);
@@ -942,28 +942,28 @@ private:
return TaskReturn::finish(1);
}
case ScriptKernelTask::CamShake:
- return TaskReturn::waitFor(g_engine->camera().shake(process(),
+ return TaskReturn::waitFor(g_engine->cameraV3().shake(process(),
Vector2d(getNumberArg(1), getNumberArg(2)),
Vector2d(getNumberArg(3), getNumberArg(4)),
getNumberArg(0)));
case ScriptKernelTask::LerpCamXY:
- return TaskReturn::waitFor(g_engine->camera().lerpPos(process(),
+ return TaskReturn::waitFor(g_engine->cameraV3().lerpPos(process(),
Vector2d(getNumberArg(0), getNumberArg(1)),
getNumberArg(2), (EasingType)getNumberArg(3)));
case ScriptKernelTask::LerpCamXYZ:
- return TaskReturn::waitFor(g_engine->camera().lerpPos(process(),
+ return TaskReturn::waitFor(g_engine->cameraV3().lerpPos(process(),
Vector3d(getNumberArg(0), getNumberArg(1), getNumberArg(2)),
getNumberArg(3), (EasingType)getNumberArg(4)));
case ScriptKernelTask::LerpCamZ:
- return TaskReturn::waitFor(g_engine->camera().lerpPosZ(process(),
+ return TaskReturn::waitFor(g_engine->cameraV3().lerpPosZ(process(),
getNumberArg(0),
getNumberArg(1), (EasingType)getNumberArg(2)));
case ScriptKernelTask::LerpCamScale:
- return TaskReturn::waitFor(g_engine->camera().lerpScale(process(),
+ return TaskReturn::waitFor(g_engine->cameraV3().lerpScale(process(),
getNumberArg(0) * 0.01f,
getNumberArg(1), (EasingType)getNumberArg(2)));
case ScriptKernelTask::LerpCamRotation:
- return TaskReturn::waitFor(g_engine->camera().lerpRotation(process(),
+ return TaskReturn::waitFor(g_engine->cameraV3().lerpRotation(process(),
getNumberArg(0),
getNumberArg(1), (EasingType)getNumberArg(2)));
case ScriptKernelTask::LerpCamToObjectKeepingZ: {
@@ -974,7 +974,7 @@ private:
pointObject = g_engine->game().unknownCamLerpTarget("LerpCamToObjectKeepingZ", getStringArg(0));
if (pointObject == nullptr)
return TaskReturn::finish(1);
- return TaskReturn::waitFor(g_engine->camera().lerpPos(process(),
+ return TaskReturn::waitFor(g_engine->cameraV3().lerpPos(process(),
as2D(pointObject->position()),
getNumberArg(1), EasingType::Linear));
}
@@ -986,7 +986,7 @@ private:
pointObject = g_engine->game().unknownCamLerpTarget("LerpCamToObjectResettingZ", getStringArg(0));
if (pointObject == nullptr)
return TaskReturn::finish(1);
- return TaskReturn::waitFor(g_engine->camera().lerpPos(process(),
+ return TaskReturn::waitFor(g_engine->cameraV3().lerpPos(process(),
as3D(pointObject->position()),
getNumberArg(1), (EasingType)getNumberArg(2)));
}
@@ -994,13 +994,13 @@ private:
float targetScale = getNumberArg(1) * 0.01f;
if (!process().isActiveForPlayer())
// the scale will wait then snap the scale
- return TaskReturn::waitFor(g_engine->camera().lerpScale(process(), targetScale, getNumberArg(2), EasingType::Linear));
+ return TaskReturn::waitFor(g_engine->cameraV3().lerpScale(process(), targetScale, getNumberArg(2), EasingType::Linear));
auto pointObject = getObjectArg<PointObject>(0);
if (pointObject == nullptr)
pointObject = g_engine->game().unknownCamLerpTarget("LerpCamToObjectWithScale", getStringArg(0));
if (pointObject == nullptr)
return TaskReturn::finish(1);
- return TaskReturn::waitFor(g_engine->camera().lerpPosScale(process(),
+ return TaskReturn::waitFor(g_engine->cameraV3().lerpPosScale(process(),
as3D(pointObject->position()), targetScale,
getNumberArg(2), (EasingType)getNumberArg(3), (EasingType)getNumberArg(4)));
}
@@ -1010,7 +1010,7 @@ private:
const auto duration = getNumberArg(0);
return TaskReturn::waitFor(duration == 0
? g_engine->input().waitForInput(process())
- : g_engine->camera().disguise(process(), duration));
+ : g_engine->cameraV3().disguise(process(), duration));
}
// Fades
Commit: 8ade46170b80548687a7f834c1514fdd219f4ee5
https://github.com/scummvm/scummvm/commit/8ade46170b80548687a7f834c1514fdd219f4ee5
Author: Helco (hermann.noll at hotmail.com)
Date: 2026-02-08T19:01:39+01:00
Commit Message:
ALCACHOFA: TERROR: Fix outro
Changed paths:
engines/alcachofa/game-movie-adventure-original.cpp
diff --git a/engines/alcachofa/game-movie-adventure-original.cpp b/engines/alcachofa/game-movie-adventure-original.cpp
index d6904937a45..af0a23c11e3 100644
--- a/engines/alcachofa/game-movie-adventure-original.cpp
+++ b/engines/alcachofa/game-movie-adventure-original.cpp
@@ -88,7 +88,7 @@ static constexpr const ScriptKernelTask kScriptKernelTaskMap[] = {
ScriptKernelTask::Animate,
ScriptKernelTask::HadNoMousePressFor,
ScriptKernelTask::ChangeCharacter,
- ScriptKernelTask::LerpCamToObjectKeepingZ,
+ ScriptKernelTask::LerpOrSetCam,
ScriptKernelTask::Drop,
ScriptKernelTask::ChangeDoor,
ScriptKernelTask::Disguise,
@@ -327,12 +327,17 @@ public:
return nullptr;
}
- // an original bug, Pos_Final_Morta/File is defined in room ENTRADA_PUEBLO
+ // an original bug, Pos_Final_Morta/File is defined in room ENTRADA_PUEBLO or PANTANO_EXT
// but the current room is ENTRADA_PUEBLO_INTRO
- if (!scumm_stricmp(name, "Pos_Final_Morta"))
- return getPointFromRoom("ENTRADA_PUEBLO", "Pos_Final_Morta", action);
- if (!scumm_stricmp(name, "Pos_Final_File"))
- return getPointFromRoom("ENTRADA_PUEBLO", "Pos_Final_File", action);
+ if (!scumm_stricmp(name, "Pos_Final_Morta") || !scumm_stricmp(name, "Pos_Final_File")) {
+ // for terror there is no ENTRADA_PUEBLO either, nor Pos_Final_*
+ if (g_engine->world().getRoomByName("ENTRADA_PUEBLO") == nullptr) {
+ return !scumm_stricmp(name, "Pos_Final_Morta")
+ ? getPointFromRoom("PANTANO_EXT", "PANTANO_MORTA", action)
+ : getPointFromRoom("PANTANO_EXT", "PANTANO_FILE", action);
+ } else
+ return getPointFromRoom("ENTRADA_PUEBLO", name, action);
+ }
return Game::unknownGoPutTarget(process, action, name);
}
@@ -346,7 +351,11 @@ public:
}
void missingSound(const Common::String &fileName) override {
- if (fileName == "CHAS" || fileName == "0563" || fileName == "M2137")
+ if (fileName == "CHAS" ||
+ fileName == "0563" ||
+ fileName == "M2137" ||
+ fileName == "1413" || // are stored in OESTE.EMC but played during terror outro
+ fileName == "M1414")
return;
return Game::missingSound(fileName);
}
Commit: 461eeec147ba2265a1eb8874817d88a721a32759
https://github.com/scummvm/scummvm/commit/461eeec147ba2265a1eb8874817d88a721a32759
Author: Helco (hermann.noll at hotmail.com)
Date: 2026-02-08T19:01:39+01:00
Commit Message:
ALCACHOFA: Add CameraV1
Changed paths:
engines/alcachofa/alcachofa.cpp
engines/alcachofa/alcachofa.h
engines/alcachofa/camera.cpp
engines/alcachofa/camera.h
engines/alcachofa/game-objects.cpp
engines/alcachofa/global-ui.cpp
engines/alcachofa/rooms.cpp
engines/alcachofa/script.cpp
engines/alcachofa/script.h
engines/alcachofa/tasks.h
diff --git a/engines/alcachofa/alcachofa.cpp b/engines/alcachofa/alcachofa.cpp
index a921d76c421..c36a0da111c 100644
--- a/engines/alcachofa/alcachofa.cpp
+++ b/engines/alcachofa/alcachofa.cpp
@@ -84,7 +84,7 @@ Common::Error AlcachofaEngine::run() {
_world.load();
_renderer.reset(IRenderer::createOpenGLRenderer(game().getResolution()));
_drawQueue.reset(new DrawQueue(_renderer.get()));
- _camera.reset(new CameraV3());
+ _camera.reset(isV1() ? static_cast<Camera *>(new CameraV1()) : new CameraV3());
_script.reset(new Script());
_player.reset(new Player());
_globalUI.reset(isV1() ? static_cast<GlobalUI *>(new GlobalUIV1()) : new GlobalUIV3());
diff --git a/engines/alcachofa/alcachofa.h b/engines/alcachofa/alcachofa.h
index a75acdf8673..0cc423bc455 100644
--- a/engines/alcachofa/alcachofa.h
+++ b/engines/alcachofa/alcachofa.h
@@ -133,11 +133,13 @@ public:
inline Config &config() { return _config; }
inline bool isDebugModeActive() const { return _debugHandler != nullptr; }
- inline CameraV3 &cameraV3() {
- auto result = dynamic_cast<CameraV3 *>(_camera.get());
+ template<class T> inline T &cameraAs() {
+ auto result = dynamic_cast<T *>(_camera.get());
scumm_assert(result != nullptr);
return *result;
}
+ inline CameraV1 &cameraV1() { return cameraAs<CameraV1>(); }
+ inline CameraV3 &cameraV3() { return cameraAs<CameraV3>(); }
uint32 getMillis() const;
void setMillis(uint32 newMillis);
diff --git a/engines/alcachofa/camera.cpp b/engines/alcachofa/camera.cpp
index 46db22db5ba..3bf2a86d285 100644
--- a/engines/alcachofa/camera.cpp
+++ b/engines/alcachofa/camera.cpp
@@ -118,6 +118,230 @@ Point Camera::transform3Dto2D(Point p3d) const {
return { (int16)v2d.x(), (int16)v2d.y() };
}
+static void syncMatrix(Serializer &s, Matrix4 &m) {
+ float *data = m.getData();
+ for (int i = 0; i < 16; i++)
+ s.syncAsFloatLE(data[i]);
+}
+
+static void syncVector(Serializer &s, Vector3d &v) {
+ s.syncAsFloatLE(v.x());
+ s.syncAsFloatLE(v.y());
+ s.syncAsFloatLE(v.z());
+}
+
+static void syncFollowTarget(Serializer &s, WalkingCharacter *&followTarget) {
+ // originally the follow object is also searched for before changing the room
+ // so that would practically mean only the main characters could be reasonably found
+ // instead we fall back to global search
+ String name;
+ if (followTarget != nullptr)
+ name = followTarget->name();
+ s.syncString(name);
+ if (s.isLoading()) {
+ if (name.empty())
+ followTarget = nullptr;
+ else {
+ followTarget = dynamic_cast<WalkingCharacter *>(g_engine->world().getObjectByName(name.c_str()));
+ if (followTarget == nullptr)
+ followTarget = dynamic_cast<WalkingCharacter *>(g_engine->world().getObjectByNameFromAnyRoom(name.c_str()));
+ if (followTarget == nullptr)
+ warning("Camera follow target from savestate was not found: %s", name.c_str());
+ }
+ }
+}
+
+//
+// CameraV1
+//
+
+Angle CameraV1::rotation() const {
+ return {};
+}
+
+float CameraV1::scale() const {
+ return 1.0f;
+}
+
+void CameraV1::preUpdate() {
+}
+
+void CameraV1::update() {
+ auto deltaTime = (g_engine->getMillis() - _lastUpdateTime) / 1000.0f;
+ auto newCenter = _appliedCenter;
+
+ if (_followTarget != nullptr) {
+ // this threshold is responsible for the jitter while following
+ const auto threshold = _isLerping ? 100 : 200;
+ _target = as3D(_followTarget->position());
+ auto deltaPos = _target - newCenter;
+ _lastUpdateTime = g_engine->getMillis();
+
+ _isLerping = false;
+ if (fabsf(deltaPos.x()) > threshold) {
+ newCenter.x() += copysignf(350.0f, deltaPos.x()) * deltaTime;
+ _isLerping = true;
+ }
+ if (fabsf(deltaPos.y()) > threshold) {
+ newCenter.y() += copysignf(350.0f, deltaPos.y()) * deltaTime;
+ _isLerping = true;
+ }
+ } else if (_isLerping) {
+ auto distance = newCenter.getDistanceTo(_target);
+ auto move = deltaTime * _lerpSpeed;
+ _lastUpdateTime = g_engine->getMillis();
+
+ if (move < distance)
+ newCenter += (_target - newCenter) / distance * move;
+ else {
+ newCenter = _target;
+ _isLerping = false;
+ }
+ }
+
+ setAppliedCenter(newCenter);
+}
+
+void CameraV1::setRoomBounds(Graphic &background) {
+ auto bgSize = background.animation().imageSize(0);
+ Point screenSize(g_system->getWidth(), g_system->getHeight());
+ _roomMin = as2D(background.topLeft() + screenSize / 2);
+ _roomMax = _roomMin + as2D(bgSize - screenSize);
+ _roomScale = 0;
+}
+
+void CameraV1::setFollow(WalkingCharacter *target) {
+ _lastUpdateTime = g_engine->getMillis();
+ _followTarget = target;
+ _isLerping = false;
+ if (target != nullptr)
+ setAppliedCenter(as3D(target->position()));
+}
+
+void CameraV1::onChangedRoom(bool resetCamera) {
+ // nothing to do in V1
+}
+
+void CameraV1::onTriggeredDoor(WalkingCharacter *target) {
+ setFollow(target);
+}
+
+void CameraV1::onTriggeredDoor(Common::Point fixedPosition) {
+ // should probably never be called
+ debug(1, "Set camera to fixed position in V1: %d, %d", fixedPosition.x, fixedPosition.y);
+}
+
+void CameraV1::onScriptChangedCharacter(MainCharacterKind kind) {
+ if (kind != MainCharacterKind::None)
+ setFollow(g_engine->player().activeCharacter());
+}
+
+void CameraV1::onUserChangedCharacter() {
+ setFollow(g_engine->player().activeCharacter());
+}
+
+void CameraV1::onOpenMenu() {
+ // we rely on room bounds clipping to set the camera position
+ // interaction locks prevent opening menus during lerps, follows are fine due to clipping
+}
+
+void CameraV1::onCloseMenu() {
+}
+
+void CameraV1::syncGame(Serializer &s) {
+ syncVector(s, _appliedCenter);
+ syncMatrix(s, _mat3Dto2D);
+ syncMatrix(s, _mat2Dto3D);
+ syncFollowTarget(s, _followTarget);
+ syncVector(s, _target);
+ s.syncAsByte(_isLerping);
+ s.syncAsFloatLE(_lerpSpeed);
+ s.syncAsUint32LE(_lastUpdateTime);
+}
+
+void CameraV1::lerpOrSet(Point target, int32 mode) {
+ _target = as3D(target);
+ _lastUpdateTime = g_engine->getMillis();
+ _followTarget = nullptr;
+ _isLerping = true;
+
+ if (mode == 1) {
+ // snap to target
+ _isLerping = false;
+ _appliedCenter = _target;
+ } else if (mode <= 0) {
+ // fixed speed, overshoot target
+ _target.x() += copysignf(100, _appliedCenter.x() - _target.x());
+ _target.y() += copysignf(100, _appliedCenter.y() - _target.y());
+ _lerpSpeed = 350.0f;
+ } else {
+ // dynamic speed
+ _lerpSpeed = MAX(1.0f, _target.getDistanceTo(_appliedCenter) / mode);
+ }
+}
+
+// The original name for this task is "disfraza" which I can only translate as "disguise"
+// It is a slightly bouncing vertical camera movement with fixed distance
+
+struct CamV1DisguiseTask final : public Task {
+ CamV1DisguiseTask(Process &process, int32 durationMs)
+ : Task(process)
+ , _camera(g_engine->cameraV1())
+ , _durationMs(durationMs) {}
+
+ CamV1DisguiseTask(Process &process, Serializer &s)
+ : Task(process)
+ , _camera(g_engine->cameraV1()) {
+ CamV1DisguiseTask::syncGame(s);
+ }
+
+ TaskReturn run() override {
+ if (_startTime == 0) {
+ _startPosition = _camera._appliedCenter;
+ _startTime = g_engine->getMillis();
+ }
+ if (_durationMs <= 0 || g_engine->getMillis() - _startTime >= (uint32)_durationMs)
+ return TaskReturn::finish(0);
+
+ Vector3d newPosition = _startPosition;
+ uint32 t = (g_engine->getMillis() - _startTime) * 5;
+ if (t <= 50)
+ newPosition.y() += t;
+ else if (t <= 150)
+ newPosition.y() += 100 - t;
+ else if (t >= 200)
+ newPosition.y() += t - 200;
+ _camera._appliedCenter = newPosition;
+ _camera.setFollow(nullptr);
+
+ return TaskReturn::yield();
+ }
+
+ void debugPrint() override {
+ g_engine->getDebugger()->debugPrintf("\"Disguise\" camera for %dms", _durationMs);
+ }
+
+ void syncGame(Serializer &s) override {
+ Task::syncGame(s);
+ s.syncAsSint32LE(_durationMs);
+ s.syncAsUint32LE(_startTime);
+ syncVector(s, _startPosition);
+ }
+
+ const char *taskName() const override;
+
+private:
+ CameraV1 &_camera;
+ int32 _durationMs = 0;
+ uint32 _startTime = 0;
+ Vector3d _startPosition;
+};
+DECLARE_TASK(CamV1DisguiseTask)
+
+Task *CameraV1::disguise(Process &process, int32 duration) {
+ return new CamV1DisguiseTask(process, duration);
+}
+
//
// CameraV3
//
@@ -136,29 +360,26 @@ void CameraV3::preUpdate() {
void CameraV3::setRoomBounds(Graphic &background) {
auto bgSize = background.animation().imageSize(0);
- if (g_engine->isV1()) {
- Point screenSize(g_system->getWidth(), g_system->getHeight());
- _roomMin = as2D(background.topLeft() + screenSize / 2);
- _roomMax = _roomMin + as2D(bgSize - screenSize);
- _roomScale = 0;
- } else {
- /* The fallback fixes a bug where if the background image is invalid the original engine
- * would not update the background size. This would be around 1024,768 due to
- * previous rooms in the bug instances I found.
- */
- if (bgSize == Point(0, 0))
- bgSize = Point(1024, 768);
+ /* The fallback fixes a bug where if the background image is invalid the original engine
+ * would not update the background size. This would be around 1024,768 due to
+ * previous rooms in the bug instances I found.
+ */
+ if (bgSize == Point(0, 0))
+ bgSize = Point(1024, 768);
- const auto bgScale = background.scale();
- float scaleFactor = 1 - bgScale * kInvBaseScale;
- _roomMin = Vector2d(
- g_system->getWidth() / 2 * scaleFactor,
- g_system->getHeight() / 2 * scaleFactor);
- _roomMax = _roomMin + Vector2d(
- bgSize.x * bgScale * kInvBaseScale,
- bgSize.y * bgScale * kInvBaseScale);
- _roomScale = bgScale;
- }
+ const auto bgScale = background.scale();
+ float scaleFactor = 1 - bgScale * kInvBaseScale;
+ _roomMin = Vector2d(
+ g_system->getWidth() / 2 * scaleFactor,
+ g_system->getHeight() / 2 * scaleFactor);
+ _roomMax = _roomMin + Vector2d(
+ bgSize.x * bgScale * kInvBaseScale,
+ bgSize.y * bgScale * kInvBaseScale);
+ _roomScale = bgScale;
+}
+
+void CameraV3::setFollow(WalkingCharacter *target) {
+ setFollow(target, false);
}
void CameraV3::setFollow(WalkingCharacter *target, bool catchUp) {
@@ -304,18 +525,6 @@ void CameraV3::updateFollowing(float deltaTime) {
}
}
-static void syncMatrix(Serializer &s, Matrix4 &m) {
- float *data = m.getData();
- for (int i = 0; i < 16; i++)
- s.syncAsFloatLE(data[i]);
-}
-
-static void syncVector(Serializer &s, Vector3d &v) {
- s.syncAsFloatLE(v.x());
- s.syncAsFloatLE(v.y());
- s.syncAsFloatLE(v.z());
-}
-
void CameraV3::State::syncGame(Serializer &s) {
syncVector(s, _usedCenter);
s.syncAsFloatLE(_scale);
@@ -338,24 +547,7 @@ void CameraV3::syncGame(Serializer &s) {
for (uint i = 0; i < kStateBackupCount; i++)
_backups[i].syncGame(s);
- // originally the follow object is also searched for before changing the room
- // so that would practically mean only the main characters could be reasonably found
- // instead we fall back to global search
- String name;
- if (_followTarget != nullptr)
- name = _followTarget->name();
- s.syncString(name);
- if (s.isLoading()) {
- if (name.empty())
- _followTarget = nullptr;
- else {
- _followTarget = dynamic_cast<WalkingCharacter *>(g_engine->world().getObjectByName(name.c_str()));
- if (_followTarget == nullptr)
- _followTarget = dynamic_cast<WalkingCharacter *>(g_engine->world().getObjectByNameFromAnyRoom(name.c_str()));
- if (_followTarget == nullptr)
- warning("Camera follow target from savestate was not found: %s", name.c_str());
- }
- }
+ syncFollowTarget(s, _followTarget);
}
struct CamLerpTask : public Task {
@@ -742,66 +934,4 @@ Task *CameraV3::shake(Process &process, Math::Vector2d amplitude, Math::Vector2d
return new CamShakeTask(process, amplitude, frequency, duration);
}
-// The original name for this task is "disfraza" which I can only translate as "disguise"
-// It is a slightly bouncing vertical camera movement with fixed distance
-
-struct CamDisguiseTask final : public Task {
- CamDisguiseTask(Process &process, int32 durationMs)
- : Task(process)
- , _camera(g_engine->cameraV3())
- , _durationMs(durationMs) {}
-
- CamDisguiseTask(Process &process, Serializer &s)
- : Task(process)
- , _camera(g_engine->cameraV3()) {
- CamDisguiseTask::syncGame(s);
- }
-
- TaskReturn run() override {
- if (_startTime == 0) {
- _startPosition = { _camera._cur._usedCenter.x(), _camera._cur._usedCenter.y() };
- _startTime = g_engine->getMillis();
- }
- if (_durationMs <= 0 || g_engine->getMillis() - _startTime >= (uint32)_durationMs)
- return TaskReturn::finish(0);
-
- Vector2d newPosition = _startPosition;
- uint32 t = (g_engine->getMillis() - _startTime) * 5;
- if (t <= 50)
- newPosition.setY(_startPosition.getY() + t);
- else if (t <= 150)
- newPosition.setY(_startPosition.getY() - t + 100);
- else if (t >= 200)
- newPosition.setY(_startPosition.getY() + t - 200);
- _camera.setPosition(newPosition);
- _camera.setFollow(nullptr);
-
- return TaskReturn::yield();
- }
-
- void debugPrint() override {
- g_engine->getDebugger()->debugPrintf("\"Disguise\" camera for %dms", _durationMs);
- }
-
- void syncGame(Serializer &s) override {
- Task::syncGame(s);
- s.syncAsSint32LE(_durationMs);
- s.syncAsUint32LE(_startTime);
- syncVector(s, _startPosition);
- }
-
- const char *taskName() const override;
-
-private:
- CameraV3 &_camera;
- int32 _durationMs = 0;
- uint32 _startTime = 0;
- Vector2d _startPosition;
-};
-DECLARE_TASK(CamDisguiseTask)
-
-Task *CameraV3::disguise(Process &process, int32 duration) {
- return new CamDisguiseTask(process, duration);
-}
-
} // namespace Alcachofa
diff --git a/engines/alcachofa/camera.h b/engines/alcachofa/camera.h
index 296d98d4db0..35d2c98ee4e 100644
--- a/engines/alcachofa/camera.h
+++ b/engines/alcachofa/camera.h
@@ -44,7 +44,7 @@ public:
virtual void preUpdate() = 0;
virtual void update() = 0;
virtual void setRoomBounds(Graphic &background) = 0;
- virtual void setFollow(WalkingCharacter *target, bool catchUp = false) = 0;
+ virtual void setFollow(WalkingCharacter *target) = 0;
virtual void onChangedRoom(bool resetCamera) = 0;
virtual void onTriggeredDoor(WalkingCharacter *target) = 0;
virtual void onTriggeredDoor(Common::Point fixedPosition) = 0;
@@ -72,6 +72,37 @@ protected:
_mat2Dto3D;
};
+class CameraV1 : public Camera {
+public:
+ Math::Angle rotation() const override;
+ float scale() const override;
+
+ void preUpdate() override;
+ void update() override;
+ void setRoomBounds(Graphic &background) override;
+ void setFollow(WalkingCharacter *target) override;
+ void onChangedRoom(bool resetCamera) override;
+ void onTriggeredDoor(WalkingCharacter *target) override;
+ void onTriggeredDoor(Common::Point fixedPosition) override;
+ void onScriptChangedCharacter(MainCharacterKind kind) override;
+ void onUserChangedCharacter() override;
+ void onOpenMenu() override;
+ void onCloseMenu() override;
+ void syncGame(Common::Serializer &s) override;
+ void lerpOrSet(Common::Point target, int32 mode);
+
+ Task *disguise(Process &process, int32 duration);
+
+private:
+ friend struct CamV1DisguiseTask;
+
+ WalkingCharacter *_followTarget = nullptr;
+ Math::Vector3d _target;
+ bool _isLerping = false;
+ float _lerpSpeed = 0.0f;
+ uint32 _lastUpdateTime = 0;
+};
+
class CameraV3 : public Camera {
public:
Math::Angle rotation() const override;
@@ -80,7 +111,8 @@ public:
void preUpdate() override;
void update() override;
void setRoomBounds(Graphic &background) override;
- void setFollow(WalkingCharacter *target, bool catchUp = false) override;
+ void setFollow(WalkingCharacter *target) override;
+ void setFollow(WalkingCharacter *target, bool catchup);
void onChangedRoom(bool resetCamera) override;
void onTriggeredDoor(WalkingCharacter *target) override;
void onTriggeredDoor(Common::Point fixedPosition) override;
@@ -110,15 +142,8 @@ public:
int32 duration, EasingType moveEasingType, EasingType scaleEasingType);
Task *waitToStop(Process &process);
Task *shake(Process &process, Math::Vector2d amplitude, Math::Vector2d frequency, int32 duration);
- Task *disguise(Process &process, int32 duration);
private:
- void resetRotationAndScale();
- void setPosition(Math::Vector2d v);
- void setPosition(Math::Vector3d v);
- void backup(uint slot);
- void restore(uint slot);
-
friend struct CamLerpTask;
friend struct CamLerpPosTask;
friend struct CamLerpScaleTask;
@@ -127,7 +152,12 @@ private:
friend struct CamShakeTask;
friend struct CamWaitToStopTask;
friend struct CamSetInactiveAttributeTask;
- friend struct CamDisguiseTask;
+
+ void resetRotationAndScale();
+ void setPosition(Math::Vector2d v);
+ void setPosition(Math::Vector3d v);
+ void backup(uint slot);
+ void restore(uint slot);
void updateFollowing(float deltaTime);
struct State {
diff --git a/engines/alcachofa/game-objects.cpp b/engines/alcachofa/game-objects.cpp
index ef0c4c85f5b..93296c4a163 100644
--- a/engines/alcachofa/game-objects.cpp
+++ b/engines/alcachofa/game-objects.cpp
@@ -924,7 +924,7 @@ void MainCharacter::walkTo(
}
WalkingCharacter::walkTo(target, endDirection, activateObject, activateAction);
- if (this == g_engine->player().activeCharacter())
+ if (this == g_engine->player().activeCharacter() && g_engine->isV3())
g_engine->camera().setFollow(this);
}
diff --git a/engines/alcachofa/global-ui.cpp b/engines/alcachofa/global-ui.cpp
index 1c9d8aedd26..9e7c0383d5d 100644
--- a/engines/alcachofa/global-ui.cpp
+++ b/engines/alcachofa/global-ui.cpp
@@ -143,8 +143,8 @@ bool GlobalUI::updateChangingCharacter() {
player.setActiveCharacter(player.inactiveCharacter()->kind());
player.heldItem() = nullptr;
- g_engine->camera().onUserChangedCharacter();
player.changeRoom(player.activeCharacter()->room()->name(), false);
+ g_engine->camera().onUserChangedCharacter();
g_engine->game().onUserChangedCharacter();
g_engine->sounds().startMusic(g_engine->game().getCharacterJingle(player.activeCharacterKind()));
diff --git a/engines/alcachofa/rooms.cpp b/engines/alcachofa/rooms.cpp
index 7dbba1a9f1c..bab88b1e590 100644
--- a/engines/alcachofa/rooms.cpp
+++ b/engines/alcachofa/rooms.cpp
@@ -261,7 +261,6 @@ void Room::updateInteraction() {
player.activeCharacter()->room() == this &&
player.pressedObject() == nullptr) {
player.activeCharacter()->walkToMouse();
- g_engine->camera().setFollow(player.activeCharacter());
}
} else {
player.selectedObject()->markSelected();
diff --git a/engines/alcachofa/script.cpp b/engines/alcachofa/script.cpp
index 6da4d7e23d6..732f28353f6 100644
--- a/engines/alcachofa/script.cpp
+++ b/engines/alcachofa/script.cpp
@@ -938,7 +938,7 @@ private:
auto kind = getMainCharacterKindArg(0);
if (kind != MainCharacterKind::None)
target = &g_engine->world().getMainCharacterByKind(kind);
- g_engine->camera().setFollow(target, getNumberArg(1) != 0);
+ g_engine->cameraV3().setFollow(target, getNumberArg(1) != 0);
return TaskReturn::finish(1);
}
case ScriptKernelTask::CamShake:
@@ -1004,13 +1004,24 @@ private:
as3D(pointObject->position()), targetScale,
getNumberArg(2), (EasingType)getNumberArg(3), (EasingType)getNumberArg(4)));
}
+ case ScriptKernelTask::LerpOrSetCam: {
+ if (process().isActiveForPlayer()) {
+ auto pointObject = getObjectArg<PointObject>(0);
+ if (pointObject == nullptr)
+ pointObject = g_engine->game().unknownCamLerpTarget("LerpOrSetCam", getStringArg(0));
+ if (pointObject == nullptr)
+ return TaskReturn::finish(1);
+ g_engine->cameraV1().lerpOrSet(pointObject->position(), getNumberArg(1));
+ }
+ return TaskReturn::finish(0);
+ }
case ScriptKernelTask::Disguise: {
// a somewhat bouncy vertical camera movement used in V1
// or waiting for user to click
const auto duration = getNumberArg(0);
return TaskReturn::waitFor(duration == 0
? g_engine->input().waitForInput(process())
- : g_engine->cameraV3().disguise(process(), duration));
+ : g_engine->cameraV1().disguise(process(), duration));
}
// Fades
diff --git a/engines/alcachofa/script.h b/engines/alcachofa/script.h
index e2595794fb1..6178d742549 100644
--- a/engines/alcachofa/script.h
+++ b/engines/alcachofa/script.h
@@ -119,6 +119,7 @@ enum class ScriptKernelTask {
LerpCamToObjectWithScale,
LerpCamToObjectResettingZ,
LerpCamRotation,
+ LerpOrSetCam, // only V1
FadeIn,
FadeOut,
FadeIn2,
diff --git a/engines/alcachofa/tasks.h b/engines/alcachofa/tasks.h
index b42a680103c..b2a3314eadf 100644
--- a/engines/alcachofa/tasks.h
+++ b/engines/alcachofa/tasks.h
@@ -38,7 +38,7 @@ DEFINE_TASK(CamLerpRotationTask)
DEFINE_TASK(CamShakeTask)
DEFINE_TASK(CamWaitToStopTask)
DEFINE_TASK(CamSetInactiveAttributeTask)
-DEFINE_TASK(CamDisguiseTask)
+DEFINE_TASK(CamV1DisguiseTask)
DEFINE_TASK(SayTextTask)
DEFINE_TASK(AnimateCharacterTask)
DEFINE_TASK(LerpLodBiasTask)
More information about the Scummvm-git-logs
mailing list