//========================================= // CinematicPoint //========================================= class CinematicPoint extends Keypoint; enum EInterpolation { INTERP_Linear, INTERP_QuadIn, INTERP_QuadOut, INTERP_QuadInOut, INTERP_CubicIn, INTERP_CubicOut, INTERP_CubicInOut }; enum EPlaybackPosition { PP_Beginning, PP_End }; // Adjustable properties var() EInterpolation Interpolation; // Interpolation algorithm var() bool bReleaseTarget; // If this point is the last one, return the actor to its normal state var() bool bTargetHidden; // Whether to hide the actor var() float DelayAfter; // Second to wait before triggering the next point var() float Duration; // How long the interpolation takes var() float FOV; // The desired FOV var() name TargetTag; // The tag of the actor, set this to "Player" for camera control var(Sound) ESoundSlot TransientSoundSlot; // The slot in which to play the transient sound var(Sound) Sound TransientSound; // A sound to play once var(Sound) float TransientSoundPitch; // The pitch at which to play the transient sound var(Sound) EPlaybackPosition TransientSoundPosition; // When to play the transient sound var(Animation) name AnimationSequence; // Which animation to play on the target actor var(Animation) float AnimationRate; // The speed of the animation var(Animation) float AnimationTweenTime; // The speed at which to blend between animations var(Animation) bool bLoopAnimation; // Whether to loop the animation var(Animation) EPlaybackPosition AnimationPosition; // When to play the animation // Internal variables var Actor aTarget; // The target actor to interpolate var DeusExPlayer aPlayer; // Useful reference to the player var Sound AmbientSoundStore; // Store the AmbientSound here instead, to prevent the point itself from emitting it var bool bIsFirst; // Whether this point is the first in the event chain var bool bIsLast; // Whether this point is the last in the event chain var float CurTime; // Time elapsed since the point was triggered var bool bWaitingToStart; // Whether we're waiting to start // Interpolation variables var Rotator StartRotation; var Vector StartLocation; var float StartFOV; var float StartSoundPitch; var float StartSoundVolume; // Defaults defaultproperties { AnimationRate=1.0 AnimationTweenTime=1.0 CollisionHeight=0.000000 CollisionRadius=0.000000 SoundPitch=64 SoundRadius=32 SoundVolume=128 TransientSoundPitch=1.0 TransientSoundRadius=128.0 bDirectional=True bLoopAnimation=True bStatic=False } // ----------------- // We're in the game // ----------------- event BeginPlay() { AmbientSoundStore = AmbientSound; AmbientSound = None; } // ----------------------------- // Check if we're the last point // ----------------------------- function bool IsLast() { local CinematicPoint aCinematicPoint; if(Event == '') return True; foreach AllActors(class'CinematicPoint', aCinematicPoint, Event) { return False; } return True; } // ------------------------------ // Check if we're the first point // ------------------------------ function bool IsFirst() { local CinematicPoint aCinematicPoint; foreach AllActors(class'CinematicPoint', aCinematicPoint) { if(aCinematicPoint.Event == Tag) return False; } return True; } // ----------------------------------- // Triggers the next event in the chain // ----------------------------------- function TriggerNext() { local Actor aTriggerActor; local DeusExPlayer aPlayer; if(Event == '') return; aPlayer = DeusExPlayer(GetPlayerPawn()); foreach AllActors(class'Actor', aTriggerActor, Event) { aTriggerActor.Trigger(Self, aPlayer); } } // ---------------------- // Initializes this point // ---------------------- function Init() { local Actor aActor; aPlayer = DeusExPlayer(GetPlayerPawn()); if(TargetTag == 'Player') { aTarget = aPlayer; } else { foreach AllActors(class'Actor', aActor, TargetTag) { aTarget = aActor; break; } } bIsLast = IsLast(); bIsFirst = IsFirst(); } // ------------------- // Plays the animation // ------------------- function PlayAnimation() { if(AnimationSequence == '' || aTarget == None) return; if(bLoopAnimation) aTarget.LoopAnim(AnimationSequence, AnimationRate, AnimationTweenTime); else aTarget.PlayAnim(AnimationSequence, AnimationRate, AnimationTweenTime); } // ------------------------- // Plays the transient sound // ------------------------- function PlayTransientSound() { if(TransientSound == None || aTarget == None) return; aTarget.PlaySound(TransientSound, TransientSoundSlot, TransientSoundVolume, False, TransientSoundRadius, TransientSoundPitch); } // ----------------- // Starts this point // ----------------- function StartInterpolation() { local Rotator NewRotation; if(aTarget == None) return; // Clamp rotation for better interpolation NewRotation.Pitch = Rotation.Pitch % 65536; NewRotation.Yaw = Rotation.Yaw % 65536; NewRotation.Roll = Rotation.Roll % 65536; SetRotation(NewRotation); NewRotation.Pitch = aTarget.Rotation.Pitch % 65536; NewRotation.Yaw = aTarget.Rotation.Yaw % 65536; NewRotation.Roll = aTarget.Rotation.Roll % 65536; aTarget.SetRotation(NewRotation); // Save the beginning values StartLocation = aTarget.Location; StartRotation = aTarget.Rotation; StartSoundVolume = aTarget.SoundVolume; StartSoundPitch = aTarget.SoundPitch; StartFOV = aPlayer.FOVAngle; // If the target is a player, turn it into a camera if(aTarget == aPlayer) { StartRotation = aPlayer.ViewRotation; aPlayer.ShowHUD(False); aPlayer.Ghost(); aPlayer.GoToState('Paralyzed', 'Letterbox'); aPlayer.bHidden = True; aPlayer.bCollideWorld = False; aPlayer.SetCollision(False, False, False); aPlayer.bDetectable = False; aPlayer.Visibility = 0; if(aPlayer.Shadow != None) { aPlayer.Shadow.Destroy(); aPlayer.Shadow = None; } } else { aTarget.SetCollision(False, False, False); aTarget.bCollideWorld = False; aTarget.SetPhysics(PHYS_None); aTarget.PhysRate = 1.0; aTarget.PhysAlpha = 0.0; aTarget.bStasis = False; } // Play stuff if(TransientSoundPosition == PP_Beginning) PlayTransientSound(); if(AnimationPosition == PP_Beginning) PlayAnimation(); if(AmbientSoundStore != aTarget.AmbientSound) aTarget.AmbientSound = AmbientSoundStore; } // ---------------------------------------------------------------------------- // Calculates a smoothing coefficient based on the specified interpolation type // ---------------------------------------------------------------------------- function float GetSmoothingCoefficient(float Alpha) { if(Interpolation == INTERP_QuadIn) { return Alpha * Alpha; } else if(Interpolation == INTERP_QuadOut) { return Alpha * (2.0 - Alpha); } else if(Interpolation == INTERP_QuadInOut) { if ((Alpha *= 2.0) < 1.0) { return 0.5 * Alpha * Alpha; } Alpha -= 1.0; return - 0.5 * (Alpha * (Alpha - 2.0) - 1.0); } else if(Interpolation == INTERP_CubicIn) { return Alpha * Alpha * Alpha; } else if(Interpolation == INTERP_CubicOut) { Alpha -= 1.0; return Alpha * Alpha * Alpha + 1; } else if(Interpolation == INTERP_CubicInOut) { Alpha *= 2.0; if (Alpha < 1.0) { return 0.5 * Alpha * Alpha * Alpha; } Alpha -= 2.0; return 0.5 * (Alpha * Alpha * Alpha + 2.0); } else { return Alpha; } } // ---------------------- // Ends the interpolation // ---------------------- function EndInterpolation() { if(aTarget == None) return; if(TransientSoundPosition == PP_End) PlayTransientSound(); if(AnimationPosition == PP_End) PlayAnimation(); // Snap target to desired values if(aTarget == aPlayer) { aPlayer.ViewRotation = Rotation; } else { aTarget.SetRotation(Rotation); } if(FOV > 0) { aPlayer.SetFOVAngle(FOV); aPlayer.DesiredFOV = FOV; } aTarget.SetLocation(Location); aTarget.AmbientSound = None; } // -------------------------- // Finishes the interpolation // -------------------------- function Finish() { if(aTarget != None) { if(bIsLast && bReleaseTarget) { aTarget.bCollideWorld = True; aTarget.bHidden = False; aTarget.SetCollision(True, True, True); if(aTarget == aPlayer) { aPlayer.GoToState('PlayerWalking'); aPlayer.bDetectable = True; aPlayer.BaseEyeHeight = aPlayer.Default.BaseEyeHeight; aPlayer.ShowHUD(True); aPlayer.Visibility = 1; if(aPlayer.Shadow == None) { aPlayer.CreateShadow(); } } else { aTarget.SetPhysics(PHYS_None); aTarget.GotoState('Idle'); aTarget.bStasis = True; } } } // Trigger the next event TriggerNext(); } // --------------------------- // Processes the interpolation // --------------------------- function Process(float DeltaTime) { local float Alpha, Beta; local Vector CurLoc; local Vector DiffLoc; local Rotator CurRot, DiffRot; local float CurFOV; // Calculate our smoothing coefficient Alpha = FClamp(CurTime / Duration, 0.0, 1.0); Beta = GetSmoothingCoefficient(Alpha); // Hide/unhide the target if(aTarget.bHidden != bTargetHidden) { aTarget.bHidden = bTargetHidden; } // Make sure we rotate the shortest direction DiffRot = Rotation - StartRotation; if (DiffRot.Pitch >= 32768) DiffRot.Pitch = DiffRot.Pitch - 65536; else if (DiffRot.Pitch <= -32768) DiffRot.Pitch = DiffRot.Pitch + 65536; if (DiffRot.Yaw >= 32768) DiffRot.Yaw = DiffRot.Yaw - 65536; else if (DiffRot.Yaw <= -32768) DiffRot.Yaw = DiffRot.Yaw + 65536; if (DiffRot.Roll >= 32768) DiffRot.Roll = DiffRot.Roll - 65536; else if (DiffRot.Roll <= -32768) DiffRot.Roll = DiffRot.Roll + 65536; DiffLoc = Location - StartLocation; // Interpolate the sound values aTarget.SoundVolume = Lerp(Alpha, StartSoundVolume, SoundVolume); aTarget.SoundPitch = Lerp(Alpha, StartSoundPitch, SoundPitch); // Interpolate the camera rotation, movement, and FOV CurRot = StartRotation + Beta * DiffRot; CurLoc = StartLocation + Beta * DiffLoc; if(FOV > 0) { CurFOV = StartFOV + Beta * (FOV - StartFOV); aPlayer.SetFOVAngle(CurFOV); aPlayer.DesiredFOV = CurFOV; } aTarget.SetLocation(CurLoc); if(aTarget == aPlayer) { if(bIsLast && bReleaseTarget) { aPlayer.BaseEyeHeight = Lerp(Alpha, 0.0, aPlayer.Default.BaseEyeHeight); } else { aPlayer.BaseEyeHeight = Lerp(DeltaTime, aPlayer.BaseEyeHeight, 0.0); } aPlayer.ViewRotation = CurRot; } else { aTarget.SetRotation(CurRot); } } // ------ // States // ------ auto state Idle { function Trigger(Actor Other, Pawn Instigator) { Super.Trigger(Other, Instigator); Init(); bWaitingToStart = True; } function Tick(float DeltaTime) { if(bWaitingToStart && !aPlayer.InConversation()) { bWaitingToStart = False; StartInterpolation(); GoToState('Running'); } Super.Tick(DeltaTime); } } state Running { function Tick(float DeltaTime) { CurTime += DeltaTime; if (CurTime >= Duration) { EndInterpolation(); GoToState('Waiting'); } else { Process(DeltaTime); } Super.Tick(DeltaTime); } } state Waiting { function Tick(float DeltaTime) { CurTime += DeltaTime; if (CurTime >= Duration + DelayAfter) { Finish(); GoToState('Idle'); } Super.Tick(DeltaTime); } }