0
0
Fork 0
mirror of https://github.com/id-Software/DOOM-3-BFG.git synced 2025-03-15 23:21:35 +00:00
doom3-bfg/base/script/ai_alphalabs2_scientist1.script
2022-08-27 13:19:00 +02:00

1387 lines
30 KiB
Text

/***********************************************************************
ai_alphalabs2_scientist1.script
***********************************************************************/
#define ED_WAIT_GETCLOSER 4
#define ED_LEAD_TIMEOUT 1
#define ED_MIN_LOOK_DELAY 4
#define ED_MAX_LOOK_DELAY 8
#define ED_LOOK_TIME 1.5
#define ED_LEAD_DIST 128
#define ED_LOST_DIST 256
#define ED_NUM_EVENTS 7
#define ED_POINT_OF_NO_RETURN (ED_NUM_EVENTS - 1)
#define ED_COWER_ANGLE_LEFT 85
#define ED_COWER_ANGLE_RIGHT -85
#define ED_COWER_BLEND 9
#define ED_BLEND_TURN_TO_IDLE 0
#define ED_TURN_THRESHOLD 25
object ai_alphalabs2_scientist1 : ai {
boolean attack_count;
boolean hurry_count;
boolean cower;
float talk_count;
float event;
float lastHurryTime;
entity light;
entity playerEnemy;
entity lookTarget;
float playerMoveState;
vector lastValidPlayerPosition;
float playerPositionThread;
//
// States
//
void state_WorkingOnStuff();
void state_DeathScene();
void state_Killed();
void state_NoticePlayer();
void state_Wait();
void state_Spooked();
void state_Lead();
void state_FindPlayer();
void state_Cower();
void init();
void destroy();
void faceTowardsEntity( entity target, float duration );
void light_fade_out( float fadeTime );
void light_fade_in( float fadeTime );
void light_fade( float stay_off );
void light_fade1();
void light_fade2();
void doEvent();
void sayStuff();
void hurry_up();
float checkDestinationDistance();
void updatePlayerPositionThread();
void checkBlocked();
// head anim states
void Head_Idle();
void Head_Death();
void Head_DeathScene();
void Head_Greeting();
void Head_Speech();
void Head_Hurry();
void Head_StayClose();
void Head_Electro_Pulses();
void Head_Pulse1();
void Head_Pulse2();
void Head_WatchIt();
void Head_Spooked();
void Head_Exit();
void Head_SayStuff();
void Head_Attacked();
void Head_AttackDone();
// torso anim states
void Torso_DeathScene();
void Torso_Death();
void Torso_Idle();
void Torso_Pain();
void Torso_Work();
// legs anim states
void Legs_Death();
void Legs_Idle();
void Legs_Walk();
void Legs_TurnLeft();
void Legs_TurnRight();
void Legs_Cower();
};
/***********************************************************************
Torso animation control
***********************************************************************/
void ai_alphalabs2_scientist1::Head_Idle() {
idleAnim( ANIMCHANNEL_HEAD, "stand" );
}
void ai_alphalabs2_scientist1::Head_Death() {
playAnim( ANIMCHANNEL_HEAD, "dead" );
while( AI_DEAD ) {
waitFrame();
}
}
void ai_alphalabs2_scientist1::Head_DeathScene() {
stopAnim( ANIMCHANNEL_HEAD, 0 );
while( AI_DEAD ) {
waitFrame();
}
}
void ai_alphalabs2_scientist1::Head_Greeting() {
playAnim( ANIMCHANNEL_HEAD, "lips_dontshoot" );
while( !( animDone( ANIMCHANNEL_HEAD, 0 ) ) ) {
lookAt( $player1, 1 );
waitFrame();
}
lookAt( $player1, 0 );
animState( ANIMCHANNEL_HEAD, "Head_Idle", 4 );
}
void ai_alphalabs2_scientist1::Head_Speech() {
playAnim( ANIMCHANNEL_HEAD, "lips_canhelp" );
while( !( animDone( ANIMCHANNEL_HEAD, 0 ) ) ) {
lookAt( $player1, 1 );
waitFrame();
}
playAnim( ANIMCHANNEL_HEAD, "lips_lightsout" );
while( !( animDone( ANIMCHANNEL_HEAD, 0 ) ) ) {
lookAt( $player1, 1 );
waitFrame();
}
lookAt( $player1, 0 );
animState( ANIMCHANNEL_HEAD, "Head_Idle", 4 );
}
void ai_alphalabs2_scientist1::Head_Hurry() {
if ( hurry_count ) {
playAnim( ANIMCHANNEL_HEAD, "lips_hurry1" );
} else {
playAnim( ANIMCHANNEL_HEAD, "lips_hurry2" );
}
hurry_count = !hurry_count;
while( !( animDone( ANIMCHANNEL_HEAD, 0 ) ) ) {
lookAt( $player1, 1 );
waitFrame();
}
lookAt( $player1, 0 );
animState( ANIMCHANNEL_HEAD, "Head_Idle", 4 );
}
void ai_alphalabs2_scientist1::Head_StayClose() {
playAnim( ANIMCHANNEL_HEAD, "lips_stayclose" );
while( !( animDone( ANIMCHANNEL_HEAD, 0 ) ) ) {
lookAt( $player1, 1 );
waitFrame();
}
lookAt( $player1, 0 );
animState( ANIMCHANNEL_HEAD, "Head_Idle", 4 );
}
void ai_alphalabs2_scientist1::Head_Electro_Pulses() {
playAnim( ANIMCHANNEL_HEAD, "lips_electro" );
while( !( animDone( ANIMCHANNEL_HEAD, 0 ) ) ) {
lookAt( $player1, 1 );
waitFrame();
}
lookAt( $player1, 0 );
animState( ANIMCHANNEL_HEAD, "Head_Idle", 4 );
}
void ai_alphalabs2_scientist1::Head_Pulse1() {
playAnim( ANIMCHANNEL_HEAD, "lips_theresone" );
while( !( animDone( ANIMCHANNEL_HEAD, 0 ) ) ) {
lookAt( $player1, 1 );
waitFrame();
}
lookAt( $player1, 0 );
animState( ANIMCHANNEL_HEAD, "Head_Idle", 4 );
}
void ai_alphalabs2_scientist1::Head_Pulse2() {
playAnim( ANIMCHANNEL_HEAD, "lips_hangon" );
while( !( animDone( ANIMCHANNEL_HEAD, 0 ) ) ) {
lookAt( $player1, 1 );
waitFrame();
}
lookAt( $player1, 0 );
animState( ANIMCHANNEL_HEAD, "Head_Idle", 4 );
}
void ai_alphalabs2_scientist1::Head_WatchIt() {
playAnim( ANIMCHANNEL_HEAD, "lips_watchit" );
while( !( animDone( ANIMCHANNEL_HEAD, 0 ) ) ) {
lookAt( $player1, 1 );
waitFrame();
}
lookAt( $player1, 0 );
animState( ANIMCHANNEL_HEAD, "Head_Idle", 4 );
}
void ai_alphalabs2_scientist1::Head_Spooked() {
playAnim( ANIMCHANNEL_HEAD, "lips_whatwasthat" );
while( !( animDone( ANIMCHANNEL_HEAD, 0 ) ) ) {
waitFrame();
}
animState( ANIMCHANNEL_HEAD, "Head_Idle", 4 );
}
void ai_alphalabs2_scientist1::Head_Exit() {
playAnim( ANIMCHANNEL_HEAD, "lips_theexit" );
while( !( animDone( ANIMCHANNEL_HEAD, 0 ) ) ) {
lookAt( $player1, 1 );
waitFrame();
}
lookAt( $player1, 00 );
animState( ANIMCHANNEL_HEAD, "Head_Idle", 4 );
}
void ai_alphalabs2_scientist1::Head_SayStuff() {
if ( !talk_count ) {
talk_count = 1;
playAnim( ANIMCHANNEL_HEAD, "lips_wecantstop" );
} else if ( talk_count == 1 ) {
talk_count = 2;
playAnim( ANIMCHANNEL_HEAD, "lips_canttalknow" );
} else if ( talk_count == 2 ) {
talk_count = 1;
playAnim( ANIMCHANNEL_HEAD, "lips_itisntfar" );
}
while( !( animDone( ANIMCHANNEL_HEAD, 0 ) ) ) {
lookAt( $player1, 1 );
waitFrame();
}
lookAt( $player1, 0 );
animState( ANIMCHANNEL_HEAD, "Head_Idle", 4 );
}
void ai_alphalabs2_scientist1::Head_Attacked() {
if ( attack_count ) {
playAnim( ANIMCHANNEL_HEAD, "lips_ohgod" );
} else {
playAnim( ANIMCHANNEL_HEAD, "lips_killit" );
}
while( !( animDone( ANIMCHANNEL_HEAD, 0 ) ) ) {
lookAt( $player1, 1 );
waitFrame();
}
lookAt( $player1, 0 );
animState( ANIMCHANNEL_HEAD, "Head_Idle", 4 );
}
void ai_alphalabs2_scientist1::Head_AttackDone() {
if ( attack_count ) {
playAnim( ANIMCHANNEL_HEAD, "lips_ohthankgod" );
} else {
playAnim( ANIMCHANNEL_HEAD, "lips_thatwasclose" );
}
attack_count = !attack_count;
while( !( animDone( ANIMCHANNEL_HEAD, 0 ) ) ) {
lookAt( $player1, 1 );
waitFrame();
}
lookAt( $player1, 0 );
animState( ANIMCHANNEL_HEAD, "Head_Idle", 4 );
}
/***********************************************************************
Torso animation control
***********************************************************************/
void ai_alphalabs2_scientist1::Torso_Work() {
playAnim( ANIMCHANNEL_TORSO, "working" );
while( !( animDone( ANIMCHANNEL_TORSO, 12 ) ) ) {
waitFrame();
}
finishAction( "work" );
animState( ANIMCHANNEL_TORSO, "Torso_Idle", 12 );
}
void ai_alphalabs2_scientist1::Torso_DeathScene() {
string animname;
overrideAnim( ANIMCHANNEL_LEGS );
playAnim( ANIMCHANNEL_TORSO, "killme" );
while( !animDone( ANIMCHANNEL_TORSO, 0 ) ) {
waitFrame();
}
becomeRagdoll();
finishAction( "dead" );
// never exit
waitUntil( 0 );
}
void ai_alphalabs2_scientist1::Torso_Death() {
finishAction( "dead" );
// never exit
waitUntil( 0 );
}
void ai_alphalabs2_scientist1::Torso_Idle() {
idleAnim( ANIMCHANNEL_TORSO, "stand" );
while( !AI_PAIN ) {
waitFrame();
}
animState( ANIMCHANNEL_TORSO, "Torso_Pain", 0 );
}
void ai_alphalabs2_scientist1::Torso_Pain() {
string animname;
float nextpain;
float currenttime;
animname = getPainAnim();
playAnim( ANIMCHANNEL_TORSO, animname );
nextpain = sys.getTime() + 0.25;
while( !animDone( ANIMCHANNEL_TORSO, 4 ) ) {
if ( AI_PAIN ) {
currenttime = sys.getTime();
if ( currenttime > nextpain ) {
animState( ANIMCHANNEL_TORSO, "Torso_Pain", 0 );
}
}
waitFrame();
}
finishAction( "pain" );
animState( ANIMCHANNEL_TORSO, "Torso_Idle", 4 );
}
/***********************************************************************
Legs animation control
***********************************************************************/
void ai_alphalabs2_scientist1::Legs_Death() {
while( AI_DEAD ) {
waitFrame();
}
animState( ANIMCHANNEL_LEGS, "Legs_Idle", 4 );
}
void ai_alphalabs2_scientist1::Legs_Idle() {
float delta;
delta = getTurnDelta();
if ( !AI_FORWARD && !facingIdeal() ) {
if ( delta > 10 ) {
animState( ANIMCHANNEL_LEGS, "Legs_TurnLeft", 4 );
}
if ( delta < -10 ) {
animState( ANIMCHANNEL_LEGS, "Legs_TurnRight", 4 );
}
}
if ( AI_FORWARD ) {
animState( ANIMCHANNEL_LEGS, "Legs_Walk", 12 );
}
idleAnim( ANIMCHANNEL_LEGS, "stand" );
eachFrame {
if ( AI_FORWARD ) {
animState( ANIMCHANNEL_LEGS, "Legs_Walk", 12 );
}
if ( cower ) {
animState( ANIMCHANNEL_LEGS, "Legs_Cower", 12 );
}
if ( !facingIdeal() ) {
delta = getTurnDelta();
if ( delta > 10 ) {
animState( ANIMCHANNEL_LEGS, "Legs_TurnLeft", 4 );
}
if ( delta < -10 ) {
animState( ANIMCHANNEL_LEGS, "Legs_TurnRight", 4 );
}
}
}
}
void ai_alphalabs2_scientist1::Legs_Walk() {
float delta;
playCycle( ANIMCHANNEL_LEGS, "walk" );
while( AI_FORWARD ) {
waitFrame();
}
animState( ANIMCHANNEL_LEGS, "Legs_Idle", 12 );
}
void ai_alphalabs2_scientist1::Legs_TurnLeft() {
float delta;
allowMovement( true );
animTurn( 180 );
playAnim( ANIMCHANNEL_LEGS, "turn_left" );
while( !animDone( ANIMCHANNEL_LEGS, ED_BLEND_TURN_TO_IDLE ) ) {
if ( AI_FORWARD ) {
break;
}
waitFrame();
}
animTurn( 0 );
if ( AI_FORWARD ) {
animState( ANIMCHANNEL_LEGS, "Legs_Walk", 12 );
}
if ( !facingIdeal() ) {
delta = getTurnDelta();
if ( delta > 10 ) {
animState( ANIMCHANNEL_LEGS, "Legs_TurnLeft", ED_BLEND_TURN_TO_IDLE );
}
if ( delta < -10 ) {
animState( ANIMCHANNEL_LEGS, "Legs_TurnRight", ED_BLEND_TURN_TO_IDLE );
}
}
animState( ANIMCHANNEL_LEGS, "Legs_Idle", ED_BLEND_TURN_TO_IDLE );
}
void ai_alphalabs2_scientist1::Legs_TurnRight() {
float delta;
allowMovement( true );
animTurn( 180 );
playAnim( ANIMCHANNEL_LEGS, "turn_right" );
while( !animDone( ANIMCHANNEL_LEGS, ED_BLEND_TURN_TO_IDLE ) ) {
if ( AI_FORWARD ) {
break;
}
waitFrame();
}
animTurn( 0 );
if ( AI_FORWARD ) {
animState( ANIMCHANNEL_LEGS, "Legs_Walk", 12 );
}
if ( !facingIdeal() ) {
delta = getTurnDelta();
if ( delta > 10 ) {
animState( ANIMCHANNEL_LEGS, "Legs_TurnLeft", ED_BLEND_TURN_TO_IDLE );
}
if ( delta < -10 ) {
animState( ANIMCHANNEL_LEGS, "Legs_TurnRight", ED_BLEND_TURN_TO_IDLE );
}
}
animState( ANIMCHANNEL_LEGS, "Legs_Idle", ED_BLEND_TURN_TO_IDLE );
}
void ai_alphalabs2_scientist1::Legs_Cower() {
vector delta;
vector ang1;
vector ang2;
vector ang3;
float yaw;
float frac;
yaw = 0;
overrideAnim( ANIMCHANNEL_TORSO );
playCycle( ANIMCHANNEL_LEGS, "cower" );
while( cower ) {
disableEyeFocus(); // gets reenabled by the head anim ending, so just set it every frame
if ( playerEnemy ) {
delta = playerEnemy.getOrigin();
delta = delta - getOrigin();
ang1 = sys.VecToAngles( delta );
ang2 = getAngles();
ang3 = anglemod180( ang1 - ang2 );
if ( ang3_y > ED_COWER_ANGLE_LEFT ) {
ang3_y = ED_COWER_ANGLE_LEFT;
} else if ( ang3_y < ED_COWER_ANGLE_RIGHT ) {
ang3_y = ED_COWER_ANGLE_RIGHT;
}
yaw = yaw * 0.9 + ang3_y * 0.1;
if ( yaw < 0 ) {
frac = yaw / ED_COWER_ANGLE_RIGHT;
setSyncedAnimWeight( ANIMCHANNEL_LEGS, 0, 1 - frac ); // center
setSyncedAnimWeight( ANIMCHANNEL_LEGS, 1, 0 ); // left
setSyncedAnimWeight( ANIMCHANNEL_LEGS, 2, frac ); // right
} else {
frac = yaw / ED_COWER_ANGLE_LEFT;
setSyncedAnimWeight( ANIMCHANNEL_LEGS, 0, 1 - frac ); // center
setSyncedAnimWeight( ANIMCHANNEL_LEGS, 1, frac ); // left
setSyncedAnimWeight( ANIMCHANNEL_LEGS, 2, 0 ); // right
}
}
waitFrame();
}
enableEyeFocus();
animState( ANIMCHANNEL_LEGS, "Legs_Idle", 12 );
}
/***********************************************************************
AI
***********************************************************************/
/*
=====================
ai_alphalabs2_scientist1::init
=====================
*/
void ai_alphalabs2_scientist1::init() {
setBoneMod( true );
talk_count = 0;
lastHurryTime = 0;
cower = false;
attack_count = 0;
hurry_count = 0;
event = 0;
lookTarget = sys.spawn( "target_null" );
lookTarget.bind( self );
lookTarget.setOrigin( '120 0 72' );
light = sys.spawn( "light" );
light.setShader( "lights/lanternglow" );
light.setRadius( 192 );
light.setAngles( '0 -90 0' );
light.bindToJoint( self, "lanternlight", true );
light.setOrigin( '-5 0 0' );
animState( ANIMCHANNEL_HEAD, "Head_Idle", 0 );
animState( ANIMCHANNEL_TORSO, "Torso_Idle", 0 );
animState( ANIMCHANNEL_LEGS, "Legs_Idle", 0 );
setState( "state_WorkingOnStuff" );
}
/*
=====================
ai_alphalabs2_scientist1::destroy
=====================
*/
void ai_alphalabs2_scientist1::destroy() {
lookTarget.remove();
light.remove();
if ( playerPositionThread ) {
sys.terminate( playerPositionThread );
playerPositionThread = 0;
}
}
/*
=====================
ai_alphalabs2_scientist1::faceTowardsEntity
=====================
*/
void ai_alphalabs2_scientist1::faceTowardsEntity( entity target, float duration ) {
vector delta;
vector ang1;
vector ang2;
vector ang3;
delta = target.getOrigin();
delta = delta - getOrigin();
ang1 = sys.VecToAngles( delta );
ang2 = getAngles();
ang3 = anglemod180( ang1 - ang2 );
if ( ang3_y < -ED_TURN_THRESHOLD ) {
turnTo( ang1_y );
} else if ( ang3_y > ED_TURN_THRESHOLD ) {
turnTo( ang1_y );
}
lookAt( target, duration );
}
/*
=====================
ai_alphalabs2_scientist1::light_fade_out
=====================
*/
void ai_alphalabs2_scientist1::light_fade_out( float fadeTime ) {
float i;
vector c;
float frac;
float numTics;
setSkin( "skins/characters/npcs/labcoat_old_lantern_off.skin" );
// convert to the total number of game tics
numTics = fadeTime * GAME_FPS;
for( i = 0; i < numTics; i++ ) {
frac = 1 - ( i / numTics );
light.setColor( frac, frac, frac );
global_flashlight_intensity = frac;
// wait one game frame
sys.waitFrame();
}
// make sure we are set to exactly the final value
light.setColor( 0, 0, 0 );
global_flashlight_intensity = 0;
}
/*
=====================
ai_alphalabs2_scientist1::light_fade_in
=====================
*/
void ai_alphalabs2_scientist1::light_fade_in( float fadeTime ) {
float i;
vector c;
float frac;
float numTics;
setSkin( "skins/characters/npcs/body_labcoat_lantern" );
// convert to the total number of game tics
numTics = fadeTime * GAME_FPS;
for( i = 0; i < numTics; i++ ) {
frac = i / numTics;
light.setColor( frac, frac, frac );
global_flashlight_intensity = frac;
// wait one game frame
sys.waitFrame();
}
// make sure we are set to exactly the final value
light.setColor( 1, 1, 1 );
global_flashlight_intensity = 1;
}
/*
=====================
ai_alphalabs2_scientist1::light_fade
=====================
*/
void ai_alphalabs2_scientist1::light_fade( float stay_off ) {
light_fade_out( 0.1 );
light_fade_in( 0.05 );
light_fade_out( 0.1 );
light_fade_in( 0.2 );
light_fade_out( 0.05 );
if ( !stay_off ) {
sys.wait( 2 );
thread light_fade_in( 3 );
lookTarget.setOrigin( '80 -40 72' );
lookAt( lookTarget, 1.2 );
sys.wait( 1.2 );
lookTarget.setOrigin( '80 40 72' );
lookAt( lookTarget, 1.5 );
sys.wait( 1.5 );
}
}
/*
=====================
ai_alphalabs2_scientist1::light_fade1
=====================
*/
void ai_alphalabs2_scientist1::light_fade1() {
float currentTime;
float threadNum;
sys.wait( 0.2 );
threadNum = thread light_fade( false );
sys.wait( 1 );
stopMove();
currentTime = sys.getTime();
animState( ANIMCHANNEL_HEAD, "Head_Pulse1", 4 );
sys.waitForThread( threadNum );
setState( "state_Lead" );
}
/*
=====================
ai_alphalabs2_scientist1::light_fade2
=====================
*/
void ai_alphalabs2_scientist1::light_fade2() {
float currentTime;
float threadNum;
threadNum = thread light_fade( false );
sys.wait( 0.5 );
stopMove();
currentTime = sys.getTime();
animState( ANIMCHANNEL_HEAD, "Head_Pulse2", 4 );
sys.waitForThread( threadNum );
setState( "state_Lead" );
}
/*
=====================
ai_alphalabs2_scientist1::doEvent
=====================
*/
void ai_alphalabs2_scientist1::doEvent() {
float currentTime;
AI_ACTIVATED = false;
currentTime = sys.getTime();
event = event + 1;
if ( event == 1 ) {
animState( ANIMCHANNEL_HEAD, "Head_Electro_Pulses", 4 );
setState( "state_Lead" );
} else if ( event == 2 ) {
light_fade1();
} else if ( event == 3 ) {
setState( "state_Spooked" );
} else if ( event == 4) {
light_fade2();
} else if ( event == 5 ) {
animState( ANIMCHANNEL_HEAD, "Head_Exit", 4 );
setState( "state_Lead" );
} else if ( event == ( ED_NUM_EVENTS - 1) ) {
// point of no return
;
} else if ( event >= ED_NUM_EVENTS ) {
setState( "state_DeathScene" );
}
}
/*
=====================
ai_alphalabs2_scientist1::sayStuff
=====================
*/
void ai_alphalabs2_scientist1::sayStuff() {
setTalkTarget( $null_entity );
if ( !inAnimState( ANIMCHANNEL_HEAD, "Head_Idle" ) ) {
return;
}
animState( ANIMCHANNEL_HEAD, "Head_SayStuff", 4 );
}
/*
=====================
ai_alphalabs2_scientist1::hurry_up
=====================
*/
void ai_alphalabs2_scientist1::hurry_up() {
float currentTime;
currentTime = sys.getTime();
if ( ( currentTime > lastHurryTime ) && inAnimState( ANIMCHANNEL_HEAD, "Head_Idle" ) ) {
animState( ANIMCHANNEL_HEAD, "Head_Hurry", 4 );
lastHurryTime = currentTime + 6;
}
}
/*
=====================
ai_alphalabs2_scientist1::checkDestinationDistance()
=====================
*/
float ai_alphalabs2_scientist1::checkDestinationDistance() {
float playerDist;
float currentDist;
float leadDistance;
float relativeMoveDir;
vector delta;
// determine if the player is moving toward us
delta = getOrigin() - $player1.getOrigin();
relativeMoveDir = delta * $player1.getLinearVelocity();
if ( relativeMoveDir > 1 ) {
// Player is approaching
playerMoveState = APPROACHING;
} else if ( relativeMoveDir < -1 ) {
// Player is moving away from us
playerMoveState = RETREATING;
} else {
// Player is standing still
playerMoveState = NOT_MOVING;
}
playerDist = distanceToPoint( lastValidPlayerPosition );
if ( playerDist < ED_LEAD_DIST ) {
return PLAYER_OK;
}
if ( !canSee( $player1 ) ) {
currentDist = travelDistanceToEntity( $scientist_destination );
leadDistance = travelDistanceBetweenPoints( lastValidPlayerPosition, $scientist_destination.getOrigin() );
if ( currentDist > leadDistance ) {
return PLAYER_AHEAD_OF_ME;
} else {
return PLAYER_LOST;
}
}
if ( playerDist > ED_LOST_DIST ) {
currentDist = travelDistanceToEntity( $scientist_destination );
leadDistance = travelDistanceBetweenPoints( lastValidPlayerPosition, $scientist_destination.getOrigin() );
if ( currentDist > leadDistance ) {
return PLAYER_AHEAD_OF_ME;
} else {
return PLAYER_BEHIND_ME;
}
}
return PLAYER_OK;
}
/*
=====================
ai_alphalabs2_scientist1::updatePlayerPositionThread()
=====================
*/
void ai_alphalabs2_scientist1::updatePlayerPositionThread() {
vector pos;
while( 1 ) {
if ( canReachEntity( $player1 ) ) {
lastValidPlayerPosition = getReachableEntityPosition( $player1 );
}
//sys.debugBounds( '1 0 0', lastValidPlayerPosition + $player1.getMins(), lastValidPlayerPosition + $player1.getMaxs(), 0 );
waitFrame();
}
}
/*
=====================
ai_alphalabs2_scientist1::checkBlocked
=====================
*/
void ai_alphalabs2_scientist1::checkBlocked() {
entity obstacle;
vector player_pos;
vector delta;
if ( moveStatus() >= MOVE_STATUS_BLOCKED_BY_OBJECT ) {
obstacle = getObstacle();
if ( obstacle != $player1 ) {
kickObstacles( obstacle, 60 );
return;
}
hurry_up();
player_pos = $player1.getOrigin();
saveMove();
stopMove();
while( 1 ) {
delta = player_pos - $player1.getOrigin();
delta_z = 0;
if ( sys.vecLength( delta ) > 4 ) {
restoreMove();
if ( moveStatus() < MOVE_STATUS_BLOCKED_BY_OBJECT ) {
break;
}
if ( getObstacle() != $player1 ) {
break;
}
stopMove();
}
if ( $player1.hasEnemies() ) {
setState( "state_Cower" );
}
faceTowardsEntity( $player1, 1 );
if ( AI_TALK ) {
sayStuff();
}
waitFrame();
}
}
}
/***********************************************************************
States
***********************************************************************/
/*
=====================
ai_alphalabs2_scientist1::state_Killed
=====================
*/
void ai_alphalabs2_scientist1::state_Killed() {
light.Off();
setSkin( "skins/characters/npcs/body_labcoat_no_lantern.skin" );
stopMove();
sys.terminate( playerPositionThread );
playerPositionThread = 0;
animState( ANIMCHANNEL_HEAD, "Head_Death", 0 );
animState( ANIMCHANNEL_TORSO, "Torso_Death", 0 );
animState( ANIMCHANNEL_LEGS, "Legs_Death", 0 );
waitAction( "dead" );
stopThinking();
}
/*
=====================
ai_alphalabs2_scientist1::state_DeathScene
=====================
*/
void ai_alphalabs2_scientist1::state_DeathScene() {
// keep walking
AI_FORWARD = true;
setNeverDormant( false );
sys.terminate( playerPositionThread );
playerPositionThread = 0;
thread light_fade( true );
sys.wait( 0.5 );
setTalkState( TALK_DEAD );
stopMove();
sys.trigger( $edkiller );
thread light_fade_in( 2.0 ); // turn flashlight back on after ed's death
animState( ANIMCHANNEL_HEAD, "Head_DeathScene", 0 );
animState( ANIMCHANNEL_TORSO, "Torso_DeathScene", 0 );
animState( ANIMCHANNEL_LEGS, "Legs_Death", 0 );
waitAction( "dead" );
stopThinking();
}
/*
=====================
ai_alphalabs2_scientist1::state_WorkingOnStuff
=====================
*/
void ai_alphalabs2_scientist1::state_WorkingOnStuff() {
vector ang1;
vector ang2;
ang1 = $interesting_object1.getAngles();
ang2 = $interesting_object2.getAngles();
AI_ACTIVATED = false;
while( 1 ) {
moveToEntity( $interesting_object1 );
while( !AI_MOVE_DONE ) {
if ( AI_ACTIVATED ) {
setState( "state_NoticePlayer" );
}
waitFrame();
}
turnTo( ang1_y );
while( !facingIdeal() ) {
if ( AI_ACTIVATED ) {
setState( "state_NoticePlayer" );
}
waitFrame();
}
while( !inAnimState( ANIMCHANNEL_LEGS, "Legs_Idle" ) ) {
if ( AI_ACTIVATED ) {
setState( "state_NoticePlayer" );
}
waitFrame();
}
animState( ANIMCHANNEL_TORSO, "Torso_Work", 8 );
while( inAnimState( ANIMCHANNEL_TORSO, "Torso_Work" ) ) {
if ( AI_ACTIVATED ) {
setState( "state_NoticePlayer" );
}
waitFrame();
}
moveToEntity( $interesting_object2 );
while( !AI_MOVE_DONE ) {
if ( AI_ACTIVATED ) {
setState( "state_NoticePlayer" );
}
waitFrame();
}
turnTo( ang2_y );
while( !facingIdeal() ) {
if ( AI_ACTIVATED ) {
setState( "state_NoticePlayer" );
}
waitFrame();
}
while( !inAnimState( ANIMCHANNEL_LEGS, "Legs_Idle" ) ) {
if ( AI_ACTIVATED ) {
setState( "state_NoticePlayer" );
}
waitFrame();
}
animState( ANIMCHANNEL_TORSO, "Torso_Work", 8 );
while( inAnimState( ANIMCHANNEL_TORSO, "Torso_Work" ) ) {
if ( AI_ACTIVATED ) {
setState( "state_NoticePlayer" );
}
waitFrame();
}
}
}
/*
=====================
ai_alphalabs2_scientist1::state_NoticePlayer
=====================
*/
void ai_alphalabs2_scientist1::state_NoticePlayer() {
animState( ANIMCHANNEL_TORSO, "Torso_Idle", 12 );
setNeverDormant( true );
AI_ACTIVATED = false;
lookAt( $player1, 10 );
animState( ANIMCHANNEL_HEAD, "Head_Greeting", 4 );
moveToEntity( $greet_player );
while( !AI_MOVE_DONE ) {
if ( distanceTo( $player1 ) < 64 ) {
AI_ACTIVATED = true;
turnToEntity( $player1 );
break;
}
lookAt( $player1, 1 );
waitFrame();
}
stopMove();
while( !AI_ACTIVATED ) {
faceTowardsEntity( $player1, 1 );
waitFrame();
}
AI_ACTIVATED = false;
animState( ANIMCHANNEL_HEAD, "Head_Speech", 4 );
while( !inAnimState( ANIMCHANNEL_HEAD, "Head_Idle" ) ) {
faceTowardsEntity( $player1, 1 );
waitFrame();
}
setTalkTarget( $null_entity );
playerPositionThread = thread updatePlayerPositionThread();
setState( "state_Lead" );
}
/*
=====================
ai_alphalabs2_scientist1::state_Wait
=====================
*/
void ai_alphalabs2_scientist1::state_Wait() {
float getCloserTime;
float currentTime;
float result = checkDestinationDistance();
if ( result == PLAYER_LOST ) {
setState( "state_FindPlayer" );
} else if ( result == PLAYER_AHEAD_OF_ME ) {
setState( "state_Lead" );
} else if ( ( result == PLAYER_OK ) && ( playerMoveState == APPROACHING ) ) {
setState( "state_Lead" );
}
stopMove();
hurry_up();
getCloserTime = currentTime + ED_WAIT_GETCLOSER;
while( 1 ) {
faceTowardsEntity( $player1, 1 );
if ( AI_TALK ) {
sayStuff();
}
result = checkDestinationDistance();
if ( result == PLAYER_LOST ) {
setState( "state_FindPlayer" );
} else if ( result == PLAYER_AHEAD_OF_ME ) {
setState( "state_Lead" );
} else if ( ( result == PLAYER_OK ) && ( playerMoveState == APPROACHING ) ) {
setState( "state_Lead" );
} else if ( ( sys.getTime() > getCloserTime ) && ( result == PLAYER_BEHIND_ME ) ) {
setState( "state_GetCloser" );
}
if ( $player1.hasEnemies() ) {
setState( "state_Cower" );
}
if ( AI_ACTIVATED ) {
if ( inAnimState( ANIMCHANNEL_HEAD, "Head_Idle" ) ) {
doEvent();
}
}
waitFrame();
}
}
/*
=====================
ai_alphalabs2_scientist1::state_GetCloser
=====================
*/
void ai_alphalabs2_scientist1::state_GetCloser() {
while( 1 ) {
moveToPosition( lastValidPlayerPosition );
if ( AI_MOVE_DONE ) {
if ( !canReachEntity( $player1 ) ) {
setState( "state_CantReachPlayer" );
}
}
if ( $player1.hasEnemies() ) {
setState( "state_Cower" );
}
checkBlocked();
float result = checkDestinationDistance();
if ( result == PLAYER_LOST ) {
setState( "state_FindPlayer" );
}
if ( result == PLAYER_OK ) {
setState( "state_Wait" );
}
waitFrame();
}
}
/*
=====================
ai_alphalabs2_scientist1::state_CantReachPlayer
=====================
*/
void ai_alphalabs2_scientist1::state_CantReachPlayer() {
startSound( "snd_cant_reach_player", SND_CHANNEL_VOICE, false );
stopMove();
while( 1 ) {
if ( canReachEntity( $player1 ) ) {
setState( "state_Wait" );
}
if ( $player1.hasEnemies() ) {
setState( "state_Cower" );
}
waitFrame();
}
}
/*
=====================
ai_alphalabs2_scientist1::state_Spooked
=====================
*/
void ai_alphalabs2_scientist1::state_Spooked() {
vector ang;
float endTime;
animState( ANIMCHANNEL_HEAD, "Head_Spooked", 4 );
lookAt( $player1, 1.2 );
stopMove();
sys.wait( 1.2 );
if ( $player1.hasEnemies() ) {
setState( "state_Cower" );
}
lookTarget.setOrigin( '80 -120 72' );
lookAt( lookTarget, 1.7 );
endTime = sys.getTime() + 1.7;
while( endTime > sys.getTime() ) {
if ( $player1.hasEnemies() ) {
setState( "state_Cower" );
}
waitFrame();
}
lookTarget.setOrigin( '80 120 72' );
lookAt( lookTarget, 1.7 );
endTime = sys.getTime() + 1.7;
while( endTime > sys.getTime() ) {
if ( $player1.hasEnemies() ) {
setState( "state_Cower" );
}
waitFrame();
}
if ( $player1.hasEnemies() ) {
setState( "state_Cower" );
}
animState( ANIMCHANNEL_HEAD, "Head_StayClose", 4 );
while( !inAnimState( ANIMCHANNEL_HEAD, "Head_Idle" ) ) {
waitFrame();
}
setState( "state_Lead" );
}
/*
=====================
ai_alphalabs2_scientist1::state_Lead
=====================
*/
void ai_alphalabs2_scientist1::state_Lead() {
float nextLookTime;
float leadTimeOut;
nextLookTime = RandomDelay( ED_MIN_LOOK_DELAY, ED_MAX_LOOK_DELAY );
moveToEntity( $scientist_destination );
leadTimeOut = sys.getTime() + ED_LEAD_TIMEOUT;
while( 1 ) {
if ( AI_TALK ) {
sayStuff();
}
if ( $player1.hasEnemies() ) {
setState( "state_Cower" );
}
if ( sys.getTime() > nextLookTime ) {
lookAt( $player1, ED_LOOK_TIME );
nextLookTime = RandomDelay( ED_MIN_LOOK_DELAY, ED_MAX_LOOK_DELAY );
}
checkBlocked();
float result = checkDestinationDistance();
if ( ( result != PLAYER_BEHIND_ME ) && ( result != PLAYER_LOST ) ) {
leadTimeOut = sys.getTime() + ED_LEAD_TIMEOUT;
} else if ( sys.getTime() > leadTimeOut ) {
if ( event < ED_POINT_OF_NO_RETURN ) {
setState( "state_Wait" );
}
} else {
// look back at player to see what he's up to
lookAt( $player1, 0.1 );
nextLookTime += 0.1;
}
if ( AI_MOVE_DONE ) {
moveToEntity( $scientist_destination );
}
if ( AI_ACTIVATED ) {
if ( inAnimState( ANIMCHANNEL_HEAD, "Head_Idle" ) ) {
doEvent();
}
}
waitFrame();
}
}
/*
=====================
ai_alphalabs2_scientist1::state_FindPlayer
=====================
*/
void ai_alphalabs2_scientist1::state_FindPlayer() {
setTalkTarget( $null_entity );
while( 1 ) {
moveToPosition( lastValidPlayerPosition );
if ( AI_MOVE_DONE || AI_DEST_UNREACHABLE ) {
if ( !canReachEntity( $player1 ) ) {
setState( "state_CantReachPlayer" );
}
}
if ( $player1.hasEnemies() ) {
setState( "state_Cower" );
}
if ( AI_TALK ) {
sayStuff();
}
checkBlocked();
if ( AI_ACTIVATED ) {
if ( inAnimState( ANIMCHANNEL_HEAD, "Head_Idle" ) ) {
doEvent();
}
}
float result = checkDestinationDistance();
if ( canSee( $player1 ) && ( ( result == PLAYER_BEHIND_ME ) || ( result == PLAYER_OK ) ) ) {
setState( "state_Wait" );
} else if ( result == PLAYER_AHEAD_OF_ME ) {
setState( "state_Lead" );
}
waitFrame();
}
}
/*
=====================
ai_alphalabs2_scientist1::state_Cower
=====================
*/
void ai_alphalabs2_scientist1::state_Cower() {
sys.wait( 0.6 );
setTalkState( TALK_BUSY );
setTalkTarget( $null_entity );
lookAt( self, 0 );
playerEnemy = $player1.closestEnemyToPoint( getOrigin() );
if ( playerEnemy ) {
stopMove();
faceTowardsEntity( playerEnemy, 1 );
sys.wait( 0.4 );
animState( ANIMCHANNEL_HEAD, "Head_Attacked", 4 );
sys.wait( 0.2 );
cower = true;
stopMove();
while( $player1.hasEnemies() ) {
if ( !playerEnemy ) {
playerEnemy = $player1.closestEnemyToPoint( getOrigin() );
}
waitFrame();
}
}
sys.wait( 0.8 );
cower = false;
setTalkState( TALK_OK );
lookAt( $player1, 1 );
sys.wait( 0.5 );
animState( ANIMCHANNEL_HEAD, "Head_AttackDone", 10 );
while( !inAnimState( ANIMCHANNEL_HEAD, "Head_Idle" ) ) {
faceTowardsEntity( $player1, 1 );
waitFrame();
}
sys.wait( 0.2 );
setState( "state_Lead" );
}