From 0e379c6509ee269b8ab1952248ec6886b542482f Mon Sep 17 00:00:00 2001 From: zxcPandora <81985226+zxcPandora@users.noreply.github.com> Date: Tue, 13 Sep 2022 23:29:01 +0800 Subject: [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> --- .../scripts/vscripts/weapons/sh_phase_shift.gnut | 774 +++++++++++++++++++++ 1 file changed, 774 insertions(+) create mode 100644 Northstar.CustomServers/mod/scripts/vscripts/weapons/sh_phase_shift.gnut (limited to 'Northstar.CustomServers/mod') 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 function GetAttachedEnts( entity ent ) +{ + array 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 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 -- cgit v1.2.3