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"
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"
2018-03-17 16:40:33 +01:00
# include "bladerunner/bladerunner.h"
2015-05-02 22:31:07 +02:00
# include "bladerunner/boundingbox.h"
2018-01-14 12:12:06 +01:00
# include "bladerunner/game_info.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"
2018-03-17 16:14:48 +01:00
# include "bladerunner/savefile.h"
2016-09-10 18:16:17 +02:00
# include "bladerunner/scene.h"
# include "bladerunner/scene_objects.h"
2018-02-10 20:34:28 +01:00
# include "bladerunner/script/scene_script.h"
# include "bladerunner/script/ai_script.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"
2018-12-15 22:40:07 +01:00
# include "bladerunner/time.h"
2018-06-18 14:10:00 +03:00
# include "bladerunner/subtitles.h"
2016-09-10 18:16:17 +02:00
# 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 ;
2018-02-12 20:53:13 +01:00
_walkInfo = new ActorWalk ( vm ) ;
2015-09-15 20:26:46 +02:00
_movementTrack = new MovementTrack ( ) ;
2019-04-04 21:01:25 +03:00
_cluesLimit = ( actorId = = kActorMcCoy | | actorId = = kActorVoiceOver ) ? 4 : 2 ;
2018-11-21 23:16:15 +01:00
_clues = new ActorClues ( vm , _cluesLimit ) ;
2018-02-12 20:53:13 +01:00
_combatInfo = new ActorCombat ( vm ) ;
2015-05-02 22:31:07 +02:00
2018-02-12 20:53:13 +01:00
_friendlinessToOther . resize ( _vm - > _gameInfo - > getActorCount ( ) ) ;
2018-02-01 20:40:49 +01:00
2018-02-12 20:53:13 +01:00
setup ( actorId ) ;
2015-05-02 22:31:07 +02:00
}
Actor : : ~ Actor ( ) {
2016-09-12 00:54:40 +02:00
delete _combatInfo ;
delete _clues ;
delete _movementTrack ;
delete _walkInfo ;
2015-05-02 22:31:07 +02:00
}
void Actor : : setup ( int actorId ) {
2019-07-17 19:08:43 +03:00
_id = actorId ;
_setId = - 1 ;
2015-05-02 22:31:07 +02:00
2019-07-17 19:08:43 +03:00
_position = Vector3 ( 0.0 , 0.0 , 0.0 ) ;
_facing = 512 ;
_targetFacing = - 1 ;
_walkboxId = - 1 ;
2015-05-02 22:31:07 +02:00
2018-02-12 20:53:13 +01:00
_animationId = 0 ;
2015-05-02 22:31:07 +02:00
_animationFrame = 0 ;
2018-02-12 20:53:13 +01:00
_fps = 15 ;
2019-07-17 19:08:43 +03:00
_frameMs = 1000 / _fps ;
2015-05-02 22:31:07 +02:00
2019-03-04 12:13:37 +02:00
_mustReachWalkDestination = false ; // Original's _inWalkLoop. Moved here from our constructor, since it's here in the original's init()
2019-07-17 19:08:43 +03:00
_isMoving = false ;
_isTarget = false ;
_inCombat = false ;
_isInvisible = false ;
_isImmuneToObstacles = false ;
_isRetired = false ;
2016-09-10 18:16:17 +02:00
2019-07-17 19:08:43 +03:00
_width = 0 ;
_height = 0 ;
_retiredWidth = 0 ;
_retiredHeight = 0 ;
_scale = 1.0f ;
2015-05-02 22:31:07 +02:00
2019-07-17 19:08:43 +03:00
_timer4RemainDefault = 60000u ;
2018-03-30 00:25:25 +02:00
2017-03-23 00:25:38 +01:00
_movementTrackWalkingToWaypointId = - 1 ;
2019-07-22 01:08:23 +03:00
_movementTrackDelayOnNextWaypoint = - 1 ;
2017-03-23 00:25:38 +01:00
2019-04-09 16:31:39 +03:00
for ( int i = 0 ; i ! = kActorTimers ; + + i ) {
2019-07-17 19:08:43 +03:00
_timersLeft [ i ] = 0u ;
2018-12-15 22:40:07 +01:00
_timersLast [ i ] = _vm - > _time - > current ( ) ;
2015-05-02 22:31:07 +02:00
}
2019-04-09 16:31:39 +03:00
_timersLeft [ kActorTimerClueExchange ] = _timer4RemainDefault ; // This was in original code. We need to init this timer in order to kick off periodic updates for acquireCluesByRelations
2015-05-02 22:31:07 +02:00
2019-07-17 19:08:43 +03:00
_honesty = 50 ;
_intelligence = 50 ;
_combatAggressiveness = 50 ;
_stability = 50 ;
2015-05-02 22:31:07 +02:00
2019-07-17 19:08:43 +03:00
_currentHP = 50 ;
_maxHP = 50 ;
2019-03-04 12:13:37 +02:00
2019-07-17 19:08:43 +03:00
_damageAnimIfMoving = true ; // Set to true (like in original). And moved here from our constructor, since it's here in the original's init().
2019-03-04 12:13:37 +02:00
2019-07-17 19:08:43 +03:00
_goalNumber = - 1 ;
2015-05-02 22:31:07 +02:00
2018-02-12 20:53:13 +01:00
_movementTrackPaused = false ;
2017-03-23 00:25:38 +01:00
_movementTrackNextWaypointId = - 1 ;
2019-07-22 01:08:23 +03:00
_movementTrackNextDelay = - 1 ;
2018-02-12 20:53:13 +01:00
_movementTrackNextAngle = - 1 ;
_movementTrackNextRunning = false ;
2017-03-23 00:25:38 +01:00
2019-07-17 19:08:43 +03:00
_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 ;
2018-02-12 20:53:13 +01:00
_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 ;
2019-05-09 19:18:08 +03:00
# if BLADERUNNER_ORIGINAL_BUGS
# else
// if player actor was not idle and had an active _walkInfo then
2019-10-25 01:46:36 +03:00
// upon starting a new game, the player actor would be put on the old _walkInfo
2019-05-09 19:18:08 +03:00
_walkInfo - > reset ( ) ;
// // delete _walkInfo and re-allocate it (a reset method would probably be better)
// if (_walkInfo != nullptr) {
// delete(_walkInfo);
// }
// _walkInfo = new ActorWalk(_vm);
# endif // BLADERUNNER_ORIGINAL_BUGS
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 ( ) ;
2019-02-10 19:45:50 +01:00
switch ( _id ) {
case kActorMcCoy :
_sitcomRatio = 50 ;
break ;
case kActorGordo :
_sitcomRatio = 0 ;
break ;
case kActorGuzza :
case kActorChew :
case kActorVoiceOver :
_sitcomRatio = 75 ;
break ;
case kActorCrazylegs :
case kActorBulletBob :
case kActorRunciter :
case kActorZuben :
case kActorLeon :
_sitcomRatio = 90 ;
break ;
case kActorGrigorian :
case kActorMoraji :
_sitcomRatio = 100 ;
break ;
default :
_sitcomRatio = 33 ;
break ;
}
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 ) {
2018-02-10 20:34:28 +01:00
_vm - > _aiScripts - > changeAnimationMode ( _id , animationMode ) ;
2016-09-10 18:16:17 +02:00
_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 ;
2019-03-09 21:37:21 +01:00
if ( fps = = 0 ) { // stop actor's animation
2018-02-18 22:18:41 +01:00
_frameMs = 0 ;
2019-03-09 21:37:21 +01:00
} else if ( fps = = - 1 ) { // sync actor's animation with scene animation
2018-02-18 22:18:41 +01:00
_frameMs = - 1000 ;
2019-03-09 21:37:21 +01:00
} else if ( fps = = - 2 ) { // set FPS to default from the model
2016-09-10 18:16:17 +02:00
_fps = _vm - > _sliceAnimations - > getFPS ( _animationId ) ;
2018-02-18 22:18:41 +01:00
_frameMs = 1000 / _fps ;
2016-09-12 00:54:40 +02:00
} else {
2018-02-18 22:18:41 +01:00
_frameMs = 1000 / fps ;
2016-09-10 18:16:17 +02:00
}
}
2018-02-18 22:18:41 +01:00
void Actor : : increaseFPS ( ) {
int fps = MIN ( _fps + 3 , 30 ) ;
setFPS ( fps ) ;
}
2019-07-22 01:08:23 +03:00
void Actor : : timerStart ( int timerId , int32 interval ) {
2019-04-09 16:31:39 +03:00
assert ( timerId > = 0 & & timerId < kActorTimers ) ;
2019-07-22 01:08:23 +03:00
if ( interval < 0 ) {
interval = 0 ;
2019-07-17 19:08:43 +03:00
}
2019-07-22 01:08:23 +03:00
_timersLeft [ timerId ] = ( uint32 ) interval ;
2018-12-15 22:40:07 +01:00
_timersLast [ timerId ] = _vm - > _time - > current ( ) ;
2017-03-23 00:25:38 +01:00
}
2018-02-18 22:18:41 +01:00
void Actor : : timerReset ( int timerId ) {
2019-04-09 16:31:39 +03:00
assert ( timerId > = 0 & & timerId < kActorTimers ) ;
2019-07-17 19:08:43 +03:00
_timersLeft [ timerId ] = 0u ;
2017-03-23 00:25:38 +01:00
}
2019-07-17 19:08:43 +03:00
uint32 Actor : : timerLeft ( int timerId ) {
2019-04-09 16:31:39 +03:00
assert ( timerId > = 0 & & timerId < kActorTimers ) ;
2018-02-18 22:18:41 +01:00
return _timersLeft [ timerId ] ;
2017-03-23 00:25:38 +01:00
}
2018-02-18 22:18:41 +01:00
void Actor : : timersUpdate ( ) {
2017-03-23 00:25:38 +01:00
for ( int i = 0 ; i < = 6 ; i + + ) {
2018-02-18 22:18:41 +01:00
timerUpdate ( i ) ;
2017-03-23 00:25:38 +01:00
}
}
2018-02-18 22:18:41 +01:00
void Actor : : timerUpdate ( int timerId ) {
2019-07-17 19:08:43 +03:00
if ( _timersLeft [ timerId ] = = 0u ) {
2017-03-23 00:25:38 +01:00
return ;
}
2018-12-15 22:40:07 +01:00
uint32 timeNow = _vm - > _time - > current ( ) ;
2019-07-17 19:08:43 +03:00
uint32 timeDiff = timeNow - _timersLast [ timerId ] ; // unsigned difference is intentional
2018-02-18 22:18:41 +01:00
_timersLast [ timerId ] = timeNow ;
2019-07-17 19:08:43 +03:00
// new check is safe-guard against old saves, _timersLeft should never have very big value anyway
if ( ( int32 ) _timersLeft [ timerId ] < 0 ) {
// this will make it 0u in the next command below
_timersLeft [ timerId ] = 0u ;
}
_timersLeft [ timerId ] = ( _timersLeft [ timerId ] < timeDiff ) ? 0u : ( _timersLeft [ timerId ] - timeDiff ) ;
2017-03-23 00:25:38 +01:00
2019-07-17 19:08:43 +03:00
if ( _timersLeft [ timerId ] = = 0u ) { // original check was <= 0
2017-03-23 00:25:38 +01:00
switch ( timerId ) {
2019-04-09 16:31:39 +03:00
case kActorTimerAIScriptCustomTask0 :
2019-05-31 16:42:31 +03:00
// fall through
2019-04-09 16:31:39 +03:00
case kActorTimerAIScriptCustomTask1 :
2019-05-31 16:42:31 +03:00
// fall through
2019-04-09 16:31:39 +03:00
case kActorTimerAIScriptCustomTask2 :
2018-02-10 20:34:28 +01:00
if ( ! _vm - > _aiScripts - > isInsideScript ( ) & & ! _vm - > _sceneScript - > isInsideScript ( ) ) {
2018-02-18 22:18:41 +01:00
_vm - > _aiScripts - > timerExpired ( _id , timerId ) ;
2019-07-17 19:08:43 +03:00
_timersLeft [ timerId ] = 0u ;
2017-03-23 00:25:38 +01:00
} else {
2019-07-17 19:08:43 +03:00
_timersLeft [ timerId ] = 1u ;
2017-03-23 00:25:38 +01:00
}
break ;
2019-04-09 16:31:39 +03:00
case kActorTimerMovementTrack :
2019-07-17 19:08:43 +03:00
_timersLeft [ kActorTimerMovementTrack ] = 0u ;
2017-03-23 00:25:38 +01:00
if ( _movementTrack - > isPaused ( ) ) {
2019-07-17 19:08:43 +03:00
_timersLeft [ kActorTimerMovementTrack ] = 1u ;
2017-03-23 00:25:38 +01:00
} else {
movementTrackNext ( false ) ;
}
break ;
2019-04-09 16:31:39 +03:00
case kActorTimerClueExchange :
2018-02-18 22:18:41 +01:00
// Exchange clues between actors
2018-03-30 00:25:25 +02:00
acquireCluesByRelations ( ) ;
2019-04-09 16:31:39 +03:00
_timersLeft [ kActorTimerClueExchange ] = _timer4RemainDefault ;
2017-03-23 00:25:38 +01:00
break ;
2019-04-09 16:31:39 +03:00
case kActorTimerAnimationFrame :
2017-03-23 00:25:38 +01:00
// Actor animation frame timer
break ;
2019-04-09 16:31:39 +03:00
case kActorTimerRunningStaminaFPS :
2017-03-23 00:25:38 +01:00
if ( isRunning ( ) ) {
if ( _fps > 15 ) {
int newFps = _fps - 2 ;
if ( newFps < 15 ) {
newFps = 15 ;
}
setFPS ( newFps ) ;
}
}
2019-07-17 19:08:43 +03:00
_timersLeft [ kActorTimerRunningStaminaFPS ] = 200u ;
2017-03-23 00:25:38 +01:00
break ;
2019-10-04 01:34:31 +01:00
default :
break ;
2017-03-23 00:25:38 +01:00
}
}
}
void Actor : : movementTrackNext ( bool omitAiScript ) {
bool hasNextMovement ;
2018-02-19 22:04:44 +01:00
bool running ;
2017-03-23 00:25:38 +01:00
int angle ;
2019-07-22 01:08:23 +03:00
int32 delay ;
2017-03-23 00:25:38 +01:00
int waypointId ;
Vector3 waypointPosition ;
2017-04-01 08:56:30 +02:00
bool arrived ;
2017-03-23 00:25:38 +01:00
2018-02-19 22:04:44 +01:00
hasNextMovement = _movementTrack - > next ( & waypointId , & delay , & angle , & running ) ;
2017-03-23 00:25:38 +01:00
_movementTrackNextWaypointId = waypointId ;
_movementTrackNextDelay = delay ;
_movementTrackNextAngle = angle ;
2018-02-19 22:04:44 +01:00
_movementTrackNextRunning = running ;
2017-03-23 00:25:38 +01:00
if ( hasNextMovement ) {
if ( angle = = - 1 ) {
angle = 0 ;
}
2019-02-21 20:37:23 +01:00
int waypointSetId = _vm - > _waypoints - > getSetId ( waypointId ) ;
2017-03-23 00:25:38 +01:00
_vm - > _waypoints - > getXYZ ( waypointId , & waypointPosition . x , & waypointPosition . y , & waypointPosition . z ) ;
if ( _setId = = waypointSetId & & waypointSetId = = _vm - > _actors [ 0 ] - > _setId ) {
stopWalking ( false ) ;
2018-02-19 22:04:44 +01: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 ) {
2019-07-22 01:08:23 +03:00
delay = 1 ;
2017-03-23 00:25:38 +01:00
}
2019-07-22 01:08:23 +03:00
if ( delay > 1 ) {
2017-03-29 01:50:47 +02:00
changeAnimationMode ( kAnimationModeIdle , false ) ;
2017-03-23 00:25:38 +01:00
}
2019-04-09 16:31:39 +03:00
timerStart ( kActorTimerMovementTrack , delay ) ;
2017-03-23 00:25:38 +01:00
}
//return true;
} else {
if ( ! omitAiScript ) {
2018-02-10 20:34:28 +01:00
_vm - > _aiScripts - > completedMovementTrack ( _id ) ;
2017-03-23 00:25:38 +01:00
}
//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 ( ) {
2018-01-29 21:48:48 +01:00
if ( ! _movementTrack - > isPaused ( ) & & _id ! = kActorMcCoy ) {
2019-07-22 01:08:23 +03:00
if ( _movementTrackWalkingToWaypointId > = 0 & & _movementTrackDelayOnNextWaypoint > = 0 ) {
2017-03-23 00:25:38 +01:00
if ( ! _movementTrackDelayOnNextWaypoint ) {
2019-07-22 01:08:23 +03:00
_movementTrackDelayOnNextWaypoint = 1 ;
2016-09-12 00:54:40 +02:00
}
2019-08-28 21:32:12 +03:00
# if !BLADERUNNER_ORIGINAL_BUGS
// Honor the heading defined by the AI_Movement_Track_Append_With_Facing method
if ( _movementTrackNextAngle > = 0 ) {
faceHeading ( _movementTrackNextAngle , true ) ;
}
# endif
2018-02-10 20:34:28 +01:00
if ( _vm - > _aiScripts - > reachedMovementTrackWaypoint ( _id , _movementTrackWalkingToWaypointId ) ) {
2019-07-22 01:08:23 +03:00
int32 delay = _movementTrackDelayOnNextWaypoint ;
if ( delay > 1 ) {
2017-03-29 01:50:47 +02:00
changeAnimationMode ( kAnimationModeIdle , false ) ;
2018-02-18 22:18:41 +01:00
delay = _movementTrackDelayOnNextWaypoint ; // todo: analyze if movement is changed in some aiscript->ChangeAnimationMode?
2016-09-12 00:54:40 +02:00
}
2019-04-09 16:31:39 +03:00
timerStart ( kActorTimerMovementTrack , delay ) ;
2016-09-12 00:54:40 +02:00
}
}
2017-03-23 00:25:38 +01:00
_movementTrackWalkingToWaypointId = - 1 ;
2019-07-22 01:08:23 +03:00
_movementTrackDelayOnNextWaypoint = 0 ;
2017-03-23 00:25:38 +01:00
}
2016-09-12 00:54:40 +02:00
}
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
2018-01-14 12:12:06 +01:00
_vm - > _sceneObjects - > remove ( _id + kSceneObjectOffsetActors ) ;
2015-09-15 20:26:46 +02:00
2016-09-12 00:54:40 +02:00
if ( _vm - > _scene - > getSetId ( ) = = _setId ) {
2018-03-24 17:20:27 +01:00
_vm - > _sceneObjects - > addActor ( _id + kSceneObjectOffsetActors , _bbox , _screenRectangle , true , moving , _isTarget , 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 ) ;
}
2019-02-01 00:01:22 +01:00
bool Actor : : loopWalk ( const Vector3 & destination , int proximity , bool interruptible , bool runFlag , const Vector3 & start , float targetWidth , float targetSize , bool mustReach , bool * isRunningFlag , bool async ) {
2018-02-18 22:44:28 +01:00
* isRunningFlag = false ;
2016-10-04 02:21:08 +02:00
2019-02-01 00:01:22 +01:00
if ( proximity > 0 ) {
2018-01-29 21:48:48 +01:00
float dist = distance ( _position , destination ) ;
2019-02-01 00:01:22 +01:00
if ( dist - targetSize < = proximity ) {
2017-09-10 20:19:02 +02:00
return false ;
}
2018-01-29 21:48:48 +01:00
}
2016-10-04 02:21:08 +02:00
2019-02-01 00:01:22 +01:00
if ( mustReach & & ! async & & _id ! = kActorMcCoy & & proximity < = 24 ) {
2018-01-29 21:48:48 +01:00
if ( distance ( _vm - > _playerActor - > _position , destination ) < = 24.0f ) {
2019-02-01 00:01:22 +01:00
_vm - > _playerActor - > stepAway ( destination , 48.0f ) ;
2016-10-04 02:21:08 +02:00
}
2018-01-29 21:48:48 +01:00
}
2016-09-10 18:33:04 +02:00
2018-01-29 21:48:48 +01:00
if ( _id ! = kActorMcCoy ) {
interruptible = false ;
}
2016-09-10 18:16:17 +02:00
2018-01-29 21:48:48 +01:00
Vector3 destinationX ( destination ) ;
2016-10-04 02:21:08 +02:00
2019-02-01 00:01:22 +01:00
if ( proximity > 0 ) {
findNearestPosition ( & destinationX , targetWidth , proximity , targetSize , _position , destination ) ;
2018-01-29 21:48:48 +01:00
}
2016-10-04 02:21:08 +02:00
2019-02-01 00:01:22 +01:00
bool walking = walkTo ( runFlag , destinationX , mustReach ) ;
2016-10-04 02:21:08 +02:00
2018-01-29 21:48:48 +01:00
if ( async ) {
return false ;
}
2016-10-04 02:21:08 +02:00
2019-02-01 00:01:22 +01:00
if ( ! walking & & proximity > 0 ) {
walking = walkTo ( runFlag , destination , mustReach ) ;
2018-01-29 21:48:48 +01:00
}
2016-10-04 02:21:08 +02:00
2018-01-29 21:48:48 +01:00
if ( ! walking ) {
2018-02-18 22:18:41 +01:00
faceXYZ ( destination , false ) ;
2018-01-29 21:48:48 +01:00
return false ;
}
2016-10-04 02:21:08 +02:00
2018-01-29 21:48:48 +01:00
if ( _id ! = kActorMcCoy ) {
_vm - > _mouse - > disable ( ) ;
}
2018-02-12 20:53:13 +01:00
2018-01-29 21:48:48 +01:00
if ( interruptible ) {
2018-02-18 22:18:41 +01:00
_vm - > _isWalkingInterruptible = true ;
_vm - > _interruptWalking = false ;
2018-01-29 21:48:48 +01:00
} else {
_vm - > playerLosesControl ( ) ;
}
2016-10-04 02:21:08 +02:00
2019-02-01 00:01:22 +01:00
if ( mustReach ) {
_mustReachWalkDestination = true ;
2018-01-29 21:48:48 +01:00
}
2016-10-04 02:21:08 +02:00
2018-01-29 21:48:48 +01:00
bool wasInterrupted = false ;
while ( _walkInfo - > isWalking ( ) & & _vm - > _gameIsRunning ) {
if ( _walkInfo - > isRunning ( ) ) {
2018-02-18 22:44:28 +01:00
* isRunningFlag = true ;
2016-10-04 02:21:08 +02:00
}
2018-01-29 21:48:48 +01:00
_vm - > gameTick ( ) ;
if ( _id = = kActorMcCoy & & interruptible & & _vm - > _interruptWalking ) {
stopWalking ( false ) ;
wasInterrupted = true ;
2016-10-04 02:21:08 +02:00
}
2016-09-10 18:16:17 +02:00
}
2019-02-01 00:01:22 +01:00
if ( mustReach ) {
_mustReachWalkDestination = false ;
2018-01-29 21:48:48 +01:00
}
2019-02-01 00:01:22 +01:00
2018-01-29 21:48:48 +01:00
if ( interruptible ) {
_vm - > _isWalkingInterruptible = false ;
} else {
_vm - > playerGainsControl ( ) ;
}
2019-02-01 00:01:22 +01:00
2019-06-22 11:01:39 +03:00
# if BLADERUNNER_ORIGINAL_BUGS
2019-02-01 00:01:22 +01:00
if ( ! wasInterrupted & & proximity = = 0 & & ! _vm - > _playerActorIdle ) {
2018-01-29 21:48:48 +01:00
setAtXYZ ( destination , _facing , true , false , false ) ;
}
2019-06-22 11:01:39 +03:00
# else
if ( ! wasInterrupted & & proximity = = 0
& & ( _id = = kActorMcCoy & & ! _vm - > _playerActorIdle )
& & ! isRetired ( )
) {
setAtXYZ ( destination , _facing , true , false , false ) ;
}
# endif // BLADERUNNER_ORIGINAL_BUGS
2019-02-01 00:01:22 +01:00
2018-01-29 21:48:48 +01:00
if ( _id ! = kActorMcCoy ) {
_vm - > _mouse - > enable ( ) ;
}
2019-02-01 00:01:22 +01:00
2018-01-29 21:48:48 +01:00
return wasInterrupted ;
2016-09-10 18:16:17 +02:00
}
2019-02-01 00:01:22 +01:00
bool Actor : : walkTo ( bool runFlag , const Vector3 & destination , bool mustReach ) {
2017-04-01 08:56:30 +02:00
bool arrived ;
2019-02-01 00:01:22 +01:00
return _walkInfo - > setup ( _id , runFlag , _position , destination , mustReach , & arrived ) ;
2016-10-04 02:21:08 +02:00
}
2019-02-01 00:01:22 +01:00
bool Actor : : loopWalkToActor ( int otherActorId , int proximity , int interruptible , bool runFlag , bool mustReach , bool * isRunningFlag ) {
return loopWalk ( _vm - > _actors [ otherActorId ] - > _position , proximity , interruptible , runFlag , _position , 24.0f , 24.0f , mustReach , isRunningFlag , false ) ;
2017-09-10 20:19:02 +02:00
}
2019-02-01 00:01:22 +01:00
bool Actor : : loopWalkToItem ( int itemId , int proximity , int interruptible , bool runFlag , bool mustReach , bool * isRunningFlag ) {
2017-09-10 20:19:02 +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 ) ;
2019-02-01 00:01:22 +01:00
return loopWalk ( itemPosition , proximity , interruptible , runFlag , _position , width , 24.0f , mustReach , isRunningFlag , false ) ;
2016-10-04 02:21:08 +02:00
}
2016-09-10 18:16:17 +02:00
2019-02-01 00:01:22 +01:00
bool Actor : : loopWalkToSceneObject ( const Common : : String & objectName , int proximity , bool interruptible , bool runFlag , bool mustReach , bool * isRunningFlag ) {
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 ;
2016-09-10 18:16:17 +02:00
}
2019-02-21 20:37:23 +01: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
2019-02-01 00:01:22 +01:00
return loopWalk ( destination , proximity , interruptible , runFlag , _position , 0.0f , 24.0f , mustReach , isRunningFlag , false ) ;
2016-10-04 02:21:08 +02:00
}
2016-09-10 18:16:17 +02:00
2019-02-01 00:01:22 +01:00
bool Actor : : loopWalkToWaypoint ( int waypointId , int proximity , int interruptible , bool runFlag , bool mustReach , bool * isRunningFlag ) {
2017-03-23 00:25:38 +01:00
Vector3 waypointPosition ;
_vm - > _waypoints - > getXYZ ( waypointId , & waypointPosition . x , & waypointPosition . y , & waypointPosition . z ) ;
2019-02-01 00:01:22 +01:00
return loopWalk ( waypointPosition , proximity , interruptible , runFlag , _position , 0.0f , 24.0f , mustReach , isRunningFlag , false ) ;
2016-09-10 18:16:17 +02:00
}
2019-02-01 00:01:22 +01:00
bool Actor : : loopWalkToXYZ ( const Vector3 & destination , int proximity , bool interruptible , bool runFlag , bool mustReach , bool * isRunningFlag ) {
return loopWalk ( destination , proximity , interruptible , runFlag , _position , 0.0f , 24.0f , mustReach , isRunningFlag , false ) ;
2017-09-10 20:19:02 +02:00
}
2019-02-01 00:01:22 +01:00
bool Actor : : asyncWalkToWaypoint ( int waypointId , int proximity , bool runFlag , bool mustReach ) {
2018-02-18 22:44:28 +01:00
bool running ;
2017-09-10 20:19:02 +02:00
Vector3 waypointPosition ;
_vm - > _waypoints - > getXYZ ( waypointId , & waypointPosition . x , & waypointPosition . y , & waypointPosition . z ) ;
2019-02-01 00:01:22 +01:00
return loopWalk ( waypointPosition , proximity , false , runFlag , _position , 0.0f , 24.0f , mustReach , & running , true ) ;
2017-09-10 20:19:02 +02:00
}
2019-02-01 00:01:22 +01:00
void Actor : : asyncWalkToXYZ ( const Vector3 & destination , int proximity , bool runFlag , bool mustReach ) {
2018-02-18 22:44:28 +01:00
bool running ;
2019-02-01 00:01:22 +01:00
loopWalk ( destination , proximity , false , runFlag , _position , 0.0f , 24.0f , mustReach , & running , true ) ;
2018-02-18 22:18:41 +01:00
}
void Actor : : run ( ) {
_walkInfo - > run ( _id ) ;
2017-09-10 20:19:02 +02:00
}
2017-03-28 17:50:04 +02:00
bool Actor : : tick ( bool forceDraw , Common : : Rect * screenRect ) {
2019-07-17 19:08:43 +03:00
uint32 timeLeft = 0u ;
2016-09-10 18:16:17 +02:00
bool needsUpdate = false ;
2016-09-12 00:54:40 +02:00
if ( _fps > 0 ) {
2019-04-09 16:31:39 +03:00
timerUpdate ( kActorTimerAnimationFrame ) ;
timeLeft = timerLeft ( kActorTimerAnimationFrame ) ;
2019-07-17 19:08:43 +03:00
needsUpdate = ( timeLeft = = 0 ) ; // original was <= 0, with timeLeft int
2019-03-09 21:37:21 +01:00
} else if ( _fps = = 0 ) {
needsUpdate = false ;
2016-09-12 00:54:40 +02:00
} else if ( forceDraw ) {
2016-09-10 18:16:17 +02:00
needsUpdate = true ;
2019-07-17 19:08:43 +03:00
timeLeft = 0u ;
2016-09-10 18:16:17 +02:00
}
2018-07-02 10:45:17 +03:00
2016-09-12 00:54:40 +02:00
if ( needsUpdate ) {
2016-09-10 18:16:17 +02:00
int newAnimation = 0 , newFrame = 0 ;
2018-02-10 20:34:28 +01:00
_vm - > _aiScripts - > updateAnimation ( _id , & newAnimation , & newFrame ) ;
2016-09-10 18:16:17 +02:00
2019-01-21 21:57:44 +01:00
assert ( newFrame > = 0 ) ;
2019-01-19 23:12:45 +01:00
2016-09-10 18:16:17 +02:00
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
2018-01-29 21:48:48 +01:00
if ( _id = = kActorHysteriaPatron1 ) {
2016-09-12 00:54:40 +02:00
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
}
2018-02-18 22:18:41 +01:00
_targetFacing = - 1 ;
2016-09-12 00:54:40 +02:00
2019-02-01 00:01:22 +01:00
bool walkInterrupted = _walkInfo - > tick ( _id , - positionChange . y , _mustReachWalkDestination ) ;
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 ) ;
2018-02-18 22:18:41 +01:00
setAtXYZ ( pos , facing , false , _isMoving , false ) ;
2019-02-01 00:01:22 +01:00
if ( walkInterrupted ) {
2017-03-29 01:50:47 +02:00
_vm - > _actors [ _id ] - > changeAnimationMode ( kAnimationModeIdle ) ;
2018-02-18 22:18:41 +01:00
movementTrackWaypointReached ( ) ;
if ( inCombat ( ) ) {
changeAnimationMode ( _animationModeCombatIdle , false ) ;
2016-09-12 00:54:40 +02:00
} else {
2018-02-18 22:18:41 +01:00
changeAnimationMode ( kAnimationModeIdle , false ) ;
2016-09-12 00:54:40 +02:00
}
}
} else {
2019-08-28 21:32:12 +03:00
// actor is not walking / is idle
2016-10-04 02:21:08 +02:00
if ( angleChange ! = 0.0f ) {
int facingChange = angleChange * ( 512.0f / M_PI ) ;
if ( facingChange ! = 0 ) {
2018-02-18 22:18:41 +01:00
_facing = _facing - facingChange ;
2019-01-19 10:29:32 +01:00
while ( _facing < 0 ) {
2018-02-18 22:18:41 +01:00
_facing + = 1024 ;
2016-09-12 00:54:40 +02:00
}
2019-01-19 10:29:32 +01:00
while ( _facing > = 1024 ) {
_facing - = 1024 ;
2016-09-12 00:54:40 +02:00
}
}
}
2019-08-28 21:32:12 +03:00
if ( _vm - > _cutContent ) {
// the following Generic Walker models don't have an animation Id that is idle
// so we use a frame of their walking animation to show them as stopped
// However, we also need to override the positionChange vector for their walking animation too
if ( ( _id = = kActorGenwalkerA | | _id = = kActorGenwalkerB | | _id = = kActorGenwalkerC )
& &
( _animationId = = 436 | | _animationId = = 434 | | _animationId = = 435 | | _animationId = = 422 | | _animationId = = 423 )
) {
positionChange . x = 0.0f ;
positionChange . y = 0.0f ;
positionChange . z = 0.0f ;
}
}
2016-09-12 00:54:40 +02:00
if ( 0.0f ! = positionChange . x | | 0.0f ! = positionChange . y | | 0.0f ! = positionChange . z ) {
2018-02-18 22:18:41 +01:00
if ( _actorSpeed . x ! = 0.0f ) {
positionChange . x = positionChange . x * _actorSpeed . x ;
2016-09-12 00:54:40 +02:00
}
2018-02-18 22:18:41 +01:00
if ( _actorSpeed . y ! = 0.0f ) {
positionChange . y = positionChange . y * _actorSpeed . y ;
2016-09-12 00:54:40 +02:00
}
2018-02-18 22:18:41 +01:00
if ( _actorSpeed . z ! = 0.0f ) {
positionChange . z = positionChange . z * _actorSpeed . z ;
2016-09-12 00:54:40 +02:00
}
2018-06-23 21:34:38 -07:00
float sinx = _vm - > _sinTable1024 - > at ( _facing ) ;
float cosx = _vm - > _cosTable1024 - > at ( _facing ) ;
2016-09-12 00:54:40 +02:00
2018-02-18 22:18:41 +01:00
float originalX = _position . x ;
float originalY = _position . y ;
float originalZ = _position . z ;
2016-09-12 00:54:40 +02:00
2018-03-06 00:07:42 +01:00
// Yes, Z & Y are switched between world space and model space. X is also negated for some unknown reason (wrong dirertion for angles?)
_position . x = _position . x - positionChange . x * cosx - positionChange . y * sinx ;
_position . z = _position . z - positionChange . x * sinx + positionChange . y * cosx ;
2018-02-18 22:18:41 +01:00
_position . y = _position . y + positionChange . z ;
2016-09-12 00:54:40 +02:00
2018-02-18 22:18:41 +01:00
if ( _vm - > _sceneObjects - > existsOnXZ ( _id + kSceneObjectOffsetActors , _position . x , _position . z , false , false ) = = 1 & & ! _isImmuneToObstacles ) {
_position . x = originalX ;
_position . y = originalY ;
_position . z = originalZ ;
2016-09-12 00:54:40 +02:00
}
2018-02-18 22:18:41 +01:00
setAtXYZ ( _position , _facing , true , _isMoving , _isRetired ) ;
2016-09-12 00:54:40 +02:00
}
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 ) {
2019-07-17 19:08:43 +03:00
int nextFrameTime = ( int ) ( timeLeft + _frameMs ) ; // Should be ok
2018-02-18 22:18:41 +01:00
if ( nextFrameTime < = 0 ) {
2016-09-10 18:16:17 +02:00
nextFrameTime = 1 ;
2018-02-18 22:18:41 +01:00
}
2019-07-22 01:08:23 +03:00
timerStart ( kActorTimerAnimationFrame , nextFrameTime ) ;
2016-09-10 18:16:17 +02:00
}
2018-02-18 22:18:41 +01:00
if ( _targetFacing > = 0 ) {
if ( _targetFacing = = _facing ) {
_targetFacing = - 1 ;
2016-09-12 00:54:40 +02:00
} else {
2018-02-18 22:18:41 +01:00
setFacing ( _targetFacing , false ) ;
2016-09-12 00:54:40 +02:00
}
}
2017-03-28 17:50:04 +02:00
return isVisible ;
2015-05-02 22:31:07 +02:00
}
2018-03-17 16:40:33 +01:00
void Actor : : tickCombat ( ) {
if ( _id ! = kActorMcCoy & & ! _isRetired & & _inCombat ) {
_combatInfo - > tick ( ) ;
}
}
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 ) ;
2019-05-05 22:16:28 +02:00
# if !BLADERUNNER_ORIGINAL_BUGS
// In the original game, Moraji appears to be floating above the ground a bit
if ( _id = = kActorMoraji & & _setId = = kSetDR01_DR02_DR04 ) {
drawPosition . z - = 6.0f ;
}
# endif
2016-10-04 02:21:08 +02:00
float drawAngle = M_PI - _facing * ( M_PI / 512.0f ) ;
float drawScale = _scale ;
2015-05-02 22:31:07 +02:00
2019-02-10 20:32:49 +01:00
if ( _vm - > _shortyMode ) {
drawScale = 0.7f ;
}
2016-10-03 12:38:43 +02:00
2018-01-14 12:12:06 +01:00
_vm - > _sliceRenderer - > drawInWorld ( _animationId , _animationFrame , drawPosition , drawAngle , drawScale , _vm - > _surfaceFront , _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
}
2018-01-14 12:12:06 +01:00
int Actor : : getSetId ( ) const {
2015-09-15 20:26:46 +02:00
return _setId ;
}
void Actor : : setSetId ( int setId ) {
if ( _setId = = setId ) {
return ;
}
int i ;
2020-02-04 17:02:28 +02:00
// leaving _setId for setId
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 ) {
2018-02-10 20:34:28 +01:00
_vm - > _aiScripts - > otherAgentExitedThisScene ( i , _id ) ;
2015-09-15 20:26:46 +02:00
}
}
}
2020-02-04 17:02:28 +02:00
// _setId updated to new (arrived in) setId
2015-09-15 20:26:46 +02:00
_setId = setId ;
2018-02-10 20:34:28 +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 ) {
2018-02-10 20:34:28 +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
2019-01-19 10:29:32 +01:00
_facing + = offset ;
while ( _facing < 0 ) {
_facing + = 1024 ;
}
while ( _facing > = 1024 ) {
_facing - = 1024 ;
}
2015-09-15 20:26:46 +02:00
}
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 ) {
2018-03-24 17:20:27 +01:00
_bbox . setXYZ ( position . x - ( _retiredWidth / 2.0f ) ,
position . y ,
position . z - ( _retiredWidth / 2.0f ) ,
2015-09-15 20:26:46 +02:00
2018-03-24 17:20:27 +01:00
position . x + ( _retiredWidth / 2.0f ) ,
position . y + _retiredHeight ,
position . z + ( _retiredWidth / 2.0f ) ) ;
2015-09-19 01:43:38 +02:00
} else {
2018-03-24 17:20:27 +01:00
_bbox . setXYZ ( position . x - 12.0f ,
position . y + 6.0f ,
position . z - 12.0f ,
2016-09-10 18:16:17 +02:00
2018-03-24 17:20:27 +01:00
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 {
2018-02-18 22:18:41 +01:00
float xDist = _position . x - view - > _cameraPosition . x ;
2018-03-11 11:41:21 +01:00
float zDist = _position . z + view - > _cameraPosition . y ; // y<->z is intentional, not a bug
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 ) {
2018-01-29 21:48:48 +01:00
if ( value & & _id = = kActorMcCoy ) {
2015-09-15 20:26:46 +02:00
_vm - > _playerActorIdle = true ;
}
2016-09-10 18:16:17 +02:00
if ( isWalking ( ) ) {
2019-05-20 13:12:06 +03:00
_walkInfo - > stop ( _id , true , _animationModeCombatIdle , kAnimationModeIdle ) ;
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 ;
}
2018-02-18 22:18:41 +01:00
faceXYZ ( otherActor - > _position , animate ) ;
2015-09-15 20:26:46 +02:00
}
2018-03-24 17:20:27 +01:00
void Actor : : faceObject ( const Common : : String & 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 ) ;
}
2018-02-18 22:18:41 +01:00
void Actor : : faceXYZ ( const Vector3 & pos , bool animate ) {
faceXYZ ( pos . x , pos . y , pos . z , animate ) ;
}
2015-09-15 20:26:46 +02:00
void Actor : : faceCurrentCamera ( bool animate ) {
2018-03-11 11:41:21 +01:00
faceXYZ ( _vm - > _view - > _cameraPosition . x , _vm - > _view - > _cameraPosition . z , - _vm - > _view - > _cameraPosition . y , animate ) ; // y<->z is intentional, not a bug
2015-09-15 20:26:46 +02:00
}
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 ) {
2019-07-29 13:56:47 +03:00
_friendlinessToOther [ otherActorId ] = CLIP ( friendliness , 0 , 100 ) ;
2015-09-15 20:26:46 +02:00
}
2018-03-30 00:25:25 +02:00
bool Actor : : checkFriendlinessAndHonesty ( int otherActorId ) {
int honestyDiff = 2 * _friendlinessToOther [ otherActorId ] - _honesty ;
2018-06-29 09:20:20 +02:00
uint friendlinessRange ;
2018-03-30 00:25:25 +02:00
if ( honestyDiff > 30 ) {
friendlinessRange = 100 ;
} else if ( honestyDiff > = 0 & & honestyDiff < = 30 ) {
friendlinessRange = 50 ;
} else {
friendlinessRange = 0 ;
}
return _vm - > _rnd . getRandomNumberRng ( 1 , 100 ) < = friendlinessRange ;
}
2015-09-15 20:26:46 +02:00
void Actor : : setHonesty ( int honesty ) {
2019-07-29 13:56:47 +03:00
_honesty = CLIP ( honesty , 0 , 100 ) ;
2015-09-15 20:26:46 +02:00
}
void Actor : : setIntelligence ( int intelligence ) {
2019-07-29 13:56:47 +03:00
_intelligence = CLIP ( intelligence , 0 , 100 ) ;
2015-09-15 20:26:46 +02:00
}
void Actor : : setStability ( int stability ) {
2019-07-29 13:56:47 +03:00
_stability = CLIP ( stability , 0 , 100 ) ;
2015-09-15 20:26:46 +02:00
}
void Actor : : setCombatAggressiveness ( int combatAggressiveness ) {
2019-07-29 13:56:47 +03:00
_combatAggressiveness = CLIP ( combatAggressiveness , 0 , 100 ) ;
2015-09-15 20:26:46 +02:00
}
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 : : 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 ;
}
2018-01-14 12:12:06 +01:00
bool Actor : : getFlagDamageAnimIfMoving ( ) const {
2015-09-15 20:26:46 +02:00
return _damageAnimIfMoving ;
}
2019-02-10 19:45:50 +01:00
int Actor : : getSitcomRatio ( ) const {
return _sitcomRatio ;
}
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 ) ;
2018-01-29 21:48:48 +01:00
if ( _id = = kActorMcCoy & & _isRetired ) {
2015-09-15 20:26:46 +02:00
_vm - > playerLosesControl ( ) ;
_vm - > _playerDead = true ;
}
2016-09-10 18:16:17 +02:00
if ( _isRetired ) {
2018-02-10 20:34:28 +01:00
_vm - > _aiScripts - > retired ( _id , retiredByActorId ) ;
2015-09-15 20:26:46 +02:00
}
}
2015-09-19 01:43:38 +02:00
2018-02-18 22:18:41 +01:00
void Actor : : setTarget ( bool target ) {
_isTarget = target ;
2015-09-19 01:43:38 +02:00
}
2018-03-17 16:40:33 +01:00
void Actor : : setCurrentHP ( int hp ) {
2019-07-29 13:56:47 +03:00
_currentHP = CLIP ( hp , 0 , 100 ) ;
2018-03-17 16:40:33 +01:00
if ( hp > 0 ) {
retire ( false , 0 , 0 , - 1 ) ;
}
}
2015-09-19 01:43:38 +02:00
void Actor : : setHealth ( int hp , int maxHp ) {
2019-07-29 13:56:47 +03:00
if ( hp > maxHp ) {
hp = maxHp ;
}
_currentHP = CLIP ( hp , 0 , 100 ) ;
_maxHP = CLIP ( maxHp , 0 , 100 ) ;
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
}
}
2018-03-17 16:40:33 +01:00
void Actor : : modifyCurrentHP ( signed int change ) {
_currentHP = CLIP ( _currentHP + change , 0 , 100 ) ;
if ( _currentHP > 0 ) {
retire ( false , 0 , 0 , - 1 ) ;
}
}
void Actor : : modifyMaxHP ( signed int change ) {
_maxHP = CLIP ( _maxHP + change , 0 , 100 ) ;
}
2019-01-28 19:23:30 +01:00
void Actor : : combatModeOn ( int initialState , bool rangedAttack , int enemyId , int waypointType , int animationModeCombatIdle , int animationModeCombatWalk , int animationModeCombatRun , int fleeRatio , int coverRatio , int attackRatio , int damage , int range , bool unstoppable ) {
2017-03-29 01:50:47 +02:00
_animationModeCombatIdle = animationModeCombatIdle ;
_animationModeCombatWalk = animationModeCombatWalk ;
_animationModeCombatRun = animationModeCombatRun ;
2015-09-19 01:43:38 +02:00
_inCombat = true ;
2019-02-20 22:02:43 +01:00
if ( _id ! = kActorMcCoy & & enemyId ! = - 1 ) {
2019-01-28 19:23:30 +01:00
_combatInfo - > combatOn ( _id , initialState , rangedAttack , enemyId , waypointType , fleeRatio , coverRatio , attackRatio , damage , range , unstoppable ) ;
2018-02-19 22:04:44 +01:00
}
2016-10-04 02:21:08 +02:00
stopWalking ( false ) ;
2017-03-29 01:50:47 +02:00
changeAnimationMode ( _animationModeCombatIdle , false ) ;
2018-03-17 17:07:51 +01:00
for ( int i = 0 ; i < ( int ) _vm - > _gameInfo - > getActorCount ( ) ; i + + ) {
2015-09-19 01:43:38 +02:00
Actor * otherActor = _vm - > _actors [ i ] ;
if ( i ! = _id & & otherActor - > _setId = = _setId & & ! otherActor - > _isRetired ) {
2018-02-19 22:04:44 +01:00
_vm - > _aiScripts - > otherAgentEnteredCombatMode ( i , _id , true ) ;
2015-09-19 01:43:38 +02:00
}
}
}
void Actor : : combatModeOff ( ) {
2018-02-19 22:04:44 +01:00
if ( _id ! = kActorMcCoy ) {
2015-09-19 01:43:38 +02:00
_combatInfo - > combatOff ( ) ;
2018-02-19 22:04:44 +01:00
}
2015-09-19 01:43:38 +02:00
_inCombat = false ;
2016-10-04 02:21:08 +02:00
stopWalking ( false ) ;
2017-03-29 01:50:47 +02:00
changeAnimationMode ( kAnimationModeIdle , false ) ;
2018-03-17 17:07:51 +01:00
for ( int i = 0 ; i < ( int ) _vm - > _gameInfo - > getActorCount ( ) ; i + + ) {
2015-09-19 01:43:38 +02:00
Actor * otherActor = _vm - > _actors [ i ] ;
if ( i ! = _id & & otherActor - > _setId = = _setId & & ! otherActor - > _isRetired ) {
2018-02-19 22:04:44 +01:00
_vm - > _aiScripts - > otherAgentEnteredCombatMode ( i , _id , false ) ;
2015-09-19 01:43:38 +02:00
}
}
}
float Actor : : distanceFromActor ( int otherActorId ) {
return ( _position - _vm - > _actors [ otherActorId ] - > _position ) . length ( ) ;
}
2018-03-17 16:40:33 +01:00
int Actor : : angleTo ( const Vector3 & target ) const {
int angle = angle_1024 ( _position . x , _position . z , target . x , target . z ) - _facing ;
if ( angle < - 512 ) {
angle + = 1024 ;
} else if ( angle > 512 ) {
angle - = 1024 ;
}
return angle ;
}
2018-01-14 12:12:06 +01:00
float Actor : : getX ( ) const {
2015-09-19 01:43:38 +02:00
return _position . x ;
}
2018-01-14 12:12:06 +01:00
float Actor : : getY ( ) const {
2015-09-19 01:43:38 +02:00
return _position . y ;
}
2018-01-14 12:12:06 +01:00
float Actor : : getZ ( ) const {
2015-09-19 01:43:38 +02:00
return _position . z ;
}
2018-03-17 16:40:33 +01:00
Vector3 Actor : : getXYZ ( ) const {
return _position ;
2015-09-19 01:43:38 +02:00
}
2018-01-14 12:12:06 +01:00
int Actor : : getFacing ( ) const {
2015-09-19 01:43:38 +02:00
return _facing ;
}
2018-01-14 12:12:06 +01:00
int Actor : : getAnimationMode ( ) const {
2015-09-19 01:43:38 +02:00
return _animationMode ;
}
2019-05-04 17:24:20 +03:00
int Actor : : getAnimationId ( ) const {
return _animationId ;
}
2015-09-19 01:43:38 +02:00
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
2018-02-10 20:34:28 +01:00
_vm - > _aiScripts - > goalChanged ( _id , oldGoalNumber , goalNumber ) ;
_vm - > _sceneScript - > actorChangedGoal ( _id , goalNumber , oldGoalNumber , _vm - > _scene - > getSetId ( ) = = _setId ) ;
2015-09-19 01:43:38 +02:00
}
2018-01-14 12:12:06 +01:00
int Actor : : getGoal ( ) const {
2015-09-19 01:43:38 +02:00
return _goalNumber ;
}
void Actor : : speechPlay ( int sentenceId , bool voiceOver ) {
2018-03-24 17:20:27 +01:00
Common : : String name = Common : : String : : format ( " %02d-%04d%s.AUD " , _id , sentenceId , _vm - > _languageCode . c_str ( ) ) ;
2015-09-19 01:43:38 +02:00
2019-03-06 20:32:45 +01:00
int pan = 0 ;
2018-03-24 17:20:27 +01:00
if ( ! voiceOver & & _id ! = BladeRunnerEngine : : kActorVoiceOver ) {
2019-03-04 19:10:45 +01:00
Vector3 screenPosition = _vm - > _view - > calculateScreenPosition ( _position ) ;
2019-03-06 20:32:45 +01:00
pan = ( 75 * ( 2 * CLIP < int > ( screenPosition . x , 0 , 640 ) - 640 ) ) / 640 ; // map [0..640] to [-75..75]
2015-09-19 01:43:38 +02:00
}
2019-07-15 00:26:18 +02:00
_vm - > _subtitles - > loadInGameSubsText ( _id , sentenceId ) ;
2018-07-02 10:45:17 +03:00
_vm - > _subtitles - > show ( ) ;
2019-03-06 20:32:45 +01:00
_vm - > _audioSpeech - > playSpeech ( name , pan ) ;
2015-09-19 01:43:38 +02:00
}
void Actor : : speechStop ( ) {
2018-07-02 10:45:17 +03:00
_vm - > _subtitles - > hide ( ) ;
2015-09-19 01:43:38 +02:00
_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
}
2018-11-21 23:16:15 +01:00
bool Actor : : canAcquireClue ( int clueId ) const {
return _clues - > exists ( clueId ) ;
}
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 ) {
2018-02-10 20:34:28 +01:00
_vm - > _aiScripts - > receivedClue ( _id , clueId , fromActorId ) ;
2017-08-22 19:51:11 +02:00
}
2015-09-19 01:43:38 +02:00
}
void Actor : : loseClue ( int clueId ) {
_clues - > lose ( clueId ) ;
}
2018-01-14 12:12:06 +01:00
bool Actor : : hasClue ( int clueId ) const {
2015-09-19 01:43:38 +02:00
return _clues - > isAcquired ( clueId ) ;
}
2019-05-13 00:10:27 +03:00
bool Actor : : copyClues ( int actorId ) {
bool newCluesAcquired = false ;
2015-09-19 01:43:38 +02:00
Actor * otherActor = _vm - > _actors [ actorId ] ;
2016-10-03 12:38:43 +02:00
for ( int i = 0 ; i < ( int ) _vm - > _gameInfo - > getClueCount ( ) ; i + + ) {
2019-09-05 13:13:21 +03:00
int clueId = i ;
2019-09-05 10:37:47 +03:00
if ( hasClue ( clueId ) & & ! _clues - > isPrivate ( clueId ) & & otherActor - > canAcquireClue ( clueId ) & & ! otherActor - > hasClue ( clueId ) ) {
2015-09-19 01:43:38 +02:00
int fromActorId = _id ;
2018-01-14 12:12:06 +01:00
if ( _id = = BladeRunnerEngine : : kActorVoiceOver ) {
2019-09-05 10:37:47 +03:00
fromActorId = _clues - > getFromActorId ( clueId ) ;
2017-04-02 18:17:43 +02:00
}
2019-09-05 10:37:47 +03:00
otherActor - > acquireClue ( clueId , false , fromActorId ) ;
2019-05-13 00:10:27 +03:00
newCluesAcquired = true ;
2015-09-19 01:43:38 +02:00
}
}
2019-05-13 00:10:27 +03:00
return newCluesAcquired ;
2015-09-19 01:43:38 +02:00
}
2018-03-30 00:25:25 +02:00
void Actor : : acquireCluesByRelations ( ) {
if ( _setId > = 0 & & _setId ! = kSetFreeSlotG & & _setId ! = _vm - > _actors [ 0 ] - > _setId ) {
2018-06-29 09:23:12 +02:00
for ( int i = 0 ; i < ( int ) _vm - > _gameInfo - > getActorCount ( ) ; i + + ) {
2018-03-30 00:25:25 +02:00
if ( i ! = _id & & _vm - > _actors [ i ] - > _setId = = _setId & & i & & _id
& & checkFriendlinessAndHonesty ( i )
2018-03-30 10:14:10 +02:00
& & _vm - > _actors [ i ] - > checkFriendlinessAndHonesty ( _id ) ) {
2018-03-30 00:25:25 +02:00
_clues - > acquireCluesByRelations ( _id , i ) ;
}
}
}
}
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 ) ;
2019-03-06 20:32:45 +01:00
return ( 35 * CLIP < int > ( 100 - ( dist / 12 ) , 0 , 100 ) ) / 100 ; // map [0..1200] to [35..0]
2016-09-20 00:33:06 +02:00
}
2019-03-06 20:32:45 +01:00
int Actor : : soundPan ( ) const {
2016-10-02 00:20:56 +02:00
Vector3 screenPosition = _vm - > _view - > calculateScreenPosition ( _position ) ;
2019-03-06 20:32:45 +01:00
return ( 35 * ( 2 * CLIP < int > ( screenPosition . x , 0 , 640 ) - 640 ) ) / 640 ; // map [0..640] to [-35..35]
2016-09-20 00:33:06 +02:00
}
2018-03-17 16:40:33 +01:00
bool Actor : : isObstacleBetween ( const Vector3 & target ) {
return _vm - > _sceneObjects - > isObstacleBetween ( _position , target , - 1 ) ;
2018-02-18 22:18:41 +01:00
}
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 ;
}
2019-02-01 00:01:22 +01:00
bool Actor : : findEmptyPositionAround ( const Vector3 & startPosition , const Vector3 & targetPosition , float size , Vector3 * emptyPosition ) {
emptyPosition - > x = 0.0f ;
emptyPosition - > y = 0.0f ;
emptyPosition - > z = 0.0f ;
int facingLeft = angle_1024 ( targetPosition , startPosition ) ;
int facingRight = facingLeft ;
int facingLeftCounter = 0 ;
int facingRightCounter = 0 ;
2016-10-04 02:21:08 +02:00
while ( true ) {
2019-02-01 00:01:22 +01:00
float rotatedX = targetPosition . x + size * _vm - > _sinTable1024 - > at ( facingLeft ) ;
float rotatedZ = targetPosition . z - size * _vm - > _cosTable1024 - > at ( facingLeft ) ;
2016-10-04 02:21:08 +02:00
2019-02-01 00:01:22 +01:00
if ( ! _walkInfo - > isXYZOccupied ( rotatedX , targetPosition . y , rotatedZ , _id ) ) {
2016-10-04 02:21:08 +02:00
if ( _vm - > _scene - > _set - > findWalkbox ( rotatedX , rotatedZ ) > = 0 ) {
2019-02-01 00:01:22 +01:00
emptyPosition - > x = rotatedX ;
emptyPosition - > y = targetPosition . y ;
emptyPosition - > z = rotatedZ ;
2016-10-04 02:21:08 +02:00
return true ;
}
2019-02-01 00:01:22 +01:00
} else { // looks like a bug as it might not find anything when there is no walkbox at this angle
facingLeft + = 20 ;
2019-07-11 07:25:39 +03:00
# if BLADERUNNER_ORIGINAL_BUGS
2019-02-01 00:01:22 +01:00
if ( facingLeft > 1024 ) {
facingLeft - = 1024 ;
2016-10-04 02:21:08 +02:00
}
2019-07-11 07:25:39 +03:00
# else
// if facingLeft + 20 == 1024 then it could cause the assertion fault
// in common/sinetables.cpp for SineTable::at(int index) -> assert((index >= 0) && (index < _nPoints))
if ( facingLeft > = 1024 ) {
facingLeft - = 1024 ;
}
# endif
2019-02-01 00:01:22 +01:00
facingLeftCounter + = 20 ;
2016-10-04 02:21:08 +02:00
}
2019-02-01 00:01:22 +01:00
rotatedX = size * _vm - > _sinTable1024 - > at ( facingRight ) + targetPosition . x ;
rotatedZ = size * _vm - > _cosTable1024 - > at ( facingRight ) + targetPosition . z ;
2016-10-04 02:21:08 +02:00
2019-02-01 00:01:22 +01:00
if ( ! _walkInfo - > isXYZOccupied ( rotatedX , targetPosition . y , rotatedZ , _id ) ) {
2016-10-04 02:21:08 +02:00
if ( _vm - > _scene - > _set - > findWalkbox ( rotatedX , rotatedZ ) > = 0 ) {
2019-02-01 00:01:22 +01:00
emptyPosition - > x = rotatedX ;
emptyPosition - > y = targetPosition . y ;
emptyPosition - > z = rotatedZ ;
2016-10-04 02:21:08 +02:00
return true ;
}
2019-02-01 00:01:22 +01:00
} else { // looks like a bug as it might not find anything when there is no walkbox at this angle
facingRight - = 20 ;
if ( facingRight < 0 ) {
facingRight + = 1024 ;
2016-10-04 02:21:08 +02:00
}
2019-02-01 00:01:22 +01:00
facingRightCounter + = 20 ;
2016-10-04 02:21:08 +02:00
}
2019-02-01 00:01:22 +01:00
if ( facingLeftCounter > 1024 & & facingRightCounter > 1024 ) {
2016-10-04 02:21:08 +02:00
return false ;
}
}
}
2019-02-01 00:01:22 +01:00
bool Actor : : findNearestPosition ( Vector3 * nearestPosition , float targetWidth , int proximity , float targetSize , const Vector3 & startPosition , const Vector3 & targetPosition ) {
nearestPosition - > x = 0.0f ;
nearestPosition - > y = 0.0f ;
nearestPosition - > z = 0.0f ;
float size = proximity + targetSize * 0.5f + targetWidth * 0.5f ;
2016-10-04 02:21:08 +02:00
float distance = ( startPosition - targetPosition ) . length ( ) - targetWidth * 0.5f - targetSize * 0.5f ;
if ( size < distance ) {
2019-02-01 00:01:22 +01:00
return findEmptyPositionAround ( startPosition , targetPosition , size , nearestPosition ) ;
2016-10-04 02:21:08 +02:00
} else {
2019-02-01 00:01:22 +01:00
* nearestPosition = targetPosition ;
2016-10-04 02:21:08 +02:00
return true ;
}
}
2019-02-01 00:01:22 +01:00
bool Actor : : stepAway ( const Vector3 & destination , float distance ) {
2016-10-04 02:21:08 +02:00
Vector3 out ;
2018-02-18 22:44:28 +01:00
bool running ;
2019-02-01 00:01:22 +01:00
if ( _walkInfo - > findEmptyPositionAround ( _id , destination , distance , out ) ) {
2018-02-18 22:44:28 +01:00
loopWalk ( out , 0 , false , false , _position , 0.0f , 24.0f , false , & running , false ) ;
2016-10-04 02:21:08 +02:00
return true ;
}
return false ;
}
2018-03-24 17:20:27 +01:00
void Actor : : save ( SaveFileWriteStream & f ) {
f . writeInt ( _id ) ;
f . writeInt ( _setId ) ;
f . writeVector3 ( _position ) ;
f . writeInt ( _facing ) ;
f . writeInt ( _targetFacing ) ;
2018-03-30 00:25:25 +02:00
f . writeInt ( _timer4RemainDefault ) ;
2018-03-24 17:20:27 +01:00
f . writeInt ( _honesty ) ;
f . writeInt ( _intelligence ) ;
f . writeInt ( _combatAggressiveness ) ;
2018-11-21 23:16:15 +01:00
f . writeInt ( _stability ) ;
2018-03-24 17:20:27 +01:00
f . writeInt ( _goalNumber ) ;
f . writeInt ( _currentHP ) ;
f . writeInt ( _maxHP ) ;
f . writeBool ( _movementTrackPaused ) ;
f . writeInt ( _movementTrackNextWaypointId ) ;
f . writeInt ( _movementTrackNextDelay ) ;
f . writeInt ( _movementTrackNextAngle ) ;
f . writeBool ( _movementTrackNextRunning ) ;
2018-11-21 23:16:15 +01:00
f . writeInt ( _cluesLimit ) ;
2018-03-24 17:20:27 +01:00
f . writeBool ( _isMoving ) ;
f . writeBool ( _isTarget ) ;
f . writeBool ( _inCombat ) ;
f . writeBool ( _isInvisible ) ;
f . writeBool ( _isRetired ) ;
f . writeBool ( _isImmuneToObstacles ) ;
f . writeInt ( _animationMode ) ;
f . writeInt ( _fps ) ;
f . writeInt ( _frameMs ) ;
f . writeInt ( _animationId ) ;
f . writeInt ( _animationFrame ) ;
f . writeInt ( _movementTrackWalkingToWaypointId ) ;
f . writeInt ( _movementTrackDelayOnNextWaypoint ) ;
f . writeRect ( _screenRectangle ) ;
f . writeInt ( _retiredWidth ) ;
f . writeInt ( _retiredHeight ) ;
f . writeInt ( _damageAnimIfMoving ) ;
2019-03-04 18:57:25 +01:00
f . writeInt ( 0 ) ;
f . writeInt ( 0 ) ;
2018-03-24 17:20:27 +01:00
f . writeFloat ( _scale ) ;
2018-03-17 16:14:48 +01:00
2019-04-09 16:31:39 +03:00
for ( int i = 0 ; i < kActorTimers ; + + i ) {
2018-03-24 17:20:27 +01:00
f . writeInt ( _timersLeft [ i ] ) ;
2018-03-17 16:14:48 +01:00
}
2018-12-15 22:40:07 +01:00
uint32 now = _vm - > _time - > getPauseStart ( ) ;
2019-04-09 16:31:39 +03:00
for ( int i = 0 ; i < kActorTimers ; + + i ) {
2019-05-31 16:42:31 +03:00
// this effectively stores the next timeDiff to be applied to timer i (in timerUpdate)
2019-07-17 19:08:43 +03:00
f . writeInt ( now - _timersLast [ i ] ) ; // Unsigned difference is intentional
2018-03-17 16:14:48 +01:00
}
int actorCount = _vm - > _gameInfo - > getActorCount ( ) ;
for ( int i = 0 ; i ! = actorCount ; + + i ) {
2018-03-24 17:20:27 +01:00
f . writeInt ( _friendlinessToOther [ i ] ) ;
2018-03-17 16:14:48 +01:00
}
_clues - > save ( f ) ;
_movementTrack - > save ( f ) ;
_walkInfo - > save ( f ) ;
2018-11-21 23:16:15 +01:00
f . writeBoundingBox ( _bbox , false ) ;
2018-03-17 16:14:48 +01:00
_combatInfo - > save ( f ) ;
2018-11-21 23:16:15 +01:00
2018-03-24 17:20:27 +01:00
f . writeInt ( _animationModeCombatIdle ) ;
f . writeInt ( _animationModeCombatWalk ) ;
f . writeInt ( _animationModeCombatRun ) ;
}
void Actor : : load ( SaveFileReadStream & f ) {
_id = f . readInt ( ) ;
_setId = f . readInt ( ) ;
_position = f . readVector3 ( ) ;
_facing = f . readInt ( ) ;
_targetFacing = f . readInt ( ) ;
2019-07-22 01:08:23 +03:00
_timer4RemainDefault = f . readUint32LE ( ) ;
2018-03-24 17:20:27 +01:00
_honesty = f . readInt ( ) ;
_intelligence = f . readInt ( ) ;
_combatAggressiveness = f . readInt ( ) ;
2018-11-21 23:16:15 +01:00
_stability = f . readInt ( ) ;
2018-03-24 17:20:27 +01:00
_goalNumber = f . readInt ( ) ;
_currentHP = f . readInt ( ) ;
_maxHP = f . readInt ( ) ;
_movementTrackPaused = f . readBool ( ) ;
_movementTrackNextWaypointId = f . readInt ( ) ;
2019-07-22 01:08:23 +03:00
_movementTrackNextDelay = f . readInt ( ) ;
2018-03-24 17:20:27 +01:00
_movementTrackNextAngle = f . readInt ( ) ;
_movementTrackNextRunning = f . readBool ( ) ;
2018-11-21 23:16:15 +01:00
_cluesLimit = f . readInt ( ) ;
2018-03-24 17:20:27 +01:00
_isMoving = f . readBool ( ) ;
_isTarget = f . readBool ( ) ;
_inCombat = f . readBool ( ) ;
_isInvisible = f . readBool ( ) ;
_isRetired = f . readBool ( ) ;
_isImmuneToObstacles = f . readBool ( ) ;
_animationMode = f . readInt ( ) ;
_fps = f . readInt ( ) ;
_frameMs = f . readInt ( ) ;
_animationId = f . readInt ( ) ;
_animationFrame = f . readInt ( ) ;
_movementTrackWalkingToWaypointId = f . readInt ( ) ;
2019-07-22 01:08:23 +03:00
_movementTrackDelayOnNextWaypoint = f . readInt ( ) ;
2018-03-24 17:20:27 +01:00
_screenRectangle = f . readRect ( ) ;
_retiredWidth = f . readInt ( ) ;
_retiredHeight = f . readInt ( ) ;
_damageAnimIfMoving = f . readInt ( ) ;
2019-03-04 18:57:25 +01:00
f . skip ( 4 ) ;
f . skip ( 4 ) ;
2018-03-24 17:20:27 +01:00
_scale = f . readFloat ( ) ;
2019-04-09 16:31:39 +03:00
for ( int i = 0 ; i < kActorTimers ; + + i ) {
2019-07-22 01:08:23 +03:00
_timersLeft [ i ] = f . readUint32LE ( ) ;
2018-03-24 17:20:27 +01:00
}
2019-04-09 16:31:39 +03:00
// Bugfix: Special initialization case for timer 4 (kActorTimerClueExchange) when its value is restored as 0
2019-02-23 04:18:39 +02:00
// This should be harmless, but will remedy any broken save-games where the timer 4 was saved as 0.
2019-07-17 19:08:43 +03:00
if ( _timersLeft [ kActorTimerClueExchange ] = = 0u ) {
2019-04-09 16:31:39 +03:00
_timersLeft [ kActorTimerClueExchange ] = _timer4RemainDefault ;
2019-02-23 04:18:39 +02:00
}
2018-03-24 17:20:27 +01:00
2018-12-15 22:40:07 +01:00
uint32 now = _vm - > _time - > getPauseStart ( ) ;
2019-04-09 16:31:39 +03:00
for ( int i = 0 ; i < kActorTimers ; + + i ) {
2019-07-22 01:08:23 +03:00
_timersLast [ i ] = now - f . readUint32LE ( ) ; // we require an unsigned difference here, since _timersLast is essentially keeping time
2018-03-24 17:20:27 +01:00
}
int actorCount = _vm - > _gameInfo - > getActorCount ( ) ;
for ( int i = 0 ; i ! = actorCount ; + + i ) {
_friendlinessToOther [ i ] = f . readInt ( ) ;
}
_clues - > load ( f ) ;
_movementTrack - > load ( f ) ;
_walkInfo - > load ( f ) ;
2018-11-21 23:16:15 +01:00
_bbox = f . readBoundingBox ( false ) ;
2018-03-24 17:20:27 +01:00
_combatInfo - > load ( f ) ;
_animationModeCombatIdle = f . readInt ( ) ;
_animationModeCombatWalk = f . readInt ( ) ;
_animationModeCombatRun = f . readInt ( ) ;
2018-03-17 16:14:48 +01:00
}
2015-05-02 22:31:07 +02:00
} // End of namespace BladeRunner