mirror of
https://github.com/id-Software/DOOM-3-BFG.git
synced 2025-03-15 23:21:35 +00:00
320 lines
7.4 KiB
Text
320 lines
7.4 KiB
Text
/***********************************************************************
|
|
|
|
ai_monster_demon_hellknight.script
|
|
|
|
monster_demon_hellknight
|
|
|
|
***********************************************************************/
|
|
|
|
#define HELLKNIGHT_ATTACK_RATE 3
|
|
#define HELLKNIGHT_PAIN_DELAY 0.25
|
|
#define HELLKNIGHT_NOFOVTIME 6
|
|
|
|
// anim blend times
|
|
#define HELLKNIGHT_PAIN_TO_IDLE 2
|
|
#define HELLKNIGHT_PAIN_TO_PAIN 0
|
|
#define HELLKNIGHT_SIGHT_TO_IDLE 4
|
|
#define HELLKNIGHT_MELEE_TO_IDLE 4
|
|
#define HELLKNIGHT_RANGE_TO_IDLE 4
|
|
#define HELLKNIGHT_WAIT_TO_OUT 4
|
|
#define HELLKNIGHT_IN_TO_WAIT 4
|
|
#define HELLKNIGHT_WALK_TO_WAIT 4
|
|
#define HELLKNIGHT_WALK_TO_ACTION 4
|
|
#define HELLKNIGHT_ACTION_TO_IDLE 4
|
|
#define HELLKNIGHT_IDLE_TO_PAIN 0
|
|
#define HELLKNIGHT_IDLE_TO_WALK 4
|
|
#define HELLKNIGHT_IDLE_TO_SIGHT 4
|
|
#define HELLKNIGHT_WALK_TO_IDLE 4
|
|
#define HELLKNIGHT_WALK_TO_RANGEATTACK 4
|
|
#define HELLKNIGHT_IDLE_TO_RANGEATTACK 4
|
|
#define HELLKNIGHT_WALK_TO_MELEE 4
|
|
#define HELLKNIGHT_IDLE_TO_TURRETATTACK 4
|
|
#define HELLKNIGHT_TURRETATTACK_TO_IDLE 4
|
|
|
|
object monster_demon_hellknight : monster_base {
|
|
float nextAttack;
|
|
float nextNoFOVAttack;
|
|
entity combat_node;
|
|
string range_attack_anim;
|
|
|
|
//
|
|
// States
|
|
//
|
|
void state_Begin();
|
|
void state_Idle();
|
|
|
|
// attacks
|
|
float check_attacks();
|
|
void do_attack( float attack_flags );
|
|
void combat_range();
|
|
void combat_melee();
|
|
|
|
void init();
|
|
|
|
// torso anim states
|
|
void Torso_Idle();
|
|
void Torso_Pain();
|
|
void Torso_MeleeAttack();
|
|
void Torso_RangeAttack();
|
|
void Torso_TurretAttack();
|
|
|
|
// legs anim states
|
|
void Legs_Idle();
|
|
void Legs_Walk();
|
|
};
|
|
|
|
/***********************************************************************
|
|
|
|
Torso animation control
|
|
|
|
***********************************************************************/
|
|
|
|
void monster_demon_hellknight::Torso_Idle() {
|
|
idleAnim( ANIMCHANNEL_TORSO, "stand" );
|
|
|
|
while( !AI_PAIN ) {
|
|
waitFrame();
|
|
}
|
|
|
|
animState( ANIMCHANNEL_TORSO, "Torso_Pain", HELLKNIGHT_IDLE_TO_PAIN );
|
|
}
|
|
|
|
void monster_demon_hellknight::Torso_Pain() {
|
|
string animname;
|
|
float nextpain;
|
|
float currenttime;
|
|
|
|
animname = getPainAnim();
|
|
playAnim( ANIMCHANNEL_TORSO, animname );
|
|
|
|
nextpain = sys.getTime() + HELLKNIGHT_PAIN_DELAY;
|
|
|
|
while( !animDone( ANIMCHANNEL_TORSO, HELLKNIGHT_PAIN_TO_IDLE ) ) {
|
|
if ( AI_PAIN ) {
|
|
currenttime = sys.getTime();
|
|
if ( currenttime > nextpain ) {
|
|
animState( ANIMCHANNEL_TORSO, "Torso_Pain", HELLKNIGHT_PAIN_TO_PAIN );
|
|
}
|
|
}
|
|
waitFrame();
|
|
}
|
|
|
|
finishAction( "pain" );
|
|
animState( ANIMCHANNEL_TORSO, "Torso_Idle", HELLKNIGHT_PAIN_TO_IDLE );
|
|
}
|
|
|
|
void monster_demon_hellknight::Torso_MeleeAttack() {
|
|
playAnim( ANIMCHANNEL_TORSO, "melee_attack" );
|
|
|
|
while( !animDone( ANIMCHANNEL_TORSO, HELLKNIGHT_MELEE_TO_IDLE ) ) {
|
|
waitFrame();
|
|
}
|
|
|
|
finishAction( "melee_attack" );
|
|
animState( ANIMCHANNEL_TORSO, "Torso_Idle", HELLKNIGHT_MELEE_TO_IDLE );
|
|
}
|
|
|
|
void monster_demon_hellknight::Torso_RangeAttack() {
|
|
string anim;
|
|
|
|
disablePain();
|
|
faceEnemy();
|
|
|
|
playAnim( ANIMCHANNEL_TORSO, range_attack_anim );
|
|
while( !animDone( ANIMCHANNEL_TORSO, HELLKNIGHT_RANGE_TO_IDLE ) ) {
|
|
lookAtEnemy( 1 );
|
|
waitFrame();
|
|
}
|
|
|
|
allowMovement( true );
|
|
finishAction( "range_attack" );
|
|
animState( ANIMCHANNEL_TORSO, "Torso_Idle", HELLKNIGHT_RANGE_TO_IDLE );
|
|
}
|
|
|
|
void monster_demon_hellknight::Torso_TurretAttack() {
|
|
allowMovement( false );
|
|
disablePain();
|
|
faceEnemy();
|
|
|
|
playAnim( ANIMCHANNEL_TORSO, "turret_attack" );
|
|
while( !animDone( ANIMCHANNEL_TORSO, 4 ) ) {
|
|
waitFrame();
|
|
}
|
|
|
|
finishAction( "turret_attack" );
|
|
allowMovement( true );
|
|
animState( ANIMCHANNEL_TORSO, "Torso_Idle", 4 );
|
|
}
|
|
|
|
/***********************************************************************
|
|
|
|
Legs animation control
|
|
|
|
***********************************************************************/
|
|
|
|
void monster_demon_hellknight::Legs_Idle() {
|
|
idleAnim( ANIMCHANNEL_LEGS, "stand" );
|
|
|
|
eachFrame {
|
|
if ( AI_FORWARD ) { animState( ANIMCHANNEL_LEGS, "Legs_Walk", 4 ); }
|
|
}
|
|
}
|
|
|
|
void monster_demon_hellknight::Legs_Walk() {
|
|
playCycle( ANIMCHANNEL_LEGS, "walk" );
|
|
|
|
eachFrame {
|
|
if ( !AI_FORWARD ) { animState( ANIMCHANNEL_LEGS, "Legs_Idle", 4 ); }
|
|
}
|
|
}
|
|
|
|
/***********************************************************************
|
|
|
|
AI
|
|
|
|
***********************************************************************/
|
|
|
|
/*
|
|
=====================
|
|
monster_demon_hellknight::init
|
|
=====================
|
|
*/
|
|
void monster_demon_hellknight::init() {
|
|
setState( "state_Begin" );
|
|
}
|
|
|
|
/***********************************************************************
|
|
|
|
States
|
|
|
|
***********************************************************************/
|
|
|
|
/*
|
|
=====================
|
|
monster_demon_hellknight::state_Begin
|
|
=====================
|
|
*/
|
|
void monster_demon_hellknight::state_Begin() {
|
|
animState( ANIMCHANNEL_TORSO, "Torso_Idle", 0 );
|
|
animState( ANIMCHANNEL_LEGS, "Legs_Idle", 0 );
|
|
monster_begin();
|
|
setMoveType( MOVETYPE_ANIM );
|
|
setState( "state_Idle" );
|
|
}
|
|
|
|
/*
|
|
=====================
|
|
monster_demon_hellknight::state_Idle
|
|
=====================
|
|
*/
|
|
void monster_demon_hellknight::state_Idle() {
|
|
wait_for_enemy();
|
|
|
|
nextAttack = 0;
|
|
nextNoFOVAttack = 0;
|
|
|
|
setState( "state_Combat" );
|
|
}
|
|
|
|
/***********************************************************************
|
|
|
|
attacks
|
|
|
|
***********************************************************************/
|
|
|
|
/*
|
|
=====================
|
|
monster_demon_hellknight::do_attack
|
|
=====================
|
|
*/
|
|
void monster_demon_hellknight::do_attack( float attack_flags ) {
|
|
nextNoFOVAttack = sys.getTime() + HELLKNIGHT_NOFOVTIME;
|
|
if ( attack_flags & ATTACK_COMBAT_NODE ) {
|
|
combat_ainode( combat_node );
|
|
} else if ( attack_flags & ATTACK_MELEE ) {
|
|
combat_melee();
|
|
} else if ( attack_flags & ATTACK_MISSILE ) {
|
|
combat_range();
|
|
}
|
|
}
|
|
|
|
/*
|
|
=====================
|
|
monster_demon_hellknight::check_attacks
|
|
=====================
|
|
*/
|
|
float monster_demon_hellknight::check_attacks() {
|
|
float currentTime;
|
|
float canMelee;
|
|
float attack_flags;
|
|
vector vel;
|
|
float t;
|
|
vector jumpTarget;
|
|
string anim;
|
|
|
|
attack_flags = 0;
|
|
|
|
canMelee = testMeleeAttack();
|
|
currentTime = sys.getTime();
|
|
if ( !canMelee ) {
|
|
combat_node = getCombatNode();
|
|
if ( combat_node ) {
|
|
attack_flags |= ATTACK_COMBAT_NODE;
|
|
}
|
|
}
|
|
|
|
if ( canMelee ) {
|
|
attack_flags |= ATTACK_MELEE;
|
|
}
|
|
|
|
if ( ( ( sys.getTime() > nextNoFOVAttack ) && AI_ENEMY_VISIBLE ) || AI_ENEMY_IN_FOV ) {
|
|
if ( !canReachEnemy() || ( currentTime >= nextAttack ) ) {
|
|
range_attack_anim = chooseAnim( ANIMCHANNEL_LEGS, "turret_attack" );
|
|
if ( canHitEnemyFromAnim( range_attack_anim ) ) {
|
|
attack_flags |= ATTACK_MISSILE;
|
|
}
|
|
|
|
anim = chooseAnim( ANIMCHANNEL_LEGS, "range_attack" );
|
|
if ( testAnimMoveTowardEnemy( anim ) ) {
|
|
if ( canHitEnemyFromAnim( anim ) ) {
|
|
range_attack_anim = anim;
|
|
attack_flags |= ATTACK_MISSILE;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return attack_flags;
|
|
}
|
|
|
|
/*
|
|
=====================
|
|
monster_demon_hellknight::combat_range
|
|
=====================
|
|
*/
|
|
void monster_demon_hellknight::combat_range() {
|
|
faceEnemy();
|
|
if ( !AI_ENEMY_IN_FOV ) {
|
|
sys.wait( 0.4 );
|
|
}
|
|
|
|
animState( ANIMCHANNEL_TORSO, "Torso_RangeAttack", HELLKNIGHT_WALK_TO_RANGEATTACK );
|
|
waitAction( "range_attack" );
|
|
|
|
// don't attack for a bit
|
|
nextAttack = DelayTime( HELLKNIGHT_ATTACK_RATE );
|
|
nextNoFOVAttack = sys.getTime() + HELLKNIGHT_NOFOVTIME;
|
|
}
|
|
|
|
/*
|
|
=====================
|
|
monster_demon_hellknight::combat_melee
|
|
=====================
|
|
*/
|
|
void monster_demon_hellknight::combat_melee() {
|
|
lookAtEnemy( 100 );
|
|
faceEnemy();
|
|
animState( ANIMCHANNEL_TORSO, "Torso_MeleeAttack", HELLKNIGHT_WALK_TO_MELEE );
|
|
waitAction( "melee_attack" );
|
|
lookAtEnemy( 1 );
|
|
}
|