diff options
author | Peter Kohaut | 2018-02-18 22:18:41 +0100 |
---|---|---|
committer | Peter Kohaut | 2018-02-18 22:20:16 +0100 |
commit | 7090841ccc43c64d5a1d9058071ebccaf6b52fc2 (patch) | |
tree | 44fb7798096b66646039a34c6d4756e091bc700b /engines | |
parent | 1d69120112e16a74a9d101a0d4d9de04196d29de (diff) | |
download | scummvm-rg350-7090841ccc43c64d5a1d9058071ebccaf6b52fc2.tar.gz scummvm-rg350-7090841ccc43c64d5a1d9058071ebccaf6b52fc2.tar.bz2 scummvm-rg350-7090841ccc43c64d5a1d9058071ebccaf6b52fc2.zip |
BLADERUNNER: Support for running
Fixed Runciter idle state
Fixed movement track delay
Basic combat support
Diffstat (limited to 'engines')
37 files changed, 1049 insertions, 408 deletions
diff --git a/engines/bladerunner/actor.cpp b/engines/bladerunner/actor.cpp index 4d66d74f5e..14c8ef9563 100644 --- a/engines/bladerunner/actor.cpp +++ b/engines/bladerunner/actor.cpp @@ -82,10 +82,10 @@ void Actor::setup(int actorId) { _animationId = 0; _animationFrame = 0; _fps = 15; - _frame_ms = 1000 / _fps; + _frameMs = 1000 / _fps; _isMoving = false; - _isTargetable = false; + _isTarget = false; _inCombat = false; _isInvisible = false; _isImmuneToObstacles = false; @@ -101,8 +101,8 @@ void Actor::setup(int actorId) { _movementTrackDelayOnNextWaypoint = -1; for (int i = 0; i != 7; ++i) { - _timersRemain[i] = 0; - _timersStart[i] = _vm->getTotalPlayTime(); + _timersLeft[i] = 0; + _timersLast[i] = _vm->getTotalPlayTime(); } _honesty = 50; @@ -120,7 +120,9 @@ void Actor::setup(int actorId) { _movementTrackNextAngle = -1; _movementTrackNextRunning = false; - _timersRemain[4] = 60000; + // Timer for exchanging clues + _timersLeft[4] = 60000; + _animationMode = -1; _screenRectangle = Common::Rect(-1, -1, -1, -1); @@ -154,73 +156,76 @@ void Actor::setFPS(int fps) { _fps = fps; if (fps == 0) { - _frame_ms = 0; + _frameMs = 0; } else if (fps == -1) { - _frame_ms = -1000; + _frameMs = -1000; } else if (fps == -2) { _fps = _vm->_sliceAnimations->getFPS(_animationId); - _frame_ms = 1000 / _fps; + _frameMs = 1000 / _fps; } else { - _frame_ms = 1000 / fps; + _frameMs = 1000 / fps; } } -void Actor::countdownTimerStart(int timerId, int interval) { +void Actor::increaseFPS() { + int fps = MIN(_fps + 3, 30); + setFPS(fps); +} + +void Actor::timerStart(int timerId, int interval) { assert(timerId >= 0 && timerId < 7); - _timersRemain[timerId] = interval; - _timersStart[timerId] = _vm->getTotalPlayTime(); + _timersLeft[timerId] = interval; + _timersLast[timerId] = _vm->getTotalPlayTime(); } -void Actor::countdownTimerReset(int timerId) { +void Actor::timerReset(int timerId) { assert(timerId >= 0 && timerId < 7); - _timersRemain[timerId] = 0; + _timersLeft[timerId] = 0; } -int Actor::countdownTimerGetRemainingTime(int timerId) { +int Actor::timerLeft(int timerId) { assert(timerId >= 0 && timerId < 7); - return _timersRemain[timerId]; + return _timersLeft[timerId]; } -void Actor::countdownTimersUpdate() { +void Actor::timersUpdate() { for (int i = 0; i <= 6; i++) { - countdownTimerUpdate(i); + timerUpdate(i); } } -void Actor::countdownTimerUpdate(int timerId) { - if (_timersRemain[timerId] == 0) { +void Actor::timerUpdate(int timerId) { + if (_timersLeft[timerId] == 0) { return; } - uint32 now = _vm->getTotalPlayTime(); - int tickInterval = now - _timersStart[timerId]; - _timersStart[timerId] = now; + uint32 timeNow = _vm->getTotalPlayTime(); + int timeDiff = timeNow - _timersLast[timerId]; + _timersLast[timerId] = timeNow; + _timersLeft[timerId] -= timeDiff; - //warning("tickInterval: %d", tickInterval); - _timersRemain[timerId] -= tickInterval; - - if (_timersRemain[timerId] <= 0) { + if (_timersLeft[timerId] <= 0) { switch (timerId) { case 0: case 1: case 2: if (!_vm->_aiScripts->isInsideScript() && !_vm->_sceneScript->isInsideScript()) { - _vm->_aiScripts->timerExpired(this->_id, timerId); - this->_timersRemain[timerId] = 0; + _vm->_aiScripts->timerExpired(_id, timerId); + _timersLeft[timerId] = 0; } else { - this->_timersRemain[timerId] = 1; + _timersLeft[timerId] = 1; } break; case 3: - _timersRemain[3] = 0; + _timersLeft[3] = 0; if (_movementTrack->isPaused()) { - _timersRemain[3] = 1; + _timersLeft[3] = 1; } else { movementTrackNext(false); } break; case 4: - // Something timer + // Exchange clues between actors break; case 5: // Actor animation frame timer @@ -235,7 +240,7 @@ void Actor::countdownTimerUpdate(int timerId) { setFPS(newFps); } } - _timersRemain[6] = 200; + _timersLeft[6] = 200; break; } } @@ -244,18 +249,18 @@ void Actor::countdownTimerUpdate(int timerId) { void Actor::movementTrackNext(bool omitAiScript) { bool hasNextMovement; int waypointSetId; - int running; + bool run; int angle; int delay; int waypointId; Vector3 waypointPosition; bool arrived; - hasNextMovement = _movementTrack->next(&waypointId, &delay, &angle, &running); + hasNextMovement = _movementTrack->next(&waypointId, &delay, &angle, &run); _movementTrackNextWaypointId = waypointId; _movementTrackNextDelay = delay; _movementTrackNextAngle = angle; - _movementTrackNextRunning = running; + _movementTrackNextRunning = run; if (hasNextMovement) { if (angle == -1) { angle = 0; @@ -264,7 +269,7 @@ void Actor::movementTrackNext(bool omitAiScript) { _vm->_waypoints->getXYZ(waypointId, &waypointPosition.x, &waypointPosition.y, &waypointPosition.z); if (_setId == waypointSetId && waypointSetId == _vm->_actors[0]->_setId) { stopWalking(false); - _walkInfo->setup(_id, running, _position, waypointPosition, false, &arrived); + _walkInfo->setup(_id, run, _position, waypointPosition, false, &arrived); _movementTrackWalkingToWaypointId = waypointId; _movementTrackDelayOnNextWaypoint = delay; @@ -281,7 +286,7 @@ void Actor::movementTrackNext(bool omitAiScript) { if (delay > 1) { changeAnimationMode(kAnimationModeIdle, false); } - countdownTimerStart(3, delay); + timerStart(3, delay); } //return true; } else { @@ -315,19 +320,18 @@ void Actor::movementTrackUnpause() { } void Actor::movementTrackWaypointReached() { - int seconds; if (!_movementTrack->isPaused() && _id != kActorMcCoy) { - if (_movementTrackWalkingToWaypointId >= 0 && _movementTrackDelayOnNextWaypoint) { + if (_movementTrackWalkingToWaypointId >= 0 && _movementTrackDelayOnNextWaypoint >= 0) { if (!_movementTrackDelayOnNextWaypoint) { _movementTrackDelayOnNextWaypoint = 1; } if (_vm->_aiScripts->reachedMovementTrackWaypoint(_id, _movementTrackWalkingToWaypointId)) { - seconds = _movementTrackDelayOnNextWaypoint; - if (seconds > 1) { + int delay = _movementTrackDelayOnNextWaypoint; + if (delay > 1) { changeAnimationMode(kAnimationModeIdle, false); - seconds = _movementTrackDelayOnNextWaypoint; // todo: analyze if movement is changed in some aiscript->ChangeAnimationMode? + delay = _movementTrackDelayOnNextWaypoint; // todo: analyze if movement is changed in some aiscript->ChangeAnimationMode? } - countdownTimerStart(3, seconds); + timerStart(3, delay); } } _movementTrackWalkingToWaypointId = -1; @@ -350,7 +354,7 @@ void Actor::setAtXYZ(const Vector3 &position, int facing, bool snapFacing, bool _vm->_sceneObjects->remove(_id + kSceneObjectOffsetActors); if (_vm->_scene->getSetId() == _setId) { - _vm->_sceneObjects->addActor(_id + kSceneObjectOffsetActors, _bbox, &_screenRectangle, 1, moving, _isTargetable, retired); + _vm->_sceneObjects->addActor(_id + kSceneObjectOffsetActors, _bbox, &_screenRectangle, 1, moving, _isTarget, retired); } } @@ -360,8 +364,8 @@ void Actor::setAtWaypoint(int waypointId, int angle, int moving, bool retired) { setAtXYZ(waypointPosition, angle, true, moving, retired); } -bool Actor::loopWalk(const Vector3 &destination, int destinationOffset, bool interruptible, bool run, const Vector3 &start, float targetWidth, float targetSize, bool a8, bool *flagIsRunning, bool async) { - *flagIsRunning = false; +bool Actor::loopWalk(const Vector3 &destination, int destinationOffset, bool interruptible, bool run, const Vector3 &start, float targetWidth, float targetSize, bool a8, bool *isRunning, bool async) { + *isRunning = false; if (destinationOffset > 0) { float dist = distance(_position, destination); @@ -397,7 +401,7 @@ bool Actor::loopWalk(const Vector3 &destination, int destinationOffset, bool int } if (!walking) { - faceXYZ(destination.x, destination.y, destination.z, false); + faceXYZ(destination, false); return false; } @@ -406,8 +410,8 @@ bool Actor::loopWalk(const Vector3 &destination, int destinationOffset, bool int } if (interruptible) { - _vm->_isWalkingInterruptible = 1; - _vm->_interruptWalking = 0; + _vm->_isWalkingInterruptible = true; + _vm->_interruptWalking = false; } else { _vm->playerLosesControl(); } @@ -419,7 +423,7 @@ bool Actor::loopWalk(const Vector3 &destination, int destinationOffset, bool int bool wasInterrupted = false; while (_walkInfo->isWalking() && _vm->_gameIsRunning) { if (_walkInfo->isRunning()) { - *flagIsRunning = true; + *isRunning = true; } _vm->gameTick(); if (_id == kActorMcCoy && interruptible && _vm->_interruptWalking) { @@ -450,21 +454,21 @@ bool Actor::walkTo(bool run, const Vector3 &destination, bool a3) { return _walkInfo->setup(_id, run, _position, destination, a3, &arrived); } -bool Actor::loopWalkToActor(int otherActorId, int destinationOffset, int interruptible, bool run, bool a5, bool *flagIsRunning) { - return loopWalk(_vm->_actors[otherActorId]->_position, destinationOffset, interruptible, run, _position, 24.0f, 24.0f, a5, flagIsRunning, false); +bool Actor::loopWalkToActor(int otherActorId, int destinationOffset, int interruptible, bool run, bool a5, bool *isRunning) { + return loopWalk(_vm->_actors[otherActorId]->_position, destinationOffset, interruptible, run, _position, 24.0f, 24.0f, a5, isRunning, false); } -bool Actor::loopWalkToItem(int itemId, int destinationOffset, int interruptible, bool run, bool a5, bool *flagIsRunning) { +bool Actor::loopWalkToItem(int itemId, int destinationOffset, int interruptible, bool run, bool a5, bool *isRunning) { float x, y, z; int width, height; _vm->_items->getXYZ(itemId, &x, &y, &z); _vm->_items->getWidthHeight(itemId, &width, &height); Vector3 itemPosition(x, y, z); - return loopWalk(itemPosition, destinationOffset, interruptible, run, _position, width, 24.0f, a5, flagIsRunning, false); + return loopWalk(itemPosition, destinationOffset, interruptible, run, _position, width, 24.0f, a5, isRunning, false); } -bool Actor::loopWalkToSceneObject(const char *objectName, int destinationOffset, bool interruptible, bool run, bool a5, bool *flagIsRunning) { +bool Actor::loopWalkToSceneObject(const char *objectName, int destinationOffset, bool interruptible, bool run, bool a5, bool *isRunning) { int sceneObject = _vm->_scene->_set->findObject(objectName); if (sceneObject < 0) { return true; @@ -506,41 +510,45 @@ bool Actor::loopWalkToSceneObject(const char *objectName, int destinationOffset, float y = _vm->_scene->_set->getAltitudeAtXZ(closestX, closestZ, &inWalkbox); Vector3 destination(closestX, y, closestZ); - return loopWalk(destination, destinationOffset, interruptible, run, _position, 0.0f, 24.0f, a5, flagIsRunning, false); + return loopWalk(destination, destinationOffset, interruptible, run, _position, 0.0f, 24.0f, a5, isRunning, false); } -bool Actor::loopWalkToWaypoint(int waypointId, int destinationOffset, int interruptible, bool run, bool a5, bool *flagIsRunning) { +bool Actor::loopWalkToWaypoint(int waypointId, int destinationOffset, int interruptible, bool run, bool a5, bool *isRunning) { Vector3 waypointPosition; _vm->_waypoints->getXYZ(waypointId, &waypointPosition.x, &waypointPosition.y, &waypointPosition.z); - return loopWalk(waypointPosition, destinationOffset, interruptible, run, _position, 0.0f, 24.0f, a5, flagIsRunning, false); + return loopWalk(waypointPosition, destinationOffset, interruptible, run, _position, 0.0f, 24.0f, a5, isRunning, false); } -bool Actor::loopWalkToXYZ(const Vector3 &destination, int destinationOffset, bool interruptible, bool run, bool a5, bool *flagIsRunning) { - return loopWalk(destination, destinationOffset, interruptible, run, _position, 0.0f, 24.0f, a5, flagIsRunning, false); +bool Actor::loopWalkToXYZ(const Vector3 &destination, int destinationOffset, bool interruptible, bool run, bool a5, bool *isRunning) { + return loopWalk(destination, destinationOffset, interruptible, run, _position, 0.0f, 24.0f, a5, isRunning, false); } bool Actor::asyncWalkToWaypoint(int waypointId, int destinationOffset, bool run, bool a5) { - bool flagIsRunning; + bool isRunning; Vector3 waypointPosition; _vm->_waypoints->getXYZ(waypointId, &waypointPosition.x, &waypointPosition.y, &waypointPosition.z); - return loopWalk(waypointPosition, destinationOffset, false, run, _position, 0.0f, 24.0f, a5, &flagIsRunning, true); + return loopWalk(waypointPosition, destinationOffset, false, run, _position, 0.0f, 24.0f, a5, &isRunning, true); } void Actor::asyncWalkToXYZ(const Vector3 &destination, int destinationOffset, bool run, int a6) { - bool flagIsRunning; - loopWalk(destination, destinationOffset, false, run, _position, 0.0f, 24.0f, a6, &flagIsRunning, true); + bool isRunning; + loopWalk(destination, destinationOffset, false, run, _position, 0.0f, 24.0f, a6, &isRunning, true); +} + +void Actor::run() { + _walkInfo->run(_id); } bool Actor::tick(bool forceDraw, Common::Rect *screenRect) { - int remain = 0; + int timeLeft = 0; bool needsUpdate = false; if (_fps > 0) { - countdownTimerUpdate(5); - remain = countdownTimerGetRemainingTime(5); - needsUpdate = remain <= 0; + timerUpdate(5); + timeLeft = timerLeft(5); + needsUpdate = timeLeft <= 0; } else if (forceDraw) { needsUpdate = true; - remain = 0; + timeLeft = 0; } if (needsUpdate) { @@ -570,68 +578,68 @@ bool Actor::tick(bool forceDraw, Common::Rect *screenRect) { positionChange.y = -4.0f; } - this->_targetFacing = -1; + _targetFacing = -1; bool walked = _walkInfo->tick(_id, -positionChange.y, false); Vector3 pos; int facing; _walkInfo->getCurrentPosition(_id, &pos, &facing); - setAtXYZ(pos, facing, false, this->_isMoving, false); + setAtXYZ(pos, facing, false, _isMoving, false); if (walked) { _vm->_actors[_id]->changeAnimationMode(kAnimationModeIdle); - this->movementTrackWaypointReached(); - if (this->inCombat()) { - this->changeAnimationMode(this->_animationModeCombatIdle, false); + movementTrackWaypointReached(); + if (inCombat()) { + changeAnimationMode(_animationModeCombatIdle, false); } else { - this->changeAnimationMode(kAnimationModeIdle, false); + changeAnimationMode(kAnimationModeIdle, false); } } } else { if (angleChange != 0.0f) { int facingChange = angleChange * (512.0f / M_PI); if (facingChange != 0) { - this->_facing = this->_facing - facingChange; - if (this->_facing < 0) { - this->_facing += 1024; + _facing = _facing - facingChange; + if (_facing < 0) { + _facing += 1024; } - if (this->_facing >= 1024) { - this->_facing = this->_facing - 1024; + if (_facing >= 1024) { + _facing = _facing - 1024; } } } if (0.0f != positionChange.x || 0.0f != positionChange.y || 0.0f != positionChange.z) { - if (this->_actorSpeed.x != 0.0f) { - positionChange.x = positionChange.x * this->_actorSpeed.x; + if (_actorSpeed.x != 0.0f) { + positionChange.x = positionChange.x * _actorSpeed.x; } - if (this->_actorSpeed.y != 0.0f) { - positionChange.y = positionChange.y * this->_actorSpeed.y; + if (_actorSpeed.y != 0.0f) { + positionChange.y = positionChange.y * _actorSpeed.y; } - if (this->_actorSpeed.z != 0.0f) { - positionChange.z = positionChange.z * this->_actorSpeed.z; + if (_actorSpeed.z != 0.0f) { + positionChange.z = positionChange.z * _actorSpeed.z; } float angle = _facing * (M_PI / 512.0f); float sinx = sin(angle); float cosx = cos(angle); - float originalX = this->_position.x; - float originalY = this->_position.y; - float originalZ = this->_position.z; + float originalX = _position.x; + float originalY = _position.y; + float originalZ = _position.z; - this->_position.x = this->_position.x + positionChange.x * cosx - positionChange.y * sinx; - this->_position.z = this->_position.z + positionChange.x * sinx + positionChange.y * cosx; - this->_position.y = this->_position.y + positionChange.z; + _position.x = _position.x + positionChange.x * cosx - positionChange.y * sinx; + _position.z = _position.z + positionChange.x * sinx + positionChange.y * cosx; + _position.y = _position.y + positionChange.z; - if (_vm->_sceneObjects->existsOnXZ(this->_id + kSceneObjectOffsetActors, this->_position.x, this->_position.z, false, false) == 1 && !this->_isImmuneToObstacles) { - this->_position.x = originalX; - this->_position.y = originalY; - this->_position.z = originalZ; + if (_vm->_sceneObjects->existsOnXZ(_id + kSceneObjectOffsetActors, _position.x, _position.z, false, false) == 1 && !_isImmuneToObstacles) { + _position.x = originalX; + _position.y = originalY; + _position.z = originalZ; } - setAtXYZ(this->_position, this->_facing, true, this->_isMoving, this->_isRetired); + setAtXYZ(_position, _facing, true, _isMoving, _isRetired); } } } @@ -645,16 +653,17 @@ bool Actor::tick(bool forceDraw, Common::Rect *screenRect) { } if (needsUpdate) { - int nextFrameTime = remain + _frame_ms; - if (nextFrameTime <= 0) + int nextFrameTime = timeLeft + _frameMs; + if (nextFrameTime <= 0) { nextFrameTime = 1; - countdownTimerStart(5, nextFrameTime); + } + timerStart(5, nextFrameTime); } - if (this->_targetFacing >= 0) { - if (this->_targetFacing == this->_facing) { - this->_targetFacing = -1; + if (_targetFacing >= 0) { + if (_targetFacing == _facing) { + _targetFacing = -1; } else { - this->setFacing(this->_targetFacing, false); + setFacing(_targetFacing, false); } } return isVisible; @@ -761,8 +770,8 @@ void Actor::setBoundingBox(const Vector3 &position, bool retired) { } float Actor::distanceFromView(View *view) const{ - float xDist = this->_position.x - view->_cameraPosition.x; - float zDist = this->_position.z + view->_cameraPosition.z; + float xDist = _position.x - view->_cameraPosition.x; + float zDist = _position.z + view->_cameraPosition.z; return sqrt(xDist * xDist + zDist * zDist); } @@ -799,7 +808,7 @@ void Actor::faceActor(int otherActorId, bool animate) { return; } - faceXYZ(otherActor->_position.x, otherActor->_position.y, otherActor->_position.z, animate); + faceXYZ(otherActor->_position, animate); } void Actor::faceObject(const char *objectName, bool animate) { @@ -843,6 +852,10 @@ void Actor::faceXYZ(float x, float y, float z, bool animate) { faceHeading(heading, animate); } +void Actor::faceXYZ(const Vector3 &pos, bool animate) { + faceXYZ(pos.x, pos.y, pos.z, animate); +} + void Actor::faceCurrentCamera(bool animate) { faceXYZ(_vm->_view->_cameraPosition.x, _vm->_view->_cameraPosition.y, -_vm->_view->_cameraPosition.z, animate); } @@ -936,8 +949,8 @@ void Actor::retire(bool retired, int width, int height, int retiredByActorId) { } } -void Actor::setTargetable(bool targetable) { - _isTargetable = targetable; +void Actor::setTarget(bool target) { + _isTarget = target; } void Actor::setHealth(int hp, int maxHp) { @@ -1095,6 +1108,22 @@ int Actor::soundBalance() const { return 35.0f * (CLIP(screenPosition.x / 640.0f, 0.0f, 1.0f) * 2.0f - 1.0f); } +bool Actor::isObstacleBetween(float targetX, float targetZ) { + return _vm->_sceneObjects->isObstacleBetween(_position.x, _position.z, targetX, targetZ, _position.y, -1); +} + +int Actor::findTargetUnderMouse(BladeRunnerEngine *vm, int mouseX, int mouseY) { + int setId = vm->_scene->getSetId(); + for (int i = 0; i < (int)vm->_gameInfo->getActorCount(); ++i) { + if (vm->_actors[i]->isTarget() && vm->_actors[i]->getSetId() == setId) { + if (vm->_actors[i]->_screenRectangle.contains(mouseX, mouseY)) { + return i; + } + } + } + return -1; +} + bool Actor::walkFindU1(const Vector3 &startPosition, const Vector3 &targetPosition, float size, Vector3 *newDestination) { newDestination->x = 0.0f; newDestination->y = 0.0f; @@ -1163,9 +1192,9 @@ bool Actor::walkFindU2(Vector3 *newDestination, float targetWidth, int destinati bool Actor::walkToNearestPoint(const Vector3 &destination, float distance) { Vector3 out; - bool flagIsRunning; + bool isRunning; if (_walkInfo->findNearestEmptyPosition(_id, destination, distance, out)) { - loopWalk(out, 0, false, false, _position, 0.0f, 24.0f, false, &flagIsRunning, false); + loopWalk(out, 0, false, false, _position, 0.0f, 24.0f, false, &isRunning, false); return true; } return false; diff --git a/engines/bladerunner/actor.h b/engines/bladerunner/actor.h index b160ca3238..6bbcf93be5 100644 --- a/engines/bladerunner/actor.h +++ b/engines/bladerunner/actor.h @@ -71,7 +71,7 @@ private: int _walkboxId; // Flags - bool _isTargetable; + bool _isTarget; bool _isInvisible; bool _isImmuneToObstacles; bool _inWalkLoop; @@ -98,15 +98,15 @@ private: int _animationModeCombatWalk; int _animationModeCombatRun; int _fps; - int _frame_ms; + int _frameMs; int _animationId; int _animationFrame; int _retiredWidth; int _retiredHeight; - int _timersRemain[7]; - int _timersStart[7]; + int _timersLeft[7]; + int _timersLast[7]; float _scale; @@ -132,25 +132,29 @@ public: void changeAnimationMode(int animationMode, bool force = false); void setFPS(int fps); + void increaseFPS(); - void countdownTimerStart(int timerId, int interval); - void countdownTimerReset(int timerId); - int countdownTimerGetRemainingTime(int timerId); - void countdownTimersUpdate(); - void countdownTimerUpdate(int timerId); + void timerStart(int timerId, int interval); + void timerReset(int timerId); + int timerLeft(int timerId); + void timersUpdate(); + void timerUpdate(int timerId); void movementTrackNext(bool omitAiScript); void movementTrackPause(); void movementTrackUnpause(); void movementTrackWaypointReached(); - bool loopWalkToActor(int otherActorId, int destinationOffset, int interruptible, bool run, bool a5, bool *flagIsRunning); - bool loopWalkToItem(int itemId, int destinationOffset, int interruptible, bool run, bool a5, bool *flagIsRunning); - bool loopWalkToSceneObject(const char *objectName, int destinationOffset, bool interruptible, bool run, bool a5, bool *flagIsRunning); - bool loopWalkToWaypoint(int waypointId, int destinationOffset, int interruptible, bool run, bool a5, bool *flagIsRunning); - bool loopWalkToXYZ(const Vector3 &destination, int destinationOffset, bool interruptible, bool run, bool a5, bool *flagIsRunning); + bool loopWalk(const Vector3 &destination, int destinationOffset, bool interruptible, bool run, const Vector3 &start, float a6, float a7, bool a8, bool *isRunning, bool async); + bool walkTo(bool run, const Vector3 &destination, bool a3); + bool loopWalkToActor(int otherActorId, int destinationOffset, int interruptible, bool run, bool a5, bool *isRunning); + bool loopWalkToItem(int itemId, int destinationOffset, int interruptible, bool run, bool a5, bool *isRunning); + bool loopWalkToSceneObject(const char *objectName, int destinationOffset, bool interruptible, bool run, bool a5, bool *isRunning); + bool loopWalkToWaypoint(int waypointId, int destinationOffset, int interruptible, bool run, bool a5, bool *isRunning); + bool loopWalkToXYZ(const Vector3 &destination, int destinationOffset, bool interruptible, bool run, bool a5, bool *isRunning); bool asyncWalkToWaypoint(int waypointId, int destinationOffset, bool run, bool a5); void asyncWalkToXYZ(const Vector3 &destination, int destinationOffset, bool run, int a6); + void run(); bool tick(bool forceUpdate, Common::Rect *screenRect); bool draw(Common::Rect *screenRect); @@ -161,8 +165,8 @@ public: Common::Rect *getScreenRectangle() { return &_screenRectangle; } int getWalkbox() const { return _walkboxId; } bool isRetired() const { return _isRetired; } - bool isTargetable() const { return _isTargetable; } - void setTargetable(bool targetable); + bool isTarget() const { return _isTarget; } + void setTarget(bool targetable); bool isImmuneToObstacles() const { return _isImmuneToObstacles; } bool inCombat() const { return _inCombat; } bool isMoving() const { return _isMoving; } @@ -177,6 +181,7 @@ public: void faceItem(int itemId, bool animate); void faceWaypoint(int waypointId, bool animate); void faceXYZ(float x, float y, float z, bool animate); + void faceXYZ(const Vector3 &pos, bool animate); void faceCurrentCamera(bool animate); void faceHeading(int heading, bool animate); void modifyFriendlinessToOther(int otherActorId, signed int change); @@ -203,7 +208,7 @@ public: void combatModeOff(); void setGoal(int goalNumber); - int getGoal() const; + int getGoal() const; float distanceFromActor(int otherActorId); @@ -220,14 +225,14 @@ public: int soundVolume() const; int soundBalance() const; + bool isObstacleBetween(float targetX, float targetZ); + + static int findTargetUnderMouse(BladeRunnerEngine *vm, int mouseX, int mouseY); private: void setFacing(int facing, bool halfOrSet = true); void setBoundingBox(const Vector3 &position, bool retired); float distanceFromView(View *view) const; - bool loopWalk(const Vector3 &destination, int destinationOffset, bool interruptible, bool run, const Vector3 &start, float a6, float a7, bool a8, bool *isRunning, bool async); - bool walkTo(bool run, const Vector3 &destination, bool a3); - bool walkFindU1(const Vector3 &startPosition, const Vector3 &targetPosition, float a3, Vector3 *newDestination); bool walkFindU2(Vector3 *newDestination, float targetWidth, int destinationOffset, float targetSize, const Vector3 &startPosition, const Vector3 &targetPosition); bool walkToNearestPoint(const Vector3 &destination, float distance); diff --git a/engines/bladerunner/actor_walk.cpp b/engines/bladerunner/actor_walk.cpp index fccc8e22b3..3a2327a8df 100644 --- a/engines/bladerunner/actor_walk.cpp +++ b/engines/bladerunner/actor_walk.cpp @@ -37,8 +37,8 @@ namespace BladeRunner { ActorWalk::ActorWalk(BladeRunnerEngine *vm) { _vm = vm; - _walking = 0; - _running = 0; + _walking = false; + _running = false; _facing = -1; _status = 0; @@ -228,6 +228,16 @@ void ActorWalk::stop(int actorId, bool immediately, int combatAnimationMode, int } } +void ActorWalk::run(int actorId) { + _running = true; + + int animationMode = kAnimationModeRun; + if (_vm->_actors[actorId]->inCombat()) { + animationMode = kAnimationModeCombatRun; + } + _vm->_actors[actorId]->changeAnimationMode(animationMode, false); +} + bool ActorWalk::isXYZEmpty(float x, float y, float z, int actorId) const { if (_vm->_scene->_set->findWalkbox(x, z) == -1) { return true; diff --git a/engines/bladerunner/actor_walk.h b/engines/bladerunner/actor_walk.h index 07e383ac25..e3e48b8b76 100644 --- a/engines/bladerunner/actor_walk.h +++ b/engines/bladerunner/actor_walk.h @@ -58,6 +58,7 @@ public: bool findNearestEmptyPosition(int actorId, const Vector3 &from, int distance, Vector3 &out) const; void stop(int actorId, bool immediately, int combatAnimationMode, int animationMode); + void run(int actorId); private: int nextOnPath(int actorId, const Vector3 &from, const Vector3 &to, Vector3 &next) const; diff --git a/engines/bladerunner/bladerunner.cpp b/engines/bladerunner/bladerunner.cpp index 5f565d972c..a45c0e6d92 100644 --- a/engines/bladerunner/bladerunner.cpp +++ b/engines/bladerunner/bladerunner.cpp @@ -97,7 +97,7 @@ BladeRunnerEngine::BladeRunnerEngine(OSystem *syst, const ADGameDescription *des _gameIsLoading = false; _sceneIsLoading = false; - _walkingActorId = -1; + _runningActorId = -1; _isWalkingInterruptible = false; _interruptWalking = false; @@ -178,6 +178,7 @@ BladeRunnerEngine::BladeRunnerEngine(OSystem *syst, const ADGameDescription *des for (int i = 0; i != kActorCount; ++i) { _actors[i] = nullptr; } + walkingReset(); } BladeRunnerEngine::~BladeRunnerEngine() { @@ -341,8 +342,7 @@ bool BladeRunnerEngine::startup(bool hasSavegames) { _playerActor = _actors[_gameInfo->getPlayerId()]; _playerActor->setFPS(15); - - // TODO: set _playerActor countdown timer 6 + _playerActor->timerStart(6, 200); // TODO: Set actor ids (redundant?) @@ -863,16 +863,16 @@ void BladeRunnerEngine::gameTick() { Vector3 pos = _view->calculateScreenPosition(0.5 * (a + b)); int color; - switch (sceneObject->sceneObjectType) { + switch (sceneObject->type) { case kSceneObjectTypeActor: color = 0b111110000000000; drawBBox(a, b, _view, &_surfaceFront, color); - _mainFont->drawColor(_textActorNames->getText(sceneObject->sceneObjectId - kSceneObjectOffsetActors), _surfaceFront, pos.x, pos.y, color); + _mainFont->drawColor(_textActorNames->getText(sceneObject->id - kSceneObjectOffsetActors), _surfaceFront, pos.x, pos.y, color); break; case kSceneObjectTypeItem: char itemText[40]; drawBBox(a, b, _view, &_surfaceFront, color); - sprintf(itemText, "item %i", sceneObject->sceneObjectId - kSceneObjectOffsetItems); + sprintf(itemText, "item %i", sceneObject->id - kSceneObjectOffsetItems); _mainFont->drawColor(itemText, _surfaceFront, pos.x, pos.y, color); break; case kSceneObjectTypeObject: @@ -883,10 +883,10 @@ void BladeRunnerEngine::gameTick() { color = 0b000001111100000; } drawBBox(a, b, _view, &_surfaceFront, color); - _mainFont->drawColor(_scene->objectGetName(sceneObject->sceneObjectId - kSceneObjectOffsetObjects), _surfaceFront, pos.x, pos.y, color); + _mainFont->drawColor(_scene->objectGetName(sceneObject->id - kSceneObjectOffsetObjects), _surfaceFront, pos.x, pos.y, color); break; } - _surfaceFront.frameRect(sceneObject->screenRectangle, color); + _surfaceFront.frameRect(*sceneObject->screenRectangle, color); } } @@ -1001,12 +1001,31 @@ void BladeRunnerEngine::actorsUpdate() { Actor *actor = _actors[i]; if (actor->getSetId() == setId) { _aiScripts->update(i); - actor->countdownTimersUpdate(); + actor->timersUpdate(); } } } } +void BladeRunnerEngine::walkingReset() { + _mouseClickTimeLast = 0; + _mouseClickTimeDiff = 0; + _walkingToExitId = -1; + _isInsideScriptExit = false; + _walkingToRegionId = -1; + _isInsideScriptRegion = false; + _walkingToObjectId = -1; + _isInsideScriptObject = false; + _walkingToItemId = -1; + _isInsideScriptItem = false; + _walkingToEmpty = false; + _walkingToEmptyX = 0; + _walkingToEmptyY = 0; + _isInsideScriptEmpty = false; + _walkingToActorId = -1; + _isInsideScriptActor = false; +} + void BladeRunnerEngine::handleEvents() { if (shouldQuit()) { _gameIsRunning = false; @@ -1149,16 +1168,23 @@ void BladeRunnerEngine::handleKeyDown(Common::Event &event) { } } -void BladeRunnerEngine::handleMouseAction(int x, int y, bool buttonLeft, bool buttonDown) { +void BladeRunnerEngine::handleMouseAction(int x, int y, bool mainButton, bool buttonDown) { + int timeNow = getTotalPlayTime(); + + if (buttonDown) { + _mouseClickTimeDiff = timeNow - _mouseClickTimeLast; + _mouseClickTimeLast = timeNow; + } + if (!playerHasControl() || _mouse->isDisabled()) { return; } if (_kia->isOpen()) { if (buttonDown) { - _kia->handleMouseDown(x, y, buttonLeft); + _kia->handleMouseDown(x, y, mainButton); } else { - _kia->handleMouseUp(x, y, buttonLeft); + _kia->handleMouseUp(x, y, mainButton); } return; } @@ -1174,18 +1200,18 @@ void BladeRunnerEngine::handleMouseAction(int x, int y, bool buttonLeft, bool bu if (_esper->isOpen()) { if (buttonDown) { - _esper->handleMouseDown(x, y, buttonLeft); + _esper->handleMouseDown(x, y, mainButton); } else { - _esper->handleMouseUp(x, y, buttonLeft); + _esper->handleMouseUp(x, y, mainButton); } return; } if (_vk->isOpen()) { if (buttonDown) { - _vk->handleMouseDown(x, y, buttonLeft); + _vk->handleMouseDown(x, y, mainButton); } else { - _vk->handleMouseUp(x, y, buttonLeft); + _vk->handleMouseUp(x, y, mainButton); } return; } @@ -1200,91 +1226,379 @@ void BladeRunnerEngine::handleMouseAction(int x, int y, bool buttonLeft, bool bu } if (_dialogueMenu->waitingForInput()) { - if (buttonLeft && !buttonDown) { + if (mainButton && !buttonDown) { _dialogueMenu->mouseUp(); } return; } - if (buttonLeft && !buttonDown) { + if (mainButton) { Vector3 scenePosition = _mouse->getXYZ(x, y); bool isClickable; bool isObstacle; bool isTarget; - int sceneObjectId = _sceneObjects->findByXYZ(&isClickable, &isObstacle, &isTarget, scenePosition.x, scenePosition.y, scenePosition.z, true, false, true); + int sceneObjectId = _sceneObjects->findByXYZ(&isClickable, &isObstacle, &isTarget, scenePosition, true, false, true); int exitIndex = _scene->_exits->getRegionAtXY(x, y); + int regionIndex = _scene->_regions->getRegionAtXY(x, y); - if ((sceneObjectId < 0 || sceneObjectId > 73) && exitIndex >= 0) { - handleMouseClickExit(x, y, exitIndex); - return; + if ((sceneObjectId < kSceneObjectOffsetActors || sceneObjectId >= kSceneObjectOffsetActors) && exitIndex >= 0) { + handleMouseClickExit(exitIndex, x, y, buttonDown); + } else if (regionIndex >= 0) { + handleMouseClickRegion(regionIndex, x, y, buttonDown); + } else if (sceneObjectId == -1) { + handleMouseClickEmpty(x, y, scenePosition, buttonDown); + } else if (sceneObjectId >= kSceneObjectOffsetActors && sceneObjectId < kSceneObjectOffsetItems) { + handleMouseClickActor(sceneObjectId - kSceneObjectOffsetActors, mainButton, buttonDown, scenePosition, x, y); + } else if (sceneObjectId >= kSceneObjectOffsetItems && sceneObjectId < kSceneObjectOffsetObjects) { + handleMouseClickItem(sceneObjectId - kSceneObjectOffsetItems, buttonDown); + } else if (sceneObjectId >= kSceneObjectOffsetObjects && sceneObjectId <= 293) { + handleMouseClick3DObject(sceneObjectId - kSceneObjectOffsetObjects, buttonDown, isClickable, isTarget); } - - int regionIndex = _scene->_regions->getRegionAtXY(x, y); - if (regionIndex >= 0) { - handleMouseClickRegion(x, y, regionIndex); - return; + } else if (buttonDown) { + if (_playerActor->inWalkLoop()) { + _playerActor->stopWalking(false); } + _combat->change(); + } +} - if (sceneObjectId == -1) { - handleMouseClickEmpty(x, y, scenePosition); - return; - } else if (sceneObjectId >= 0 && sceneObjectId <= 73) { - handleMouseClickActor(x, y, sceneObjectId); - return; - } else if (sceneObjectId >= 74 && sceneObjectId <= 197) { - handleMouseClickItem(x, y, sceneObjectId - 74); - return; - } else if (sceneObjectId >= 198 && sceneObjectId <= 293) { - handleMouseClick3DObject(x, y, sceneObjectId - 198, isClickable, isTarget); - return; - } +void BladeRunnerEngine::handleMouseClickExit(int exitId, int x, int y, bool buttonDown) { + debug("clicked on exit %d %d %d", exitId, x, y); + + if (_isWalkingInterruptible && exitId != _walkingToExitId) { + _isWalkingInterruptible = false; + _interruptWalking = true; + walkingReset(); + _walkingToExitId = exitId; + return; } - if (!buttonLeft && buttonDown) { - // TODO: stop walking && switch combat mode + + if (buttonDown) { + return; } + if (_isInsideScriptExit && exitId == _walkingToExitId) { + _playerActor->run(); + if (_mouseClickTimeDiff <= 10000) { + _playerActor->increaseFPS(); + } + } else { + _walkingToExitId = exitId; + _walkingToRegionId = -1; + _walkingToObjectId = -1; + _walkingToItemId = -1; + _walkingToEmpty = false; + _walkingToActorId = -1; + + _isInsideScriptExit = true; + _sceneScript->clickedOnExit(exitId); + _isInsideScriptExit = false; + } } -void BladeRunnerEngine::handleMouseClickExit(int x, int y, int exitIndex) { - debug("clicked on exit %d %d %d", exitIndex, x, y); - _sceneScript->clickedOnExit(exitIndex); -} +void BladeRunnerEngine::handleMouseClickRegion(int regionId, int x, int y, bool buttonDown) { + debug("clicked on region %d %d %d", regionId, x, y); + + if (_isWalkingInterruptible && regionId != _walkingToRegionId) { + _isWalkingInterruptible = false; + _interruptWalking = true; + walkingReset(); + _walkingToRegionId = regionId; + return; + } -void BladeRunnerEngine::handleMouseClickRegion(int x, int y, int regionIndex) { - debug("clicked on region %d %d %d", regionIndex, x, y); - _sceneScript->clickedOn2DRegion(regionIndex); + if (buttonDown || _mouse->isInactive()) { + return; + } + + if (_isInsideScriptRegion && regionId == _walkingToRegionId) { + _playerActor->run(); + if (_mouseClickTimeDiff <= 10000) { + _playerActor->increaseFPS(); + } + } else { + _walkingToExitId = -1; + _walkingToRegionId = regionId; + _walkingToObjectId = -1; + _walkingToItemId = -1; + _walkingToEmpty = false; + _walkingToActorId = -1; + + _isInsideScriptRegion = true; + _sceneScript->clickedOn2DRegion(regionId); + _isInsideScriptRegion = false; + } } -void BladeRunnerEngine::handleMouseClick3DObject(int x, int y, int objectId, bool isClickable, bool isTarget) { +void BladeRunnerEngine::handleMouseClick3DObject(int objectId, bool buttonDown, bool isClickable, bool isTarget) { const char *objectName = _scene->objectGetName(objectId); debug("Clicked on object %s", objectName); - _sceneScript->clickedOn3DObject(objectName, false); + + if (_isWalkingInterruptible && objectId != _walkingToObjectId) { + _isWalkingInterruptible = false; + _interruptWalking = true; + walkingReset(); + _walkingToObjectId = objectId; + return; + } + + if (_mouse->isInactive()) { + return; + } + + if (!_combat->isActive()) { + if (buttonDown || !isClickable) { + return; + } + + if (_isInsideScriptObject && objectId == _walkingToObjectId) { + _playerActor->run(); + if (_mouseClickTimeDiff <= 10000) { + _playerActor->increaseFPS(); + } + } else { + _walkingToExitId = -1; + _walkingToRegionId = -1; + _walkingToObjectId = objectId; + _walkingToItemId = -1; + _walkingToEmpty = false; + _walkingToActorId = -1; + + _isInsideScriptObject = true; + _sceneScript->clickedOn3DObject(objectName, false); + _isInsideScriptObject = false; + } + } else { + if (!buttonDown || !isTarget) { + return; + } + _playerActor->stopWalking(false); + _playerActor->faceObject(objectName, false); + _playerActor->changeAnimationMode(kAnimationModeCombatShoot, false); + _settings->decreaseAmmo(); + _audioPlayer->playAud(_gameInfo->getSfxTrack(_combat->getHitSound()), 100, 0, 0, 90, 0); + + //TODO mouse::randomize(Mouse); + + _isInsideScriptObject = true; + _sceneScript->clickedOn3DObject(objectName, true); + _isInsideScriptObject = false; + } } -void BladeRunnerEngine::handleMouseClickEmpty(int x, int y, Vector3 &mousePosition) { +void BladeRunnerEngine::handleMouseClickEmpty(int x, int y, Vector3 &scenePosition, bool buttonDown) { + debug("Clicked on nothing %f, %f, %f", scenePosition.x, scenePosition.y, scenePosition.z); + + if (_isWalkingInterruptible) { + _isWalkingInterruptible = false; + _interruptWalking = true; + walkingReset(); + _walkingToEmpty = false; + return; + } + + _isInsideScriptEmpty = true; bool sceneMouseClick = _sceneScript->mouseClick(x, y); + _isInsideScriptEmpty = false; if (sceneMouseClick) { return; } - bool isRunning; - debug("Clicked on nothing %f, %f, %f", mousePosition.x, mousePosition.y, mousePosition.z); - _playerActor->loopWalkToXYZ(mousePosition, 0, false, false, false, &isRunning); + int actorId = Actor::findTargetUnderMouse(this, x, y); + int itemId = _items->findTargetUnderMouse(x, y); + + if (_combat->isActive() && buttonDown && actorId > 0 && itemId > 0) { + _playerActor->stopWalking(false); + if (actorId > 0) { + _playerActor->faceActor(actorId, false); + } else { + _playerActor->faceItem(itemId, false); + } + _playerActor->changeAnimationMode(kAnimationModeCombatShoot, false); + _settings->decreaseAmmo(); + _audioPlayer->playAud(_gameInfo->getSfxTrack(_combat->getMissSound()), 100, 0, 0, 90, 0); + + //TODO mouse::randomize(Mouse); + + if (actorId) { + _aiScripts->shotAtAndMissed(actorId); + } + } else { + if (buttonDown) { + return; + } + + _walkingToExitId = -1; + _walkingToRegionId = -1; + _walkingToObjectId = -1; + _walkingToItemId = -1; + _walkingToEmpty = true; + _walkingToActorId = -1; + + if (_combat->isActive() && (actorId > 0 || itemId > 0)) { + return; + } + + int xDist = abs(_walkingToEmptyX - x); + int yDist = abs(_walkingToEmptyY - y); + + _walkingToEmptyX = x; + _walkingToEmptyY = y; + + bool inWalkbox = false; + float altitude = _scene->_set->getAltitudeAtXZ(scenePosition.x, scenePosition.z, &inWalkbox); + + if (!inWalkbox || scenePosition.y >= altitude + 6.0f) { + return; + } + + bool run = _playerActor->isRunning();; + if (_mouseClickTimeDiff <= 10000 && xDist < 10 && yDist < 10) { + run = true; + } + + _playerActor->walkTo(run, scenePosition, false); + + if (run && _playerActor->isWalking()) { + _playerActor->increaseFPS(); + } + } } -void BladeRunnerEngine::handleMouseClickItem(int x, int y, int itemId) { +void BladeRunnerEngine::handleMouseClickItem(int itemId, bool buttonDown) { debug("Clicked on item %d", itemId); - _sceneScript->clickedOnItem(itemId, false); + + if (_isWalkingInterruptible && itemId != _walkingToItemId) { + _isWalkingInterruptible = false; + _interruptWalking = true; + walkingReset(); + _walkingToItemId = itemId; + return; + } + + if (_mouse->isInactive()) { + return; + } + + if (!_combat->isActive()) { + if (buttonDown) { + return; + } + + if (_isInsideScriptItem && itemId == _walkingToItemId) { + _playerActor->run(); + if (_mouseClickTimeDiff <= 10000) { + _playerActor->increaseFPS(); + } + } else { + _walkingToExitId = -1; + _walkingToRegionId = -1; + _walkingToObjectId = -1; + _walkingToItemId = itemId; + _walkingToEmpty = false; + _walkingToActorId = -1; + + _isInsideScriptItem = true; + _sceneScript->clickedOnItem(itemId, false); + _isInsideScriptItem = false; + } + } else { + if (!buttonDown || !_items->isTarget(itemId) /* || _mouse->isRandomized() */) { + return; + } + + _playerActor->stopWalking(false); + _playerActor->faceItem(itemId, false); + _playerActor->changeAnimationMode(kAnimationModeCombatShoot, false); + _settings->decreaseAmmo(); + _audioPlayer->playAud(_gameInfo->getSfxTrack(_combat->getHitSound()), 100, 0, 0, 90, 0); + + //TODO mouse::randomize(Mouse); + _isInsideScriptItem = true; + _sceneScript->clickedOnItem(itemId, true); + _isInsideScriptItem = false; + } } -void BladeRunnerEngine::handleMouseClickActor(int x, int y, int actorId) { +void BladeRunnerEngine::handleMouseClickActor(int actorId, bool mainButton, bool buttonDown, Vector3 &scenePosition, int x, int y) { debug("Clicked on actor %d", actorId); - bool t = _sceneScript->clickedOnActor(actorId); - if (!_combat->isActive() && !t) { - _aiScripts->clickedByPlayer(actorId); + + if (_isWalkingInterruptible && actorId != _walkingToActorId) { + _isWalkingInterruptible = false; + _interruptWalking = true; + walkingReset(); + _walkingToActorId = actorId; + return; + } + + if (_mouse->isInactive()) { + return; + } + + if (!buttonDown) { + if (actorId == kActorMcCoy) { + if (mainButton) { + if (!_combat->isActive()) { + _kia->openLastOpened(); + } + } else if (!_playerActor->inWalkLoop()) { + _combat->change(); + } + return; + } + + if (_isInsideScriptActor && actorId == _walkingToActorId) { + _playerActor->run(); + if (_mouseClickTimeDiff <= 10000) { + _playerActor->increaseFPS(); + } + } else { + _walkingToExitId = -1; + _walkingToRegionId = -1; + _walkingToObjectId = -1; + _walkingToItemId = -1; + _walkingToEmpty = false; + _walkingToActorId = actorId; + + _isInsideScriptActor = true; + bool processedBySceneScript = _sceneScript->clickedOnActor(actorId); + _isInsideScriptActor = false; + + if (!_combat->isActive() && !processedBySceneScript) { + _aiScripts->clickedByPlayer(actorId); + } + } + } else { + if (!_combat->isActive() || actorId == kActorMcCoy || !_actors[actorId]->isTarget() || _actors[actorId]->isRetired() /*|| _mouse->isRandomized()*/) { + return; + } + _playerActor->stopWalking(false); + _playerActor->faceActor(actorId, false); + _playerActor->changeAnimationMode(kAnimationModeCombatShoot, false); + _settings->decreaseAmmo(); + + float targetX = _actors[actorId]->getX(); + float targetZ = _actors[actorId]->getZ(); + + bool missed = _playerActor->isObstacleBetween(targetX, targetZ); + + _audioPlayer->playAud(_gameInfo->getSfxTrack(missed ? _combat->getMissSound() : _combat->getHitSound()), 100, 0, 0, 90, 0); + + //TODO mouse::randomize(Mouse); + + if (missed) { + _aiScripts->shotAtAndMissed(actorId); + } else { + _isInsideScriptActor = true; + bool canShoot = _aiScripts->shotAtAndHit(actorId); + _isInsideScriptActor = false; + if (!canShoot) { + _combat->shoot(actorId, scenePosition, x); + } + } } } diff --git a/engines/bladerunner/bladerunner.h b/engines/bladerunner/bladerunner.h index 07e52de345..373974f238 100644 --- a/engines/bladerunner/bladerunner.h +++ b/engines/bladerunner/bladerunner.h @@ -174,7 +174,25 @@ public: int _walkSoundId; int _walkSoundVolume; int _walkSoundBalance; - int _walkingActorId; + int _runningActorId; + + int _mouseClickTimeLast; + int _mouseClickTimeDiff; + + int _walkingToExitId; + bool _isInsideScriptExit; + int _walkingToRegionId; + bool _isInsideScriptRegion; + int _walkingToObjectId; + bool _isInsideScriptObject; + int _walkingToItemId; + bool _isInsideScriptItem; + bool _walkingToEmpty; + int _walkingToEmptyX; + int _walkingToEmptyY; + bool _isInsideScriptEmpty; + int _walkingToActorId; + bool _isInsideScriptActor; private: MIXArchive _archives[kArchiveCount]; @@ -199,17 +217,22 @@ public: void gameLoop(); void gameTick(); + void actorsUpdate(); + + void walkingReset(); + void handleEvents(); void handleKeyUp(Common::Event &event); void handleKeyDown(Common::Event &event); - void handleMouseAction(int x, int y, bool buttonLeft, bool buttonDown); - void handleMouseClickExit(int x, int y, int exitIndex); - void handleMouseClickRegion(int x, int y, int regionIndex); - void handleMouseClickItem(int x, int y, int itemId); - void handleMouseClickActor(int x, int y, int actorId); - void handleMouseClick3DObject(int x, int y, int objectId, bool isClickable, bool isTarget); - void handleMouseClickEmpty(int x, int y, Vector3 &mousePosition); + void handleMouseAction(int x, int y, bool mainButton, bool buttonDown); + void handleMouseClickExit(int exitId, int x, int y, bool buttonDown); + void handleMouseClickRegion(int regionId, int x, int y, bool buttonDown); + void handleMouseClickItem(int itemId, bool buttonDown); + void handleMouseClickActor(int actorId, bool mainButton, bool buttonDown, Vector3 &scenePosition, int x, int y); + void handleMouseClick3DObject(int objectId, bool buttonDown, bool isClickable, bool isTarget); + void handleMouseClickEmpty(int x, int y, Vector3 &scenePosition, bool buttonDown); + void gameWaitForActive(); void loopActorSpeaking(); diff --git a/engines/bladerunner/boundingbox.cpp b/engines/bladerunner/boundingbox.cpp index f7e7eca190..a1c79a17e7 100644 --- a/engines/bladerunner/boundingbox.cpp +++ b/engines/bladerunner/boundingbox.cpp @@ -50,6 +50,10 @@ bool BoundingBox::inside(float x, float y, float z) const { && z >= _vertices[0].z && z <= _vertices[1].z; } +bool BoundingBox::inside(Vector3 &position) const { + return inside(position.x, position.y, position.z); +} + void BoundingBox::setXYZ(float x0, float y0, float z0, float x1, float y1, float z1) { _vertices[0].x = x0; _vertices[0].y = y0; diff --git a/engines/bladerunner/boundingbox.h b/engines/bladerunner/boundingbox.h index 3f42318cde..11922cbd14 100644 --- a/engines/bladerunner/boundingbox.h +++ b/engines/bladerunner/boundingbox.h @@ -36,6 +36,7 @@ public: void expand(float x0, float y0, float z0, float x1, float y1, float z1); bool inside(float x, float y, float z) const; + bool inside(Vector3 &position) const; void setXYZ(float x0, float y0, float z0, float x1, float y1, float z1); void getXYZ(float *x0, float *y0, float *z0, float *x1, float *y1, float *z1) const; diff --git a/engines/bladerunner/combat.cpp b/engines/bladerunner/combat.cpp index 26b8b5d785..c371f7bedd 100644 --- a/engines/bladerunner/combat.cpp +++ b/engines/bladerunner/combat.cpp @@ -33,6 +33,13 @@ namespace BladeRunner { Combat::Combat(BladeRunnerEngine *vm) { _vm = vm; + reset(); +} + +Combat::~Combat() { +} + +void Combat::reset() { _active = false; _enabled = true; @@ -40,15 +47,12 @@ Combat::Combat(BladeRunnerEngine *vm) { _ammoDamage[1] = 20; _ammoDamage[2] = 30; - for (int i = 0; i < 9; i++) { + for (int i = 0; i < kSoundCount; i++) { _hitSoundId[i] = -1; _missSoundId[i] = -1; } } -Combat::~Combat() { -} - void Combat::activate() { if(_enabled) { _vm->_playerActor->combatModeOn(-1, -1, -1, -1, kAnimationModeCombatIdle, kAnimationModeCombatWalk, kAnimationModeCombatRun, -1, -1, -1, _vm->_combat->_ammoDamage[_vm->_settings->getAmmoType()], 0, 0); @@ -63,7 +67,17 @@ void Combat::deactivate() { } } -bool Combat::isActive() { +void Combat::change() { + if (!_vm->_playerActor->inWalkLoop() && _enabled) { + if (_active) { + deactivate(); + } else { + activate(); + } + } +} + +bool Combat::isActive() const{ return _active; } @@ -91,4 +105,8 @@ int Combat::getMissSound() { return _hitSoundId[3 * _vm->_settings->getAmmoType() + _vm->_rnd.getRandomNumber(2)]; } +void Combat::shoot(int actorId, Vector3 &to, int screenX) { + +} + } // End of namespace BladeRunner diff --git a/engines/bladerunner/combat.h b/engines/bladerunner/combat.h index 8f0119a854..21989dac52 100644 --- a/engines/bladerunner/combat.h +++ b/engines/bladerunner/combat.h @@ -25,15 +25,19 @@ namespace BladeRunner { +class Vector3; + class BladeRunnerEngine; class Combat { + static const int kSoundCount = 9; + BladeRunnerEngine *_vm; bool _active; bool _enabled; - int _hitSoundId[9]; - int _missSoundId[9]; + int _hitSoundId[kSoundCount]; + int _missSoundId[kSoundCount]; // int _random1; // int _random2; @@ -44,9 +48,12 @@ public: Combat(BladeRunnerEngine *vm); ~Combat(); + void reset(); + void activate(); void deactivate(); - bool isActive(); + void change(); + bool isActive() const; void enable(); void disable(); @@ -55,6 +62,8 @@ public: void setMissSound(int ammoType, int column, int soundId); int getHitSound(); int getMissSound(); + + void shoot(int actorId, Vector3 &to, int screenX); }; } // End of namespace BladeRunner diff --git a/engines/bladerunner/game_constants.h b/engines/bladerunner/game_constants.h index 30b28de714..54f5fed9eb 100644 --- a/engines/bladerunner/game_constants.h +++ b/engines/bladerunner/game_constants.h @@ -559,8 +559,11 @@ enum AnimationModes { kAnimationModeWalk = 1, kAnimationModeRun = 2, kAnimationModeCombatIdle = 4, + kAnimationModeCombatAim = 5, + kAnimationModeCombatShoot = 6, kAnimationModeCombatWalk = 7, - kAnimationModeCombatRun = 8 + kAnimationModeCombatRun = 8, + kAnimationModeFeeding = 52 }; enum SceneLoopMode { @@ -804,6 +807,21 @@ enum Elevators { kElevatorPS = 2 }; +// enum SceneObjectOffset { +// kSceneObjectActorIdStart = 0, +// kSceneObjectActorIdEnd = kSceneObjectActorIdStart + 73, +// kSceneObjectItemIdStart = kSceneObjectActorIdEnd + 1, +// kSceneObjectItemIdEnd = kSceneObjectItemIdStart + 123, +// kSceneObjectObjectIdStart = kSceneObjectItemIdEnd + 1, +// kSceneObjectObjectIdEnd = kSceneObjectObjectIdStart + 95 +// }; + +enum SceneObjectOffset { + kSceneObjectOffsetActors = 0, + kSceneObjectOffsetItems = 74, + kSceneObjectOffsetObjects = 198 +}; + } // End of namespace BladeRunner #endif diff --git a/engines/bladerunner/item.cpp b/engines/bladerunner/item.cpp index eafc99c80f..1d2de92703 100644 --- a/engines/bladerunner/item.cpp +++ b/engines/bladerunner/item.cpp @@ -47,7 +47,7 @@ Item::Item(BladeRunnerEngine *vm) { _screenX = 0; _screenY = 0; _depth = 0.0f; - _isTargetable = false; + _isTarget = false; _isSpinning = false; _facingChange = 0; _isVisible = true; @@ -69,8 +69,8 @@ void Item::getWidthHeight(int *width, int *height) const { *height = _height; } -bool Item::isTargetable() const { - return _isTargetable; +bool Item::isTarget() const { + return _isTarget; } bool Item::tick(Common::Rect *screenRect, bool special) { @@ -134,7 +134,7 @@ void Item::setXYZ(Vector3 position) { _depth = screenPosition.z * 25.5f; } -void Item::setup(int itemId, int setId, int animationId, Vector3 position, int facing, int height, int width, bool isTargetableFlag, bool isVisibleFlag, bool isPoliceMazeEnemyFlag) { +void Item::setup(int itemId, int setId, int animationId, Vector3 position, int facing, int height, int width, bool isTarget, bool isVisible, bool isPoliceMazeEnemy) { _itemId = itemId; _setId = setId; _animationId = animationId; @@ -142,9 +142,9 @@ void Item::setup(int itemId, int setId, int animationId, Vector3 position, int f _angle = facing * (M_PI / 512.0f); _width = width; _height = height; - _isTargetable = isTargetableFlag; - _isVisible = isVisibleFlag; - _isPoliceMazeEnemy = isPoliceMazeEnemyFlag; + _isTarget = isTarget; + _isVisible = isVisible; + _isPoliceMazeEnemy = isPoliceMazeEnemy; setXYZ(position); _screenRectangle.bottom = -1; _screenRectangle.right = -1; @@ -152,4 +152,12 @@ void Item::setup(int itemId, int setId, int animationId, Vector3 position, int f _screenRectangle.left = -1; } +bool Item::isUnderMouse(int mouseX, int mouseY) const { + return _isVisible + && mouseX >= _screenRectangle.left - 10 + && mouseX <= _screenRectangle.right + 10 + && mouseY >= _screenRectangle.top - 10 + && mouseY <= _screenRectangle.bottom + 10; +} + } // End of namespace BladeRunner diff --git a/engines/bladerunner/item.h b/engines/bladerunner/item.h index e14aaa5c4f..09f5ae6841 100644 --- a/engines/bladerunner/item.h +++ b/engines/bladerunner/item.h @@ -52,7 +52,7 @@ class Item { int _screenX; int _screenY; float _depth; - bool _isTargetable; + bool _isTarget; bool _isSpinning; int _facingChange; bool _isVisible; @@ -65,10 +65,12 @@ public: void setXYZ(Vector3 position); void getWidthHeight(int *width, int *height) const; - bool isTargetable() const; + bool isTarget() const; bool tick(Common::Rect *screenRect, bool special); - void setup(int itemId, int setId, int animationId, Vector3 position, int facing, int height, int width, bool isTargetableFlag, bool isVisibleFlag, bool isPoliceMazeEnemyFlag); + void setup(int itemId, int setId, int animationId, Vector3 position, int facing, int height, int width, bool isTarget, bool isVisible, bool isPoliceMazeEnemy); + + bool isUnderMouse(int mouseX, int mouseY) const; }; } diff --git a/engines/bladerunner/items.cpp b/engines/bladerunner/items.cpp index e85366e3f6..5e79f7a39b 100644 --- a/engines/bladerunner/items.cpp +++ b/engines/bladerunner/items.cpp @@ -59,15 +59,15 @@ void Items::tick() { if (_items[i]->_setId != setId) { continue; } - bool set14NotTarget = setId == kSetPS10_PS11_PS12_PS13 && !_items[i]->isTargetable(); + bool notPoliceMazeTarget = setId == kSetPS10_PS11_PS12_PS13 && !_items[i]->isTarget(); Common::Rect screenRect; - if (_items[i]->tick(&screenRect, set14NotTarget)) { + if (_items[i]->tick(&screenRect, notPoliceMazeTarget)) { _vm->_zbuffer->mark(screenRect); } } } -bool Items::addToWorld(int itemId, int animationId, int setId, Vector3 position, int facing, int height, int width, bool isTargetableFlag, bool isVisibleFlag, bool isPoliceMazeEnemyFlag, bool addToSetFlag) { +bool Items::addToWorld(int itemId, int animationId, int setId, Vector3 position, int facing, int height, int width, bool isTarget, bool isVisible, bool isPoliceMazeEnemy, bool addToSet) { if (_items.size() >= 100) { return false; } @@ -77,11 +77,11 @@ bool Items::addToWorld(int itemId, int animationId, int setId, Vector3 position, } Item *item = new Item(_vm); - item->setup(itemId, setId, animationId, position, facing, height, width, isTargetableFlag, isVisibleFlag, isPoliceMazeEnemyFlag); + item->setup(itemId, setId, animationId, position, facing, height, width, isTarget, isVisible, isPoliceMazeEnemy); _items.push_back(item); - if (addToSetFlag && setId == _vm->_scene->getSetId()) { - return _vm->_sceneObjects->addItem(itemId + kSceneObjectOffsetItems, &item->_boundingBox, &item->_screenRectangle, isTargetableFlag, isVisibleFlag); + if (addToSet && setId == _vm->_scene->getSetId()) { + return _vm->_sceneObjects->addItem(itemId + kSceneObjectOffsetItems, &item->_boundingBox, &item->_screenRectangle, isTarget, isVisible); } return true; } @@ -94,7 +94,7 @@ bool Items::addToSet(int setId) { for (int i = 0; i < itemCount; i++) { Item *item = _vm->_items->_items[i]; if (item->_setId == setId) { - _vm->_sceneObjects->addItem(item->_itemId + kSceneObjectOffsetItems, &item->_boundingBox, &item->_screenRectangle, item->isTargetable(), item->_isVisible); + _vm->_sceneObjects->addItem(item->_itemId + kSceneObjectOffsetItems, &item->_boundingBox, &item->_screenRectangle, item->isTarget(), item->_isVisible); } } return true; @@ -116,10 +116,29 @@ bool Items::remove(int itemId) { return true; } +bool Items::isTarget(int itemId) const { + int itemIndex = findItem(itemId); + if (itemIndex == -1) { + return false; + } + return _items[itemIndex]->isTarget(); +} + +int Items::findTargetUnderMouse(int mouseX, int mouseY) const { + int setId = _vm->_scene->getSetId(); + for (int i = 0 ; i < (int)_items.size(); ++i) { + if (_items[i]->_setId == setId && _items[i]->isTarget() && _items[i]->isUnderMouse(mouseX, mouseY)) { + return _items[i]->_itemId; + } + } + return -1; +} + int Items::findItem(int itemId) const { for (int i = 0; i < (int)_items.size(); i++) { - if (_items[i]->_itemId == itemId) + if (_items[i]->_itemId == itemId) { return i; + } } return -1; } diff --git a/engines/bladerunner/items.h b/engines/bladerunner/items.h index c49231f30e..711abc606f 100644 --- a/engines/bladerunner/items.h +++ b/engines/bladerunner/items.h @@ -43,10 +43,13 @@ public: void getWidthHeight(int itemId, int *width, int *height) const; void tick(); - bool addToWorld(int itemId, int animationId, int setId, Vector3 position, int facing, int height, int width, bool isTargetableFlag, bool isVisibleFlag, bool isPoliceMazeEnemyFlag, bool addToSetFlag); + bool addToWorld(int itemId, int animationId, int setId, Vector3 position, int facing, int height, int width, bool isTarget, bool isVisible, bool isPoliceMazeEnemy, bool addToSet); bool addToSet(int itemId); bool remove(int itemId); + bool isTarget(int itemId) const; + int findTargetUnderMouse(int mouseX, int mouseY) const; + private: int findItem(int itemId) const; }; diff --git a/engines/bladerunner/mouse.cpp b/engines/bladerunner/mouse.cpp index 3dfd1fe57e..7d67e98de5 100644 --- a/engines/bladerunner/mouse.cpp +++ b/engines/bladerunner/mouse.cpp @@ -22,11 +22,16 @@ #include "bladerunner/mouse.h" +#include "bladerunner/actor.h" #include "bladerunner/bladerunner.h" +#include "bladerunner/combat.h" #include "bladerunner/dialogue_menu.h" +#include "bladerunner/game_constants.h" +#include "bladerunner/items.h" #include "bladerunner/regions.h" #include "bladerunner/scene.h" #include "bladerunner/scene_objects.h" +#include "bladerunner/settings.h" #include "bladerunner/shape.h" #include "bladerunner/view.h" #include "bladerunner/zbuffer.h" @@ -267,22 +272,25 @@ void Mouse::tick(int x, int y) { return; } - Vector3 mousePosition = getXYZ(x, y); + Vector3 scenePosition = getXYZ(x, y); int cursorId = 0; bool isClickable = false; bool isObstacle = false; bool isTarget = false; - int sceneObjectId = _vm->_sceneObjects->findByXYZ(&isClickable, &isObstacle, &isTarget, mousePosition.x, mousePosition.y, mousePosition.z, 1, 0, 1); + int sceneObjectId = _vm->_sceneObjects->findByXYZ(&isClickable, &isObstacle, &isTarget, scenePosition, true, false, true); int exitType = _vm->_scene->_exits->getTypeAtXY(x, y); - if (sceneObjectId >= 0 && sceneObjectId <= 74) { + if (sceneObjectId >= kSceneObjectOffsetActors && sceneObjectId < kSceneObjectOffsetItems) { exitType = -1; } if (exitType != -1) { switch (exitType) { + case 0: + cursorId = 12; + break; case 1: cursorId = 13; break; @@ -292,26 +300,76 @@ void Mouse::tick(int x, int y) { case 3: cursorId = 15; break; - default: - cursorId = 12; } setCursor(cursorId); return; } - if (true /* not in combat */) { - if (sceneObjectId == 0 - || (sceneObjectId >= 0 && isClickable) - || _vm->_scene->_regions->getRegionAtXY(x, y) >= 0) { + if (!_vm->_combat->isActive()) { + if (sceneObjectId == kActorMcCoy + kSceneObjectOffsetActors + || (sceneObjectId > 0 && isClickable) + || _vm->_scene->_regions->getRegionAtXY(x, y) >= 0) { cursorId = 1; } setCursor(cursorId); return; } + int animationMode = _vm->_playerActor->getAnimationMode(); + int actorId = Actor::findTargetUnderMouse(_vm, x, y); + int itemId = _vm->_items->findTargetUnderMouse(x, y); + + bool isObject = isTarget && sceneObjectId >= kSceneObjectOffsetObjects && sceneObjectId <= 293; + + if (!_vm->_playerActor->isMoving()) { + if (actorId >= 0) { + _vm->_playerActor->faceActor(actorId, false); + } else if (itemId >= 0) { + _vm->_playerActor->faceItem(itemId, false); + } else if (isObject) { + _vm->_playerActor->faceXYZ(scenePosition, false); + } + } + + if (actorId >= 0 || itemId >= 0 || isObject) { + switch (_vm->_settings->getAmmoType()) { + case 0: + cursorId = 7; + break; + case 1: + cursorId = 9; + break; + case 2: + cursorId = 11; + break; + } + + if (!_vm->_playerActor->isMoving() && animationMode != kAnimationModeCombatAim && animationMode != 22 && animationMode != 49) { + _vm->_playerActor->changeAnimationMode(kAnimationModeCombatAim, false); + } + } else { + switch (_vm->_settings->getAmmoType()) { + case 0: + cursorId = 6; + break; + case 1: + cursorId = 8; + break; + case 2: + cursorId = 10; + break; + } + if (!_vm->_playerActor->isMoving() && animationMode != kAnimationModeCombatIdle && animationMode != 22 && animationMode != 49) { + _vm->_playerActor->changeAnimationMode(kAnimationModeCombatIdle, false); + } + } setCursor(cursorId); } +bool Mouse::isInactive() const { + return _cursor == 6 || _cursor == 8 || _cursor == 10; +} + // TEST: RC01 after intro: [290, 216] -> [-204.589249 51.450668 7.659241] Vector3 Mouse::getXYZ(int x, int y) const { if (_vm->_scene->getSetId() == -1) diff --git a/engines/bladerunner/mouse.h b/engines/bladerunner/mouse.h index 64b01992d0..2f33d72583 100644 --- a/engines/bladerunner/mouse.h +++ b/engines/bladerunner/mouse.h @@ -62,6 +62,7 @@ public: void updateCursorFrame(); void tick(int x, int y); + bool isInactive() const; // private: Vector3 getXYZ(int x, int y) const; diff --git a/engines/bladerunner/movement_track.cpp b/engines/bladerunner/movement_track.cpp index 13b60d1d93..47eb56a098 100644 --- a/engines/bladerunner/movement_track.cpp +++ b/engines/bladerunner/movement_track.cpp @@ -41,15 +41,15 @@ void MovementTrack::reset() { _entries[i].waypointId = -1; _entries[i].delay = -1; _entries[i].angle = -1; - _entries[i].running = 0; + _entries[i].run = false; } } -int MovementTrack::append(int waypointId, int delay, int running) { - return append(waypointId, delay, -1, running); +int MovementTrack::append(int waypointId, int delay, bool run) { + return append(waypointId, delay, -1, run); } -int MovementTrack::append(int waypointId, int delay, int angle, int running) { +int MovementTrack::append(int waypointId, int delay, int angle, bool run) { if (_lastIndex >= kSize) { return 0; } @@ -57,7 +57,7 @@ int MovementTrack::append(int waypointId, int delay, int angle, int running) { _entries[_lastIndex].waypointId = waypointId; _entries[_lastIndex].delay = delay; _entries[_lastIndex].angle = angle; - _entries[_lastIndex].running = running; + _entries[_lastIndex].run = run; _lastIndex++; _hasNext = true; @@ -90,18 +90,18 @@ bool MovementTrack::hasNext() const { return _hasNext; } -bool MovementTrack::next(int *waypointId, int *delay, int *angle, int *running) { +bool MovementTrack::next(int *waypointId, int *delay, int *angle, bool *run) { if (_currentIndex < _lastIndex && _hasNext) { *waypointId = _entries[_currentIndex].waypointId; *delay = _entries[_currentIndex].delay; *angle = _entries[_currentIndex].angle; - *running = _entries[_currentIndex++].running; + *run = _entries[_currentIndex++].run; return true; } else { *waypointId = -1; *delay = -1; *angle = -1; - *running = 0; + *run = false; _hasNext = false; return false; } diff --git a/engines/bladerunner/movement_track.h b/engines/bladerunner/movement_track.h index 174b222b1e..cba9b690ff 100644 --- a/engines/bladerunner/movement_track.h +++ b/engines/bladerunner/movement_track.h @@ -34,10 +34,10 @@ class MovementTrack { static const int kSize = 100; struct Entry { - int waypointId; - int delay; - int angle; - int running; + int waypointId; + int delay; + int angle; + bool run; }; int _currentIndex; @@ -49,15 +49,15 @@ class MovementTrack { public: MovementTrack(); ~MovementTrack(); - int append(int waypointId, int delay, int running); - int append(int waypointId, int delay, int angle, int running); + int append(int waypointId, int delay, bool run); + int append(int waypointId, int delay, int angle, bool run); void flush(); void repeat(); void pause(); void unpause(); bool isPaused() const; bool hasNext() const; - bool next(int *waypointId, int *delay, int *angle, int *running); + bool next(int *waypointId, int *delay, int *angle, bool *run); //int saveGame(); diff --git a/engines/bladerunner/scene.cpp b/engines/bladerunner/scene.cpp index f20c0be0ef..c327e80fa7 100644 --- a/engines/bladerunner/scene.cpp +++ b/engines/bladerunner/scene.cpp @@ -76,13 +76,15 @@ bool Scene::open(int setId, int sceneId, bool isLoadingGame) { _vm->_actorDialogueQueue->flush(1, false); } + _vm->walkingReset(); + _setId = setId; _sceneId = sceneId; const Common::String sceneName = _vm->_gameInfo->getSceneName(_sceneId); if (isLoadingGame) { - // TODO: Set up overlays + // TODO: _vm->overlays->resume() } else { _regions->clear(); _exits->clear(); @@ -162,7 +164,7 @@ bool Scene::open(int setId, int sceneId, bool isLoadingGame) { actor->getScreenRectangle(), 1, 0, - actor->isTargetable(), + actor->isTarget(), actor->isRetired()); } } diff --git a/engines/bladerunner/scene_objects.cpp b/engines/bladerunner/scene_objects.cpp index 9f4adb5862..5d22be4a38 100644 --- a/engines/bladerunner/scene_objects.cpp +++ b/engines/bladerunner/scene_objects.cpp @@ -48,9 +48,9 @@ SceneObjects::~SceneObjects() { void SceneObjects::clear() { for (int i = 0; i < kSceneObjectCount; ++i) { - _sceneObjects[i].sceneObjectId = -1; - _sceneObjects[i].sceneObjectType = kSceneObjectTypeUnknown; - _sceneObjects[i].distanceToCamera = 0; + _sceneObjects[i].id = -1; + _sceneObjects[i].type = kSceneObjectTypeUnknown; + _sceneObjects[i].distanceToCamera = 0.0f; _sceneObjects[i].isPresent = false; _sceneObjects[i].isClickable = false; _sceneObjects[i].isObstacle = false; @@ -95,7 +95,7 @@ bool SceneObjects::remove(int sceneObjectId) { return true; } -int SceneObjects::findByXYZ(bool *isClickable, bool *isObstacle, bool *isTarget, float x, float y, float z, bool findClickables, bool findObstacles, bool findTargets) const { +int SceneObjects::findByXYZ(bool *isClickable, bool *isObstacle, bool *isTarget, Vector3 &position, bool findClickables, bool findObstacles, bool findTargets) const { *isClickable = false; *isObstacle = false; *isTarget = false; @@ -110,16 +110,16 @@ int SceneObjects::findByXYZ(bool *isClickable, bool *isObstacle, bool *isTarget, (findTargets && sceneObject->isTarget)) { BoundingBox boundingBox = sceneObject->boundingBox; - if (sceneObject->sceneObjectType == kSceneObjectTypeObject || sceneObject->sceneObjectType == kSceneObjectTypeItem) { + if (sceneObject->type == kSceneObjectTypeObject || sceneObject->type == kSceneObjectTypeItem) { boundingBox.expand(-4.0, 0.0, -4.0, 4.0, 0.0, 4.0); } - if (boundingBox.inside(x, y, z)) { + if (boundingBox.inside(position)) { *isClickable = sceneObject->isClickable; *isObstacle = sceneObject->isObstacle; *isTarget = sceneObject->isTarget; - return sceneObject->sceneObjectId; + return sceneObject->id; } } } @@ -127,7 +127,7 @@ int SceneObjects::findByXYZ(bool *isClickable, bool *isObstacle, bool *isTarget, return -1; } -bool SceneObjects::existsOnXZ(int exceptSceneObjectId, float x, float z, bool a5, bool a6) const { +bool SceneObjects::existsOnXZ(int exceptSceneObjectId, float x, float z, bool movingActorIsObstacle, bool standingActorIsObstacle) const { float xMin = x - 12.5f; float xMax = x + 12.5f; float zMin = z - 12.5f; @@ -138,20 +138,20 @@ bool SceneObjects::existsOnXZ(int exceptSceneObjectId, float x, float z, bool a5 if (count > 0) { for (int i = 0; i < count; i++) { const SceneObject *sceneObject = &_sceneObjects[_sceneObjectsSortedByDistance[i]]; - bool v13 = false; - if (sceneObject->sceneObjectType == kSceneObjectTypeActor) { + bool isObstacle = false; + if (sceneObject->type == kSceneObjectTypeActor) { if (sceneObject->isRetired) { - v13 = false; + isObstacle = false; } else if (sceneObject->isMoving) { - v13 = a5 != 0; + isObstacle = movingActorIsObstacle != 0; } else { - v13 = a6 != 0; + isObstacle = standingActorIsObstacle != 0; } } else { - v13 = sceneObject->isObstacle; + isObstacle = sceneObject->isObstacle; } - if (v13 && sceneObject->sceneObjectId != exceptSceneObjectId) { + if (isObstacle && sceneObject->id != exceptSceneObjectId) { float x1, y1, z1, x2, y2, z2; sceneObject->boundingBox.getXYZ(&x1, &y1, &z1, &x2, &y2, &z2); if (z1 <= zMax && z2 >= zMin && x1 <= xMax && x2 >= xMin) { @@ -167,7 +167,7 @@ int SceneObjects::findById(int sceneObjectId) const { for (int i = 0; i < _count; ++i) { int j = this->_sceneObjectsSortedByDistance[i]; - if (_sceneObjects[j].isPresent && _sceneObjects[j].sceneObjectId == sceneObjectId) { + if (_sceneObjects[j].isPresent && _sceneObjects[j].id == sceneObjectId) { return j; } } @@ -180,11 +180,11 @@ bool SceneObjects::addSceneObject(int sceneObjectId, SceneObjectType sceneObject return false; } - _sceneObjects[index].sceneObjectId = sceneObjectId; - _sceneObjects[index].sceneObjectType = sceneObjectType; + _sceneObjects[index].id = sceneObjectId; + _sceneObjects[index].type = sceneObjectType; _sceneObjects[index].isPresent = true; _sceneObjects[index].boundingBox = *boundingBox; - _sceneObjects[index].screenRectangle = *screenRectangle; + _sceneObjects[index].screenRectangle = screenRectangle; _sceneObjects[index].isClickable = isClickable; _sceneObjects[index].isObstacle = isObstacle; _sceneObjects[index].unknown1 = unknown1; @@ -237,7 +237,7 @@ void SceneObjects::setRetired(int sceneObjectId, bool isRetired) { _sceneObjects[i].isRetired = isRetired; } -bool SceneObjects::isBetweenTwoXZ(int sceneObjectId, float x1, float z1, float x2, float z2) const { +bool SceneObjects::isBetween(float sourceX, float sourceZ, float targetX, float targetZ, int sceneObjectId) const { int i = findById(sceneObjectId); if (i == -1) { return false; @@ -246,15 +246,46 @@ bool SceneObjects::isBetweenTwoXZ(int sceneObjectId, float x1, float z1, float x float objectX1, objectY1, objectZ1, objectX2, objectY2, objectZ2; _sceneObjects[i].boundingBox.getXYZ(&objectX1, &objectY1, &objectZ1, &objectX2, &objectY2, &objectZ2); - //TODO - // if (!lineIntersectection(sourceX, sourceZ, targetX, targetZ, objectX1, objectZ1, objectX2, objectZ1, &intersectionX, &intersectionY, &v18) - // && !lineIntersectection(sourceX, sourceZ, targetX, targetZ, objectX2, objectZ1, objectX2, objectZ2, &intersectionX, &intersectionY, &v18) - // && !lineIntersectection(sourceX, sourceZ, targetX, targetZ, objectX2, objectZ2, objectX1, objectZ2, &intersectionX, &intersectionY, &v18) - // && !lineIntersectection(sourceX, sourceZ, targetX, targetZ, objectX1, objectZ2, objectX1, objectZ1, &intersectionX, &intersectionY, &v18)) - // return false; - return true; + Vector2 intersection; + return lineIntersection(Vector2(sourceX, sourceZ), Vector2(targetX, targetZ), Vector2(objectX1, objectZ1), Vector2(objectX2, objectZ1), &intersection) + || lineIntersection(Vector2(sourceX, sourceZ), Vector2(targetX, targetZ), Vector2(objectX2, objectZ1), Vector2(objectX2, objectZ2), &intersection) + || lineIntersection(Vector2(sourceX, sourceZ), Vector2(targetX, targetZ), Vector2(objectX2, objectZ2), Vector2(objectX1, objectZ2), &intersection) + || lineIntersection(Vector2(sourceX, sourceZ), Vector2(targetX, targetZ), Vector2(objectX1, objectZ2), Vector2(objectX1, objectZ1), &intersection); } +bool SceneObjects::isObstacleBetween(float sourceX, float sourceZ, float targetX, float targetZ, float altitude, int exceptSceneObjectId) const { + for (int i = 0; i < _count; ++i) { + const SceneObject *sceneObject = &_sceneObjects[_sceneObjectsSortedByDistance[i]]; + + if (sceneObject->type == kSceneObjectTypeActor || !sceneObject->isObstacle || sceneObject->id == exceptSceneObjectId) { + continue; + } + + float objectX1, objectY1, objectZ1, objectX2, objectY2, objectZ2; + _sceneObjects[i].boundingBox.getXYZ(&objectX1, &objectY1, &objectZ1, &objectX2, &objectY2, &objectZ2); + + if (84.0f <= objectY1 - altitude || 72.0f >= objectY2 - altitude) { + continue; + } + + float xAdjustement = (objectX2 - objectX1) * 0.1f; + float zAdjustement = (objectZ2 - objectZ1) * 0.1f; + + objectX1 = objectX1 + xAdjustement; + objectZ1 = objectZ1 + zAdjustement; + objectX2 = objectX2 - xAdjustement; + objectZ2 = objectZ2 - zAdjustement; + + Vector2 intersection; + if (lineIntersection(Vector2(sourceX, sourceZ), Vector2(targetX, targetZ), Vector2(objectX1, objectZ1), Vector2(objectX2, objectZ1), &intersection) + || lineIntersection(Vector2(sourceX, sourceZ), Vector2(targetX, targetZ), Vector2(objectX2, objectZ1), Vector2(objectX2, objectZ2), &intersection) + || lineIntersection(Vector2(sourceX, sourceZ), Vector2(targetX, targetZ), Vector2(objectX2, objectZ2), Vector2(objectX1, objectZ2), &intersection) + || lineIntersection(Vector2(sourceX, sourceZ), Vector2(targetX, targetZ), Vector2(objectX1, objectZ2), Vector2(objectX1, objectZ1), &intersection)) { + return true; + } + } + return false; +} void SceneObjects::setIsClickable(int sceneObjectId, bool isClickable) { int i = findById(sceneObjectId); @@ -282,12 +313,12 @@ void SceneObjects::setIsTarget(int sceneObjectId, bool isTarget) { void SceneObjects::updateObstacles() { _vm->_obstacles->clear(); - for(int i = 0; i < _count; i++) { + for (int i = 0; i < _count; ++i) { int index = _sceneObjectsSortedByDistance[i]; - SceneObject sceneObject = _sceneObjects[index]; - if(sceneObject.isObstacle) { + const SceneObject *sceneObject = &_sceneObjects[index]; + if (sceneObject->isObstacle) { float x0, y0, z0, x1, y1, z1; - sceneObject.boundingBox.getXYZ(&x0, &y0, &z0, &x1, &y1, &z1); + sceneObject->boundingBox.getXYZ(&x0, &y0, &z0, &x1, &y1, &z1); _vm->_obstacles->add(x0, z0, x1, z1); } } diff --git a/engines/bladerunner/scene_objects.h b/engines/bladerunner/scene_objects.h index 23f6f985ad..624deee119 100644 --- a/engines/bladerunner/scene_objects.h +++ b/engines/bladerunner/scene_objects.h @@ -39,12 +39,6 @@ enum SceneObjectType { kSceneObjectTypeItem = 2 }; -enum SceneObjectOffset { - kSceneObjectOffsetActors = 0, - kSceneObjectOffsetItems = 74, - kSceneObjectOffsetObjects = 198 -}; - class SceneObjects { #if BLADERUNNER_DEBUG_RENDERING friend class BladeRunnerEngine; @@ -52,10 +46,10 @@ class SceneObjects { static const int kSceneObjectCount = 115; struct SceneObject { - int sceneObjectId; - SceneObjectType sceneObjectType; + int id; + SceneObjectType type; BoundingBox boundingBox; - Common::Rect screenRectangle; + Common::Rect *screenRectangle; float distanceToCamera; bool isPresent; bool isClickable; @@ -82,16 +76,18 @@ public: bool addItem(int sceneObjectId, BoundingBox *boundingBox, Common::Rect *screenRectangle, bool isTarget, bool isObstacle); bool remove(int sceneObjectId); void clear(); - int findByXYZ(bool *isClickable, bool *isObstacle, bool *isTarget, float x, float y, float z, bool findClickables, bool findObstacles, bool findTargets) const; - bool existsOnXZ(int exceptSceneObjectId, float x, float z, bool a5, bool a6) const; + int findByXYZ(bool *isClickable, bool *isObstacle, bool *isTarget, Vector3 &position, bool findClickables, bool findObstacles, bool findTargets) const; + bool existsOnXZ(int exceptSceneObjectId, float x, float z, bool movingActorIsObstacle, bool standingActorIsObstacle) const; void setMoving(int sceneObjectId, bool isMoving); void setRetired(int sceneObjectId, bool isRetired); - bool isBetweenTwoXZ(int sceneObjectId, float x1, float z1, float x2, float z2) const; + bool isBetween(float sourceX, float sourceZ, float targetX, float targetZ, int sceneObjectId) const; + bool isObstacleBetween(float sourceX, float sourceZ, float targetX, float targetZ, float altitude, int exceptSceneObjectId) const; void setIsClickable(int sceneObjectId, bool isClickable); void setIsObstacle(int sceneObjectId, bool isObstacle); void setIsTarget(int sceneObjectId, bool isTarget); void updateObstacles(); + private: int findById(int sceneObjectId) const; bool addSceneObject(int sceneObjectId, SceneObjectType sceneObjectType, BoundingBox *boundingBox, Common::Rect *screenRectangle, bool isClickable, bool isObstacle, uint8 unknown1, bool isTarget, bool isMoving, bool isRetired); diff --git a/engines/bladerunner/script/ai/leon.cpp b/engines/bladerunner/script/ai/leon.cpp index 9d82464708..3d136eea4e 100644 --- a/engines/bladerunner/script/ai/leon.cpp +++ b/engines/bladerunner/script/ai/leon.cpp @@ -128,10 +128,11 @@ void AIScriptLeon::OtherAgentEnteredCombatMode(int otherActorId, int combatMode) void AIScriptLeon::ShotAtAndMissed() {} -void AIScriptLeon::ShotAtAndHit() { +bool AIScriptLeon::ShotAtAndHit() { if (Actor_Query_Goal_Number(kActorLeon) != 7) { Actor_Set_Goal_Number(kActorLeon, 7); } + return false; } void AIScriptLeon::Retired(int byActorId) {} @@ -351,7 +352,7 @@ bool AIScriptLeon::UpdateAnimation(int *animation, int *frame) { bool AIScriptLeon::ChangeAnimationMode(int mode) { switch (mode) { - case 0: + case kAnimationModeIdle: switch (_animationState) { case 2: case 3: @@ -370,7 +371,7 @@ bool AIScriptLeon::ChangeAnimationMode(int mode) { break; } break; - case 1: + case kAnimationModeWalk: _animationState = 1; _animationFrame = 0; break; @@ -379,7 +380,7 @@ bool AIScriptLeon::ChangeAnimationMode(int mode) { _animationFrame = 0; var_45EDAC = 0; break; - case 6: + case kAnimationModeCombatShoot: _animationState = 10; _animationFrame = 0; break; diff --git a/engines/bladerunner/script/ai/maggie.cpp b/engines/bladerunner/script/ai/maggie.cpp index 3fd213f1de..89dd651c01 100644 --- a/engines/bladerunner/script/ai/maggie.cpp +++ b/engines/bladerunner/script/ai/maggie.cpp @@ -139,7 +139,7 @@ void AIScriptMaggie::ClickedByPlayer() { Actor_Set_Targetable(kActorMaggie, true); AI_Movement_Track_Flush(kActorMaggie); Actor_Face_Actor(kActorMcCoy, kActorMaggie, true); - Actor_Says(kActorMcCoy, 2400, 52); + Actor_Says(kActorMcCoy, 2400, kAnimationModeFeeding); } return; // true } @@ -210,10 +210,11 @@ void AIScriptMaggie::OtherAgentEnteredCombatMode(int otherActorId, int combatMod void AIScriptMaggie::ShotAtAndMissed() { } -void AIScriptMaggie::ShotAtAndHit() { +bool AIScriptMaggie::ShotAtAndHit() { AI_Movement_Track_Flush(kActorMaggie); Actor_Set_Goal_Number(kActorMaggie, 414); Actor_Set_Targetable(kActorMaggie, false); + return false; } void AIScriptMaggie::Retired(int byActorId) { @@ -270,7 +271,7 @@ bool AIScriptMaggie::GoalChanged(int currentGoalNumber, int newGoalNumber) { Loop_Actor_Walk_To_Actor(kActorMaggie, kActorMcCoy, 48, false, false); Actor_Face_Actor(kActorMcCoy, kActorMaggie, true); Actor_Face_Actor(kActorMaggie, kActorMcCoy, false); - Actor_Says(kActorMcCoy, 2400, 52); + Actor_Says(kActorMcCoy, 2400, kAnimationModeFeeding); Actor_Set_Goal_Number(kActorMaggie, 8); Player_Gains_Control(); return true; @@ -593,7 +594,7 @@ bool AIScriptMaggie::ChangeAnimationMode(int mode) { } } break; - case 52: + case kAnimationModeFeeding: if (Game_Flag_Query(kFlagMaggieIsHurt)) { _animationState = kMaggieStateHurtJumping; _animationFrame = 0; diff --git a/engines/bladerunner/script/ai/mccoy.cpp b/engines/bladerunner/script/ai/mccoy.cpp index f84c9a9d52..3f3888f99f 100644 --- a/engines/bladerunner/script/ai/mccoy.cpp +++ b/engines/bladerunner/script/ai/mccoy.cpp @@ -219,7 +219,8 @@ void AIScriptMcCoy::OtherAgentEnteredCombatMode(int otherActorId, int combatMode void AIScriptMcCoy::ShotAtAndMissed() { } -void AIScriptMcCoy::ShotAtAndHit() { +bool AIScriptMcCoy::ShotAtAndHit() { + return false; } void AIScriptMcCoy::Retired(int byActorId) { @@ -633,7 +634,7 @@ bool AIScriptMcCoy::UpdateAnimation(int *animation, int *frame) { *animation = 32; _animationFrame++; if (_animationFrame == 7) { - Actor_Change_Animation_Mode(kActorMaggie, 52); + Actor_Change_Animation_Mode(kActorMaggie, kAnimationModeFeeding); } if (_animationFrame >= Slice_Animation_Query_Number_Of_Frames(*animation)) { *animation = 19; @@ -1244,7 +1245,7 @@ bool AIScriptMcCoy::ChangeAnimationMode(int mode) { _animationState = 70; } return true; - case 52: + case kAnimationModeFeeding: _animationState = 55; _animationFrame = 0; return true; @@ -1488,19 +1489,19 @@ bool AIScriptMcCoy::ChangeAnimationMode(int mode) { dword_45A0F4 = 21; } return true; - case 8: + case kAnimationModeCombatRun: if (_animationState != 27 && _animationState != 50) { _animationState = 37; _animationFrame = 0; } return true; - case 7: + case kAnimationModeCombatWalk: if (_animationState != 27 && _animationState != 50) { _animationState = 36; _animationFrame = 0; } return true; - case 6: + case kAnimationModeCombatShoot: _animationState = 21; _animationFrame = 0; return true; @@ -1524,7 +1525,7 @@ bool AIScriptMcCoy::ChangeAnimationMode(int mode) { break; } return true; - case 4: + case kAnimationModeCombatIdle: switch (_animationState) { case 22: _animationState = 19; @@ -1586,7 +1587,7 @@ bool AIScriptMcCoy::ChangeAnimationMode(int mode) { _animationNext = 20; } return true; - case 2: + case kAnimationModeRun: if (_animationState == 27 || _animationState == 50) { return true; } @@ -1598,7 +1599,7 @@ bool AIScriptMcCoy::ChangeAnimationMode(int mode) { _animationState = 58; _animationFrame = 4; return true; - case 1: + case kAnimationModeWalk: if (_animationState == 27 || _animationState == 50) { return true; } @@ -1610,7 +1611,7 @@ bool AIScriptMcCoy::ChangeAnimationMode(int mode) { _animationState = 58; _animationFrame = 0; return true; - case 0: + case kAnimationModeIdle: if (Game_Flag_Query(550)) { if (_animationFrame > 6) { _animationState = 57; diff --git a/engines/bladerunner/script/ai/officer_leary.cpp b/engines/bladerunner/script/ai/officer_leary.cpp index 86b3ace09c..c95ba202ca 100644 --- a/engines/bladerunner/script/ai/officer_leary.cpp +++ b/engines/bladerunner/script/ai/officer_leary.cpp @@ -209,10 +209,11 @@ void AIScriptOfficerLeary::OtherAgentEnteredCombatMode(int otherActorId, int com void AIScriptOfficerLeary::ShotAtAndMissed() {} -void AIScriptOfficerLeary::ShotAtAndHit() { +bool AIScriptOfficerLeary::ShotAtAndHit() { if (Actor_Query_Goal_Number(kActorOfficerLeary) == 307) { Actor_Set_Health(kActorOfficerLeary, 50, 50); } + return false; } void AIScriptOfficerLeary::Retired(int byActorId) { diff --git a/engines/bladerunner/script/ai/runciter.cpp b/engines/bladerunner/script/ai/runciter.cpp index c18dd2d5f0..d1d7a08182 100644 --- a/engines/bladerunner/script/ai/runciter.cpp +++ b/engines/bladerunner/script/ai/runciter.cpp @@ -139,7 +139,7 @@ void AIScriptRunciter::OtherAgentEnteredCombatMode(int otherActorId, int combatM void AIScriptRunciter::ShotAtAndMissed() {} -void AIScriptRunciter::ShotAtAndHit() { +bool AIScriptRunciter::ShotAtAndHit() { Actor_Set_Targetable(kActorRunciter, false); Actor_Change_Animation_Mode(kActorRunciter, 48); Actor_Set_Goal_Number(kActorRunciter, 599); @@ -153,6 +153,7 @@ void AIScriptRunciter::ShotAtAndHit() { Actor_Voice_Over(2090, kActorVoiceOver); } Actor_Modify_Friendliness_To_Other(kActorClovis, kActorMcCoy, 3); + return false; } void AIScriptRunciter::Retired(int byActorId) {} @@ -472,8 +473,8 @@ bool AIScriptRunciter::UpdateAnimation(int *animation, int *frame) { bool AIScriptRunciter::ChangeAnimationMode(int mode) { switch (mode) { - case kAnimationModeCombatIdle: - if (_animationState <= 11) { + case kAnimationModeIdle: + if (_animationState >= 2 && _animationState <= 11) { var_45CD88 = 1; } else { _animationState = 0; @@ -485,14 +486,14 @@ bool AIScriptRunciter::ChangeAnimationMode(int mode) { if (_animationState > 1) { _animationState = 1; _animationFrame = 0; - } else if (!_animationState) { + } else if (_animationState == 0) { _animationState = 13; _animationStateNext = 1; _animationNext = 526; } break; case 3: - if (_animationState) { + if (_animationState != 0) { _animationState = 2; _animationFrame = 0; } else { @@ -503,7 +504,7 @@ bool AIScriptRunciter::ChangeAnimationMode(int mode) { var_45CD88 = 0; break; case 12: - if (_animationState) { + if (_animationState != 0) { _animationState = 2; _animationFrame = 0; } else { @@ -514,7 +515,7 @@ bool AIScriptRunciter::ChangeAnimationMode(int mode) { var_45CD88 = 0; break; case 13: - if (_animationState) { + if (_animationState != 0) { _animationState = 2; _animationFrame = 0; } else { @@ -525,7 +526,7 @@ bool AIScriptRunciter::ChangeAnimationMode(int mode) { var_45CD88 = 0; break; case 14: - if (_animationState) { + if (_animationState != 0) { _animationState = 2; _animationFrame = 0; } else { @@ -536,7 +537,7 @@ bool AIScriptRunciter::ChangeAnimationMode(int mode) { var_45CD88 = 0; break; case 15: - if (_animationState) { + if (_animationState != 0) { _animationState = 2; _animationFrame = 0; } else { @@ -547,7 +548,7 @@ bool AIScriptRunciter::ChangeAnimationMode(int mode) { var_45CD88 = 0; break; case 16: - if (_animationState) { + if (_animationState != 0) { _animationState = 2; _animationFrame = 0; } else { @@ -558,7 +559,7 @@ bool AIScriptRunciter::ChangeAnimationMode(int mode) { var_45CD88 = 0; break; case 17: - if (_animationState) { + if (_animationState != 0) { _animationState = 2; _animationFrame = 0; } else { @@ -569,7 +570,7 @@ bool AIScriptRunciter::ChangeAnimationMode(int mode) { var_45CD88 = 0; break; case 18: - if (_animationState) { + if (_animationState != 0) { _animationState = 2; _animationFrame = 0; } else { @@ -580,7 +581,7 @@ bool AIScriptRunciter::ChangeAnimationMode(int mode) { var_45CD88 = 0; break; case 19: - if (_animationState) { + if (_animationState != 0) { _animationState = 2; _animationFrame = 0; } else { diff --git a/engines/bladerunner/script/ai_script.cpp b/engines/bladerunner/script/ai_script.cpp index 503fb733df..7b211aaa4c 100644 --- a/engines/bladerunner/script/ai_script.cpp +++ b/engines/bladerunner/script/ai_script.cpp @@ -144,6 +144,35 @@ void AIScripts::otherAgentExitedThisScene(int actor, int otherActorId) { _inScriptCounter--; } +void AIScripts::otherAgentEnteredCombatMode(int actorId, int otherActorId, int combatMode) { + assert(actorId < _actorCount); + _inScriptCounter++; + if (_AIScripts[actorId]) { + _AIScripts[actorId]->OtherAgentEnteredCombatMode(otherActorId, combatMode); + } + _inScriptCounter--; +} + +void AIScripts::shotAtAndMissed(int actorId) { + assert(actorId < _actorCount); + _inScriptCounter++; + if (_AIScripts[actorId]) { + _AIScripts[actorId]->ShotAtAndMissed(); + } + _inScriptCounter--; +} + +bool AIScripts::shotAtAndHit(int actorId) { + assert(actorId < _actorCount); + bool result = true; + _inScriptCounter++; + if (_AIScripts[actorId]) { + result = _AIScripts[actorId]->ShotAtAndHit(); + } + _inScriptCounter--; + return result; +} + void AIScripts::retired(int actor, int retiredByActorId) { assert(actor < _actorCount); _inScriptCounter++; diff --git a/engines/bladerunner/script/ai_script.h b/engines/bladerunner/script/ai_script.h index 40df2fb0d8..4be79c650b 100644 --- a/engines/bladerunner/script/ai_script.h +++ b/engines/bladerunner/script/ai_script.h @@ -50,7 +50,7 @@ public: virtual void OtherAgentExitedThisScene(int otherActorId) = 0; virtual void OtherAgentEnteredCombatMode(int otherActorId, int combatMode) = 0; virtual void ShotAtAndMissed() = 0; - virtual void ShotAtAndHit() = 0; + virtual bool ShotAtAndHit() = 0; virtual void Retired(int byActorId) = 0; virtual int GetFriendlinessModifierIfGetsClue(int otherActorId, int clueId) = 0; virtual bool GoalChanged(int currentGoalNumber, int newGoalNumber) = 0; @@ -79,7 +79,7 @@ public: \ void OtherAgentExitedThisScene(int otherActorId); \ void OtherAgentEnteredCombatMode(int otherActorId, int combatMode); \ void ShotAtAndMissed(); \ - void ShotAtAndHit(); \ + bool ShotAtAndHit(); \ void Retired(int byActorId); \ int GetFriendlinessModifierIfGetsClue(int otherActorId, int clueId); \ bool GoalChanged(int currentGoalNumber, int newGoalNumber); \ @@ -176,6 +176,9 @@ public: void enteredScene(int actor, int setId); void otherAgentEnteredThisScene(int actor, int otherActorId); void otherAgentExitedThisScene(int actor, int otherActorId); + void otherAgentEnteredCombatMode(int actorId, int otherActorId, int combatMode); + void shotAtAndMissed(int actorId); + bool shotAtAndHit(int actorId); void retired(int actor, int retiredByActorId); void goalChanged(int actor, int currentGoalNumber, int newGoalNumber); bool reachedMovementTrackWaypoint(int actor, int waypointId); diff --git a/engines/bladerunner/script/scene_script.cpp b/engines/bladerunner/script/scene_script.cpp index 639bca8c4e..01fe3e3b1e 100644 --- a/engines/bladerunner/script/scene_script.cpp +++ b/engines/bladerunner/script/scene_script.cpp @@ -174,20 +174,21 @@ bool SceneScript::mouseClick(int x, int y) { //MouseX = x; //MouseY = y; bool result = _currentScript->MouseClick(x, y); - //SelectedEntity = -1; + _vm->_runningActorId = -1; _inScriptCounter--; //MouseX = -1; //MouseY = -1; return result; } -bool SceneScript::clickedOn3DObject(const char *objectName, bool a2) { +bool SceneScript::clickedOn3DObject(const char *objectName, bool attack) { if (_inScriptCounter > 0) { return true; } _inScriptCounter++; - bool result = _currentScript->ClickedOn3DObject(objectName, a2); + bool result = _currentScript->ClickedOn3DObject(objectName, attack); + _vm->_runningActorId = -1; _inScriptCounter--; return result; } @@ -199,6 +200,7 @@ bool SceneScript::clickedOnActor(int actorId) { _inScriptCounter++; bool result = _currentScript->ClickedOnActor(actorId); + _vm->_runningActorId = -1; _inScriptCounter--; return result; } @@ -210,6 +212,7 @@ bool SceneScript::clickedOnItem(int itemId, bool a2) { _inScriptCounter++; bool result = _currentScript->ClickedOnItem(itemId, a2); + _vm->_runningActorId = -1; _inScriptCounter--; return result; } @@ -221,6 +224,7 @@ bool SceneScript::clickedOnExit(int exitId) { _inScriptCounter++; bool result = _currentScript->ClickedOnExit(exitId); + _vm->_runningActorId = -1; _inScriptCounter--; return result; } @@ -232,6 +236,7 @@ bool SceneScript::clickedOn2DRegion(int region) { _inScriptCounter++; bool result = _currentScript->ClickedOn2DRegion(region); + _vm->_runningActorId = -1; _inScriptCounter--; return result; } diff --git a/engines/bladerunner/script/scene_script.h b/engines/bladerunner/script/scene_script.h index ece96690d3..086388c2d6 100644 --- a/engines/bladerunner/script/scene_script.h +++ b/engines/bladerunner/script/scene_script.h @@ -36,7 +36,7 @@ public: virtual void InitializeScene() = 0; virtual void SceneLoaded() = 0; virtual bool MouseClick(int x, int y) = 0; - virtual bool ClickedOn3DObject(const char *objectName, bool a2) = 0; + virtual bool ClickedOn3DObject(const char *objectName, bool attack) = 0; virtual bool ClickedOnActor(int actorId) = 0; virtual bool ClickedOnItem(int itemId, bool a2) = 0; virtual bool ClickedOnExit(int exitId) = 0; @@ -57,7 +57,7 @@ public: \ void InitializeScene(); \ void SceneLoaded(); \ bool MouseClick(int x, int y); \ - bool ClickedOn3DObject(const char *objectName, bool a2); \ + bool ClickedOn3DObject(const char *objectName, bool attack); \ bool ClickedOnActor(int actorId); \ bool ClickedOnItem(int itemId, bool a2); \ bool ClickedOnExit(int exitId); \ @@ -536,7 +536,7 @@ public: void initializeScene(); void sceneLoaded(); bool mouseClick(int x, int y); - bool clickedOn3DObject(const char *objectName, bool a2); + bool clickedOn3DObject(const char *objectName, bool attack); bool clickedOnActor(int actorId); bool clickedOnItem(int itemId, bool a2); bool clickedOnExit(int exitId); diff --git a/engines/bladerunner/script/script.cpp b/engines/bladerunner/script/script.cpp index c4b0de81d9..f88f330e2f 100644 --- a/engines/bladerunner/script/script.cpp +++ b/engines/bladerunner/script/script.cpp @@ -231,7 +231,7 @@ void ScriptBase::Actor_Set_Health(int actorId, int hp, int maxHp) { } void ScriptBase::Actor_Set_Targetable(int actorId, bool targetable) { - _vm->_actors[actorId]->setTargetable(targetable); + _vm->_actors[actorId]->setTarget(targetable); } @@ -258,7 +258,7 @@ void ScriptBase::Actor_Says_With_Pause(int actorId, int sentenceId, float pause, if (actorId != kActorMcCoy) { actor->changeAnimationMode(animationMode, false); animationModeChanged = true; - } else if (_vm->_combat->isActive()) { + } else if (!_vm->_combat->isActive()) { actor->changeAnimationMode(animationMode, false); animationModeChanged = true; } @@ -364,11 +364,11 @@ bool ScriptBase::Actor_Query_In_Between_Two_Actors(int actorId, int otherActor1I float z1 = _vm->_actors[otherActor1Id]->getZ(); float x2 = _vm->_actors[otherActor2Id]->getX(); float z2 = _vm->_actors[otherActor2Id]->getZ(); - return _vm->_sceneObjects->isBetweenTwoXZ(actorId + kSceneObjectOffsetActors, x1, z1, x2, z1) - || _vm->_sceneObjects->isBetweenTwoXZ(actorId + kSceneObjectOffsetActors, x1 - 12.0f, z1 - 12.0f, x2 - 12.0f, z2 - 12.0f) - || _vm->_sceneObjects->isBetweenTwoXZ(actorId + kSceneObjectOffsetActors, x1 + 12.0f, z1 - 12.0f, x2 + 12.0f, z2 - 12.0f) - || _vm->_sceneObjects->isBetweenTwoXZ(actorId + kSceneObjectOffsetActors, x1 + 12.0f, z1 + 12.0f, x2 + 12.0f, z2 + 12.0f) - || _vm->_sceneObjects->isBetweenTwoXZ(actorId + kSceneObjectOffsetActors, x1 - 12.0f, z1 + 12.0f, x2 - 12.0f, z2 + 12.0f); + return _vm->_sceneObjects->isBetween(x1, z1, x2, z1, actorId + kSceneObjectOffsetActors) + || _vm->_sceneObjects->isBetween(x1 - 12.0f, z1 - 12.0f, x2 - 12.0f, z2 - 12.0f, actorId + kSceneObjectOffsetActors) + || _vm->_sceneObjects->isBetween(x1 + 12.0f, z1 - 12.0f, x2 + 12.0f, z2 - 12.0f, actorId + kSceneObjectOffsetActors) + || _vm->_sceneObjects->isBetween(x1 + 12.0f, z1 + 12.0f, x2 + 12.0f, z2 + 12.0f, actorId + kSceneObjectOffsetActors) + || _vm->_sceneObjects->isBetween(x1 - 12.0f, z1 + 12.0f, x2 - 12.0f, z2 + 12.0f, actorId + kSceneObjectOffsetActors); } void ScriptBase::Actor_Set_Goal_Number(int actorId, int goalNumber) { @@ -408,20 +408,21 @@ int ScriptBase::Actor_Query_Animation_Mode(int actorId) { bool ScriptBase::Loop_Actor_Walk_To_Actor(int actorId, int otherActorId, int distance, bool interruptible, bool run) { _vm->gameWaitForActive(); - if (_vm->_walkingActorId == actorId) { + if (_vm->_runningActorId == actorId) { run = true; } + _vm->_playerActorIdle = false; - bool isRunning; + bool isRunning; bool result = _vm->_actors[actorId]->loopWalkToActor(otherActorId, distance, interruptible, run, true, &isRunning); if (_vm->_playerActorIdle) { result = true; _vm->_playerActorIdle = false; } - if (isRunning == 1) { - _vm->_walkingActorId = actorId; + if (isRunning) { + _vm->_runningActorId = actorId; } Global_Variable_Set(kVariableWalkLoopActor, actorId); Global_Variable_Set(kVariableWalkLoopRun, isRunning); @@ -431,20 +432,21 @@ bool ScriptBase::Loop_Actor_Walk_To_Actor(int actorId, int otherActorId, int dis bool ScriptBase::Loop_Actor_Walk_To_Item(int actorId, int itemId, int destinationOffset, bool interruptible, bool run) { _vm->gameWaitForActive(); - if (_vm->_walkingActorId == actorId) { + if (_vm->_runningActorId == actorId) { run = true; } + _vm->_playerActorIdle = false; - bool isRunning; + bool isRunning; bool result = _vm->_actors[actorId]->loopWalkToItem(itemId, destinationOffset, interruptible, run, true, &isRunning); - if (_vm->_playerActorIdle == 1) { + if (_vm->_playerActorIdle) { result = true; _vm->_playerActorIdle = false; } - if (isRunning == 1) { - _vm->_walkingActorId = actorId; + if (isRunning) { + _vm->_runningActorId = actorId; } Global_Variable_Set(kVariableWalkLoopActor, actorId); Global_Variable_Set(kVariableWalkLoopRun, isRunning); @@ -454,20 +456,21 @@ bool ScriptBase::Loop_Actor_Walk_To_Item(int actorId, int itemId, int destinatio bool ScriptBase::Loop_Actor_Walk_To_Scene_Object(int actorId, const char *objectName, int destinationOffset, bool interruptible, bool run) { _vm->gameWaitForActive(); - if (_vm->_walkingActorId == actorId) { + if (_vm->_runningActorId == actorId) { run = true; } + _vm->_playerActorIdle = false; - bool isRunning; + bool isRunning; bool result = _vm->_actors[actorId]->loopWalkToSceneObject(objectName, destinationOffset, interruptible, run, true, &isRunning); if (_vm->_playerActorIdle) { result = true; _vm->_playerActorIdle = false; } - if (isRunning == 1) { - _vm->_walkingActorId = actorId; + if (isRunning) { + _vm->_runningActorId = actorId; } Global_Variable_Set(kVariableWalkLoopActor, actorId); Global_Variable_Set(kVariableWalkLoopRun, isRunning); @@ -477,20 +480,21 @@ bool ScriptBase::Loop_Actor_Walk_To_Scene_Object(int actorId, const char *object bool ScriptBase::Loop_Actor_Walk_To_Waypoint(int actorId, int waypointId, int destinationOffset, bool interruptible, bool run) { _vm->gameWaitForActive(); - if (_vm->_walkingActorId == actorId) { + if (_vm->_runningActorId == actorId) { run = true; } + _vm->_playerActorIdle = false; - bool isRunning; + bool isRunning; bool result = _vm->_actors[actorId]->loopWalkToWaypoint(waypointId, destinationOffset, interruptible, run, true, &isRunning); if (_vm->_playerActorIdle) { result = true; _vm->_playerActorIdle = false; } - if (isRunning == 1) { - _vm->_walkingActorId = actorId; + if (isRunning) { + _vm->_runningActorId = actorId; } Global_Variable_Set(kVariableWalkLoopActor, actorId); Global_Variable_Set(kVariableWalkLoopRun, isRunning); @@ -500,16 +504,16 @@ bool ScriptBase::Loop_Actor_Walk_To_Waypoint(int actorId, int waypointId, int de bool ScriptBase::Loop_Actor_Walk_To_XYZ(int actorId, float x, float y, float z, int destinationOffset, bool interruptible, bool run, int a7) { _vm->gameWaitForActive(); - if (_vm->_walkingActorId == actorId) { + if (_vm->_runningActorId == actorId) { if (a7) { - _vm->_walkingActorId = -1; + _vm->_runningActorId = -1; } else { run = true; } } _vm->_playerActorIdle = false; - bool isRunning; + bool isRunning; bool result = _vm->_actors[actorId]->loopWalkToXYZ(Vector3(x, y, z), destinationOffset, interruptible, run, true, &isRunning); if (_vm->_playerActorIdle) { @@ -517,7 +521,7 @@ bool ScriptBase::Loop_Actor_Walk_To_XYZ(int actorId, float x, float y, float z, _vm->_playerActorIdle = false; } if (isRunning) { - _vm->_walkingActorId = actorId; + _vm->_runningActorId = actorId; } Global_Variable_Set(kVariableWalkLoopActor, actorId); Global_Variable_Set(kVariableWalkLoopRun, isRunning); @@ -527,7 +531,7 @@ bool ScriptBase::Loop_Actor_Walk_To_XYZ(int actorId, float x, float y, float z, void ScriptBase::Async_Actor_Walk_To_Waypoint(int actorId, int waypointId, int destinationOffset, bool run) { _vm->gameWaitForActive(); - if (_vm->_walkingActorId == actorId) { + if (_vm->_runningActorId == actorId) { run = true; } @@ -537,7 +541,7 @@ void ScriptBase::Async_Actor_Walk_To_Waypoint(int actorId, int waypointId, int d void ScriptBase::Async_Actor_Walk_To_XYZ(int actorId, float x, float y, float z, int destinationOffset, bool run) { _vm->gameWaitForActive(); - if (_vm->_walkingActorId == actorId) { + if (_vm->_runningActorId == actorId) { run = true; } @@ -1234,13 +1238,13 @@ void ScriptBase::I_Sez(const char *str) { void ScriptBase::AI_Countdown_Timer_Start(int actorId, signed int timer, int seconds) { if (timer >= 0 && timer <= 2) { - _vm->_actors[actorId]->countdownTimerStart(timer, 1000 * seconds); + _vm->_actors[actorId]->timerStart(timer, 1000 * seconds); } } void ScriptBase::AI_Countdown_Timer_Reset(int actorId, int timer) { if (timer >= 0 && timer <= 2) { - _vm->_actors[actorId]->countdownTimerReset(timer); + _vm->_actors[actorId]->timerReset(timer); } } @@ -1258,19 +1262,19 @@ void ScriptBase::AI_Movement_Track_Repeat(int actorId) { } void ScriptBase::AI_Movement_Track_Append_Run_With_Facing(int actorId, int waypointId, int delay, int angle) { - _vm->_actors[actorId]->_movementTrack->append(waypointId, delay, angle, 1); + _vm->_actors[actorId]->_movementTrack->append(waypointId, delay * 1000, angle, true); } void ScriptBase::AI_Movement_Track_Append_With_Facing(int actorId, int waypointId, int delay, int angle) { - _vm->_actors[actorId]->_movementTrack->append(waypointId, delay, angle, 0); + _vm->_actors[actorId]->_movementTrack->append(waypointId, delay * 1000, angle, false); } void ScriptBase::AI_Movement_Track_Append_Run(int actorId, int waypointId, int delay) { - _vm->_actors[actorId]->_movementTrack->append(waypointId, delay, 1); + _vm->_actors[actorId]->_movementTrack->append(waypointId, delay * 1000, true); } void ScriptBase::AI_Movement_Track_Append(int actorId, int waypointId, int delay) { - _vm->_actors[actorId]->_movementTrack->append(waypointId, delay, 0); + _vm->_actors[actorId]->_movementTrack->append(waypointId, delay * 1000, false); } void ScriptBase::AI_Movement_Track_Flush(int actorId) { diff --git a/engines/bladerunner/set.cpp b/engines/bladerunner/set.cpp index a68799a232..fe10c189b6 100644 --- a/engines/bladerunner/set.cpp +++ b/engines/bladerunner/set.cpp @@ -23,6 +23,7 @@ #include "bladerunner/set.h" #include "bladerunner/bladerunner.h" +#include "bladerunner/game_constants.h" #include "bladerunner/lights.h" #include "bladerunner/scene_objects.h" #include "bladerunner/set_effects.h" diff --git a/engines/bladerunner/settings.cpp b/engines/bladerunner/settings.cpp index d0ba84321c..a5540fcb04 100644 --- a/engines/bladerunner/settings.cpp +++ b/engines/bladerunner/settings.cpp @@ -111,31 +111,51 @@ bool Settings::openNewScene() { return true; } -int Settings::getAmmoType() { +int Settings::getAmmoType() const { return _ammoType; } -int Settings::getAmmoAmount(int ammoType) { - return _ammoAmounts[ammoType]; -} - void Settings::setAmmoType(int ammoType) { if (_ammoAmounts[ammoType] > 0) { _ammoType = ammoType; } } +int Settings::getAmmo(int ammoType) const { + return _ammoAmounts[ammoType]; +} + void Settings::addAmmo(int ammoType, int ammo) { - if (ammoType > _ammoType || _ammoAmounts[_ammoType] == 0) + if (ammoType > _ammoType || _ammoAmounts[_ammoType] == 0) { _ammoType = ammoType; + } _ammoAmounts[ammoType] += ammo; } -int Settings::getDifficulty() { +void Settings::decreaseAmmo() { + if (_difficulty == 0 || _ammoType == 0) { + return; + } + + if (_ammoAmounts[_ammoType] > 0) { + --_ammoAmounts[_ammoType]; + } + + if (_ammoAmounts[_ammoType] == 0) { + for (int i = 2; i >= 0; --i) { + if (_ammoAmounts[i] > 0) { + _ammoType = i; + return; + } + } + } +} + +int Settings::getDifficulty() const { return _difficulty; } -int Settings::getPlayerAgenda() { +int Settings::getPlayerAgenda() const { return _playerAgenda; } @@ -143,4 +163,12 @@ void Settings::setPlayerAgenda(int agenda) { _playerAgenda = agenda; } +bool Settings::getLearyMode() const { + return _learyMode; +} + +void Settings::setLearyMode(bool learyMode) { + _learyMode = learyMode; +} + } // End of namespace BladeRunner diff --git a/engines/bladerunner/settings.h b/engines/bladerunner/settings.h index 85674d25c4..bf2d2d3162 100644 --- a/engines/bladerunner/settings.h +++ b/engines/bladerunner/settings.h @@ -77,11 +77,11 @@ public: _newScene = -1; } - int getNewScene() { + int getNewScene() const { return _newScene; } - int getNewSet() { + int getNewSet() const { return _newSet; } @@ -94,7 +94,7 @@ public: _loadingGame = loadingGame; } - bool getLoadingGame() { + bool getLoadingGame() const { return _loadingGame; } @@ -104,22 +104,19 @@ public: bool openNewScene(); - int getAmmoType(); - int getAmmoAmount(int ammoType); + int getAmmoType() const; void setAmmoType(int ammoType); - - int getDifficulty(); - int getPlayerAgenda(); - void setPlayerAgenda(int agenda); + int getAmmo(int ammoType) const; void addAmmo(int ammoType, int ammo); + void decreaseAmmo(); - bool getLearyMode() { - return _learyMode; - } + int getDifficulty() const; - void setLearyMode(bool learyMode) { - _learyMode = learyMode; - } + int getPlayerAgenda() const; + void setPlayerAgenda(int agenda); + + bool getLearyMode() const; + void setLearyMode(bool learyMode); }; } // End of namespace BladeRunner diff --git a/engines/bladerunner/ui/kia.cpp b/engines/bladerunner/ui/kia.cpp index a738923a06..9f7ec13ea0 100644 --- a/engines/bladerunner/ui/kia.cpp +++ b/engines/bladerunner/ui/kia.cpp @@ -329,21 +329,21 @@ void KIA::tick() { _currentSection->draw(_vm->_surfaceFront); } } - if (_vm->_settings->getAmmoAmount(0) > 0) { + if (_vm->_settings->getAmmo(0) > 0) { if (_vm->_settings->getAmmoType() == 0) { _shapes->get(42)->draw(_vm->_surfaceFront, 147, 405); } else { _shapes->get(45)->draw(_vm->_surfaceFront, 140, 446); } } - if (_vm->_settings->getAmmoAmount(1) > 0) { + if (_vm->_settings->getAmmo(1) > 0) { if (_vm->_settings->getAmmoType() == 1) { _shapes->get(43)->draw(_vm->_surfaceFront, 167, 394); } else { _shapes->get(46)->draw(_vm->_surfaceFront, 160, 446); } } - if (_vm->_settings->getAmmoAmount(2) > 0) { + if (_vm->_settings->getAmmo(2) > 0) { if (_vm->_settings->getAmmoType() == 2) { _shapes->get(44)->draw(_vm->_surfaceFront, 189, 385); } else { @@ -826,21 +826,21 @@ void KIA::createButtons(int sectionId) { _buttons->defineImage(19, kiaButton19, nullptr, nullptr, nullptr, _vm->_textKIA->getText(44)); - if (_vm->_settings->getAmmoAmount(0) > 0) { + if (_vm->_settings->getAmmo(0) > 0) { _buttons->defineImage(16, kiaButton16, nullptr, nullptr, nullptr, _vm->_textKIA->getText(50)); } Common::String tooltip; - if (_vm->_settings->getAmmoAmount(1) > 0) { + if (_vm->_settings->getAmmo(1) > 0) { if (_vm->_settings->getDifficulty() > 0) { - tooltip = Common::String::format("%d", _vm->_settings->getAmmoAmount(1)); + tooltip = Common::String::format("%d", _vm->_settings->getAmmo(1)); } else { tooltip = _vm->_textKIA->getText(50); } _buttons->defineImage(17, kiaButton17, nullptr, nullptr, nullptr, tooltip.c_str()); } - if (_vm->_settings->getAmmoAmount(2) > 0) { + if (_vm->_settings->getAmmo(2) > 0) { if (_vm->_settings->getDifficulty() > 0) { - tooltip = Common::String::format("%d", _vm->_settings->getAmmoAmount(2)); + tooltip = Common::String::format("%d", _vm->_settings->getAmmo(2)); } else { tooltip = _vm->_textKIA->getText(50); } diff --git a/engines/bladerunner/vector.h b/engines/bladerunner/vector.h index d04070f7c5..f3cc1f1e6d 100644 --- a/engines/bladerunner/vector.h +++ b/engines/bladerunner/vector.h @@ -143,6 +143,23 @@ inline float cos_1024(int angle1024) { inline float sin_1024(int angle1024) { return sin(angle1024 * (M_PI / 512.0f)); } + +inline bool lineIntersection(Vector2 a1, Vector2 a2, Vector2 b1, Vector2 b2, Vector2 *intersection) { + Vector2 s1(a2.x - a1.x, a2.y - a1.y); + Vector2 s2(b2.x - b1.x, b2.y - b1.y); + + float s = (s1.x * (a1.y - b1.y) - s1.y * (a1.x - b1.x)) / (s1.x * s2.y - s2.x * s1.y); + float t = (s2.x * (a1.y - b1.y) - s2.y * (a1.x - b1.x)) / (s1.x * s2.y - s2.x * s1.y); + + if (s >= 0.0f && s <= 1.0f && t >= 0.0f && t <= 1.0f) { + intersection->x = a1.x + (t * s1.x); + intersection->y = a1.y + (t * s1.y); + return true; + } + + return false; // No collision +} + } // End of namespace BladeRunner #endif |