284 lines
8.1 KiB
Plaintext
284 lines
8.1 KiB
Plaintext
#include maps\mp\_utility;
|
|
#include maps\mp\gametypes\_hud_util;
|
|
#include common_scripts\utility;
|
|
#include maps\mp\agents\_agent_utility;
|
|
#include maps\mp\gametypes\_damage;
|
|
|
|
//===========================================
|
|
// constants
|
|
//===========================================
|
|
CONST_MAX_ACTIVE_KILLSTREAK_ALIENS_PER_GAME = 3;
|
|
CONST_MAX_ACTIVE_KILLSTREAK_ALIENS_PER_PLAYER = 3;
|
|
CONST_MAX_ACTIVE_KILLSTREAK_AGENTS_PER_PLAYER = 2;
|
|
CONST_ALIEN_HEALTH = 350;
|
|
|
|
//===========================================
|
|
// setup_callbacks
|
|
//===========================================
|
|
setup_callbacks()
|
|
{
|
|
// level.agent_funcs["alien"] = level.agent_funcs["player"];
|
|
|
|
level.agent_funcs["alien"]["spawn"] = ::spawn_alien;
|
|
level.agent_funcs["alien"]["on_killed"] = ::on_agent_alien_killed;
|
|
level.agent_funcs["alien"]["on_damaged"] = maps\mp\agents\_agents::on_agent_generic_damaged;
|
|
level.agent_funcs["alien"]["on_damaged_finished"] = ::on_damaged_finished;
|
|
level.agent_funcs["alien"]["think"] = maps\mp\mp_dome_ns_alien_think::main;
|
|
|
|
}
|
|
|
|
//===========================================
|
|
// useAlienMinion
|
|
//===========================================
|
|
|
|
useAlien( spawn_point, number_of_aliens )
|
|
{
|
|
self endon ( "disconnect");
|
|
self endon ( "joined_team");
|
|
self endon ( "joined_spectators" );
|
|
// self endon ( "death");
|
|
|
|
setup_callbacks();
|
|
|
|
// try to spawn the agent on a path node near the player
|
|
nearestPathNode = self getValidSpawnPathNodeNearPlayer( true );
|
|
if( !IsDefined(nearestPathNode) )
|
|
{
|
|
return false;
|
|
}
|
|
|
|
thread sfx_seeker_quake(spawn_point);
|
|
|
|
for( i = 0; i < number_of_aliens; i++ )
|
|
{
|
|
// find an available agent
|
|
agent = maps\mp\agents\_agent_common::connectNewAgent( "alien" , self.team );
|
|
if( !IsDefined( agent ) )
|
|
{
|
|
return false;
|
|
}
|
|
|
|
// set the agent to the player's team
|
|
agent set_agent_team( self.team, self );
|
|
|
|
if ( i == 0 )
|
|
PathNodeArray = getstructarray ( "seeker_path_01", "script_noteworthy" );
|
|
else if( i == 1 )
|
|
PathNodeArray = getstructarray ( "seeker_path_02", "script_noteworthy" );
|
|
else
|
|
PathNodeArray = getstructarray ( "seeker_path_03", "script_noteworthy" );
|
|
|
|
agent thread spawn_alien ( spawn_point.origin, spawn_point.angles, self, PathNodeArray );
|
|
|
|
// debug aliens do not time out
|
|
if ( getdvarint( "scr_alienDebugMode" ) != 1 )
|
|
{
|
|
agent thread alien_timeout ( 60 );
|
|
}
|
|
|
|
wait .5;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
alien_timeout( duration )
|
|
{
|
|
self endon ( "death" );
|
|
wait duration;
|
|
self maps\mp\mp_dome_ns_alien_think::mp_dome_ns_alien_explode( );
|
|
}
|
|
|
|
|
|
//=======================================================
|
|
// on_agent_alien_killed
|
|
//=======================================================
|
|
on_agent_alien_killed( eInflictor, eAttacker, iDamage, sMeansOfDeath, sWeapon, vDir, sHitLoc, timeOffset, deathAnimDuration )
|
|
{
|
|
self.isActive = false;
|
|
self.hasDied = false;
|
|
|
|
if ( IsDefined( self.animCBs.OnExit[ self.aiState ] ) )
|
|
self [[ self.animCBs.OnExit[ self.aiState ] ]] ();
|
|
|
|
// award XP for killing agents
|
|
if( isPlayer( eAttacker ) && IsDefined(self.owner) && (eAttacker != self.owner) )
|
|
{
|
|
// create an animated corpse for the seeker
|
|
self SetAnimState( "explode", 0, 1 );
|
|
self.body = self CloneAgent( deathAnimDuration );
|
|
|
|
// If the alien was killed by a player, it should explode. Wrap the check in here to prevent it from exploding twice (killed by its own explosion)
|
|
self maps\mp\mp_dome_ns_alien_think::mp_dome_ns_alien_explode( undefined, 150, 128, eAttacker );
|
|
|
|
// self.owner leaderDialogOnPlayer( "dog_killed" );
|
|
self maps\mp\gametypes\_damage::onKillstreakKilled( eAttacker, sWeapon, sMeansOfDeath, iDamage );
|
|
|
|
// clean up the corpse
|
|
wait deathAnimDuration;
|
|
body = self GetCorpseEntity();
|
|
body delete();
|
|
}
|
|
|
|
self maps\mp\agents\_agent_utility::deactivateAgent();
|
|
|
|
|
|
}
|
|
|
|
|
|
on_damaged_finished( eInflictor, eAttacker, iDamage, iDFlags, sMeansOfDeath, sWeapon, vPoint, vDir, sHitLoc, timeOffset )
|
|
{
|
|
if( !IsDefined( self.playing_pain_sound ) )
|
|
self thread play_pain_sound( 2.5 );
|
|
|
|
// damage needs to be modified depending on the weapon and hit location because the head is really easy to hit when the alien is running at you
|
|
// assuming 1.4 modifier for head shots
|
|
damageModified = iDamage;
|
|
if( IsDefined( sHitLoc ) && sHitLoc == "head" && level.gametype != "horde" )
|
|
{
|
|
damageModified = int( damageModified * 0.6 );
|
|
if ( iDamage > 0 && damageModified <= 0 )
|
|
damageModified = 1;
|
|
}
|
|
|
|
if ( self.health - damageModified > 0 )
|
|
{
|
|
self maps\mp\mp_dome_ns_alien_think::OnDamage( eInflictor, eAttacker, damageModified, iDFlags, sMeansOfDeath, sWeapon, vPoint, vDir, sHitLoc, timeOffset );
|
|
}
|
|
|
|
// attack the player that has damaged them
|
|
if( IsPlayer( eAttacker ) )
|
|
{
|
|
// is the alien already attacking?
|
|
if ( IsDefined( self.attackState ) && self.attackState != "attacking" )
|
|
{
|
|
// is the attacker within the alien damaged range?
|
|
if( DistanceSquared( self.origin, eAttacker.origin ) <= self.dogDamagedRadiusSq )
|
|
{
|
|
self.favoriteEnemy = eAttacker;
|
|
self.forceAttack = true;
|
|
self thread maps\mp\mp_dome_ns_alien_think::watchFavoriteEnemyDeath();
|
|
}
|
|
}
|
|
}
|
|
|
|
maps\mp\agents\_agents::agent_damage_finished( eInflictor, eAttacker, damageModified, iDFlags, sMeansOfDeath, sWeapon, vPoint, vDir, sHitLoc, timeOffset );
|
|
}
|
|
|
|
play_pain_sound( delay ) // self == alien
|
|
{
|
|
self endon( "death" );
|
|
|
|
//self PlaySound( "anml_dog_shot_pain" );
|
|
self.playing_pain_sound = true;
|
|
wait( delay );
|
|
self.playing_pain_sound = undefined;
|
|
}
|
|
|
|
spawn_alien( optional_spawnOrigin, optional_spawnAngles, optional_owner, PathNodeArray ) // self == agent
|
|
{
|
|
self SetModel( "alien_minion" );
|
|
|
|
// creating VFX that 'follow' the alien
|
|
self thread mp_dome_ns_alien_glow();
|
|
self thread mp_dome_ns_alien_vfx();
|
|
self.species = "alien";
|
|
|
|
self.OnEnterAnimState = maps\mp\mp_dome_ns_alien_think::OnEnterAnimState;
|
|
|
|
spawnOrigin = optional_spawnOrigin;
|
|
spawnAngles = optional_spawnAngles;
|
|
// allow killstreaks to pass in specific spawn locations
|
|
if( IsDefined(optional_spawnOrigin) && IsDefined(optional_spawnAngles) )
|
|
{
|
|
spawnOrigin = optional_spawnOrigin;
|
|
spawnAngles = optional_spawnAngles;
|
|
}
|
|
else
|
|
{
|
|
spawnPoint = self [[level.getSpawnPoint]]();
|
|
spawnOrigin = spawnpoint.origin;
|
|
spawnAngles = spawnpoint.angles;
|
|
}
|
|
self activateAgent();
|
|
self.spawnTime = GetTime();
|
|
self.lastSpawnTime = GetTime();
|
|
|
|
self maps\mp\mp_dome_ns_alien_think::init();
|
|
|
|
// called from code when an agent is done initializing after AddAgent is called
|
|
// this should set up any state specific to this agent and game
|
|
|
|
self SpawnAgent( spawnOrigin, spawnAngles, "mp_dome_ns_alien_animclass", 15, 40, optional_owner );
|
|
level notify( "spawned_agent", self );
|
|
|
|
self maps\mp\agents\_agent_common::set_agent_health( CONST_ALIEN_HEALTH );
|
|
|
|
// must set the team after SpawnAgent to fix a bug with weapon crosshairs and nametags
|
|
if( IsDefined(optional_owner) )
|
|
{
|
|
self set_agent_team( optional_owner.team, optional_owner );
|
|
}
|
|
|
|
self SetThreatBiasGroup( "Dogs" );
|
|
self TakeAllWeapons();
|
|
|
|
self playsound( "alien_seeker_spawn" );
|
|
playfx (level._effect[ "vfx_alien_minion_spawn_dome" ], self.origin );
|
|
|
|
self.PathNodeArray = PathNodeArray;
|
|
|
|
self thread maps\mp\mp_dome_ns_alien_think::main();
|
|
}
|
|
|
|
mp_dome_ns_alien_glow()
|
|
{
|
|
wait 2.0;
|
|
// make aliens glow
|
|
self EmissiveBlend( 0.5, 1.0 );
|
|
}
|
|
|
|
mp_dome_alien_light(vfx_offset)
|
|
{
|
|
self endon( "death" );
|
|
level endon( "game_ended" );
|
|
|
|
// we loop this separately because the light lasts for 1 second,
|
|
// and we were spawning too many of them and they were stacking 4-5 light at a time... booo.
|
|
|
|
while (1)
|
|
{
|
|
playfx (level._effect[ "vfx_alien_minion_preexplosion" ], self.origin + vfx_offset);
|
|
wait 1.0;
|
|
}
|
|
}
|
|
|
|
mp_dome_ns_alien_vfx()
|
|
{
|
|
self endon( "death" );
|
|
level endon( "game_ended" );
|
|
|
|
vfx_offset = (0,0,16);
|
|
|
|
self thread mp_dome_alien_light(vfx_offset);
|
|
|
|
//while (IsAlive (self))
|
|
while (1)
|
|
{
|
|
// this is the particle effect, not the light.
|
|
playfx (level._effect[ "vfx_alien_minion_glow_trail_noloop" ], self.origin + vfx_offset);
|
|
wait RandomFloatRange(0.05,0.2);
|
|
}
|
|
}
|
|
|
|
sfx_seeker_quake(spawn_point)
|
|
{
|
|
if (!IsDefined( level.rumble_sfx ))
|
|
{
|
|
level.rumble_sfx = Spawn( "script_origin", spawn_point.origin );
|
|
level.rumble_sfx PlaySound("alien_seeker_quake");
|
|
wait 6.5;
|
|
level.rumble_sfx delete();
|
|
}
|
|
}
|