¡Hola! Here’s a preview of ‘Vehiclo’, an extensive T3D mod that adds additional vehicles types, functionality and vehicular AI. This simple mod will add a basic flyingVehicle to the ‘Full’ Template, with which you can begin your own experimentation with flyers in Torque. This is written for T3D 3.10 but should, with a few tweaks, work in any T3D_3+ version. Caveats: Passenger/Weapon mounting not included. By default this will make mounted players hidden Flyers have had issues ‘sticking’ to terrain since TGE. Check this post for scripted/coded fixes: http://forums.torque3d.org/viewtopic.php?f=23&t=102&p=784&hilit=flyingVehicle#p784 I hope to post the complete 'Vehiculo' mods on GitHub soon, just have to work out a few more issues… Step 1: Setup a new project using the Full template Download these files, and extract to a new directory, art/shapes/vehicles/jetFighter http://opengameart.org/content/future-fighterjet-for-torque3d Step 2: Add these files to "art/datablocks/vehicles" art/datablocks/vehicles/jetFighter_fx.cs
//-----------------------------------------------------------------------------
// Vehiculo
// "Gibby's Generic Jet Fighter FX"
// Basic Jet Fighter effects
//-----------------------------------------------------------------------------
//--------------------------------------------------------------
// Glowing explosion Sparks
//--------------------------------------------------------------
datablock ParticleData(jetFighterExplosionSparks)
{
textureName = "art/particles/SparkParticle";
dragCoefficient = 0;
gravityCoefficient = 0.5;
inheritedVelFactor = 0.1;
constantAcceleration = 0.0;
lifetimeMS = 3000;
lifetimeVarianceMS = 500;
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] = 1.0;
sizes[1] = 0.4;
sizes[2] = 0.1;
times[0] = 0.0;
times[1] = 1.4;
times[2] = 2.0;
};
datablock ParticleEmitterData(jetFighterExplosionSparkEmitter)
{
ejectionPeriodMS = 10;
periodVarianceMS = 0;
ejectionVelocity = 8;
velocityVariance = 2;
thetaMin = 0.0;
thetaMax = 180.0;
lifetimeMS = 1000;
overrideAdvances = false;
orientParticles = true;
particles = "jetFighterExplosionSparks";
};
//--------------------------------------------------------------
// Explosion Smoke
//--------------------------------------------------------------
datablock ParticleData(jetFighterExplosionSmoke)
{
textureName = "art/particles/smoke";
dragCoeffiecient = 0.7;
gravityCoefficient = 0.1;
inheritedVelFactor = 1.0;
//constantAcceleration = -0.80;
lifetimeMS = 10000;
lifetimeVarianceMS = 3000;
useInvAlpha = true;
windCoefficient = 0.0;
colors[0] = "0.56 0.36 0.26 1.0";
colors[1] = "0.0 0.0 0.0 1.0";
colors[2] = "0.2 0.2 0.2 0.0";
sizes[0] = 10.0;
sizes[1] = 20.0;
sizes[2] = 50.0;
times[0] = 0.0;
times[1] = 0.1;
times[2] = 1.0;
};
datablock ParticleEmitterData(jetFighterExplosionSmokeEmitter)
{
ejectionPeriodMS = 100;
periodVarianceMS = 0;
ejectionVelocity = 5;
velocityVariance = 5;
thetaMin = 0.0;
thetaMax = 180.0;
lifetimeMS = 1500;
particles = "jetFighterExplosionSmoke";
};
//--------------------------------------------------------------
// jetFighter Debris Smoke
//--------------------------------------------------------------
datablock ParticleData(jetFighterDebrisSmoke)
{
dragCoefficient = 0.0;
//gravityCoefficient = -0.1;
gravityCoefficient = 0.1;
inheritedVelFactor = 0.2;
windCoefficient = 0.3;
constantAcceleration = 0.0;
lifetimeMS = 4000;
lifetimeVarianceMS = 1500;
useInvAlpha = true;
spinRandomMin = -90.0;
spinRandomMax = 90.0;
textureName = "art/particles/smoke";
colors[0] = "0.1 0.1 0.1 0.8";
colors[1] = "0.7 0.7 0.7 0.6";
colors[2] = "0.9 0.9 0.9 0.0";
sizes[0] = 0.5;
sizes[1] = 1.0;
sizes[2] = 2.0;
times[0] = 0.0;
times[1] = 0.4;
times[2] = 1.0;
};
datablock ParticleEmitterData(jetFighterDebrisSmokeEmitter)
{
ejectionPeriodMS = 20;
periodVarianceMS = 0;
ejectionVelocity = 1;
velocityVariance = 1.0;
ejectionOffset = 0.0;
thetaMin = 0;
thetaMax = 35;
phiReferenceVel = 0;
phiVariance = 10;
overrideAdvances = false;
particles = "jetFighterDebrisSmoke";
lifetimeMS = 10000;
lifetimeVarianceMS = 2000;
};
//--------------------------------------------------------------
// Contrail smoke
//--------------------------------------------------------------
datablock ParticleData(jetFighterContrailParticle)
{
dragCoefficient = 1.5;
gravityCoefficient = 0;
inheritedVelFactor = 0.2;
constantAcceleration = 0.0;
lifetimeMS = 2000;
lifetimeVarianceMS = 0;
textureName = "art/particles/dustParticle";
colors[0] = "0.6 0.6 0.6 0.5";
colors[1] = "0.2 0.2 0.2 0";
sizes[0] = 0.6;
sizes[1] = 2;
};
datablock ParticleEmitterData(jetFighterContrailEmitter)
{
ejectionPeriodMS = 10;
periodVarianceMS = 0;
ejectionVelocity = 1;
velocityVariance = 1.0;
ejectionOffset = 0.0;
thetaMin = 0;
thetaMax = 10;
phiReferenceVel = 0;
phiVariance = 360;
overrideAdvances = false;
particles = "jetFighterContrailParticle";
};
//--------------------------------------------------------------
// jetFighter damage smoke
//--------------------------------------------------------------
datablock ParticleData(jetFighterDamageSmokeParticle)
{
dragCoefficient = 0.0;
gravityCoefficient = 0.1;
inheritedVelFactor = 0.5;
constantAcceleration = 0.0;
lifetimeMS = 1500;
lifetimeVarianceMS = 200;
useInvAlpha = true;
spinRandomMin = -90.0;
spinRandomMax = 90.0;
textureName = "art/particles/dustParticle";
colors[0] = "0.7 0.7 0.7 0.0";
colors[1] = "0.5 0.5 0.5 0.7";
colors[2] = "0.3 0.3 0.3 0.0";
sizes[0] = 1.2;
sizes[1] = 2.6;
sizes[2] = 4.0;
times[0] = 0.0;
times[1] = 0.5;
times[2] = 1.0;
};
datablock ParticleEmitterData(jetFighterDamageSmoke)
{
ejectionPeriodMS = 30;
periodVarianceMS = 6;
ejectionVelocity = 4.0;
velocityVariance = 0.5;
ejectionOffset = 1.5;
thetaMin = 0;
thetaMax = 35;
overrideAdvances = false;
particles = "jetFighterDamageSmokeParticle";
};
//--------------------------------------------------------------
// Flying jet smoke
//--------------------------------------------------------------
datablock ParticleData(jetFighterParticle)
{
dragCoefficient = 1.5;
gravityCoefficient = 0;
inheritedVelFactor = 0.2;
constantAcceleration = 0.0;
lifetimeMS = 1000;
lifetimeVarianceMS = 200;
useInvAlpha = true;
textureName = "art/particles/dustParticle";
colors[0] = "0.96 0.96 0.96 0.6";
colors[1] = "0.3 0.3 0.3 0";
sizes[0] = 1;
sizes[1] = 6;
//times[0] = 0.0;
//times[1] = 0.4;
};
datablock ParticleEmitterData(jetFighterJetEmitter)
{
ejectionPeriodMS = 15;
periodVarianceMS = 0;
ejectionVelocity = 20;
velocityVariance = 1.0;
ejectionOffset = 0.0;
thetaMin = 0;
thetaMax = 10;
phiReferenceVel = 0;
phiVariance = 360;
overrideAdvances = false;
particles = "jetFighterParticle";
};
//--------------------------------------------------------------
// Lift off smoke (vertical)
//--------------------------------------------------------------
datablock ParticleData(jetFighterParticleDown)
{
dragCoefficient = 1.5;
gravityCoefficient = 0.5;
inheritedVelFactor = 0.2;
constantAcceleration = 0.0;
lifetimeMS = 500;
lifetimeVarianceMS = 50;
textureName = "art/particles/dustParticle";
useInvAlpha = true;
colors[0] = "0.9 0.9 0.9 0.6";
colors[1] = "0.3 0.3 0.3 0";
//colors[0] = "0.9 0.7 0.3 0.6";
//colors[1] = "0.3 0.3 0.5 0";
sizes[0] = 1;
sizes[1] = 6;
};
datablock ParticleEmitterData(jetFighterJetEmitterDown)
{
ejectionPeriodMS = 15;
periodVarianceMS = 0;
ejectionVelocity = 20;
velocityVariance = 1.0;
ejectionOffset = 0.0;
thetaMin = 0;
thetaMax = 10;
phiReferenceVel = 0;
phiVariance = 360;
overrideAdvances = false;
particles = "jetFighterParticleDown";
};
//--------------------------------------------------------------
// Hover smoke
//--------------------------------------------------------------
datablock ParticleData(jetFighterDust)
{
dragCoefficient = 1.0;
gravityCoefficient = 0.01;
inheritedVelFactor = 0.0;
constantAcceleration = 0.0;
lifetimeMS = 1000;
lifetimeVarianceMS = 200;
useInvAlpha = true;
spinRandomMin = -90.0;
spinRandomMax = 500.0;
textureName = "art/particles/dustParticle";
colors[0] = "0.46 0.36 0.26 0.0";
colors[1] = "0.46 0.46 0.36 0.9";
colors[2] = "0.46 0.46 0.36 0.4";
sizes[0] = 3.2;
sizes[1] = 4.6;
sizes[2] = 7.0;
times[0] = 0.0;
times[1] = 0.5;
times[2] = 1.0;
};
datablock ParticleEmitterData(jetFighterDustEmitter)
{
ejectionPeriodMS = 15;
periodVarianceMS = 0;
ejectionVelocity = 15.0;
velocityVariance = 0.0;
ejectionOffset = 0.0;
thetaMin = 90;
thetaMax = 90;
phiReferenceVel = 0;
phiVariance = 360;
overrideAdvances = false;
//useEmitterColors = true;
particles = "jetFighterDust";
};
//--------------------------------------------------------------
// Foam Smoke
//--------------------------------------------------------------
datablock ParticleData(jetFighterFoamParticle)
{
dragCoefficient = 2.0;
gravityCoefficient = -0.05;
inheritedVelFactor = 0.0;
constantAcceleration = 0.0;
lifetimeMS = 1200;
lifetimeVarianceMS = 400;
useInvAlpha = false;
spinRandomMin = -90.0;
spinRandomMax = 500.0;
textureName = "art/particles/dustParticle";
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] = 2;
sizes[1] = 4;
sizes[2] = 6;
times[0] = 0.0;
times[1] = 0.5;
times[2] = 1.0;
};
datablock ParticleEmitterData(jetFighterFoamEmitter)
{
ejectionPeriodMS = 40;
periodVarianceMS = 0;
ejectionVelocity = 10.0;
velocityVariance = 1.0;
ejectionOffset = 0.0;
thetaMin = 85;
thetaMax = 85;
phiReferenceVel = 0;
phiVariance = 360;
overrideAdvances = false;
particles = "jetFighterFoamParticle";
};
// ---------------------------------------------------------------
datablock ParticleData(jetFighterExplosionParticle)
{
dragCoefficient = 2;
gravityCoefficient = 0.2;
inheritedVelFactor = 0.9;
constantAcceleration = 0.0;
lifetimeMS = 6000;
lifetimeVarianceMS = 800;
textureName = "art/particles/dustParticle";
colors[0] = "0.86 0.36 0.26 1.0";
colors[1] = "0.70 0.36 0.26 0.5";
colors[2] = "0.56 0.36 0.26 0.0";
sizes[0] = 8.5;
sizes[1] = 11.5;
sizes[2] = 17.0;
};
datablock ParticleEmitterData(jetFighterExplosionEmitter)
{
ejectionPeriodMS = 12;
periodVarianceMS = 0;
ejectionVelocity = 5;
velocityVariance = 1.0;
ejectionOffset = 0.0;
thetaMin = 0;
thetaMax = 60;
phiReferenceVel = 0;
phiVariance = 360;
overrideAdvances = false;
particles = "jetFighterExplosionParticle";
};
datablock ExplosionData(jetFighterExplosion)
{
//explosionShape = "art/shapes/vehicles/ship_scout/scout_debris.dts";
playSpeed = 1.0;
particleEmitter = jetFighterExplosionEmitter;
particleDensity = 60;
particleRadius = 2; // total size of the explosion. Scale it up to have bigger explosions
faceViewer = true;
explosionScale = "1 1 1";
shakeCamera = true;
camShakeFreq = "10.0 11.0 10.0";
camShakeAmp = "1.0 1.0 1.0";
camShakeDuration = 0.5;
camShakeRadius = 80.0;
//soundProfile = jetFighterExplosionSound;
emitter[0] = jetFighterExplosionSparkEmitter;
};
datablock DebrisData(jetFighterDebris)
{
explodeOnMaxBounce = true;
elasticity = 0.15;
friction = 0.5;
lifetime = 7.0;
lifetimeVariance = 4.0;
minSpinSpeed = 40;
maxSpinSpeed = 600;
numBounces = 1;
bounceVariance = 1;
staticOnMaxBounce = true;
gravModifier = 1.0;
useRadiusMass = true;
baseRadius = 1;
velocity = 30.0;
velocityVariance = 12.0;
emitters[0] = jetFighterDebrisSmokeEmitter;
};
art/datablocks/vehicles/jetFighterDB.cs
//-----------------------------------------------------------------------------
// Vehiculo
// "Gibby's Generic Get Fighter"
// A basic flying vehicle datablock
//-----------------------------------------------------------------------------
exec("./jetFighter_fx.cs"); // visual fx
datablock FlyingVehicleData( JetFighter )
{
category = "Vehicles";
shapeFile = "art/shapes/vehicles/fighterJet/fighterJet.dts";
// 3rd person camera settings
cameraRoll = true;
cameraMaxDist = 16;
cameraOffset = 1.0;
cameraLag = 0.1;
cameraDecay = 1.25;
// Rigid Body
mass = 100;
massCenter = "0 -0.2 0";
massBox = "0 0 0";
integration = 3;
collisionTol = 0.6;
contactTol = 0.4;
bodyFriction = 0;
bodyRestitution = 0.8;
minRollSpeed = 2000;
minImpactSpeed = 5;
softImpactSpeed = 3;
hardImpactSpeed = 15;
// Physics
drag = 0.25;
minDrag = 40;
rotationalDrag = 20;
// Autostabilizer
maxAutoSpeed = 6;
autoAngularForce = 400;
autoLinearForce = 300;
autoInputDamping = 0.55;
// Maneuvering
maxSteeringAngle = 3;
powerSteering = true; // Power Steering
steeringReturn = 0; // Steering return-to-center
steeringReturnSpeedScale = 0.01; // Steering return-to-center scale
horizontalSurfaceForce = 20;
verticalSurfaceForce = 20;
maneuveringForce = 6400;
steeringForce = 500;
steeringRollForce = 200;
rollForce = 10;
hoverHeight = 0.5;
createHoverHeight = 0.5;
maxForwardSpeed = 150;
// Vertical jetting
minJetEnergy = 5;
jetForce = 750;
jetEnergyDrain = 5;
vertThrustMultiple = 10.0;
// Object Impact Damage
collDamageThresholdVel = 10.0;
collDamageMultiplier = 0.05;
minImpactSpeed = 10; // If hit ground at speed above this then it's an impact. Meters / second
speedDamageScale = 0.5; // war 0.06
// Misc
computeCRC = true;
// Damage/Energy
maxDamage = 500; // total damage until explosion
maxEnergy = 5000; // Afterburner and any energy weapon pool
//energyPerDamagePoint = 160;
destroyedLevel = 1.40;
rechargeRate = 50; // Afterburner recharge rate was 0.41
// Emitters
forwardJetEmitter = jetFighterJetEmitter;
backwardJetEmitter = jetFighterJetEmitter;
downJetEmitter = jetFighterJetEmitterDown;
trailEmitter = jetFighterContrailEmitter;
minTrailSpeed = 10;
//splashEmitter = VehicleFoamEmitter; // water splash stuff
//dustEmitter = DustEmitter; // dust emitter when hovering over the ground
//triggerDustHeight = 8;
//dustHeight = 8;
// Sounds
engineSound = genericJetEngineSound;//FighterEngineSnd;
//jetSound = genericJetThrustSound; //FighterJettingSnd;
//----------------
softImpactSound = softImpact;
hardImpactSound = hardImpact;
// Velocities
softSplashSoundVelocity = 10.0;
mediumSplashSoundVelocity = 15.0;
hardSplashSoundVelocity = 20.0;
exitSplashSoundVelocity = 10.0;
// Damage emitters
damageEmitter[0] = jetFighterDamageSmoke;
damageEmitter[1] = HeavyDamageSmoke;
damageEmitter[2] = DestroyedDamageSmoke;
damageEmitterOffset[0] = "0 0 0";
damageLevelTolerance[0] = 0.3;
damageLevelTolerance[1] = 0.7;
damageLevelTolerance[2] = 0.9;
numDmgEmitterAreas = 3;
// Explosion and debris setup
explosion = jetFighterExplosion;
underwaterExplosion = RocketLauncherWaterExplosion;
explosionDamage = 40; // How much damage is applied through a radiusDamage function call
explosionRadius = 30; // the radius for the radiusDamage function call
debris = jetFighterDebris; // the debris datablock
debrisShapeName = "art/shapes/vehicles/fighterJet/fighterJetDebris.dts"; // our debris shape (containts the explosion parts)
mountPose = "sitting";
};
Step3: Add these lines to art/datablockExec.cs at line 65
exec("./vehicles/jetFighter_fx.cs");
exec("./vehicles/jetFighterDB.cs");
Step4: Add these lines to Empty Terrain.mis at line 115:
new FlyingVehicle() {
disableMove = "0";
isAIControlled = "0";
dataBlock = "jetFighter";
position = "-4.55322 -4.56358 246.531";
rotation = "0.00621613 0.00266831 -0.999977 24.1927";
scale = "1 1 1";
canSave = "1";
canSaveDynamicFields = "1";
mountable = "1";
};
Step 5: Add these lines to scripts/client/default.binds.cs at line 304:
//-->> Vehiculo
function doBoost(%val)
{
$mvTriggerCount3++;
}
//<<-- Vehiculo
And this to the vehicleMap at line 762:
vehicleMap.bind(keyboard, "lshift", doBoost);
Step 6: Add this file to server/vehicles/ and execute it in scriptExec.cs: jetFighter.cs
//-----------------------------------------------------------------------------
// Vehiculo
// "Gibby's Generic Jet Fighter"
// Basic flying vehicle functionality
//-----------------------------------------------------------------------------
function jetFighter::create(%block)
{
//echo("jetFighter->create called.");
%obj = new FlyingVehicle() {
dataBlock = %block;
};
return(%obj);
}
function jetFighter::onAdd(%this,%obj)
{
Parent::onAdd( %this, %obj );
%obj.setEnergyLevel(%this.MaxEnergy);
%obj.setRechargeRate(%this.rechargeRate);
//%obj.setRechargeRate( 25 );
%obj.setRepairRate(0);
%obj.mountable=true;
}
function jetFighter::onCollision(%this, %obj, %col)
{
//echo("jetFighter->onCollision called.");
if(!isObject(%obj))
return;//don't do anything if we don't exist :P
}
function jetFighter::onImpact(%this, %obj, %collidedObject, %vec, %vecLen)
{
//echo("jetFighter->onImpact called: " @ %this SPC %obj SPC %collidedObject SPC %vec SPC %vecLen);
if(%vecLen > %obj.minImpactSpeed)
%obj.damage(0, VectorAdd(%obj.getPosition(), %vec), %vecLen * %this.speedDamageScale, "Impact");
}
function jetFighter::damage(%this, %obj, %sourceObject, %position, %damage, %damageType)
{
if (%obj.getDamageState() $= "Destroyed")
return;
%name = %obj.getShapeName;
%db = %obj.getDatablock().getName();
%damageMax = %db.maxDamage;
%team = %obj.team;
%obj.applyDamage(%damage);
if (%obj.getDamageState() $= "Destroyed")
{
//Conventional Blast here
%pos = %obj.getPosition();
%blastPos = %pos;
%vehicle_blast = new explosion()
{
dataBlock = RocketLauncherExplosion;
position = %blastPos;
};
MissionCleanup.add(%vehicle_blast);
}
}
function jetFighter::onDamage(%this, %obj, %delta)
{
//echo("jetFighter->onDamage called.");
%damage = %obj.getDamageLevel();
%healthLeft = %this.maxDamage - %damage;
if(%damage >= %this.maxDamage)
{
if (isObject(%obj))
{
%obj.setDamageState(Destroyed);
}
}
}
function jetFighter::onDisabled(%this,%obj,%state)
{
//echo("jetFighter->onDisabled called.");
// Release the main weapon trigger
%obj.setImageTrigger(0,false);
%obj.setImageTrigger(1,false);
// Schedule corpse removal. Just keeping the place clean.
%obj.schedule(1, "startFade", 1, 0, true);
%obj.schedule(1, "delete");
}
$FlyerDamageWater = 1.4;
$FlyerDamageLava = 1.4;
$FlyerDamageHotLava = 1.4;
$FlyerDamageCrustyLava = 1.4;
function jetFighter::onEnterLiquid(%this, %obj, %coverage, %type)
{
//echo("jetFighter->onEnterLiquid called.");
switch(%type)
{
case 0: //Water
%obj.setDamageDt($FlyerDamageWater, "Water");
case 1: //Ocean Water
%obj.setDamageDt($FlyerDamageWater, "Water");
case 2: //River Water
%obj.setDamageDt($FlyerDamageWater, "Water");
case 3: //Stagnant Water
%obj.setDamageDt($FlyerDamageWater, "Water");
case 4: //Lava
%obj.setDamageDt($FlyerDamageLava, "Lava");
case 5: //Hot Lava
%obj.setDamageDt($FlyerDamageHotLava, "Lava");
case 6: //Crusty Lava
%obj.setDamageDt($FlyerDamageCrustyLava, "Lava");
case 7: //Quick Sand
}
}
function jetFighter::onLeaveLiquid(%this, %obj, %type)
{
//echo("jetFighter->onLeaveLiquid called.");
%obj.clearDamageDt();
}
Step 7: Change this line in PlayerData::onCollision at line 176:
if ((%db.getClassName() $= "WheeledVehicleData" || %db.getClassName() $= "FlyingVehicleData") && %obj.mountVehicle && %obj.getState() $= "Move" && %col.mountable)
Step 8: Add this line to the PlayerData::onMount function in scripts/server/player.cs at line 66:
%obj.setAllMeshesHidden(true);
%obj.isHidden = true;
Step 9: Add these lines to the PlayerData::onUnmount function in scripts/server/player.cs at line 88:
%obj.setAllMeshesHidden(false);
%obj.isHidden = false;
if(%obj.getClassName() $= "Player")
commandToClient(%obj.client, 'toggleVehicleMap', true);
Step 10: Add this line to scripts/server/scriptExec.cs at line 54:
exec("./vehicles/jetFighter.cs");
Run the game, play the ‘Empty Terrain’ mission and look to your left. Bump into the flyer and you’re airborne!