--------------------------------------------------------------------------------------------
Greande Fountain Tutorial
--------------------------------------------------------------------------------------------
This tutorial makes a weapon that fires a non-heat seaking missile, when the fire button is pressed a second time, it detonates the missile and drops a bunch of grenades over the area the missile detonates. To make depth perception easier, I added a tracking effect with a flattened out nexus effect that follows under the missile along the ground so you can easily see where to detonate it over. This is recommended for heavies only.
Step #1
// ------------------------------------------
// inventoryHud.cs
// ------------------------------------------

1a) Add these to the top of the file.

$InvWeapon[13] = "Grenade Fountain";

$NameToInv["Grenade Fountain"] = "GrenadeFountain";


1b) Add this to function buyFavorites and function buyDeployableFavorites

         case GrenadeFountain:
            %client.player.setInventory( GrenadeFountainAmmo, 400 );


Step #2
// ------------------------------------------
// weapons.cs
// ------------------------------------------

$WeaponsHudData[13, bitmapName]   = "gui/hud_grenlaunch";
$WeaponsHudData[13, itemDataName] = "GrenadeFountain";
$WeaponsHudData[13, ammoDataName] = "GrenadeFountainAmmo";

$WeaponsHudCount = 14;

$AmmoIncrement[GrenadeFountainAmmo]        = 5;

exec("scripts/weapons/GrenadeFountain.cs");


Step #3
// ------------------------------------------
// inventory.cs
// ------------------------------------------

3a) Add this with all the other 'case' in the function

function ShapeBase::hasAmmo( %this, %weapon )
{
   switch$ ( %weapon )
   {
      case GrenadeFountain:
         return( %this.getInventory( GrenadeFountainAmmo ) > 0 );
   }
}


3b) Add this with all the other cleared items

function ShapeBase::clearInventory(%this)
{
   %this.setInventory(GrenadeFountain, 0);
   %this.setInventory(GrenadeFountainAmmo, 0);
}


3c)

function serverCmdGiveAll(%client)
{
   if($TestCheats)
   {
      %player.setInventory(GrenadeFountain, 1);
      %player.setInventory(GrenadeFountainAmmo, 999);
   }
}


Step #4
// ------------------------------------------
// player.cs
// ------------------------------------------
4a) Add to player armor datablocks. Probably only want to give it to heavies.

max [GrenadeFountain] = 1;
max [GrenadeFountainAmmo] = 10;


4b)  Add these to function armor::applyConcussion

      if( %weaps[13] = %player.getInventory("GrenadeFountain") > 0 ) %numWeapons++;

and

      case 13:
         %player.use("GrenadeFountain");


Step #5
// ------------------------------------------
// hud.cs
// ------------------------------------------
Ignore this step if you use any server side reticle workarounds.

function clientCmdSetWeaponsHudActive(%slot)
{
   weaponsHud.setActiveWeapon(%slot);
   switch$($WeaponNames[%slot])
   {
      case "GrenadeFountain":
         reticleHud.setBitmap("gui/ret_missile");
         reticleFrameHud.setVisible(true);
   }
}


Step #6
// ------------------------------------------
// Ammopack.cs
// ------------------------------------------
Add ammo to ammopack, to increase with it.

$ammoItem[9] = GrenadeFountainAmmo;
$numAmmoItems = 10;

datablock ItemData(AmmoPack)
{
   max[GrenadeFountainAmmo] = 10;
}


Step #7
// ------------------------------------------
// OptionsDlg.cs
// ------------------------------------------
$RemapName[$RemapCount] = "GrenadeFountain";
$RemapCmd[$RemapCount] = "useGrenadeFountain";
$RemapCount++;


Step #8
// ------------------------------------------
// ControlDefaults.cs
// ------------------------------------------

function useGrenadeFountain( %val )
{
   if ( %val )
     use( GrenadeFountain );
}


Step #9
// ------------------------------------------
// GrenadeFountain.cs
// ------------------------------------------
Create a file called GrenadeFountain.cs in your weapon's directory. Add all this into it.


//--------------------------------------
// GrenadeFountain launcher
//--------------------------------------

//--------------------------------------------------------------------------
// Force-Feedback Effects
//--------------------------------------
datablock EffectProfile(GrenadeFountainSwitchEffect)
{
   effectname = "weapons/missile_launcher_activate";
   minDistance = 2.5;
   maxDistance = 2.5;
};

datablock EffectProfile(GrenadeFountainFireEffect)
{
   effectname = "weapons/missile_fire";
   minDistance = 2.5;
   maxDistance = 5.0;
};

datablock EffectProfile(GrenadeFountainDryFireEffect)
{
   effectname = "weapons/missile_launcher_dryfire";
   minDistance = 2.5;
   maxDistance = 2.5;
};

datablock EffectProfile(GrenadeFountainExplosionEffect)
{
   effectname = "explosions/explosion.xpl23";
   minDistance = 10;
   maxDistance = 30;
};

//--------------------------------------------------------------------------
// Sounds
//--------------------------------------
datablock AudioProfile(GrenadeFountainSwitchSound)
{
   filename    = "fx/weapons/missile_launcher_activate.wav";
   description = AudioClosest3d;
   preload = true;
   effect = GrenadeFountainSwitchEffect;
};

datablock AudioProfile(GrenadeFountainFireSound)
{
   filename    = "fx/weapons/missile_fire.WAV";
   description = AudioDefault3d;
   preload = true;
   effect = GrenadeFountainFireEffect;
};

datablock AudioProfile(GrenadeFountainProjectileSound)
{
   filename    = "fx/weapons/missile_projectile.wav";
   description = ProjectileLooping3d;
   preload = true;
};

datablock AudioProfile(GrenadeFountainReloadSound)
{
   filename    = "fx/weapons/weapon.missilereload.wav";
   description = AudioClosest3d;
   preload = true;
};

datablock AudioProfile(GrenadeFountainLockSound)
{
   filename    = "fx/weapons/missile_launcher_searching.WAV";
   description = AudioClosest3d;
   preload = true;
};

datablock AudioProfile(GrenadeFountainExplosionSound)
{
   filename    = "fx/explosions/explosion.xpl23.wav";
   description = AudioBIGExplosion3d;
   preload = true;
   effect = GrenadeFountainExplosionEffect;
};

datablock AudioProfile(GrenadeFountainDryFireSound)
{
   filename    = "fx/weapons/missile_launcher_dryfire.wav";
   description = AudioClose3d;
   preload = true;
   effect = GrenadeFountainDryFireEffect;
};


//----------------------------------------------------------------------------
// Splash Debris
//----------------------------------------------------------------------------
datablock ParticleData( MDebrisSmokeParticle )
{
   dragCoeffiecient     = 1.0;
   gravityCoefficient   = 0.10;
   inheritedVelFactor   = 0.1;

   lifetimeMS           = 1000;
   lifetimeVarianceMS   = 100;

   textureName          = "particleTest";

//   useInvAlpha =     true;

   spinRandomMin = -60.0;
   spinRandomMax = 60.0;

   colors[0]     = "0.7 0.8 1.0 1.0";
   colors[1]     = "0.7 0.8 1.0 0.5";
   colors[2]     = "0.7 0.8 1.0 0.0";
   sizes[0]      = 0.0;
   sizes[1]      = 0.8;
   sizes[2]      = 0.8;
   times[0]      = 0.0;
   times[1]      = 0.5;
   times[2]      = 1.0;
};

datablock ParticleEmitterData( MDebrisSmokeEmitter )
{
   ejectionPeriodMS = 10;
   periodVarianceMS = 1;

   ejectionVelocity = 1.0;  // A little oomph at the back end
   velocityVariance = 0.2;

   thetaMin         = 0.0;
   thetaMax         = 40.0;

   particles = "MDebrisSmokeParticle";
};


datablock DebrisData( GrenadeFountainSplashDebris )
{
   emitters[0] = MDebrisSmokeEmitter;

   explodeOnMaxBounce = true;

   elasticity = 0.4;
   friction = 0.2;

   lifetime = 0.3;
   lifetimeVariance = 0.1;

   numBounces = 1;
};


//----------------------------------------------------------------------------
// GrenadeFountain smoke spike (for debris)
//----------------------------------------------------------------------------
datablock ParticleData( GrenadeFountainSmokeSpike )
{
   dragCoeffiecient     = 1.0;
   gravityCoefficient   = 0.0;
   inheritedVelFactor   = 0.2;

   lifetimeMS           = 1000;
   lifetimeVarianceMS   = 100;

   textureName          = "particleTest";

   useInvAlpha =     true;

   spinRandomMin = -60.0;
   spinRandomMax = 60.0;

   colors[0]     = "0.6 0.6 0.6 1.0";
   colors[1]     = "0.4 0.4 0.4 0.5";
   colors[2]     = "0.4 0.4 0.4 0.0";
   sizes[0]      = 0.0;
   sizes[1]      = 1.0;
   sizes[2]      = 0.5;
   times[0]      = 0.0;
   times[1]      = 0.5;
   times[2]      = 1.0;
};

datablock ParticleEmitterData( GrenadeFountainSmokeSpikeEmitter )
{
   ejectionPeriodMS = 7;
   periodVarianceMS = 1;

   ejectionVelocity = 1.0;  // A little oomph at the back end
   velocityVariance = 0.2;

   thetaMin         = 0.0;
   thetaMax         = 40.0;

   particles = "GrenadeFountainSmokeSpike";
};


//----------------------------------------------------------------------------
// Explosion smoke particles
//----------------------------------------------------------------------------

datablock ParticleData(GrenadeFountainExplosionSmoke)
{
   dragCoeffiecient     = 0.3;
   gravityCoefficient   = -0.2;
   inheritedVelFactor   = 0.025;

   lifetimeMS           = 1250;
   lifetimeVarianceMS   = 0;

   textureName          = "particleTest";

   useInvAlpha =  true;
   spinRandomMin = -100.0;
   spinRandomMax =  100.0;

   textureName = "special/Smoke/bigSmoke";

   colors[0]     = "1.0 0.7 0.0 1.0";
   colors[1]     = "0.4 0.4 0.4 0.5";
   colors[2]     = "0.4 0.4 0.4 0.0";
   sizes[0]      = 1.0;
   sizes[1]      = 3.0;
   sizes[2]      = 1.0;
   times[0]      = 0.0;
   times[1]      = 0.5;
   times[2]      = 1.0;

};

datablock ParticleEmitterData(GrenadeFountainExplosionSmokeEMitter)
{
   ejectionOffset = 0.0;
   ejectionPeriodMS = 5;
   periodVarianceMS = 0;

   ejectionVelocity = 3.25;
   velocityVariance = 0.25;

   thetaMin         = 0.0;
   thetaMax         = 180.0;

   lifetimeMS       = 250;

   particles = "GrenadeFountainExplosionSmoke";
};



datablock DebrisData( GrenadeFountainSpikeDebris )
{
   emitters[0] = GrenadeFountainSmokeSpikeEmitter;
   explodeOnMaxBounce = true;
   elasticity = 0.4;
   friction = 0.2;
   lifetime = 0.3;
   lifetimeVariance = 0.02;
};


//---------------------------------------------------------------------------
// Explosions
//---------------------------------------------------------------------------
datablock ExplosionData(GrenadeFountainExplosion)
{
   explosionShape = "effect_plasma_explosion.dts";
   playSpeed = 1.5;
   soundProfile   = GrenadeFountainExplosionSound;
   faceViewer = true;

   sizes[0] = "0.5 0.5 0.5";
   sizes[1] = "0.5 0.5 0.5";
   sizes[2] = "0.5 0.5 0.5";

   emitter[0] = GrenadeFountainExplosionSmokeEmitter;

   debris = GrenadeFountainSpikeDebris;
   debrisThetaMin = 10;
   debrisThetaMax = 170;
   debrisNum = 8;
   debrisNumVariance = 6;
   debrisVelocity = 15.0;
   debrisVelocityVariance = 2.0;

   shakeCamera = true;
   camShakeFreq = "6.0 7.0 7.0";
   camShakeAmp = "70.0 70.0 70.0";
   camShakeDuration = 1.0;
   camShakeRadius = 7.0;
};



datablock ExplosionData(GrenadeFountainSplashExplosion)
{
   explosionShape = "disc_explosion.dts";

   faceViewer           = true;
   explosionScale = "1.0 1.0 1.0";

   debris = GrenadeFountainSplashDebris;
   debrisThetaMin = 10;
   debrisThetaMax = 80;
   debrisNum = 10;
   debrisVelocity = 10.0;
   debrisVelocityVariance = 4.0;

   sizes[0] = "0.35 0.35 0.35";
   sizes[1] = "0.15 0.15 0.15";
   sizes[2] = "0.15 0.15 0.15";
   sizes[3] = "0.15 0.15 0.15";

   times[0] = 0.0;
   times[1] = 0.333;
   times[2] = 0.666;
   times[3] = 1.0;

};


//--------------------------------------------------------------------------
// Splash
//--------------------------------------------------------------------------
datablock ParticleData(GrenadeFountainMist)
{
   dragCoefficient      = 2.0;
   gravityCoefficient   = -0.05;
   inheritedVelFactor   = 0.0;
   constantAcceleration = 0.0;
   lifetimeMS           = 400;
   lifetimeVarianceMS   = 100;
   useInvAlpha          = false;
   spinRandomMin        = -90.0;
   spinRandomMax        = 500.0;
   textureName          = "particleTest";
   colors[0]     = "0.7 0.8 1.0 1.0";
   colors[1]     = "0.7 0.8 1.0 0.5";
   colors[2]     = "0.7 0.8 1.0 0.0";
   sizes[0]      = 0.5;
   sizes[1]      = 0.5;
   sizes[2]      = 0.8;
   times[0]      = 0.0;
   times[1]      = 0.5;
   times[2]      = 1.0;
};

datablock ParticleEmitterData(GrenadeFountainMistEmitter)
{
   ejectionPeriodMS = 5;
   periodVarianceMS = 0;
   ejectionVelocity = 6.0;
   velocityVariance = 4.0;
   ejectionOffset   = 0.0;
   thetaMin         = 85;
   thetaMax         = 85;
   phiReferenceVel  = 0;
   phiVariance      = 360;
   overrideAdvances = false;
   lifetimeMS       = 250;
   particles = "GrenadeFountainMist";
};



datablock ParticleData( GrenadeFountainSplashParticle )
{
   dragCoefficient      = 1;
   gravityCoefficient   = 0.2;
   inheritedVelFactor   = 0.2;
   constantAcceleration = -0.0;
   lifetimeMS           = 600;
   lifetimeVarianceMS   = 0;
   textureName          = "special/droplet";
   colors[0]     = "0.7 0.8 1.0 1.0";
   colors[1]     = "0.7 0.8 1.0 0.5";
   colors[2]     = "0.7 0.8 1.0 0.0";
   sizes[0]      = 0.5;
   sizes[1]      = 0.5;
   sizes[2]      = 0.5;
   times[0]      = 0.0;
   times[1]      = 0.5;
   times[2]      = 1.0;
};

datablock ParticleEmitterData( GrenadeFountainSplashEmitter )
{
   ejectionPeriodMS = 1;
   periodVarianceMS = 0;
   ejectionVelocity = 6;
   velocityVariance = 3.0;
   ejectionOffset   = 0.0;
   thetaMin         = 60;
   thetaMax         = 80;
   phiReferenceVel  = 0;
   phiVariance      = 360;
   overrideAdvances = false;
   orientParticles  = true;
   lifetimeMS       = 100;
   particles = "GrenadeFountainSplashParticle";
};


datablock SplashData(GrenadeFountainSplash)
{
   numSegments = 15;
   ejectionFreq = 0.0001;
   ejectionAngle = 45;
   ringLifetime = 0.5;
   lifetimeMS = 400;
   velocity = 5.0;
   startRadius = 0.0;
   acceleration = -3.0;
   texWrap = 5.0;

   explosion = GrenadeFountainSplashExplosion;

   texture = "special/water2";

   emitter[0] = GrenadeFountainSplashEmitter;
   emitter[1] = GrenadeFountainMistEmitter;

   colors[0] = "0.7 0.8 1.0 0.0";
   colors[1] = "0.7 0.8 1.0 1.0";
   colors[2] = "0.7 0.8 1.0 0.0";
   colors[3] = "0.7 0.8 1.0 0.0";
   times[0] = 0.0;
   times[1] = 0.4;
   times[2] = 0.8;
   times[3] = 1.0;
};

//--------------------------------------------------------------------------
// Particle effects
//--------------------------------------
datablock ParticleData(GrenadeFountainSmokeParticle)
{
   dragCoeffiecient     = 0.0;
   gravityCoefficient   = -0.02;
   inheritedVelFactor   = 0.1;

   lifetimeMS           = 1200;
   lifetimeVarianceMS   = 100;

   textureName          = "particleTest";

   useInvAlpha = true;
   spinRandomMin = -90.0;
   spinRandomMax = 90.0;

   colors[0]     = "1.0 0.75 0.0 0.0";
   colors[1]     = "0.5 0.5 0.5 1.0";
   colors[2]     = "0.3 0.3 0.3 0.0";
   sizes[0]      = 1;
   sizes[1]      = 2;
   sizes[2]      = 3;
   times[0]      = 0.0;
   times[1]      = 0.1;
   times[2]      = 1.0;

};

datablock ParticleEmitterData(GrenadeFountainSmokeEmitter)
{
   ejectionPeriodMS = 10;
   periodVarianceMS = 0;

   ejectionVelocity = 1.5;
   velocityVariance = 0.3;

   thetaMin         = 0.0;
   thetaMax         = 50.0;

   particles = "GrenadeFountainSmokeParticle";
};


datablock ParticleData(GrenadeFountainFireParticle)
{
   dragCoeffiecient     = 0.0;
   gravityCoefficient   = 0.0;
   inheritedVelFactor   = 1.0;

   lifetimeMS           = 300;
   lifetimeVarianceMS   = 000;

   textureName          = "particleTest";

   spinRandomMin = -135;
   spinRandomMax =  135;

   colors[0]     = "1.0 0.75 0.2 1.0";
   colors[1]     = "1.0 0.5 0.0 1.0";
   colors[2]     = "1.0 0.40 0.0 0.0";
   sizes[0]      = 0;
   sizes[1]      = 1;
   sizes[2]      = 1.5;
   times[0]      = 0.0;
   times[1]      = 0.3;
   times[2]      = 1.0;
};

datablock ParticleEmitterData(GrenadeFountainFireEmitter)
{
   ejectionPeriodMS = 15;
   periodVarianceMS = 0;

   ejectionVelocity = 15.0;
   velocityVariance = 0.0;

   thetaMin         = 0.0;
   thetaMax         = 0.0;

   particles = "GrenadeFountainFireParticle";
};



datablock ParticleData(GrenadeFountainPuffParticle)
{
   dragCoeffiecient     = 0.0;
   gravityCoefficient   = 0.0;
   inheritedVelFactor   = 0.0;

   lifetimeMS           = 500;
   lifetimeVarianceMS   = 300;

   textureName          = "particleTest";

   spinRandomMin = -135;
   spinRandomMax =  135;

   colors[0]     = "1.0 1.0 1.0 0.5";
   colors[1]     = "0.7 0.7 0.7 0.0";
   sizes[0]      = 0.25;
   sizes[1]      = 1.0;
   times[0]      = 0.0;
   times[1]      = 1.0;
};

datablock ParticleEmitterData(GrenadeFountainPuffEmitter)
{
   ejectionPeriodMS = 50;
   periodVarianceMS = 3;

   ejectionVelocity = 0.5;
   velocityVariance = 0.0;

   thetaMin         = 0.0;
   thetaMax         = 90.0;

   particles = "GrenadeFountainPuffParticle";
};


datablock ParticleData(GrenadeFountainLauncherExhaustParticle)
{
   dragCoeffiecient     = 0.0;
   gravityCoefficient   = 0.01;
   inheritedVelFactor   = 1.0;

   lifetimeMS           = 500;
   lifetimeVarianceMS   = 300;

   textureName          = "particleTest";

   useInvAlpha = true;
   spinRandomMin = -135;
   spinRandomMax =  135;

   colors[0]     = "1.0 1.0 1.0 0.5";
   colors[1]     = "0.7 0.7 0.7 0.0";
   sizes[0]      = 0.25;
   sizes[1]      = 1.0;
   times[0]      = 0.0;
   times[1]      = 1.0;
};

datablock ParticleEmitterData(GrenadeFountainLauncherExhaustEmitter)
{
   ejectionPeriodMS = 15;
   periodVarianceMS = 0;

   ejectionVelocity = 3.0;
   velocityVariance = 0.0;

   thetaMin         = 0.0;
   thetaMax         = 20.0;

   particles = "GrenadeFountainLauncherExhaustParticle";
};

//--------------------------------------------------------------------------
// Debris
//--------------------------------------
datablock DebrisData( FlechetteDebris )
{
   shapeName = "weapon_missile_fleschette.dts";

   lifetime = 5.0;

   minSpinSpeed = -320.0;
   maxSpinSpeed = 320.0;

   elasticity = 0.2;
   friction = 0.3;

   numBounces = 3;

   gravModifier = 0.40;

   staticOnMaxBounce = true;
};

//--------------------------------------------------------------------------
// Projectile
//--------------------------------------
datablock SeekerProjectileData(ShoulderGrenadeFountain)
{
   casingShapeName     = "weapon_missile_casement.dts";
   projectileShapeName = "weapon_missile_projectile.dts";
   hasDamageRadius     = true;
   indirectDamage      = 0.8;
   damageRadius        = 8.0;
   radiusDamageType    = $DamageType::Missile;
   kickBackStrength    = 2000;

   explosion           = "GrenadeFountainExplosion";
   splash              = GrenadeFountainSplash;
   velInheritFactor    = 1.0;
   baseEmitter         = GrenadeFountainSmokeEmitter;
   delayEmitter        = GrenadeFountainFireEmitter;
//   puffEmitter         = GrenadeFountainPuffEmitter;
   bubbleEmitter       = GrenadeBubbleEmitter;
   bubbleEmitTime      = 1.0;

//   exhaustEmitter      = GrenadeFountainLauncherExhaustEmitter;
   exhaustTimeMs       = 300;
   exhaustNodeName     = "muzzlePoint1";

   lifetimeMS          = 20000;
   muzzleVelocity      = 10.0;
   maxVelocity         = 30.0;
   turningSpeed        = 0.0;
   acceleration        = 200.0;

   proximityRadius     = 3;

   terrainAvoidanceSpeed         = 180;
   terrainScanAhead              = 25;
   terrainHeightFail             = 12;
   terrainAvoidanceRadius        = 100;

   flareDistance = 200;
   flareAngle    = 30;

   sound = GrenadeFountainProjectileSound;

   hasLight    = true;
   lightRadius = 5.0;
   lightColor  = "0.2 0.05 0";

   useFlechette = true;
   flechetteDelayMs = 550;
   casingDeb = FlechetteDebris;

   explodeOnWaterImpact = false;
};



//--------------------------------------------------------------------------
// Ammo
//--------------------------------------

datablock ItemData(GrenadeFountainAmmo)
{
   className = Ammo;
   catagory = "Ammo";
   shapeFile = "ammo_missile.dts";
   mass = 1;
   elasticity = 0.2;
   friction = 0.6;
   pickupRadius = 2;
	pickUpName = "some grendade fountain ammo";

   computeCRC = true;

};

//--------------------------------------------------------------------------
// Weapon
//--------------------------------------
datablock ItemData(GrenadeFountain)
{
   className = Weapon;
   catagory = "Spawn Items";
   shapeFile = "weapon_missile.dts";
   image = GrenadeFountainImage;
   mass = 1;
   elasticity = 0.2;
   friction = 0.6;
   pickupRadius = 2;
	pickUpName = "a grenade fountain";

   computeCRC = true;
   emap = true;
};

datablock ShapeBaseImageData(GrenadeFountainImage)
{
   className = WeaponImage;
   shapeFile = "weapon_missile.dts";
   item = GrenadeFountain;
   ammo = GrenadeFountainAmmo;
   offset = "0 0 0";
   armThread = lookms;
   emap = true;

   projectile = ShoulderGrenadeFountain;
   projectileType = SeekerProjectile;

   isSeeker     = false;

   // only target objects outside this range
   minTargetingDistance             = 40;

   stateName[0]                     = "Activate";
   stateTransitionOnTimeout[0]      = "ActivateReady";
   stateTimeoutValue[0]             = 0.5;
   stateSequence[0]                 = "Activate";
   stateSound[0]                    = GrenadeFountainSwitchSound;

   stateName[1]                     = "ActivateReady";
   stateTransitionOnLoaded[1]       = "Ready";
   stateTransitionOnNoAmmo[1]       = "NoAmmo";

   stateName[2]                     = "Ready";
   stateTransitionOnNoAmmo[2]       = "NoAmmo";
   stateTransitionOnTriggerDown[2]  = "CheckWet";

   stateName[3]                     = "Fire";
   stateTransitionOnTimeout[3]      = "Reload";
   stateTimeoutValue[3]             = 0.4;
   stateFire[3]                     = true;
   stateRecoil[3]                   = LightRecoil;
   stateAllowImageChange[3]         = false;
   stateSequence[3]                 = "Fire";
   stateScript[3]                   = "onFire";
   stateSound[3]                    = GrenadeFountainFireSound;

   stateName[4]                     = "Reload";
   stateTransitionOnNoAmmo[4]       = "NoAmmo";
   stateTransitionOnTimeout[4]      = "Ready";
   stateTimeoutValue[4]             = 1.0;
   stateAllowImageChange[4]         = false;
   stateSequence[4]                 = "Reload";
   stateSound[4]                    = GrenadeFountainReloadSound;

   stateName[5]                     = "NoAmmo";
   stateTransitionOnAmmo[5]         = "Reload";
   stateSequence[5]                 = "NoAmmo";
   stateTransitionOnTriggerDown[5]  = "DryFire";

   stateName[6]                     = "DryFire";
   stateScript[6]                   = "onDryFire";
   stateSound[6]                    = GrenadeFountainDryFireSound;
   stateTimeoutValue[6]             = 1.0;
   stateTransitionOnTimeout[6]      = "ActivateReady";

   stateName[7]                     = "CheckTarget";
   stateTransitionOnNoTarget[7]     = "Fire";
   stateTransitionOnTarget[7]       = "Fire";

   stateName[8]                     = "CheckWet";
   stateTransitionOnWet[8]          = "WetFire";
   stateTransitionOnNotWet[8]       = "CheckTarget";

   stateName[9]                     = "WetFire";
   stateTransitionOnNoAmmo[9]       = "NoAmmo";
   stateTransitionOnTimeout[9]      = "Reload";
   stateSound[9]                    = GrenadeFountainFireSound;
   stateRecoil[9]                   = LightRecoil;
   stateTimeoutValue[9]             = 0.4;
   stateSequence[9]                 = "Fire";
   stateScript[9]                   = "onFire";
   stateAllowImageChange[9]         = false;
};

datablock StaticShapeData(RPCNexus)
{
   shapefile = "nexus_effect.dts";
   isInvincible = true;
   dynamicType = $TypeMasks::BeaconObjectType;
};

function GrenadeFountainImage::onFire(%data,%obj,%slot)
{
   if (isObject(%obj.GrenadeFountainProj))
      detGrenadeFountainProj(%obj);
   else
   {
      %obj.GrenadeFountainProj = Parent::onFire(%data,%obj,%slot);
      BeaconIt(%obj.GrenadeFountainProj);
   }
}

function GrenadeFountainImage::onDryFire(%data,%obj,%slot)
{
   if (isObject(%obj.GrenadeFountainProj))
      detGrenadeFountainProj(%obj);
}

function ShoulderGrenadeFountain::onExplode(%data, %proj, %pos, %mod)
{
   if (isObject(%proj.beac))
      %proj.beac.delete();
   if (isObject(%proj.sourceObject))
      %proj.sourceObject.grenadeFountainProj = "";
   if (%data.hasDamageRadius)
      RadiusExplosion(%proj, %pos, %data.damageRadius, %data.indirectDamage, %data.kickBackStrength, %proj.sourceObject, %data.radiusDamageType);
}

function detGrenadeFountainProj(%obj)
{
   %proj = %obj.GrenadeFountainProj;
   if (!isObject(%proj))
      return;
   %pos = posFromTransform(%proj.getTransform());
   %endpos = VectorAdd(%pos, "0 0 -3000");
   %hit = ContainerRayCast(%pos, %endpos, $TypeMasks::TerrainObjectType | $TypeMasks::InteriorObjectType, %proj);
   if (%hit)
      %height = getWord(%pos, 2) - getWord(%hit, 3);
   if ((%height > 150) || (!%height))
      %height = 150;
   if (%height < 10)
      %height = 10;
   %spread = 2.25 / ((%height / 20) * (%height / 20));
   %vec = "0 0 -1";
   for (%i=0;%i<20;%i++)
   {
      %x = (getRandom() - 0.5) * 2 * 3.1415926 * %spread;
      %y = (getRandom() - 0.5) * 2 * 3.1415926 * %spread;
      %z = (getRandom() - 0.5) * 2 * 3.1415926 * %spread;
      %mat = MatrixCreateFromEuler(%x @ " " @ %y @ " " @ %z);
      %vector = MatrixMulVector(%mat, %vec);
      %p = new (GrenadeProjectile)() {
         dataBlock        = BasicGrenade;
         initialDirection = %vector;
         initialPosition  = %pos;
         sourceObject     = %proj.sourceObject;
         sourceSlot       = %proj.sourceSlot;
         vehicleObject    = %proj.vehicleObject;
      };
      MissionCleanup.add(%p);
   }
   if (isObject(%obj.grenadeFountainProj.beac))
      %obj.grenadeFountainProj.beac.delete();
   %obj.grenadeFountainProj.delete();
   %obj.grenadeFountainProj = "";
}

function BeaconIt(%p)
{
   if (!isObject(%p))
      return;
   %pos = posFromTransform(%p.getTransform());
   %endpos = VectorAdd(%pos, "0 0 -3000");
   %hit = ContainerRayCast(%pos, %endpos, $TypeMasks::TerrainObjectType | $TypeMasks::InteriorObjectType, %proj);
   %pos = getWords(%hit, 1, 3);
   %p.beac = new StaticShape() {
      dataBlock = RPCNexus;
      scale = "3 3 0.1";
   };
   MissionCleanup.add(%p.beac);
   %p.beac.setTransform(%pos SPC "0 0 0 1");
   schedule(100, 0, "BeaconItTwo", %p);
}

function BeaconItTwo(%p)
{
   if (!isObject(%p))
      return;
   %pos = posFromTransform(%p.getTransform());
   %endpos = VectorAdd(%pos, "0 0 -3000");
   %hit = ContainerRayCast(%pos, %endpos, $TypeMasks::TerrainObjectType | $TypeMasks::InteriorObjectType, %proj);
   %pos = getWords(%hit, 1, 3);
   if (!isObject(%p.beac))
      return;
   %p.beac.setTransform(%pos SPC "0 0 0 1");
   schedule(100, 0, "BeaconItTwo", %p);
}