From 9a96d0bff56f1969c68bb52a2f33296095bdc67d Mon Sep 17 00:00:00 2001 From: BobTheBob <32057864+BobTheBob9@users.noreply.github.com> Date: Tue, 31 Aug 2021 23:14:58 +0100 Subject: move to new mod format --- .../scripts/vscripts/mp/_ai_superspectre.nut | 736 --------------------- 1 file changed, 736 deletions(-) delete mode 100644 Northstar.CustomServers/scripts/vscripts/mp/_ai_superspectre.nut (limited to 'Northstar.CustomServers/scripts/vscripts/mp/_ai_superspectre.nut') diff --git a/Northstar.CustomServers/scripts/vscripts/mp/_ai_superspectre.nut b/Northstar.CustomServers/scripts/vscripts/mp/_ai_superspectre.nut deleted file mode 100644 index 68e888f41..000000000 --- a/Northstar.CustomServers/scripts/vscripts/mp/_ai_superspectre.nut +++ /dev/null @@ -1,736 +0,0 @@ -untyped - -global function AiSuperspectre_Init - -global function SuperSpectre_OnGroundSlamImpact -global function SuperSpectre_OnGroundLandImpact -global function SuperSpectreThink -global function SuperSpectreOnLeeched -global function SuperSpectre_WarpFall -global function CreateExplosionInflictor -global function FragDroneDeplyAnimation -global function ForceTickLaunch - -global function Reaper_LaunchFragDrone_Think -global function ReaperMinionLauncherThink - -//============================================================== -// AI Super Spectre -// -// Super Spectre keeps an array of the minions it spawned. -// Each of those minions has a reference back to it's "master." -//============================================================== -const FRAG_DRONE_BATCH_COUNT = 10 -const FRAG_DRONE_IN_FRONT_COUNT = 2 -const FRAG_DRONE_MIN_LAUNCH_COUNT = 4 -const FRAG_DRONE_LAUNCH_INTIAL_DELAY_MIN = 10 -const FRAG_DRONE_LAUNCH_INTIAL_DELAY_MAX = 20 -const FRAG_DRONE_LAUNCH_INTERVAL = 40 -const SPAWN_ENEMY_TOO_CLOSE_RANGE_SQR = 1048576 // Don't spawn guys if the target enemy is closer than this range (1024^2). -const SPAWN_HIDDEN_ENEMY_WITHIN_RANGE_SQR = 1048576 // If the enemy can't bee seen, and they are within in this range (1024^2), spawn dudes to find him. -const SPAWN_ENEMY_ABOVE_HEIGHT = 128 // If the enemy is at least this high up, then spawn dudes to find him. -const SPAWN_FUSE_TIME = 2.0 // How long after being fired before the spawner explodes and spawns a spectre. -const SPAWN_PROJECTILE_AIR_TIME = 3.0 // How long the spawn project will be in the air before hitting the ground. -const SPECTRE_EXPLOSION_DMG_MULTIPLIER = 1.2 // +20% -const DEV_DEBUG_PRINTS = false - -struct -{ - int activeMinions_GlobalArrayIdx = -1 -} file - -function AiSuperspectre_Init() -{ - PrecacheParticleSystem( $"P_sup_spectre_death" ) - PrecacheParticleSystem( $"P_sup_spectre_death_nuke" ) - PrecacheParticleSystem( $"P_xo_damage_fire_2" ) - PrecacheParticleSystem( $"P_sup_spec_dam_vent_1" ) - PrecacheParticleSystem( $"P_sup_spec_dam_vent_2" ) - PrecacheParticleSystem( $"P_sup_spectre_dam_1" ) - PrecacheParticleSystem( $"P_sup_spectre_dam_2" ) - PrecacheParticleSystem( $"drone_dam_smoke_2" ) - PrecacheParticleSystem( $"P_wpn_muzzleflash_sspectre" ) - - PrecacheImpactEffectTable( "superSpectre_groundSlam_impact" ) - PrecacheImpactEffectTable( "superSpectre_megajump_land" ) - - RegisterSignal( "SuperSpectre_OnGroundSlamImpact" ) - RegisterSignal( "SuperSpectre_OnGroundLandImpact" ) - RegisterSignal( "SuperSpectreThinkRunning" ) - RegisterSignal( "OnNukeBreakingDamage" ) // enough damage to break out or skip nuke - RegisterSignal( "death_explosion" ) - RegisterSignal( "WarpfallComplete" ) - RegisterSignal( "BeginLaunchAttack" ) - - AddDeathCallback( "npc_super_spectre", SuperSpectreDeath ) - AddDamageCallback( "npc_super_spectre", SuperSpectre_OnDamage ) - //AddPostDamageCallback( "npc_super_spectre", SuperSpectre_PostDamage ) - - file.activeMinions_GlobalArrayIdx = CreateScriptManagedEntArray() -} - -void function SuperSpectre_OnDamage( entity npc, var damageInfo ) -{ - int damageSourceId = DamageInfo_GetDamageSourceIdentifier( damageInfo ) - if ( damageSourceId == eDamageSourceId.suicideSpectreAoE ) - { - // super spectre takes reduced damage from suicide spectres - DamageInfo_ScaleDamage( damageInfo, 0.666 ) - } -} - -void function SuperSpectre_PostDamage( entity npc, var damageInfo ) -{ - float switchRatio = 0.33 - float ratio = HealthRatio( npc ) - if ( ratio < switchRatio ) - return - float newRatio = ( npc.GetHealth() - DamageInfo_GetDamage( damageInfo ) ) / npc.GetMaxHealth() - if ( newRatio >= switchRatio ) - return - - // destroy body groups - int bodygroup - bodygroup = npc.FindBodyGroup( "lowerbody" ) - npc.SetBodygroup( bodygroup, 1 ) - bodygroup = npc.FindBodyGroup( "upperbody" ) - npc.SetBodygroup( bodygroup, 1 ) -} - -void function SuperSpectreDeath( entity npc, var damageInfo ) -{ - thread DoSuperSpectreDeath( npc, damageInfo ) -} - -void function SuperSpectreNukes( entity npc, entity attacker ) -{ - npc.EndSignal( "OnDestroy" ) - vector origin = npc.GetWorldSpaceCenter() - EmitSoundAtPosition( npc.GetTeam(), origin, "ai_reaper_nukedestruct_explo_3p" ) - PlayFX( $"P_sup_spectre_death_nuke", origin, npc.GetAngles() ) - - thread SuperSpectreNukeDamage( npc.GetTeam(), origin, attacker ) - WaitFrame() // so effect has time to grow and cover the swap to gibs - npc.Gib( <0,0,100> ) -} - -void function DoSuperSpectreDeath( entity npc, var damageInfo ) -{ - // destroyed? - if ( !IsValid( npc ) ) - return - - entity attacker = DamageInfo_GetAttacker( damageInfo ) - - const int SUPER_SPECTRE_NUKE_DEATH_THRESHOLD = 300 - - bool giveBattery = ( npc.ai.shouldDropBattery && IsSingleplayer() ) - - if ( !ShouldNukeOnDeath( npc ) || !npc.IsOnGround() || !npc.IsInterruptable() || DamageInfo_GetDamage( damageInfo ) > SUPER_SPECTRE_NUKE_DEATH_THRESHOLD || ( IsValid( attacker ) && attacker.IsTitan() ) ) - { - // just boom - vector origin = npc.GetWorldSpaceCenter() - EmitSoundAtPosition( npc.GetTeam(), origin, "ai_reaper_explo_3p" ) - npc.Gib( DamageInfo_GetDamageForce( damageInfo ) ) - if ( giveBattery ) - SpawnTitanBatteryOnDeath( npc, null ) - - return - } - - npc.ai.killShotSound = false - npc.EndSignal( "OnDestroy" ) - - entity nukeFXInfoTarget = CreateEntity( "info_target" ) - nukeFXInfoTarget.kv.spawnflags = SF_INFOTARGET_ALWAYS_TRANSMIT_TO_CLIENT - DispatchSpawn( nukeFXInfoTarget ) - - nukeFXInfoTarget.SetParent( npc, "HIJACK" ) - - EmitSoundOnEntity( nukeFXInfoTarget, "ai_reaper_nukedestruct_warmup_3p" ) - - AI_CreateDangerousArea_DamageDef( damagedef_reaper_nuke, nukeFXInfoTarget, TEAM_INVALID, true, true ) - - OnThreadEnd( - function() : ( nukeFXInfoTarget, npc, attacker, giveBattery ) - { - if ( IsValid( nukeFXInfoTarget ) ) - { - StopSoundOnEntity( nukeFXInfoTarget, "ai_reaper_nukedestruct_warmup_3p" ) - nukeFXInfoTarget.Destroy() - } - - - if ( IsValid( npc ) ) - { - thread SuperSpectreNukes( npc, attacker ) - if ( giveBattery ) - { - SpawnTitanBatteryOnDeath( npc, null ) - } - } - } - ) - - //int bodygroup = npc.FindBodyGroup( "upperbody" ) - //npc.SetBodygroup( bodygroup, 1 ) - - // TODO: Add death sound - - WaitSignalOnDeadEnt( npc, "death_explosion" ) -} - -entity function CreateExplosionInflictor( vector origin ) -{ - entity inflictor = CreateEntity( "script_ref" ) - inflictor.SetOrigin( origin ) - inflictor.kv.spawnflags = SF_INFOTARGET_ALWAYS_TRANSMIT_TO_CLIENT - DispatchSpawn( inflictor ) - return inflictor -} - -void function SuperSpectreNukeDamage( int team, vector origin, entity attacker ) -{ - // all damage must have an inflictor currently - entity inflictor = CreateExplosionInflictor( origin ) - - OnThreadEnd( - function() : ( inflictor ) - { - if ( IsValid( inflictor ) ) - inflictor.Destroy() - } - ) - - int explosions = 8 - float time = 1.0 - - for ( int i = 0; i < explosions; i++ ) - { - entity explosionOwner - if ( IsValid( attacker ) ) - explosionOwner = attacker - else - explosionOwner = GetTeamEnt( team ) - - RadiusDamage_DamageDefSimple( - damagedef_reaper_nuke, - origin, // origin - explosionOwner, // owner - inflictor, // inflictor - 0 ) // dist from attacker - - wait RandomFloatRange( 0.01, 0.21 ) - } -} - -void function SuperSpectre_OnGroundLandImpact( entity npc ) -{ - PlayImpactFXTable( npc.GetOrigin(), npc, "superSpectre_megajump_land", SF_ENVEXPLOSION_INCLUDE_ENTITIES ) -} - - -void function SuperSpectre_OnGroundSlamImpact( entity npc ) -{ - PlayGroundSlamFX( npc ) -} - - -function PlayGroundSlamFX( entity npc ) -{ - int attachment = npc.LookupAttachment( "muzzle_flash" ) - vector origin = npc.GetAttachmentOrigin( attachment ) - PlayImpactFXTable( origin, npc, "superSpectre_groundSlam_impact", SF_ENVEXPLOSION_INCLUDE_ENTITIES ) -} - - -bool function EnemyWithinRangeSqr( entity npc, entity enemy, float range ) -{ - vector pos = npc.GetOrigin() - vector enemyPos = enemy.GetOrigin() - float distance = DistanceSqr( pos, enemyPos ) - - return distance <= range -} - -bool function ShouldLaunchFragDrones( entity npc, int activeMinions_EntArrayID ) -{ -// printt( "active " + GetScriptManagedEntArrayLen( activeMinions_EntArrayID ) ) - if ( !npc.ai.superSpectreEnableFragDrones ) - return false - - // check global minions - if ( GetScriptManagedEntArrayLen( file.activeMinions_GlobalArrayIdx ) > 5 ) - return false - - // only launch if all minions are dead - if ( GetScriptManagedEntArrayLen( activeMinions_EntArrayID ) > 5 ) - return false - - entity enemy = npc.GetEnemy() - - // Only spawn dudes if we have an enemy - if ( !IsValid( enemy ) ) - return false - - vector ornull lkp = npc.LastKnownPosition( enemy ) - if ( lkp == null ) - return false - - expect vector( lkp ) - - // Don't spawn if the enemy is too far away - if ( Distance( npc.GetOrigin(), lkp ) > 1500 ) - return false - - return true -} - -function SuperSpectreOnLeeched( npc, player ) -{ - local maxHealth = npc.GetMaxHealth() - npc.SetHealth( maxHealth * 0.5 ) // refill to half health -} - -function SuperSpectreThink( entity npc ) -{ - npc.EndSignal( "OnDeath" ) - - int team = npc.GetTeam() - - int activeMinions_EntArrayID = CreateScriptManagedEntArray() - if ( npc.kv.squadname == "" ) - SetSquad( npc, UniqueString( "super_spec_squad" ) ) - - npc.ai.superSpectreEnableFragDrones = expect int( npc.Dev_GetAISettingByKeyField( "enable_frag_drones" ) ) == 1 - - OnThreadEnd ( - function() : ( activeMinions_EntArrayID, npc, team ) - { - entity owner - if ( IsValid( npc ) ) - owner = npc - - foreach ( minion in GetScriptManagedEntArray( activeMinions_EntArrayID ) ) - { - // Self destruct the suicide spectres if applicable - if ( minion.GetClassName() != "npc_frag_drone" ) - continue - - if ( minion.ai.suicideSpectreExplodingAttacker == null ) - minion.TakeDamage( minion.GetHealth(), owner, owner, { scriptType = DF_DOOMED_HEALTH_LOSS, damageSourceId = eDamageSourceId.mp_weapon_super_spectre } ) - } - } - ) - - wait RandomFloatRange( FRAG_DRONE_LAUNCH_INTIAL_DELAY_MIN, FRAG_DRONE_LAUNCH_INTIAL_DELAY_MAX ) - - npc.kv.doScheduleChangeSignal = true - - while ( 1 ) - { - if ( ShouldLaunchFragDrones( npc, activeMinions_EntArrayID ) ) - waitthread SuperSpectre_LaunchFragDrone_Think( npc, activeMinions_EntArrayID ) - - wait FRAG_DRONE_LAUNCH_INTERVAL - } -} - -void function SuperSpectre_LaunchFragDrone_Think( entity npc, int activeMinions_EntArrayID ) -{ - array targetOrigins = GetFragDroneTargetOrigins( npc, npc.GetOrigin(), 200, 2000, 64, FRAG_DRONE_BATCH_COUNT ) - - if ( targetOrigins.len() < FRAG_DRONE_MIN_LAUNCH_COUNT ) - return - - npc.RequestSpecialRangeAttack( targetOrigins.len() + FRAG_DRONE_IN_FRONT_COUNT ) - - // wait for first attack signal - npc.WaitSignal( "OnSpecialAttack" ) - npc.EndSignal( "OnDeath" ) - npc.EndSignal( "OnScheduleChange" ) // kv.doScheduleChangeSignal = true - - // drop a few in front of enemy view - entity enemy = npc.GetEnemy() - if ( enemy ) - { - vector searchOrigin = enemy.GetOrigin() + ( enemy.GetForwardVector() * 400 ) - array frontOfEnemyOrigins = GetFragDroneTargetOrigins( npc, searchOrigin, 0, 500, 16, FRAG_DRONE_IN_FRONT_COUNT ) - - foreach ( targetOrigin in frontOfEnemyOrigins ) - { - thread LaunchSpawnerProjectile( npc, targetOrigin, activeMinions_EntArrayID ) - //DebugDrawBox( targetOrigin, Vector(-10, -10, 0), Vector(10, 10, 10), 255, 0, 0, 255, 5 ) - npc.WaitSignal( "OnSpecialAttack" ) - } - } - - // drop rest in pre-searched spots - foreach ( targetOrigin in targetOrigins ) - { - thread LaunchSpawnerProjectile( npc, targetOrigin, activeMinions_EntArrayID ) - npc.WaitSignal( "OnSpecialAttack" ) - } -} - -void function ReaperMinionLauncherThink( entity reaper ) -{ - if ( GetBugReproNum() != 221936 ) - reaper.kv.squadname = "" - - StationaryAIPosition launchPos = GetClosestAvailableStationaryPosition( reaper.GetOrigin(), 8000, eStationaryAIPositionTypes.LAUNCHER_REAPER ) - launchPos.inUse = true - - OnThreadEnd( - function () : ( launchPos ) - { - launchPos.inUse = false - } - ) - - reaper.EndSignal( "OnDeath" ) - reaper.AssaultSetFightRadius( 96 ) - reaper.AssaultSetGoalRadius( reaper.GetMinGoalRadius() ) - - while ( true ) - { - WaitFrame() - - if ( Distance( reaper.GetOrigin(), launchPos.origin ) > 96 ) - { - printt( reaper," ASSAULT:", launchPos.origin, Distance( reaper.GetOrigin(), launchPos.origin ) ) - reaper.AssaultPoint( launchPos.origin ) - table signalData = WaitSignal( reaper, "OnFinishedAssault", "OnEnterGoalRadius", "OnFailedToPath" ) - printt( reaper," END ASSAULT:", launchPos.origin, signalData.signal ) - if ( signalData.signal == "OnFailedToPath" ) - continue - } - - printt( reaper," LAUNCH:", launchPos.origin ) - waitthread Reaper_LaunchFragDrone_Think( reaper, "npc_frag_drone_fd" ) - printt( reaper," END LAUNCH:", launchPos.origin ) - while ( GetScriptManagedEntArrayLen( reaper.ai.activeMinionEntArrayID ) > 2 ) - WaitFrame() - } -} - -void function Reaper_LaunchFragDrone_Think( entity reaper, string fragDroneSettings = "" ) -{ - if ( reaper.ai.activeMinionEntArrayID < 0 ) - reaper.ai.activeMinionEntArrayID = CreateScriptManagedEntArray() - - int activeMinions_EntArrayID = reaper.ai.activeMinionEntArrayID - - const int MAX_TICKS = 4 - - int currentMinions = GetScriptManagedEntArray( reaper.ai.activeMinionEntArrayID ).len() - int minionsToSpawn = MAX_TICKS - currentMinions - - if ( minionsToSpawn <= 0 ) - return - - array targetOrigins = GetFragDroneTargetOrigins( reaper, reaper.GetOrigin(), 200, 2000, 64, MAX_TICKS ) - - if ( targetOrigins.len() < minionsToSpawn ) - return - - if ( IsAlive( reaper.GetEnemy() ) && ( reaper.GetEnemy().IsPlayer() || reaper.GetEnemy().IsNPC() ) && reaper.CanSee( reaper.GetEnemy() ) ) - return - - OnThreadEnd( - function() : ( reaper ) - { - if ( IsValid( reaper ) ) - { - reaper.Anim_Stop() - } - } - ) - - printt( reaper, " BEGIN LAUNCHING: ", minionsToSpawn, reaper.GetCurScheduleName() ) - - reaper.EndSignal( "OnDeath" ) - - while ( !reaper.IsInterruptable() ) - WaitFrame() - - waitthread PlayAnim( reaper, "sspec_idle_to_speclaunch" ) - - while ( minionsToSpawn > 0 ) - { - // drop rest in pre-searched spots - foreach ( targetOrigin in targetOrigins ) - { - if ( minionsToSpawn <= 0 ) - break - - printt( reaper, " LAUNCHING: ", minionsToSpawn ) - thread LaunchSpawnerProjectile( reaper, targetOrigin, activeMinions_EntArrayID, fragDroneSettings ) - minionsToSpawn-- - - if ( minionsToSpawn <= 0 ) - break - - waitthread PlayAnim( reaper, "sspec_speclaunch_fire" ) - } - } - - waitthread PlayAnim( reaper, "sspec_speclaunch_to_idle" ) -} - - - -array function GetFragDroneTargetOrigins( entity npc, vector origin, float minRadius, float maxRadius, int randomCount, int desiredCount ) -{ - array targetOrigins -/* - vector angles = npc.GetAngles() - angles.x = 0 - angles.z = 0 - - vector origin = npc.GetOrigin() + Vector( 0, 0, 1 ) - float arc = 0 - float dist = 200 - - for ( ;; ) - { - if ( dist > 2000 || targetOrigins.len() >= 12 ) - break - - angles = AnglesCompose( angles, <0,arc,0> ) - arc += 35 - arc %= 360 - dist += 200 - - vector ornull tryOrigin = TryCreateFragDroneLaunchTrajectory( npc, origin, angles, dist ) - if ( tryOrigin == null ) - continue - expect vector( tryOrigin ) - targetOrigins.append( tryOrigin ) - } -*/ - float traceFrac = TraceLineSimple( origin, origin + <0, 0, 200>, npc ) - if ( traceFrac < 1 ) - return targetOrigins; - - array< vector > randomSpots = NavMesh_RandomPositions_LargeArea( origin, HULL_HUMAN, randomCount, minRadius, maxRadius ) - - int numFragDrones = 0 - foreach( spot in randomSpots ) - { - targetOrigins.append( spot ) - numFragDrones++ - if ( numFragDrones == desiredCount ) - break - } - - return targetOrigins -} - -vector ornull function TryCreateFragDroneLaunchTrajectory( entity npc, vector origin, vector angles, float dist ) -{ - vector forward = AnglesToForward( angles ) - vector targetOrigin = origin + forward * dist - - vector ornull clampedPos = NavMesh_ClampPointForHullWithExtents( targetOrigin, HULL_HUMAN, < 300, 300, 100 > ) - - if ( clampedPos == null ) - return null - - vector vel = GetVelocityForDestOverTime( origin, expect vector( clampedPos ), SPAWN_PROJECTILE_AIR_TIME ) - float traceFrac = TraceLineSimple( origin, origin + vel, npc ) - //DebugDrawLine( origin, origin + vel, 255, 0, 0, true, 5.0 ) - if ( traceFrac >= 0.5 ) - return clampedPos - return null -} - -void function FragDroneDeplyAnimation( entity drone, float minDelay = 0.5, float maxDelay = 2.5 ) -{ - Assert( !drone.ai.fragDroneArmed, "Armed drone was told to play can animation. Spawn drone with CreateFragDroneCan()" ) - drone.EndSignal( "OnDeath" ) - - drone.SetInvulnerable() - OnThreadEnd( - function() : ( drone ) - { - drone.ClearInvulnerable() - } - ) - - drone.Anim_ScriptedPlay( "sd_closed_idle" ) - wait RandomFloatRange( minDelay, maxDelay ) - - #if MP - while ( !drone.IsInterruptable() ) - { - WaitFrame() - } - #endif - - drone.Anim_ScriptedPlay( "sd_closed_to_open" ) - - // Wait for P_drone_frag_open_flicker FX to play inside sd_closed_to_open - wait 0.6 -} - -void function LaunchSpawnerProjectile( entity npc, vector targetOrigin, int activeMinions_EntArrayID, string droneSettings = "" ) -{ - //npc.EndSignal( "OnDeath" ) - - entity weapon = npc.GetOffhandWeapon( 0 ) - - if ( !IsValid( weapon ) ) - return - - int id = npc.LookupAttachment( "launch" ) - vector launchPos = npc.GetAttachmentOrigin( id ) - int team = npc.GetTeam() - vector launchAngles = npc.GetAngles() - string squadname = expect string( npc.kv.squadname ) - vector vel = GetVelocityForDestOverTime( launchPos, targetOrigin, SPAWN_PROJECTILE_AIR_TIME ) - -// DebugDrawLine( npc.GetOrigin() + <3,3,3>, launchPos + <3,3,3>, 255, 0, 0, true, 5.0 ) - float armTime = SPAWN_PROJECTILE_AIR_TIME + RandomFloatRange( 1.0, 2.5 ) - entity nade = weapon.FireWeaponGrenade( launchPos, vel, <200,0,0>, armTime, damageTypes.dissolve, damageTypes.explosive, PROJECTILE_NOT_PREDICTED, true, true ) - - AddToScriptManagedEntArray( activeMinions_EntArrayID, nade ) - AddToScriptManagedEntArray( file.activeMinions_GlobalArrayIdx, nade ) - - nade.SetOwner( npc ) - nade.EndSignal( "OnDestroy" ) - - OnThreadEnd( - function() : ( nade, team, activeMinions_EntArrayID, squadname, droneSettings ) - { - vector origin = nade.GetOrigin() - vector angles = nade.GetAngles() - - vector ornull clampedPos = NavMesh_ClampPointForHullWithExtents( origin, HULL_HUMAN, < 100, 100, 100 > ) - if ( clampedPos == null ) - return - - entity drone = CreateFragDroneCan( team, expect vector( clampedPos ), < 0, angles.y, 0 > ) - SetSpawnOption_SquadName( drone, squadname ) - if ( droneSettings != "" ) - { - SetSpawnOption_AISettings( drone, droneSettings ) - } - drone.kv.spawnflags = SF_NPC_ALLOW_SPAWN_SOLID // clamped to navmesh no need to check solid - DispatchSpawn( drone ) - - thread FragDroneDeplyAnimation( drone ) - - AddToScriptManagedEntArray( activeMinions_EntArrayID, drone ) - AddToScriptManagedEntArray( file.activeMinions_GlobalArrayIdx, drone ) - } - ) - - Grenade_Init( nade, weapon ) - - EmitSoundOnEntity( npc, "SpectreLauncher_AI_WpnFire" ) - WaitForever() - -// wait SPAWN_PROJECTILE_AIR_TIME + SPAWN_FUSE_TIME -} - - -// Seriously don't use this unless absolutely necessary! Used for scripted moment in Reapertown. -// Bypasses all of the tick launch rules and sends a request for launching ticks to code immediately. -void function ForceTickLaunch( entity npc ) -{ - SuperSpectre_LaunchFragDrone_Think( npc, file.activeMinions_GlobalArrayIdx ) -} - - -/************************************************************************************************\ -######## ######## ####### ######## ####### ######## ## ## ######## ######## -## ## ## ## ## ## ## ## ## ## ## ## ## ## ## -## ## ## ## ## ## ## ## ## ## #### ## ## ## -######## ######## ## ## ## ## ## ## ## ######## ###### -## ## ## ## ## ## ## ## ## ## ## ## -## ## ## ## ## ## ## ## ## ## ## ## -## ## ## ####### ## ####### ## ## ## ######## -\************************************************************************************************/ - - -function SuperSpectre_WarpFall( entity ai ) -{ - ai.EndSignal( "OnDestroy" ) - - vector origin = ai.GetOrigin() - entity mover = CreateOwnedScriptMover( ai ) - ai.SetParent( mover, "", false, 0 ) - ai.Hide() - ai.SetEfficientMode( true ) - ai.SetInvulnerable() - - WaitFrame() // give AI time to hide before moving - - vector warpPos = origin + < 0, 0, 1000 > - mover.SetOrigin( warpPos ) - - #if GRUNTCHATTER_ENABLED - GruntChatter_TryIncomingSpawn( ai, origin ) - #endif - - EmitSoundAtPosition( TEAM_UNASSIGNED, origin, "Titan_1P_Warpfall_Start" ) - - local e = {} - e.warpfx <- PlayFX( TURBO_WARP_FX, warpPos + < 0, 0, -104 >, mover.GetAngles() ) - e.smokeFx <- null - - OnThreadEnd( - function() : ( e, mover, ai ) - { - if ( IsAlive( ai ) ) - { - ai.ClearParent() - ai.SetVelocity( <0,0,0> ) - ai.Signal( "WarpfallComplete" ) - } - if ( IsValid( e.warpfx ) ) - e.warpfx.Destroy() - if ( IsValid( e.smokeFx ) ) - e.smokeFx.Destroy() - if ( IsValid( mover ) ) - mover.Destroy() - } - ) - wait 0.5 - - EmitSoundAtPosition( TEAM_UNASSIGNED, origin, "Titan_3P_Warpfall_WarpToLanding" ) - - wait 0.4 - - ai.Show() - - e.smokeFx = PlayFXOnEntity( TURBO_WARP_COMPANY, ai, "", <0.0, 0.0, 152.0> ) - - local time = 0.2 - mover.MoveTo( origin, time, 0, 0 ) - wait time - - ai.SetEfficientMode( false ) - ai.ClearInvulnerable() - - e.smokeFx.Destroy() - PlayFX( $"droppod_impact", origin ) - - Explosion_DamageDefSimple( - damagedef_reaper_fall, - origin, - ai, // attacker - ai, // inflictor - origin ) - - wait 0.1 -} - -bool function ShouldNukeOnDeath( entity ent ) -{ - if ( IsMultiplayer() ) - return false - - return ent.Dev_GetAISettingByKeyField( "nuke_on_death" ) == 1 -} \ No newline at end of file -- cgit v1.2.3