2015-05-02 22:31:07 +02:00
|
|
|
/* ScummVM - Graphic Adventure Engine
|
|
|
|
*
|
|
|
|
* ScummVM is the legal property of its developers, whose names
|
|
|
|
* are too numerous to list here. Please refer to the COPYRIGHT
|
|
|
|
* file distributed with this source distribution.
|
|
|
|
*
|
|
|
|
* This program is free software; you can redistribute it and/or
|
|
|
|
* modify it under the terms of the GNU General Public License
|
|
|
|
* as published by the Free Software Foundation; either version 2
|
|
|
|
* of the License, or (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
* along with this program; if not, write to the Free Software
|
|
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "bladerunner/actor.h"
|
|
|
|
|
|
|
|
#include "bladerunner/bladerunner.h"
|
2016-09-10 18:16:17 +02:00
|
|
|
#include "bladerunner/actor_clues.h"
|
|
|
|
#include "bladerunner/actor_combat.h"
|
|
|
|
#include "bladerunner/actor_walk.h"
|
|
|
|
#include "bladerunner/audio_speech.h"
|
2015-05-02 22:31:07 +02:00
|
|
|
#include "bladerunner/boundingbox.h"
|
|
|
|
#include "bladerunner/gameinfo.h"
|
2015-09-15 20:26:46 +02:00
|
|
|
#include "bladerunner/items.h"
|
2016-10-04 02:21:08 +02:00
|
|
|
#include "bladerunner/mouse.h"
|
2016-09-10 18:16:17 +02:00
|
|
|
#include "bladerunner/movement_track.h"
|
|
|
|
#include "bladerunner/scene.h"
|
|
|
|
#include "bladerunner/scene_objects.h"
|
2017-03-23 16:20:10 +01:00
|
|
|
#include "bladerunner/script/scene.h"
|
|
|
|
#include "bladerunner/script/ai.h"
|
2017-08-24 23:43:47 +02:00
|
|
|
#include "bladerunner/set.h"
|
2015-09-19 01:43:38 +02:00
|
|
|
#include "bladerunner/slice_animations.h"
|
2016-09-10 18:16:17 +02:00
|
|
|
#include "bladerunner/slice_renderer.h"
|
|
|
|
#include "bladerunner/waypoints.h"
|
2017-03-28 17:50:04 +02:00
|
|
|
#include "bladerunner/zbuffer.h"
|
2016-09-10 18:16:17 +02:00
|
|
|
|
2015-05-02 22:31:07 +02:00
|
|
|
namespace BladeRunner {
|
|
|
|
|
|
|
|
Actor::Actor(BladeRunnerEngine *vm, int actorId) {
|
|
|
|
_vm = vm;
|
|
|
|
_id = actorId;
|
|
|
|
|
2016-09-12 00:54:40 +02:00
|
|
|
_walkInfo = new ActorWalk(vm);
|
2015-09-15 20:26:46 +02:00
|
|
|
_movementTrack = new MovementTrack();
|
2016-09-12 00:54:40 +02:00
|
|
|
_clues = new ActorClues(vm, (actorId && actorId != 99) ? 2 : 4);
|
|
|
|
_bbox = new BoundingBox();
|
|
|
|
_combatInfo = new ActorCombat(vm);
|
2015-05-02 22:31:07 +02:00
|
|
|
|
|
|
|
_friendlinessToOther = new int[_vm->_gameInfo->getActorCount()];
|
|
|
|
}
|
|
|
|
|
|
|
|
Actor::~Actor() {
|
|
|
|
delete[] _friendlinessToOther;
|
2016-09-12 00:54:40 +02:00
|
|
|
delete _combatInfo;
|
|
|
|
delete _bbox;
|
|
|
|
delete _clues;
|
|
|
|
delete _movementTrack;
|
|
|
|
delete _walkInfo;
|
2015-05-02 22:31:07 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void Actor::setup(int actorId) {
|
2016-09-12 00:54:40 +02:00
|
|
|
_id = actorId;
|
2015-09-15 20:26:46 +02:00
|
|
|
_setId = -1;
|
2015-05-02 22:31:07 +02:00
|
|
|
|
2016-09-12 00:54:40 +02:00
|
|
|
_position = Vector3(0.0, 0.0, 0.0);
|
|
|
|
_facing = 512;
|
2015-09-15 20:26:46 +02:00
|
|
|
_targetFacing = -1;
|
2016-09-10 18:16:17 +02:00
|
|
|
_walkboxId = -1;
|
2015-05-02 22:31:07 +02:00
|
|
|
|
|
|
|
_animationId = 0;
|
|
|
|
_animationFrame = 0;
|
|
|
|
_fps = 15;
|
|
|
|
_frame_ms = 1000 / _fps;
|
|
|
|
|
2016-10-22 18:30:46 +02:00
|
|
|
_isMoving = false;
|
2016-09-12 00:54:40 +02:00
|
|
|
_isTargetable = false;
|
2016-10-22 18:30:46 +02:00
|
|
|
_inCombat = false;
|
2016-09-12 00:54:40 +02:00
|
|
|
_isInvisible = false;
|
2015-05-02 22:31:07 +02:00
|
|
|
_isImmuneToObstacles = false;
|
2016-09-10 18:16:17 +02:00
|
|
|
|
2016-09-12 00:54:40 +02:00
|
|
|
_isRetired = false;
|
2015-05-02 22:31:07 +02:00
|
|
|
|
2016-09-12 00:54:40 +02:00
|
|
|
_width = 0;
|
|
|
|
_height = 0;
|
|
|
|
_retiredWidth = 0;
|
2015-09-15 20:26:46 +02:00
|
|
|
_retiredHeight = 0;
|
2015-05-02 22:31:07 +02:00
|
|
|
|
2017-03-23 00:25:38 +01:00
|
|
|
_movementTrackWalkingToWaypointId = -1;
|
|
|
|
_movementTrackDelayOnNextWaypoint = -1;
|
|
|
|
|
2015-05-02 22:31:07 +02:00
|
|
|
for (int i = 0; i != 7; ++i) {
|
|
|
|
_timersRemain[i] = 0;
|
2016-09-12 00:54:40 +02:00
|
|
|
_timersStart[i] = _vm->getTotalPlayTime();
|
2015-05-02 22:31:07 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
_scale = 1.0;
|
|
|
|
|
2016-09-12 00:54:40 +02:00
|
|
|
_honesty = 50;
|
|
|
|
_intelligence = 50;
|
2015-05-02 22:31:07 +02:00
|
|
|
_combatAggressiveness = 50;
|
2016-09-12 00:54:40 +02:00
|
|
|
_stability = 50;
|
2015-05-02 22:31:07 +02:00
|
|
|
|
2016-09-12 00:54:40 +02:00
|
|
|
_currentHP = 50;
|
|
|
|
_maxHP = 50;
|
|
|
|
_goalNumber = -1;
|
2015-05-02 22:31:07 +02:00
|
|
|
|
2017-03-23 00:25:38 +01:00
|
|
|
_movementTrackPaused = false;
|
|
|
|
_movementTrackNextWaypointId = -1;
|
|
|
|
_movementTrackNextDelay = -1;
|
|
|
|
_movementTrackNextAngle = -1;
|
|
|
|
_movementTrackNextRunning = false;
|
|
|
|
|
2015-05-02 22:31:07 +02:00
|
|
|
_timersRemain[4] = 60000;
|
|
|
|
_animationMode = -1;
|
2015-09-19 01:43:38 +02:00
|
|
|
_screenRectangle = Common::Rect(-1, -1, -1, -1);
|
2016-09-10 18:16:17 +02:00
|
|
|
|
2017-03-29 01:50:47 +02:00
|
|
|
_animationModeCombatIdle = kAnimationModeCombatIdle;
|
|
|
|
_animationModeCombatWalk = kAnimationModeCombatWalk;
|
|
|
|
_animationModeCombatRun = kAnimationModeCombatRun;
|
2015-05-02 22:31:07 +02:00
|
|
|
|
|
|
|
int actorCount = (int)_vm->_gameInfo->getActorCount();
|
|
|
|
for (int i = 0; i != actorCount; ++i)
|
|
|
|
_friendlinessToOther[i] = 50;
|
|
|
|
|
2015-09-19 01:43:38 +02:00
|
|
|
_combatInfo->setup();
|
|
|
|
_clues->removeAll();
|
|
|
|
_movementTrack->flush();
|
2015-05-02 22:31:07 +02:00
|
|
|
|
2015-09-19 01:43:38 +02:00
|
|
|
_actorSpeed = Vector3();
|
2015-05-02 22:31:07 +02:00
|
|
|
}
|
|
|
|
|
2016-09-12 00:54:40 +02:00
|
|
|
void Actor::changeAnimationMode(int animationMode, bool force) {
|
2017-03-29 01:50:47 +02:00
|
|
|
if (force) {
|
2016-09-10 18:16:17 +02:00
|
|
|
_animationMode = -1;
|
2017-03-29 01:50:47 +02:00
|
|
|
}
|
2016-09-10 18:16:17 +02:00
|
|
|
|
|
|
|
if (animationMode != _animationMode) {
|
|
|
|
_vm->_aiScripts->ChangeAnimationMode(_id, animationMode);
|
|
|
|
_animationMode = animationMode;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-09-12 00:54:40 +02:00
|
|
|
void Actor::setFPS(int fps) {
|
2016-09-10 18:16:17 +02:00
|
|
|
_fps = fps;
|
|
|
|
|
2016-09-12 00:54:40 +02:00
|
|
|
if (fps == 0) {
|
2016-09-10 18:16:17 +02:00
|
|
|
_frame_ms = 0;
|
2016-09-12 00:54:40 +02:00
|
|
|
} else if (fps == -1) {
|
2016-09-10 18:16:17 +02:00
|
|
|
_frame_ms = -1000;
|
2016-09-12 00:54:40 +02:00
|
|
|
} else if (fps == -2) {
|
2016-09-10 18:16:17 +02:00
|
|
|
_fps = _vm->_sliceAnimations->getFPS(_animationId);
|
|
|
|
_frame_ms = 1000 / _fps;
|
2016-09-12 00:54:40 +02:00
|
|
|
} else {
|
2016-09-10 18:16:17 +02:00
|
|
|
_frame_ms = 1000 / fps;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-03-23 00:25:38 +01:00
|
|
|
void Actor::countdownTimerStart(int timerId, int interval) {
|
|
|
|
assert(timerId >= 0 && timerId < 7);
|
|
|
|
_timersRemain[timerId] = interval;
|
|
|
|
_timersStart[timerId] = _vm->getTotalPlayTime();
|
|
|
|
}
|
|
|
|
|
|
|
|
void Actor::countdownTimerReset(int timerId) {
|
|
|
|
assert(timerId >= 0 && timerId < 7);
|
|
|
|
_timersRemain[timerId] = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int Actor::countdownTimerGetRemainingTime(int timerId) {
|
|
|
|
assert(timerId >= 0 && timerId < 7);
|
|
|
|
return _timersRemain[timerId];
|
|
|
|
}
|
|
|
|
|
|
|
|
void Actor::countdownTimersUpdate() {
|
|
|
|
for (int i = 0; i <= 6; i++) {
|
|
|
|
countdownTimerUpdate(i);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void Actor::countdownTimerUpdate(int timerId) {
|
|
|
|
if (_timersRemain[timerId] == 0) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
uint32 now = _vm->getTotalPlayTime();
|
|
|
|
int tickInterval = now - _timersStart[timerId];
|
|
|
|
_timersStart[timerId] = now;
|
|
|
|
|
|
|
|
//warning("tickInterval: %d", tickInterval);
|
|
|
|
_timersRemain[timerId] -= tickInterval;
|
|
|
|
|
|
|
|
if (_timersRemain[timerId] <= 0) {
|
|
|
|
switch (timerId) {
|
|
|
|
case 0:
|
|
|
|
case 1:
|
|
|
|
case 2:
|
2017-03-23 16:20:10 +01:00
|
|
|
if (!_vm->_aiScripts->IsInsideScript() && !_vm->_sceneScript->IsInsideScript()) {
|
2017-03-23 00:25:38 +01:00
|
|
|
_vm->_aiScripts->TimerExpired(this->_id, timerId);
|
|
|
|
this->_timersRemain[timerId] = 0;
|
|
|
|
} else {
|
|
|
|
this->_timersRemain[timerId] = 1;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 3:
|
|
|
|
_timersRemain[3] = 0;
|
|
|
|
if (_movementTrack->isPaused()) {
|
|
|
|
_timersRemain[3] = 1;
|
|
|
|
} else {
|
|
|
|
movementTrackNext(false);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 4:
|
|
|
|
// Something timer
|
|
|
|
break;
|
|
|
|
case 5:
|
|
|
|
// Actor animation frame timer
|
|
|
|
break;
|
|
|
|
case 6:
|
|
|
|
if (isRunning()) {
|
|
|
|
if (_fps > 15) {
|
|
|
|
int newFps = _fps - 2;
|
|
|
|
if (newFps < 15) {
|
|
|
|
newFps = 15;
|
|
|
|
}
|
|
|
|
setFPS(newFps);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
_timersRemain[6] = 200;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void Actor::movementTrackNext(bool omitAiScript) {
|
|
|
|
bool hasNextMovement;
|
|
|
|
int waypointSetId;
|
|
|
|
int running;
|
|
|
|
int angle;
|
|
|
|
int delay;
|
|
|
|
int waypointId;
|
|
|
|
Vector3 waypointPosition;
|
2017-04-01 08:56:30 +02:00
|
|
|
bool arrived;
|
2017-03-23 00:25:38 +01:00
|
|
|
|
|
|
|
hasNextMovement = _movementTrack->next(&waypointId, &delay, &angle, &running);
|
|
|
|
_movementTrackNextWaypointId = waypointId;
|
|
|
|
_movementTrackNextDelay = delay;
|
|
|
|
_movementTrackNextAngle = angle;
|
|
|
|
_movementTrackNextRunning = running;
|
|
|
|
if (hasNextMovement) {
|
|
|
|
if (angle == -1) {
|
|
|
|
angle = 0;
|
|
|
|
}
|
|
|
|
waypointSetId = _vm->_waypoints->getSetId(waypointId);
|
|
|
|
_vm->_waypoints->getXYZ(waypointId, &waypointPosition.x, &waypointPosition.y, &waypointPosition.z);
|
|
|
|
if (_setId == waypointSetId && waypointSetId == _vm->_actors[0]->_setId) {
|
|
|
|
stopWalking(false);
|
2017-04-01 08:56:30 +02:00
|
|
|
_walkInfo->setup(_id, running, _position, waypointPosition, false, &arrived);
|
2017-03-23 00:25:38 +01:00
|
|
|
|
|
|
|
_movementTrackWalkingToWaypointId = waypointId;
|
|
|
|
_movementTrackDelayOnNextWaypoint = delay;
|
2017-04-01 08:56:30 +02:00
|
|
|
if (arrived) {
|
2017-03-23 00:25:38 +01:00
|
|
|
movementTrackWaypointReached();
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
setSetId(waypointSetId);
|
|
|
|
setAtXYZ(waypointPosition, angle, true, false, false);
|
|
|
|
|
|
|
|
if (!delay) {
|
|
|
|
delay = 1;
|
|
|
|
}
|
|
|
|
if (delay > 1) {
|
2017-03-29 01:50:47 +02:00
|
|
|
changeAnimationMode(kAnimationModeIdle, false);
|
2017-03-23 00:25:38 +01:00
|
|
|
}
|
|
|
|
countdownTimerStart(3, delay);
|
|
|
|
}
|
|
|
|
//return true;
|
|
|
|
} else {
|
|
|
|
if (!omitAiScript) {
|
|
|
|
_vm->_aiScripts->CompletedMovementTrack(_id);
|
|
|
|
}
|
|
|
|
//return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void Actor::movementTrackPause() {
|
|
|
|
_movementTrack->pause();
|
|
|
|
if (isWalking()) {
|
|
|
|
_movementTrackPaused = true;
|
|
|
|
stopWalking(false);
|
|
|
|
} else {
|
|
|
|
_movementTrackPaused = false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void Actor::movementTrackUnpause() {
|
|
|
|
Vector3 waypointPosition;
|
2017-04-01 08:56:30 +02:00
|
|
|
bool arrived;
|
2017-03-23 00:25:38 +01:00
|
|
|
|
|
|
|
_movementTrack->unpause();
|
|
|
|
if (_movementTrackNextWaypointId >= 0 && _movementTrackPaused) {
|
|
|
|
_vm->_waypoints->getXYZ(_movementTrackNextWaypointId, &waypointPosition.x, &waypointPosition.y, &waypointPosition.z);
|
2017-04-01 08:56:30 +02:00
|
|
|
_walkInfo->setup(_id, _movementTrackNextRunning, _position, waypointPosition, false, &arrived);
|
2017-03-23 00:25:38 +01:00
|
|
|
_movementTrackPaused = false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void Actor::movementTrackWaypointReached() {
|
|
|
|
int seconds;
|
|
|
|
if (!_movementTrack->isPaused() && _id != 0) {
|
|
|
|
if (_movementTrackWalkingToWaypointId >= 0 && _movementTrackDelayOnNextWaypoint) {
|
|
|
|
if (!_movementTrackDelayOnNextWaypoint) {
|
|
|
|
_movementTrackDelayOnNextWaypoint = 1;
|
2016-09-12 00:54:40 +02:00
|
|
|
}
|
2017-03-23 00:25:38 +01:00
|
|
|
if (_vm->_aiScripts->ReachedMovementTrackWaypoint(_id, _movementTrackWalkingToWaypointId)) {
|
|
|
|
seconds = _movementTrackDelayOnNextWaypoint;
|
|
|
|
if (seconds > 1) {
|
2017-03-29 01:50:47 +02:00
|
|
|
changeAnimationMode(kAnimationModeIdle, false);
|
2017-03-23 00:25:38 +01:00
|
|
|
seconds = _movementTrackDelayOnNextWaypoint; // todo: analyze if movement is changed in some aiscript->ChangeAnimationMode?
|
2016-09-12 00:54:40 +02:00
|
|
|
}
|
2017-03-23 00:25:38 +01:00
|
|
|
countdownTimerStart(3, seconds);
|
2016-09-12 00:54:40 +02:00
|
|
|
}
|
|
|
|
}
|
2017-03-23 00:25:38 +01:00
|
|
|
_movementTrackWalkingToWaypointId = -1;
|
|
|
|
_movementTrackDelayOnNextWaypoint = 0;
|
|
|
|
}
|
2016-09-12 00:54:40 +02:00
|
|
|
}
|
|
|
|
|
2017-03-29 02:34:22 +02:00
|
|
|
bool Actor::loopWalkToActor(int otherActorId, int destinationOffset, int a3, bool run, bool a5, bool *flagIsRunning) {
|
|
|
|
return loopWalk(_vm->_actors[otherActorId]->_position, destinationOffset, a3, run, _position, 24.0f, 24.0f, a5, flagIsRunning, false);
|
2016-10-04 02:21:08 +02:00
|
|
|
}
|
|
|
|
|
2017-03-29 02:34:22 +02:00
|
|
|
bool Actor::loopWalkToItem(int itemId, int destinationOffset, int a3, bool run, bool a5, bool *flagIsRunning) {
|
2016-10-04 02:21:08 +02:00
|
|
|
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);
|
|
|
|
|
2017-03-29 02:34:22 +02:00
|
|
|
return loopWalk(itemPosition, destinationOffset, a3, run, _position, width, 24.0f, a5, flagIsRunning, false);
|
2016-10-04 02:21:08 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void Actor::setAtXYZ(const Vector3 &position, int facing, bool snapFacing, bool moving, bool retired) {
|
2016-10-02 00:20:56 +02:00
|
|
|
_position = position;
|
2016-09-10 18:16:17 +02:00
|
|
|
setFacing(facing, snapFacing);
|
|
|
|
|
2017-04-01 08:56:30 +02:00
|
|
|
if (_vm->_scene->getSetId() == _setId) {
|
2016-09-10 18:16:17 +02:00
|
|
|
_walkboxId = _vm->_scene->_set->findWalkbox(_position.x, _position.y);
|
|
|
|
} else {
|
2015-09-15 20:26:46 +02:00
|
|
|
_walkboxId = -1;
|
|
|
|
}
|
|
|
|
|
2016-09-10 18:16:17 +02:00
|
|
|
setBoundingBox(_position, retired);
|
2015-09-15 20:26:46 +02:00
|
|
|
|
2017-03-20 00:28:51 +01:00
|
|
|
_vm->_sceneObjects->remove(_id + SCENE_OBJECTS_ACTORS_OFFSET);
|
2015-09-15 20:26:46 +02:00
|
|
|
|
2016-09-12 00:54:40 +02:00
|
|
|
if (_vm->_scene->getSetId() == _setId) {
|
2017-03-20 00:28:51 +01:00
|
|
|
_vm->_sceneObjects->addActor(_id + SCENE_OBJECTS_ACTORS_OFFSET, _bbox, &_screenRectangle, 1, moving, _isTargetable, retired);
|
2015-09-15 20:26:46 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-09-12 00:54:40 +02:00
|
|
|
void Actor::setAtWaypoint(int waypointId, int angle, int moving, bool retired) {
|
2015-09-15 20:26:46 +02:00
|
|
|
Vector3 waypointPosition;
|
2016-09-10 18:16:17 +02:00
|
|
|
_vm->_waypoints->getXYZ(waypointId, &waypointPosition.x, &waypointPosition.y, &waypointPosition.z);
|
|
|
|
setAtXYZ(waypointPosition, angle, true, moving, retired);
|
|
|
|
}
|
|
|
|
|
2017-03-29 02:34:22 +02:00
|
|
|
bool Actor::loopWalk(const Vector3 &destination, int destinationOffset, bool a3, bool run, const Vector3 &start, float targetWidth, float targetSize, bool a8, bool *flagIsRunning, bool async) {
|
2016-10-04 02:21:08 +02:00
|
|
|
if (true) { // simple walking
|
2017-03-29 02:34:22 +02:00
|
|
|
*flagIsRunning = false;
|
2017-04-01 08:56:30 +02:00
|
|
|
bool arrived;
|
|
|
|
_walkInfo->setup(_id, false, _position, destination, false, &arrived);
|
2016-10-04 02:21:08 +02:00
|
|
|
|
|
|
|
for (;;) {
|
|
|
|
_vm->gameTick();
|
|
|
|
if (!_walkInfo->isWalking() && !_walkInfo->isRunning())
|
|
|
|
break;
|
|
|
|
if (!_vm->_gameIsRunning)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
return false;
|
2016-10-12 23:00:33 +02:00
|
|
|
} else {
|
2016-10-04 02:21:08 +02:00
|
|
|
//TODO:
|
|
|
|
// original code, not yet working
|
2017-03-29 02:34:22 +02:00
|
|
|
*flagIsRunning = false;
|
2016-10-04 02:21:08 +02:00
|
|
|
|
|
|
|
if (destinationOffset > 0) {
|
|
|
|
float dist = distance(_position, destination);
|
|
|
|
if (dist - targetSize <= destinationOffset) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (a8 && !async && _id && destinationOffset <= 24) {
|
|
|
|
if (distance(_vm->_playerActor->_position, destination) <= 24.0f) {
|
2017-04-01 08:56:30 +02:00
|
|
|
_vm->_playerActor->walkToNearestPoint(destination, 48.0f);
|
2016-10-04 02:21:08 +02:00
|
|
|
}
|
|
|
|
}
|
2016-09-10 18:33:04 +02:00
|
|
|
|
2016-10-04 02:21:08 +02:00
|
|
|
if (_id) {
|
|
|
|
a3 = false;
|
|
|
|
}
|
2016-09-10 18:16:17 +02:00
|
|
|
|
2016-10-04 02:21:08 +02:00
|
|
|
Vector3 destinationX(destination);
|
|
|
|
|
|
|
|
if (destinationOffset > 0) {
|
|
|
|
walkFindU2(&destinationX, targetWidth, destinationOffset, targetSize, _position, destination);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool walking = walkTo(run, destinationX, a8);
|
|
|
|
|
|
|
|
if (async) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!walking && destinationOffset > 0) {
|
|
|
|
walking = walkTo(run, destination, a8);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!walking) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (async) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
if (_id) {
|
|
|
|
_vm->_mouse->disable();
|
|
|
|
}
|
|
|
|
if (a3) {
|
|
|
|
// TODO:
|
|
|
|
// dword_482990 = 1;
|
|
|
|
// dword_482994 = 0;
|
|
|
|
} else {
|
|
|
|
_vm->playerLosesControl();
|
|
|
|
}
|
|
|
|
|
|
|
|
if (a8) {
|
|
|
|
_inWalkLoop = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool v46 = false;
|
|
|
|
while (_walkInfo->isWalking() && _vm->_gameIsRunning) {
|
|
|
|
if (_walkInfo->isRunning()) {
|
2017-03-29 02:34:22 +02:00
|
|
|
*flagIsRunning = true;
|
2016-10-04 02:21:08 +02:00
|
|
|
}
|
|
|
|
_vm->gameTick();
|
|
|
|
if (_id == 0 && a3 /*&& dword_482994*/) {
|
|
|
|
stopWalking(false);
|
|
|
|
v46 = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (a8) {
|
|
|
|
_inWalkLoop = false;
|
|
|
|
}
|
|
|
|
if (a3) {
|
|
|
|
// dword_482990 = 1;
|
|
|
|
} else {
|
|
|
|
_vm->playerGainsControl();
|
|
|
|
}
|
|
|
|
if (!v46 && destinationOffset == 0 /* && !PlayerActorIdle*/) {
|
|
|
|
setAtXYZ(destination, _facing, true, false, false);
|
|
|
|
}
|
|
|
|
if (_id) {
|
|
|
|
_vm->_mouse->enable();
|
|
|
|
}
|
|
|
|
return v46;
|
2016-09-10 18:16:17 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-10-04 02:21:08 +02:00
|
|
|
bool Actor::walkTo(bool run, const Vector3 &destination, bool a3) {
|
2017-04-01 08:56:30 +02:00
|
|
|
bool arrived;
|
2016-10-04 02:21:08 +02:00
|
|
|
|
2017-04-01 08:56:30 +02:00
|
|
|
return _walkInfo->setup(_id, run, _position, destination, a3, &arrived);
|
2016-10-04 02:21:08 +02:00
|
|
|
}
|
|
|
|
|
2017-03-29 02:34:22 +02:00
|
|
|
bool Actor::loopWalkToXYZ(const Vector3 &destination, int destinationOffset, bool a3, bool run, bool a5, bool *flagIsRunning) {
|
|
|
|
return loopWalk(destination, destinationOffset, a3, run, _position, 0.0f, 24.0f, a5, flagIsRunning, false);
|
2016-10-04 02:21:08 +02:00
|
|
|
}
|
2016-09-10 18:16:17 +02:00
|
|
|
|
2017-03-29 02:34:22 +02:00
|
|
|
bool Actor::loopWalkToSceneObject(const char *objectName, int destinationOffset, bool a3, bool run, bool a5, bool *flagIsRunning) {
|
2016-09-10 18:16:17 +02:00
|
|
|
int sceneObject = _vm->_scene->_set->findObject(objectName);
|
2016-10-04 02:21:08 +02:00
|
|
|
if (sceneObject < 0) {
|
|
|
|
return true;
|
|
|
|
}
|
2016-09-10 18:16:17 +02:00
|
|
|
|
|
|
|
BoundingBox bbox;
|
2016-10-04 02:21:08 +02:00
|
|
|
if (!_vm->_scene->_set->objectGetBoundingBox(sceneObject, &bbox)) {
|
|
|
|
return true;
|
|
|
|
}
|
2016-09-10 18:16:17 +02:00
|
|
|
|
|
|
|
float x0, y0, z0, x1, y1, z1;
|
|
|
|
bbox.getXYZ(&x0, &y0, &z0, &x1, &y1, &z1);
|
|
|
|
|
2016-10-04 02:21:08 +02:00
|
|
|
float closestDistance = distance(_position.x, _position.z, x0, z0);
|
|
|
|
float closestX = x0;
|
|
|
|
float closestZ = z0;
|
2016-09-10 18:16:17 +02:00
|
|
|
|
|
|
|
float d = distance(_position.x, _position.z, x1, z0);
|
2016-10-04 02:21:08 +02:00
|
|
|
if (d < closestDistance) {
|
|
|
|
closestX = x1;
|
|
|
|
closestZ = z0;
|
|
|
|
closestDistance = d;
|
2016-09-10 18:16:17 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
d = distance(_position.x, _position.z, x1, z1);
|
2016-10-04 02:21:08 +02:00
|
|
|
if (d < closestDistance) {
|
|
|
|
closestX = x1;
|
|
|
|
closestZ = z1;
|
|
|
|
closestDistance = d;
|
2016-09-10 18:16:17 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
d = distance(_position.x, _position.z, x0, z1);
|
2016-10-04 02:21:08 +02:00
|
|
|
if (d < closestDistance) {
|
|
|
|
closestX = x0;
|
|
|
|
closestZ = z1;
|
|
|
|
closestDistance = d;
|
2016-09-10 18:16:17 +02:00
|
|
|
}
|
2016-10-04 02:21:08 +02:00
|
|
|
bool inWalkbox;
|
|
|
|
float y = _vm->_scene->_set->getAltitudeAtXZ(closestX, closestZ, &inWalkbox);
|
|
|
|
Vector3 destination(closestX, y, closestZ);
|
2016-09-10 18:16:17 +02:00
|
|
|
|
2017-03-29 02:34:22 +02:00
|
|
|
return loopWalk(destination, destinationOffset, a3, run, _position, 0.0f, 24.0f, a5, flagIsRunning, false);
|
2016-10-04 02:21:08 +02:00
|
|
|
}
|
2016-09-10 18:16:17 +02:00
|
|
|
|
2017-03-29 02:34:22 +02:00
|
|
|
bool Actor::loopWalkToWaypoint(int waypointId, int destinationOffset, int a3, bool run, bool a5, bool *flagIsRunning) {
|
2017-03-23 00:25:38 +01:00
|
|
|
Vector3 waypointPosition;
|
|
|
|
_vm->_waypoints->getXYZ(waypointId, &waypointPosition.x, &waypointPosition.y, &waypointPosition.z);
|
2017-03-29 02:34:22 +02:00
|
|
|
return loopWalk(waypointPosition, destinationOffset, a3, run, _position, 0.0f, 24.0f, a5, flagIsRunning, false);
|
2016-09-10 18:16:17 +02:00
|
|
|
}
|
|
|
|
|
2017-03-28 17:50:04 +02:00
|
|
|
bool Actor::tick(bool forceDraw, Common::Rect *screenRect) {
|
2016-09-10 18:16:17 +02:00
|
|
|
int remain = 0;
|
|
|
|
bool needsUpdate = false;
|
2016-09-12 00:54:40 +02:00
|
|
|
if (_fps > 0) {
|
2016-09-10 18:16:17 +02:00
|
|
|
countdownTimerUpdate(5);
|
|
|
|
remain = countdownTimerGetRemainingTime(5);
|
|
|
|
needsUpdate = remain <= 0;
|
2016-09-12 00:54:40 +02:00
|
|
|
} else if (forceDraw) {
|
2016-09-10 18:16:17 +02:00
|
|
|
needsUpdate = true;
|
|
|
|
remain = 0;
|
|
|
|
}
|
|
|
|
|
2016-09-12 00:54:40 +02:00
|
|
|
if (needsUpdate) {
|
2016-09-10 18:16:17 +02:00
|
|
|
int newAnimation = 0, newFrame = 0;
|
|
|
|
_vm->_aiScripts->UpdateAnimation(_id, &newAnimation, &newFrame);
|
|
|
|
|
|
|
|
if (_animationId != newAnimation) {
|
2016-09-12 00:54:40 +02:00
|
|
|
if (_fps != 0 && _fps != -1) {
|
|
|
|
_animationId = newAnimation;
|
|
|
|
setFPS(-2);
|
|
|
|
}
|
2016-09-10 18:16:17 +02:00
|
|
|
}
|
2016-09-12 00:54:40 +02:00
|
|
|
_animationId = newAnimation;
|
2016-09-10 18:16:17 +02:00
|
|
|
_animationFrame = newFrame;
|
|
|
|
|
2016-09-12 00:54:40 +02:00
|
|
|
Vector3 positionChange = _vm->_sliceAnimations->getPositionChange(_animationId);
|
2016-10-04 02:21:08 +02:00
|
|
|
float angleChange = _vm->_sliceAnimations->getFacingChange(_animationId);
|
2016-09-12 00:54:40 +02:00
|
|
|
|
|
|
|
if (_id == 47) {
|
|
|
|
positionChange.x = 0.0f;
|
|
|
|
positionChange.y = 0.0f;
|
|
|
|
positionChange.z = 0.0f;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (isWalking()) {
|
|
|
|
if (0.0f <= positionChange.y) {
|
|
|
|
positionChange.y = -4.0f;
|
2016-09-10 18:16:17 +02:00
|
|
|
}
|
|
|
|
|
2016-09-12 00:54:40 +02:00
|
|
|
this->_targetFacing = -1;
|
|
|
|
|
|
|
|
bool walked = _walkInfo->tick(_id, -positionChange.y, false);
|
2017-03-29 01:50:47 +02:00
|
|
|
|
2016-09-12 00:54:40 +02:00
|
|
|
Vector3 pos;
|
|
|
|
int facing;
|
2016-09-10 18:16:17 +02:00
|
|
|
_walkInfo->getCurrentPosition(_id, &pos, &facing);
|
2016-09-12 00:54:40 +02:00
|
|
|
setAtXYZ(pos, facing, false, this->_isMoving, false);
|
|
|
|
if (walked) {
|
2017-03-29 01:50:47 +02:00
|
|
|
_vm->_actors[_id]->changeAnimationMode(kAnimationModeIdle);
|
2016-09-12 00:54:40 +02:00
|
|
|
|
2017-03-23 00:25:38 +01:00
|
|
|
this->movementTrackWaypointReached();
|
2016-09-12 00:54:40 +02:00
|
|
|
if (this->inCombat()) {
|
2017-03-29 01:50:47 +02:00
|
|
|
this->changeAnimationMode(this->_animationModeCombatIdle, false);
|
2016-09-12 00:54:40 +02:00
|
|
|
} else {
|
2017-03-29 01:50:47 +02:00
|
|
|
this->changeAnimationMode(kAnimationModeIdle, false);
|
2016-09-12 00:54:40 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
2016-10-04 02:21:08 +02:00
|
|
|
if (angleChange != 0.0f) {
|
|
|
|
int facingChange = angleChange * (512.0f / M_PI);
|
|
|
|
if (facingChange != 0) {
|
|
|
|
this->_facing = this->_facing - facingChange;
|
2016-09-12 00:54:40 +02:00
|
|
|
if (this->_facing < 0) {
|
|
|
|
this->_facing += 1024;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (this->_facing >= 1024) {
|
|
|
|
this->_facing = this->_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 (this->_actorSpeed.y != 0.0f) {
|
|
|
|
positionChange.y = positionChange.y * this->_actorSpeed.y;
|
|
|
|
}
|
|
|
|
if (this->_actorSpeed.z != 0.0f) {
|
|
|
|
positionChange.z = positionChange.z * this->_actorSpeed.z;
|
|
|
|
}
|
|
|
|
|
2016-10-04 02:21:08 +02:00
|
|
|
float angle = _facing * (M_PI / 512.0f);
|
|
|
|
float sinx = sin(angle);
|
|
|
|
float cosx = cos(angle);
|
2016-09-12 00:54:40 +02:00
|
|
|
|
|
|
|
float originalX = this->_position.x;
|
|
|
|
float originalY = this->_position.y;
|
|
|
|
float originalZ = this->_position.z;
|
|
|
|
|
|
|
|
this->_position.x = this->_position.x + positionChange.x * cosx - positionChange.y * sinx;
|
2016-09-20 00:33:06 +02:00
|
|
|
this->_position.z = this->_position.z + positionChange.x * sinx + positionChange.y * cosx;
|
2016-09-12 00:54:40 +02:00
|
|
|
this->_position.y = this->_position.y + positionChange.z;
|
|
|
|
|
2017-03-20 00:28:51 +01:00
|
|
|
if (_vm->_sceneObjects->existsOnXZ(this->_id + SCENE_OBJECTS_ACTORS_OFFSET, this->_position.x, this->_position.z, false, false) == 1 && !this->_isImmuneToObstacles) {
|
2016-09-12 00:54:40 +02:00
|
|
|
this->_position.x = originalX;
|
|
|
|
this->_position.y = originalY;
|
|
|
|
this->_position.z = originalZ;
|
|
|
|
}
|
|
|
|
setAtXYZ(this->_position, this->_facing, true, this->_isMoving, this->_isRetired);
|
|
|
|
}
|
2016-09-10 18:16:17 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-03-28 17:50:04 +02:00
|
|
|
bool isVisible = false;
|
|
|
|
if (!_isInvisible) {
|
|
|
|
isVisible = draw(screenRect);
|
|
|
|
if (isVisible) {
|
|
|
|
_screenRectangle = *screenRect;
|
|
|
|
}
|
|
|
|
}
|
2016-09-10 18:16:17 +02:00
|
|
|
|
2016-09-12 00:54:40 +02:00
|
|
|
if (needsUpdate) {
|
2016-09-10 18:16:17 +02:00
|
|
|
int nextFrameTime = remain + _frame_ms;
|
|
|
|
if (nextFrameTime <= 0)
|
|
|
|
nextFrameTime = 1;
|
|
|
|
countdownTimerStart(5, nextFrameTime);
|
|
|
|
}
|
2016-09-12 00:54:40 +02:00
|
|
|
if (this->_targetFacing >= 0) {
|
|
|
|
if (this->_targetFacing == this->_facing) {
|
|
|
|
this->_targetFacing = -1;
|
|
|
|
} else {
|
|
|
|
this->setFacing(this->_targetFacing, false);
|
|
|
|
}
|
|
|
|
}
|
2017-03-28 17:50:04 +02:00
|
|
|
return isVisible;
|
2015-05-02 22:31:07 +02:00
|
|
|
}
|
|
|
|
|
2017-03-28 17:50:04 +02:00
|
|
|
bool Actor::draw(Common::Rect *screenRect) {
|
2016-10-04 02:21:08 +02:00
|
|
|
Vector3 drawPosition(_position.x, -_position.z, _position.y + 2.0);
|
|
|
|
float drawAngle = M_PI - _facing * (M_PI / 512.0f);
|
|
|
|
float drawScale = _scale;
|
2015-05-02 22:31:07 +02:00
|
|
|
|
|
|
|
// TODO: Handle SHORTY mode
|
2016-10-03 12:38:43 +02:00
|
|
|
|
2017-07-30 22:34:21 +02:00
|
|
|
_vm->_sliceRenderer->drawInWorld(_animationId, _animationFrame, drawPosition, drawAngle, drawScale, _vm->_surfaceGame, _vm->_zbuffer->getData());
|
2017-03-28 17:50:04 +02:00
|
|
|
_vm->_sliceRenderer->getScreenRectangle(screenRect, _animationId, _animationFrame, drawPosition, drawAngle, drawScale);
|
|
|
|
|
|
|
|
return !screenRect->isEmpty();
|
2015-05-02 22:31:07 +02:00
|
|
|
}
|
|
|
|
|
2015-09-15 20:26:46 +02:00
|
|
|
int Actor::getSetId() {
|
|
|
|
return _setId;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Actor::setSetId(int setId) {
|
|
|
|
if (_setId == setId) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
int i;
|
|
|
|
|
2016-09-12 00:54:40 +02:00
|
|
|
if (_setId > 0) {
|
2015-09-15 20:26:46 +02:00
|
|
|
for (i = 0; i < (int)_vm->_gameInfo->getActorCount(); i++) {
|
|
|
|
if (_vm->_actors[i]->_id != _id && _vm->_actors[i]->_setId == _setId) {
|
2017-03-20 22:55:31 +01:00
|
|
|
_vm->_aiScripts->OtherAgentExitedThisScene(i, _id);
|
2015-09-15 20:26:46 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
_setId = setId;
|
2017-03-20 22:55:31 +01:00
|
|
|
_vm->_aiScripts->EnteredScene(_id, _setId);
|
2015-09-15 20:26:46 +02:00
|
|
|
if (_setId > 0) {
|
|
|
|
for (i = 0; i < (int)_vm->_gameInfo->getActorCount(); i++) {
|
|
|
|
if (_vm->_actors[i]->_id != _id && _vm->_actors[i]->_setId == _setId) {
|
2017-03-20 22:55:31 +01:00
|
|
|
_vm->_aiScripts->OtherAgentEnteredThisScene(i, _id);
|
2015-09-15 20:26:46 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void Actor::setFacing(int facing, bool halfOrSet) {
|
|
|
|
if (facing < 0 || facing >= 1024) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (halfOrSet) {
|
|
|
|
_facing = facing;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
int cw;
|
|
|
|
int ccw;
|
|
|
|
int offset;
|
|
|
|
|
|
|
|
if (facing > _facing) {
|
|
|
|
cw = facing - _facing;
|
|
|
|
ccw = _facing + 1024 - facing;
|
|
|
|
} else {
|
|
|
|
ccw = _facing - facing;
|
|
|
|
cw = facing + 1024 - _facing;
|
|
|
|
}
|
|
|
|
if (cw < ccw) {
|
|
|
|
if (cw <= 32) {
|
|
|
|
offset = cw;
|
|
|
|
} else {
|
|
|
|
offset = cw / 2;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (ccw <= 32) {
|
|
|
|
offset = -ccw;
|
|
|
|
} else {
|
|
|
|
offset = -ccw / 2;
|
|
|
|
}
|
|
|
|
}
|
2016-09-10 18:16:17 +02:00
|
|
|
|
2015-09-15 20:26:46 +02:00
|
|
|
_facing = (_facing + offset) % 1024;
|
|
|
|
}
|
|
|
|
|
2016-10-04 02:21:08 +02:00
|
|
|
void Actor::setBoundingBox(const Vector3 &position, bool retired) {
|
2015-09-19 01:43:38 +02:00
|
|
|
if (retired) {
|
2016-09-10 18:16:17 +02:00
|
|
|
_bbox->setXYZ(position.x - (_retiredWidth / 2.0f),
|
|
|
|
position.y,
|
|
|
|
position.z - (_retiredWidth / 2.0f),
|
2015-09-15 20:26:46 +02:00
|
|
|
|
2016-09-10 18:16:17 +02:00
|
|
|
position.x + (_retiredWidth / 2.0f),
|
|
|
|
position.y + _retiredHeight,
|
|
|
|
position.z + (_retiredWidth / 2.0f));
|
2015-09-19 01:43:38 +02:00
|
|
|
} else {
|
2016-09-10 18:16:17 +02:00
|
|
|
_bbox->setXYZ(position.x - 12.0f,
|
|
|
|
position.y + 6.0f,
|
|
|
|
position.z - 12.0f,
|
|
|
|
|
|
|
|
position.x + 12.0f,
|
|
|
|
position.y + 72.0f,
|
|
|
|
position.z + 12.0f);
|
2015-09-19 01:43:38 +02:00
|
|
|
}
|
2015-09-15 20:26:46 +02:00
|
|
|
}
|
|
|
|
|
2017-04-01 08:56:30 +02:00
|
|
|
float Actor::distanceFromView(View *view) const{
|
2016-09-20 00:33:06 +02:00
|
|
|
float xDist = this->_position.x - view->_cameraPosition.x;
|
2017-08-24 23:43:47 +02:00
|
|
|
float zDist = this->_position.z + view->_cameraPosition.z;
|
2016-09-20 00:33:06 +02:00
|
|
|
return sqrt(xDist * xDist + zDist * zDist);
|
|
|
|
}
|
|
|
|
|
2017-04-01 08:56:30 +02:00
|
|
|
bool Actor::isWalking() const {
|
2015-09-15 20:26:46 +02:00
|
|
|
return _walkInfo->isWalking();
|
|
|
|
}
|
|
|
|
|
2017-04-01 08:56:30 +02:00
|
|
|
bool Actor::isRunning() const {
|
2017-03-23 00:25:38 +01:00
|
|
|
return _walkInfo->isRunning();
|
|
|
|
}
|
|
|
|
|
2015-09-19 01:43:38 +02:00
|
|
|
void Actor::stopWalking(bool value) {
|
|
|
|
if (value && _id == 0) {
|
2015-09-15 20:26:46 +02:00
|
|
|
_vm->_playerActorIdle = true;
|
|
|
|
}
|
|
|
|
|
2016-09-10 18:16:17 +02:00
|
|
|
if (isWalking()) {
|
2017-03-29 01:50:47 +02:00
|
|
|
_walkInfo->stop(_id, true, _animationModeCombatIdle, 0);
|
2016-09-10 18:16:17 +02:00
|
|
|
} else if (inCombat()) {
|
2017-03-29 01:50:47 +02:00
|
|
|
changeAnimationMode(_animationModeCombatIdle, false);
|
2015-09-15 20:26:46 +02:00
|
|
|
} else {
|
2017-03-29 01:50:47 +02:00
|
|
|
changeAnimationMode(kAnimationModeIdle, false);
|
2015-09-15 20:26:46 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void Actor::faceActor(int otherActorId, bool animate) {
|
2017-04-01 08:56:30 +02:00
|
|
|
if (_setId != _vm->_scene->getSetId()) {
|
2015-09-15 20:26:46 +02:00
|
|
|
return;
|
|
|
|
}
|
2016-09-10 18:16:17 +02:00
|
|
|
|
2015-09-15 20:26:46 +02:00
|
|
|
Actor *otherActor = _vm->_actors[otherActorId];
|
|
|
|
|
|
|
|
if (_setId != otherActor->_setId) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
faceXYZ(otherActor->_position.x, otherActor->_position.y, otherActor->_position.z, animate);
|
|
|
|
}
|
|
|
|
|
2016-09-10 18:16:17 +02:00
|
|
|
void Actor::faceObject(const char *objectName, bool animate) {
|
2015-09-15 20:26:46 +02:00
|
|
|
int objectId = _vm->_scene->findObject(objectName);
|
|
|
|
if (objectId == -1) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
BoundingBox boundingBox;
|
|
|
|
_vm->_scene->objectGetBoundingBox(objectId, &boundingBox);
|
|
|
|
|
|
|
|
float x0, y0, z0, x1, y1, z1;
|
2016-09-10 18:16:17 +02:00
|
|
|
boundingBox.getXYZ(&x0, &y0, &z0, &x1, &y1, &z1);
|
2015-09-15 20:26:46 +02:00
|
|
|
|
|
|
|
float x = (x1 + x0) / 2.0f;
|
|
|
|
float z = (z1 + z0) / 2.0f;
|
|
|
|
faceXYZ(x, y0, z, animate);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Actor::faceItem(int itemId, bool animate) {
|
|
|
|
float x, y, z;
|
2016-09-10 18:16:17 +02:00
|
|
|
_vm->_items->getXYZ(itemId, &x, &y, &z);
|
2015-09-15 20:26:46 +02:00
|
|
|
faceXYZ(x, y, z, animate);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Actor::faceWaypoint(int waypointId, bool animate) {
|
|
|
|
float x, y, z;
|
2016-09-10 18:16:17 +02:00
|
|
|
_vm->_waypoints->getXYZ(waypointId, &x, &y, &z);
|
2015-09-15 20:26:46 +02:00
|
|
|
faceXYZ(x, y, z, animate);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Actor::faceXYZ(float x, float y, float z, bool animate) {
|
|
|
|
if (isWalking()) {
|
2016-10-04 02:21:08 +02:00
|
|
|
stopWalking(false);
|
2015-09-15 20:26:46 +02:00
|
|
|
}
|
|
|
|
if (x == _position.x && z == _position.z) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2016-10-04 02:21:08 +02:00
|
|
|
int heading = angle_1024(_position.x, _position.z, x, z);
|
2015-09-15 20:26:46 +02:00
|
|
|
faceHeading(heading, animate);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Actor::faceCurrentCamera(bool animate) {
|
|
|
|
faceXYZ(_vm->_view->_cameraPosition.x, _vm->_view->_cameraPosition.y, -_vm->_view->_cameraPosition.z, animate);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Actor::faceHeading(int heading, bool animate) {
|
|
|
|
if (heading != _facing) {
|
|
|
|
if (animate) {
|
|
|
|
_targetFacing = heading;
|
2016-09-12 00:54:40 +02:00
|
|
|
} else {
|
2015-09-15 20:26:46 +02:00
|
|
|
setFacing(heading, true);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void Actor::modifyFriendlinessToOther(int otherActorId, signed int change) {
|
2017-08-24 23:43:47 +02:00
|
|
|
_friendlinessToOther[otherActorId] = CLIP(_friendlinessToOther[otherActorId] + change, 0, 100);
|
2015-09-15 20:26:46 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void Actor::setFriendlinessToOther(int otherActorId, int friendliness) {
|
|
|
|
_friendlinessToOther[otherActorId] = friendliness;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Actor::setHonesty(int honesty) {
|
|
|
|
_honesty = honesty;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Actor::setIntelligence(int intelligence) {
|
|
|
|
_intelligence = intelligence;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Actor::setStability(int stability) {
|
|
|
|
_stability = stability;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Actor::setCombatAggressiveness(int combatAggressiveness) {
|
|
|
|
_combatAggressiveness = combatAggressiveness;
|
|
|
|
}
|
|
|
|
|
2015-09-19 01:43:38 +02:00
|
|
|
void Actor::setInvisible(bool isInvisible) {
|
|
|
|
_isInvisible = isInvisible;
|
2015-09-15 20:26:46 +02:00
|
|
|
}
|
|
|
|
|
2015-09-19 01:43:38 +02:00
|
|
|
void Actor::setImmunityToObstacles(bool isImmune) {
|
|
|
|
_isImmuneToObstacles = isImmune;
|
2015-09-15 20:26:46 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void Actor::modifyCurrentHP(signed int change) {
|
2017-08-24 23:43:47 +02:00
|
|
|
_currentHP = CLIP(_currentHP + change, 0, 100);
|
2015-09-15 20:26:46 +02:00
|
|
|
if (_currentHP > 0)
|
2016-10-04 02:21:08 +02:00
|
|
|
retire(false, 0, 0, -1);
|
2015-09-15 20:26:46 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void Actor::modifyMaxHP(signed int change) {
|
2017-08-24 23:43:47 +02:00
|
|
|
_maxHP = CLIP(_maxHP + change, 0, 100);
|
2015-09-15 20:26:46 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void Actor::modifyCombatAggressiveness(signed int change) {
|
2017-08-24 23:43:47 +02:00
|
|
|
_combatAggressiveness = CLIP(_combatAggressiveness + change, 0, 100);
|
2015-09-15 20:26:46 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void Actor::modifyHonesty(signed int change) {
|
2017-08-24 23:43:47 +02:00
|
|
|
_honesty = CLIP(_honesty + change, 0, 100);
|
2015-09-15 20:26:46 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void Actor::modifyIntelligence(signed int change) {
|
2017-08-24 23:43:47 +02:00
|
|
|
_intelligence = CLIP(_intelligence + change, 0, 100);
|
2015-09-15 20:26:46 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void Actor::modifyStability(signed int change) {
|
2017-08-24 23:43:47 +02:00
|
|
|
_stability = CLIP(_stability + change, 0, 100);
|
2015-09-15 20:26:46 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void Actor::setFlagDamageAnimIfMoving(bool value) {
|
|
|
|
_damageAnimIfMoving = value;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Actor::getFlagDamageAnimIfMoving() {
|
|
|
|
return _damageAnimIfMoving;
|
|
|
|
}
|
|
|
|
|
2016-09-10 18:16:17 +02:00
|
|
|
void Actor::retire(bool retired, int width, int height, int retiredByActorId) {
|
|
|
|
_isRetired = retired;
|
2015-09-15 20:26:46 +02:00
|
|
|
_retiredWidth = MAX(width, 0);
|
|
|
|
_retiredHeight = MAX(height, 0);
|
2016-09-10 18:16:17 +02:00
|
|
|
if (_id == 0 && _isRetired) {
|
2015-09-15 20:26:46 +02:00
|
|
|
_vm->playerLosesControl();
|
|
|
|
_vm->_playerDead = true;
|
|
|
|
}
|
2016-09-10 18:16:17 +02:00
|
|
|
if (_isRetired) {
|
2017-03-23 16:20:10 +01:00
|
|
|
_vm->_aiScripts->Retired(_id, retiredByActorId);
|
2015-09-15 20:26:46 +02:00
|
|
|
}
|
|
|
|
}
|
2015-09-19 01:43:38 +02:00
|
|
|
|
|
|
|
void Actor::setTargetable(bool targetable) {
|
|
|
|
_isTargetable = targetable;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Actor::setHealth(int hp, int maxHp) {
|
|
|
|
_currentHP = hp;
|
|
|
|
_maxHP = maxHp;
|
2016-09-10 18:16:17 +02:00
|
|
|
if (hp > 0) {
|
2016-10-04 02:21:08 +02:00
|
|
|
retire(false, 0, 0, -1);
|
2015-09-19 01:43:38 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-03-29 01:50:47 +02:00
|
|
|
void Actor::combatModeOn(int a2, int a3, int otherActorId, int a5, int animationModeCombatIdle, int animationModeCombatWalk, int animationModeCombatRun, int a9, int a10, int a11, int ammoDamage, int a13, int a14) {
|
|
|
|
_animationModeCombatIdle = animationModeCombatIdle;
|
|
|
|
_animationModeCombatWalk = animationModeCombatWalk;
|
|
|
|
_animationModeCombatRun = animationModeCombatRun;
|
2015-09-19 01:43:38 +02:00
|
|
|
_inCombat = true;
|
|
|
|
if (_id > 0)
|
|
|
|
_combatInfo->combatOn(_id, a2, a3, otherActorId, a5, a9, a10, a11, ammoDamage, a13, a14);
|
2016-10-04 02:21:08 +02:00
|
|
|
stopWalking(false);
|
2017-03-29 01:50:47 +02:00
|
|
|
changeAnimationMode(_animationModeCombatIdle, false);
|
2015-09-19 01:43:38 +02:00
|
|
|
int i;
|
|
|
|
for (i = 0; i < (int)_vm->_gameInfo->getActorCount(); i++) {
|
|
|
|
Actor *otherActor = _vm->_actors[i];
|
|
|
|
if (i != _id && otherActor->_setId == _setId && !otherActor->_isRetired) {
|
|
|
|
//TODO: _vm->actorScript->OtherAgentEnteredCombatMode(i, _id, 1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void Actor::combatModeOff() {
|
|
|
|
if (_id > 0)
|
|
|
|
_combatInfo->combatOff();
|
|
|
|
_inCombat = false;
|
2016-10-04 02:21:08 +02:00
|
|
|
stopWalking(false);
|
2017-03-29 01:50:47 +02:00
|
|
|
changeAnimationMode(kAnimationModeIdle, false);
|
2015-09-19 01:43:38 +02:00
|
|
|
int i;
|
|
|
|
for (i = 0; i < (int)_vm->_gameInfo->getActorCount(); i++) {
|
|
|
|
Actor *otherActor = _vm->_actors[i];
|
|
|
|
if (i != _id && otherActor->_setId == _setId && !otherActor->_isRetired) {
|
|
|
|
//TODO: _vm->actorScript->OtherAgentEnteredCombatMode(i, _id, 0);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
float Actor::distanceFromActor(int otherActorId) {
|
|
|
|
return (_position - _vm->_actors[otherActorId]->_position).length();
|
|
|
|
}
|
|
|
|
|
|
|
|
float Actor::getX() {
|
|
|
|
return _position.x;
|
|
|
|
}
|
|
|
|
|
|
|
|
float Actor::getY() {
|
|
|
|
return _position.y;
|
|
|
|
}
|
|
|
|
|
|
|
|
float Actor::getZ() {
|
|
|
|
return _position.z;
|
|
|
|
}
|
|
|
|
|
2016-09-12 00:54:40 +02:00
|
|
|
void Actor::getXYZ(float *x, float *y, float *z) {
|
2015-09-19 01:43:38 +02:00
|
|
|
*x = _position.x;
|
|
|
|
*y = _position.y;
|
|
|
|
*z = _position.z;
|
|
|
|
}
|
|
|
|
|
|
|
|
int Actor::getFacing() {
|
|
|
|
return _facing;
|
|
|
|
}
|
|
|
|
|
|
|
|
int Actor::getAnimationMode() {
|
|
|
|
return _animationMode;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Actor::setGoal(int goalNumber) {
|
2017-03-23 00:57:35 +01:00
|
|
|
int oldGoalNumber = _goalNumber;
|
|
|
|
_goalNumber = goalNumber;
|
|
|
|
if (goalNumber == oldGoalNumber) {
|
2015-09-19 01:43:38 +02:00
|
|
|
return;
|
2017-03-28 17:50:04 +02:00
|
|
|
}
|
2015-09-19 01:43:38 +02:00
|
|
|
|
2017-03-23 00:57:35 +01:00
|
|
|
_vm->_aiScripts->GoalChanged(_id, oldGoalNumber, goalNumber);
|
2017-03-23 16:20:10 +01:00
|
|
|
_vm->_sceneScript->ActorChangedGoal(_id, goalNumber, oldGoalNumber, _vm->_scene->getSetId() == _setId);
|
2015-09-19 01:43:38 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
int Actor::getGoal() {
|
|
|
|
return _goalNumber;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Actor::speechPlay(int sentenceId, bool voiceOver) {
|
|
|
|
char name[13];
|
|
|
|
sprintf(name, "%02d-%04d.AUD", _id, sentenceId); //TODO somewhere here should be also language code
|
|
|
|
int balance;
|
|
|
|
|
2016-10-24 19:24:32 +02:00
|
|
|
if (voiceOver || _id == VOICEOVER_ACTOR) {
|
2015-09-19 01:43:38 +02:00
|
|
|
balance = 0;
|
2016-09-10 18:16:17 +02:00
|
|
|
} else {
|
|
|
|
// Vector3 pos = _vm->_view->_frameViewMatrix * _position;
|
|
|
|
int screenX = 320; //, screenY = 0;
|
2015-09-19 01:43:38 +02:00
|
|
|
//TODO: transform to screen space using fov;
|
|
|
|
balance = 127 * (2 * screenX - 640) / 640;
|
2017-08-24 23:43:47 +02:00
|
|
|
balance = CLIP<int>(balance, -127, 127);
|
2015-09-19 01:43:38 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
_vm->_audioSpeech->playSpeech(name, balance);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Actor::speechStop() {
|
|
|
|
_vm->_audioSpeech->stopSpeech();
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Actor::isSpeeching() {
|
|
|
|
return _vm->_audioSpeech->isPlaying();
|
|
|
|
}
|
|
|
|
|
2017-04-02 18:17:43 +02:00
|
|
|
void Actor::addClueToDatabase(int clueId, int weight, bool clueAcquired, bool unknownFlag, int fromActorId) {
|
|
|
|
_clues->add(_id, clueId, weight, clueAcquired, unknownFlag, fromActorId);
|
2015-09-19 01:43:38 +02:00
|
|
|
}
|
|
|
|
|
2017-04-02 18:17:43 +02:00
|
|
|
void Actor::acquireClue(int clueId, bool unknownFlag, int fromActorId) {
|
2017-08-22 19:51:11 +02:00
|
|
|
bool hasAlready = hasClue(clueId);
|
2015-09-19 01:43:38 +02:00
|
|
|
_clues->acquire(clueId, unknownFlag, fromActorId);
|
2017-08-22 19:51:11 +02:00
|
|
|
if (!hasAlready) {
|
|
|
|
_vm->_aiScripts->ReceivedClue(_id, clueId, fromActorId);
|
|
|
|
}
|
2015-09-19 01:43:38 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void Actor::loseClue(int clueId) {
|
|
|
|
_clues->lose(clueId);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Actor::hasClue(int clueId) {
|
|
|
|
return _clues->isAcquired(clueId);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Actor::copyClues(int actorId) {
|
|
|
|
Actor *otherActor = _vm->_actors[actorId];
|
2016-10-03 12:38:43 +02:00
|
|
|
for (int i = 0; i < (int)_vm->_gameInfo->getClueCount(); i++) {
|
2016-09-10 18:16:17 +02:00
|
|
|
if (hasClue(i) && !_clues->isFlag4(i) && !otherActor->hasClue(i)) {
|
2015-09-19 01:43:38 +02:00
|
|
|
int fromActorId = _id;
|
2017-04-02 18:17:43 +02:00
|
|
|
if (_id == VOICEOVER_ACTOR) {
|
2015-09-19 01:43:38 +02:00
|
|
|
fromActorId = _clues->getFromActorId(i);
|
2017-04-02 18:17:43 +02:00
|
|
|
}
|
|
|
|
otherActor->acquireClue(i, false, fromActorId);
|
2015-09-19 01:43:38 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-04-01 08:56:30 +02:00
|
|
|
int Actor::soundVolume() const {
|
2016-09-20 00:33:06 +02:00
|
|
|
float dist = distanceFromView(_vm->_view);
|
2017-08-24 23:43:47 +02:00
|
|
|
return 35.0f * CLIP(1.0f - (dist / 1200.0f), 0.0f, 1.0f);
|
2016-09-20 00:33:06 +02:00
|
|
|
}
|
|
|
|
|
2017-04-01 08:56:30 +02:00
|
|
|
int Actor::soundBalance() const {
|
2016-10-02 00:20:56 +02:00
|
|
|
Vector3 screenPosition = _vm->_view->calculateScreenPosition(_position);
|
2017-08-24 23:43:47 +02:00
|
|
|
return 35.0f * (CLIP(screenPosition.x / 640.0f, 0.0f, 1.0f) * 2.0f - 1.0f);
|
2016-09-20 00:33:06 +02:00
|
|
|
}
|
|
|
|
|
2016-10-04 02:21:08 +02:00
|
|
|
bool Actor::walkFindU1(const Vector3 &startPosition, const Vector3 &targetPosition, float size, Vector3 *newDestination) {
|
|
|
|
newDestination->x = 0.0f;
|
|
|
|
newDestination->y = 0.0f;
|
|
|
|
newDestination->z = 0.0f;
|
|
|
|
int facing = angle_1024(targetPosition, startPosition);
|
|
|
|
int facing1 = 0;
|
|
|
|
|
|
|
|
int facing2 = facing;
|
|
|
|
int facing3 = 0;
|
|
|
|
while (true) {
|
2017-04-01 08:56:30 +02:00
|
|
|
float rotatedX = targetPosition.x + size * sin_1024(facing);
|
|
|
|
float rotatedZ = targetPosition.z - size * cos_1024(facing);
|
2016-10-04 02:21:08 +02:00
|
|
|
|
|
|
|
if (!_walkInfo->isXYZEmpty(rotatedX, targetPosition.y, rotatedZ, _id)) {
|
|
|
|
if (_vm->_scene->_set->findWalkbox(rotatedX, rotatedZ) >= 0) {
|
|
|
|
newDestination->x = rotatedX;
|
|
|
|
newDestination->y = targetPosition.y;
|
|
|
|
newDestination->z = rotatedZ;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
facing += 20;
|
|
|
|
if (facing > 1024) {
|
|
|
|
facing -= 1024;
|
|
|
|
}
|
|
|
|
facing3 += 20;
|
|
|
|
}
|
|
|
|
|
2016-10-04 18:59:25 +02:00
|
|
|
rotatedX = size * sin_1024(facing2) + targetPosition.x;
|
|
|
|
rotatedZ = size * cos_1024(facing2) + targetPosition.z;
|
2016-10-04 02:21:08 +02:00
|
|
|
|
|
|
|
if (!_walkInfo->isXYZEmpty(rotatedX, targetPosition.y, rotatedZ, _id)) {
|
|
|
|
if (_vm->_scene->_set->findWalkbox(rotatedX, rotatedZ) >= 0) {
|
|
|
|
newDestination->x = rotatedX;
|
|
|
|
newDestination->y = targetPosition.y;
|
|
|
|
newDestination->z = rotatedZ;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
facing2 -= 20;
|
|
|
|
if (facing2 < 0) {
|
|
|
|
facing2 += 1024;
|
|
|
|
}
|
|
|
|
facing1 += 20;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (facing3 > 1024 && facing1 > 1024) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Actor::walkFindU2(Vector3 *newDestination, float targetWidth, int destinationOffset, float targetSize, const Vector3 &startPosition, const Vector3 &targetPosition) {
|
|
|
|
newDestination->x = 0.0f;
|
|
|
|
newDestination->y = 0.0f;
|
|
|
|
newDestination->z = 0.0f;
|
|
|
|
float size = destinationOffset + targetSize * 0.5f + targetWidth * 0.5f;
|
|
|
|
float distance = (startPosition - targetPosition).length() - targetWidth * 0.5f - targetSize * 0.5f;
|
|
|
|
if (size < distance) {
|
|
|
|
return walkFindU1(startPosition, targetPosition, size, newDestination);
|
|
|
|
} else {
|
|
|
|
*newDestination = targetPosition;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-04-01 08:56:30 +02:00
|
|
|
bool Actor::walkToNearestPoint(const Vector3 &destination, float distance) {
|
2016-10-04 02:21:08 +02:00
|
|
|
Vector3 out;
|
2017-03-29 18:47:38 +02:00
|
|
|
bool flagIsRunning;
|
2017-04-01 08:56:30 +02:00
|
|
|
if (_walkInfo->findNearestEmptyPosition(_id, destination, distance, out)) {
|
2017-03-29 18:47:38 +02:00
|
|
|
loopWalk(out, 0, false, false, _position, 0.0f, 24.0f, false, &flagIsRunning, false);
|
2016-10-04 02:21:08 +02:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2015-05-02 22:31:07 +02:00
|
|
|
} // End of namespace BladeRunner
|