VitalOverdose/SFX Painful
Part of Vital'sPMT
Overview
This is a custom emitter actor that can track up to 20 particles from 1 of its emitters (ActiveEmitterNumb) and cause pain to any pawn they collide with. Using an iterator in this way to scan the particles locations is fairly stressful to the CPU so I've capped the particles to 20. Its totally untested as yet as to how many can be tracked without out any significant drop in game play speed. If anyone does get round to testing it please let me know.
Properties
Note any changes to the properties will have to be made in the default properties by the mapper. Although you could write a custom spawner that can set the properties as the emitters are spawned (you cant change MaxParticles this way its a constant)
ActiveEmitterNumb access by DefaultProperties - The number of the emitter that is to be tracked. TimerFrequency access by DefaultProperties - The Scanning frequency capped to 0.1 of a second max (10x Scans a second); ScanSize access by DefaultProperties - the scan radius for each particle TheDamageType access by DefaultProperties - The damagetype to apply on contact with a pawn DamageToVec access by DefaultProperties - The damage amount for vehicles DamageToPawn access by DefaultProperties - The damage amount for xpawns DamageToMonster access by DefaultProperties - The Damage Amount for monsters VecCollisionFx access by DefaultProperties - The Collision FX for vehicles PawnCollisionFx access by DefaultProperties - The Collision FX for xpawns MonsterCollisionFx access by DefaultProperties - The Collision FX for monsters VecCollisionSound access by DefaultProperties - The collision Sound For vehicles PawnCollisionSound access by DefaultProperties - The collision Sound For xpawns MonsterCollisionSound access by DefaultProperties - The collision Sound For monsters
Simulated Function PostBeginPlay()
OK here is where the capping takes place any value set outside the range of the programmer has set results in the value being set at its max for the scan size and for its min on the timerfrequency.
The call to destroy the actor if set wrong may seem a little harsh but its not possible to alter the maxparticle count after game-play has started as its a constant variable;
The timer is started at the end of this function. Set to run continuously being called every timerFrequency seconds. This is of course the 'Scan Rate' for the tracked particles.
Simulated Function PostBeginPlay() { Super.PostBeginPlay(); If ( Emitters[ActiveEmitterNumb].MaxParticles > 20) { Destroyed(); } if (ScanSize < 64 ) { ScanSize=64; } if (TimerFrequency < 0.1) { TimerFrequency = 0.1; } SetTimer( TimerFrequency , true ); }
Simulated Function Timer()
Every time this function is called (once every Timerfrequency Seconds) the particles from the tracked emitter have their locations scanned with an iterator for any pawns. If one is found the valid ref for the pawn is bundled together with the velocity the particle was traveling at x 500 and set to the function ProcessCollision()
Simulated Function Timer() { local Pawn FoundPawn; Local Int Counter; for ( Counter=0 ; Counter < Emitters[ActiveEmitterNumb].Particles.Length ; Counter++ ) { foreach visiblecollidingActors(Class'Pawn', FoundPawn , ScanSize , Emitters[ActiveEmitterNumb].Particles[Counter].Location ) { ProcessCollision (FoundPawn ,Emitters[ActiveEmitterNumb].Particles[Counter].Velocity*500); } } }
Simulated Function ProcessCollision(Pawn CollidedWith, Vector ParticleMomentum)
Here the valid ref of the pawn the particle came in contact with is received along with a slightly increased velocity which comes in the form of a vector. Here the ProcessCollision is really just dealing out the pain ,sound and FX to the unlucky pawn who came in contact with the particle. As there's 3 different possible sets of sounds ,pain amount and fx (one of each for xpawn , monster and vec) it results in 3 lots of code. Ive used local variables to store what has to be played , spawned and ..er applied for each eventuality and then just applied it to one set of actions. This is about the only thing i could come up with to make this function slightly more efficient the just writing out 3 lots of the same code. If you know of a more efficient way of doing it please let me know. CaseSwitch may be more efficient IDK i haven't got round to using it yet.
Simulated function ProcessCollision(Pawn CollidedWith, vector Particlemomentum) { Local Int ThePain; local Emitter SpawnedFX; local Sound CollisionSound; local Class<emitter> Collisionfxclass; if ((CollidedWith.IsA('Vehicle')) && (DamageTovec !=0 )) { ThePain = DamageTovec; if (VecCollisionSound!=None) { CollisionSound=VecCollisionSound; } if ( VecCollisionFx != None ) { Collisionfxclass = VecCollisionFx; } } else if ((CollidedWith.IsA('monster')) && (DamageTomonster !=0 )) { ThePain = DamageTomonster; if (MonsterCollisionSound!=None) { CollisionSound=MonsterCollisionSound; } if ( VecCollisionFx != None ) { Collisionfxclass = MonsterCollisionFx; } } else if ( (CollidedWith.IsA('xPawn') ) && (DamageToPawn !=0 )) { ThePain = DamageToPawn; if (VecCollisionSound!=None) { CollisionSound=PawnCollisionSound; } if ( PawnCollisionFx != None ) { Collisionfxclass = PawnCollisionFx; } } if ( CollisionSound != none ) // dealing out the pain,the fx,and the sound { CollidedWith.PlaySound( CollisionSound ); } if ( Collisionfxclass != None ) { SpawnedFX = spawn(Collisionfxclass,CollidedWith,,CollidedWith.location,CollidedWith.rotation); } if ( ThePain != 0 ) { CollidedWith.TakeDamage( DamageToPawn, Instigator, CollidedWith.Location , Particlemomentum, TheDamageType ); } }
The Complete Script
Here is the completed script for now;-
//============================================================================= // SFX_Painful. //============================================================================= class SFX_Painful extends emitter Placeable; var int TotalParticles; // The mapper has no access to these Var () int ActiveEmitterNumb; // The mapper has no access to this property Var () int TimerFrequency; // The mapper has no access to this property Var () int DamageToPawn; // The mapper has no access to this property Var () int DamageToVec; // The mapper has no access to this property Var () int DamageToMonster; // The mapper has no access to this property Var () float ScanSize; // The mapper has no access to this property var () Class<DamageType> TheDamageType; // The mapper has no access to this property var () class <emitter> MonsterCollisionFx; var () class <emitter> VecCollisionFx; var () class <emitter> PawnCollisionFx; var () sound PawnCollisionSound; var () Sound VecCollisionSound; var () Sound MonsterCollisionSound; Simulated Function PostBeginPlay() { Super.PostBeginPlay(); If ( Emitters[ActiveEmitterNumb].MaxParticles > 20) { Destroyed(); } if (ScanSize < 64 ) { ScanSize=64; } if (TimerFrequency < 0.1) { TimerFrequency = 0.1; } SetTimer( TimerFrequency , true ); } Simulated Function Timer() { local Pawn FoundPawn; Local Int Counter; for ( Counter=0 ; Counter < Emitters[ActiveEmitterNumb].Particles.Length ; Counter++ ) { foreach visiblecollidingActors(Class'Pawn', FoundPawn , ScanSize , Emitters[ActiveEmitterNumb].Particles[Counter].Location ) { ProcessCollision (FoundPawn ,Emitters[ActiveEmitterNumb].Particles[Counter].Velocity*500); } } } Simulated function ProcessCollision(Pawn CollidedWith, vector Particlemomentum) { Local int ThePain; local emitter SpawnedFX; local sound CollisionSound; local class<emitter> Collisionfxclass; if ((CollidedWith.IsA('Vehicle')) && (DamageTovec !=0 )) { ThePain = DamageTovec; if (VecCollisionSound!=None) { CollisionSound=VecCollisionSound; } if ( VecCollisionFx != None ) { Collisionfxclass = VecCollisionFx; } } else if ((CollidedWith.IsA('monster')) && (DamageTomonster !=0 )) { ThePain = DamageTomonster; if (MonsterCollisionSound!=None) { CollisionSound=MonsterCollisionSound; } if ( VecCollisionFx != None ) { Collisionfxclass = MonsterCollisionFx; } } else if ( (CollidedWith.IsA('xPawn') ) && (DamageToPawn !=0 )) { ThePain = DamageToPawn; if (VecCollisionSound!=None) { CollisionSound=PawnCollisionSound; } if ( PawnCollisionFx != None ) { Collisionfxclass = PawnCollisionFx; } } // dealing out the pain,the fx,and the sound if ( CollisionSound != none ) { CollidedWith.PlaySound( CollisionSound ); } if ( Collisionfxclass != None ) { SpawnedFX = spawn(Collisionfxclass,CollidedWith,,CollidedWith.location,CollidedWith.rotation); } if ( ThePain != 0 ) { CollidedWith.TakeDamage( DamageToPawn, Instigator, CollidedWith.Location , Particlemomentum, TheDamageType ); } }
There may be some small alterations to this at a later date i have a few ideas of making it run more efficiantly so more than 20 particles can be tracked. But its all going to need some fairly detailed testing before i make any serious changes to the way it works.
Related Topics
- VitalOverdose/SFX Painful
- VitalOverdose/SFX VecTeleporting
- VitalOverdose/SFX PawnTeleporting
- VitalOverdose/SFX Triggering
- VitalOverdose/SFX Boosting
- VitalOverdose/SFX MonsterSpawning
- VitalOverdose/SFX Healing
- VitalOverdose/InventoryFlare
Discussion
DaWrecka: Have you considered making the emitter work server-side? If you could guarantee running on the server (which is required for dealing damage anyway) you can easily use Level.ControllerList. Since it's a linked list of nothing but controllers, you can vastly reduce the number of actors iterated through, since you can be sure that if Controller.Pawn != None, then the Pawn is a) a Pawn and not something else (obviously), b) Valid, and thus c) fair game. You're also not iterating through actors you wouldn't want damaged anyway like static meshes and brushes. The load will reduce vastly and consequently allow you to either use no cap or a much higher cap.