//============================================================================= // Emitter actor class. // Copyright 1998-2013 Epic Games, Inc. All Rights Reserved. //============================================================================= class Emitter extends Actor native placeable; var() editconst const ParticleSystemComponent ParticleSystemComponent; var() editconst const DynamicLightEnvironmentComponent LightEnvironment; var bool bDestroyOnSystemFinish; var() bool bPostUpdateTickGroup; /** used to update status of toggleable level placed emitters on clients */ var repnotify bool bCurrentlyActive; `if(`__TW_) /** Allows particle emitters to omit depth testing (by setting to false) */ var transient bool bDepthTestEnabled; /** Allow this emitter to be rendered in the depth pass and be used as an occluder */ var(Rendering) const bool bUseAsOccluder; `endif struct CheckpointRecord { var bool bIsActive; }; replication { if (bNoDelete) bCurrentlyActive; } cpptext { void SetTemplate(UParticleSystem* NewTemplate, UBOOL bDestroyOnFinish=false); void AutoPopulateInstanceProperties(); // AActor interface. virtual void Spawned(); virtual void PostBeginPlay(); /** * ticks the actor * @param DeltaTime The time slice of this tick * @param TickType The type of tick that is happening * * @return TRUE if the actor was ticked, FALSE if it was aborted (e.g. because it's in stasis) */ virtual UBOOL Tick( FLOAT DeltaTime, enum ELevelTick TickType ); /** * Function that gets called from within Map_Check to allow this actor to check itself * for any potential errors and register them with map check dialog. */ #if WITH_EDITOR virtual void CheckForErrors(); #endif #if USE_GAMEPLAY_PROFILER /** * This function actually does the work for the GetProfilerAssetObject and is virtual. * It should only be called from GetProfilerAssetObject as GetProfilerAssetObject is safe to call on NULL object pointers */ virtual UObject* GetProfilerAssetObjectInternal() const; #endif /** * This will return detail info about this specific object. (e.g. AudioComponent will return the name of the cue, * ParticleSystemComponent will return the name of the ParticleSystem) The idea here is that in many places * you have a component of interest but what you really want is some characteristic that you can use to track * down where it came from. * */ virtual FString GetDetailedInfoInternal() const; /** * Called to reset the emitter actor in the level. * Intended for use in editor only */ void ResetInLevel(); #if __TW_ virtual void PostEditChangeProperty(FPropertyChangedEvent& PropertyChangedEvent); #endif } native noexport event SetTemplate(ParticleSystem NewTemplate, optional bool bDestroyOnFinish); simulated event PostBeginPlay() { Super.PostBeginPlay(); // Let them die quickly on a dedicated server if (WorldInfo.NetMode == NM_DedicatedServer && (RemoteRole == ROLE_None || bNetTemporary)) { LifeSpan = 0.2; `if(`__TW_PERFORMANCE_) // Lifespan won't do us much good for NoDelete actors! if ( bNoDelete ) { SetTickIsDisabled(true); } `endif } // Set Notification Delegate if (ParticleSystemComponent != None) { ParticleSystemComponent.OnSystemFinished = OnParticleSystemFinished; bCurrentlyActive = ParticleSystemComponent.bAutoActivate; `if(`__TW_) // Allow certain emitters to be rendered in the depth pass and be used as occluders ParticleSystemComponent.bUseAsOccluder = bUseAsOccluder; ReattachComponent(ParticleSystemComponent); `endif } } simulated event ReplicatedEvent(name VarName) { if (VarName == 'bCurrentlyActive') { ParticleSystemComponent.SetActive(bCurrentlyActive); } else { Super.ReplicatedEvent(VarName); } } simulated function OnParticleSystemFinished(ParticleSystemComponent FinishedComponent) { if (bDestroyOnSystemFinish) { Lifespan = 0.0001f; } bCurrentlyActive = false; } /** * Handling Toggle event from Kismet. */ function OnToggle(SeqAct_Toggle action) { // Turn ON if (action.InputLinks[0].bHasImpulse) { ParticleSystemComponent.ActivateSystem(); bCurrentlyActive = TRUE; } // Turn OFF else if (action.InputLinks[1].bHasImpulse) { ParticleSystemComponent.DeactivateSystem(); bCurrentlyActive = FALSE; } // Toggle else if (action.InputLinks[2].bHasImpulse) { // If spawning is suppressed or we aren't turned on at all, activate. if (ParticleSystemComponent.bSuppressSpawning || !bCurrentlyActive) { ParticleSystemComponent.ActivateSystem(); bCurrentlyActive = TRUE; } else { ParticleSystemComponent.DeactivateSystem(); bCurrentlyActive = FALSE; } } ParticleSystemComponent.LastRenderTime = WorldInfo.TimeSeconds; ForceNetRelevant(); if (RemoteRole != ROLE_None) { // force replicate flag if necessary SetForcedInitialReplicatedProperty(Property'Engine.Emitter.bCurrentlyActive', (bCurrentlyActive == default.bCurrentlyActive)); } } /** * Handling ParticleEventGenerator event from Kismet. * - Does nothing... just here to stop Kismet from complaining */ function OnParticleEventGenerator(SeqAct_ParticleEventGenerator action) { } simulated function ShutDown() { Super.ShutDown(); bCurrentlyActive = false; } simulated function SetFloatParameter(name ParameterName, float Param) { if (ParticleSystemComponent != none) ParticleSystemComponent.SetFloatParameter(ParameterName, Param); else `log("Warning: Attempting to set a parameter on "$self$" when the PSC does not exist"); } simulated function SetVectorParameter(name ParameterName, vector Param) { if (ParticleSystemComponent != none) ParticleSystemComponent.SetVectorParameter(ParameterName, Param); else `log("Warning: Attempting to set a parameter on "$self$" when the PSC does not exist"); } simulated function SetColorParameter(name ParameterName, color Param) { if (ParticleSystemComponent != none) ParticleSystemComponent.SetColorParameter(ParameterName, Param); else `log("Warning: Attempting to set a parameter on "$self$" when the PSC does not exist"); } simulated function SetExtColorParameter(name ParameterName, byte Red, byte Green, byte Blue, byte Alpha) { local color c; if (ParticleSystemComponent != none) { c.r = Red; c.g = Green; c.b = Blue; c.a = Alpha; ParticleSystemComponent.SetColorParameter(ParameterName, C); } else `log("Warning: Attempting to set a parameter on "$self$" when the PSC does not exist"); } simulated function SetActorParameter(name ParameterName, actor Param) { if (ParticleSystemComponent != none) ParticleSystemComponent.SetActorParameter(ParameterName, Param); else `log("Warning: Attempting to set a parameter on "$self$" when the PSC does not exist"); } /** * Kismet handler for setting particle instance parameters. */ simulated function OnSetParticleSysParam(SeqAct_SetParticleSysParam Action) { local int Idx, ParamIdx; if (ParticleSystemComponent != None && Action.InstanceParameters.Length > 0) { for (Idx = 0; Idx < Action.InstanceParameters.Length; Idx++) { if (Action.InstanceParameters[Idx].ParamType != PSPT_None) { // look for an existing entry ParamIdx = ParticleSystemComponent.InstanceParameters.Find('Name',Action.InstanceParameters[Idx].Name); // create one if necessary if (ParamIdx == -1) { ParamIdx = ParticleSystemComponent.InstanceParameters.Length; ParticleSystemComponent.InstanceParameters.Length = ParamIdx + 1; } // update the instance parm ParticleSystemComponent.InstanceParameters[ParamIdx] = Action.InstanceParameters[Idx]; if (Action.bOverrideScalar) { ParticleSystemComponent.InstanceParameters[ParamIdx].Scalar = Action.ScalarValue; } } } } } function bool ShouldSaveForCheckpoint() { return (bNoDelete && RemoteRole != ROLE_None); } function CreateCheckpointRecord(out CheckpointRecord Record) { Record.bIsActive = bCurrentlyActive; } function ApplyCheckpointRecord(const out CheckpointRecord Record) { bCurrentlyActive = Record.bIsActive; if (bCurrentlyActive) { ParticleSystemComponent.ActivateSystem(); } else { ParticleSystemComponent.DeactivateSystem(); } ForceNetRelevant(); } /** Function used to have the emitter hide itself and put itself into stasis **/ simulated function HideSelf(); defaultproperties { // Visual things should be ticked in parallel with physics TickGroup=TG_DuringAsyncWork Begin Object Class=SpriteComponent Name=Sprite Sprite=Texture2D'EditorResources.S_Emitter' HiddenGame=True AlwaysLoadOnClient=False AlwaysLoadOnServer=False bIsScreenSizeScaled=True ScreenSize=0.0025 SpriteCategoryName="Effects" End Object Components.Add(Sprite) Begin Object Class=ParticleSystemComponent Name=ParticleSystemComponent0 SecondsBeforeInactive=1 End Object ParticleSystemComponent=ParticleSystemComponent0 Components.Add(ParticleSystemComponent0) Begin Object Class=ArrowComponent Name=ArrowComponent0 ArrowColor=(R=0,G=255,B=128) ArrowSize=1.5 AlwaysLoadOnClient=False AlwaysLoadOnServer=False bTreatAsASprite=True SpriteCategoryName="Effects" End Object Components.Add(ArrowComponent0) bEdShouldSnap=true bHardAttach=true bGameRelevant=true bNoDelete=true `if(`__TW_) bDepthTestEnabled=true `endif SupportedEvents.Add(class'SeqEvent_ParticleEvent') }