diff options
author | zxcPandora <81985226+zxcPandora@users.noreply.github.com> | 2022-09-13 23:29:01 +0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-09-13 17:29:01 +0200 |
commit | 0e379c6509ee269b8ab1952248ec6886b542482f (patch) | |
tree | 510c932579c423999169df83f325b6b2e744f482 /Northstar.CustomServers/mod | |
parent | 6a9d495d7b98dee746c076eac0c905a5c90de704 (diff) | |
download | NorthstarMods-0e379c6509ee269b8ab1952248ec6886b542482f.tar.gz NorthstarMods-0e379c6509ee269b8ab1952248ec6886b542482f.zip |
[FD]Ronin Phase Shift fix (#473)
* Ronin NoTarget Bug fix
it'll case a Ronin Bug;Common in Frontier Defense
Npc will ignore the player and other team player in the this titan
Here's test log
Normal:
Start Phase Shift: ent.GetNoTarget() = false
Start No target before: ent.GetNoTarget() = false
Start No target after: ent.GetNoTarget() = true
End Phase Shift: ent.GetNoTarget() = false
Start Phase Shift: ent.GetNoTarget() = false
Start No target before: ent.GetNoTarget() = false
Start No target after: ent.GetNoTarget() = true
End Phase Shift: ent.GetNoTarget() = false
After trigger bug:
Start Phase Shift: ent.GetNoTarget() = false
Start No target before: ent.GetNoTarget() = false
Start No target after: ent.GetNoTarget() = true
Start Phase Shift: ent.GetNoTarget() = true
Start No target before: ent.GetNoTarget() = true
Start No target after: ent.GetNoTarget() = true
End Phase Shift: ent.GetNoTarget() = false
End Phase Shift: ent.GetNoTarget() = true
* carry over the old state between phases
* Update Northstar.CustomServers/mod/scripts/vscripts/weapons/sh_phase_shift.gnut
Co-authored-by: Jack <66967891+ASpoonPlaysGames@users.noreply.github.com>
* Update Northstar.CustomServers/mod/scripts/vscripts/weapons/sh_phase_shift.gnut
Co-authored-by: Jack <66967891+ASpoonPlaysGames@users.noreply.github.com>
* Update Northstar.CustomServers/mod/scripts/vscripts/weapons/sh_phase_shift.gnut
thx
Co-authored-by: Jack <66967891+ASpoonPlaysGames@users.noreply.github.com>
* Add convar "ns_use_phase_fix"
make this toggleable through a convar, default to fixing ronin phase shift problem
allow people to turn off the fix if they wanted
Co-authored-by: ASpoonPlaysGames <66967891+ASpoonPlaysGames@users.noreply.github.com>
Diffstat (limited to 'Northstar.CustomServers/mod')
-rw-r--r-- | Northstar.CustomServers/mod/scripts/vscripts/weapons/sh_phase_shift.gnut | 774 |
1 files changed, 774 insertions, 0 deletions
diff --git a/Northstar.CustomServers/mod/scripts/vscripts/weapons/sh_phase_shift.gnut b/Northstar.CustomServers/mod/scripts/vscripts/weapons/sh_phase_shift.gnut new file mode 100644 index 00000000..52d07f00 --- /dev/null +++ b/Northstar.CustomServers/mod/scripts/vscripts/weapons/sh_phase_shift.gnut @@ -0,0 +1,774 @@ +untyped
+#if CLIENT
+#endif
+
+global function MpAbilityShifter_Init
+global function PhaseShift
+global function CodeCallback_EnterPhaseShift
+global function CodeCallback_ExitPhaseShift
+global function CancelPhaseShift
+
+#if SERVER
+global function PlayPhaseShiftDisappearFX
+global function UntrackAllToneMarks
+#endif
+
+const SHIFTER_OUTRO_TIME_BEFORE_END = 1.5
+
+const SHIFTER_PRE_FX = $"P_warpjump_FP"
+
+const SHIFTER_APPEAR_FX = $"P_phase_shift_main"
+const SHIFTER_APPEAR_FX_TITAN = $"P_phase_shift_main_XO"
+const SHIFTER_DISAPPEAR_FX = $"P_phase_shift_main"
+const SHIFTER_DISAPPEAR_FX_TITAN = $"P_phase_shift_main_XO"
+
+const SHIFTER_SCREEN_FX = $"P_phase_shift_screen"
+const SHIFTER_PERSONAL_FX = $"P_phase_shift_player"
+const SHIFTER_SCREEN_FX_START = $"P_phase_shift_screen_start"
+const SHIFTER_COLORCORRECTION = "materials/correction/mp_ability_shifter.raw"
+
+const SHIFTER_PRE_SOUND_1P = "Pilot_PhaseShift_PreActivate_1P"
+const SHIFTER_PRE_SOUND_3P = "Pilot_PhaseShift_PreActivate_3P"
+global const SHIFTER_START_SOUND_1P = "Pilot_PhaseShift_Activate_1P"
+global const SHIFTER_START_SOUND_3P = "Pilot_PhaseShift_Activate_3P"
+const SHIFTER_LOOP_SOUND_1P = "Pilot_PhaseShift_Loop_1P"
+const SHIFTER_LOOP_SOUND_3P = "Pilot_PhaseShift_Loop_3P"
+const SHIFTER_PRE_END_SOUND_1P = "Pilot_PhaseShift_WarningToEnd_1P"
+const SHIFTER_PRE_END_SOUND_3P = "Pilot_PhaseShift_WarningToEnd_3P"
+global const SHIFTER_END_SOUND_1P = "Pilot_PhaseShift_End_1P"
+global const SHIFTER_END_SOUND_3P = "Pilot_PhaseShift_End_3P"
+
+const SHIFTER_PRE_SOUND_1P_TITAN = "Pilot_PhaseShift_PreActivate_1P"
+const SHIFTER_PRE_SOUND_3P_TITAN = "Pilot_PhaseShift_PreActivate_3P"
+global const SHIFTER_START_SOUND_1P_TITAN = "titan_phasedash_activate_1p"
+global const SHIFTER_START_SOUND_3P_TITAN = "titan_phasedash_activate_3p"
+const SHIFTER_LOOP_SOUND_1P_TITAN = "titan_phasedash_loop_1p"
+const SHIFTER_LOOP_SOUND_3P_TITAN = "titan_phasedash_loop_3p"
+const SHIFTER_PRE_END_SOUND_1P_TITAN = "titan_phasedash_warningtoend_1p"
+const SHIFTER_PRE_END_SOUND_3P_TITAN = "titan_phasedash_warningtoend_3p"
+global const SHIFTER_END_SOUND_1P_TITAN = "titan_phasedash_end_1p"
+global const SHIFTER_END_SOUND_3P_TITAN = "titan_phasedash_end_3p"
+
+const int TELEFRAG_DAMAGE = 5000;
+
+struct
+{
+} file;
+
+void function CodeCallback_EnterPhaseShift( entity ent )
+{
+ PhaseShift( ent, 0.0, 999.0 )
+}
+
+void function CodeCallback_ExitPhaseShift( entity ent )
+{
+#if SERVER
+ CancelPhaseShift( ent )
+#endif
+}
+
+void function CancelPhaseShift( entity ent )
+{
+ ent.PhaseShiftCancel()
+
+#if SERVER
+ ent.Signal( "ForceStopPhaseShift" )
+ PlayPhaseShiftAppearFX( ent )
+#endif //
+}
+
+
+void function MpAbilityShifter_Init()
+{
+#if CLIENT
+ //ColorCorrection_RegisterRemoteTurret( "materials/correction/remote_turret.raw" )
+
+ ColorCorrection_RegisterPhaseShift( SHIFTER_COLORCORRECTION )
+ thread ClientPhaseShiftFirstPersonFXThread()
+
+ thread ClientRemoteTurretFirstPersonFXThread()
+#endif // #if CLIENT
+
+ PrecacheParticleSystem( SHIFTER_PRE_FX )
+ PrecacheParticleSystem( SHIFTER_APPEAR_FX )
+ PrecacheParticleSystem( SHIFTER_APPEAR_FX_TITAN )
+ PrecacheParticleSystem( SHIFTER_DISAPPEAR_FX )
+ PrecacheParticleSystem( SHIFTER_DISAPPEAR_FX_TITAN )
+ PrecacheParticleSystem( SHIFTER_PERSONAL_FX )
+ PrecacheParticleSystem( SHIFTER_SCREEN_FX )
+ PrecacheParticleSystem( SHIFTER_SCREEN_FX_START )
+
+ MpAbilityShifterWeapon_Init()
+
+ RegisterSignal( "StartPhaseShift" )
+ RegisterSignal( "StopPhaseShift" )
+ RegisterSignal( "ForceStopPhaseShift" )
+}
+
+int function PhaseShift( entity ent, float warmupTime, float duration )
+{
+ if ( !IsAlive( ent ) )
+ return 0
+
+ if ( ent.IsPhaseShifted() )
+ return 0
+
+ // PROTO: this should be better eventually
+ // this is to prevent weirdness if you're already in a context action
+ if ( ent.IsPlayer() )
+ {
+ entity proxy = ent.GetFirstPersonProxy()
+ if ( ( ent.ContextAction_IsActive() || (proxy != null && proxy.Anim_IsActive()) )
+ && !ent.IsZiplining()
+ && !ent.ContextAction_IsLeeching()
+ && ent.GetTitanSoulBeingRodeoed() == null )
+ {
+ return 0
+ }
+
+ ent.PhaseShiftBegin( warmupTime, duration )
+
+ #if SERVER
+ thread ServerPhaseShiftPlayerThread( ent, warmupTime, duration )
+ #else
+ thread ClientPhaseShiftWarmupThread( ent, warmupTime )
+ #endif // #if SERVER
+
+ return 1
+ }
+ else
+ {
+ ent.PhaseShiftBegin( warmupTime, duration )
+
+ #if SERVER
+ thread ServerPhaseShiftPlayerThread( ent, warmupTime, duration )
+ #endif // #if SERVER
+
+ return 1
+ }
+
+ unreachable
+}
+
+#if SERVER
+void function ServerPhaseShiftPlayerThread( entity ent, float warmupTime, float shiftTime )
+{
+ ent.EndSignal( "OnDeath" )
+ ent.EndSignal( "ForceStopPhaseShift" )
+
+ // initialise the two ent.s variables if needed
+ if ( !( "oldPhaseStateLock" in ent.s ) || !( "oldPhaseState" in ent.s ) )
+ {
+ ent.s.oldPhaseStateLock <- false
+ ent.s.oldPhaseState <- false
+ }
+
+ bool keepAnimActive = false
+
+ if ( ent.IsPlayer() )
+ {
+ ent.EndSignal( "player_embarks_titan" )
+
+ Leech_Disallow( ent )
+ // EmitSoundOnEntityExceptToPlayer( ent, ent, SHIFTER_PRE_SOUND_3P )
+
+ entity proxy = ent.GetFirstPersonProxy()
+ if ( proxy != null )
+ proxy.SetForceVisibleInPhaseShift( true )
+
+ if ( Rodeo_IsAttached( ent ) )
+ {
+ if ( ent.GetParent() != null && ent.GetParent().IsPhaseShifted() )
+ keepAnimActive = true
+ else
+ ent.Signal( "RodeoOver" )
+ }
+
+ if ( ent.IsTitan() )
+ {
+ UntrackAllToneMarks( ent )
+ entity titanSoul = ent.GetTitanSoul()
+ if ( titanSoul != null )
+ {
+ if ( titanSoul.soul.batteryContainer != null )
+ {
+ titanSoul.soul.batteryContainer.SetForceVisibleInPhaseShift( true )
+ }
+ }
+ }
+
+ Battery_StopFXAndHideIconForPlayer( ent )
+ }
+ else
+ {
+ if ( ent.IsTitan() )
+ UntrackAllToneMarks( ent )
+ ent.EnableNPCFlag( NPC_IGNORE_ALL )
+ EmitSoundOnEntity( ent, SHIFTER_PRE_SOUND_3P )
+ }
+
+ // only change the oldPhaseState if it's not locked
+ if ( !ent.s.oldPhaseStateLock || !GetConVarBool("ns_use_phase_fix") )
+ {
+ ent.s.oldPhaseStateLock <- true
+ ent.s.oldPhaseState <- ent.GetNoTarget()
+ }
+
+ OnThreadEnd(
+ function() : ( ent )
+ {
+ if ( IsValid( ent ) )
+ {
+ ent.Signal( "StopPhaseShift" )
+ ent.Solid()
+ ent.SetNoTarget( ent.s.oldPhaseState )
+ // unlock the oldPhaseState
+ ent.s.oldPhaseStateLock <- false
+
+ StopSoundOnEntity( ent, SHIFTER_PRE_SOUND_3P )
+ StopSoundOnEntity( ent, SHIFTER_LOOP_SOUND_3P )
+ StopSoundOnEntity( ent, SHIFTER_PRE_SOUND_3P_TITAN )
+ StopSoundOnEntity( ent, SHIFTER_LOOP_SOUND_3P_TITAN )
+
+ ent.DisablePhaseShiftFlags()
+
+ if ( ent.IsPlayer() )
+ {
+ Leech_Allow( ent )
+ UpdatePlayerHighlightsSettings( ent )
+
+ if ( GetSoulFromPlayer( ent ) != null )
+ {
+ entity soul = GetSoulFromPlayer( ent )
+ if ( soul.soul.batteryContainer != null )
+ {
+ soul.soul.batteryContainer.SetForceVisibleInPhaseShift( false )
+ }
+ }
+
+ entity proxy = ent.GetFirstPersonProxy()
+ if ( proxy != null )
+ proxy.SetForceVisibleInPhaseShift( false )
+
+ if ( PlayerHasBattery( ent ) )
+ Battery_StartFX( GetBatteryOnBack( ent ) )
+ }
+ else
+ {
+ ent.DisableNPCFlag( NPC_IGNORE_ALL )
+ Highlight_ClearEnemyHighlight( ent )
+ }
+
+ entity teleFragTarget = ent.GetEntityAtPhaseShiftExitPosition();
+ if ( IsValid( teleFragTarget ) )
+ {
+ if ( !IsHumanSized( teleFragTarget ) )
+ {
+ if ( ShouldEntitySelfKill( ent, teleFragTarget ) )
+ {
+ ent.TakeDamage( ent.GetHealth() + 1, teleFragTarget, teleFragTarget, { damageSourceId = eDamageSourceId.phase_shift, scriptType = DF_GIB | DF_BYPASS_SHIELD | DF_SKIPS_DOOMED_STATE } );
+ }
+ else
+ {
+ printt( "Pushed players apart" )
+ PushPlayersApart( teleFragTarget, ent, 600.0 ) // this will work for NPCs too
+ }
+ }
+ else
+ {
+ teleFragTarget.TakeDamage( teleFragTarget.GetHealth() + 1, ent, ent, { damageSourceId = eDamageSourceId.phase_shift, scriptType = DF_GIB | DF_BYPASS_SHIELD | DF_SKIPS_DOOMED_STATE } );
+ }
+ }
+ }
+ }
+ )
+
+ wait warmupTime
+
+ //thread PROTO_CapVelocity( ent )
+
+ entity soul
+ if ( ent.IsTitan() )
+ {
+ soul = ent.GetTitanSoul()
+ string titanType = GetSoulTitanSubClass( soul )
+ entity rider = GetRodeoPilot( ent )
+ if ( rider != null && Rodeo_IsAttached( rider ) )
+ {
+ if ( !rider.IsPlayer() )
+ rider.Signal( "RodeoOver" )
+ else
+ PhaseShift( rider, 0, shiftTime )
+ }
+ }
+
+ entity fx = PlayPhaseShiftDisappearFX( ent )
+ thread PhaseShiftDisappearEffectCleanup( ent, fx, shiftTime )
+
+ ent.Signal( "StartPhaseShift" )
+ if ( !keepAnimActive )
+ ent.Signal( "ScriptAnimStop" )
+ ent.NotSolid()
+ ent.SetNoTarget( true )
+ ent.EnablePhaseShiftFlags()
+ ent.Highlight_SetCurrentContext( -1 )
+
+ if ( ent.IsPlayer() )
+ {
+ PlayerDropsScriptedItems( ent )
+ if ( ent.IsTitan() )
+ {
+ EmitSoundOnEntityExceptToPlayer( ent, ent, SHIFTER_START_SOUND_3P_TITAN )
+ EmitSoundOnEntityExceptToPlayerNotPredicted( ent, ent, SHIFTER_LOOP_SOUND_3P_TITAN )
+ }
+ else
+ {
+ EmitSoundOnEntityExceptToPlayer( ent, ent, SHIFTER_START_SOUND_3P )
+ EmitSoundOnEntityExceptToPlayerNotPredicted( ent, ent, SHIFTER_LOOP_SOUND_3P )
+ }
+
+ foreach( statusEffect in ent.p.empStatusEffectsToClearForPhaseShift ) //Not great, done to avoid needing code work to get a separate empSlow/empSTurnEffects
+ {
+ StatusEffect_Stop( ent, statusEffect )
+ }
+
+ ent.p.empStatusEffectsToClearForPhaseShift.clear()
+ }
+ else
+ {
+ if ( ent.IsTitan() )
+ {
+ EmitSoundOnEntity( ent, SHIFTER_START_SOUND_3P_TITAN )
+ EmitSoundOnEntity( ent, SHIFTER_LOOP_SOUND_3P_TITAN )
+ }
+ else
+ {
+ EmitSoundOnEntity( ent, SHIFTER_START_SOUND_3P )
+ EmitSoundOnEntity( ent, SHIFTER_LOOP_SOUND_3P )
+ }
+ }
+
+ float FX_WARMUP_TIME = 0.3
+ bool timeAdjusted = false
+
+ if ( shiftTime > FX_WARMUP_TIME )
+ {
+ shiftTime -= FX_WARMUP_TIME // need to play the fx a little earlier so the timing lines up
+ timeAdjusted = true
+ }
+
+ if ( shiftTime >= SHIFTER_OUTRO_TIME_BEFORE_END )
+ {
+ wait ( shiftTime - SHIFTER_OUTRO_TIME_BEFORE_END )
+
+ if ( ent.IsPlayer() )
+ {
+ if ( ent.IsTitan() )
+ {
+ EmitSoundOnEntityOnlyToPlayer( ent, ent, SHIFTER_PRE_END_SOUND_1P_TITAN )
+ EmitSoundOnEntityExceptToPlayer( ent, ent, SHIFTER_PRE_END_SOUND_3P_TITAN )
+ }
+ else
+ {
+ EmitSoundOnEntityOnlyToPlayer( ent, ent, SHIFTER_PRE_END_SOUND_1P )
+ EmitSoundOnEntityExceptToPlayer( ent, ent, SHIFTER_PRE_END_SOUND_3P )
+ }
+
+ }
+ else
+ {
+ if ( ent.IsTitan() )
+ EmitSoundOnEntity( ent, SHIFTER_PRE_END_SOUND_3P_TITAN )
+ else
+ EmitSoundOnEntity( ent, SHIFTER_PRE_END_SOUND_3P )
+ }
+
+ wait SHIFTER_OUTRO_TIME_BEFORE_END
+ }
+ else
+ {
+ wait shiftTime
+ }
+
+ PlayPhaseShiftAppearFX( ent )
+
+ if ( timeAdjusted )
+ wait FX_WARMUP_TIME
+}
+
+// ASSUMES THAT SECOND ENTITY IS NOT HUMAN SIZED
+bool function ShouldEntitySelfKill( entity ent, entity largeTelefragTarget )
+{
+ if ( IsHumanSized( ent ) )
+ return true
+
+ if ( IsSingleplayer() )
+ return false
+
+ return ( DistanceSqr( largeTelefragTarget.GetOrigin(), ent.GetOrigin() ) < 4096.0 )
+}
+
+void function PhaseShiftDisappearEffectCleanup( entity ent, entity fx, float duration )
+{
+ fx.EndSignal( "OnDestroy" )
+ ent.EndSignal( "ForceStopPhaseShift" )
+
+ OnThreadEnd(
+ function() : ( fx )
+ {
+ if ( IsValid( fx ) )
+ {
+ EffectStop( fx )
+ }
+ }
+ )
+
+ float bufferTime = 1.4
+ if ( ent.IsTitan() )
+ bufferTime = 0.0
+
+ wait max( duration - bufferTime, 0.0 )
+}
+
+entity function PlayPhaseShiftAppearFX( entity ent )
+{
+ asset effect = SHIFTER_APPEAR_FX
+ if ( !IsHumanSized( ent ) )
+ effect = SHIFTER_APPEAR_FX_TITAN
+
+ if ( ent.IsPlayer() )
+ {
+ if ( ent.IsTitan() )
+ EmitSoundOnEntityExceptToPlayer( ent, ent, SHIFTER_END_SOUND_3P_TITAN )
+ else
+ EmitSoundOnEntityExceptToPlayer( ent, ent, SHIFTER_END_SOUND_3P )
+
+ return PlayFXOnEntityForEveryoneExceptPlayer( effect, ent, ent )
+ }
+ else
+ {
+ if ( ent.IsTitan() )
+ EmitSoundOnEntity( ent, SHIFTER_END_SOUND_3P_TITAN )
+ else
+ EmitSoundOnEntity( ent, SHIFTER_END_SOUND_3P )
+ return PlayFXOnEntity( effect, ent )
+ }
+}
+
+entity function PlayPhaseShiftDisappearFX( entity ent )
+{
+ asset effect = SHIFTER_DISAPPEAR_FX
+ if ( !IsHumanSized( ent ) )
+ effect = SHIFTER_DISAPPEAR_FX_TITAN
+
+ int fxid = GetParticleSystemIndex( effect )
+ int attachId = ent.LookupAttachment( "ORIGIN" )
+
+ return StartParticleEffectOnEntity_ReturnEntity( ent, fxid, FX_PATTACH_POINT_FOLLOW, attachId )
+}
+
+array<entity> function GetAttachedEnts( entity ent )
+{
+ array<entity> ents = [ ent ]
+
+ if ( HasSoul( ent ) )
+ {
+ entity soul = ent.GetTitanSoul()
+ if ( IsValid( soul.soul.batteryContainer ) )
+ ents.append( soul.soul.batteryContainer )
+ }
+
+ entity weapon = ent.GetActiveWeapon()
+ if ( IsValid( weapon ) )
+ ents.append( weapon )
+
+ return ents
+}
+
+/*
+void function PROTO_CapVelocity( player )
+{
+ player.EndSignal( "OnDeath" )
+ player.EndSignal( "StopPhaseShift" )
+
+ while( 1 )
+ {
+ local newVel = player.GetVelocity()
+ local zVel = newVel.z
+ newVel = Vector( newVel.x, newVel.y, 0 )
+ local speed = Length( newVel )
+ newVel = Normalize( newVel )
+ speed = min( speed, 400 )
+ newVel = newVel * speed
+ player.SetVelocity( Vector(newVel.x,newVel.y,zVel) )
+ WaitFrame()
+ }
+}
+*/
+
+void function UntrackAllToneMarks( entity ent )
+{
+ if ( IsSingleplayer() ) //JFS::Probably want to remove this for R3
+ return
+
+ array<entity> enemyTitans = GetTitanArrayOfEnemies( ent.GetTeam() )
+ foreach( titan in enemyTitans )
+ {
+ entity offhand = titan.GetOffhandWeapon( OFFHAND_RIGHT )
+ if ( !IsValid( offhand ) )
+ return
+
+ if ( offhand.GetWeaponClassName() != "mp_titanweapon_tracker_rockets" )
+ continue
+
+ offhand.SmartAmmo_UntrackEntity( ent )
+ }
+}
+#endif // #if SERVER
+
+
+#if CLIENT
+void function ClientPhaseShiftWarmupThread( entity player, float warmupTime )
+{
+ player.EndSignal( "OnDeath" )
+
+ if ( player != GetLocalViewPlayer() )
+ return
+ if ( InPrediction() && !IsFirstTimePredicted() )
+ return
+
+ if ( warmupTime <= 0 )
+ return
+
+ int index = GetParticleSystemIndex( SHIFTER_PRE_FX )
+ int fxID = StartParticleEffectInWorldWithHandle( index, ZERO_VECTOR, ZERO_VECTOR )
+
+ OnThreadEnd(
+ function() : ( fxID )
+ {
+ EffectStop( fxID, true, true );
+ }
+ )
+
+ if ( player.IsTitan() )
+ EmitSoundOnEntity( player, SHIFTER_PRE_SOUND_1P_TITAN )
+ else
+ EmitSoundOnEntity( player, SHIFTER_PRE_SOUND_1P )
+
+ wait warmupTime
+}
+
+void function ClientPhaseShiftFirstPersonFXThread()
+{
+ int effectSparkles;
+ int effectScreen;
+ bool effectsAreActive = false;
+ bool endSoundPlayed = false;
+ entity ourPlayer = null;
+
+ while( true )
+ {
+ if ( effectsAreActive )
+ {
+ entity localViewPlayer = GetLocalViewPlayer();
+
+ bool needShutdown = false;
+ if ( !IsValid( ourPlayer ) || !IsAlive( ourPlayer ) )
+ needShutdown = true;
+ else if ( ourPlayer != localViewPlayer )
+ needShutdown = true;
+ else if ( !ourPlayer.IsPhaseShifted() )
+ needShutdown = true;
+
+ if ( needShutdown )
+ {
+ if ( IsValid( ourPlayer ) && (ourPlayer == localViewPlayer) )
+ {
+ // FX
+ {
+ int fxIndex = GetParticleSystemIndex( SHIFTER_SCREEN_FX_START )
+ StartParticleEffectInWorldWithHandle( fxIndex, ZERO_VECTOR, ZERO_VECTOR )
+ }
+
+ // FX
+ {
+ int fxIndex = GetParticleSystemIndex( SHIFTER_APPEAR_FX )
+ vector viewAngles = ourPlayer.EyeAngles()
+ vector viewForward = AnglesToForward( viewAngles )
+ vector viewForward2d = Normalize( Vector( viewForward.x, viewForward.y, 0.0 ) )
+ StartParticleEffectOnEntityWithPos( ourPlayer, fxIndex, FX_PATTACH_ABSORIGIN, -1, (viewForward2d * 30), ZERO_VECTOR )
+ }
+
+ if ( ourPlayer.IsTitan() )
+ {
+ EmitSoundOnEntity( ourPlayer, SHIFTER_END_SOUND_1P_TITAN )
+ }
+ else
+ {
+ EmitSoundOnEntity( ourPlayer, SHIFTER_END_SOUND_1P )
+ }
+ StopSoundOnEntity( ourPlayer, SHIFTER_LOOP_SOUND_1P )
+ StopSoundOnEntity( ourPlayer, SHIFTER_LOOP_SOUND_1P_TITAN )
+ }
+
+ ClientPhaseShift_SCRIPT_HACKS_OFF()
+
+ EffectStop( effectSparkles, true, true )
+ EffectStop( effectScreen, true, true )
+ effectsAreActive = false;
+ ourPlayer = null;
+ endSoundPlayed = false;
+ }
+ else if ( IsValid( localViewPlayer ) && localViewPlayer.IsPhaseShifted() )
+ {
+ if ( !endSoundPlayed && (localViewPlayer.PhaseShiftTimeRemaining() <= SHIFTER_OUTRO_TIME_BEFORE_END) )
+ {
+ endSoundPlayed = true;
+ if ( localViewPlayer.IsTitan() )
+ EmitSoundOnEntity( localViewPlayer, SHIFTER_PRE_END_SOUND_1P_TITAN )
+ else
+ EmitSoundOnEntity( localViewPlayer, SHIFTER_PRE_END_SOUND_1P )
+ }
+ }
+
+ }
+
+ if ( !effectsAreActive )
+ {
+ entity localViewPlayer = GetLocalViewPlayer();
+
+ if ( IsValid( localViewPlayer ) && localViewPlayer.IsPhaseShifted() )
+ {
+ // FX
+ {
+ int fxIndex = GetParticleSystemIndex( SHIFTER_PERSONAL_FX )
+ int attachIdx = localViewPlayer.LookupAttachment( "CHESTFOCUS" )
+ effectSparkles = StartParticleEffectOnEntity( localViewPlayer, fxIndex, FX_PATTACH_POINT_FOLLOW, attachIdx )
+ }
+
+ // FX
+ {
+ int fxIndex = GetParticleSystemIndex( SHIFTER_SCREEN_FX )
+ effectScreen = StartParticleEffectInWorldWithHandle( fxIndex, ZERO_VECTOR, ZERO_VECTOR )
+ }
+
+ // FX
+ {
+ int fxIndex = GetParticleSystemIndex( SHIFTER_SCREEN_FX_START )
+ StartParticleEffectInWorldWithHandle( fxIndex, ZERO_VECTOR, ZERO_VECTOR )
+ }
+
+ // FX
+ {
+ entity viewModelEntity = localViewPlayer.GetViewModelEntity()
+ entity firstPersonProxy = localViewPlayer.GetPredictedFirstPersonProxy()
+
+ if ( IsValid( viewModelEntity ) )
+ {
+ viewModelEntity.Highlight_HideInside( 0.0 )
+ viewModelEntity.Highlight_HideOutline( 0.0 )
+ }
+
+ if ( IsValid( firstPersonProxy ) )
+ {
+ firstPersonProxy.Highlight_HideInside( 0.0 )
+ firstPersonProxy.Highlight_HideOutline( 0.0 )
+ }
+ }
+
+ ClientPhaseShift_SCRIPT_HACKS_ON()
+
+ if ( localViewPlayer.IsTitan() )
+ EmitSoundOnEntity( localViewPlayer, SHIFTER_START_SOUND_1P_TITAN )
+ else
+ EmitSoundOnEntity( localViewPlayer, SHIFTER_START_SOUND_1P )
+
+ if ( localViewPlayer.IsTitan() )
+ EmitSoundOnEntity( localViewPlayer, SHIFTER_LOOP_SOUND_1P_TITAN )
+ else
+ EmitSoundOnEntity( localViewPlayer, SHIFTER_LOOP_SOUND_1P )
+
+ effectsAreActive = true;
+ ourPlayer = localViewPlayer;
+ }
+ }
+
+ WaitFrame()
+ }
+}
+
+void function ClientRemoteTurretFirstPersonFXThread()
+{
+ int effectSparkles;
+ int effectScreen;
+ bool effectsAreActive = false;
+ entity ourPlayer = null;
+
+ const string TURRET_LOOP_SOUND = "Pilot_RemoteTurret_Loop_1P"
+
+ while( true )
+ {
+ if ( effectsAreActive )
+ {
+ entity localViewPlayer = GetLocalViewPlayer();
+
+ bool needShutdown = false;
+ if ( !IsValid( ourPlayer ) || !IsAlive( ourPlayer ) )
+ needShutdown = true;
+ else if ( ourPlayer != localViewPlayer )
+ needShutdown = true;
+ else if ( ourPlayer.GetRemoteTurret() == null )
+ needShutdown = true;
+
+ if ( needShutdown )
+ {
+ if ( IsValid( ourPlayer ) && (ourPlayer == localViewPlayer) )
+ StopSoundOnEntity( ourPlayer, TURRET_LOOP_SOUND )
+
+ effectsAreActive = false;
+ ourPlayer = null;
+ }
+ }
+
+ if ( !effectsAreActive )
+ {
+ entity localViewPlayer = GetLocalViewPlayer();
+ if ( IsValid( localViewPlayer ) && (localViewPlayer.GetRemoteTurret() != null) )
+ {
+ EmitSoundOnEntity( localViewPlayer, TURRET_LOOP_SOUND )
+ effectsAreActive = true;
+ ourPlayer = localViewPlayer;
+ }
+ }
+
+ WaitFrame()
+ }
+}
+
+void function ClientPhaseShift_SCRIPT_HACKS_ON()
+{
+ entity localViewPlayer = GetLocalViewPlayer();
+
+ localViewPlayer.Signal( "StartPhaseShift" )
+
+ if ( localViewPlayer == GetLocalClientPlayer() )
+ {
+ //localViewPlayer.cv.PlayerPetTitanIcon.Hide()
+ //localViewPlayer.cv.PlayerPetTitanArrow.Hide()
+ //localViewPlayer.cv.PlayerPetTitanLabel.Hide()
+ }
+}
+
+void function ClientPhaseShift_SCRIPT_HACKS_OFF()
+{
+ entity localViewPlayer = GetLocalViewPlayer();
+
+ if ( localViewPlayer == GetLocalClientPlayer() )
+ UpdatePetTitanIcon( localViewPlayer )
+
+ //It would be great if we could automatically hide icons using SetEntityOverhead if that entity is phased out.
+ // if ( GameRules_GetGameMode() == SURVIVOR )
+ // DisplayScrapCounter( GetLocalClientPlayer(), LIFE_ALIVE, LIFE_ALIVE )
+}
+
+#endif // #if CLIENT
|