aboutsummaryrefslogtreecommitdiff
path: root/Northstar.CustomServers/scripts/vscripts/ai/_ai_suicide_spectres.gnut
diff options
context:
space:
mode:
Diffstat (limited to 'Northstar.CustomServers/scripts/vscripts/ai/_ai_suicide_spectres.gnut')
-rw-r--r--Northstar.CustomServers/scripts/vscripts/ai/_ai_suicide_spectres.gnut576
1 files changed, 0 insertions, 576 deletions
diff --git a/Northstar.CustomServers/scripts/vscripts/ai/_ai_suicide_spectres.gnut b/Northstar.CustomServers/scripts/vscripts/ai/_ai_suicide_spectres.gnut
deleted file mode 100644
index f8e0652ce..000000000
--- a/Northstar.CustomServers/scripts/vscripts/ai/_ai_suicide_spectres.gnut
+++ /dev/null
@@ -1,576 +0,0 @@
-global function SuicideSpectres_Init
-global function MakeSuicideSpectre
-global function SpectreSuicideOnDamaged
-global function GetNPCAttackerEnt
-
-const FX_SPECTRE_EXPLOSION = $"P_drone_frag_exp"
-
-//
-// Suicide spectre script
-//
-
-const SPECTRE_EXPLOSION_DELAY = 0.25 // Delay for the first spectre in a chain to start exploding.
-const SPECTRE_DAMAGE_MULTIPLIER_BODY = 1.5
-const SPECTRE_DAMAGE_MULTIPLIER_HEAD = 6.0
-const SPECTRE_DAMAGE_MULTIPLIER_SMART_PISTOL = 2.0
-const SPECTRE_HEADSHOT_KEEP_WALKING_CHANCE = 100 // 35% chance to keep walking after a headshot to add variety
-
-struct
-{
- int chainExplosionIndex
- float lastChainExplosionTime
-
- table< string, array<string> > spectreAnims
- float nextOverloadTime
-
-} file
-
-const SFX_TICK_OVERLOAD = "corporate_spectre_overload_beep"
-const SFX_TICK_EXPLODE = "corporate_spectre_death_explode"
-
-const SFX_FRAGDRONE_OVERLOAD = "weapon_sentryfragdrone_preexplo"
-const SFX_FRAGDRONE_EXPLODE = "weapon_sentryfragdrone_explo"
-const SFX_FRAGDRONE_SUPERPURSUIT = "weapon_sentryfragdrone_superpursuit"
-
-const CHAIN_EXPLOSION_MAXINDEX = 10
-
-
-void function SuicideSpectres_Init()
-{
- RegisterSignal( "SuicideSpectreForceExplode" )
- RegisterSignal( "SuicideSpectreExploding" )
- RegisterSignal( "SuicideGotEnemy" )
- RegisterSignal( "SuicideLostEnemy" )
-
- PrecacheParticleSystem( FX_SPECTRE_EXPLOSION )
-
- file.spectreAnims[ "spectreSearch" ] <- []
- file.spectreAnims[ "spectreSearch" ].append( "sp_suicide_spectre_search" )
- file.spectreAnims[ "spectreSearch" ].append( "sp_suicide_spectre_search_B" )
- file.spectreAnims[ "spectreSearch" ].append( "sp_suicide_spectre_search_C" )
-
- AddDamageCallback( "npc_frag_drone", SpectreSuicideOnDamaged_Callback )
- AddDeathCallback( "npc_frag_drone", FragDroneDeath )
-}
-
-/************************************************************************************************\
-
- ###### ######## ######## ## ## ########
-## ## ## ## ## ## ## ##
-## ## ## ## ## ## ##
- ###### ###### ## ## ## ########
- ## ## ## ## ## ##
-## ## ## ## ## ## ##
- ###### ######## ## ####### ##
-
-\************************************************************************************************/
-void function MakeSuicideSpectre( entity spectre )
-{
- spectre.SetAimAssistAllowed( true )
- spectre.SetAllowMelee( false )
- DisableLeeching( spectre )
-
- spectre.SetNPCMoveSpeedScale( 1.0 )
-
- spectre.EnableNPCMoveFlag( NPCMF_IGNORE_CLUSTER_DANGER_TIME | NPCMF_PREFER_SPRINT )
- spectre.DisableNPCMoveFlag( NPCMF_FOLLOW_SAFE_PATHS | NPCMF_INDOOR_ACTIVITY_OVERRIDE )
-
- spectre.kv.allowShoot = 0
-
- // Frag drones do suicide spectre behavior but we don't want them doing the enemy changed sounds so filter them out
- if ( !IsFragDrone( spectre ) && !IsTick( spectre ) )
- spectre.SetEnemyChangeCallback( SuicideSpectreEnemyChanged )
-
- spectre.SetLookDistOverride( SPECTRE_MAX_SIGHT_DIST )
- //spectre.SetHearingSensitivity( 10 ) //1 is default
- spectre.EnableNPCFlag( NPC_MUTE_TEAMMATE )
-
- spectre.ai.suicideSpectreExplosionDelay = -1
-
- thread SpectreWaitToExplode( spectre )
- AddAnimEvent( spectre, "frag_drone_armed", FragDroneArmed )
-}
-
-void function FragDroneArmed( entity npc )
-{
- npc.ai.fragDroneArmed = true
-}
-
-void function FragDroneDeath( entity spectre, var damageInfo )
-{
- FragDroneDeath_Think( spectre, damageInfo )
-}
-
-// for reloadscripts
-void function FragDroneDeath_Think( entity spectre, var damageInfo )
-{
- vector pos = spectre.GetOrigin()
- int tagID = spectre.LookupAttachment( "CHESTFOCUS" )
- vector fxOrg = spectre.GetAttachmentOrigin( tagID )
- string expSFX
- if ( spectre.mySpawnOptions_aiSettings == "npc_frag_drone_throwable" )
- expSFX = SFX_FRAGDRONE_EXPLODE
- else
- expSFX = SFX_TICK_EXPLODE
- int expFX = GetParticleSystemIndex( FX_SPECTRE_EXPLOSION )
-
- entity attacker = DamageInfo_GetAttacker( damageInfo )
- entity attackerEnt = GetNPCAttackerEnt( spectre, attacker )
-
- int team = GetExplosionTeamBasedOnGamemode( spectre )
-
- int damageDef = GetDamageDefForFragDrone( spectre )
-
- RadiusDamage_DamageDefSimple( damageDef, pos, attackerEnt, spectre, 0 )
- EmitSoundAtPosition( spectre.GetTeam(), pos, expSFX )
- CreateShake( pos, 10, 105, 1.25, 768 )
- StartParticleEffectInWorld( expFX, fxOrg, Vector( 0, 0, 0 ) )
-
- spectre.Gib( <0, 0, 100> ) //Used to do .Destroy() on the frag drones immediately, but this meant you can't display the obiturary correctly. Instead, since it's dead already just hide it
-}
-
-entity function GetNPCAttackerEnt( entity npc, entity attacker )
-{
- entity owner = npc.GetBossPlayer()
- bool ownerIsPlayer = owner != null && owner.IsPlayer()
-
- if ( IsMultiplayer() )
- return ownerIsPlayer ? owner : npc
-
- if ( !IsAlive( attacker ) )
- return npc
-
- // dont give player credit, since that does some bad things
- if ( ownerIsPlayer )
- return owner
-
- if ( attacker.IsPlayer() )
- return GetEnt( "worldspawn" )
-
- return attacker
-}
-
-
-int function GetDamageDefForFragDrone( entity drone )
-{
- var damageDef = drone.Dev_GetAISettingByKeyField( "damageDefOverride" )
- if ( damageDef != null )
- {
- expect string( damageDef )
- return eDamageSourceId[ damageDef ]
- }
-
- entity owner = drone.GetBossPlayer()
- if ( owner != null && owner.IsPlayer() )
- return damagedef_frag_drone_throwable_PLAYER
-
- return damagedef_frag_drone_throwable_NPC
-}
-
-void function SuicideSpectreEnemyChanged( entity spectre )
-{
- // Spectre "Speaks"
- if ( ( RandomFloat( 1.0 ) ) < 0.02 )
- EmitSoundOnEntity( spectre, "diag_imc_spectre_gs_spotenemypilot_01_1" )
-}
-
-/************************************************************************************************\
-
-######## ######## ####### ## ## #### ## ## #### ######## ## ##
-## ## ## ## ## ## ## ## ## ### ### ## ## ## ##
-## ## ## ## ## ## ## ## ## #### #### ## ## ####
-######## ######## ## ## ### ## ## ### ## ## ## ##
-## ## ## ## ## ## ## ## ## ## ## ## ##
-## ## ## ## ## ## ## ## ## ## ## ## ##
-## ## ## ####### ## ## #### ## ## #### ## ##
-
-\************************************************************************************************/
-void function SpectreWaitToExplode( entity spectre )
-{
- Assert( spectre.IsNPC() )
- spectre.EndSignal( "OnDeath" )
-
- waitthread SuicideSpectre_WaittillNearEnemyOrExploding( spectre )
-
- if ( spectre.ai.suicideSpectreExplodingAttacker == null )
- {
- // not exploding, so overload
- spectre.ai.suicideSpectreExplosionDelay = GetSpectreExplosionTime( spectre )
- waitthread SpectreOverloads( spectre )
- }
-
- if ( spectre.ai.suicideSpectreExplosionDelay > 0 )
- wait spectre.ai.suicideSpectreExplosionDelay
-
- entity attacker = spectre.ai.suicideSpectreExplodingAttacker
- if ( !IsValid( attacker ) )
- {
- entity lastAttacker = GetLastAttacker( spectre )
- if ( IsValid( lastAttacker ) )
- {
- attacker = lastAttacker
- }
- else
- {
- attacker = spectre
- }
- }
-
- vector force = GetDeathForce()
-
- Assert( !attacker.IsProjectile(), "Suicide Spectre attacker was a projectile! Type: " + attacker.ProjectileGetWeaponClassName() )
-
- // JFS: sometimes the attacker is a projectile, which can cause a script error.
- // The real solution is to figure out which weapon is passing in the projectile as the attacker and correct that.
- if ( attacker.IsProjectile() )
- {
- attacker = spectre
- }
-
- spectre.Die( attacker, attacker, { force = force, scriptType = DF_DOOMED_HEALTH_LOSS, damageSourceId = eDamageSourceId.suicideSpectreAoE } )
-}
-
-void function SetSuicideSpectreExploding( entity spectre, entity attacker, float explodingTime )
-{
- Assert( spectre.ai.suicideSpectreExplodingAttacker == null )
- spectre.ai.suicideSpectreExplodingAttacker = attacker
- spectre.ai.suicideSpectreExplosionDelay = explodingTime
-
- spectre.Signal( "SuicideSpectreExploding" )
-}
-
-float function GetSpectreExplosionTime( entity spectre )
-{
- if ( Time() - file.lastChainExplosionTime > 1.0 )
- file.chainExplosionIndex = 0
-
- float waitTime = file.chainExplosionIndex * 0.14 // RandomFloatRange( CHAIN_EXPLOSION_INTERVALMIN, CHAIN_EXPLOSION_INTERVALMAX )
- file.lastChainExplosionTime = Time()
- file.chainExplosionIndex++
- return waitTime
-}
-
-void function SuicideSpectre_WaittillNearEnemyOrExploding( entity spectre )
-{
- spectre.EndSignal( "OnDeath" )
- spectre.EndSignal( "SuicideSpectreExploding" )
- spectre.EndSignal( "SuicideSpectreForceExplode" )
-
- bool pursuitSoundPlaying = false
-
- float minScale = expect float( spectre.Dev_GetAISettingByKeyField( "minSpeedScale" ) )
- float maxScale = expect float( spectre.Dev_GetAISettingByKeyField( "maxSpeedScale" ) )
-
- while ( true )
- {
- wait 0.1
-
- if ( !spectre.ai.fragDroneArmed )
- continue
-
- if ( spectre.ai.suicideSpectreExplodingAttacker != null )
- return
-
- //If spectre is not interrruptable, don't bother
- if ( !spectre.IsInterruptable() )
- continue
-
- //If spectre is parented, don't bother
- if ( IsValid( spectre.GetParent() ) )
- continue
-
- // speed up when near enemy
- entity enemy = spectre.GetEnemy()
- if ( IsAlive( enemy ) )
- {
- float dist = Distance( enemy.GetOrigin(), spectre.GetOrigin() )
- float maxDist = 850
- if ( spectre.mySpawnOptions_aiSettings == "npc_frag_drone_throwable" )
- {
- if ( dist < maxDist )
- {
- if ( pursuitSoundPlaying == false )
- {
- EmitSoundOnEntity( spectre, SFX_FRAGDRONE_SUPERPURSUIT )
- pursuitSoundPlaying = true
- }
- }
- else
- {
- if ( pursuitSoundPlaying == true )
- {
- StopSoundOnEntity( spectre, SFX_FRAGDRONE_SUPERPURSUIT )
- pursuitSoundPlaying = false
- }
- }
- }
- float speed = GraphCapped( dist, 200, 850, maxScale, minScale )
- spectre.SetNPCMoveSpeedScale( speed )
- }
-
- // offset the overload time
- if ( Time() < file.nextOverloadTime )
- continue
-
- entity attacker = SuicideSpectre_NearEnemy( spectre )
- if ( attacker != null )
- {
- //SetSuicideSpectreOverloading( spectre, attacker )
- //Assert( 0 ) // never reached
- return
- }
- }
-}
-
-entity function SuicideSpectre_NearEnemy( entity spectre )
-{
- // See if any player is close eneough to trigger self-destruct
- array<entity> enemies
- entity closestEnemy = spectre.GetClosestEnemy()
- if ( closestEnemy )
- enemies.append( closestEnemy )
-
- entity currentEnemy = spectre.GetEnemy()
- if ( currentEnemy && currentEnemy != closestEnemy )
- enemies.append( currentEnemy )
-
- vector origin = spectre.GetOrigin()
- float dist = expect float( spectre.Dev_GetAISettingByKeyField( "suicideExplosionDistance" ) )
- foreach ( enemy in enemies )
- {
- if ( !IsAlive( enemy ) )
- continue
- if ( enemy.IsCloaked( true ) )
- continue
- if ( enemy.GetNoTarget() )
- continue
- if ( enemy.IsPlayer() && enemy.IsPhaseShifted() )
- continue
-
- vector enemyOrigin = enemy.GetOrigin()
-
- if ( Distance( origin, enemyOrigin ) > dist )
- continue
-
- float heightDiff = enemyOrigin.z - origin.z
-
- // dont explode because you jump over me or I am on the floor above you
- if ( fabs( heightDiff ) > 40 )
- {
- // unless enemy is standing on something slightly above you and there is a clear trace
- float curTime = Time()
- float timeDiff = curTime - spectre.ai.suicideSpectreExplosionTraceTime
- const float TRACE_INTERVAL = 2
-
- if ( heightDiff > 0 && timeDiff > TRACE_INTERVAL && enemy.IsOnGround() && spectre.CanSee( enemy ) )
- {
- spectre.ai.suicideSpectreExplosionTraceTime = curTime
- float frac = TraceHullSimple( origin, < origin.x, origin.y, enemyOrigin.z >, spectre.GetBoundingMins(), spectre.GetBoundingMaxs(), spectre )
- if ( frac == 1.0 )
- return enemy
- }
- continue
- }
-
- return enemy
- }
-
- return null
-}
-
-void function SpectreOverloads( entity spectre )
-{
- spectre.EndSignal( "SuicideSpectreExploding" )
- file.nextOverloadTime = Time() + 0.05
-
- #if MP
- var chaseTime = spectre.Dev_GetAISettingByKeyField( "SuicideChaseTime" )
- if ( chaseTime != null )
- {
- float maxScale = expect float( spectre.Dev_GetAISettingByKeyField( "maxSpeedScale" ) )
- spectre.SetNPCMoveSpeedScale( maxScale )
-
- expect float( chaseTime )
- float endChaseTime = Time() + chaseTime
-
- for ( ;; )
- {
- if ( Time() >= endChaseTime )
- break
-
- if ( !IsAlive( spectre.GetEnemy() ) )
- break
-
- entity nearEnemy = SuicideSpectre_NearEnemy( spectre )
- if ( IsAlive( nearEnemy ) )
- {
- if ( nearEnemy.IsTitan() && spectre.IsInterruptable() )
- {
- JumpAtTitan( spectre, nearEnemy )
- spectre.ai.suicideSpectreExplosionDelay = 0.0
- return
- }
- break
- }
-
- WaitFrame()
- }
- }
- #endif
-
- for ( ;; )
- {
- #if SP
- if ( spectre.IsInterruptable() && !spectre.Anim_IsActive() )
- break
- #elseif MP
- if ( spectre.IsInterruptable() && !spectre.Anim_IsActive() && spectre.IsOnGround() )
- break
- #endif
-
- WaitFrame()
- }
-
- string overloadSF
- bool isFragDrone = spectre.mySpawnOptions_aiSettings == "npc_frag_drone_throwable"
- if ( isFragDrone )
- overloadSF = SFX_FRAGDRONE_OVERLOAD
- else
- overloadSF = SFX_TICK_OVERLOAD
- // Overload Sound
- EmitSoundOnEntity( spectre, overloadSF )
-
- AI_CreateDangerousArea_DamageDef( damagedef_frag_drone_explode, spectre, TEAM_INVALID, true, false )
-
- // Cleanup on thread end
- OnThreadEnd(
- function() : ( spectre, overloadSF )
- {
- if ( IsValid( spectre ) )
- {
- StopSoundOnEntity( spectre, overloadSF )
- }
- }
- )
-
- bool jumpAtTitans = spectre.Dev_GetAISettingByKeyField( "JumpAtTitans" ) == null || spectre.Dev_GetAISettingByKeyField( "JumpAtTitans" ) == 1
-
- entity enemy = spectre.GetEnemy()
- if ( enemy && enemy.IsTitan() && jumpAtTitans && !spectre.IsInterruptable() )
- {
- JumpAtTitan( spectre, enemy )
- }
- else
- {
- string anim = "sp_suicide_spectre_explode_stand"
- var overrideAnim = spectre.Dev_GetAISettingByKeyField( "OverrideOverloadAnim" )
-
- if ( overrideAnim != null )
- {
- anim = expect string( overrideAnim )
- }
-
- waitthread PlayAnim( spectre, anim )
-
- if ( !isFragDrone )
- wait 0.25
- }
-}
-
-void function JumpAtTitan( entity spectre, entity enemy )
-{
- vector myOrigin = spectre.GetOrigin()
- vector dirToEnemy = enemy.EyePosition() - myOrigin
-
- float dist = Length( dirToEnemy )
- if ( dist > 0 )
- {
- const float MAX_DIST = 100
- dirToEnemy *= min( MAX_DIST, dist ) / dist
- }
-
- vector refOrigin = myOrigin + Vector( dirToEnemy.x, dirToEnemy.y, 256 )
- vector refAngles = spectre.GetAngles() + Vector( 0, 180, 0 )
- spectre.Anim_ScriptedPlayWithRefPoint( "sd_jump_explode", refOrigin, refAngles, 0.3 )
- WaittillAnimDone( spectre )
- return
-}
-
-int function GetExplosionTeamBasedOnGamemode( entity spectre )
-{
- return spectre.GetTeam()
-}
-
-
-/************************************************************************************************\
-
-######## ### ## ## ### ###### ########
-## ## ## ## ### ### ## ## ## ## ##
-## ## ## ## #### #### ## ## ## ##
-## ## ## ## ## ### ## ## ## ## #### ######
-## ## ######### ## ## ######### ## ## ##
-## ## ## ## ## ## ## ## ## ## ##
-######## ## ## ## ## ## ## ###### ########
-
-\************************************************************************************************/
-void function SpectreSuicideOnDamaged_Callback( entity spectre, var damageInfo )
-{
- SpectreSuicideOnDamaged( spectre, damageInfo )
-}
-
-
-void function SpectreSuicideOnDamaged( entity spectre, var damageInfo )
-{
- //Assert( IsSuicideSpectre( spectre ) )
-
- int damageType = DamageInfo_GetCustomDamageType( damageInfo )
- DamageInfo_SetCustomDamageType( damageInfo, damageType )
-
- if ( !IsAlive( spectre ) )
- return
-
-
- entity attacker = DamageInfo_GetAttacker( damageInfo )
- entity inflictor = DamageInfo_GetInflictor( damageInfo )
- float damage = DamageInfo_GetDamage( damageInfo )
- int damageSourceId = DamageInfo_GetDamageSourceIdentifier( damageInfo )
-
- // Calculate build time credit
- if ( attacker.IsPlayer() )
- {
- if ( GameModeRulesShouldGiveTimerCredit( attacker, spectre, damageInfo ) && !TitanDamageRewardsTitanCoreTime() )
- {
- float timerCredit = CalculateBuildTimeCredit( attacker, spectre, damage, spectre.GetHealth(), spectre.GetMaxHealth(), "spectre_kill_credit", 9 )
- if ( timerCredit )
- DecrementBuildTimer( attacker, timerCredit )
- }
- }
-
- // No pain anims for suicide spectres
- DamageInfo_AddDamageFlags( damageInfo, DAMAGEFLAG_NOPAIN )
-
-
- spectre.Signal( "SuicideSpectreExploding" )
-
- if ( !IsValid( inflictor ) || !inflictor.IsPlayer() )
- {
- if ( spectre.ai.suicideSpectreExplodingAttacker == null )
- {
- if ( spectre.GetHealth() - damage <= 0 || ( IsValid( inflictor ) && IsTick( inflictor ) ) )
- {
- float explosionTime = GetSpectreExplosionTime( spectre )
- SetSuicideSpectreExploding( spectre, attacker, explosionTime )
- DamageInfo_SetDamage( damageInfo, 0 )
- return
- }
- }
- else
- {
- // already exploding
- DamageInfo_SetDamage( damageInfo, 0 )
- return
- }
-
- DamageInfo_SetDamage( damageInfo, damage )
- }
-}