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_monster_zombie_commando_cgun.script
2022-08-27 13:19:00 +02:00

640 lines
15 KiB
Text

/***********************************************************************
ai_monster_zombie_commando_cgun.script
monster_zombie_commando_cgun
***********************************************************************/
#define ZOMBIE_CGUN_RUNDISTANCE 192
#define ZOMBIE_CGUN_WALKTURN 65
#define ZOMBIE_CGUN_DODGE_RATE 3
#define ZOMBIE_CGUN_ATTACK_DELAY_MIN 0.5
#define ZOMBIE_CGUN_ATTACK_DELAY_MAX 2
#define ZOMBIE_CGUN_ATTACK_MAX_LENGTH 2.5
#define ZOMBIE_CGUN_ATTACK_MIN_LENGTH 1
#define ZOMBIE_CGUN_WAIT_MIN_LENGTH 0.3
#define ZOMBIE_CGUN_WAIT_MAX_LENGTH 1.5
#define ZOMBIE_CGUN_CROUCH_ATTACK_MAX_LENGTH 15
#define ZOMBIE_CGUN_CROUCH_ATTACK_MIN_LENGTH 3
#define ZOMBIE_CGUN_STAND_ATTACK_MAX_LENGTH 15
#define ZOMBIE_CGUN_STAND_ATTACK_MIN_LENGTH 3
#define ZOMBIE_CGUN_MIN_SHOT_TIME 0.5
#define ZOMBIE_CGUN_NOFOVTIME 4
#define ATTACK_ZCC_CROUCHFIRE ATTACK_SPECIAL1
object monster_zombie_commando_cgun : monster_base {
boolean fire;
boolean crouch_fire;
boolean step_left;
boolean step_right;
float nextDodge;
float nextAttack;
float nextNoFOVAttack;
entity combat_node;
void state_Begin();
void state_Idle();
// attacks
float check_attacks();
void do_attack( float attack_flags );
void crouch_attack();
void stand_attack();
void combat_dodge_left();
void combat_dodge_right();
void init();
// torso anim states
void Torso_Idle();
void Torso_Pain();
void Torso_RangeAttack();
void Torso_CrouchAttack();
// legs anim states
void Legs_Idle();
void Legs_Walk();
void Legs_Run();
void Legs_DodgeLeft();
void Legs_DodgeRight();
void Legs_StepLeft();
void Legs_StepRight();
};
/***********************************************************************
Torso animation control
***********************************************************************/
void monster_zombie_commando_cgun::Torso_Idle() {
idleAnim( ANIMCHANNEL_TORSO, "range_attack_aim" );
eachFrame {
if ( AI_PAIN ) {
Torso_Pain();
idleAnim( ANIMCHANNEL_TORSO, "range_attack_aim" );
}
if ( fire ) {
animState( ANIMCHANNEL_TORSO, "Torso_RangeAttack", 8 );
}
if ( crouch_fire ) {
animState( ANIMCHANNEL_TORSO, "Torso_CrouchAttack", 8 );
}
}
}
void monster_zombie_commando_cgun::Torso_Pain() {
string animname;
animname = getPainAnim();
setBlendFrames( ANIMCHANNEL_TORSO, 3 );
playAnim( ANIMCHANNEL_TORSO, animname );
while( !animDone( ANIMCHANNEL_TORSO, 12 ) ) {
waitFrame();
}
preventPain( 0.6 );
finishAction( "pain" );
setBlendFrames( ANIMCHANNEL_TORSO, 12 );
}
void monster_zombie_commando_cgun::Torso_RangeAttack() {
float endtime;
float mintime;
setAnimPrefix( "" );
playAnim( ANIMCHANNEL_TORSO, "range_attack" );
while( !animDone( ANIMCHANNEL_TORSO, 12 ) ) {
if ( AI_PAIN ) {
Torso_Pain();
}
waitFrame();
}
mintime = sys.getTime() + ZOMBIE_CGUN_MIN_SHOT_TIME;
while( fire || ( sys.getTime() < mintime ) ) {
playAnim( ANIMCHANNEL_TORSO, "range_attack_loop" );
while( ( fire || ( sys.getTime() < mintime ) ) && !animDone( ANIMCHANNEL_TORSO, 12 ) ) {
if ( sys.influenceActive() ) {
fire = false;
mintime = 0;
break;
}
if ( AI_PAIN ) {
Torso_Pain();
}
waitFrame();
}
}
if ( !animDone( ANIMCHANNEL_TORSO, 8 ) ) {
setBlendFrames( ANIMCHANNEL_TORSO, 8 );
}
playAnim( ANIMCHANNEL_TORSO, "range_attack_end" );
while( !animDone( ANIMCHANNEL_TORSO, 12 ) ) {
if ( AI_PAIN ) {
Torso_Pain();
}
waitFrame();
}
finishAction( "range_attack" );
animState( ANIMCHANNEL_TORSO, "Torso_Idle", 12 );
}
void monster_zombie_commando_cgun::Torso_TurretAttack() {
float endtime;
setAnimPrefix( "" );
playAnim( ANIMCHANNEL_TORSO, "range_attack" );
while( !animDone( ANIMCHANNEL_TORSO, 8 ) ) {
if ( AI_PAIN ) {
Torso_Pain();
}
waitFrame();
}
endtime = RandomDelay( ZOMBIE_CGUN_ATTACK_MIN_LENGTH, ZOMBIE_CGUN_ATTACK_MAX_LENGTH );
while( ( sys.getTime() < endtime ) && canHitEnemyFromAnim( "range_attack_loop" ) ) {
playAnim( ANIMCHANNEL_TORSO, "range_attack_loop" );
while( !animDone( ANIMCHANNEL_TORSO, 8 ) ) {
if ( sys.influenceActive() ) {
endtime = 0;
break;
}
if ( AI_PAIN ) {
Torso_Pain();
}
waitFrame();
}
}
if ( !animDone( ANIMCHANNEL_TORSO, 8 ) ) {
setBlendFrames( ANIMCHANNEL_TORSO, 8 );
}
playAnim( ANIMCHANNEL_TORSO, "range_attack_end" );
while( !animDone( ANIMCHANNEL_TORSO, 8 ) ) {
if ( AI_PAIN ) {
Torso_Pain();
}
waitFrame();
}
finishAction( "turret_attack" );
animState( ANIMCHANNEL_TORSO, "Torso_Idle", 8 );
}
void monster_zombie_commando_cgun::Torso_CrouchAttack() {
float endtime;
float mintime;
overrideAnim( ANIMCHANNEL_LEGS );
setAnimPrefix( "crouch" );
playAnim( ANIMCHANNEL_TORSO, "range_attack" );
while( !animDone( ANIMCHANNEL_TORSO, 8 ) ) {
if ( AI_PAIN ) {
Torso_Pain();
}
waitFrame();
}
mintime = sys.getTime() + ZOMBIE_CGUN_MIN_SHOT_TIME;
while( crouch_fire || ( sys.getTime() < mintime ) ) {
endtime = RandomDelay( ZOMBIE_CGUN_ATTACK_MIN_LENGTH, ZOMBIE_CGUN_ATTACK_MAX_LENGTH );
while( ( crouch_fire || ( sys.getTime() < mintime ) ) && ( sys.getTime() < endtime ) ) {
playAnim( ANIMCHANNEL_TORSO, "range_attack_loop" );
while( !animDone( ANIMCHANNEL_TORSO, 8 ) ) {
if ( sys.influenceActive() ) {
crouch_fire = false;
endtime = 0;
break;
}
if ( AI_PAIN ) {
Torso_Pain();
}
waitFrame();
}
}
if ( !crouch_fire ) {
break;
}
playCycle( ANIMCHANNEL_TORSO, "range_attack_aim" );
endtime = RandomDelay( ZOMBIE_CGUN_WAIT_MIN_LENGTH, ZOMBIE_CGUN_WAIT_MAX_LENGTH );
while( crouch_fire && ( sys.getTime() < endtime ) ) {
if ( sys.influenceActive() ) {
crouch_fire = false;
endtime = 0;
break;
}
if ( AI_PAIN ) {
Torso_Pain();
}
waitFrame();
}
}
playAnim( ANIMCHANNEL_TORSO, "range_attack_end" );
while( !animDone( ANIMCHANNEL_TORSO, 8 ) ) {
if ( AI_PAIN ) {
Torso_Pain();
}
waitFrame();
}
finishAction( "crouch_attack" );
setAnimPrefix( "" );
animState( ANIMCHANNEL_TORSO, "Torso_Idle", 8 );
}
/***********************************************************************
Legs animation control
***********************************************************************/
void monster_zombie_commando_cgun::Legs_Idle() {
idleAnim( ANIMCHANNEL_LEGS, "range_attack_aim" );
eachFrame {
if ( run && AI_FORWARD ) { animState( ANIMCHANNEL_LEGS, "Legs_Run", 8 ); }
if ( AI_FORWARD ) { animState( ANIMCHANNEL_LEGS, "Legs_Walk", 8 ); }
if ( step_left ) { animState( ANIMCHANNEL_LEGS, "Legs_StepLeft", 8 ); }
if ( step_right ) { animState( ANIMCHANNEL_LEGS, "Legs_StepRight", 8 ); }
}
}
void monster_zombie_commando_cgun::Legs_Walk() {
playCycle( ANIMCHANNEL_LEGS, "walk" );
eachFrame {
if ( run && AI_FORWARD ) { animState( ANIMCHANNEL_LEGS, "Legs_Run", 8 ); }
if ( !AI_FORWARD ) { animState( ANIMCHANNEL_LEGS, "Legs_Idle", 8 ); }
}
}
void monster_zombie_commando_cgun::Legs_Run() {
playCycle( ANIMCHANNEL_LEGS, "run" );
eachFrame {
if ( !run && AI_FORWARD ) { animState( ANIMCHANNEL_LEGS, "Legs_Walk", 8 ); }
if ( !AI_FORWARD ) { animState( ANIMCHANNEL_LEGS, "Legs_Idle", 8 ); }
}
}
void monster_zombie_commando_cgun::Legs_DodgeLeft() {
playAnim( ANIMCHANNEL_LEGS, "evade_left" );
while( !animDone( ANIMCHANNEL_LEGS, 8 ) ) {
waitFrame();
}
finishAction( "strafe" );
animState( ANIMCHANNEL_LEGS, "Legs_Idle", 8 );
}
void monster_zombie_commando_cgun::Legs_DodgeRight() {
playAnim( ANIMCHANNEL_LEGS, "evade_right" );
while( !animDone( ANIMCHANNEL_LEGS, 8 ) ) {
waitFrame();
}
finishAction( "strafe" );
animState( ANIMCHANNEL_LEGS, "Legs_Idle", 8 );
}
void monster_zombie_commando_cgun::Legs_StepLeft() {
playAnim( ANIMCHANNEL_LEGS, "step_left" );
while( !animDone( ANIMCHANNEL_LEGS, 8 ) ) {
waitFrame();
}
step_left = false;
finishAction( "sidestep" );
animState( ANIMCHANNEL_LEGS, "Legs_Idle", 8 );
}
void monster_zombie_commando_cgun::Legs_StepRight() {
playAnim( ANIMCHANNEL_LEGS, "step_right" );
while( !animDone( ANIMCHANNEL_LEGS, 8 ) ) {
waitFrame();
}
step_right = false;
finishAction( "sidestep" );
animState( ANIMCHANNEL_LEGS, "Legs_Idle", 8 );
}
/***********************************************************************
AI
***********************************************************************/
/*
=====================
monster_zombie_commando_cgun::init
=====================
*/
void monster_zombie_commando_cgun::init() {
run_distance = ZOMBIE_CGUN_RUNDISTANCE;
walk_turn = ZOMBIE_CGUN_WALKTURN;
setState( "state_Begin" );
}
/***********************************************************************
States
***********************************************************************/
/*
=====================
monster_zombie_commando_cgun::state_Begin
=====================
*/
void monster_zombie_commando_cgun::state_Begin() {
fire = false;
crouch_fire = false;
step_left = false;
step_right = false;
animState( ANIMCHANNEL_TORSO, "Torso_Idle", 8 );
animState( ANIMCHANNEL_LEGS, "Legs_Idle", 8 );
monster_begin();
setMoveType( MOVETYPE_ANIM );
setState( "state_Idle" );
}
/*
=====================
monster_zombie_commando_cgun::state_Idle
=====================
*/
void monster_zombie_commando_cgun::state_Idle() {
wait_for_enemy();
nextAttack = 0;
nextNoFOVAttack = 0;
nextDodge = RandomTime( ZOMBIE_CGUN_DODGE_RATE );
setState( "state_Combat" );
}
/***********************************************************************
attacks
***********************************************************************/
/*
=====================
monster_zombie_commando_cgun::do_attack
=====================
*/
void monster_zombie_commando_cgun::do_attack( float attack_flags ) {
nextNoFOVAttack = sys.getTime() + ZOMBIE_CGUN_NOFOVTIME;
if ( attack_flags & ATTACK_DODGE_LEFT ) {
combat_dodge_left();
} else if ( attack_flags & ATTACK_DODGE_RIGHT ) {
combat_dodge_right();
} else if ( attack_flags & ATTACK_COMBAT_NODE ) {
combat_ainode( combat_node );
} else if ( attack_flags & ATTACK_MISSILE ) {
stand_attack();
} else if ( attack_flags & ATTACK_ZCC_CROUCHFIRE ) {
crouch_attack();
}
}
/*
=====================
monster_zombie_commando_cgun::check_attacks
=====================
*/
float monster_zombie_commando_cgun::check_attacks() {
float currentTime;
float attack_flags;
boolean try_attack;
boolean reachable;
attack_flags = 0;
currentTime = sys.getTime();
if ( AI_PAIN && ( currentTime >= nextDodge ) ) {
if ( testAnimMove( "evade_left" ) ) {
attack_flags |= ATTACK_DODGE_LEFT;
}
if ( testAnimMove( "evade_right" ) ) {
attack_flags |= ATTACK_DODGE_RIGHT;
// if we can dodge either direction, pick one
if ( attack_flags & ATTACK_DODGE_LEFT ) {
if ( sys.random( 100 ) < 50 ) {
attack_flags &= ~ATTACK_DODGE_RIGHT;
} else {
attack_flags &= ~ATTACK_DODGE_LEFT;
}
}
}
}
combat_node = getCombatNode();
if ( combat_node ) {
attack_flags |= ATTACK_COMBAT_NODE;
}
reachable = canReachEnemy();
if ( AI_ENEMY_IN_FOV && ( !reachable || ( currentTime >= nextAttack ) ) ) {
try_attack = true;
} else if ( ( sys.getTime() > nextNoFOVAttack ) && AI_ENEMY_VISIBLE && ( !reachable || ( currentTime >= nextAttack ) ) ) {
try_attack = true;
} else if ( touches( getEnemy() ) ) {
try_attack = true;
} else {
try_attack = false;
}
if ( try_attack ) {
if ( sys.random( 1 ) < 0.5 ) {
if ( canHitEnemyFromAnim( "crouch_range_attack_loop" ) ) {
attack_flags |= ATTACK_ZCC_CROUCHFIRE;
} else if ( canHitEnemyFromAnim( "range_attack_loop" ) ) {
attack_flags |= ATTACK_MISSILE;
}
} else if ( canHitEnemyFromAnim( "range_attack_loop" ) ) {
attack_flags |= ATTACK_MISSILE;
}
}
return attack_flags;
}
/*
=====================
monster_zombie_commando_cgun::stand_attack
=====================
*/
void monster_zombie_commando_cgun::stand_attack() {
float attackTime;
float endtime;
float attack_flags;
faceEnemy();
attackTime = RandomDelay( ZOMBIE_CGUN_STAND_ATTACK_MIN_LENGTH, ZOMBIE_CGUN_STAND_ATTACK_MAX_LENGTH );
while( AI_ENEMY_VISIBLE && !sys.influenceActive() ) {
fire = true;
endtime = RandomDelay( 2, 5 );
while( sys.getTime() < endtime ) {
if ( sys.influenceActive() ) {
break;
}
if ( !canHitEnemyFromAnim( "range_attack_loop" ) ) {
break;
}
if ( AI_PAIN ) {
attack_flags = check_attacks();
if ( attack_flags & ( ATTACK_DODGE_LEFT | ATTACK_DODGE_RIGHT ) ) {
fire = false;
do_attack( attack_flags );
return;
}
}
waitFrame();
}
fire = false;
while( !inAnimState( ANIMCHANNEL_TORSO, "Torso_Idle" ) ) {
lookAtEnemy( 1 );
waitFrame();
}
if ( sys.influenceActive() ) {
break;
}
if ( sys.getTime() > attackTime ) {
break;
}
if ( !AI_ENEMY_VISIBLE || !canHitEnemyFromAnim( "range_attack_loop" ) ) {
break;
}
step_left = testAnimMove( "step_left" );
step_right = testAnimMove( "step_right" );
if ( step_left && step_right ) {
if ( sys.random( 100 ) < 50 ) {
step_left = false;
} else {
step_right = false;
}
}
while( step_left || step_right ) {
lookAtEnemy( 1 );
waitFrame();
}
}
fire = false;
while( !inAnimState( ANIMCHANNEL_TORSO, "Torso_Idle" ) ) {
waitFrame();
}
// don't attack for a bit
nextAttack = RandomDelay( ZOMBIE_CGUN_ATTACK_DELAY_MIN, ZOMBIE_CGUN_ATTACK_DELAY_MAX );
nextNoFOVAttack = sys.getTime() + ZOMBIE_CGUN_NOFOVTIME;
}
/*
=====================
monster_zombie_commando_cgun::crouch_attack
=====================
*/
void monster_zombie_commando_cgun::crouch_attack() {
float attackTime;
float attack_flags;
faceEnemy();
crouch_fire = true;
attackTime = RandomDelay( ZOMBIE_CGUN_CROUCH_ATTACK_MIN_LENGTH, ZOMBIE_CGUN_CROUCH_ATTACK_MAX_LENGTH );
while( AI_ENEMY_VISIBLE ) {
if ( sys.influenceActive() ) {
break;
}
if ( sys.getTime() > attackTime ) {
break;
}
if ( AI_PAIN ) {
attack_flags = check_attacks();
if ( attack_flags & ( ATTACK_DODGE_LEFT | ATTACK_DODGE_RIGHT ) ) {
crouch_fire = false;
setAnimPrefix( "" );
do_attack( attack_flags );
return;
}
}
lookAtEnemy( 1 );
if ( !canHitEnemyFromAnim( "range_attack_loop" ) ) {
break;
}
waitFrame();
}
crouch_fire = false;
while( inAnimState( ANIMCHANNEL_TORSO, "Torso_CrouchAttack" ) ) {
waitFrame();
}
// don't attack for a bit
nextAttack = RandomDelay( ZOMBIE_CGUN_ATTACK_DELAY_MIN, ZOMBIE_CGUN_ATTACK_DELAY_MAX );
nextNoFOVAttack = sys.getTime() + ZOMBIE_CGUN_NOFOVTIME;
}
/*
=====================
monster_zombie_commando_cgun::combat_dodge_left
=====================
*/
void monster_zombie_commando_cgun::combat_dodge_left() {
stopMove();
faceEnemy();
animState( ANIMCHANNEL_LEGS, "Legs_DodgeLeft", 8 );
waitAction( "strafe" );
nextDodge = DelayTime( ZOMBIE_CGUN_DODGE_RATE );
}
/*
=====================
monster_zombie_commando_cgun::combat_dodge_right
=====================
*/
void monster_zombie_commando_cgun::combat_dodge_right() {
stopMove();
faceEnemy();
animState( ANIMCHANNEL_LEGS, "Legs_DodgeRight", 8 );
waitAction( "strafe" );
nextDodge = DelayTime( ZOMBIE_CGUN_DODGE_RATE );
}