IW4-Dump-Files/animscripts/death.gsc

957 lines
25 KiB
Plaintext

#include common_scripts\utility;
#include animscripts\utility;
#include animscripts\combat_utility;
#include maps\_utility;
#using_animtree( "generic_human" );
//
// Damage Yaw
//
// front
// /----|----\
// / 180 \
// /\ | /\
// / -135 | 135 \
// | \ | / |
// left|-90----+----90-|right
// | / | \ |
// \ -45 | 45 /
// \/ | \/
// \ 0 /
// \----|----/
// back
main()
{
self endon( "killanimscript" );
// make sure the guy doesn't talk after death
self stopsoundchannel( "voice" );
changeTime = 0.3;
self clearanim( %scripted_talking, changeTime );
// don't abort at this point unless you're going to play another animation!
// just playing ragdoll isn't sufficient because sometimes ragdoll fails, and then
// you'll just have a corpse standing around in limbo.
if ( self.a.nodeath == true )
return;
if ( isdefined( self.deathFunction ) )
{
result = self [[ self.deathFunction ]]();
if ( !isdefined( result ) )
result = true;
if ( result )
return;
}
animscripts\utility::initialize( "death" );
// should move this to squad manager somewhere...
removeSelfFrom_SquadLastSeenEnemyPos( self.origin );
anim.numDeathsUntilCrawlingPain -- ;
anim.numDeathsUntilCornerGrenadeDeath -- ;
if ( isDefined( self.ragdoll_immediate ) || self.forceRagdollImmediate )
{
self doImmediateRagdollDeath();
// ragdoll can fail so don't assume that we can quit the function
}
if ( isDefined( self.deathanim ) )
{
playDeathAnim( self.deathAnim );
// Added so that I can do special stuff in Level scripts on an ai
if ( isdefined( self.deathanimscript ) )
self [[ self.deathanimscript ]]();
return;
}
explosiveDamage = self animscripts\pain::wasDamagedByExplosive();
if ( self.damageLocation == "helmet" || self.damageLocation == "head" )
self helmetPop();
else if ( explosiveDamage && randomint( 3 ) == 0 )
self helmetPop();
self clearanim( %root, 0.3 );
if ( !damageLocationIsAny( "head", "helmet" ) )
{
if ( self.dieQuietly )
{
// replace with actual die quietly gurglesque sound
// if ( randomint(3) < 2 )
// self animscripts\face::SayGenericDialogue("pain");
}
else
{
PlayDeathSound();
}
}
if ( explosiveDamage && playExplodeDeathAnim() )
return;
// different from deathFunction above, doesn't skip explosion deaths, immediate ragdoll, sounds, etc
if ( isdefined( self.specialDeathFunc ) )
{
if ( [[ self.specialDeathFunc ]]() )
return;
}
// TODO: replace these with the above specialDeathFunc
if ( specialDeath() )
return;
deathAnim = getDeathAnim();
/#
if ( getdvarint( "scr_paindebug" ) == 1 )
println( "^2Playing pain: ", deathAnim, " ; pose is ", self.a.pose );
#/
playDeathAnim( deathAnim );
}
doImmediateRagdollDeath()
{
self animscripts\shared::DropAllAIWeapons();
self.skipDeathAnim = true; // this helps playDeathAnim() do failsafes for ragdoll failures later
initialImpulse = 10;
damageType = common_scripts\_destructible::getDamageType( self.damageMod );
if( IsDefined( self.attacker ) && self.attacker == level.player && damageType == "melee" )
{
initialImpulse = 5;
}
damageTaken = self.damagetaken;
if ( damageType == "bullet" )
damageTaken = max( damageTaken, 300 );
directionScale = initialImpulse * damageTaken;
directionUp = max( 0.3, self.damagedir[ 2 ] );
direction = ( self.damagedir[ 0 ], self.damagedir[ 1 ], directionUp );
direction *= directionScale;
if ( self.forceRagdollImmediate )
direction += self.prevAnimDelta * 20 * 10; // 20 frames/sec
self startragdollfromimpact( self.damagelocation, direction );
// wait a bit so that the ragdoll can start before the death script tries to play a regular
// death animation as a failsafe - if ragdolling, the regular death anim won't do anything when called
wait( 0.05 );
}
playDeathAnim( deathAnim )
{
if ( !animHasNoteTrack( deathAnim, "dropgun" ) && !animHasNoteTrack( deathAnim, "fire_spray" ) )// && !animHasNotetrack( deathAnim, "gun keep" )
self animscripts\shared::DropAllAIWeapons();
//if ( isdefined( self.faceDamageDir ) )
// self orientmode( "face angle", self.damageYaw );
self setFlaggedAnimKnobAllRestart( "deathanim", deathAnim, %body, 1, .1 );
if ( IsDefined( self.skipDeathAnim ) )
{
ASSERTEX( self.skipDeathAnim, "self.skipDeathAnim must be either true or undefined." );
if( !isdefined( self.noragdoll ) )
self startRagDoll();
wait( 0.05 );
// failsafe in case ragdoll fails: he'll still be playing a deathanim,
// but at least he'll fall to the ground
self AnimMode( "gravity" );
}
else if ( !animHasNotetrack( deathanim, "start_ragdoll" ) )
{
self thread waitForRagdoll( getanimlength( deathanim ) * 0.35 );
}
// do we really need this anymore?
/#
if ( getdebugdvar( "debug_grenadehand" ) == "on" )
{
if ( animhasnotetrack( deathAnim, "bodyfall large" ) )
return;
if ( animhasnotetrack( deathAnim, "bodyfall small" ) )
return;
println( "Death animation ", deathAnim, " does not have a bodyfall notetrack" );
iprintlnbold( "Death animation needs fixing (check console and report bug in the animation to Boon)" );
}
#/
// SRS 11/20/08: blood pools don't always line up with ragdoll corpses, so skip them if
// we did ragdoll without a death anim (which usually sends the body farther away from the death spot)
if ( !IsDefined( self.skipDeathAnim ) )
{
self thread playDeathFX();
}
self animscripts\shared::DoNoteTracks( "deathanim" );
self animscripts\shared::DropAllAIWeapons();
}
waitForRagdoll( time )
{
wait( time );
if ( isdefined( self ) )
self animscripts\shared::DropAllAIWeapons();
if ( isdefined( self ) && !isdefined( self.noragdoll ) )
self startragdoll();
}
playDeathFX()
{
self endon( "killanimscript" );
//iprintlnbold("bleed'n");
if ( self.stairsState != "none" )
return;
wait 2;
play_blood_pool();
}
play_blood_pool( note, flagName )
{
if ( !isdefined( self ) )
return;
if ( isdefined( self.skipBloodPool ) )
{
assertex( self.skipBloodPool, "Setting must be either true or undefined" );
return;
}
tagPos = self gettagorigin( "j_SpineUpper" ); // rough tag to play fx on
tagAngles = self gettagangles( "j_SpineUpper" );
forward = anglestoforward( tagAngles );
up = anglestoup( tagAngles );
right = anglestoright( tagAngles );
tagPos = tagPos + vector_multiply( forward, -8.5 ) + vector_multiply( up, 5 ) + vector_multiply( right, 0 );
trace = bulletTrace( tagPos + ( 0, 0, 30 ), tagPos - ( 0, 0, 100 ), false, undefined );
if ( trace[ "normal" ][2] > 0.9 )
playfx( level._effect[ "deathfx_bloodpool_generic" ], tagPos );
}
// TODO: replace these with specialDeathFunc
// Special death is for corners, rambo behavior, mg42's, anything out of the ordinary stand, crouch and prone.
// It returns true if it handles the death for the special animation state, or false if it wants the regular
// death function to handle it.
specialDeath()
{
if ( self.a.special == "none" )
return false;
switch( self.a.special )
{
case "cover_right":
if ( self.a.pose == "stand" )
{
deathArray = [];
deathArray[ 0 ] = %corner_standr_deathA;
deathArray[ 1 ] = %corner_standr_deathB;
DoDeathFromArray( deathArray );
}
else
{
deathArray = [];
if ( damageLocationIsAny( "head", "neck" ) )
{
deathArray[ 0 ] = %CornerCrR_alert_death_slideout;
}
else
{
deathArray[ 0 ] = %CornerCrR_alert_death_slideout;
deathArray[ 1 ] = %CornerCrR_alert_death_back;
}
DoDeathFromArray( deathArray );
}
return true;
case "cover_left":
if ( self.a.pose == "stand" )
{
deathArray = [];
deathArray[ 0 ] = %corner_standl_deathA;
deathArray[ 1 ] = %corner_standl_deathB;
DoDeathFromArray( deathArray );
}
else
{
deathArray = [];
deathArray[ 0 ] = %CornerCrL_death_side;
deathArray[ 1 ] = %CornerCrL_death_back;
DoDeathFromArray( deathArray );
}
return true;
case "cover_stand":
deathArray = [];
deathArray[ 0 ] = %coverstand_death_left;
deathArray[ 1 ] = %coverstand_death_right;
DoDeathFromArray( deathArray );
return true;
case "cover_crouch":
deathArray = [];
if ( damageLocationIsAny( "head", "neck" ) && ( self.damageyaw > 135 || self.damageyaw <= -45 ) ) // Front / Left quadrant
deathArray[ deathArray.size ] = %covercrouch_death_1;
if ( ( self.damageyaw > - 45 ) && ( self.damageyaw <= 45 ) ) // Back quadrant
deathArray[ deathArray.size ] = %covercrouch_death_3;
deathArray[ deathArray.size ] = %covercrouch_death_2;
DoDeathFromArray( deathArray );
return true;
case "saw":
if ( self.a.pose == "stand" )
DoDeathFromArray( array( %saw_gunner_death ) );
else if ( self.a.pose == "crouch" )
DoDeathFromArray( array( %saw_gunner_lowwall_death ) );
else
DoDeathFromArray( array( %saw_gunner_prone_death ) );
return true;
case "dying_crawl":
if ( isdefined( self.a.onback ) && self.a.pose == "crouch" )
{
deathArray = array( %dying_back_death_v2, %dying_back_death_v3, %dying_back_death_v4 );
DoDeathFromArray( deathArray );
}
else
{
assertex( self.a.pose == "prone", self.a.pose );
deathArray = array( %dying_crawl_death_v1, %dying_crawl_death_v2 );
DoDeathFromArray( deathArray );
}
return true;
}
return false;
}
DoDeathFromArray( deathArray )
{
deathAnim = deathArray[ randomint( deathArray.size ) ];
playDeathAnim( deathAnim );
//nate - adding my own special death flag on top of special death.
if ( isdefined( self.deathanimscript ) )
self [[ self.deathanimscript ]]();
}
PlayDeathSound()
{
// if (self.team == "allies")
// self playsound("allied_death");
// else
// self playsound("german_death");
self animscripts\face::SayGenericDialogue( "death" );
}
print3dfortime( place, text, time )
{
numframes = time * 20;
for ( i = 0; i < numframes; i++ )
{
print3d( place, text );
wait .05;
}
}
helmetPop()
{
if ( !isdefined( self ) )
return;
if ( !isdefined( self.hatModel ) )
return;
// used to check self removableHat() in cod2... probably not necessary though
partName = GetPartName( self.hatModel, 0 );
model = spawn( "script_model", self.origin + ( 0, 0, 64 ) );
model setmodel( self.hatModel );
model.origin = self GetTagOrigin( partName );// self . origin + ( 0, 0, 64 );
model.angles = self GetTagAngles( partName );// ( -90, 0 + randomint( 90 ), 0 + randomint( 90 ) );
model thread helmetLaunch( self.damageDir );
hatModel = self.hatModel;
self.hatModel = undefined;
wait 0.05;
if ( !isdefined( self ) )
return;
self detach( hatModel, "" );
}
helmetLaunch( damageDir )
{
launchForce = damageDir;
launchForce = launchForce * randomFloatRange( 2000, 4000 );
forcex = launchForce[ 0 ];
forcey = launchForce[ 1 ];
forcez = randomFloatRange( 1500, 3000 );
contactPoint = self.origin + ( randomfloatrange( -1, 1 ), randomfloatrange( -1, 1 ), randomfloatrange( -1, 1 ) ) * 5;
self PhysicsLaunchClient( contactPoint, ( forcex, forcey, forcez ) );
wait 60;
while ( 1 )
{
if ( !isdefined( self ) )
return;
if ( distanceSquared( self.origin, level.player.origin ) > 512 * 512 )
break;
wait 30;
}
self delete();
}
removeSelfFrom_SquadLastSeenEnemyPos( org )
{
for ( i = 0;i < anim.squadIndex.size;i++ )
anim.squadIndex[ i ] clearSightPosNear( org );
}
clearSightPosNear( org )
{
if ( !isdefined( self.sightPos ) )
return;
if ( distance( org, self.sightPos ) < 80 )
{
self.sightPos = undefined;
self.sightTime = gettime();
}
}
shouldDoRunningForwardDeath()
{
if ( self.a.movement != "run" )
return false;
if ( self getMotionAngle() > 60 || self getMotionAngle() < - 60 )
return false;
/*
if ( ( self.damageyaw >= 120 ) || ( self.damageyaw <= -120 ) )// Front quadrant
return true;
if ( ( self.damageyaw >= -45 ) && ( self.damageyaw <= 45 ) )// Back quadrant
return true;
return false;
*/
return true;
}
shouldDoStrongBulletDamage( damageWeapon, damageMod, damagetaken, attacker )
{
ASSERT( IsDefined( damageWeapon ) );
if ( isdefined( self.a.doingLongDeath ) )
{
return false;
}
if ( self.a.pose == "prone" || isdefined( self.a.onback ) )
{
return false;
}
if( damageWeapon == "none" )
{
return false;
}
if ( damagetaken > 500 )
{
return true;
}
if( damageMod == "MOD_MELEE" )
{
return false;
}
// if I'm running, and the attacker is far enough away, sometimes let me do
// a running death instead. this helps minimize repetition of strong damage animations
// when a line of dudes is running towards you and you're mowing them down, etc.
if( self.a.movement == "run" && !isAttackerWithinDist( attacker, 275 ) )
{
if( RandomInt( 100 ) < 65 )
{
return false;
}
}
if ( isSniperRifle( damageWeapon ) && self.maxHealth < damageTaken )
{
return true;
}
if( isShotgun( damageWeapon ) && isAttackerWithinDist( attacker, 512 ) )
{
return true;
}
if( isDesertEagle( damageWeapon ) && isAttackerWithinDist( attacker, 425 ) )
{
return true;
}
return false;
}
isDesertEagle( damageWeapon )
{
if( damageWeapon == "deserteagle" )
{
return true;
}
return false;
}
isAttackerWithinDist( attacker, maxDist )
{
if( !IsDefined( attacker ) )
{
return false;
}
if( Distance( self.origin, attacker.origin ) > maxDist )
{
return false;
}
return true;
}
getDeathAnim()
{
if ( shouldDoStrongBulletDamage( self.damageWeapon, self.damageMod, self.damagetaken, self.attacker ) )
{
deathAnim = getStrongBulletDamageDeathAnim();
if ( IsDefined( deathAnim ) )
{
return deathAnim;
}
}
if ( isdefined( self.a.onback ) )
{
if ( self.a.pose == "crouch" )
return getBackDeathAnim();
else
animscripts\shared::stopOnBack();
}
if ( self.a.pose == "stand" )
{
if ( shouldDoRunningForwardDeath() )
{
return getRunningForwardDeathAnim();
}
else
{
return getStandDeathAnim();
}
}
else if ( self.a.pose == "crouch" )
{
return getCrouchDeathAnim();
}
else if ( self.a.pose == "prone" )
{
return getProneDeathAnim();
}
}
// may return undefined
// large death animation for shotguns, snipers etc.
getStrongBulletDamageDeathAnim()
{
damageYaw = abs( self.damageYaw );
if ( damageYaw < 45 )
return;
if ( damageYaw > 150 )
{
if ( damageLocationIsAny( "left_leg_upper", "left_leg_lower", "right_leg_upper", "right_leg_lower", "left_foot", "right_foot" ) )
{
deathArray = array( %death_shotgun_legs, %death_stand_sniper_leg );
}
else
{
deathArray = [];
if ( self.damageLocation == "torso_lower" )
{
deathArray[ deathArray.size ] = %death_shotgun_legs;
deathArray[ deathArray.size ] = %death_stand_sniper_leg;
}
deathArray[ deathArray.size ] = %death_shotgun_back_v1;
deathArray[ deathArray.size ] = %exposed_death_blowback;
deathArray[ deathArray.size ] = %death_stand_sniper_chest1;
deathArray[ deathArray.size ] = %death_stand_sniper_chest2;
deathArray[ deathArray.size ] = %death_stand_sniper_spin1;
}
//self.faceDamageDir = true;
}
else if ( self.damageYaw < 0 )
{
deathArray = array( %death_shotgun_spinL, %death_stand_sniper_spin1, %death_stand_sniper_chest1, %death_stand_sniper_chest2 );
}
else
{
deathArray = array( %death_shotgun_spinR, %death_stand_sniper_spin2, %death_stand_sniper_chest1, %death_stand_sniper_chest2 );
}
return deathArray[ randomint( deathArray.size ) ];
}
getRunningForwardDeathAnim()
{
deathArray = [];
deathArray[ deathArray.size ] = tryAddDeathAnim( %run_death_facedown );
deathArray[ deathArray.size ] = tryAddDeathAnim( %run_death_roll );
deathArray[ deathArray.size ] = tryAddDeathAnim( %run_death_fallonback );
deathArray[ deathArray.size ] = tryAddDeathAnim( %run_death_flop );
deathArray = animscripts\pain::removeBlockedAnims( deathArray );
if ( !deathArray.size )
return getStandDeathAnim();
return deathArray[ randomint( deathArray.size ) ];
}
// remove undefined entries from array
removeUndefined( array )
{
newArray = [];
for ( index = 0; index < array.size; index++ )
{
if ( !isDefined( array[ index ] ) )
continue;
newArray[ newArray.size ] = array[ index ];
}
return newArray;
}
getStandPistolDeathAnim()
{
deathArray = [];
if ( abs( self.damageYaw ) < 50 )
{
deathArray[ deathArray.size ] = %pistol_death_2;// falls forwards
}
else
{
if ( abs( self.damageYaw ) < 110 )
deathArray[ deathArray.size ] = %pistol_death_2;// falls forwards
if ( damageLocationIsAny( "torso_lower", "torso_upper", "left_leg_upper", "left_leg_lower", "right_leg_upper", "right_leg_lower" ) )
{
deathArray[ deathArray.size ] = %pistol_death_3;// hit in groin from front
if ( !damageLocationIsAny( "torso_upper" ) )
deathArray[ deathArray.size ] = %pistol_death_3;// ( twice as likely )
}
if ( !damageLocationIsAny( "head", "neck", "helmet", "left_foot", "right_foot", "left_hand", "right_hand", "gun" ) && randomint( 2 ) == 0 )
deathArray[ deathArray.size ] = %pistol_death_4;// hit at top and falls backwards, but more dragged out
if ( deathArray.size == 0 || damageLocationIsAny( "torso_lower", "torso_upper", "neck", "head", "helmet", "right_arm_upper", "left_arm_upper" ) )
deathArray[ deathArray.size ] = %pistol_death_1;// falls backwards
}
return deathArray;
}
getStandDeathAnim()
{
deathArray = [];
extendedDeathArray = [];
if ( usingSidearm() )
{
deathArray = getStandPistolDeathAnim();
}
else
{
// torso or legs
if ( damageLocationIsAny( "torso_lower", "left_leg_upper", "left_leg_lower", "right_leg_lower", "right_leg_lower" ) )
{
deathArray[ deathArray.size ] = tryAddDeathAnim( %exposed_death_groin );
deathArray[ deathArray.size ] = tryAddDeathAnim( %stand_death_leg );
extendedDeathArray[ extendedDeathArray.size ] = tryAddDeathAnim( %stand_death_crotch );
extendedDeathArray[ extendedDeathArray.size ] = tryAddDeathAnim( %stand_death_guts );
}
if ( damageLocationIsAny( "head", "helmet" ) )
{
deathArray[ deathArray.size ] = tryAddDeathAnim( %exposed_death_headshot );
deathArray[ deathArray.size ] = tryAddDeathAnim( %exposed_death_flop );
}
if ( damageLocationIsAny( "neck" ) )
{
deathArray[ deathArray.size ] = tryAddDeathAnim( %exposed_death_neckgrab );
}
if ( damageLocationIsAny( "torso_upper", "left_arm_upper" ) )
{
deathArray[ deathArray.size ] = tryAddDeathAnim( %exposed_death_twist );
deathArray[ deathArray.size ] = tryAddDeathAnim( %stand_death_shoulder_spin );
deathArray[ deathArray.size ] = tryAddDeathAnim( %stand_death_shoulderback );
}
if ( damageLocationIsAny( "torso_upper" ) )
{
deathArray[ deathArray.size ] = tryAddDeathAnim( %stand_death_tumbleforward );
deathArray[ deathArray.size ] = tryAddDeathAnim( %stand_death_stumbleforward );
extendedDeathArray[ extendedDeathArray.size ] = tryAddDeathAnim( %stand_death_fallside );
}
// quadrants
if ( ( self.damageyaw > 135 ) || ( self.damageyaw <= -135 ) )// Front quadrant
{
if ( damageLocationIsAny( "neck", "head", "helmet" ) )
{
deathArray[ deathArray.size ] = tryAddDeathAnim( %stand_death_face );
deathArray[ deathArray.size ] = tryAddDeathAnim( %stand_death_headshot_slowfall );
extendedDeathArray[ extendedDeathArray.size ] = tryAddDeathAnim( %stand_death_head_straight_back );
}
if ( damageLocationIsAny( "torso_upper" ) )
{
deathArray[ deathArray.size ] = tryAddDeathAnim( %stand_death_tumbleback );
extendedDeathArray[ extendedDeathArray.size ] = tryAddDeathAnim( %stand_death_chest_stunned );
}
}
//else if ( ( self.damageyaw > 45 ) && ( self.damageyaw <= 135 ) )// Right quadrant
//{
//}
else if ( ( self.damageyaw > -45 ) && ( self.damageyaw <= 45 ) )// Back quadrant
{
deathArray[ deathArray.size ] = tryAddDeathAnim( %exposed_death_falltoknees );
deathArray[ deathArray.size ] = tryAddDeathAnim( %exposed_death_falltoknees_02 );
}
//else// Left quadrant
//{
//}
foundLocDamageDeath = ( deathArray.size > 0 );
if ( !foundLocDamageDeath || RandomInt( 100 ) < 15 )
{
deathArray[ deathArray.size ] = tryAddDeathAnim( %exposed_death_02 );
deathArray[ deathArray.size ] = tryAddDeathAnim( %exposed_death_nerve );
}
if ( RandomInt( 100 ) < 10 && firingDeathAllowed() )
{
deathArray[ deathArray.size ] = tryAddFiringDeathAnim( %exposed_death_firing_02 );
deathArray[ deathArray.size ] = tryAddFiringDeathAnim( %exposed_death_firing );
deathArray = removeUndefined( deathArray );
}
}
assertex( deathArray.size > 0, deathArray.size );
if ( deathArray.size == 0 )
deathArray[ deathArray.size ] = %exposed_death;
if ( !self.a.disableLongDeath && self.stairsState == "none" && !isdefined( self.a.painOnStairs ) )
{
index = randomint( deathArray.size + extendedDeathArray.size );
if ( index < deathArray.size )
return deathArray[ index ];
else
return extendedDeathArray[ index - deathArray.size ];
}
assertex( deathArray.size > 0, deathArray.size );
return deathArray[ randomint( deathArray.size ) ];
}
getCrouchDeathAnim()
{
deathArray = [];
if ( damageLocationIsAny( "head", "neck" ) ) // Front / Left quadrant
deathArray[ deathArray.size ] = tryAddDeathAnim( %exposed_crouch_death_fetal );
if ( damageLocationIsAny( "torso_upper", "torso_lower", "left_arm_upper", "right_arm_upper", "neck" ) )
deathArray[ deathArray.size ] = tryAddDeathAnim( %exposed_crouch_death_flip );
if ( deathArray.size < 2 )
deathArray[ deathArray.size ] = tryAddDeathAnim( %exposed_crouch_death_twist );
if ( deathArray.size < 2 )
deathArray[ deathArray.size ] = tryAddDeathAnim( %exposed_crouch_death_flip );
assertex( deathArray.size > 0, deathArray.size );
return deathArray[ randomint( deathArray.size ) ];
}
getProneDeathAnim()
{
if ( isdefined( self.a.proneAiming ) )
return %prone_death_quickdeath;
else
return %dying_crawl_death_v1;
}
getBackDeathAnim()
{
deathArray = array( %dying_back_death_v1, %dying_back_death_v2, %dying_back_death_v3, %dying_back_death_v4 );
return deathArray[ randomint( deathArray.size ) ];
}
firingDeathAllowed()
{
if ( !isdefined( self.weapon ) || !usingRifleLikeWeapon() || !weaponIsAuto( self.weapon ) || self.dieQuietly )
return false;
if ( self.a.weaponPos[ "right" ] == "none" )
return false;
return true;
}
tryAddDeathAnim( animName )
{
assert( !animHasNoteTrack( animName, "fire" ) && !animHasNoteTrack( animName, "fire_spray" ) );
return animName;
}
tryAddFiringDeathAnim( animName )
{
assert( animHasNoteTrack( animName, "fire" ) || animHasNoteTrack( animName, "fire_spray" ) );
return animName;
}
playExplodeDeathAnim()
{
if ( isdefined( self.juggernaut ) )
return false;
if ( self.damageLocation != "none" )
return false;
deathArray = [];
if ( self.a.movement != "run" )
{
if ( ( self.damageyaw > 135 ) || ( self.damageyaw <= -135 ) ) // Front quadrant
{
deathArray[ deathArray.size ] = tryAddDeathAnim( %death_explosion_stand_B_v1 );
deathArray[ deathArray.size ] = tryAddDeathAnim( %death_explosion_stand_B_v2 );
deathArray[ deathArray.size ] = tryAddDeathAnim( %death_explosion_stand_B_v3 );
deathArray[ deathArray.size ] = tryAddDeathAnim( %death_explosion_stand_B_v4 );
}
else if ( ( self.damageyaw > 45 ) && ( self.damageyaw <= 135 ) ) // Right quadrant
{
deathArray[ deathArray.size ] = tryAddDeathAnim( %death_explosion_stand_L_v1 );
deathArray[ deathArray.size ] = tryAddDeathAnim( %death_explosion_stand_L_v2 );
deathArray[ deathArray.size ] = tryAddDeathAnim( %death_explosion_stand_L_v3 );
}
else if ( ( self.damageyaw > - 45 ) && ( self.damageyaw <= 45 ) ) // Back quadrant
{
deathArray[ deathArray.size ] = tryAddDeathAnim( %death_explosion_stand_F_v1 );
deathArray[ deathArray.size ] = tryAddDeathAnim( %death_explosion_stand_F_v2 );
deathArray[ deathArray.size ] = tryAddDeathAnim( %death_explosion_stand_F_v3 );
deathArray[ deathArray.size ] = tryAddDeathAnim( %death_explosion_stand_F_v4 );
}
else
{ // Left quadrant
deathArray[ deathArray.size ] = tryAddDeathAnim( %death_explosion_stand_R_v1 );
deathArray[ deathArray.size ] = tryAddDeathAnim( %death_explosion_stand_R_v2 );
}
}
else
{
if ( ( self.damageyaw > 135 ) || ( self.damageyaw <= -135 ) ) // Front quadrant
{
deathArray[ deathArray.size ] = tryAddDeathAnim( %death_explosion_run_B_v1 );
deathArray[ deathArray.size ] = tryAddDeathAnim( %death_explosion_run_B_v2 );
}
else if ( ( self.damageyaw > 45 ) && ( self.damageyaw <= 135 ) ) // Right quadrant
{
deathArray[ deathArray.size ] = tryAddDeathAnim( %death_explosion_run_L_v1 );
deathArray[ deathArray.size ] = tryAddDeathAnim( %death_explosion_run_L_v2 );
}
else if ( ( self.damageyaw > - 45 ) && ( self.damageyaw <= 45 ) ) // Back quadrant
{
deathArray[ deathArray.size ] = tryAddDeathAnim( %death_explosion_run_F_v1 );
deathArray[ deathArray.size ] = tryAddDeathAnim( %death_explosion_run_F_v2 );
deathArray[ deathArray.size ] = tryAddDeathAnim( %death_explosion_run_F_v3 );
deathArray[ deathArray.size ] = tryAddDeathAnim( %death_explosion_run_F_v4 );
}
else
{ // Left quadrant
deathArray[ deathArray.size ] = tryAddDeathAnim( %death_explosion_run_R_v1 );
deathArray[ deathArray.size ] = tryAddDeathAnim( %death_explosion_run_R_v2 );
}
}
deathAnim = deathArray[ randomint( deathArray.size ) ];
if ( getdvar( "scr_expDeathMayMoveCheck", "on" ) == "on" )
{
localDeltaVector = getMoveDelta( deathAnim, 0, 1 );
endPoint = self localToWorldCoords( localDeltaVector );
if ( !self mayMoveToPoint( endPoint, false ) )
return false;
}
// this should really be in the notetracks
self animMode( "nogravity" );
playDeathAnim( deathAnim );
return true;
}