//============================================================================= // KFDynamicFogAndDamageVolumeInfo //============================================================================= // A fog volume that can be dynamically blended in and out, and which can // also damage actors within the bounds of the volume //============================================================================= // Killing Floor 2 // Copyright (C) 2015 Tripwire Interactive LLC // - John "Ramm-Jaeger" Gibson //============================================================================= class KFDynamicFogAndDamageVolumeInfo extends FogVolumeConstantDensityInfo showcategories(Movement) placeable; /** The spawn group setup of a wave */ /** This property allows the fog volume to damage a player as long as they are within it. Using a negative value will allow the volume to have a regenerative effect. NB. bPainCausing must be set to TRUE to activate this */ var() float DamagePerSec; /** When damage is applied to an object, it is done so using a specific DamageType. Each available DamageType has a KDamageImpulse property which controls the magnitude of the impulse to be applied along the momentum vector. */ var() class DamageType; /** This property activates the ability to cause damage. Used in conjunction with DamagePerSecond and PainInterval */ var() bool bPainCausing; /** Amount of time, in seconds, between damage applications. NB. bPainCausing must be set to TRUE to activate this */ var() float PainInterval; /** True if this volume should damage zeds */ var() bool bDamageZeds; /** How long to take to blend fog in/out. Note: Damage blends in/out with the fading */ var() float FogBlendTime; /** The remaining time for this fog blend transition */ var float FogBlendTimeRemaining; /** Fog is blending in */ var bool bBlendingFogIn; /** Fog is blending out */ var bool bBlendingFogOut; /** Stores the old value of bEnabled for checking against */ var bool bOldEnabled; /** Fog is blending out */ var repnotify byte FogBlendAmountRep; /** What was the density when this fog volume spawned */ var float InitialDensity; /** What is the current fog density */ var float CurrentDensity; /** Temp message to play when this volume activates */ var() String ActivateMessage; /** Temp message to play when this volume deactivates */ var() String DeactivateMessage; replication { if (Role == ROLE_Authority) FogBlendAmountRep; } simulated event PostBeginPlay() { Super.PostBeginPlay(); // Store the initial density InitialDensity = FogVolumeConstantDensityComponent(DensityComponent).Density; CurrentDensity = InitialDensity; // Clear the density if it's not enabled, so it won't pop in with density if( !bEnabled ) { FogVolumeConstantDensityComponent(DensityComponent).Density = 0; ReattachComponent(DensityComponent); } if ( Role < ROLE_Authority ) return; if ( bPainCausing ) { SetTimer(PainInterval, true, nameof(TimerPop)); } } simulated event ReplicatedEvent(name VarName) { local float BlendedFogAmount; if (VarName == 'FogBlendAmountRep') { BlendedFogAmount = Float(FogBlendAmountRep)/255.0; SetFogDensity( BlendedFogAmount ); } else if (VarName != 'bEnabled') { Super.ReplicatedEvent(VarName); } } /* epic =============================================== * ::OnToggle * * Scripted support for toggling height fog, checks which * operation to perform by looking at the action input. * * Input 1: turn on * Input 2: turn off * Input 3: toggle * * ===================================================== */ simulated function OnToggle(SeqAct_Toggle action) { if (action.InputLinks[0].bHasImpulse) { // turn on StartBlendIn(); } else if (action.InputLinks[1].bHasImpulse) { // turn off StartBlendOut(); } else if (action.InputLinks[2].bHasImpulse) { // toggle if( bEnabled ) { StartBlendOut(); } else { StartBlendIn(); } } } /** Set the fog density and handle setting replicated fog density */ simulated function SetFogDensity( float NewDensity ) { if ( Role < ROLE_Authority ) { if( NewDensity == 0 ) { if( bOldEnabled ) Deactivate(); } else { if( !bOldEnabled ) Activate(); } } FogVolumeConstantDensityComponent(DensityComponent).Density = NewDensity * InitialDensity; CurrentDensity = FogVolumeConstantDensityComponent(DensityComponent).Density; if ( Role == ROLE_Authority ) { FogBlendAmountRep = CurrentDensity/InitialDensity * 255; bNetDirty = true; bForceNetUpdate = TRUE; } //`log("FogBlendAmountRep = "$FogBlendAmountRep$" CurrentDensity = "$CurrentDensity$" InitialDensity = "$InitialDensity); // Must reattach the component to get the fog values to change. TODO: this may be expensive, so might need a graphics programmer to improve this if( WorldInfo.NetMode != NM_DedicatedServer ) { ReattachComponent(DensityComponent); } } event Tick( float DeltaTime ) { if ( Role < ROLE_Authority ) return; if( bBlendingFogIn ) { FogBlendTimeRemaining -= DeltaTime; if( FogBlendTimeRemaining <= 0 ) { SetFogDensity( 1.0 ); bBlendingFogIn=false; //`log("Blending in complete, density = "$FogVolumeConstantDensityComponent(DensityComponent).Density); } else { SetFogDensity( 1.0 - (FogBlendTimeRemaining/FogBlendTime) ); //`log("Blending in, density = "$FogVolumeConstantDensityComponent(DensityComponent).Density$" blend time: "$(FogBlendTimeRemaining/FogBlendTime)); } } else if( bBlendingFogOut ) { FogBlendTimeRemaining -= DeltaTime; if( FogBlendTimeRemaining <= 0 ) { SetFogDensity( 0 ); bBlendingFogOut=false; //`log("Blending out complete, density = "$FogVolumeConstantDensityComponent(DensityComponent).Density); Deactivate(); } else { SetFogDensity( FogBlendTimeRemaining/FogBlendTime ); //`log("Blending out, density = "$FogVolumeConstantDensityComponent(DensityComponent).Density$" blend time: "$(FogBlendTimeRemaining/FogBlendTime)); } } } event Touch( Actor Other, PrimitiveComponent OtherComp, vector HitLocation, vector HitNormal ) { Super.Touch(Other, OtherComp, HitLocation, HitNormal); if ( (Other == None) || Other.bStatic ) return; if ( bPainCausing ) { if ( Other.bCanBeDamaged ) { if( bEnabled ) { CausePainTo(Other); } } } } function CausePainTo(Actor Other) { if( !bDamageZeds && KFPawn_Monster(Other) != none ) { return; } if (DamagePerSec > 0) { if ( (DamageType == None) || (DamageType == class'DamageType') ) `log("No valid damagetype ("$DamageType$") specified for "$PathName(self)); Other.TakeDamage(DamagePerSec*PainInterval*(CurrentDensity/InitialDensity), none/*DamageInstigator*/, Location, vect(0,0,1), DamageType,, self); //`log("Damaging other for "$DamagePerSec*PainInterval*(CurrentDensity/InitialDensity)); } else { Other.HealDamage(-DamagePerSec * PainInterval*(CurrentDensity/InitialDensity), none/*DamageInstigator*/, DamageType); } } /* TimerPop damage touched actors if pain causing. */ function TimerPop() { local Actor A; if( !bEnabled ) { return; } if ( !bPainCausing ) return; ForEach TouchingActors(class'Actor', A) { if ( A.bCanBeDamaged && !A.bStatic ) { CausePainTo(A); } } } /** Activate this fog volume */ simulated function Activate() { SetEnabled( true ); TempMessagePlayers( ActivateMessage ); } /** Deactivate this fog volume */ simulated function Deactivate() { if( bEnabled ) { TempMessagePlayers( DeactivateMessage ); } SetEnabled( false ); } /** Blend in and activate this fog volume */ simulated function StartBlendIn() { Activate(); bBlendingFogIn = true; bBlendingFogOut = false; FogBlendTimeRemaining = FogBlendTime; } /** Blend out and deactivate this fog volume */ simulated function StartBlendOut() { if( bEnabled ) { bBlendingFogOut = true; bBlendingFogIn = false; FogBlendTimeRemaining = FogBlendTime; } } /** Toggled the enabled setting for this fog volume */ simulated function SetEnabled( bool bNewEnabled ) { DensityComponent.SetEnabled(bNewEnabled); bEnabled = DensityComponent.bEnabled; bOldEnabled = bEnabled; ForceNetRelevant(); SetForcedInitialReplicatedProperty(Property'Engine.FogVolumeDensityInfo.bEnabled', (bEnabled == default.bEnabled)); NetUpdateFrequency = 5.0; } /** Temporary method of handling messaging the players for this volume */ simulated function TempMessagePlayers( coerce String Msg ) { `if(`notdefined(FINAL_RELEASE)) local KFPlayerController KFPC; `log( "!!!!"@Msg@"!!!!" ); foreach LocalPlayerControllers(class'KFPlayerController', KFPC) { KFPC.MyGFxHUD.ShowNonCriticalMessage( Msg ); } `endif } defaultproperties { Begin Object Name=AutomaticMeshComponent0 CollideActors=true StaticMesh=StaticMesh'EngineMeshes.Cube' bCastDynamicShadow=FALSE BlockActors=false BlockZeroExtent=false BlockNonZeroExtent=true BlockRigidBody=false bForceDirectLightMap=FALSE bAcceptsDynamicLights=FALSE bAcceptsLights=FALSE CastShadow=FALSE bUsePrecomputedShadows=FALSE bAcceptsStaticDecals=FALSE bAcceptsDynamicDecals=FALSE bUseAsOccluder=FALSE bSelectable=FALSE bIgnoreOwnerHidden=TRUE WireframeColor=(R=100,G=100,B=200,A=255) End Object bCollideActors=True DamageType=class'Engine.DamageType' PainInterval=1.f FogBlendTime=3.0 }