mirror of
https://github.com/id-Software/DOOM-3-BFG.git
synced 2025-03-15 23:21:35 +00:00
814 lines
16 KiB
Text
814 lines
16 KiB
Text
/***********************************************************************
|
|
|
|
ai_monster_boss_maledict.script
|
|
|
|
monster_boss_maledict
|
|
|
|
***********************************************************************/
|
|
|
|
#define MALEDICT_ATTACK_RATE 2.5
|
|
|
|
#define MALEDICT_FLAME_WALL_NUM 24
|
|
#define MALEDICT_FLAME_WALL_SEPERATION 64
|
|
|
|
#define MALEDICT_SWOOP_HORIZ 0
|
|
#define MALEDICT_SWOOP_VERT 1
|
|
|
|
// anim blend times
|
|
#define MALEDICT_BLEND_FRAMES 0
|
|
|
|
#define MALEDICT_COMBAT_STAGE1 0
|
|
#define MALEDICT_COMBAT_STAGE2 1
|
|
|
|
object monster_boss_maledict : monster_base {
|
|
float nextAttack;
|
|
float attackCount;
|
|
|
|
float currentPt;
|
|
float swoopDir;
|
|
|
|
boolean damageSkin;
|
|
float damageHealth;
|
|
|
|
float combatStage;
|
|
float stageCounter;
|
|
float currentDamageCap;
|
|
|
|
float numForgottens;
|
|
boolean previousAttackForgottens;
|
|
|
|
//
|
|
// Initialize
|
|
//
|
|
void init();
|
|
//
|
|
// States
|
|
//
|
|
void state_Begin();
|
|
void state_Idle();
|
|
|
|
void state_Intro();
|
|
void state_Down();
|
|
void state_Swoop();
|
|
void state_Combat();
|
|
void state_Perch();
|
|
void state_FakeDeath();
|
|
|
|
// attacks
|
|
float check_attacks();
|
|
void do_attack( float attack_flags );
|
|
|
|
void combat_range();
|
|
void combat_forgotten();
|
|
|
|
void forgotten_spawn();
|
|
void forgotten_killed();
|
|
|
|
void move_to_position( float newPt );
|
|
|
|
void spawn_flame_wall( vector org );
|
|
vector flame_wall_start_pos( float dir );
|
|
void flame_wall_sound_end( entity sEnt );
|
|
void flame_wall_loop();
|
|
void flame_wall();
|
|
|
|
void asteroid_loop();
|
|
void asteroid_attack();
|
|
|
|
// torso anim states
|
|
void Torso_Idle();
|
|
|
|
void Torso_RangeAttack();
|
|
void Torso_ForgottenAttack();
|
|
void Torso_SwoopAttack();
|
|
void Torso_PerchAttack();
|
|
};
|
|
|
|
/***********************************************************************
|
|
|
|
Torso animation control
|
|
|
|
***********************************************************************/
|
|
|
|
void monster_boss_maledict::Torso_Idle() {
|
|
idleAnim( ANIMCHANNEL_LEGS, "idle" );
|
|
}
|
|
|
|
/*
|
|
===========================
|
|
Attacks
|
|
===========================
|
|
*/
|
|
|
|
void monster_boss_maledict::Torso_RangeAttack() {
|
|
|
|
playAnim( ANIMCHANNEL_LEGS, "attack_a" );
|
|
while( !animDone( ANIMCHANNEL_LEGS, MALEDICT_BLEND_FRAMES ) ) {
|
|
// Check for transition to damaged skin
|
|
if ( !damageSkin && getHealth() < damageHealth ) {
|
|
setSkin( "skins/models/monsters/maledict_burning_nohead" );
|
|
damageSkin = true;
|
|
}
|
|
|
|
lookAt( getEnemy(), 1 );
|
|
waitFrame();
|
|
}
|
|
|
|
finishAction( "range_attack" );
|
|
animState( ANIMCHANNEL_LEGS, "Torso_Idle", MALEDICT_BLEND_FRAMES );
|
|
}
|
|
|
|
void monster_boss_maledict::Torso_ForgottenAttack() {
|
|
vector clearAngles;
|
|
|
|
lookAt( self, 0 );
|
|
|
|
clearAngles_x = 0;
|
|
clearAngles_y = 0;
|
|
clearAngles_z = 0;
|
|
setAngles( clearAngles );
|
|
|
|
playAnim( ANIMCHANNEL_LEGS, "forgotten" );
|
|
while( !animDone( ANIMCHANNEL_LEGS, MALEDICT_BLEND_FRAMES ) ) {
|
|
// Check for transition to damaged skin
|
|
if ( !damageSkin && getHealth() < damageHealth ) {
|
|
setSkin( "skins/models/monsters/maledict_burning_nohead" );
|
|
damageSkin = true;
|
|
}
|
|
|
|
waitFrame();
|
|
}
|
|
|
|
finishAction( "forgotten_attack" );
|
|
animState( ANIMCHANNEL_LEGS, "Torso_Idle", MALEDICT_BLEND_FRAMES );
|
|
}
|
|
|
|
void monster_boss_maledict::Torso_SwoopAttack() {
|
|
vector clearAngles;
|
|
vector spot;
|
|
vector playerOrg;
|
|
vector newPos;
|
|
float startTime;
|
|
|
|
lookAt( self, 0 );
|
|
|
|
clearAngles_x = 0;
|
|
clearAngles_y = 0;
|
|
clearAngles_z = 0;
|
|
setAngles( clearAngles );
|
|
|
|
playerOrg = $player1.getOrigin();
|
|
|
|
if ( swoopDir == MALEDICT_SWOOP_HORIZ ) {
|
|
spot = $spot_A.getOrigin();
|
|
newPos = spot;
|
|
newPos_y = playerOrg_y;
|
|
|
|
playAnim( ANIMCHANNEL_LEGS, "swoop_horiz" );
|
|
} else if ( swoopDir == MALEDICT_SWOOP_VERT ) {
|
|
spot = $spot_C.getOrigin();
|
|
newPos = spot;
|
|
newPos_x = playerOrg_x;
|
|
|
|
playAnim( ANIMCHANNEL_LEGS, "swoop_vert" );
|
|
} else {
|
|
spot = $spot_C.getOrigin();
|
|
newPos = spot;
|
|
playAnim( ANIMCHANNEL_LEGS, "charge" );
|
|
}
|
|
|
|
setOrigin( newPos );
|
|
|
|
startTime = sys.getTime();
|
|
|
|
while( !animDone( ANIMCHANNEL_LEGS, MALEDICT_BLEND_FRAMES ) ) {
|
|
// Check for transition to damaged skin
|
|
if ( !damageSkin && getHealth() < damageHealth ) {
|
|
setSkin( "skins/models/monsters/maledict_burning_nohead" );
|
|
damageSkin = true;
|
|
}
|
|
|
|
// Update maledict position
|
|
if ( sys.getTime() < ( startTime + 1.7 ) ) {
|
|
playerOrg = $player1.getOrigin();
|
|
|
|
if ( swoopDir == MALEDICT_SWOOP_HORIZ ) {
|
|
newPos_y = playerOrg_y;
|
|
} else if ( swoopDir == MALEDICT_SWOOP_VERT ) {
|
|
newPos_x = playerOrg_x;
|
|
}
|
|
setOrigin( newPos );
|
|
}
|
|
|
|
waitFrame();
|
|
}
|
|
|
|
finishAction( "swoop_attack" );
|
|
animState( ANIMCHANNEL_LEGS, "Torso_Idle", MALEDICT_BLEND_FRAMES );
|
|
}
|
|
|
|
|
|
void monster_boss_maledict::Torso_PerchAttack() {
|
|
vector clearAngles;
|
|
|
|
lookAt( self, 0 );
|
|
|
|
clearAngles_x = 0;
|
|
clearAngles_y = 0;
|
|
clearAngles_z = 0;
|
|
setAngles( clearAngles );
|
|
|
|
playAnim( ANIMCHANNEL_LEGS, "perch" );
|
|
while( !animDone( ANIMCHANNEL_LEGS, MALEDICT_BLEND_FRAMES ) ) {
|
|
waitFrame();
|
|
}
|
|
|
|
finishAction( "perch_attack" );
|
|
animState( ANIMCHANNEL_LEGS, "Torso_Idle", MALEDICT_BLEND_FRAMES );
|
|
}
|
|
|
|
/***********************************************************************
|
|
|
|
AI
|
|
|
|
***********************************************************************/
|
|
|
|
/*
|
|
=====================
|
|
monster_boss_maledict::init
|
|
=====================
|
|
*/
|
|
void monster_boss_maledict::init() {
|
|
|
|
attackCount = 0;
|
|
currentPt = 0;
|
|
swoopDir = MALEDICT_SWOOP_HORIZ;
|
|
|
|
damageSkin = false;
|
|
damageHealth = getHealth() / 4;
|
|
|
|
combatStage = MALEDICT_COMBAT_STAGE1;
|
|
|
|
currentDamageCap = damageHealth + 100;
|
|
setDamageCap( currentDamageCap );
|
|
|
|
stageCounter = 0;
|
|
numForgottens = 0;
|
|
previousAttackForgottens = false;
|
|
|
|
setState( "state_Begin" );
|
|
}
|
|
|
|
/***********************************************************************
|
|
|
|
States
|
|
|
|
***********************************************************************/
|
|
|
|
/*
|
|
=====================
|
|
monster_boss_maledict::state_Begin
|
|
=====================
|
|
*/
|
|
void monster_boss_maledict::state_Begin() {
|
|
animState( ANIMCHANNEL_LEGS, "Torso_Idle", MALEDICT_BLEND_FRAMES );
|
|
monster_begin();
|
|
|
|
setMoveType( MOVETYPE_ANIM );
|
|
setState( "state_Idle" );
|
|
}
|
|
|
|
/*
|
|
=====================
|
|
monster_boss_maledict::state_Idle
|
|
=====================
|
|
*/
|
|
void monster_boss_maledict::state_Idle() {
|
|
wait_for_enemy();
|
|
|
|
nextAttack = DelayTime( MALEDICT_ATTACK_RATE );
|
|
|
|
setState( "state_Intro" );
|
|
}
|
|
|
|
/*
|
|
=====================
|
|
monster_boss_maledict::state_Intro
|
|
=====================
|
|
*/
|
|
void monster_boss_maledict::state_Intro() {
|
|
|
|
move_to_position( 0 );
|
|
swoopDir = -1;
|
|
|
|
animState( ANIMCHANNEL_LEGS, "Torso_SwoopAttack", MALEDICT_BLEND_FRAMES );
|
|
waitAction( "swoop_attack" );
|
|
|
|
swoopDir = 0;
|
|
setState( "state_Down" );
|
|
}
|
|
|
|
/*
|
|
=====================
|
|
monster_boss_maledict::state_Down
|
|
=====================
|
|
*/
|
|
void monster_boss_maledict::state_Down() {
|
|
|
|
animState( ANIMCHANNEL_LEGS, "Torso_Idle", MALEDICT_BLEND_FRAMES );
|
|
|
|
hide();
|
|
|
|
// Check for Death
|
|
if ( combatStage == MALEDICT_COMBAT_STAGE2 && getHealth() <= 2 ) {
|
|
setState( "state_FakeDeath" );
|
|
}
|
|
|
|
// Update Battle stage
|
|
if ( damageSkin && combatStage == MALEDICT_COMBAT_STAGE1 ) {
|
|
combatStage = MALEDICT_COMBAT_STAGE2;
|
|
|
|
stageCounter = 0;
|
|
currentDamageCap = 100;
|
|
setDamageCap( currentDamageCap );
|
|
setHealth( 3000 );
|
|
}
|
|
|
|
// Update Damage Cap
|
|
if ( currentDamageCap > 1 ) {
|
|
|
|
if ( stageCounter > 2 ) {
|
|
|
|
if ( combatStage == MALEDICT_COMBAT_STAGE1 ) {
|
|
currentDamageCap = 1;
|
|
} else {
|
|
currentDamageCap = 1;
|
|
}
|
|
setDamageCap( currentDamageCap );
|
|
}
|
|
}
|
|
stageCounter++;
|
|
|
|
if ( combatStage == MALEDICT_COMBAT_STAGE2 ) {
|
|
// Choose attack type
|
|
if ( attackCount > 0 ) {
|
|
|
|
attackCount = 0;
|
|
sys.wait( 1 );
|
|
setState( "state_Swoop" );
|
|
} else {
|
|
sys.wait( 1 );
|
|
setState( "state_Perch" );
|
|
}
|
|
} else {
|
|
// Choose attack type
|
|
if ( attackCount >= 2 ) {
|
|
|
|
attackCount = 0;
|
|
sys.wait( 1.5 );
|
|
setState( "state_Swoop" );
|
|
} else {
|
|
sys.wait( 1.5 );
|
|
setState( "state_Combat" );
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
=====================
|
|
monster_boss_maledict::state_Combat
|
|
=====================
|
|
*/
|
|
void monster_boss_maledict::state_Combat() {
|
|
float attack_flags;
|
|
float bestPt;
|
|
|
|
// Choose best attack position
|
|
bestPt = sys.randomInt(5) + 1;
|
|
move_to_position( bestPt );
|
|
|
|
show();
|
|
|
|
eachFrame {
|
|
faceEnemy();
|
|
|
|
if ( AI_ENEMY_IN_FOV ) {
|
|
lookAtEnemy( 1 );
|
|
}
|
|
|
|
if ( sys.influenceActive() ) {
|
|
continue;
|
|
}
|
|
|
|
if ( AI_ENEMY_DEAD ) {
|
|
enemy_dead();
|
|
}
|
|
|
|
// Do attacks!
|
|
attack_flags = check_attacks();
|
|
if ( attack_flags ) {
|
|
do_attack( attack_flags );
|
|
setState( "state_Down" );
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
=====================
|
|
monster_boss_maledict::state_Swoop
|
|
=====================
|
|
*/
|
|
void monster_boss_maledict::state_Swoop() {
|
|
float bestPt;
|
|
|
|
previousAttackForgottens = false;
|
|
show();
|
|
|
|
eachFrame {
|
|
if ( sys.influenceActive() ) {
|
|
continue;
|
|
}
|
|
|
|
if ( AI_ENEMY_DEAD ) {
|
|
enemy_dead();
|
|
}
|
|
|
|
animState( ANIMCHANNEL_LEGS, "Torso_SwoopAttack", MALEDICT_BLEND_FRAMES );
|
|
waitAction( "swoop_attack" );
|
|
|
|
if ( swoopDir == MALEDICT_SWOOP_HORIZ ) {
|
|
swoopDir = MALEDICT_SWOOP_VERT;
|
|
} else {
|
|
swoopDir = MALEDICT_SWOOP_HORIZ;
|
|
}
|
|
|
|
setState( "state_Down" );
|
|
}
|
|
}
|
|
|
|
/*
|
|
=====================
|
|
monster_boss_maledict::state_Perch
|
|
=====================
|
|
*/
|
|
void monster_boss_maledict::state_Perch() {
|
|
float bestPt;
|
|
|
|
show();
|
|
|
|
eachFrame {
|
|
if ( sys.influenceActive() ) {
|
|
continue;
|
|
}
|
|
|
|
if ( AI_ENEMY_DEAD ) {
|
|
enemy_dead();
|
|
}
|
|
|
|
// The perch always starts from spot C
|
|
move_to_position( 0 );
|
|
|
|
animState( ANIMCHANNEL_LEGS, "Torso_PerchAttack", MALEDICT_BLEND_FRAMES );
|
|
waitAction( "perch_attack" );
|
|
|
|
attackCount++;
|
|
|
|
setState( "state_Down" );
|
|
}
|
|
}
|
|
|
|
/*
|
|
=====================
|
|
monster_boss_maledict::state_FakeDeath
|
|
=====================
|
|
*/
|
|
void monster_boss_maledict::state_FakeDeath() {
|
|
animState( ANIMCHANNEL_LEGS, "Torso_Idle", MALEDICT_BLEND_FRAMES );
|
|
|
|
kill();
|
|
}
|
|
|
|
/***********************************************************************
|
|
|
|
attacks
|
|
|
|
***********************************************************************/
|
|
|
|
/*
|
|
=====================
|
|
monster_boss_maledict::do_attack
|
|
=====================
|
|
*/
|
|
void monster_boss_maledict::do_attack( float attack_flags ) {
|
|
if ( attack_flags & ATTACK_SPECIAL1 ) {
|
|
combat_forgotten();
|
|
} else if ( attack_flags & ATTACK_MISSILE ) {
|
|
combat_range();
|
|
}
|
|
}
|
|
|
|
/*
|
|
=====================
|
|
monster_boss_maledict::check_attacks
|
|
=====================
|
|
*/
|
|
float monster_boss_maledict::check_attacks() {
|
|
float currentTime;
|
|
float attack_flags;
|
|
|
|
attack_flags = 0;
|
|
currentTime = sys.getTime();
|
|
|
|
// Attack!
|
|
if ( !previousAttackForgottens && numForgottens <= 0 ) {
|
|
attack_flags |= ATTACK_SPECIAL1;
|
|
|
|
} else if ( currentTime >= nextAttack ) {
|
|
attack_flags |= ATTACK_MISSILE;
|
|
}
|
|
|
|
return attack_flags;
|
|
}
|
|
|
|
/*
|
|
=====================
|
|
monster_boss_maledict::combat_range
|
|
=====================
|
|
*/
|
|
void monster_boss_maledict::combat_range() {
|
|
|
|
previousAttackForgottens = false;
|
|
|
|
faceEnemy();
|
|
animState( ANIMCHANNEL_LEGS, "Torso_RangeAttack", MALEDICT_BLEND_FRAMES );
|
|
waitAction( "range_attack" );
|
|
|
|
attackCount++;
|
|
|
|
// don't attack for a bit
|
|
nextAttack = DelayTime( MALEDICT_ATTACK_RATE );
|
|
}
|
|
|
|
/*
|
|
=====================
|
|
monster_boss_maledict::combat_forgotten
|
|
=====================
|
|
*/
|
|
void monster_boss_maledict::combat_forgotten() {
|
|
|
|
previousAttackForgottens = true;
|
|
move_to_position( 0 );
|
|
|
|
animState( ANIMCHANNEL_LEGS, "Torso_ForgottenAttack", MALEDICT_BLEND_FRAMES );
|
|
waitAction( "forgotten_attack" );
|
|
|
|
// don't attack for a bit
|
|
nextAttack = DelayTime( MALEDICT_ATTACK_RATE );
|
|
}
|
|
|
|
/*
|
|
=====================
|
|
monster_boss_maledict::forgotten_spawn
|
|
=====================
|
|
*/
|
|
void monster_boss_maledict::forgotten_spawn() {
|
|
entity ent;
|
|
entity spot;
|
|
|
|
sys.setSpawnArg( "teleport", "1" );
|
|
sys.setSpawnArg( "target", "forgotten_dead" );
|
|
ent = sys.spawn( "monster_flying_forgotten" );
|
|
ent.setKey( "cinematic_remove", "1" ); // make sure it gets removed in cinematics
|
|
|
|
if ( numForgottens < 2 ) {
|
|
spot = $spot_forgotten1;
|
|
} else {
|
|
spot = $spot_forgotten2;
|
|
}
|
|
|
|
ent.setOrigin( spot.getOrigin() );
|
|
ent.setAngles( spot.getAngles() );
|
|
|
|
sys.trigger( ent );
|
|
|
|
numForgottens++;
|
|
}
|
|
|
|
/*
|
|
=====================
|
|
monster_boss_maledict::forgotten_killed
|
|
=====================
|
|
*/
|
|
void monster_boss_maledict::forgotten_killed() {
|
|
numForgottens--;
|
|
}
|
|
|
|
/*
|
|
=====================
|
|
monster_boss_maledict::move_to_position
|
|
=====================
|
|
*/
|
|
void monster_boss_maledict::move_to_position( float newPt ) {
|
|
entity spot;
|
|
|
|
if ( newPt == 0 ) {
|
|
spot = $spot_C;
|
|
} else if ( newPt == 1 ) {
|
|
spot = $spot_A;
|
|
} else if ( newPt == 2 ) {
|
|
spot = $spot_B;
|
|
} else if ( newPt == 3 ) {
|
|
spot = $spot_D;
|
|
} else if ( newPt == 4 ) {
|
|
spot = $spot_E;
|
|
} else if ( newPt == 5 ) {
|
|
spot = $spot_F;
|
|
}
|
|
|
|
currentPt = newPt;
|
|
|
|
setOrigin( spot.getOrigin() );
|
|
setAngles( spot.getAngles() );
|
|
}
|
|
|
|
/*
|
|
=====================
|
|
monster_boss_maledict::spawn_flame_wall
|
|
=====================
|
|
*/
|
|
void monster_boss_maledict::spawn_flame_wall( vector org ) {
|
|
entity ent;
|
|
vector ang;
|
|
float flameNum;
|
|
string flameEntName;
|
|
|
|
flameNum = sys.randomInt(3) + 1;
|
|
flameEntName = "maledict_flamewall" + flameNum;
|
|
|
|
ang_y = sys.random( 360 );
|
|
ent = sys.spawn( flameEntName );
|
|
ent.setKey( "cinematic_remove", "1" ); // make sure it gets removed in cinematics
|
|
ent.setShaderParm( 4, -sys.getTime() );
|
|
ent.setShaderParm( 5, sys.random( 1 ) );
|
|
ent.setOrigin( org );
|
|
ent.setAngles( ang );
|
|
ent.setOwner( self );
|
|
ent.disable();
|
|
sys.wait( 0.2 );
|
|
ent.enable();
|
|
sys.wait( 0.8 );
|
|
ent.disable();
|
|
sys.wait( 1.8 );
|
|
ent.remove();
|
|
}
|
|
|
|
/*
|
|
=====================
|
|
monster_boss_maledict::flame_wall_start_pos
|
|
=====================
|
|
*/
|
|
vector monster_boss_maledict::flame_wall_start_pos( float dir ) {
|
|
float i;
|
|
float frac;
|
|
vector finalPos;
|
|
vector startPos;
|
|
vector pos;
|
|
vector offset;
|
|
|
|
if ( swoopDir == MALEDICT_SWOOP_HORIZ ) {
|
|
offset = '-64 0 0';
|
|
} else {
|
|
offset = '0 64 0';
|
|
}
|
|
|
|
startPos = $player1.getOrigin();
|
|
pos = startPos + offset;
|
|
|
|
finalPos = pos;
|
|
|
|
for( i = 0; i < MALEDICT_FLAME_WALL_NUM; i++ ) {
|
|
pos_z += 128;
|
|
if ( sys.trace( pos, pos + offset, '-8 -8 0', '8 8 16', MASK_SOLID, self ) < 1 ) {
|
|
break;
|
|
}
|
|
pos = pos + offset;
|
|
frac = sys.trace( pos, pos - '0 0 256', '-8 -8 0', '8 8 16', MASK_SOLID, self );
|
|
if ( frac == 1 ) {
|
|
break;
|
|
}
|
|
pos_z -= 256 * frac;
|
|
|
|
finalPos = pos;
|
|
}
|
|
|
|
return finalPos;
|
|
}
|
|
|
|
/*
|
|
=====================
|
|
monster_boss_maledict::flame_wall_sound_end
|
|
=====================
|
|
*/
|
|
void monster_boss_maledict::flame_wall_sound_end( entity sEnt ) {
|
|
|
|
sys.wait( 1 );
|
|
sEnt.fadeSound( SND_CHANNEL_ANY, -60, 2 );
|
|
sys.wait( 2 );
|
|
sEnt.Off();
|
|
sEnt.remove();
|
|
}
|
|
|
|
/*
|
|
=====================
|
|
monster_boss_maledict::flame_wall_loop
|
|
=====================
|
|
*/
|
|
void monster_boss_maledict::flame_wall_loop() {
|
|
float i;
|
|
vector dir;
|
|
vector ang;
|
|
vector pos;
|
|
float frac;
|
|
entity soundEnt;
|
|
|
|
if ( swoopDir == MALEDICT_SWOOP_HORIZ ) {
|
|
pos = flame_wall_start_pos( swoopDir );
|
|
ang = '0 0 0';
|
|
} else if ( swoopDir == MALEDICT_SWOOP_VERT ) {
|
|
pos = flame_wall_start_pos( swoopDir );
|
|
ang = '0 270 0';
|
|
} else {
|
|
pos = $flamewall_intro.getOrigin();
|
|
ang = $flamewall_intro.getAngles();
|
|
}
|
|
|
|
dir = sys.angToForward( ang ) * MALEDICT_FLAME_WALL_SEPERATION;
|
|
|
|
sys.wait( 0.5 );
|
|
|
|
soundEnt = sys.spawn( "maledict_flamewall_sound" );
|
|
soundEnt.On();
|
|
|
|
for( i = 0; i < MALEDICT_FLAME_WALL_NUM; i++ ) {
|
|
pos_z += 256;
|
|
if ( sys.trace( pos, pos + dir, '-8 -8 0', '8 8 16', MASK_SOLID, self ) < 1 ) {
|
|
break;
|
|
}
|
|
pos = pos + dir;
|
|
frac = sys.trace( pos, pos - '0 0 512', '-8 -8 0', '8 8 16', MASK_SOLID, self );
|
|
if ( frac == 1 ) {
|
|
break;
|
|
}
|
|
pos_z -= 512 * frac;
|
|
pos_z += 2;
|
|
|
|
soundEnt.setOrigin( pos );
|
|
|
|
thread spawn_flame_wall( pos );
|
|
sys.wait( 0.075 );
|
|
}
|
|
|
|
thread flame_wall_sound_end( soundEnt );
|
|
}
|
|
|
|
/*
|
|
=====================
|
|
monster_boss_maledict::flame_wall
|
|
=====================
|
|
*/
|
|
void monster_boss_maledict::flame_wall() {
|
|
thread flame_wall_loop();
|
|
}
|
|
|
|
/*
|
|
=====================
|
|
monster_boss_maledict::asteroid_loop
|
|
=====================
|
|
*/
|
|
void monster_boss_maledict::asteroid_loop() {
|
|
float i;
|
|
float delay;
|
|
string fxName;
|
|
entity fxEnt;
|
|
|
|
for( i = 1; i < 15; i++ ) {
|
|
fxName = "nrv_func_fx_" + i;
|
|
fxEnt = sys.getEntity( fxName );
|
|
|
|
sys.trigger( fxEnt );
|
|
|
|
delay = 0.5 + sys.random( 0.3 );
|
|
//delay = 0.10 + sys.random( 0.3 );
|
|
sys.wait( delay );
|
|
}
|
|
}
|
|
|
|
/*
|
|
=====================
|
|
monster_boss_maledict::asteroid_attack
|
|
=====================
|
|
*/
|
|
void monster_boss_maledict::asteroid_attack() {
|
|
thread asteroid_loop();
|
|
}
|
|
|