--------------------------------------------------------------------------------------------
Long Range Artillery Tutorial
--------------------------------------------------------------------------------------------
This tutorial creates a tank type vehicle with a dual chaingun turret. It also has two stationary cannons pointing up in the air. When the targeting laser is used between 250 and 750 meters away, the vehicle auto fires the cannons at the spot being lazed. It becomes a little less accurate when firing at max distance. This one could probably stand to be toned down a little for balancing purposes, but I'll leave that up to you.
Step #1
// ------------------------------------------
// Station.cs
// ------------------------------------------
In function StationVehiclePad::onAdd, add this:
if(%obj.Artillery !$= "Removed")
%sv.vehicle[Artillery] = true;
Step #2
// ------------------------------------------
// ServerVehicleHud.cs
// ------------------------------------------
In function VehicleHud::updateHud, add this:
if ( %station.vehicle[Artillery] )
{
messageClient( %client, 'SetLineHud', "", %tag, %count, "LONG RANGE ARTILLERY", "", Artillery, $VehicleMax[Artillery] - $VehicleTotalCount[%team, Artillery] );
%count++;
}
Step #3
// ------------------------------------------
// Vehicle.cs
// ------------------------------------------
3a)Add this line at the appropriate spot:
$VehicleMax[Artillery] = 2;
3b) In function clearVehicleCount, add this:
$VehicleTotalCount[%team, Artillery] = 0;
Step #4
// ------------------------------------------
// Server.cs
// ------------------------------------------
In function CreateServer, above this line:
exec("scripts/vehicles/vehicle.cs");
Add this:
exec("scripts/vehicles/vehicle_artillery.cs");
Step #5
// ------------------------------------------
// Projectiles.cs
// ------------------------------------------
Add this to the bottom of function TargetingLaserImage::onFire:
%obj.posLaze = 1;
Next below that function, add this function:
function TargetingLaserImage::deconstruct(%data, %obj, %slot)
{
%obj.posLaze = 0;
Parent::deconstruct(%data, %obj, %slot);
}
Step #6
// ------------------------------------------
// vehicle_artillery.cs
// ------------------------------------------
Create a file called vehicle_artillery.cs in your vehicle's directory. Add all this into it.
//**************************************************************
// Long Range Artillery
//**************************************************************
//**************************************************************
// SOUNDS
//**************************************************************
datablock AudioProfile(ArtillerySkid)
{
filename = "fx/vehicles/tank_skid.wav";
description = ClosestLooping3d;
preload = true;
};
datablock AudioProfile(ArtilleryEngineSound)
{
filename = "fx/vehicles/tank_engine.wav";
description = AudioDefaultLooping3d;
preload = true;
};
datablock AudioProfile(ArtilleryThrustSound)
{
filename = "fx/vehicles/tank_boost.wav";
description = AudioDefaultLooping3d;
preload = true;
};
datablock AudioProfile(ArtilleryChaingunFireSound)
{
filename = "fx/vehicles/tank_chaingun.wav";
description = AudioDefaultLooping3d;
preload = true;
};
datablock AudioProfile(ArtilleryChaingunReloadSound)
{
filename = "fx/weapons/chaingun_dryfire.wav";
description = AudioClose3d;
preload = true;
};
datablock AudioProfile(TankChaingunProjectile)
{
filename = "fx/weapons/chaingun_projectile.wav";
description = ProjectileLooping3d;
preload = true;
};
datablock AudioProfile(ArtilleryTurretActivateSound)
{
filename = "fx/vehicles/tank_activate.wav";
description = AudioClose3d;
preload = true;
};
datablock AudioProfile(ArtilleryChaingunDryFireSound)
{
filename = "fx/weapons/chaingun_dryfire.wav";
description = AudioClose3d;
preload = true;
};
datablock AudioProfile(ArtilleryChaingunIdleSound)
{
filename = "fx/misc/diagnostic_on.wav";
description = ClosestLooping3d;
preload = true;
};
datablock AudioProfile(ArtilleryMortarDryFireSound)
{
filename = "fx/weapons/mortar_dryfire.wav";
description = AudioClose3d;
preload = true;
};
datablock AudioProfile(ArtilleryMortarFireSound)
{
filename = "fx/vehicles/tank_mortar_fire.wav";
description = AudioClose3d;
preload = true;
};
datablock AudioProfile(ArtilleryMortarReloadSound)
{
filename = "fx/weapons/mortar_reload.wav";
description = AudioClose3d;
preload = true;
};
datablock AudioProfile(ArtilleryMortarIdleSound)
{
filename = "fx/misc/diagnostic_on.wav";
description = ClosestLooping3d;
preload = true;
};
//**************************************************************
// LIGHTS
//**************************************************************
datablock RunningLightData(TankLight1)
{
radius = 1.5;
color = "1.0 1.0 1.0 0.2";
nodeName = "Headlight_node01";
direction = "0.0 1.0 0.0";
texture = "special/headlight4";
};
datablock RunningLightData(TankLight2)
{
radius = 1.5;
color = "1.0 1.0 1.0 0.2";
nodeName = "Headlight_node02";
direction = "0.0 1.0 0.0";
texture = "special/headlight4";
};
datablock RunningLightData(TankLight3)
{
radius = 1.5;
color = "1.0 1.0 1.0 0.2";
nodeName = "Headlight_node03";
direction = "0.0 1.0 0.0";
texture = "special/headlight4";
};
datablock RunningLightData(TankLight4)
{
radius = 1.5;
color = "1.0 1.0 1.0 0.2";
nodeName = "Headlight_node04";
direction = "0.0 1.0 0.0";
texture = "special/headlight4";
};
//**************************************************************
// VEHICLE CHARACTERISTICS
//**************************************************************
datablock HoverVehicleData(Artillery) : TankDamageProfile
{
spawnOffset = "0 0 4";
floatingGravMag = 4.5;
catagory = "Vehicles";
shapeFile = "vehicle_grav_tank.dts";
multipassenger = true;
computeCRC = true;
renderWhenDestroyed = false;
weaponNode = 1;
debrisShapeName = "vehicle_land_assault_debris.dts";
debris = ShapeDebris;
drag = 0.0;
density = 0.9;
mountPose[0] = sitting;
mountPose[1] = sitting;
numMountPoints = 2;
isProtectedMountPoint[0] = true;
isProtectedMountPoint[1] = true;
cameraMaxDist = 20;
cameraOffset = 3;
cameraLag = 1.5;
explosion = LargeGroundVehicleExplosion2;
explosionDamage = 0.5;
explosionRadius = 5.0;
maxSteeringAngle = 0.5; // 20 deg.
maxDamage = 1.575;
destroyedLevel = 1.575;
isShielded = true;
rechargeRate = 1.0;
energyPerDamagePoint = 300;
maxEnergy = 400;
minJetEnergy = 15;
jetEnergyDrain = 2.0;
// Rigid Body
mass = 4000;
bodyFriction = 0.8;
bodyRestitution = 0.5;
minRollSpeed = 3;
gyroForce = 400;
gyroDamping = 0.3;
stabilizerForce = 20;
minDrag = 10;
softImpactSpeed = 15; // Play SoftImpact Sound
hardImpactSpeed = 18; // Play HardImpact Sound
// Ground Impact Damage (uses DamageType::Ground)
minImpactSpeed = 17;
speedDamageScale = 0.060;
// Object Impact Damage (uses DamageType::Impact)
collDamageThresholdVel = 18;
collDamageMultiplier = 0.045;
dragForce = 40 / 20;
vertFactor = 0.0;
floatingThrustFactor = 0.15;
mainThrustForce = 50;
reverseThrustForce = 40;
strafeThrustForce = 40;
turboFactor = 1.7;
brakingForce = 25;
brakingActivationSpeed = 4;
stabLenMin = 3.25;
stabLenMax = 4;
stabSpringConstant = 50;
stabDampingConstant = 20;
gyroDrag = 20;
normalForce = 20;
restorativeForce = 10;
steeringForce = 15;
rollForce = 5;
pitchForce = 3;
dustEmitter = TankDustEmitter;
triggerDustHeight = 3.5;
dustHeight = 1.0;
dustTrailEmitter = TireEmitter;
dustTrailOffset = "0.0 -1.0 0.5";
triggerTrailHeight = 3.6;
dustTrailFreqMod = 15.0;
jetSound = ArtilleryThrustSound;
engineSound = ArtilleryEngineSound;
floatSound = ArtillerySkid;
softImpactSound = GravSoftImpactSound;
hardImpactSound = HardImpactSound;
wheelImpactSound = WheelImpactSound;
forwardJetEmitter = TankJetEmitter;
//
softSplashSoundVelocity = 5.0;
mediumSplashSoundVelocity = 10.0;
hardSplashSoundVelocity = 15.0;
exitSplashSoundVelocity = 10.0;
exitingWater = VehicleExitWaterMediumSound;
impactWaterEasy = VehicleImpactWaterSoftSound;
impactWaterMedium = VehicleImpactWaterMediumSound;
impactWaterHard = VehicleImpactWaterMediumSound;
waterWakeSound = VehicleWakeMediumSplashSound;
minMountDist = 4;
damageEmitter[0] = SmallLightDamageSmoke;
damageEmitter[1] = SmallHeavyDamageSmoke;
damageEmitter[2] = DamageBubbles;
damageEmitterOffset[0] = "0.0 -1.5 3.5 ";
damageLevelTolerance[0] = 0.3;
damageLevelTolerance[1] = 0.7;
numDmgEmitterAreas = 1;
splashEmitter[0] = VehicleFoamDropletsEmitter;
splashEmitter[1] = VehicleFoamEmitter;
shieldImpact = VehicleShieldImpact;
cmdCategory = "Tactical";
cmdIcon = CMDGroundTankIcon;
cmdMiniIconName = "commander/MiniIcons/com_tank_grey";
targetNameTag = 'Beowulf';
targetTypeTag = 'Long Range Artillery';
sensorData = VehiclePulseSensor;
checkRadius = 5.5535;
observeParameters = "1 10 10";
runningLight[0] = TankLight1;
runningLight[1] = TankLight2;
runningLight[2] = TankLight3;
runningLight[3] = TankLight4;
shieldEffectScale = "0.9 1.0 0.6";
showPilotInfo = 1;
};
//**************************************************************
// WEAPONS
//**************************************************************
//-------------------------------------
// Artillery CHAINGUN (projectile)
//-------------------------------------
datablock TracerProjectileData(ArtilleryChaingunBullet)
{
doDynamicClientHits = true;
projectileShapeName = "";
directDamage = 0.16;
directDamageType = $DamageType::TankChaingun;
hasDamageRadius = false;
splash = ChaingunSplash;
kickbackstrength = 0.0;
sound = TankChaingunProjectile;
dryVelocity = 425.0;
wetVelocity = 100.0;
velInheritFactor = 1.0;
fizzleTimeMS = 3000;
lifetimeMS = 3000;
explodeOnDeath = false;
reflectOnWaterImpactAngle = 0.0;
explodeOnWaterImpact = false;
deflectionOnWaterImpact = 0.0;
fizzleUnderwaterMS = 3000;
tracerLength = 15.0;
tracerAlpha = false;
tracerMinPixels = 6;
tracerColor = 211.0/255.0 @ " " @ 215.0/255.0 @ " " @ 120.0/255.0 @ " 0.75";
tracerTex[0] = "special/tracer00";
tracerTex[1] = "special/tracercross";
tracerWidth = 0.10;
crossSize = 0.20;
crossViewAng = 0.990;
renderCross = true;
decalData[0] = ChaingunDecal1;
decalData[1] = ChaingunDecal2;
decalData[2] = ChaingunDecal3;
decalData[3] = ChaingunDecal4;
decalData[4] = ChaingunDecal5;
decalData[5] = ChaingunDecal6;
activateDelayMS = 100;
explosion = ChaingunExplosion;
};
//-------------------------------------
// Artillery CHAINGUN CHARACTERISTICS
//-------------------------------------
datablock TurretData(ArtilleryPlasmaTurret) : TurretDamageProfile
{
className = VehicleTurret;
catagory = "Turrets";
shapeFile = "Turret_tank_base.dts";
preload = true;
mass = 1.0; // Not really relevant
maxEnergy = 1;
maxDamage = Artillery.maxDamage;
destroyedLevel = Artillery.destroyedLevel;
repairRate = 0;
// capacitor
maxCapacitorEnergy = 250;
capacitorRechargeRate = 1.0;
thetaMin = 0;
thetaMax = 100;
inheritEnergyFromMount = true;
firstPersonOnly = true;
useEyePoint = true;
numWeapons = 1;
cameraDefaultFov = 90.0;
cameraMinFov = 5.0;
cameraMaxFov = 120.0;
targetNameTag = 'Artillery Chaingun';
targetTypeTag = 'Turret';
};
datablock TurretImageData(ArtilleryTurretParam)
{
mountPoint = 2;
shapeFile = "turret_muzzlepoint.dts";
projectile = ArtilleryChaingunBullet;
projectileType = TracerProjectile;
useCapacitor = true;
usesEnergy = true;
// Turret parameters
activationMS = 1000;
deactivateDelayMS = 1500;
thinkTimeMS = 200;
degPerSecTheta = 500;
degPerSecPhi = 500;
attackRadius = 75;
};
datablock TurretImageData(ArtilleryPlasmaTurretBarrel)
{
shapeFile = "turret_tank_barrelchain.dts";
mountPoint = 1;
projectile = ArtilleryChaingunBullet;
projectileType = TracerProjectile;
casing = ShellDebris;
shellExitDir = "1.0 0.3 1.0";
shellExitOffset = "0.15 -0.56 -0.1";
shellExitVariance = 15.0;
shellVelocity = 3.0;
projectileSpread = 12.0 / 1000.0;
useCapacitor = true;
usesEnergy = true;
useMountEnergy = true;
fireEnergy = 3.75;
minEnergy = 15.0;
// Turret parameters
activationMS = 4000;
deactivateDelayMS = 500;
thinkTimeMS = 200;
degPerSecTheta = 360;
degPerSecPhi = 360;
attackRadius = 75;
// State transitions
stateName[0] = "Activate";
stateTransitionOnNotLoaded[0] = "Dead";
stateTransitionOnLoaded[0] = "ActivateReady";
stateSound[0] = ArtilleryTurretActivateSound;
stateName[1] = "ActivateReady";
stateSequence[1] = "Activate";
stateSound[1] = ArtilleryTurretActivateSound;
stateTimeoutValue[1] = 1;
stateTransitionOnTimeout[1] = "Ready";
stateTransitionOnNotLoaded[1] = "Deactivate";
stateName[2] = "Ready";
stateTransitionOnNotLoaded[2] = "Deactivate";
stateTransitionOnTriggerDown[2] = "Fire";
stateTransitionOnNoAmmo[2] = "NoAmmo";
stateName[3] = "Fire";
stateSequence[3] = "Fire";
stateSequenceRandomFlash[3] = true;
stateFire[3] = true;
stateAllowImageChange[3] = false;
stateSound[3] = ArtilleryChaingunFireSound;
stateScript[3] = "onFire";
stateTimeoutValue[3] = 0.1;
stateTransitionOnTimeout[3] = "Fire";
stateTransitionOnTriggerUp[3] = "Reload";
stateTransitionOnNoAmmo[3] = "noAmmo";
stateName[4] = "Reload";
stateSequence[4] = "Reload";
stateTimeoutValue[4] = 0.1;
stateAllowImageChange[4] = false;
stateTransitionOnTimeout[4] = "Ready";
stateTransitionOnNoAmmo[4] = "NoAmmo";
stateWaitForTimeout[4] = true;
stateName[5] = "Deactivate";
stateSequence[5] = "Activate";
stateDirection[5] = false;
stateTimeoutValue[5] = 30;
stateTransitionOnTimeout[5] = "ActivateReady";
stateName[6] = "Dead";
stateTransitionOnLoaded[6] = "ActivateReady";
stateTransitionOnTriggerDown[6] = "DryFire";
stateName[7] = "DryFire";
stateSound[7] = ArtilleryChaingunDryFireSound;
stateTimeoutValue[7] = 0.5;
stateTransitionOnTimeout[7] = "NoAmmo";
stateName[8] = "NoAmmo";
stateTransitionOnAmmo[8] = "Reload";
stateSequence[8] = "NoAmmo";
stateTransitionOnTriggerDown[8] = "DryFire";
};
datablock TurretImageData(ArtilleryPlasmaTurretBarrel2) : ArtilleryPlasmaTurretBarrel
{
mountPoint = 0;
};
datablock ShapeBaseImageData(ArtilleryCannonTurret)
{
className = WeaponImage;
shapeFile = "turret_tank_barrelmortar.dts";
mountPoint = 3;
offset = "2 -2.5 1.5";
rotation = "-1 0 0 80";
activationMS = 1000;
deactivateDelayMS = 1500;
thinkTimeMS = 200;
degPerSecTheta = 500;
degPerSecPhi = 500;
attackRadius = 500;
};
datablock ShapeBaseImageData(ArtilleryCannonTurret2)
{
className = WeaponImage;
shapeFile = "turret_tank_barrelmortar.dts";
mountPoint = 3;
offset = "-2 -2.5 1.5";
rotation = "-1 0 0 80";
activationMS = 1000;
deactivateDelayMS = 1500;
thinkTimeMS = 200;
degPerSecTheta = 500;
degPerSecPhi = 500;
attackRadius = 500;
};
function Artillery::onAdd(%this, %obj)
{
Parent::onAdd(%this, %obj);
%turret = TurretData::create(ArtilleryPlasmaTurret);
%turret.selectedWeapon = 1;
MissionCleanup.add(%turret);
%turret.team = %obj.teamBought;
%turret.setSelfPowered();
%obj.mountObject(%turret, 10);
%turret.setCapacitorRechargeRate( %turret.getDataBlock().capacitorRechargeRate );
%obj.turretObject = %turret;
%turret.setAutoFire(false);
%turret.mountImage(ArtilleryPlasmaTurretBarrel, 2);
%turret.mountImage(ArtilleryPlasmaTurretBarrel2, 4);
%turret.mountImage(AssaultTurretParam, 0);
%obj.schedule(6000, "playThread", $ActivateThread, "activate");
setTargetSensorGroup(%turret.getTarget(), %turret.team);
setTargetNeverVisMask(%turret.getTarget(), 0xffffffff);
%obj.mountImage(ArtilleryCannonTurret, 3);
%obj.mountImage(ArtilleryCannonTurret2, 4);
schedule(6100, 0, "ArtilleryLookForTarget", %obj);
}
function Artillery::deleteAllMounted(%data, %obj)
{
%turret = %obj.getMountNodeObject(10);
if (%turret)
{
if(%client = %turret.getControllingClient())
{
%client.player.setControlObject(%client.player);
%client.player.mountImage(%client.player.lastWeapon, $WeaponSlot);
%client.player.mountVehicle = false;
}
%turret.delete();
}
%turret = %obj.getMountNodeObject(10);
if(%turret)
%turret.delete();
}
function Artillery::playerMounted(%data, %obj, %player, %node)
{
if(%node == 0)
commandToClient(%player.client, 'setHudMode', 'Pilot', "Assault", %node);
else if(%node == 1)
{
%turret = %obj.getMountNodeObject(10);
%player.vehicleTurret = %turret;
%player.setTransform("0 0 0 0 0 1 0");
%player.lastWeapon = %player.getMountedImage($WeaponSlot);
%player.unmountImage($WeaponSlot);
if(!%player.client.isAIControlled())
{
%player.setControlObject(%turret);
%player.client.setObjectActiveImage(%turret, 2);
}
%turret.turreteer = %player;
$aWeaponActive = 0;
commandToClient(%player.client,'SetWeaponryVehicleKeys', true);
%obj.getMountNodeObject(10).selectedWeapon = 1;
commandToClient(%player.client, 'setHudMode', 'Pilot', "Assault", %node);
}
if( %player.client.observeCount > 0 )
resetObserveFollow( %player.client, false );
%passString = buildPassengerString(%obj);
for(%i = 0; %i < %data.numMountPoints; %i++)
if(%obj.getMountNodeObject(%i) > 0)
commandToClient(%obj.getMountNodeObject(%i).client, 'checkPassengers', %passString);
}
function ArtilleryPlasmaTurret::onDamage(%data, %obj)
{
%newDamageVal = %obj.getDamageLevel();
if(%obj.lastDamageVal !$= "")
if(isObject(%obj.getObjectMount()) && %obj.lastDamageVal > %newDamageVal)
%obj.getObjectMount().setDamageLevel(%newDamageVal);
%obj.lastDamageVal = %newDamageVal;
}
function ArtilleryPlasmaTurret::damageObject(%this, %targetObject, %sourceObject, %position, %amount, %damageType ,%vec, %client, %projectile)
{
%vehicle = %targetObject.getObjectMount();
if(%vehicle)
%vehicle.getDataBlock().damageObject(%vehicle, %sourceObject, %position, %amount, %damageType, %vec, %client, %projectile);
}
function ArtilleryPlasmaTurret::onTrigger(%data, %obj, %trigger, %state)
{
switch (%trigger)
{
case 0:
%obj.fireTrigger = %state;
if(%state)
{
%obj.setImageTrigger(2, true);
%obj.setImageTrigger(4, true);
}
else
{
%obj.setImageTrigger(2, false);
%obj.setImageTrigger(4, false);
}
case 2:
if(%state)
%obj.getDataBlock().playerDismount(%obj);
}
}
function ArtilleryPlasmaTurret::playerDismount(%data, %obj)
{
%obj.fireTrigger = 0;
%obj.setImageTrigger(2, false);
%obj.setImageTrigger(4, false);
%client = %obj.getControllingClient();
%client.player.mountImage(%client.player.lastWeapon, $WeaponSlot);
%client.player.mountVehicle = false;
setTargetSensorGroup(%obj.getTarget(), 0);
setTargetNeverVisMask(%obj.getTarget(), 0xffffffff);
}
function ArtilleryCannonTurret::onMount(%this, %obj, %slot)
{
}
function ArtilleryCannonTurret::onUnmount(%this, %obj, %slot)
{
}
function ArtilleryCannonTurret2::onMount(%this, %obj, %slot)
{
}
function ArtilleryCannonTurret2::onUnmount(%this, %obj, %slot)
{
}
function ArtilleryLookForTarget(%obj)
{
if (isObject(%obj))
{
if (%obj.lastcannon == 3)
%obj.lastcannon = 4;
else
%obj.lastcannon = 3;
%pos = %obj.getMuzzlePoint(%obj.lastcannon);
%vec = %obj.getMuzzleVector(%obj.lastcannon);
%count = ClientGroup.getCount();
%mainDist = 760;
%targetPos = "";
%damageMasks = $TypeMasks::PlayerObjectType | $TypeMasks::VehicleObjectType |
$TypeMasks::StationObjectType | $TypeMasks::GeneratorObjectType |
$TypeMasks::SensorObjectType | $TypeMasks::TurretObjectType |
$TypeMasks::InteriorObjectType | $TypeMasks::TerrainObjectType;
for (%i=0;%i<%count;%i++)
{
%obj2 = ClientGroup.getObject(%i);
%player = %obj2.player;
if (%player)
{
if ((%player.team == %obj.team) && (%player.posLaze))
{
%muzzlePos = %player.getMuzzlePoint($WeaponSlot);
%muzzleVec = %player.getMuzzleVector($WeaponSlot);
%endPos = VectorAdd(%muzzlePos, VectorScale(%muzzleVec, 1000));
%hit = ContainerRayCast(%muzzlePos, %endPos, %damageMasks, %player);
if (%hit)
%pos2 = getWords(%hit, 1, 3);
%dist = VectorDist(%pos, %pos2);
if ((%dist > 250) && (%dist < 750) && (%dist < %mainDist))
{
%targetPos = %pos2;
%mainDist = %dist;
}
}
}
}
if (%targetPos)
{
%p = new GrenadeProjectile() {
dataBlock = ArtilleryShot;
initialDirection = %vec;
initialPosition = %pos;
sourceObject = %obj.lastpilot;
sourceSlot = %obj.lastcannon;
vehicleObject = %obj;
};
MissionCleanup.add(%p);
schedule(2000, 0, ArtilleryShotDrop, %p, %pos, %targetPos);
}
schedule (5000, 0, ArtilleryLookForTarget, %obj);
}
}
function ArtilleryShotDrop(%b, %pos, %pos2)
{
if (isObject(%b))
{
%dist = VectorDist(%pos, %pos2);
%accuracy = %dist / 100;
%b.schedule(50, "delete");
%pos3 = VectorAdd(%pos2, "0 0 500");
%vec = "0 0 -1";
%x = (getRandom() - 0.5) * 2 * 3.1415926 * %accuracy / 1000;
%y = (getRandom() - 0.5) * 2 * 3.1415926 * %accuracy / 1000;
%z = (getRandom() - 0.5) * 2 * 3.1415926 * %accuracy / 1000;
%mat = MatrixCreateFromEuler(%x @ " " @ %y @ " " @ %z);
%vec = MatrixMulVector(%mat, %vec);
%p = new GrenadeProjectile() {
dataBlock = ArtilleryShot;
initialDirection = %vec;
initialPosition = %pos3;
sourceObject = %b.sourceObject;
sourceSlot = %b.sourceSlot;
vehicleObject = %b.vehicleObject;
};
MissionCleanup.add(%p);
}
}
datablock GrenadeProjectileData(ArtilleryShot)
{
projectileShapeName = "mortar_projectile.dts";
emitterDelay = -1;
directDamage = 0.0;
hasDamageRadius = true;
indirectDamage = 1.0;
damageRadius = 25.0;
radiusDamageType = $DamageType::Mortar;
kickBackStrength = 2500;
scale = "2 2 2";
explosion = "MortarExplosion";
underwaterExplosion = "UnderwaterMortarExplosion";
velInheritFactor = 0.5;
splash = MortarSplash;
depthTolerance = 10.0; // depth at which it uses underwater explosion
baseEmitter = MortarSmokeEmitter;
bubbleEmitter = MortarBubbleEmitter;
grenadeElasticity = 0.15;
grenadeFriction = 0.4;
armingDelayMS = 10;
muzzleVelocity = 300;
drag = 0.01;
sound = MortarProjectileSound;
hasLight = true;
lightRadius = 4;
lightColor = "0.05 0.2 0.05";
hasLightUnderwaterColor = true;
underWaterLightColor = "0.05 0.075 0.2";
};