


This example will show how projectiles like the ripper blades are converted into a subclass of EnhancedProjectile.
Often projectiles will work if you just replace the "extends Projectile" in
the class declaration with "extends EnhancedProjectile", but they can't take
advantage of the features the EnhancedProjectile class offers.
Projectiles require a bit more work than the projectile weapon they are fired
from, but depending on the projectile there might be much less code in the
class than before. The changes include the use of the death message variables,
the DirectHit and/or SplashDamage functions and the
Explosion and SpawnSubmunition functions.
The advantage of placing the death messages in the projectile class will become
clearly visible if you try the following: Fire some ripper blades or shock
rifle plasma balls at a nenemy that is very far away and quickly switch to
another weapon, e.g. the impact hammer. If those shots kill the enemy you will
now get the death message message of the currently selected weapon, e.g.
"<your enemy's name> was smeared by <your name>'s
piston.", which obviously isn't the message that should be displayed.
Try to use the Explosion function to handle the projectile's
impact effect.
localized string ProjectileName
localized string DirectHitString
localized string SplashHitString
localized string HeadHitString
localized string SuicideString
localized string SuicideFString
localized string HeadSuicideString
localized string HeadSuicideFString%k (the killer's name),
%o (the victim's name), %w (the killer's weapon) and
%p (this projectile's name).%o, %w and
%p. If %o is not used the suicider's name is placed
in front of the message.%p in death messages. The headshot strings will only be used if
bCanHeadShoot is True. (see
EnhancedProjectile
for details)
Explosion (optional vector HitLocation,
optional vector HitNormal, optional actor HitActor) [simulated]
SplashDamage (optional vector HitLocation,
optional actor Other, optional vector HitNormal, optional bool bSpecialHit)DamageRadius > 0)
DirectHit (vector HitLocation, actor
Other, optional vector HitNormal, optional bool bSpecialHit)DamageRadius == 0)
SpawnSubMunition (vector HitLocation,
vector HitNormal, int Number)
SpawnExplosionEffects (vector HitLocation,
vector HitNormal) [simulated]
BlowUp (vector HitLocation)
Destroy ( )SpawnSubMunition function spawns the amount and type of
projectiles specified in the SubMunitionCount and
SubMunitionClass. These projectiles can be modified through the
ModifySubMunition function.SpawnExplosionEffects creates the visual impact effects
(ExplosionEffectClass) and decals (ExplosionDecal).DirectHit
instead of TakeDamage and SplashDamage instead of
HurtRadius unless you are sure that no player is going to be hit,
because these functions activate the death messages. If you want to have the
death messages when killing a pawn with the Died function you can
use these functions:
SetKillType (bool bSplashHit, bool
bHeadHit) [final]
RestoreKillType ( ) [final]SetKillType activates the specified type of death message and
RestoreKillType resets it.
The ripper blades are an excellent example, since they are capable of doing
headshots, they can hit their owner and with secondary firing mode they can
also do splash damage.
First we'll look at the Razor2 class, then we'll change the
Razor2Alt class. Start by copying both classes and let them extend
from EnhancedProjectile. Delete the #exec lines. The original
Ripper's models, textures and sounds can be used.
The first thing we'll change in Razor2 is the
ProcessTouch function of the Flying state:
simulated function ProcessTouch (Actor Other, Vector HitLocation) // old
{
if ( bCanHitInstigator || (Other != Instigator) )
{
if ( Role == ROLE_Authority )
{
if ( Other.bIsPawn && (HitLocation.Z - Other.Location.Z > 0.62 * Other.CollisionHeight)
&& (!Instigator.IsA('Bot') || !Bot(Instigator).bNovice) )
Other.TakeDamage(3.5 * damage, instigator,HitLocation,
(MomentumTransfer * Normal(Velocity)), 'decapitated' );
else
Other.TakeDamage(damage, instigator,HitLocation,
(MomentumTransfer * Normal(Velocity)), 'shredded' );
}
if ( Other.bIsPawn )
PlaySound(MiscSound, SLOT_Misc, 2.0);
else
PlaySound(ImpactSound, SLOT_Misc, 2.0);
destroy();
}
}
simulated function ProcessTouch (Actor Other, Vector HitLocation) // new
{
if ( bCanHitInstigator || Other != Instigator ) {
if ( Other != None && Other.bIsPawn )
PlaySound(MiscSound, SLOT_Misc, 2.0);
else
PlaySound(ImpactSound, SLOT_Misc, 2.0);
Explosion(HitLocation,,Other);
}
}
As you can see there's much less code in that function now. The missing code
will not be added anywhere else, everything is handled in the
Explosion function.defaultproperties section:
defaultproperties
{
DirectHitString="%k ripped a chunk of meat out of %o with the %w."
SplashHitString="%k killed %o with an explosive %p."
HeadHitString="%k ripped %o's head off!"
SuicideString=" ripped into himself."
SuicideFString=" ripped into herself."
HeadSuicideString=" ripped his own head off."
HeadSuicideFString=" ripped her own head off."
bCanHeadShoot=True
HeadShotDamageFactor=3.500000
MyDamageType=Sliced
FiredFrom=<your ripper class here>
ProjectileName="ripper blade"
(...)
}
For some reason the damage type was not specified here. (And 'sliced' sounds
much more descriptive than 'shredded' in this case.) Set FiredFrom
to the class of the ripper you created in the Ripper
I tutorial.HeadDamageType is not set here, since we
still want the "Head Shot!" announcement, which will only be
displayed when the damage type is 'Decapitated', the default value of
HeadDamageType.SplashHitString could have been added to the alt fire ripper
blade, but it's nicer to have all those strings in one class, if you want to
translate them using localization files.ProcessTouchExplodeBlowUpif ( Level.bDropDetail )to
if ( Level.bDropDetail || (bDropEffects && !bKeepLightEffects) )in the
PostBeginPlay function. This will disable the light effect
of the explosive blade not only in the frame rate is low, but also if the
player chose to drop some effects to further increase performance.HitWall function from
Super(Projectile).HitWall(HitNormal, Wall);to
Super(EnhancedProjectile).HitWall(HitNormal, Wall);The reason for that change is pretty obvious: The primary blade's parent class is EnhancedProjectile now, instead of Projectile.
defaultproperties
section. Remove the MomentumTransfer and MyDamageType
lines and add:
bCanHeadShoot=False
SplashDamageType=RipperSplashDamage
DamageRadius=180.000000
SplashMomentum=87000.000000
ExplosionEffectClass=Class'Botpack.RipperPulse'
ExploWallOut=16.000000
The alt firing blade cannot cause headshots, but it does splash damage and
plays and explosion animation.Congratulations! You can now compile and test your new Ripper.