Torque Tutorials - How to Customize Weapons

What we want to do is to change the weapon in the game to say, a snowball thrower, water gun or a paintball gun. Something less violent and accessible for young gamers. I guess at some point we need to change the orcs as well. Cause they’re pretty scary looking. At least that’s what my daughter says.

GarageGames has a fabulous tool called the Torque ShowTool Pro. This is a program that allows you to see the different animations contained in a .dts file inluding the textures and how it would look in the Toruque game engine. Here’s a view of the activate sequence. This shows the ready mode of the activate sequence. It is actually a little animation.

Torque ShowTool by David Wyand

I had a look at the weapon.dts file. And it contains the following sequences:

1. activate - from the closed to the open and ready mode.
2. fire - this is the fire animation, then I guess you already knew that.
3. reload - this pops in more ammo in the barrel of the crossbow.
4. deactivate - from the ready mode to the close mode.
5. noammo - this looks like the open ready mode, but with no ammo in place. In other words, you’re in trouble. Better get more ammo.

The above seqences correspond to different states of the crossbow during game play. Along with the different animation sequences in .dts format, the crossbow also has an explosion animation that is used when the arrows hits a target. As well as ammo box that gets loaded into the weapon and the arrows that actually get shot.

As you get to tinker with the weapons files you will notice that is very complex. This makes sense since it is a major part of the game.

The above sequences are called from the following files and also correlate to other parts of the game files. By the way the number in brackets is the line number and are approximations. Your could be different by now as there have been a number of updates:
starter.fps\client\config.cs(34): moveMap.bind(mouse0, “button0″, mouseFire);
starter.fps\client\scripts\default.bind.cs(141): moveMap.bind( mouse, button0, mouseFire );
starter.fps\server\scripts\crossbow.cs(914): function CrossbowImage::onFire(%this, %obj,
%slot)

Here’s the files that relate to the word weapon:

starter.fps\server\scripts\crossbow.cs(7): // Crossbow weapon. This file contains all the items related to this weapon
starter.fps\server\scripts\item.cs(18)
starter.fps\server\scripts\player.cs(718): %obj.mountImage(%obj.lastWeapon, $WeaponSlot);
starter.fps\server\scripts\weapon.cs(6): // This file contains Weapon and Ammo Class/”namespace” helper methods

Simplified model of the crossbow as I learn
Above: The simple model with joints intact.

The test weapon mounted and ready to go.
Above: Ahhh, our lovely orcs with shiny new additions, namely, the weapon loaded in the game and being in use by the orc. Mind you, at this point I haven’t even touched the code. All this just happens automatically. I provide the model and just make sure it’s named weapon.dts. Ofcourse, just make sure it is a .dts file that you export from MilkShape3d.

Sequence named in MilkShape3d
The Torque Engine as defined by the script calls the different animation sequences. In this case, the activate, fire, reload, deactivate, and noammo. If you squint a bit, notice the “opt:scale=0.02″ materials definition. If you do not define the scale, everything is super huge and it will not fit properly.

Mountpoints in the 3d model.
The mountpoints define how the model (in this case the weapon model) will mount or get added to the orc. There is an associated script(s) that defines how this gets added.

The Explosions and Debris When Something Gets Hit
Here’s the file(s) that has something to do with explosions and the like. By experimenting and trying out different settings, you can enable different effects to take place. It really is a issue of trying it out. After a while, you become so pro or you stick to what you know that you just plug in the numbers like no one’s business:
starter.fps\server\scripts\crossbow.cs

Below, the crossbow.cs file with notations regarding the smoke.

//—————————————————————————–
// Torque Game Engine
// Copyright (C) GarageGames.com, Inc.
//—————————————————————————–

//—————————————————————————–
// Crossbow weapon. This file contains all the items related to this weapon
// including explosions, ammo, the item and the weapon item image.
// These objects rely on the item & inventory support system defined
// in item.cs and inventory.cs
//—————————————————————————–

//—————————————————————————–
// Sounds profiles

datablock AudioProfile(CrossbowReloadSound)
{
filename = “~/data/sound/crossbow_reload.ogg”;
description = AudioClose3d;
preload = true;
};

datablock AudioProfile(CrossbowFireSound)
{
filename = “~/data/sound/crossbow_firing.ogg”;
description = AudioClose3d;
preload = true;
};

datablock AudioProfile(CrossbowFireEmptySound)
{
filename = “~/data/sound/crossbow_firing_empty.ogg”;
description = AudioClose3d;
preload = true;
};

datablock AudioProfile(CrossbowExplosionSound)
{
filename = “~/data/sound/crossbow_explosion.ogg”;
description = AudioDefault3d;
preload = true;
};

//—————————————————————————–
// Crossbow bolt projectile splash

datablock ParticleData(CrossbowSplashMist)
{
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 = “~/data/shapes/crossbow/splash”;

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(CrossbowSplashMistEmitter)
{
ejectionPeriodMS = 5;
periodVarianceMS = 0;
ejectionVelocity = 3.0;
velocityVariance = 2.0;
ejectionOffset = 0.0;
thetaMin = 85;
thetaMax = 85;
phiReferenceVel = 0;
phiVariance = 360;
overrideAdvance = false;
lifetimeMS = 250;
particles = “CrossbowSplashMist”;
};

datablock ParticleData( CrossbowSplashParticle )
{
dragCoefficient = 1;
gravityCoefficient = 0.2;
inheritedVelFactor = 0.2;
constantAcceleration = -0.0;
lifetimeMS = 600;
lifetimeVarianceMS = 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.5;
sizes[1] = 0.5;
sizes[2] = 0.5;
times[0] = 0.0;
times[1] = 0.5;
times[2] = 1.0;
};

datablock ParticleEmitterData( CrossbowSplashEmitter )
{
ejectionPeriodMS = 1;
periodVarianceMS = 0;
ejectionVelocity = 3;
velocityVariance = 1.0;
ejectionOffset = 0.0;
thetaMin = 60;
thetaMax = 80;
phiReferenceVel = 0;
phiVariance = 360;
overrideAdvance = false;
orientParticles = true;
lifetimeMS = 100;
particles = “CrossbowSplashParticle”;
};

datablock SplashData(CrossbowSplash)
{
numSegments = 15;
ejectionFreq = 15;
ejectionAngle = 40;
ringLifetime = 0.5;
lifetimeMS = 300;
velocity = 4.0;
startRadius = 0.0;
acceleration = -3.0;
texWrap = 5.0;

texture = “~/data/shapes/crossbow/splash”;

emitter[0] = CrossbowSplashEmitter;
emitter[1] = CrossbowSplashMistEmitter;

colors[0] = “0.7 0.8 1.0 0.0″;
colors[1] = “0.7 0.8 1.0 0.3″;
colors[2] = “0.7 0.8 1.0 0.7″;
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;
};

//—————————————————————————–
// Crossbow bolt projectile particles

datablock ParticleData(CrossbowBoltParticle)
{
textureName = “~/data/shapes/particles/smoke”;
dragCoefficient = 0.0;
gravityCoefficient = -0.1; // rises slowly
inheritedVelFactor = 0.0;
lifetimeMS = 150;
lifetimeVarianceMS = 10; // …more or less
useInvAlpha = false;
spinRandomMin = -30.0;
spinRandomMax = 30.0;

//jt trailing color on crossbow bolt
//the thing that gets shot from the crossbos
colors[0] = “0.1 0.1 0.1 1.0″;
colors[1] = “0.1 0.1 0.1 1.0″;
colors[2] = “0.1 0.1 0.1 0″;

//jt yellow
//colors[0] = “0.7 0.7 0.0 0.7″;
//colors[1] = “0.9 0.8 0.0 0.3″;
//colors[2] = “0.8 0.8 0.0 0.2″;

sizes[0] = 0.15;
sizes[1] = 0.20;
sizes[2] = 0.25;

times[0] = 0.0;
times[1] = 0.3;
times[2] = 1.0;
};

datablock ParticleData(CrossbowBubbleParticle)
{
textureName = “~/data/shapes/particles/bubble”;
dragCoefficient = 0.0;
gravityCoefficient = -0.25; // rises slowly
inheritedVelFactor = 0.0;
constantAcceleration = 0.0;
lifetimeMS = 1500;
lifetimeVarianceMS = 600; // …more or less
useInvAlpha = false;
spinRandomMin = -100.0;
spinRandomMax = 100.0;

colors[0] = “0.7 0.8 1.0 0.4″;
colors[1] = “0.7 0.8 1.0 1.0″;
colors[2] = “0.7 0.8 1.0 0.0″;

sizes[0] = 0.2;
sizes[1] = 0.2;
sizes[2] = 0.2;

times[0] = 0.0;
times[1] = 0.5;
times[2] = 1.0;
};

datablock ParticleEmitterData(CrossbowBoltEmitter)
{
ejectionPeriodMS = 2;
periodVarianceMS = 0;

ejectionVelocity = 0.0;
velocityVariance = 0.10;

thetaMin = 0.0;
thetaMax = 90.0;

particles = CrossbowBoltParticle;
};

datablock ParticleEmitterData(CrossbowBoltBubbleEmitter)
{
ejectionPeriodMS = 9;
periodVarianceMS = 0;

ejectionVelocity = 1.0;
ejectionOffset = 0.1;
velocityVariance = 0.5;

thetaMin = 0.0;
thetaMax = 80.0;

phiReferenceVel = 0;
phiVariance = 360;
overrideAdvances = false;

particles = CrossbowBubbleParticle;
};

//—————————————————————————–
// Explosion Debris

// Debris “spark” explosion
datablock ParticleData(CrossbowDebrisSpark)
{
textureName = “~/data/shapes/particles/fire”;
dragCoefficient = 0;
gravityCoefficient = 0.0;
windCoefficient = 0;
inheritedVelFactor = 0.5;
constantAcceleration = 0.0;
lifetimeMS = 500;
lifetimeVarianceMS = 50;
spinRandomMin = -90.0;
spinRandomMax = 90.0;
useInvAlpha = false;

colors[0] = “0.8 0.2 0 1.0″;
colors[1] = “0.8 0.2 0 1.0″;
colors[2] = “0 0 0 0.0″;

sizes[0] = 0.2;
sizes[1] = 0.3;
sizes[2] = 0.1;

times[0] = 0.0;
times[1] = 0.5;
times[2] = 1.0;
};

datablock ParticleEmitterData(CrossbowDebrisSparkEmitter)
{
ejectionPeriodMS = 20;
periodVarianceMS = 0;
ejectionVelocity = 0.5;
velocityVariance = 0.25;
ejectionOffset = 0.0;
thetaMin = 0;
thetaMax = 90;
phiReferenceVel = 0;
phiVariance = 360;
overrideAdvances = false;
orientParticles = false;
lifetimeMS = 300;
particles = “CrossbowDebrisSpark”;
};

datablock ExplosionData(CrossbowDebrisExplosion)
{
emitter[0] = CrossbowDebrisSparkEmitter;

// Turned off..
shakeCamera = false;
impulseRadius = 0;
lightStartRadius = 0;
lightEndRadius = 0;
};

// Debris smoke trail
datablock ParticleData(CrossbowDebrisTrail)
{
textureName = “~/data/shapes/particles/fire”;
dragCoefficient = 1;
gravityCoefficient = 0;
inheritedVelFactor = 0;
windCoefficient = 0;
constantAcceleration = 0;
lifetimeMS = 800;
lifetimeVarianceMS = 100;
spinSpeed = 0;
spinRandomMin = -90.0;
spinRandomMax = 90.0;
useInvAlpha = true;

//jt makes a black trail of smoke trailing the debris
colors[0] = “0.8 0.3 0.0 1.0″;
colors[1] = “0.1 0.1 0.1 0.7″;
colors[2] = “0.1 0.1 0.1 0.0″;

//jt makes a yello trail in the debris
//colors[0] = “0.7 0.7 0.0 0.7″;
//colors[1] = “0.9 0.8 0.0 0.3″;
//colors[2] = “0.8 0.8 0.0 0.2″;

sizes[0] = 0.2;
sizes[1] = 0.3;
sizes[2] = 0.4;

times[0] = 0.1;
times[1] = 0.2;
times[2] = 1.0;
};

datablock ParticleEmitterData(CrossbowDebrisTrailEmitter)
{
ejectionPeriodMS = 30;
periodVarianceMS = 0;
ejectionVelocity = 0.0;
velocityVariance = 0.0;
ejectionOffset = 0.0;
thetaMin = 170;
thetaMax = 180;
phiReferenceVel = 0;
phiVariance = 360;
//overrideAdvances = false;
//orientParticles = true;
lifetimeMS = 5000;
particles = “CrossbowDebrisTrail”;
};

// Debris object
datablock DebrisData(CrossbowExplosionDebris)
{
shapeFile = “~/data/shapes/crossbow/debris.dts”;
emitters = “CrossbowDebrisTrailEmitter”;
explosion = CrossbowDebrisExplosion;

elasticity = 0.6;
friction = 0.5;
numBounces = 1;
bounceVariance = 1;
explodeOnMaxBounce = true;
staticOnMaxBounce = false;
snapOnMaxBounce = false;
minSpinSpeed = 0;
maxSpinSpeed = 700;
render2D = false;
lifetime = 4;
lifetimeVariance = 0.4;
velocity = 5;
velocityVariance = 0.5;
fade = false;
useRadiusMass = true;
baseRadius = 0.3;
gravModifier = 0.5;
terminalVelocity = 6;
ignoreWater = true;
};

//—————————————————————————–
// Bolt Explosion

datablock ParticleData(CrossbowExplosionSmoke)
{
textureName = “~/data/shapes/particles/smoke”;
dragCoeffiecient = 100.0;
gravityCoefficient = 0;
inheritedVelFactor = 0.25;
constantAcceleration = -0.30;
lifetimeMS = 1200;
lifetimeVarianceMS = 300;
useInvAlpha = true;
spinRandomMin = -80.0;
spinRandomMax = 80.0;

//jt color of the explosions smoke
//after the middle explosion smoke
//colors[0] = “0.56 0.36 0.26 1.0″;
//colors[1] = “0.2 0.2 0.2 1.0″;
//colors[2] = “0.0 0.0 0.0 0.0″;

//51 102 0 rgb green
//colors[0] = “0.1 0.5 0.0 0.1″;

//yellow
//colors[1] = “0.9 0.9 0.0 0.3″;

//lighter intensity of yellow
//colors[2] = “0.9 0.9 0.0 0.2″;

sizes[0] = 4.0;
sizes[1] = 2.5;
sizes[2] = 1.0;

times[0] = 0.0;
times[1] = 0.5;
times[2] = 1.0;
};

datablock ParticleData(CrossbowExplosionBubble)
{
textureName = “~/data/shapes/particles/bubble”;
dragCoeffiecient = 0.0;
gravityCoefficient = -0.25;
inheritedVelFactor = 0.0;
constantAcceleration = 0.0;
lifetimeMS = 1500;
lifetimeVarianceMS = 600;
useInvAlpha = false;
spinRandomMin = -100.0;
spinRandomMax = 100.0;

colors[0] = “0.7 0.8 1.0 0.4″;
colors[1] = “0.7 0.8 1.0 0.4″;
colors[2] = “0.7 0.8 1.0 0.0″;

sizes[0] = 0.3;
sizes[1] = 0.3;
sizes[2] = 0.3;

times[0] = 0.0;
times[1] = 0.5;
times[2] = 1.0;
};

datablock ParticleEmitterData(CrossbowExplosionSmokeEmitter)
{
ejectionPeriodMS = 10;
periodVarianceMS = 0;
ejectionVelocity = 4;
velocityVariance = 0.5;
thetaMin = 0.0;
thetaMax = 180.0;
lifetimeMS = 250;
particles = “CrossbowExplosionSmoke”;
};

datablock ParticleEmitterData(CrossbowExplosionBubbleEmitter)
{
ejectionPeriodMS = 9;
periodVarianceMS = 0;
ejectionVelocity = 1;
ejectionOffset = 0.1;
velocityVariance = 0.5;
thetaMin = 0.0;
thetaMax = 80.0;
phiReferenceVel = 0;
phiVariance = 360;
overrideAdvances = false;
particles = “CrossbowExplosionBubble”;
};

datablock ParticleData(CrossbowExplosionFire)
{
textureName = “~/data/shapes/particles/fire”;
dragCoeffiecient = 100.0;
gravityCoefficient = 0;
inheritedVelFactor = 0.25;
constantAcceleration = 0.1;
lifetimeMS = 1200;
lifetimeVarianceMS = 300;
useInvAlpha = false;
spinRandomMin = -80.0;
spinRandomMax = 80.0;

//jt the middle part of the explosion
//colors[0] = “0.8 0.4 0 0.8″;
//colors[1] = “0.2 0.0 0 0.8″;
//colors[2] = “0.0 0.0 0.0 0.0″;

//jt green
colors[0] = “0.1 0.5 0.0 0.1″;
colors[1] = “0.1 0.5 0.0 0.1″;
colors[2] = “0.1 0.5 0.0 0.1″;

sizes[0] = 1.5;
sizes[1] = 0.9;
sizes[2] = 0.5;

times[0] = 0.0;
times[1] = 0.5;
times[2] = 1.0;
};

datablock ParticleEmitterData(CrossbowExplosionFireEmitter)
{
ejectionPeriodMS = 10;
periodVarianceMS = 0;
ejectionVelocity = 0.8;
velocityVariance = 0.5;
thetaMin = 0.0;
thetaMax = 180.0;
lifetimeMS = 250;
particles = “CrossbowExplosionFire”;
};

datablock ParticleData(CrossbowExplosionSparks)
{
textureName = “~/data/shapes/particles/spark”;
dragCoefficient = 1;
gravityCoefficient = 0.0;
inheritedVelFactor = 0.2;
constantAcceleration = 0.0;
lifetimeMS = 500;
lifetimeVarianceMS = 350;

colors[0] = “0.60 0.40 0.30 1.0″;
colors[1] = “0.60 0.40 0.30 1.0″;
colors[2] = “1.0 0.40 0.30 0.0″;

sizes[0] = 0.25;
sizes[1] = 0.15;
sizes[2] = 0.15;

times[0] = 0.0;
times[1] = 0.5;
times[2] = 1.0;
};

datablock ParticleData(CrossbowExplosionWaterSparks)
{
textureName = “~/data/shapes/particles/bubble”;
dragCoefficient = 0;
gravityCoefficient = 0.0;
inheritedVelFactor = 0.2;
constantAcceleration = 0.0;
lifetimeMS = 500;
lifetimeVarianceMS = 350;

colors[0] = “0.4 0.4 1.0 1.0″;
colors[1] = “0.4 0.4 1.0 1.0″;
colors[2] = “0.4 0.4 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(CrossbowExplosionSparkEmitter)
{
ejectionPeriodMS = 3;
periodVarianceMS = 0;
ejectionVelocity = 5;
velocityVariance = 1;
ejectionOffset = 0.0;
thetaMin = 0;
thetaMax = 180;
phiReferenceVel = 0;
phiVariance = 360;
overrideAdvances = false;
orientParticles = true;
lifetimeMS = 100;
particles = “CrossbowExplosionSparks”;
};

datablock ParticleEmitterData(CrossbowExplosionWaterSparkEmitter)
{
ejectionPeriodMS = 3;
periodVarianceMS = 0;
ejectionVelocity = 4;
velocityVariance = 4;
ejectionOffset = 0.0;
thetaMin = 0;
thetaMax = 60;
phiReferenceVel = 0;
phiVariance = 360;
overrideAdvances = false;
orientParticles = true;
lifetimeMS = 200;
particles = “CrossbowExplosionWaterSparks”;
};

datablock ExplosionData(CrossbowSubExplosion1)
{
offset = 0;
emitter[0] = CrossbowExplosionSmokeEmitter;
emitter[1] = CrossbowExplosionSparkEmitter;
};

datablock ExplosionData(CrossbowSubExplosion2)
{
offset = 1.0;
emitter[0] = CrossbowExplosionSmokeEmitter;
emitter[1] = CrossbowExplosionSparkEmitter;
};

datablock ExplosionData(CrossbowSubWaterExplosion1)
{
delayMS = 100;
offset = 1.2;
playSpeed = 1.5;

emitter[0] = CrossbowExplosionBubbleEmitter;
emitter[1] = CrossbowExplosionWaterSparkEmitter;

sizes[0] = “0.75 0.75 0.75″;
sizes[1] = “1.0 1.0 1.0″;
sizes[2] = “0.5 0.5 0.5″;
times[0] = 0.0;
times[1] = 0.5;
times[2] = 1.0;
};

datablock ExplosionData(CrossbowSubWaterExplosion2)
{
delayMS = 50;
offset = 1.2;
playSpeed = 0.75;

emitter[0] = CrossbowExplosionBubbleEmitter;
emitter[1] = CrossbowExplosionWaterSparkEmitter;

sizes[0] = “1.5 1.5 1.5″;
sizes[1] = “1.5 1.5 1.5″;
sizes[2] = “1.0 1.0 1.0″;
times[0] = 0.0;
times[1] = 0.5;
times[2] = 1.0;
};

datablock ExplosionData(CrossbowExplosion)
{
soundProfile = CrossbowExplosionSound;
lifeTimeMS = 1200;

// Volume particles
particleEmitter = CrossbowExplosionFireEmitter;
particleDensity = 75;
particleRadius = 2;

// Point emission
emitter[0] = CrossbowExplosionSmokeEmitter;
emitter[1] = CrossbowExplosionSparkEmitter;

// Sub explosion objects
subExplosion[0] = CrossbowSubExplosion1;
subExplosion[1] = CrossbowSubExplosion2;

// Camera Shaking
shakeCamera = true;
camShakeFreq = “10.0 11.0 10.0″;
camShakeAmp = “1.0 1.0 1.0″;
camShakeDuration = 0.5;
camShakeRadius = 10.0;

// Exploding debris
debris = CrossbowExplosionDebris;
debrisThetaMin = 0;
debrisThetaMax = 60;
debrisPhiMin = 0;
debrisPhiMax = 360;
debrisNum = 6;
debrisNumVariance = 2;
debrisVelocity = 1;
debrisVelocityVariance = 0.5;

// Impulse
impulseRadius = 10;
impulseForce = 15;

// Dynamic light
lightStartRadius = 6;
lightEndRadius = 3;
lightStartColor = “0.5 0.5 0″;
lightEndColor = “0 0 0″;
};

datablock ExplosionData(CrossbowWaterExplosion)
{
soundProfile = CrossbowExplosionSound;

// Volume particles
particleEmitter = CrossbowExplosionBubbleEmitter;
particleDensity = 375;
particleRadius = 2;

// Point emission
emitter[0] = CrossbowExplosionBubbleEmitter;
emitter[1] = CrossbowExplosionWaterSparkEmitter;

// Sub explosion objects
subExplosion[0] = CrossbowSubWaterExplosion1;
subExplosion[1] = CrossbowSubWaterExplosion2;

// Camera Shaking
shakeCamera = true;
camShakeFreq = “8.0 9.0 7.0″;
camShakeAmp = “3.0 3.0 3.0″;
camShakeDuration = 1.3;
camShakeRadius = 20.0;

// Exploding debris
debris = CrossbowExplosionDebris;
debrisThetaMin = 0;
debrisThetaMax = 60;
debrisPhiMin = 0;
debrisPhiMax = 360;
debrisNum = 6;
debrisNumVariance = 2;
debrisVelocity = 0.5;
debrisVelocityVariance = 0.2;

// Impulse
impulseRadius = 10;
impulseForce = 15;

// Dynamic light
lightStartRadius = 6;
lightEndRadius = 3;
lightStartColor = “0 0.5 0.5″;
lightEndColor = “0 0 0″;
};

//—————————————————————————–
// Projectile Object

datablock ProjectileData(CrossbowProjectile)
{
projectileShapeName = “~/data/shapes/crossbow/projectile.dts”;
directDamage = 20;
radiusDamage = 20;
damageRadius = 1.5;
explosion = CrossbowExplosion;
waterExplosion = CrossbowWaterExplosion;

particleEmitter = CrossbowBoltEmitter;
particleWaterEmitter= CrossbowBoltBubbleEmitter;

splash = CrossbowSplash;

muzzleVelocity = 100;
velInheritFactor = 0.3;

armingDelay = 0;
lifetime = 5000;
fadeDelay = 5000;
bounceElasticity = 0;
bounceFriction = 0;
isBallistic = false;
gravityMod = 0.80;

hasLight = true;
lightRadius = 4;
lightColor = “0.5 0.5 0.25″;

hasWaterLight = true;
waterLightColor = “0 0.5 0.5″;
};

function CrossbowProjectile::onCollision(%this,%obj,%col,%fade,%pos,%normal)
{
// Apply damage to the object all shape base objects
if (%col.getType() & $TypeMasks::ShapeBaseObjectType)
%col.damage(%obj,%pos,%this.directDamage,”CrossbowBolt”);

// Radius damage is a support scripts defined in radiusDamage.cs
// Push the contact point away from the contact surface slightly
// along the contact normal to derive the explosion center. -dbs
radiusDamage
(%obj, VectorAdd(%pos, VectorScale(%normal, 0.01)),
%this.damageRadius,%this.radiusDamage,”Radius”,40);
}

//—————————————————————————–
// Ammo Item

datablock ItemData(CrossbowAmmo)
{
// Mission editor category
category = “Ammo”;

// Add the Ammo namespace as a parent. The ammo namespace provides
// common ammo related functions and hooks into the inventory system.
className = “Ammo”;

// Basic Item properties
shapeFile = “~/data/shapes/crossbow/ammo.dts”;
mass = 1;
elasticity = 0.2;
friction = 0.6;

// Dynamic properties defined by the scripts
pickUpName = “crossbow bolts”;
maxInventory = 20;
};

//————————————————————————–
// Weapon Item. This is the item that exists in the world, i.e. when it’s
// been dropped, thrown or is acting as re-spawnable item. When the weapon
// is mounted onto a shape, the CrossbowImage is used.

datablock ItemData(Crossbow)
{
// Mission editor category
category = “Weapon”;

// Hook into Item Weapon class hierarchy. The weapon namespace
// provides common weapon handling functions in addition to hooks
// into the inventory system.
className = “Weapon”;

// Basic Item properties
shapeFile = “~/data/shapes/crossbow/weapon.dts”;
mass = 1;
elasticity = 0.2;
friction = 0.6;
emap = true;

// Dynamic properties defined by the scripts
pickUpName = “a crossbow”;
image = CrossbowImage;
};

//————————————————————————–
// Crossbow image which does all the work. Images do not normally exist in
// the world, they can only be mounted on ShapeBase objects.

datablock ShapeBaseImageData(CrossbowImage)
{
// Basic Item properties
shapeFile = “~/data/shapes/crossbow/weapon.dts”;
emap = true;

// Specify mount point & offset for 3rd person, and eye offset
// for first person rendering.
mountPoint = 0;
eyeOffset = “0.1 0.4 -0.6″;

// When firing from a point offset from the eye, muzzle correction
// will adjust the muzzle vector to point to the eye LOS point.
// Since this weapon doesn’t actually fire from the muzzle point,
// we need to turn this off.
correctMuzzleVector = false;

// Add the WeaponImage namespace as a parent, WeaponImage namespace
// provides some hooks into the inventory system.
className = “WeaponImage”;

// Projectile && Ammo.
item = Crossbow;
ammo = CrossbowAmmo;
projectile = CrossbowProjectile;
projectileType = Projectile;

// Images have a state system which controls how the animations
// are run, which sounds are played, script callbacks, etc. This
// state system is downloaded to the client so that clients can
// predict state changes and animate accordingly. The following
// system supports basic ready->fire->reload transitions as
// well as a no-ammo->dryfire idle state.

// Initial start up state
stateName[0] = “Preactivate”;
stateTransitionOnLoaded[0] = “Activate”;
stateTransitionOnNoAmmo[0] = “NoAmmo”;

// Activating the gun. Called when the weapon is first
// mounted and there is ammo.
stateName[1] = “Activate”;
stateTransitionOnTimeout[1] = “Ready”;
stateTimeoutValue[1] = 0.6;
stateSequence[1] = “Activate”;

// Ready to fire, just waiting for the trigger
stateName[2] = “Ready”;
stateTransitionOnNoAmmo[2] = “NoAmmo”;
stateTransitionOnTriggerDown[2] = “Fire”;

// Fire the weapon. Calls the fire script which does
// the actual work.
stateName[3] = “Fire”;
stateTransitionOnTimeout[3] = “Reload”;
stateTimeoutValue[3] = 0.2;
stateFire[3] = true;
stateRecoil[3] = LightRecoil;
stateAllowImageChange[3] = false;
stateSequence[3] = “Fire”;
stateScript[3] = “onFire”;
stateSound[3] = CrossbowFireSound;

// Play the relead animation, and transition into
stateName[4] = “Reload”;
stateTransitionOnNoAmmo[4] = “NoAmmo”;
stateTransitionOnTimeout[4] = “Ready”;
stateTimeoutValue[4] = 0.8;
stateAllowImageChange[4] = false;
stateSequence[4] = “Reload”;
stateEjectShell[4] = true;
stateSound[4] = CrossbowReloadSound;

// No ammo in the weapon, just idle until something
// shows up. Play the dry fire sound if the trigger is
// pulled.
stateName[5] = “NoAmmo”;
stateTransitionOnAmmo[5] = “Reload”;
stateSequence[5] = “NoAmmo”;
stateTransitionOnTriggerDown[5] = “DryFire”;

// No ammo dry fire
stateName[6] = “DryFire”;
stateTimeoutValue[6] = 1.0;
stateTransitionOnTimeout[6] = “NoAmmo”;
stateSound[6] = CrossbowFireEmptySound;
};

//—————————————————————————–

function CrossbowImage::onFire(%this, %obj, %slot)
{
%projectile = %this.projectile;

// Decrement inventory ammo. The image’s ammo state is update
// automatically by the ammo inventory hooks.
%obj.decInventory(%this.ammo,1);

// Determin initial projectile velocity based on the
// gun’s muzzle point and the object’s current velocity
%muzzleVector = %obj.getMuzzleVector(%slot);
%objectVelocity = %obj.getVelocity();
%muzzleVelocity = VectorAdd(
VectorScale(%muzzleVector, %projectile.muzzleVelocity),
VectorScale(%objectVelocity, %projectile.velInheritFactor));

// Create the projectile object
%p = new (%this.projectileType)() {
dataBlock = %projectile;
initialVelocity = %muzzleVelocity;
initialPosition = %obj.getMuzzlePoint(%slot);
sourceObject = %obj;
sourceSlot = %slot;
client = %obj.client;
};
MissionCleanup.add(%p);
return %p;
}

…smokes, was that long or what (pun intended)? Ok, my next tutorial will be how to make a simple character that will run, walk, jump, and even pee (naw, just kidding) in Torque! However it is July and I am ready for a much needed break from all and many things digital. Please chime in and add your comments. Let me know that these tutorials are not falling on deaf ears, so to speak.

…sip…

Leave a Reply

You must be logged in to post a comment.