This tutorial is intended to give modellers an overview of the process of creating art assets for BF1942, and more specifically, a working aircraft. The aircraft I chose to model is the Boulton Paul Defiant, an aircraft that in all reality was heavy, underpowered, easily exploited and used in a limited capacity during WW2 before it was given a new lease on life as a target tug.
But that's beside the point. In an ideal world, ie BF1942, it becomes a formidable weapon with it's 4 Browning .303 Machine guns with the ability to attack all 360 degrees within a limited elevation above the plane. But without further ado, on to the tutorial
You will need:
Before you start with any form of model tinkering, first thing you'll have to do is extract the entire contents of standardMesh.RFA, texture.RFA, and objects.RFA, all into your root BF1942 folder. Once you've done this, rename the RFA files so the game won't find them and look for the uncompressed data files.
Second up, put Rexman's scripts into the right place. Usually /3dsmax/scripts, and create a directory on your C: called "tmpmax" which is optional but very useful.
I'm not going to explain the process of modelling but I will give some pointers and guidelines for what you should be aiming toward.
At this point, I'm assuming you've got a model all ready to go.
Note the orderly naming scheme, applied texture, and position. Position is of the utmost importance, because the origin works as the Centre of Gravity. My first export had the origin just above the landing gear, and it kept tipping forward if you tried to slow it down during a landing.
Now, if you haven't done so already, you'll need to save out individual files with the various components. Once you've done that, we start the exporting.
This is the main part of your model, and is the first thing you'll think about bundling up. Run Rexman's script and select the appropriate models. You want your main visible mesh to be the fuselage itself, the first collision box is your higher detail collision box, the second is the lower detail one. For the time being export with simple shaders, up to 6 LOD levels, and a Mat ID of 61. In a later tutorial we'll look at shaders and materials a little more in depth.
With any luck, the export should complete succesfully. (if not check out Rexman's FAQ for a little bit of troubleshooting, or post here on the forums)
We'll start our moving parts export with what is probably the simplest. Open up the file that contains your elevators. You can export them as a single object if you'd like as they are both going to move in unison, but I exported them as separate objects just because that's how my mind decided to rationalise them.
Now, take a look at their position. You'll want to write it down somewhere. The easiest way to do this for Max 4 and 5 users is to look just below your viewports at this:
Or you can do it the old school way by either right-clicking your Move tool button or hitting F12 to bring up the Transform Type-In dialogue:
IMPORTANT: BF1942 has differing axes to 3DSMax. X still corresponds to lateral horizontal movement (side to side) but Y corresponds to vertical and Z corresponds to longitudinal horizontal movement. So what that means to you, is switch your Y and Z values when you write them down. Now divide the values by 10, and we'll come back to them later.
Once you've written the position down, you can right click on the spinners to centre the object pivot point on the origin. Because you should have already moved you pivot points into the appropriate positions, when BF1942 rotates an object around the origin, it should all be correct as per your specifications.
With your Ailerons you basically want to do exactly as you've just done with the elevators, however, chances are, you want the rotation of your ailerons to be on a slight angle so they stay even with the wing.
As a (slightly exaggerated) example, take a look at what happens if the ailerons of my Defiant are rotated along a cardinal axis:
Obviously that's going to look a little funky in game, so let's rotate the aileron itself so it lines up with an axis, but make sure you take note of exactly how far you rotate it and write it down with the position co-ordinates. You should end up with something like this:
Now for whatever reason, you can't seem to execute a ObjectTemplate.setInputToPitch function for a Wing object. More on this later, but for the time being, take my word regarding the rudder.
Do as above, writing down the co-ords and centring the rudder to the origin, and now rotate it 90 degrees along Max's Z-axis so it looks something like:
I found for simplicities sake it was best to have the landing gear in it's extended position for export, although you will have to take notice of how far it need to rotate in order to retract.
And here's where I hand it over to you, because from the above you should know all you need to know about exporting bits and pieces to be rotational. The landing gear, propeller, turrets, guns and anything else you have all abide by the same sort of guidelines as above. To reiterate:
Now we start with our .CON files which tell the engine how the plane behaves and fits together. The first thing we have to do is point the engine to our geometry that we've just exported, so copy all the .SM and .RS files from your C:\tmpmax\standardmesh folder into .\standardmesh\ in your BF1942 folder.
Now go to .\objects\vehicles\air\ and create a folder for your aircraft. Mine is called "Defiant" In that folder create a text file and rename it to "Geometries.CON", open it up and make with the bits and pieces.
Each piece of mesh needs to have a Geometry Template created, and you can do so with the following functions:
GeometryTemplate.create StandardMesh [GeometryName] GeometryTemplate.file [FileName]
...where [GeometryName] is the name you are going to use to reference the Geometry Template you are creating, and [FileName] is the name of the .SM file you wish to use, minus the .SM extension. So for example:
GeometryTemplate.create StandardMesh Defiant_Fuselage GeometryTemplate.file Defiant_Fuselage
The next thing you'll want to add are the LOD distances for that object. Something like:
GeometryTemplate.setLodDistance 0 0 GeometryTemplate.setLodDistance 1 10 GeometryTemplate.setLodDistance 2 15 GeometryTemplate.setLodDistance 3 30 GeometryTemplate.setLodDistance 4 50 GeometryTemplate.setLodDistance 5 100
...but the values can be whatever you want. The above example is a fairly steepish falloff, and is ideal for objects with lots of polys like the fuselage, but you might want a smooth progression for objects that are already fairly simple, such as ailerons.
For objects that should cast shadows (currently unsupported by the export tools) you can add:
GeometryTemplate.hasDynamicShadow 1
...and for most aircraft this is the fuselage only. Considering it makes up most of the aircraft, theres not much point in the performance hit that all objects casting shadows would cause.
Here's the Geometries.con file for my Defiant as a text file for your perusal.
...because this is where it starts to require a bit more attention. We're going to do this bit by bit, and the first thing you have to do is create an Objects.con file. Open it up, and let's get into it.
First of all all vehicles need to have at least one Player Control Object. This is how the player "interfaces" with a vehicle.
rem *** Defiant *** ObjectTemplate.create PlayerControlObject [Vehicle]
...where [Vehicle] is the name of your vehicle. Mine will eventually be Defiant, but to make it possible for me to see and use my plane without any map editing, I'm replacing the AichiVal, so my line reads "ObjectTemplate.create PlayerControlObject AichiVal".
ObjectTemplate.setNetworkableInfo AichiVal_body_info
I'm ignoring this line for the time being, as the aircraft is not networkable until we get mod support from DICE, so I've copied the Network.con file from the AichiVal, and I am using it's NetworkableInfo.
ObjectTemplate.saveInSeparateFile 1
Not entirely sure what this does, but it's a good idea to add it.
objectTemplate.cullRadiusScale 5
This scales the LODing of the object. The values you have in the Geometries.con file are affected by a factor of 5. I haven't done any tests, but I assume this to mean multiplied by 5.
ObjectTemplate.hasMobilePhysics 1 ObjectTemplate.hasCollisionPhysics 1 ObjectTemplate.hasResponsePhysics 1
You obviously want your aircraft to move, collide and respond to controls, so add these three lines.
ObjectTemplate.hasDynamicShadow 1
This seems a little redundant with shadows also being specified according to individual geometry templates, but throw it in.
ObjectTemplate.drag 0.65 ObjectTemplate.mass 3500 ObjectTemplate.inertiaModifier 1.02/0.855/0.922
Some more physics values.
ObjectTemplate.explosionRadius 8 ObjectTemplate.explosionDamage 5 ObjectTemplate.explosionForceMod 15
When your vehicle is destroyed, and let's face it, it's likely to happen repeatedly, it blows up in a ball of flame. You can specify the degree of damage and the size of the explosion, and also how far it's likely to throw any nearby objects.
ObjectTemplate.angleMod 1 ObjectTemplate.speedMod 2
Haven't experimented with these at all.
ObjectTemplate.hasArmor 1 ObjectTemplate.hitpoints 130 ObjectTemplate.maxHitpoints 130 ObjectTemplate.material 60
Most aircraft have armour, so it's a good idea. Not sure of the effects of not having armour, but it's liekyl that it affects the pilot when damage is taken. Hitpoints are pretty self-explanatory, and the material affects sprite effects when bullets strike, and possibly armour, but I haven't experimented.
ObjectTemplate.criticalDamage 20 ObjectTemplate.hpLostWhileCriticalDamage 1.5
I'm fairly sure this is a percentile chance, and also the modifier should that critical chance come into play. Adds a little spice to the battle.
ObjectTemplate.hpLostWhileUpSideDown 10 ObjectTemplate.damageFromWater 1 ObjectTemplate.hpLostWhileDamageFromWater 10
Upside down constitutes being at rest (on land or water) and being upside down, being airborne will not affect it. If the plane is non-amphibious then it should take damage from water, obviously aircraft like the Catalina shouldn't take damage.
ObjectTemplate.addArmorEffect 65 em_AichiValDamage 0/0.102/2.11 ObjectTemplate.addArmorEffect 65 em_PlaneDamage 0/-0.303/2.21 ObjectTemplate.addArmorEffect 20 e_AichiValFire 0/1/2.11 ObjectTemplate.addArmorEffect 0 e_ExplGas 0/0/0 ObjectTemplate.addArmorEffect 0 e_ScrapMetal_AichiVal 0/0/0 ObjectTemplate.addArmorEffect -1 WaterWaterExplosion 0/0/0
When the HitPoint of the aircraft drop to a certain value, then certain effects are triggered. At half damage (65/130) it starts to smoke, at (20/130) it catches fire, and at 0 it explodes, spawning scrap metal and an explosion.
ObjectTemplate.aiTemplate AichiVal
I plan to delve into AI Scripts at a later date, but for the time being, the AI pilots can treat it as an Aichi Val.
ObjectTemplate.addTemplate lodDefiant
Very Important. This is where the engine decides what mesh(es) to render, and is created later in the .CON file.
ObjectTemplate.setSoldierExitLocation -2.8/0.203/-3.9 0/0/0
When the pilot exits the plane, he must be spawned at the apprpriate location. You can work this out in 3DSMax fairly easily. The second set of 3 values I haven't played with, but I'm assuming it's an angle vector.
ObjectTemplate.GUIIndex 27
This displays the little icon down in the bottom left corner, in this case the front seat position of an Aichi Val.
ObjectTemplate.setVehicleCategory VCAir ObjectTemplate.setVehicleType VTFighter
Unsure how these affect the game, but I'm assuming it's something to do with spawn points.
And that's our control object. This will allow the player to get in and out and control the plane, but not by itself. There is yet much to learn.
rem *** lodDefiant *** ObjectTemplate.create LodObject lodDefiant ObjectTemplate.hasMobilePhysics 1 ObjectTemplate.hasCollisionPhysics 1 ObjectTemplate.hasResponsePhysics 1
ObjectTemplates are something you'll deal with a LOT. Here we're creating a LODObject, which enables LOD controls, and adds templates for the various model detail levels. Like it's parent it too has physics.
ObjectTemplate.addTemplate DefiantComplex ObjectTemplate.addTemplate DefiantSimple ObjectTemplate.addTemplate DefiantWreck
The three objects that may be displayed are listed here. The plane can either be the Complex bundle, (with moving parts and high detail mesh) the Simple object (a static, low-detail mesh) or the Wrecked version of the model. But how does it know which one to use? Because...
ObjectTemplate.lodSelector DefiantLodSelector
...all LODObjects should have a lodselector, which is specified below.
rem *** DefiantLodSelector *** LodSelectorTemplate.create DistCompareSelector2 DefiantLodSelector LodSelectorTemplate.hasDestroyedLod 1 LodSelectorTemplate.addLodDistance 200
Here we create the LodSelector template using DistCompareSelector2. Don't ask me about it, just take my word. The template has a destroyed version of the object, and a LodDistance of 200. I don't know for sure, but I'm fairly sure this takes the list specified in the LodObject (above) and treats the first added template as the highest detail and the last as the destroyed version, as it never explicitly specifies according to name.
rem *** DefiantComplex *** ObjectTemplate.create Bundle DefiantComplex ObjectTemplate.hasMobilePhysics 1 ObjectTemplate.hasCollisionPhysics 1 ObjectTemplate.hasResponsePhysics 1
Our next step is to create the Complex version of the aircraft, which must be a Bundle object to keep all the various bits of the model together. Note physics bools are all true again.
ObjectTemplate.addTemplate lodDefiantCockpit
Another LOD object we'll see later in the piece, this time to decide whether the player sees the fuselage of the plane, or the cockpit.
ObjectTemplate.addTemplate DefiantEngine ObjectTemplate.setPosition 0/0.3/4
The engine, and what is going to get our plane moving. The object itself is in Physics.con and it will be further explained there. The position offset pertains to the propellor location.
ObjectTemplate.addTemplate DefiantCamera ObjectTemplate.setPosition 0.011/0.963/0.75 ObjectTemplate.addTemplate DefiantEntry ObjectTemplate.setPosition 0/0/0.25 ObjectTemplate.addTemplate DefiantSeat ObjectTemplate.setPosition 0/-0.45/0.15
These three all pertain to the cockpit, the first is the internal Camera position, the second is the entry point object, which will put the player inside the plane when they use it within range and the third is the seat itself which spawns a pilot model sitting inside the plane. More on them later.
ObjectTemplate.addTemplate DefiantFlaps1 ObjectTemplate.addTemplate DefiantFlaps2
These two templates are contained within the Physics.con file, which we'll look at shortly.
ObjectTemplate.addTemplate DefiantBodyWing ObjectTemplate.setPosition 0/0/0.35 ObjectTemplate.setRotation 0/0/-89.999
This is another physics object.
ObjectTemplate.addTemplate DefiantAileronLeft ObjectTemplate.setPosition -4.143/-0.11/0.45 ObjectTemplate.setRotation 10/0/0 ObjectTemplate.addTemplate DefiantAileronRight ObjectTemplate.setPosition 4.139/-0.09/0.45 ObjectTemplate.setRotation -10/0/0
The two Ailerons. Positioning taken from the Max coords written down earlier, and Rotation from the small rotation made to line up the ailerons with the axis. The actual objects are also in Physics.con
ObjectTemplate.addTemplate DefiantElevatorLeft ObjectTemplate.setPosition -0.9/0.464/-4.335 ObjectTemplate.addTemplate DefiantElevatorRight ObjectTemplate.setPosition 0.87/0.464/-4.335
The elevators, positions once again derived from Max coords, and the objects in Physics.con
ObjectTemplate.addTemplate DefiantRudder ObjectTemplate.setPosition 0/0.85/-4.46 ObjectTemplate.setRotation 0/0/-90
The Rudder, positions once again derived from Max coords, and when we go through Physics.con, we'll see why we rotated the rudder model in max and then rotated it back again here.
ObjectTemplate.addTemplate DefiantWheelBack ObjectTemplate.setPosition 0/-0.187/-3.95
The rear wheel, created later on as a rotational bundle so it can turn along with the rudder.
ObjectTemplate.addTemplate DefiantCanopy ObjectTemplate.setPosition 0/0/1.25 ObjectTemplate.addTemplate DefiantExhaust ObjectTemplate.setPosition 0/0/1.25
Two redundant objects that should have been exported as part of the fuselage.
ObjectTemplate.addTemplate DefiantBombRack
A reference to Weapons.con that will attach the Bomb weapon to the aircraft.
ObjectTemplate.addTemplate DefiantRearGunControl ObjectTemplate.setPosition 0/0.52/-0.42 ObjectTemplate.setRotation -180/0/0
The second control point in the aircraft for whoever is manning the turret. Exported facing forwards, and rotated to it's default position facing the tail.
Okay, now we move on to all the objects that make up the Complex bundle:
rem *** lodDefiantCockpit *** ObjectTemplate.create LodObject lodDefiantCockpit rem ------------------------------------- ObjectTemplate.addTemplate DefiantCockpitExternal ObjectTemplate.addTemplate DefiantCockpitInternal ObjectTemplate.setPosition 0/-1.599/0.11 rem ------------------------------------- ObjectTemplate.lodSelector DefiantCockpitSelector
Another LOD object, this time to determine whether to render the internal model for the cockpit. It's set a little higher and a little to the rear of the central point, and once again has a LOD selector.
rem *** DefiantCockpitExternal *** ObjectTemplate.create SimpleObject DefiantCockpitExternal ObjectTemplate.hasDynamicShadow 1 ObjectTemplate.geometry Defiant_Fuselage
Here we have the external cockpit, ie the fuselage of the plane. I've created it as a SimpleObject, because its a single piece of geometry and nothing more.
rem *** DefiantCockpitInternal *** ObjectTemplate.create SimpleObject DefiantCockpitInternal ObjectTemplate.geometry 1p_Aichi_Val_m1
An Aichi Val cockpit because I haven't yet modelled my internals. Simple object again, although if you really wanted to, you could quite easily have a Bundle here that incorporates an artificial horizon, and possibly some gauges, but they would be more difficult to implement.
rem *** DefiantCockpitSelector *** LodSelectorTemplate.create DistCompareSelector DefiantCockpitSelector LodSelectorTemplate.addLodDistance 20 LodSelectorTemplate.addLodComparison 0.5
Another LOD Selector, this time a DistCompareSelector (as opposed to the DistCompareSelector2 we saw earlier. Not sure what the distinction is.) A short LOD distance, and a LOD comparison. Unsure of what function that serves.
rem *** DefiantCamera *** ObjectTemplate.create Camera DefiantCamera ObjectTemplate.setMinRotation -45/-40/0 ObjectTemplate.setMaxRotation 45/14/0 ObjectTemplate.setMaxSpeed 90/-90/0 ObjectTemplate.setAcceleration 5000/5000/0 ObjectTemplate.setInputToYaw c_PIMouseLookX ObjectTemplate.setInputToPitch c_PIMouseLookY ObjectTemplate.toggleMouseLook 1 ObjectTemplate.OutsideHudOffset 0.004/0/3.5
Now our first Camera object, this time the pilot's view. The first few variables were ripped straight from the Aichi Val, and while I suspect they affect the pitch and roll rates of the aircraft, I can't confirm it. The MaxSpeed and acceleration should be set to something high, as a lower rate probably makes the aircraft less responsive to player input. The camera is set to take its input from the mouse's X and Y movements, which I assume is fed on to the control surface in Physics.con, and I'll try to confirm some of these grey areas over the weekend. The final variable is the offset for NoseCam, and you can work out the appropriate Offset by working out the desired nose position in Max, and then working out the difference between that and the position of the camera object.
rem *** DefiantEntry *** ObjectTemplate.create EntryPoint DefiantEntry ObjectTemplate.setEntryRadius 6
The Entrypoint is require for players to actually use the plane, and it needs a variable to specify the active radius. Whenever the player uses the plane within this radius, they are attached to the Player Control Object that is the parent of the Entry Point.
rem *** DefiantSeat *** ObjectTemplate.create SeatObject DefiantSeat ObjectTemplate.seatFlags c_SeatShowHalfBodySoldier
This one is nice and simple. Half a soldier model is placed in the seat location, and his movements are tied into the MouseLook automatically.
rem *** DefiantCanopy *** ObjectTemplate.create SimpleObject DefiantCanopy ObjectTemplate.geometry Defiant_Glass
rem *** DefiantExhaust *** ObjectTemplate.create SimpleObject DefiantExhaust ObjectTemplate.geometry Defiant_Engine
These are the two redundant objects I mentioned earlier. They should be part of the fuselage, but it serves to illustrate a point. You can put anything in a Bundle.
rem *** DefiantWheelBack *** ObjectTemplate.create RotationalBundle DefiantWheelBack ObjectTemplate.hasMobilePhysics 1 ObjectTemplate.hasCollisionPhysics 1 ObjectTemplate.hasResponsePhysics 1
A Rotational Bundle, which works exactly like a normal bundle, except that it's pitch, roll and yaw can receive input and funnily enough, rotate. More physics.
ObjectTemplate.addTemplate DefiantWheelBackSpring ObjectTemplate.setPosition 0/-0.26/0
This Object is in Physics.con and once again an unconfirmed piece of info - The position offset determines the spring length.
ObjectTemplate.setMinRotation -20/0/0 ObjectTemplate.setMaxRotation 20/0/0 ObjectTemplate.setMaxSpeed 200/0/0 ObjectTemplate.setAcceleration -110/0/0 ObjectTemplate.setInputToYaw c_PIYaw ObjectTemplate.setAutomaticReset 1
The above chunk doesn't actually affect the wheel rolling but limits the wheel so that it can only rotate a little when taxiing the plane. The Yaw input is tied into the player input, and theoretically you could allow a wider rotation and your plane to rotate almost on the spot, which is handy for carrier born aircraft.
rem *** lodDefiantPropeller *** ObjectTemplate.create LodObject lodDefiantPropeller
Another LOD object with yet another purpose. This time to display the appropriate propeller. Either the static mesh, or the flat plane with the blur.
ObjectTemplate.addTemplate DefiantPropellerStatic ObjectTemplate.addTemplate DefiantPropellerBlurred rem ------------------------------------- ObjectTemplate.lodSelector DefiantPropSelector
You should understand this portion by now. The two options for the LOD selector, and the reference to the object itself.
rem *** DefiantPropellerStatic *** ObjectTemplate.create SimpleObject DefiantlPropellerStatic ObjectTemplate.geometry Defiant_Prop_Static
rem *** DefiantPropellerBlurred *** ObjectTemplate.create SimpleObject DefiantPropellerBlurred ObjectTemplate.geometry Defiant_Prop_Blur
And the two objects in question for the LODing. Both simple, as they inherit their rotation from their parent object, the engine, which we'll see a bit later in Physics.con.
rem *** DefiantPropSelector *** LodSelectorTemplate.create CompareSelector DefiantPropSelector LodSelectorTemplate.addLodComparison 0.07
And a different LOD selector once more, this time a CompareSelector, which doesn't take distance into account at all. As of yet, I have no idea what comparison is being made here, but it's obviously got something to do with the throttle and/or the rate of rotation for the props.
Okay, well most of the plane is now there, with the exception of the Dorsal Turret and the simple and wrecked versions of the fuselage.
rem *** DefiantLandingGearRight *** ObjectTemplate.create LandingGear DefiantLandingGearRight
Our first LandingGear object. These are pretty nifty and fairly well automated. As children of the engine object, they take altitude and throttle into account.
ObjectTemplate.loadSoundScript ../Common/Sounds/LandingGear.ssc
And our first sound script. I'll cover them in a later turorial, but for now add in that line as is, and you'll get some sound feedback when your gear extends/retracts.
ObjectTemplate.geometry Defiant_Undercarriage_Right ObjectTemplate.hasMobilePhysics 1 ObjectTemplate.hasCollisionPhysics 1 ObjectTemplate.hasResponsePhysics 1
You know this already right? Attaching a bit of geometry and the usual physics stuff.
ObjectTemplate.addTemplate DefiantWheelCoverRight ObjectTemplate.setPosition 0/-0.5/0 ObjectTemplate.addTemplate DefiantWheel1 ObjectTemplate.setPosition -0.1/-1/0.1
Okay here we have two objects, the first one is pretty much redundant, and an artifact of my "advanced" landing gear that didn't quite work. However it does illustrate one thing that wigged out on me. I've attached the Wheel Cover (a simple object) and the wheel itself here, after simply attaching the wheel to the wheel cover. This resulted in my wheels losing their collision properties due to some heirarchical mix up. I may try to shorten up the Y offset for the wheel object, as it seems to make the spring fairly deep, and at times the plane sinks far enough for the landing gear mesh to clip.
ObjectTemplate.setMinRotation 0/0/-86 ObjectTemplate.setMaxSpeed 0/0/28 ObjectTemplate.setAcceleration 0/0/-90 ObjectTemplate.setGearDownHeight 25 ObjectTemplate.setGearUpHeight 23 ObjectTemplate.setGearDownEngineInput 0.55
Okay here's an interesting bit. When the landing gear is extended, it's at its minimum rotation, and when it's retracted, it's at the maximum. The speed will affect how slowly the gear extends and retracts so it's good to have it set around 20-30 so it seems fairly realistic, and makes landings more calculated.
The Up and Down heights refer to the altitude the plane must be above or below before the gear considers working. The engine input variable indicates what percentage of the maximum speed the plane must be travelling below before the gear will extend, which forces the player to slow down for landings.
rem *** DefiantLandingGearLeft *** ObjectTemplate.create LandingGear DefiantLandingGearLeft
Second verse, same as the first. A couple of changes to Min and max rotation, as well as offsets but it's not worth posting.
rem *** DefiantWheelCoverRight *** ObjectTemplate.create SimpleObject DefiantWheelCoverRight ObjectTemplate.geometry Defiant_LandingGear_Right rem *** DefiantWheelCoverLeft *** ObjectTemplate.create SimpleObject DefiantWheelCoverLeft ObjectTemplate.geometry Defiant_LandingGear_Left
The wheel covers. Elegant simplicity, and would have been better as part of the Undercarriage mesh.
rem *** DefiantWheelFlapRight *** ObjectTemplate.create LandingGear DefiantWheelFlapRight ObjectTemplate.loadSoundScript ../Common/Sounds/LandingGear.ssc ObjectTemplate.geometry Defiant_WheelFlap_Right ObjectTemplate.hasMobilePhysics 1 ObjectTemplate.hasCollisionPhysics 1 ObjectTemplate.hasResponsePhysics 1 rem ------------------------------------- ObjectTemplate.setMaxRotation 0/0/94 ObjectTemplate.setMaxSpeed 0/0/28 ObjectTemplate.setAcceleration 0/0/90 ObjectTemplate.setGearDownHeight 25 ObjectTemplate.setGearUpHeight 23 ObjectTemplate.setGearDownEngineInput 0.55
Another landing gear object, this one without a wheel attached. This one is a tiny piece of mesh that folds in the opposite direction to the one bearing the wheel, and serves only to completely seal the undercarriage bay.
Now we move on to the turret, and thankfully the uncontrollable fits of cursing I went through when trying to get my first turret (B-17 + AichiVal) working are a thing of the past. This time around it was a breeze.
rem *** DefiantRearGunControl *** ObjectTemplate.create PlayerControlObject DefiantRearGunControl ObjectTemplate.setNetworkableInfo AichiVal_body_info ObjectTemplate.aiTemplate AichivalMGAI
Our second Player Control Object, this time for the Dorsal Turret. The Network and AI functions are placeholders because for the time being they're kind of useless. I could have applied a B-17 turret AI, or simply modified the AichivalMG script so that the AI knows it can shoot in all 360 degrees, but I'll save that for another day.
ObjectTemplate.addTemplate DefiantDorsalTurret rem ObjectTemplate.setPosition 0/0.65/0.4 ObjectTemplate.addTemplate DefiantEntry ObjectTemplate.setPosition 0/-0.191/0
Here we have another Entry Point, which hopefully you should be familiar with, and a reference to a rotational bundle we'll meet soon.
ObjectTemplate.setSoldierExitLocation -3/0.05/1 0/0/0 ObjectTemplate.GUIIndex 54 ObjectTemplate.setVehicleCategory VCLand ObjectTemplate.setVehicleType VTDiveBomber
Another Exit Location that will dump the gunner in the right place when he jumps out. The GUIIndex here applies to the rear seat of an Aichi Val, and the Vehicle Category is VCLand for for the sole reason that that's what DICE have for their machine gun positions on aircraft.
rem *** DefiantDorsalTurret *** ObjectTemplate.create RotationalBundle DefiantDorsalTurret ObjectTemplate.setNetworkableInfo AichiVal_body_info ObjectTemplate.loadSoundScript Sounds/TurretDorsal.ssc ObjectTemplate.geometry Defiant_Turret
Another Rotational Bundle and the mesh for the turret. The most interesting thing here is a sound script to play a mechanical sound when the turret rotates, but more on that at a later date.
ObjectTemplate.addTemplate DefiantTurretGuns ObjectTemplate.setPosition 0/0.4/0.1 rem ------------------------------------- ObjectTemplate.setMaxSpeed 90/0/0 ObjectTemplate.setAcceleration 5000/0/0 ObjectTemplate.setInputToYaw c_PIMouseLookX
Here, we add another rotational bundle, and you'll notice that this bundle is only tied into yaw. The way the turret is set up is that the entire unit can rotate a full 360 degrees according to the mouse's X axis movement, and the guns, well... we'll see. The speed and acceleration are nice and high so the turret should turn just as fast as the player can mouselook.
rem *** DefiantTurretGuns *** ObjectTemplate.create RotationalBundle DefiantTurretGuns ObjectTemplate.setNetworkableInfo AichiVal_body_info ObjectTemplate.setAttachToListener 1 ObjectTemplate.loadSoundScript Sounds/TurretVentral.ssc ObjectTemplate.geometry Defiant_Guns
Okay, and here's another sound script, and an attach to listener that I don't quite understand, but lifted from the b-17s .CON file.
ObjectTemplate.addTemplate DefiantRearCamera ObjectTemplate.setPosition 0/0/0 ObjectTemplate.addTemplate Defiant_4xBrowning
Now we add the camera that the player will look through while gunning, and the guns themselves, which are contained within the Weapons.con file along with the bombrack from earlier.
ObjectTemplate.setMinRotation 0/-60/0 ObjectTemplate.setMaxRotation 0/0/0 ObjectTemplate.setMaxSpeed 0/90/0 ObjectTemplate.setAcceleration 0/5000/0 ObjectTemplate.setInputToPitch c_PIMouseLookY
The gun object already inherits it's yaw from it's parent object, the dorsal turret, and so we only need some pitch, which is taking it's input from the mouse's Y-axis, and this time we've added in some rotation limits so the player can't aim the guns too high.
rem *** DefiantRearCamera *** ObjectTemplate.create Camera DefiantRearCamera ObjectTemplate.setMaxSpeed 200/200/0 ObjectTemplate.setAcceleration 1000/1000/0
And the rear camera object, much simpler than it's forward facing counterpart. All it needs to do is point in the direction the guns are aiming.
rem *** DefiantSimple *** ObjectTemplate.create SimpleObject DefiantSimple ObjectTemplate.geometry Defiant_LowDetail rem *** DefiantWreck *** ObjectTemplate.create SimpleObject DefiantWreck ObjectTemplate.geometry Wreck_Defiant
And the grand finale of the Objects.con file si somewhat of an anticlimax. Two mundane, simple items, but never fear, because we shall now move on to the Physics and Weapons .CON files.
It's time to delve into our next .CON file, which you should create if you haven't already. Name it "Physics.con" and open it up in your favourite text editor.
rem *** DefiantFlaps1 *** ObjectTemplate.create Wing DefiantFlaps1 ObjectTemplate.setNetworkableInfo AichiVal_wing_info
Here's something new. A Wing object. All of the control surfaces are wings and they are required to give your aircraft lift, unless you've got a rocket engine or something. We've got another piece of Aichi Val network stuff that we don't really care about at this point.
What we do care about however is that these objects are flaps, and in real-life flaps are put on planes to provide extra lift during takeoff and landing, and also to increase drag, which slows the airspeed. In BF1942, they provide a similar function, although I haven't done enough testing to determine whether or not they only function during take-off and landing or whether they are permanent.
ObjectTemplate.setMinRotation 0/-2/0 ObjectTemplate.setMaxRotation 0/2/0 ObjectTemplate.setMaxSpeed 0/30/0 ObjectTemplate.setAcceleration 0/120/0
You've seen these functions before, and should know what they do by now.
ObjectTemplate.setPitchOffset 0.5 ObjectTemplate.setPositionOffset -1.778/0.302/0.12
Okay, the position offset is fairly self explanatory, and I assume the PitchOffset rotates the object according to pitch, but I'm not entirely sure, as that could easily be done through ObjectTemplate.setRotation.
ObjectTemplate.setFlapLift 2 ObjectTemplate.setRegulateToLift 3 ObjectTemplate.setWingToRegulatorRatio 1
I have no idea about the Regulate functions, but the Flap Lift is important, as it will get your plane into the air.
rem *** DefiantFlaps2 *** ObjectTemplate.create Wing DefiantFlaps2
More of the same...
rem *** DefiantBodyWing *** ObjectTemplate.create Wing AichiValBodyWing ObjectTemplate.setAutomaticReset 1 ObjectTemplate.setPositionOffset 0/0/-0.1 ObjectTemplate.setWingLift 2 ObjectTemplate.setFlapLift 0
If you recall, this was rotated 90 degrees when it was added in Objects.con and I'm not entirely sure of it's purpose, but it seems like something the BF1942 standard panes have, so it was added.
rem *** DefiantAileronRight *** ObjectTemplate.create Wing DefiantAileronRight ObjectTemplate.setNetworkableInfo AichiVal_wing_info ObjectTemplate.loadSoundScript ../Common/Sounds/HullRight.ssc ObjectTemplate.geometry Defiant_Aileron_Right
Now we start with our ailerons, which have a mesh, another soundscript and more networkable info.
ObjectTemplate.setMinRotation 0/-25/0 ObjectTemplate.setMaxRotation 0/25/0 ObjectTemplate.setMaxSpeed 0/150/0 ObjectTemplate.setAcceleration 0/150/0
More familiar stuff.
ObjectTemplate.setInputToPitch c_PIRoll ObjectTemplate.setAutomaticReset 1 ObjectTemplate.setPitchOffset 0.5
The pitch for the Ailerons is tied into the roll from the player input. The automatic reset brings them back to neutral position if there is no player input, and the pitch offset shifts the angle slightly
ObjectTemplate.setWingLift 1.8 ObjectTemplate.setFlapLift 1.8
And as you can see, these little guys are creating quite a bit of lift, so when they rotate they actually roll the plane.
rem *** DefiantAileronLeft *** ObjectTemplate.create Wing DefiantAileronLeft
Another very similar function because clone movies always sell at the box office.
rem *** DefiantElevatorLeft *** ObjectTemplate.create Wing DefiantElevatorLeft ObjectTemplate.setNetworkableInfo AichiVal_wing_info ObjectTemplate.geometry Defiant_Elevator_Left ObjectTemplate.setMinRotation 0/-10/0 ObjectTemplate.setMaxRotation 0/20/0 ObjectTemplate.setMaxSpeed 0/60/0 ObjectTemplate.setAcceleration 0/-60/0 ObjectTemplate.setInputToPitch c_PIPitch ObjectTemplate.setAutomaticReset 1 ObjectTemplate.setPositionOffset 0.5/0/0 ObjectTemplate.rememberExcessInput 1 ObjectTemplate.setWingLift 0.5 ObjectTemplate.setFlapLift 0.5
This stuff should be looking pretty samey by now, but we can see this time the rotation is tied to pitch, and that ExcessInput is remembered. I haven't tested this extensively, but it should serve to make the automatic reset happen a little later if you are really yanking back/pushing the stick.
rem *** DefiantElevatorRight *** ObjectTemplate.create Wing DefiantElevatorRight
Yawn.
rem *** DefiantRudder *** ObjectTemplate.create Wing DefiantRudder ObjectTemplate.setNetworkableInfo AichiVal_wing_info ObjectTemplate.geometry Defiant_Rudder ObjectTemplate.setMinRotation 0/-15/0 ObjectTemplate.setMaxRotation 0/15/0 ObjectTemplate.setMaxSpeed 0/60/0 ObjectTemplate.setAcceleration 0/60/0 ObjectTemplate.setInputToPitch c_PIYaw ObjectTemplate.setAutomaticReset 1 ObjectTemplate.setPositionOffset 0/-0.5/0 ObjectTemplate.setWingLift 1.5 ObjectTemplate.setFlapLift 1.5
The rudder, and as we noted before during our export, it was rotated 90 degrees. It seems that the Wing object doesn't respond to ObjectTemplate.setInputToYaw and so we use pitch instead and rotate it 90 degrees. A bit of a pain in the arse, but that's how DICE have their aircraft set up, so we run with it.
rem *** DefiantWheelBackSpring *** ObjectTemplate.create Spring DefiantWheelBackSpring ObjectTemplate.geometry Defiant_RearWheel ObjectTemplate.hasMobilePhysics 1 ObjectTemplate.hasCollisionPhysics 1 ObjectTemplate.hasResponsePhysics 1 ObjectTemplate.Grip c_PGFRollGripWhenOccupied ObjectTemplate.setStrength 24 ObjectTemplate.setDamping 12
A new object type, this time a Spring with a few new variable setting functions. The Grip function makes the wheel roll as the vehicle moves (provided it's occupied) and the strength and damping set the characteristics of the spring. A higher strength means increases the reaction of the spring, as it releases after being pushed in and the dampening smooths the motion a little. At high strength the plane tends to bounce in a jittery kind of fashion.
rem *** DefiantWheel1 *** ObjectTemplate.create Spring DefiantWheel1 ObjectTemplate.geometry rh_aichi_rwhe_M1 ObjectTemplate.hasMobilePhysics 1 ObjectTemplate.hasCollisionPhysics 1 ObjectTemplate.hasResponsePhysics 1 ObjectTemplate.Grip c_PGFRollGripWhenOccupied rem ------------------------------------- ObjectTemplate.addTemplate e_wdustPlane ObjectTemplate.addTemplate e_wdustPlaneL rem ------------------------------------- ObjectTemplate.setStrength 24 ObjectTemplate.setDamping 2
More of the same, with the addition of collision effects, spawning dust when the wheels roll. I'm using the Aichi wheels here until I can resolve my Mat ID issues.
rem *** DefiantWheel2 *** ObjectTemplate.create Spring DefiantWheel2
Rinse. Wash. Repeat.
rem *** DefiantEngine *** ObjectTemplate.create Engine DefiantEngine ObjectTemplate.setNetworkableInfo AichiVal_engine_info ObjectTemplate.loadSoundScript Sounds/AichiValEngine.ssc
We now introduce the Engine object, and an associated sound script.
ObjectTemplate.addTemplate lodDefiantPropeller ObjectTemplate.addTemplate DefiantLandingGearLeft ObjectTemplate.setPosition -1.52/-0.69/-2.786 ObjectTemplate.addTemplate DefiantLandingGearRight ObjectTemplate.setPosition 1.52/-0.69/-2.786 ObjectTemplate.addTemplate DefiantWheelFlapLeft ObjectTemplate.setPosition -0.26/-0.79/-2.786 ObjectTemplate.setRotation -4.5/0/0 ObjectTemplate.addTemplate DefiantWheelFlapRight ObjectTemplate.setPosition 0.26/-0.79/-2.786 ObjectTemplate.setRotation 4.5/0/0
And here we firstly add the prop LOD object, and then any landing gear objects, which require input from the engine for speed limits. All of the coords here need to be offset be the engine position as specified in Objects.con.
ObjectTemplate.setMinRotation -0.3/0/-3000 ObjectTemplate.setMaxRotation 0.3/0/5000 ObjectTemplate.setMaxSpeed 1000/0/500 ObjectTemplate.setAcceleration 500/0/1000 ObjectTemplate.setInputToRoll c_PIThrottle ObjectTemplate.setAutomaticReset 1 ObjectTemplate.setEngineType c_ETPlane
These are all pretty standard across the suite of planes offered by DICE, and the Rotation, Speed and Acceleration don't seem to affect anything other than the visuals of the prop spinning. The Automatic Reset kills the throttle if the player takes their hand off it, and could make things interesting if set to false. The engine type is a bit of a no brainer. I have no idea what would happen if you dropped a jeep engine into a plane, but it probably wouldn't be good.
ObjectTemplate.setTorque 15 ObjectTemplate.setDifferential 5 ObjectTemplate.setGearUp 0.6 ObjectTemplate.setGearDown 0.3 ObjectTemplate.setNoPropellerEffectAtSpeed 70
The Torque controls the effectiveness of the engine. A high torque means the engine is rotating faster, and outputting more thrust. I haven't played with the differential, but I have a feeling it's a modifier to the torque. Gear up and down affect the landing gear, and while I haven't experimented with the NoPropEffect, I think it's basically there to cap the speed of the aircraft.
Now we're getting toward the end of this tutorial which is probably a good thing, because the beers are starting to kick in, and it's probably best if I keep this thing legible.
rem *** Defiant_4xBrowning *** ObjectTemplate.create FireArms Defiant_4xBrowning ObjectTemplate.loadSoundScript Sounds/DefiantGuns.ssc ObjectTemplate.setNetworkableInfo PlaneFireArmInfo
A new object - FireArms, a soundscript and networkable info to leave until a later date.
ObjectTemplate.visibleBarrelTemplate e_MuzzHeavy
This adds a muzzle effect whenever the gun is fired, and this can be set to just about anything in the .\objects\effects\ folder. I went with e_MuzzHeavy because it seemed appropriate and looked good enough for me to have little to no desire look any further.
ObjectTemplate.projectileTemplate DefiantProjectile ObjectTemplate.projectilePosition 0/0/2 ObjectTemplate.setTracerTemplate Tracer_Projectile CRD_NONE/3/0/0
Here we can give the weapon a projectile. Defiant Projectile (which actually deals the damage) is defined below, and the tracer gives the player an idea of where their gun is shooting.
ObjectTemplate.magSize 600 ObjectTemplate.numOfMag 1 ObjectTemplate.velocity 400 ObjectTemplate.roundOfFire 10
Now we deal with some of the properties of the weapon itself. Here we have a 600 round magazine, with no reloads, a muzzle velocity of 400 and a rate of fire of 10.
ObjectTemplate.addFireArmsPosition 0.28/0.106/0.79 0/0/0 ObjectTemplate.addFireArmsPosition -0.28/0.106/0.79 0/0/0 ObjectTemplate.addFireArmsPosition 0.28/-0.106/0.79 0/0/0 ObjectTemplate.addFireArmsPosition -0.28/-0.106/0.79 0/0/0
Here we have offsets relative to the Parent object, in this case the DefiantTurretGuns object. Offsets calculate through 3DSMax.
ObjectTemplate.AmmoType 10
I haven't got a definitive list of ammo types, but this is what the B-17 turrets use so it seemed logical.
rem *** DefiantProjectile *** ObjectTemplate.create Projectile DefiantProjectile ObjectTemplate.createNotInGrid 1 ObjectTemplate.loadSoundScript ../../../Common/Sounds/Projectile.ssc ObjectTemplate.hasMobilePhysics 1 ObjectTemplate.hasCollisionPhysics 1 ObjectTemplate.hasResponsePhysics 1
Projectile now, and the only unfamiliarity is the NotInGrid, which I am not familiar with myself, but it seems a staple of most projectiles, so in it goes.
ObjectTemplate.timeToLive CRD_NONE/2/0/0 ObjectTemplate.gravityModifier 1 ObjectTemplate.material 224 ObjectTemplate.material2 -1 ObjectTemplate.stopAtEndEffect 1 ObjectTemplate.hasCollisionEffect 1
Here we can control range with the timeToLive, although I haven't experimented a great deal. For most aircraft weapons there is a gravity modifier of 0, as otherwise it makes accurate shooting quite difficult. I upped it to 1 to make the turret a little more challenging, and a little less uber. Materials will be covered in a later tute, and the last two lines are pretty self-explanatory.
rem *** DefiantBombDummy *** ObjectTemplate.create FireArms DefiantBombRack ObjectTemplate.setNetworkableInfo PlaneFireArmInfo ObjectTemplate.aiTemplate AichiValBombs ObjectTemplate.projectileTemplate DiveBomberBomb ObjectTemplate.projectilePosition 0/-0.4/-0.2 ObjectTemplate.magSize 30 ObjectTemplate.numOfMag 1 ObjectTemplate.velocity 0 ObjectTemplate.roundOfFire 0.2 ObjectTemplate.setInputFire c_PIAltFire ObjectTemplate.addFireArmsPosition -3.299/-0.199/0 0/0/0 ObjectTemplate.addFireArmsPosition 3.299/-0.199/0 0/0/0 ObjectTemplate.AmmoType 7
Lifted straight from the AichiVal. When I play with it some more I'll update this little section.
And that about concludes the first part of this tute, so post/flame away, and please help me to fill in the grey areas where I've just posted some vague rants. Enjoy.