//============================================================================= // KFWeap_ScopedBase //============================================================================= // Base class for weapons with scopes //============================================================================= // Killing Floor 2 // Copyright (C) 2015 Tripwire Interactive LLC // John "Ramm-Jaeger" Gibson //============================================================================= class KFWeap_ScopedBase extends KFWeapon abstract; /** component that renders the scene to a texture */ var(Scope) const TWSceneCapture2DDPGComponent SceneCapture; /** Ratio of the scope texture relative to screen resolution (Should be between 0.0-1.0) */ var (Scope) float ScopeTextureScale; /** Restrict the scene capture texture from getting too large, especially on ultra wide displays **/ var int MaxSceneCaptureSize; /** Name of the parameter used to blend between scene capture texture (when in ironsights) and regular texture (when hipped) 1.0 => Scene capture texture 0.0 => Generic texture */ var(Scope) name InterpParamName; /** Texture target to which the above SceneCapture component renders to */ var TextureRenderTarget2D SniperScopeTextureTarget; /** Template MIC used by the sniper scope. The MIC actually used by the scope should derive from this. This is necessary because Unreal warns against modifying an MIC in a package directly*/ var const MaterialInstanceConstant ScopeLenseMICTemplate; /** Actual MIC used by the scope */ var MaterialInstanceConstant ScopeLenseMIC; /** Current length of the square scope texture. This is checked against before modifying the ScopeTextureSize in the scenario when InitFOV is called multiple times with the same values */ var int CurrentScopeTextureSize; var(Scope) float ScopedSensitivityMod; /** MIC Index for the scope material */ var byte ScopeMICIndex; simulated exec function ScopeFOV( float NewFOV ) { //SetCaptureParameters( optional TextureRenderTarget2D NewTextureTarget = TextureTarget, // optional float NewFOV = FieldOfView, optional float NewNearPlane = NearPlane, // optional float NewFarPlane = FarPlane ); SceneCapture.SetCaptureParameters(,NewFOV); } /** Returns trader filter index based on weapon type (copied from riflebase) */ static simulated event EFilterTypeUI GetTraderFilter() { if( default.FiringStatesArray[DEFAULT_FIREMODE] == 'WeaponFiring' || default.FiringStatesArray[DEFAULT_FIREMODE] == 'WeaponBurstFiring' ) { return FT_Assault; } else // if( FiringStatesArray[DEFAULT_FIREMODE] == 'WeaponSingleFiring') { return FT_Rifle; } } /** * See Pawn.ProcessInstantHit * @param DamageReduction: Custom KF parameter to handle penetration damage reduction */ simulated function ProcessInstantHitEx(byte FiringMode, ImpactInfo Impact, optional int NumHits, optional out float out_PenetrationVal, optional int ImpactNum ) { local KFPerk InstigatorPerk; InstigatorPerk = GetPerk(); if( InstigatorPerk != none ) { InstigatorPerk.UpdatePerkHeadShots( Impact, InstantHitDamageTypes[FiringMode], ImpactNum ); } super.ProcessInstantHitEx( FiringMode, Impact, NumHits, out_PenetrationVal, ImpactNum ); } /** * Initialize the FOV settings for this weapon, adjusting for aspect ratio * @param SizeX the X resolution of the screen * @param SizeY the Y resolution of the screen * @param DefaultPlayerFOV the default player FOV of the player holding this weapon */ simulated function InitFOV(float SizeX, float SizeY, float DefaultPlayerFOV) { local int NewScopeTextureSize; super.InitFOV(SizeX, SizeY, DefaultPlayerFOV); NewScopeTextureSize = int(ScopeTextureScale*SizeX); if(NewScopeTextureSize > MaxSceneCaptureSize) NewScopeTextureSize = MaxSceneCaptureSize; if( CurrentScopeTextureSize != NewScopeTextureSize ) { SniperScopeTextureTarget = class'TextureRenderTarget2D'.static.Create(NewScopeTextureSize, NewScopeTextureSize, PF_FloatRGBA); SniperScopeTextureTarget.TargetGamma = 1.f; SceneCapture.SetCaptureParameters(SniperScopeTextureTarget); if( ScopeLenseMIC != none ) { ScopeLenseMIC.SetTextureParameterValue('ScopeTextureTarget', SniperScopeTextureTarget); } CurrentScopeTextureSize = NewScopeTextureSize; } } /** * Set parameters for the weapon once replication is complete (works in Standalone as well) */ reliable client function ClientWeaponSet(bool bOptionalSet, optional bool bDoNotActivate) { Super.ClientWeaponSet(bOptionalSet); // Only want to spawn sniper lenses on human players, but when PostBeginPlay // gets called Instigator isn't valid yet. So using NetMode == NM_Client, // since weapons should only exist on owning human clients with that netmode if( Instigator != none && Instigator.IsLocallyControlled() && Instigator.IsHumanControlled() ) { ScopeLenseMIC = new class'MaterialInstanceConstant'; ScopeLenseMIC.SetParent(ScopeLenseMICTemplate); ScopeLenseMIC.SetTextureParameterValue('ScopeTextureTarget', SniperScopeTextureTarget); ScopeLenseMIC.SetScalarParameterValue(InterpParamName, 0.0); mesh.SetMaterial(ScopeMICIndex, ScopeLenseMIC); } } /** * This function aligns the gun model in the world */ simulated event SetPosition(KFPawn Holder) { if ( !Holder.IsFirstPerson() ) return; super.SetPosition(Holder); if( ScopeLenseMIC != none ) { ScopeLenseMIC.SetScalarParameterValue('u_position_shadow', -WeaponLag.Y); ScopeLenseMIC.SetScalarParameterValue('v_position_shadow', WeaponLag.Z); } if( bUsingSights ) { SceneCapture.SetView(Location, Rotation); } } /** * Return an FOVAngle used by the PlayerInput class to determine how much to * reduce the sensitivity when using sights/scopes. Added since the 3d scope * zooms in farther than the player's FOV. */ simulated function float GetModifiedFOVAngle() { if( bUsingSights ) { return default.PlayerIronSightFOV/SceneCapture.FieldOfView * ScopedSensitivityMod; } else { return Super.GetModifiedFOVAngle(); } } /** * Attach Weapon Mesh, Weapon MuzzleFlash and Muzzle Flash Dynamic Light to a SkeletalMesh * * @param who is the pawn to attach to */ simulated function AttachWeaponTo( SkeletalMeshComponent MeshCpnt, optional Name SocketName ) { Super.AttachWeaponTo( MeshCpnt, SocketName ); if( Instigator != none ) { Instigator.AttachComponent(SceneCapture); } } /** * Detach weapon from skeletal mesh * * @param SkeletalMeshComponent weapon is attached to. */ simulated function DetachWeapon() { super.DetachWeapon(); if( Instigator != none ) { Instigator.DetachComponent(SceneCapture); } } /** * Tick the weapon (used for simple updates) * * @param DeltaTime Elapsed time. */ simulated event Tick(float DeltaTime) { local float InterpValue; local float DefaultZoomInTime; super.Tick(DeltaTime); if( ScopeLenseMIC == none ) { return; } if( Instigator != none && Instigator.Controller != none && Instigator.IsHumanControlled() ) { if( bZoomingOut ) { InterpValue = ZoomTime/default.ZoomOutTime; ScopeLenseMIC.SetScalarParameterValue(InterpParamName, InterpValue); } else if( bZoomingIn ) { DefaultZoomInTime = default.ZoomInTime; InterpValue = -ZoomTime/DefaultZoomInTime + 1; ScopeLenseMIC.SetScalarParameterValue(InterpParamName, InterpValue); } } } /** * Called by the native code when the interpolation of the first person weapon to the zoomed position finishes */ simulated event OnZoomInFinished() { if( ScopeLenseMIC != none ) { ScopeLenseMIC.SetScalarParameterValue(InterpParamName, 1.0); } super.OnZoomInFinished(); } /** * Called by the native code when the interpolation of the first person weapon from the zoomed position finishes */ simulated event OnZoomOutFinished() { if( ScopeLenseMIC != none ) { ScopeLenseMIC.SetScalarParameterValue(InterpParamName, 0.0); } super.OnZoomOutFinished(); } /** * Handles all the functionality for zooming in including * setting the parameters for the weapon, pawn, and playercontroller * * @param bAnimateTransition whether or not to animate this zoom transition */ simulated function ZoomIn(bool bAnimateTransition, float ZoomTimeToGo) { super.ZoomIn(bAnimateTransition, ZoomTimeToGo); if( SceneCapture != none && Instigator != none && !Instigator.PlayerReplicationInfo.bBot ) { SceneCapture.bEnabled=true; SceneCapture.SetFrameRate(SceneCapture.default.FrameRate); } ClearTimer(nameof(ZoomOutFastFinished)); } /** * Handles all the functionality for zooming out including * setting the parameters for the weapon, pawn, and playercontroller * * @param bAnimateTransition whether or not to animate this zoom transition */ simulated function ZoomOut(bool bAnimateTransition, float ZoomTimeToGo) { super.ZoomOut(bAnimateTransition, ZoomTimeToGo); if( !bAnimateTransition ) { SetTimer(ZoomTimeToGo + 0.01,false,nameof(ZoomOutFastFinished)); } else { if( SceneCapture != none && Instigator != none && !Instigator.PlayerReplicationInfo.bBot ) { SceneCapture.bEnabled=false; SceneCapture.SetFrameRate(0.0); } } } /** * Handles zoom out cleanup/finish after a "quick" zoom out, which doesn't normally do notifies */ simulated function ZoomOutFastFinished() { // Finish blacking out the lense when the fast zoom out finishes if( ScopeLenseMIC != none ) { ScopeLenseMIC.SetScalarParameterValue(InterpParamName, 0.0); } // Stop updating the scope when the fast zoom out finishes if( SceneCapture != none && Instigator != none && !Instigator.PlayerReplicationInfo.bBot ) { SceneCapture.bEnabled=false; SceneCapture.SetFrameRate(0.0); } } DefaultProperties { // 2D scene capture Begin Object Class=TWSceneCapture2DDPGComponent Name=SceneCapture2DComponent0 NearPlane=10 FarPlane=0 // NOTE: Far plane of 0 translates to infinity. Any other value here throws off the projection matrix ever so slightly which causes artifacts when doing position reconstruction during deferred lighting FieldOfView=6.0 // "4X" (approximate, since you have to eyeball it with 3d scopes) bEnabled=false ViewMode=SceneCapView_Lit FrameRate=60 bEnableFog=true bUpdateMatrices=false bRenderWorldDPG=true bRenderForegroundDPG=false End Object SceneCapture=SceneCapture2DComponent0 Components.Add(SceneCapture2DComponent0) ScopedSensitivityMod=6.0 InterpParamName=mat_blend_scaler ScopeTextureScale=0.5 //currently the materials don't go above 1024 MaxSceneCaptureSize=1024 // BASH_FIREMODE InstantHitDamage(BASH_FIREMODE)=15.0 // Aim Assist AimCorrectionSize=40.f ScopeMICIndex=2 }