Pipebombs

From Oldunreal-Wiki
Jump to navigation Jump to search

Ok, for this tutorial I'll show you how to code a near-perfect pipebomb cannon and a pipebomb. The whole thing is relatively simple so I'll just go straight into the basics with the code.

For the weapon, we'll have it fire out multiple pipebombs and have alt-fire detonate them. Here's the code for the weapon complete with comments:

class PipebombCannon expands TournamentWeapon;

var bool bAlreadyFiring;

// Don't really need this but I'm a lefty so it's nice to see a left handed model :-)
function setHand(float Hand)
{
 Super.SetHand(Hand);
 if ( Hand == 1 )
   Mesh = mesh(DynamicLoadObject("Botpack.PulseGunL", class'Mesh'));
 else
   Mesh = mesh'PulseGunR';
}
// Could use rateself but the bots didn't use the gun right
function PlayFiring() // Plays the firing animation
{
 Owner.PlaySound(FireSound, SLOT_Misc,2.0*Pawn(Owner).SoundDampening);
 PlayAnim( 'Boltend', 0.3 );    
 bWarnTarget = (FRand() < 0.2);

}

function AltFire( float Value ) // This is the main core of the gun
{
 local Vector Start, X,Y,Z;
 local Pipebomb PB;
 ForEach AllActors(class'PipeBomb', PB) // Calls all pipebomb actors
 {
   // Used settimer() because Explosion() blows player up
   PB.Settimer(0.000001, false);
 }
 // Necessary otherwise the gun gets jammed
 GoToState('AltFiring2');
}
//////////////////////////////////////////////////
// Normal projectile stuff
state NormalFire
{
 function Projectile ProjectileFire(class ProjClass, float ProjSpeed, bool bWarn)
 {
   local Projectile D;
   local int i;
   local vector Start,X,Y,Z;
   local Rotator StartRot, AltRotation;
   D = Global.ProjectileFire(ProjClass, ProjSpeed, bWarn);
   StartRot = D.Rotation;
   Start = D.Location;
   // Try changing 4 to 15 for ultimate carnage
   for (i = 0; i< 4; i++)
   {
     if (AmmoType.UseAmmo(1))
     {
       AltRotation = StartRot;
       AltRotation.Pitch += FRand()*3000-1500;
       AltRotation.Yaw += FRand()*3000-1500;
       AltRotation.Roll += FRand()*9000-4500;
       D = Spawn(ProjectileClass,,, Start - 2 * VRand(), AltRotation);
     }
   }
 }
Begin:
 FinishAnim();  
 PlayAnim('Still');
 Sleep(0.4);
 // Turns the pulsegun barrel at the end of firing
 PlayPostSelect();
 Finish()
}
///////////////////////////////////////////////////
// This just makes sure that the gun doesn't jam up
state AltFiring2
{
 function EndState()
 {
   Finish();
 }
 function AnimEnd()
 {
   Finish();
 }
Begin:
 GotoState('Idle');
}
///////////////////////////////////////////////////
function PlayIdleAnim()
{
 PlayAnim('Still');
}
defaultproperties
{
  AmmoName=Class'Botpack.PAmmo'
  PickupAmmoCount=40
  bAltWarnTarget=True
  FireOffset=(X=15.000000,Y=-15.000000,Z=2.000000)
  ProjectileClass=Class'Pipebomb'
  AltProjectileClass=Class'Botpack.Plasmasphere'br>    shakemag=120.000000
  AIRating=0.400000
  RefireRate=0.800000
  FireSound=Sound'UnrealShare.ASMD.TazerFire'
  SelectSound=Sound'Botpack.PulseGun.PulsePickup'
  Misc1Sound=Sound'UnrealShare.Stinger.EndFire'
  DeathMessage="%o was boomed by %k's %w"
  AutoSwitchPriority=6
  InventoryGroup=6
  PickupMessage="You picked up the Pipebomb cannon"
  ItemName="Pipebomb cannon"
  PlayerViewOffset=(X=1.700000,Z=-2.000000)
  PlayerViewMesh=LodMesh'Botpack.PulseGunR'
  PickupViewMesh=LodMesh'Botpack.PulsePickup'
  ThirdPersonMesh=LodMesh'Botpack.PulseGun3rd'
  ThirdPersonScale=0.400000
  PickupSound=Sound'UnrealShare.Pickups.WeaponPickup'
  Mesh=LodMesh'Botpack.PulsePickup'
  bNoSmooth=False
  SoundRadius=64
  SoundVolume=255
  CollisionRadius=27.000000
  CollisionHeight=8.000000
}

Ok, so as you can see, altfire is where the real difference is. Now all we need is a pipebomb. Here's the code, the projectile doesn't have to be anything special:

class Pipebomb expands Projectile;
var bool bCanHitOwner, bHitWater;
var float Count, SmokeRate;
var ScriptedPawn WarnTarget;
var int NumExtraGrenades;
simulated function PostBeginPlay()
{
 local vector X,Y,Z;
 local rotator RandRot;
 Super.PostBeginPlay();
 if ( Level.NetMode != NM_DedicatedServer )
   PlayAnim('WingIn');
 //This'll take a while to blow up
 SetTimer(999999+FRand()*1,false);
 if ( Role == ROLE_Authority )
 {
   GetAxes(Instigator.ViewRotation,X,Y,Z);  
   Velocity = X * (Instigator.Velocity Dot X)*0.4 + Vector(Rotation)
            * (Speed + FRand() * 100);
   Velocity.z += 210;
   RandRot.Pitch = FRand() * 1400 - 700;
   RandRot.Yaw = FRand() * 1400 - 700;
   RandRot.Roll = FRand() * 1400 - 700;
   MaxSpeed = 1000;
   Velocity = Velocity >> RandRot;
   RandSpin(50000);  
   bCanHitOwner = False;
   if (Instigator.HeadRegion.Zone.bWaterZone)
   {
     bHitWater = True;
     Disable('Tick');
     Velocity=0.6*Velocity;
   }
 }
}
simulated function ZoneChange( Zoneinfo NewZone )
{
 local waterring w;
 
 if (!NewZone.bWaterZone || bHitWater) Return;
 bHitWater = True;
 w = Spawn(class'WaterRing',,,,rot(16384,0,0));
 w.DrawScale = 0.2;
 w.RemoteRole = ROLE_None;
 Velocity=0.6*Velocity;
}
simulated function Timer()
{
 // Try to use Explosion in the alt-fire and for some reason the owner blows up
 Explosion(Location+Vect(0,0,1)*16);
}
simulated function Landed( vector HitNormal )
{
 HitWall( HitNormal, None );
}
simulated function ProcessTouch( actor Other, vector HitLocation )
{
 if ( (Other!=instigator) || bCanHitOwner )
   Explosion(HitLocation);
}
simulated function HitWall( vector HitNormal, actor Wall )
{
 bCanHitOwner = True;
 // Reflect off Wall w/damping
 Velocity = 0.8*(( Velocity dot HitNormal ) * HitNormal * (-2.0) + Velocity);
 RandSpin(100000);
 speed = VSize(Velocity);
 if ( Level.NetMode != NM_DedicatedServer )
   PlaySound(ImpactSound, SLOT_Misc, FMax(0.5, speed/800) );
 if ( Velocity.Z > 400 )
   Velocity.Z = 0.5 * (400 + Velocity.Z);
 else if ( speed < 20 )
 {
   bBounce = False;
   SetPhysics(PHYS_None);
 }
}
///////////////////////////////////////////////////////
function BlowUp(vector HitLocation)
{
 // Basic damage stuff
 HurtRadius(damage, 200, 'corroded', MomentumTransfer, HitLocation);
 MakeNoise(1.0);
}
simulated function Explosion(vector HitLocation)
{
 local UT_FlameExplosion s;
 BlowUp(HitLocation);
 s = spawn(class'UT_FlameExplosion',,,HitLocation);
 Spawn(Class'UT_Ringexplosion');
 s.RemoteRole = ROLE_None;
 Destroy();
}
defaultproperties
{
  speed=600.000000
  MaxSpeed=1000.000000
  Damage=90.000000
  MomentumTransfer=50000
  ImpactSound=Sound'UnrealShare.ASMD.TazerFire'
  Physics=PHYS_Falling
  RemoteRole=ROLE_SimulatedProxy
  AnimSequence=WingIn
  Texture=Texture'Botpack.ASMDAlt.ASMDAlt_a00'
  DrawScale=0.400000
  DrawType=DT_Sprite
  Style=STY_Translucent
  AmbientGlow=64
  bUnlit=True
  bBounce=True
  bFixedRotationDir=True
  DesiredRotation=(Pitch=12000,Yaw=5666,Roll=2334)
}

Ok, so basically what we have is a pulsegun that fires out a bunch of pipebombs. You can then use alt-fire to detonate them prematurely. This can probably be improved, for example there's no code to distinquish the owner of the pipebombs. So in theory any pipebombs on the level shot by anybody can be blown up. However this is just a simple example of a pipebomb weapon. Hope it helps.