doom3-bfg/base/script/ai_follower.script
2022-08-27 13:19:00 +02:00

387 lines
7.5 KiB
Text

/***********************************************************************
ai_follower.script
***********************************************************************/
#define FOLLOW_MAXDIST 120
#define FOLLOW_MINDIST 80
#define FOLLOW_RUNDIST 180
object follower : ai {
string customAnim;
boolean inCustomAnim;
float customBlendOut;
boolean run;
//
// States
//
void state_Idle();
void state_Killed();
void state_Follow();
void getCloser();
void init();
void playCustomCycle( string animname, float blendTime );
void playCustomAnim( string animname, float blendIn, float blendOut );
float should_turn_left();
float should_turn_right();
// torso anim states
void Torso_Death();
void Torso_Idle();
void Torso_Pain();
void Torso_CustomAnim();
void Torso_CustomCycle();
// legs anim states
void Legs_Death();
void Legs_Idle();
void Legs_Walk();
void Legs_Run();
void Legs_TurnLeft();
void Legs_TurnRight();
};
/***********************************************************************
Torso animation control
***********************************************************************/
void follower::Torso_CustomCycle() {
overrideAnim( ANIMCHANNEL_LEGS );
playCycle( ANIMCHANNEL_TORSO, customAnim );
eachFrame {
;
}
}
void follower::Torso_CustomAnim() {
inCustomAnim = true;
playAnim( ANIMCHANNEL_TORSO, customAnim );
while( !( animDone( ANIMCHANNEL_TORSO, customBlendOut ) ) ) {
waitFrame();
}
finishAction( "customAnim" );
inCustomAnim = false;
animState( ANIMCHANNEL_TORSO, "Torso_Idle", customBlendOut );
}
void follower::Torso_Death() {
finishAction( "dead" );
}
void follower::Torso_Idle() {
idleAnim( ANIMCHANNEL_TORSO, "idle" );
while( !AI_PAIN ) {
waitFrame();
}
animState( ANIMCHANNEL_TORSO, "Torso_Pain", 0 );
}
void follower::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 follower::Legs_Death() {
}
float follower::should_turn_left() {
float turnAmount;
turnAmount = getTurnDelta();
if ( turnAmount > 10 ) {
if ( hasAnim( ANIMCHANNEL_LEGS, "turn_left" ) ) {
return true;
}
}
return false;
}
float follower::should_turn_right() {
float turnAmount;
turnAmount = getTurnDelta();
if ( turnAmount < -10 ) {
if ( hasAnim( ANIMCHANNEL_LEGS, "turn_right" ) ) {
return true;
}
}
return false;
}
void follower::Legs_Idle() {
if ( !AI_FORWARD && !facingIdeal() ) {
if ( should_turn_left() ) {
animState( ANIMCHANNEL_LEGS, "Legs_TurnLeft", 4 );
}
if ( should_turn_right() ) {
animState( ANIMCHANNEL_LEGS, "Legs_TurnRight", 4 );
}
}
idleAnim( ANIMCHANNEL_LEGS, "idle" );
eachFrame {
if ( AI_FORWARD ) {
if ( run ) {
animState( ANIMCHANNEL_LEGS, "Legs_Run", 12 );
} else {
animState( ANIMCHANNEL_LEGS, "Legs_Walk", 12 );
}
}
if ( !facingIdeal() ) {
if ( should_turn_left() ) {
animState( ANIMCHANNEL_LEGS, "Legs_TurnLeft", 4 );
}
if ( should_turn_right() ) {
animState( ANIMCHANNEL_LEGS, "Legs_TurnRight", 4 );
}
}
}
}
void follower::Legs_Walk() {
playCycle( ANIMCHANNEL_LEGS, "walk" );
while( AI_FORWARD && !run ) {
waitFrame();
}
if ( AI_FORWARD && run ) {
animState( ANIMCHANNEL_LEGS, "Legs_Run", 12 );
}
animState( ANIMCHANNEL_LEGS, "Legs_Idle", 12 );
}
void follower::Legs_Run() {
playCycle( ANIMCHANNEL_LEGS, "run" );
while( AI_FORWARD && run ) {
waitFrame();
}
if ( AI_FORWARD ) {
animState( ANIMCHANNEL_LEGS, "Legs_Walk", 12 );
}
animState( ANIMCHANNEL_LEGS, "Legs_Idle", 12 );
}
void follower::Legs_TurnLeft() {
float turnAmount;
turnAmount = getTurnDelta();
if ( turnAmount > 110 ) {
// do it in two turns
turnAmount *= 0.5;
}
playAnim( ANIMCHANNEL_LEGS, "turn_left" );
while( !animDone( ANIMCHANNEL_LEGS, 0 ) ) {
waitFrame();
}
playAnim( ANIMCHANNEL_LEGS, "turn_right" );
while( !animDone( ANIMCHANNEL_LEGS, 4 ) ) {
waitFrame();
}
animState( ANIMCHANNEL_LEGS, "Legs_Idle", 4 );
}
void follower::Legs_TurnRight() {
float turnAmount;
turnAmount = getTurnDelta();
if ( turnAmount < -110 ) {
// do it in two turns
turnAmount *= 0.5;
}
playAnim( ANIMCHANNEL_LEGS, "turn_right" );
while( !animDone( ANIMCHANNEL_LEGS, 0 ) ) {
waitFrame();
}
playAnim( ANIMCHANNEL_LEGS, "turn_left" );
while( !animDone( ANIMCHANNEL_LEGS, 4 ) ) {
waitFrame();
}
animState( ANIMCHANNEL_LEGS, "Legs_Idle", 4 );
}
/***********************************************************************
AI
***********************************************************************/
/*
=====================
follower::init
=====================
*/
void follower::init() {
inCustomAnim = false;
run = false;
float mod;
mod = getIntKey( "head_look" );
setBoneMod( mod );
setTalkState( TALK_OK );
self.setKey( "conversationNext", "" );
setKey( "wander", "1" );
animState( ANIMCHANNEL_TORSO, "Torso_Idle", 0 );
animState( ANIMCHANNEL_LEGS, "Legs_Idle", 0 );
setState( "state_Idle" );
}
/*
=====================
follower::playCustomCycle
=====================
*/
void follower::playCustomCycle( string animname, float blendTime ) {
customAnim = animname;
animState( ANIMCHANNEL_TORSO, "Torso_CustomCycle", blendTime );
}
/*
=====================
follower::playCustomAnim
=====================
*/
void follower::playCustomAnim( string animname, float blendIn, float blendOut ) {
customBlendOut = blendOut;
customAnim = animname;
inCustomAnim = true;
animState( ANIMCHANNEL_TORSO, "Torso_CustomAnim", blendIn );
}
/***********************************************************************
States
***********************************************************************/
/*
=====================
follower::state_Idle
=====================
*/
void follower::state_Idle() {
stopMove();
setTalkTarget( $null_entity );
while( 1 ) {
if ( AI_TALK ) {
setState( "state_Follow" );
}
waitFrame();
}
}
/*
=====================
follower::state_Killed
=====================
*/
void follower::state_Killed() {
stopMove();
animState( ANIMCHANNEL_TORSO, "Torso_Death", 0 );
animState( ANIMCHANNEL_LEGS, "Legs_Death", 0 );
waitAction( "dead" );
stopThinking();
}
/*
=====================
follower::state_Follow
=====================
*/
void follower::state_Follow() {
entity leader;
leader = getTalkTarget();
if ( !leader ) {
leader = $player1;
}
setTalkTarget( $null_entity );
while( 1 ) {
lookAt( leader, 0.1 );
if ( AI_TALK ) {
setState( "state_Idle" );
}
if ( distanceTo( leader ) > FOLLOW_MAXDIST ) {
getCloser();
} else {
faceEntity( leader );
}
waitFrame();
}
}
void follower::getCloser() {
entity leader;
leader = getTalkTarget();
if ( !leader ) {
leader = $player1;
}
setTalkTarget( $null_entity );
run = false;
moveToEntity( leader );
while( !AI_DEST_UNREACHABLE && !AI_MOVE_DONE && ( distanceTo( leader ) > FOLLOW_MINDIST ) ) {
lookAt( leader, 0.1 );
if ( distanceTo( leader ) > FOLLOW_RUNDIST ) {
run = true;
}
if ( distanceTo( leader ) < FOLLOW_MAXDIST ) {
run = false;
}
if ( AI_TALK ) {
setState( "state_Idle" );
}
waitFrame();
}
stopMove();
}