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

494 lines
11 KiB
Text

/***********************************************************************
ai_monster_boss_sabaoth.script
monster_boss_sabaoth
***********************************************************************/
#define SABAOTH_ATTACK_RATE 4
#define SABAOTH_ATTACK_RATE_MELEE 1
#define SABAOTH_SLOW_DIST 64
#define SECTION_MOVE_DIST 190
#define CENTER_DIST 304
#define MELEE_INIT 290
object monster_boss_sabaoth : monster_base {
float nextAttack;
float movespeed;
entity projectile;
//
// States
//
void state_Begin();
void state_Idle();
void state_Combat();
void state_Killed();
// attacks
float check_attacks( float meleeOnly );
void do_attack( float attack_flags );
void combat_range();
void combat_melee();
void fire_bfg();
void init();
void move_to_corner( entity path, boolean noslowtostop );
void turn_to_corner( entity path );
void closeSection( entity path );
void openSection( entity path );
// torso anim states
void Torso_Idle();
void Torso_RangeAttack();
void Torso_MeleeAttack();
// legs anim states
void Legs_Idle();
void Legs_Walk();
void open_section_1();
void close_section_1();
void open_section_2();
void close_section_2();
void close_section_3();
void open_section_3();
void close_section_4();
void open_section_4();
void open_section_5();
void close_section_5();
void open_section_6();
void close_section_6();
void open_section_7();
void close_section_7();
void open_section_8();
void close_section_8();
};
/***********************************************************************
Torso animation control
***********************************************************************/
void monster_boss_sabaoth::Torso_Idle() {
idleAnim( ANIMCHANNEL_TORSO, "stand" );
}
void monster_boss_sabaoth::Torso_MeleeAttack() {
playAnim( ANIMCHANNEL_TORSO, "melee_attack" );
while( !animDone( ANIMCHANNEL_TORSO, 3 ) ) {
lookAtEnemy( 1 );
waitFrame();
}
finishAction( "melee_attack" );
animState( ANIMCHANNEL_TORSO, "Torso_Idle", 6 );
}
void monster_boss_sabaoth::Torso_RangeAttack() {
playAnim( ANIMCHANNEL_TORSO, "range_attack" );
while( !animDone( ANIMCHANNEL_TORSO, 3 ) ) {
lookAtEnemy( 1 );
waitFrame();
}
finishAction( "range_attack" );
nextAttack = DelayTime( SABAOTH_ATTACK_RATE );
animState( ANIMCHANNEL_TORSO, "Torso_Idle", 6 );
}
/***********************************************************************
Legs animation control
***********************************************************************/
void monster_boss_sabaoth::Legs_Idle() {
idleAnim( ANIMCHANNEL_LEGS, "stand" );
eachFrame {
if ( AI_FORWARD ) { animState( ANIMCHANNEL_LEGS, "Legs_Walk", 4 ); }
}
}
void monster_boss_sabaoth::Legs_Walk() {
playCycle( ANIMCHANNEL_LEGS, "move_forward" );
eachFrame {
if ( !AI_FORWARD ) { animState( ANIMCHANNEL_LEGS, "Legs_Idle", 4 ); }
}
}
/***********************************************************************
AI
***********************************************************************/
/*
=====================
monster_boss_sabaoth::init
=====================
*/
void monster_boss_sabaoth::init() {
open_section_2();
open_section_3();
open_section_4();
open_section_5();
open_section_6();
open_section_7();
open_section_8();
// bring center section up
$func_mover_13.move( UP, CENTER_DIST );
movespeed = getFloatKey( "fly_speed" );
setState( "state_Begin" );
}
/***********************************************************************
States
***********************************************************************/
/*
=====================
monster_boss_sabaoth::state_Killed
=====================
*/
void monster_boss_sabaoth::state_Killed() {
stopMove();
animState( ANIMCHANNEL_TORSO, "Torso_Death", 0 );
animState( ANIMCHANNEL_LEGS, "Legs_Death", 0 );
waitAction( "dead" );
setState( "state_Dead" );
}
/*
=====================
monster_boss_sabaoth::state_Begin
=====================
*/
void monster_boss_sabaoth::state_Begin() {
animState( ANIMCHANNEL_TORSO, "Torso_Idle", 0 );
animState( ANIMCHANNEL_LEGS, "Legs_Idle", 0 );
monster_begin();
setMoveType( MOVETYPE_SLIDE );
setState( "state_Idle" );
}
/*
=====================
monster_boss_sabaoth::state_Idle
=====================
*/
void monster_boss_sabaoth::state_Idle() {
wait_for_enemy();
nextAttack = 0;
current_path = randomPath();
setState( "state_Combat" );
}
/*
=====================
monster_boss_sabaoth::move_to_corner
=====================
*/
void monster_boss_sabaoth::move_to_corner( entity path, boolean noslowtostop ) {
float attack_flags;
float dist;
float randomSpeed = sys.random ( 100 ) + 75;
float currentMoveSpeed = movespeed + randomSpeed;
setFlySpeed( currentMoveSpeed );
startSound ("snd_move_start", SND_CHANNEL_BODY, false );
startSound ("snd_move", SND_CHANNEL_BODY2, false );
moveToEntity( path );
while( !AI_MOVE_DONE ) {
dist = distanceTo( path );
if ( dist < SABAOTH_SLOW_DIST ) {
if ( noslowtostop ) {
return;
}
setFlySpeed( currentMoveSpeed * ( dist / SABAOTH_SLOW_DIST ) );
}
if ( AI_ENEMY_VISIBLE ) {
lookAtEnemy( 1 );
}
if ( AI_ENEMY_DEAD ) {
enemy_dead();
}
attack_flags = check_attacks( 0 );
if ( attack_flags ) {
do_attack( attack_flags );
continue;
}
if ( !enemyPositionValid() ) {
locateEnemy();
}
waitFrame();
}
if ( !noslowtostop ) {
setFlySpeed( 0 );
}
startSound ("snd_move_stop", SND_CHANNEL_BODY2, false );
stopMove();
}
/*
=====================
monster_boss_sabaoth::turn_to_corner
=====================
*/
void monster_boss_sabaoth::turn_to_corner( entity path ) {
float attack_flags;
startSound ("snd_move_start", SND_CHANNEL_BODY, false );
startSound ("snd_move", SND_CHANNEL_BODY2, false );
turnToEntity( path );
while( !facingIdeal() ) {
if ( AI_ENEMY_VISIBLE ) {
lookAtEnemy( 1 );
}
if ( AI_ENEMY_DEAD ) {
enemy_dead();
}
attack_flags = check_attacks( 1 );
if ( attack_flags ) {
do_attack( attack_flags );
continue;
}
if ( !enemyPositionValid() ) {
locateEnemy();
}
waitFrame();
}
stopMove();
}
/*
=====================
monster_boss_sabaoth::closeSection
=====================
*/
void monster_boss_sabaoth::closeSection( entity path ) {
string func;
func = path.getKey( "close" );
if ( func != "" ) {
callFunction( func );
}
}
/*
=====================
monster_boss_sabaoth::openSection
=====================
*/
void monster_boss_sabaoth::openSection( entity path ) {
string func;
func = path.getKey( "open" );
if ( func != "" ) {
callFunction( func );
}
}
/*
=====================
monster_boss_sabaoth::state_Combat
=====================
*/
void monster_boss_sabaoth::state_Combat() {
entity next_path;
entity prev_path;
boolean no_turn;
next_path = current_path.randomPath();
no_turn = false;
while( current_path ) {
if ( !no_turn ) {
turn_to_corner( current_path );
} else {
sys.print( "no turn to " + current_path.getName() + "\n" );
}
no_turn = current_path.getIntKey( "no_turn" );
if ( no_turn ) {
sys.print( "no slow to " + current_path.getName() + "\n" );
}
move_to_corner( current_path, no_turn );
openSection( prev_path );
prev_path = current_path;
current_path = next_path;
next_path = current_path.randomPath();
closeSection( next_path );
}
}
/***********************************************************************
attacks
***********************************************************************/
/*
=====================
monster_boss_sabaoth::do_attack
=====================
*/
void monster_boss_sabaoth::do_attack( float attack_flags ) {
if ( attack_flags & ATTACK_MISSILE ) {
combat_range();
} else if ( attack_flags & ATTACK_MELEE ) {
combat_melee();
}
}
/*
=====================
monster_boss_sabaoth::check_attacks
=====================
*/
float monster_boss_sabaoth::check_attacks( float meleeOnly ) {
float attack_flags;
float checkMelee;
attack_flags = 0;
if ( !inAnimState( ANIMCHANNEL_TORSO, "Torso_Idle" ) ) {
return attack_flags;
}
if ( AI_ENEMY_VISIBLE ) {
if ( enemyRange() < MELEE_INIT ) {
attack_flags |= ATTACK_MELEE;
} else if ( !meleeOnly && ( !projectile || ( projectile.getProjectileState() != PROJECTILE_LAUNCHED ) ) && ( !canReachEnemy() || ( sys.getTime() >= nextAttack ) ) ) {
if ( canHitEnemyFromJoint( "mech_bfg" ) ) {
attack_flags |= ATTACK_MISSILE;
}
}
}
return attack_flags;
}
/*
=====================
monster_boss_sabaoth::combat_range
=====================
*/
void monster_boss_sabaoth::combat_range() {
animState( ANIMCHANNEL_TORSO, "Torso_RangeAttack", 4 );
// animation will set the next attack time, so just delay it for a long time for now
nextAttack = sys.getTime() + 10000;
}
/*
=====================
monster_boss_sabaoth::combat_melee
=====================
*/
void monster_boss_sabaoth::combat_melee() {
animState( ANIMCHANNEL_TORSO, "Torso_MeleeAttack", 4 );
}
/*
=====================
monster_boss_sabaoth::fire_bfg
=====================
*/
void monster_boss_sabaoth::fire_bfg() {
projectile = attackMissile( "mech_bfg" );
}
void monster_boss_sabaoth::open_section_1() {
$func_mover_7.move( NORTH, SECTION_MOVE_DIST );
}
void monster_boss_sabaoth::close_section_1() {
$func_mover_7.move( NORTH, -SECTION_MOVE_DIST );
}
void monster_boss_sabaoth::open_section_2() {
$func_mover_8.move( NORTH, SECTION_MOVE_DIST );
$func_mover_9.move( EAST, SECTION_MOVE_DIST );
}
void monster_boss_sabaoth::close_section_2() {
$func_mover_8.move( NORTH, -SECTION_MOVE_DIST );
$func_mover_9.move( EAST, -SECTION_MOVE_DIST );
}
void monster_boss_sabaoth::open_section_3() {
$func_mover_10.move( EAST, SECTION_MOVE_DIST );
}
void monster_boss_sabaoth::close_section_3() {
$func_mover_10.move( EAST, -SECTION_MOVE_DIST );
}
void monster_boss_sabaoth::open_section_4() {
$func_mover_11.move( EAST, SECTION_MOVE_DIST );
$func_mover_12.move( SOUTH, SECTION_MOVE_DIST );
}
void monster_boss_sabaoth::close_section_4() {
$func_mover_11.move( EAST, -SECTION_MOVE_DIST );
$func_mover_12.move( SOUTH, -SECTION_MOVE_DIST );
}
void monster_boss_sabaoth::open_section_5() {
$func_mover_1.move( SOUTH, SECTION_MOVE_DIST );
}
void monster_boss_sabaoth::close_section_5() {
$func_mover_1.move( SOUTH, -SECTION_MOVE_DIST );
}
void monster_boss_sabaoth::open_section_6() {
$func_mover_2.move( SOUTH, SECTION_MOVE_DIST );
$func_mover_3.move( WEST, SECTION_MOVE_DIST );
}
void monster_boss_sabaoth::close_section_6() {
$func_mover_2.move( SOUTH, -SECTION_MOVE_DIST );
$func_mover_3.move( WEST, -SECTION_MOVE_DIST );
}
void monster_boss_sabaoth::open_section_7() {
$func_mover_4.move( WEST, SECTION_MOVE_DIST );
}
void monster_boss_sabaoth::close_section_7() {
$func_mover_4.move( WEST, -SECTION_MOVE_DIST );
}
void monster_boss_sabaoth::open_section_8() {
$func_mover_5.move( WEST, SECTION_MOVE_DIST );
$func_mover_6.move( NORTH, SECTION_MOVE_DIST );
}
void monster_boss_sabaoth::close_section_8() {
$func_mover_5.move( WEST, -SECTION_MOVE_DIST );
$func_mover_6.move( NORTH, -SECTION_MOVE_DIST );
}