Howto:Adding Bombable to FlightGear Aircraft

From FlightGear wiki
Jump to navigation Jump to search
Camel-through-wing.jpg
Spad-vs-camel.jpg
Warthog-down-on-bay-bridge.jpg

How to make a FlightGear aircraft work with Bombable.

When you follow these instructions, you will add the following properties to your aircraft:

  • AI aircraft can fly, maneuver, dodge, and attack the main aircraft. They can avoid the ground (aircraft) or stay on the ground (ships, vehicles) while maneuvering.
  • AI and MP aircraft can be damaged by the main aircraft and will stop functioning, crash, catch fire, explode, etc., appropriately when hit by weapons or bombs. MP aircraft will report damage back over MP to the main aircraft, making multiplayer dogfights possible.
  • MP aircraft will display weapons shooting whenever the remote MP aircraft is shooting, and report damage back to the main aircraft if the remote MP aircraft shoots or damages your aircraft.
  • AI and MP aircraft can have smoke, contrails, and damaged engine smoke
  • AI aircraft can automatically follow the main aircraft and attack it with weapons, which will be visible.
  • You can design and customize the features per aircraft--to make, for instance, a maneuverable twisty dogfighter, light and easily damaged, or a fast, heavily armored energy fighter with lower maneuverability.

To make FlightGear aircraft work with Bombable--as the main aircraft, an AI aircraft, and via Multiplayer (MP)--you need three things:

  • Weapons submodels that report impacts properly
  • A snippet of code added to the aircraft's -set.xml file to allow communication of Bombable information over Multiplayer
  • A section of code in the load/unload section of the Aircraft's XML files that allow Bombable to initialize and give it information about the aircraft needed to operate as an AI or Multiplayer model

There are several decisions you will have to make about where to put your file and what to name it (see "Where your aircraft files are" below for more info).

For our example, we'll mod the F-15E model from FGUK to become Bombable. We'll assume:

  • You have Bombable installed already
  • You have the aircraft installed in FGDATA/aircraft/F-15E
  • We will add the files/mods needed for AI aircraft to the FGDATA/aircraft/F-15E directories (rather than creating a new, separate FGDATA/AI/Aircraft version of the F-15E)
  • We're just going to mod the existing F-15E directories and aircraft without changing and aircraft or file names (rather than creating a separate, new, differently named F-15E-Bombable aircraft)

Helpful/Needed files

Step 1: Check the weapons models for impact reporting

Most FG aircraft that have weapons already work with Bombable at a basic level, right out of the box. That is because FG has a way for aircraft weapons to report their impacts, and most FG aircraft with weapons already use the impact reporting system.

First, find the XML file that defines the weapons submodels. Typically this is in the aircraft's Models directory (or a subdirectory). It may be named submodels.xml, or F-15-submodels.xml, or guns.xml, or something similar.

When you open the correct file (FGDATA\Aircraft\F-15E\Models\Effects\guns\submodels.xml, in this case), it will look something like this:

<PropertyList>

 <submodel>
   <name>left</name>
   <model>Aircraft/F-15E/Models/Effects/guns/apibullet-tracer.xml</model>
   <trigger>controls/armament/trigger</trigger>
   <speed>2460.0</speed>
   <repeat>true</repeat>
 . . . 

A complete description of these files is here.

For each <submodel></submodel> section, the areas of interest are the <name> and the <collision> and <impact> areas.

Submodel name

For the submodel name, in FG 2.4.0 we are working around a little FG bug, and Bombable identifies munitions and weapons by their name.

So it is very important that the name of each weapons submodel include one of the following keywords:

gun, tracer, bullet, round, cannon, bomb, heavy-bomb, rocket, missile, 
MK-81, MK-82, MK-83, MK-84, 5 pound, 25 pound, 100 pound, 150 pound, 
250 pound, 500 pound, 1000 pound, 2000 pound

The name simply needs to include the appropriate keyword in some way--so if you have another name you prefer, just include the keyword at the end, like "MKFD Special Munition (250 pound)".

In this case, it is a 20 mm gatling gun, so more into cannon range, with projectiles weighing in at about .25 lb. So we simply add "cannon" to each of the submodel names:

 <submodel>
   <name>left cannon</name>
 <submodel>
   <name>right cannon</name>

Collision and impact reporting

The collision and impact areas of this file look like this:

   <collision>true</collision>
   <collision-report>sim/ai/aircraft/collision/gun</collision-report>
   <impact>true</impact>
   <impact-report>sim/ai/aircraft/impact/bullet</impact-report>

[IMPORTANT!] Both <collision> and <impact> should be set to true.

[IMPORTANT!] <impact-report> should be one of these--the first one is the default, but any is fine:

     ai/models/model-impact
     sim/armament/weapons/impact
     sim/ai/aircraft/impact/bullet
     sim/ai/aircraft/impact/gun
     sim/ai/aircraft/impact/cannon
     sim/ai/aircraft/impact/bomb

According to the FG documentation, the <collision-report> setting is no longer used, so you can safely delete it (though it does no harm to leave it be).

For the F-15E, this section of each <submodel> looks fine, so we just leave it alone.

We save the file with the changes to the <name> sections.

STEP 2: Adding code needed for MultiPlayer to the -set.xml file

In the aircraft's -set.XML file, we need to add a <multiplay> section in the <PropertyList><sim> section.

This gets a bit confusing for two reasons:

  • -set.xml files may (or may not!) load other files, so the <sim> section where we need to add our code may be in the -set.xml file OR in one of the other .xml files the -set.xml file loads
  • There may be existing code in <sim><multiplayer> and so we can simply add our code to that rather than creating a new/different <multiplayer> section.

In the case of the F-15E, we open FGDATA\Aircraft\F-15E\F-15E_StrikeEagle-set.xml and find:

<?xml version="1.0"?>
<PropertyList>
 <sim>

 <description>F-15E_Strike_Eagle</description>
 <author>Flying Toaster 3DM, StuartC</author>
 <status>Alpha 2.01</status>
 . . .

Find out more about the -set.xml file here.

The <sim> section is what we are looking for.

We search for <multiplayer> and don't find any existing <multiplayer> section. So we can add our needed <multiplayer> section in any convenient place. Let's place it between the <submodels> and <panel> sections. The added code is in between those two:

 <submodels> 
     <serviceable type="bool">true</serviceable>
     <path>Aircraft/F-15E/Models/Effects/guns/submodels.xml</path>
     <path>Aircraft/F-15E/Models/weapons/loads.xml</path>
 </submodels>

 <multiplay>
   <generic>
     <string n="9" type="string"/>
     <int n="10" alias="controls/armament/trigger" />
   </generic>
 </multiplay>


 <panel>
  <visibility archive="y">false</visibility>
 </panel>

You'll notice we have customized one line: <int n="10" alias="controls/armament/trigger" />

The alias, controls/armament/trigger, refers to the submodel <trigger> which we observed in Step 1.

If the aircraft has more than one trigger (for more than one weapon, for example), we can make several triggers like this:

     <int n="10" alias="controls/armament/trigger" />
     <int n="11" alias="controls/armament/trigger1" />
     <int n="12" alias="controls/armament/trigger2" />
     <int n="13" alias="controls/armament/trigger3" />
     <int n="14" alias="controls/armament/trigger4" />

Each alias should correspond to a different <trigger> property in the submodel.xml definitions.

Save the -set.xml file with the changes.

STEP 3: Add the Bombable Nasal code to the Model XML file

Bombable needs to have certain code run when the AI or MP aircraft initializes. The code is in Nasal, FlightGear's scripting language. The code gives Bombable needed information about the aircraft (dimensions, vulnerabilities, weapons, etc) and also the code tells Bombable which systems to initialize for this aircraft.

The simplest way to create this code is to start with a similar aircraft in the Bombable download, then copy and mod the Bombable code as needed.

There are two steps in this process:

  • Create the -bombableinclude.xml file
  • Link the -bombableinclude.xml file to the aircraft's existing model XML file

Create the -bombableinclude.xml file

In the Bombable distribution, the include files are named [aircraftname]-bombableinclude.xml and are generally found in FGDATA/AI/Aircraft/[aircraftname]/Models.

In this case, the most similar aircraft in the Bombable distribution is the A-10. If Bombable is installed, the needed file is in:

FGDATA\AI\Aircraft\A-10-Bombable\Models\A-10-bombableinclude.xml

Open the file with a text editor and save it with a new name in your F-15E directory. The new name & directory should be something like:

FGDATA\Aircraft\F-15E\Models\F-15E_StrikeEagle-bombableinclude.xml

Now you can open and edit this file. Most changes are quite obvious--change the name, change the dimensions, etc.

When done, we end up with a file like this:

 <?xml version="1.0"?>
 
 <PropertyList>
 	<nasal>
 	  
 
 		<load>
 			<![CDATA[
 			print("Loading F-15E ", cmdarg().getPath());
 
       var nodeName = cmdarg().getPath(); 
 
       ##checks whether it has been initialized already; if so, just return
       if ( bombable.check_overall_initialized (nodeName) ) return;
 
 			
 			
 
 ############################################
 #FUNCTION object_init, INITIALIZER
 			var object_init = func() {
 				# Datas of this object are under: cmdarg().getPath()
 				var thisNodeName = cmdarg().getPath();
 				var thisNode = props.globals.getNode(thisNodeName);
 				# Add some useful nodes
 
 
 				
         ########################################################################
         ########################################################################
         # INITIALIZE BOMBABLE
         # 
         # Initialize constants and main routines for maintaining altitude
         # relative to ground-level, relocating after file/reset, and 
         # creating bombable/shootable objects.
         # 
         # These routines are found in FG/nasal/bombable.nas
         #  
         ########################################################################               
         # INITIALIZE BOMBABLE Object
         # This object will be slurped in the object's node as a child
         # node named "bombable".                 
         # All distances are specified in meters.
         # All altitudes are relative to current ground level at the object's 
         # location
         # 
          
         thisNodeName = cmdarg().getPath(); 
 
         var bombableObject = {  
           
           
           objectNodeName : thisNodeName,
           objectNode : props.globals.getNode(thisNodeName),
           updateTime_s : 1/3, #time, in seconds, between the updates that 
           #keep the object at its AGL. Tradeoff is high-speed updates look more
           #realistic but slow down the framerate/cause jerkiness.  Faster-moving
           #objects will need more frequent updates to look realistic.
           #update time faster than about 1/3 seems to have a noticeable effect
           #on frame rate                    
 
 		                        
           #########################################                              
           # ALTITUDE DEFINITIONS
           #         
           altitudes : {	
             wheelsOnGroundAGL_m : 1 , #altitude correction to add to your aircraft or ship that is needed to put wheels on ground (or, for a ship, make it float in the water at the correct level).  For most objects this is 0 but some models need a small correction to place them exactly at ground level
             
             minimumAGL_m : 300, #minimum altitude above ground level this object is allowed to fly
             maximumAGL_m : 50000, #maximum altitude AGL this object is allowed to fly, ie, operational ceiling	    
             crashedAGL_m : 0.6, #altitude AGL when crashed.  Ships will sink to this level, aircraft or vehicles will sink into the ground as landing gear collapses or tires deflate. Should be negative, even just -0.001.
           },
           #  
           #########################################
           # VELOCITIES DEFINITIONS
           # 
           velocities : {               
             maxSpeedReduce_percent : 0.5, #max % to reduce speed, per step, when damaged
             minSpeed_kt : 112, #minimum speed to reduce to when damaged.  Ground vehicles and ships might stop completely when damaged but aircraft will need a minimum speed so they keep moving until they hit the ground.
             cruiseSpeed_kt : 550, #cruising speed, typical/optimal cruising speed, V C for aircraft
             
             attackSpeed_kt : 900, #typical/optimal speed when aggressively attacking or evading, in
                                  #level flight for aircraft
             
             maxSpeed_kt : 1400 , #Maximum possible speed under dive or downhill conditions, V NE for aircraft
     
             damagedAltitudeChangeMaxRate_meterspersecond : 30, #max rate to sink or fly downwards when damaged, in meters/second
 
             #The terminal velocities are calculated by opening the 'real' AC 
             #in FG, level flight, full throttle, then putting
             #the AC at different angles of attack with the autopilot,
             #and noting the terminal airspeed & vertical speed velocities.
             #For best results, do it near sea level, under 5000 feet altitude.
             #One or two each of climb & dive velocities are probably sufficient.
             #However if you do more we may be able to use the more precise
             #data in the future.
             #
             #Note that these are intended to be true airspeed whereas FG's
             #/velocities/airspeed-kt reports indicated airspeed, so some 
             #conversion or reference to groundspeed-kt is needed.
             # 
             #In FG /velocities/groundspeed-kt is equal (or close 
             #to equal, except for wind . . .) true airspeed when pitch=0 
             #but as pitch increases or decreases that will change.
             #                          
             diveTerminalVelocities: {
                 point1: { airspeed_kt : 1060, vertical_speed_fps : - 337},
                 point2: { airspeed_kt : 1230, vertical_speed_fps : - 755},
                 
             },
 
             climbTerminalVelocities: {
               point1: { airspeed_kt : 468, vertical_speed_fps : 236},
               point2: { airspeed_kt : 843, vertical_speed_fps : 251},
               #point3: { airspeed_kt : 1100, vertical_speed_fps : 161},
           
             },
             
           },
           #  
           #########################################
           # EVASION DEFINITIONS
           # 
           # The evasion system makes the AI aircraft dodge when they come under
           # fire. 
           evasions : {               
             dodgeDelayMax_sec : 15, #max time to delay/wait between dodges
             dodgeDelayMin_sec : 5, #minimum time to delay/wait between dodges
             dodgeMax_deg : 88, #Max amount to turn when dodging
                               #90 degrees = instant turn, unrealistic
                               #up to 80 is usually OK, somewhere in 80-85 starts to be unrealistically fast
                               #>85 is usually very unrealistic.  You must test this in your scenario, however.
             
             dodgeMin_deg : 83, #minimum amount to turn when dodging           
             rollRateMax_degpersec : 300, #you can figure this out by rolling the corresponding FG aircraft and timing a 180 or 360 deg roll            
             dodgeROverLPreference_percent : 50, # Preference for right turns vs. left when dodging.  90% means 90% right turns, 50% means 50% right turns.
             dodgeAltMin_m : -8000, #Aircraft will begin to move up or down 
             dodgeAltMax_m : 8000, #Max & Min are relative to current alt 
             dodgeVertSpeedClimb_mps : 1500, #Max speed to climb when evading
             dodgeVertSpeedDive_mps : 1500, #Max speed to dive when evading 
           },
           #  
           #########################################
           # ATTACK DEFINITIONS
           # 
           # The attack system makes the AI aircraft turn and fly towards 
           # other aircraft 
           attacks : {               
             maxDistance_m : 30000, #max distance to turn & attack main aircraft
             minDistance_m : 4000, #min distance to turn & attack main aircraft, ie, fly away this far before turning to attack again
             continueAttackAngle_deg : 80, #when within minDistance_m, the aircraft will continue to turn towards the main aircraft and attack *if* if the angle is less than this amount from dead ahead
             altitudeHigherCutoff_m : 30000, # will attack the main aircraft unless this amount higher than it or more
             altitudeLowerCutoff_m : 30000, # will attack the main aircraft unless this amount lower than it or more
             climbPower : 8000, # How powerful the aircraft is when climbing during an attack; 4000 would be typical for, say a Zero--scale accordingly for others; higher is stronger
             divePower : 10000, # How powerful the aircraft is when diving during and attack; 6000 typical of a Zero--could be much more than climbPower if the aircraft is a weak climber but a strong diver              
             rollMin_deg : 82, #when turning on attack, roll to this angle min
                               #for sedate, Cessna-like manuevers make rollMin low.  If you want an aggressive,
                               #attacking, aiming fighter keep it close to rollMax, or even almost equal to rollMax 
             rollMax_deg : 87, #when turning on attack, roll to this angle max
                               #90 degrees = instant turn, unrealistic
                               #up to 80 might be OK, depending on aircraft & speed; somewhere in 80-85 starts to be unrealistically fast
                               #>85 is usually very unrealistic.  You must test this in your scenario, however.
             rollRateMax_degpersec : 120, #you can figure this out by rolling the corresponding FG aircraft and timing a 180 or 360 deg roll            
             attackCheckTime_sec : 10, # check for need to attack/correct course this often  
             attackCheckTimeEngaged_sec : 0.5, # once engaged with enemy, check/update course this frequently
                 
           },
           
           #  
           #########################################
           # WEAPONS DEFINITIONS
           # 
           # The weapons system makes the AI aircraft fire on the main aircraft 
           # You can define any number of weapons--just enclose each in curly brackets
           # and separate with commas (,).           
           weapons : {
              front_gun :  #internal name - this can be any name you want; must be a valid nasal variable name
               {               
                 name : "Machine Gun", # name presented to users, ie in on-screen messages
                 maxDamage_percent : 5, # maximum percentage damage one hit from the aircraft's main weapon/machine guns will do to an opponent
                 maxDamageDistance_m : 2000, # maximum distance at which the aircrafts main weapon/maching guns will be able to damage an opponent
                 weaponAngle_deg  :  { heading: 0, elevation: 0 }, # direction the aircraft's main weapon is aimed.   
                                                                   # 0,0 = straight ahead, 90,0=directly right, 0,90=directly up, 0,180=directly back, etc.
                 weaponOffset_m : {x:2, y:0, z:0}, # Offset of the weapon from the main aircraft center
                 weaponSize_m : {start:.1, end:.1}, # Visual size of the weapon's projectile, in meters, at start & end of its path
 
               },    
              sidewinder_missile :  #internal name - this can be any name you want; must be a valid nasal variable name
               {               
                 name : "Sidewinder guided missile", # name presented to users, ie in on-screen messages
                 maxDamage_percent : 40, # maximum percentage damage one hit from the aircraft's main weapon/machine guns will do to an opponent
                 maxDamageDistance_m : 6000, # maximum distance at which the aircrafts main weapon/machine guns will be able to damage an opponent
                 weaponAngle_deg  :  { heading: 0, elevation: 0 }, # direction the aircraft's main weapon is aimed.   
                                                                   # 0,0 = straight ahead, 90,0=directly right, 0,90=directly up, 0,180=directly back, etc.
                 weaponOffset_m : {x:2, y:0, z:0}, # Offset of the weapon from the main aircraft center
                 weaponSize_m : {start:1, end:1}, # Visual size of the weapon's projectile, in meters, at start & end of its path
 
               },    
 
 
           },  
           
           #  
           #########################################
           # DIMENSION DEFINITIONS
           #
           # All dimensions are in meters
           #           
           #           
           dimensions : {                  
             width_m : 17.53,  #width of your object, ie, for aircraft, wingspan
             length_m : 16.26, #length of your object, ie, for aircraft, distance nose to tail
             height_m : 4.47, #height of your object, ie, for aircraft ground to highest point when sitting on runway
             
             damageRadius_m : 8, #typically 1/2 the longest dimension of the object. Hits within this distance of the 
                                 #center of object have some possibility of damage
             vitalDamageRadius_m : 2, #typically the radius of the fuselage or cockpit or other most 
                                      # vital area at the center of the object.  Always smaller than damageRadius_m
                                     
             crashRadius_m : 6, #It's a crash if the main aircraft hits in this area.
                                 
           },
           #
           #########################################
           # VULNERABILITIES DEFINITIONS        
           #
           vulnerabilities : {                   
             damageVulnerability : 9, #Vulnerability to damage from armament, 1=normal M1 tank; higher to make objects easier to kill and lower to make them more difficult.  This is a multiplier, so 5 means 5X easier to kill than an M1, 1/5 means 5X harder to kill. 
             
             engineDamageVulnerability_percent : 6, #Chance that a small-caliber machine-gun round will damage the engine.       
             
             fireVulnerability_percent : 5, #Vulnerability to catching on fire. 100% means even the slightest impact will set it on fire; 20% means quite difficult to set on fire; 0% means set on fire only when completely damaged; -1% means never set on fire.                          
             
             fireDamageRate_percentpersecond : .1, #Amount of damage to add, per second, when on fire.  100%=completely damaged. Warthog is relatively damage-resistant.
             
             fireExtinguishMaxTime_seconds : 80, #Once a fire starts, for this many seconds there is a chance to put out the fire; fires lasting longer than this won't be put out until the object burns out.
             
             fireExtinguishSuccess_percentage : 45, #Chance of the crew putting out the fire within the MaxTime above. Warthoge is relatively damage-resistant.
             
             explosiveMass_kg : 27772 , #mass of the object in KG, but give at least a 2-10X bonus to anything carrying flammables or high explosives.
           },
           #
           #########################################
           # LIVERY DEFINITIONS
           #
           # Path to livery files to use at different damage levels.
           # Path is relative to the AI aircraft's directory.
           # The object will start with the first livery listed and 
           # change to succeeding liveries as the damage
           # level increases. The final livery should indicate full damage/
           # object destroyed.        
           # 
           # If you don't want to specify any special liveries simply set 
           # damageLivery : nil and the object's normal livery will be used.  
           #                                                            
           damageLiveries : {
             damageLivery : [  ]                        
           },
                             
         };
 
         #########################################
         # INITIALIZE ROUTINES
         # 
         # OVERALL INITIALIZER: Needed to make all the others work
         bombable.initialize ( bombableObject );
         #
         # LOCATION: Relocate object to maintain its position after file/reset       
         # (best not used for airplanes)
         # bombable.location_init ( thisNodeName );
         #
         # GROUND: Keep object at altitude relative to ground level
         bombable.ground_init ( thisNodeName );
         #
         # ATTACK: Make the object attack the main aircraft        
         bombable.attack_init ( thisNodeName );
         #
         # WEAPONS: Make the object shoot the main aircraft        
         bombable.weapons_init ( thisNodeName );                
         #
         # BOMBABLE: Make the object bombable/damageable        
         bombable.bombable_init ( thisNodeName );
         #
         # SMOKE/CONTRAIL: Start a flare, contrail, smoke trail, or exhaust 
         # trail for the object.
         # Smoke types available: flare, jetcontrail, pistonexhaust, smoketrail,
         # damagedengine                        
         bombable.startSmoke("jetcontrail", thisNodeName );
         #F-15E already has contrails, we're leaving this out
         #
         # END INITIALIZE BOMBABLE
         ########################################################################
         ########################################################################                
 	      
 
 				
 			}
 			
 			object_init();
 			]]>
 		</load>
 		<unload>
 			<![CDATA[
 			print("Unload F-15E.");
       var nodeName= cmdarg().getPath();  
       bombable.de_overall_initialize( nodeName );
       bombable.initialize_del( nodeName );
       bombable.ground_del( nodeName );
       bombable.location_del (nodeName);
       bombable.bombable_del( nodeName );
       bombable.attack_del( nodeName );
       bombable.weapons_del (nodeName);      
 #  </unload>
 
 			]]>
 		</unload>
  </nasal>  
 
 </PropertyList>

Save this file with the name you have chosen ( FGDATA\Aircraft\F-15E\Models\F-15E_StrikeEagle-bombableinclude.xml).

Link the -bombableinclude.xml file to the existing F-15 model file

Now that we have created the -bombableinclude.xml file, we need to set up the aircraft to load the file on startup.

AI scenarios (and MP aircraft) load the aircraft's model file. So we need to locate that file and include the new -bombableinclude.xml file in it.

Where is the model file? Look in the aircraft's -set.xml file. In that file will be a section called <model>. For the F-15E it looks like this:

 <model>
  <path>Aircraft/F-15E/Models/F-15E_StrikeEagle.xml</path>
 </model>

So Aircraft/F-15E/Models/F-15E_StrikeEagle.xml is our model file.


Load Aircraft/F-15E/Models/F-15E_StrikeEagle.xml in a text editor. At the beginning of that file you will find this:

<?xml version="1.0"?>

<PropertyList>

Change it to this:

<?xml version="1.0"?>

<PropertyList include="F-15E_StrikeEagle-bombableinclude.xml">

Save the file.

Notes

  • The statement include="F-15E_StrikeEagle-bombableinclude.xml" indicates that F-15E_StrikeEagle-bombableinclude.xml will be in the same directory as F-15E_StrikeEagle.xml. That directory is Aircraft/F-15E/Models -- so make sure that the -bombableinclude.xml file is indeed in that directory!
  • Model files can have only ONE Nasal <load> section and one <unload> section.

If you have more than one, the second and subsequent <load>/<unload> sections are ignored.

The problem? Your aircraft may already have a <load> or <unload> section. When you add the Bombable code, one of the two <load> sections (the pre-existing one or Bombable's) will be ignored.

The solution is to combine the two <load> sections into one, and the same with the <unload> sections. You'll need to know a little about Nasal programming to do anything complicated, but as a rule you can just copy/paste whatever is in the aircraft's <load> section to the start of Bombable's <load> section, and the same with <unload>.

  • You'll notice the Nasal code starts with <![CDATA[ and ends with ]]>. That is needed to make Nasal code work within XML files. CDATA usage is explained here.

STEP 4. Add to an AI Scenario

Now we can add the F-15E to an AI scenario.

Create a file named F-15E-demo.xml and save it in your FGDATA/AI directory.

Most of the entries in the scenario file are self-explanatory. For the <model> entry you'll need the path of the same model file for the F-15 that we located in Step 3--which is Aircraft/F-15E/Models/F-15E_StrikeEagle.xml.

Here is how the file should look when you are done:

<?xml version="1.0"?>
<PropertyList>
 <scenario>
   <description>My new F-15E scenario.  Starts at KSFO! </description>
		
   <entry>
     <type>aircraft</type>
     <callsign>Jones</callsign>
     <name>F15E Leader</name>
     <model type="string">Aircraft/F-15E/Models/F-15E_StrikeEagle.xml</model>
     <latitude type="double">37.608720</latitude>
     <longitude type="double">-122.3076</longitude>
     <altitude type="double">309</altitude>
     <speed>280.0</speed>
     <heading type="double">192</heading>
   </entry>
    
   <entry>
     <type>aircraft</type>
     <callsign>Cooper</callsign>
     <name>F15E Wingman</name>
     <model type="string">Aircraft/F-15E/Models/F-15E_StrikeEagle.xml</model>
     <latitude type="double">37.608200</latitude>
     <longitude type="double">-122.2988</longitude>
     <altitude type="double">309</altitude>
     <speed>270.0</speed>
     <heading type="double">192</heading>
   </entry>
 <scenario>

</PropertyList>

Again, save as FGDATA/AI/F-15E-demo.xml. When you start FGRun next time, F-15E-demo will be listed as one of the scenario file options. (You may need to quit and re-start FGRun.)

STEP 5. Troubleshooting

OK, we're done. Time to fly our new aircraft in our new scenario!

Oh, yeah . . . we just followed a very complicated process with numerous steps that could go wrong. Maybe we'd better test a bit first.

Start Flightgear. Using FGRun:

1. Choose UFO bombable as the main aircraft (best for testing . . . ) 2. Airport KSFO 3. Scenario F-15-demo (which we just created--if saved correctly in the FGDATA/AI directory, it will show up in the scenario list of FGRun) 4. Click "Run" 5. Closely watch the command console as FG starts. You may pick up important errors in XML files and/or Nasal code. 6. You should see

* Bombable (ver. 4.4) loaded . . . 
* loading scenario "f-15-demo"

Uh-oh. There is our first error. f-15-demo.xml, line 31, column 2, I have "<scenario>" rather than "</scenario>".

I fix, save the fixed file, and re-start. Now I get:

* Bombable (ver. 4.4) loaded . . . 
* loading scenario "f-15-demo"
* Failed to load XML: . . .  F-15E-StrikeEagle-bombableinclude.xml

OK, this is typical. There is a typo or stray character on the .xml file . . . or something.

After a few minutes of trying different things, I discover I've made a typo:

  • In \Aircraft\F-15E\Models\F-15E_StrikeEagle.xml is this line:
 <PropertyList include="F-15E_StrikeEagle-bombableinclude.xml">
  • But I've saved the file as
FGDATA/Aircraft/F-15E/F-15-StrikeEagle-bombableinclude.xml

OK, that one little "E" made all the difference. I change the filename to match what's in the -set.xml file and try again.

And finally:

* Bombable (ver. 4.4) loaded . . . 
* loading scenario "f-15-demo"
* Loading F-15E /ai/models/aircraft
* Loading F-15E /ai/models/aircraft[1]
* A bunch of other Bombable messages showing the aircraft initializing (I have Bombable menu/Debug turned on, which is helpful at this stage)
* A bunch of error messages showing various animations and systems not load (ahhh . . . that's why we create stripped-down versions of aircraft in the AI/Aircraft directory--a completely separate and even longer article).

I open Equipment/Maps, click "traffic", see the two aircraft "Jones" and "Cooper", track them down with the UFO, they show proper smoke trails, I shoot at them, I shoot them down. It works!

Success!

Well, except . . . are they flying realistically? Climbing, turning, diving, shooting? Are they taking damage realistically? Does it work properly under Multiplayer?

Here is where you spend hours researching real F-15s, flying against the AI models with the UFO and other aircraft, tweaking parameters in the -bombableinclude.xml file, and so on and on.

You're just getting started.

Good luck!

Testing/parsing XML files

One final tip: XML files are extremely persnickety. Just one wrong character can make an entire file fail to load.

The best/easiest way to test XML files is load them in Internet Explorer. It will parse the XML file and display any errors it finds. (If you don't have access to IE there are other XML parsers available.) This is far easier and faster than starting and re-starting FG repeatedly, and IE gives better, more informative error messages as well.

IMPORTANT POSTSCRIPT: Where your aircraft files are

An important detail in getting Bombable to work with aircraft over AI and MP is the directories you store the files in and the names you choose to use for them.

FlightGear stores aircraft and AI aircraft files in at least two different places.

In a typical FG installation, in your FGDATA folder, you will find

* FGDATA/Aircraft
* FGDATA/AI/Aircraft

FGDATA/Aircraft holds files for the main aircraft whereas FGDATA/AI/Aircraft holds files for AI and MP aircraft.

AI/MP aircraft don't have all the features of main aircraft, so you might find the very same aircraft in FGDATA/Aircraft and in FGDATA/AI/Aircraft--but the one in FGDATA/AI/Aircraft will be very stripped down, fewer files, smaller, and less complex.

When building a FlightGear AI scenario, you can specify the exact path and filename of the file FlightGear looks for. You can specify a file in the FGDATA/Aircraft directory, or in the FGDATA/AI/Aircraft, or really anywhere within the FGDATA directory that you like. Examples:

<model type="string">AI/Aircraft/sopwithCamel-Bombable/Models/sopwithCamel-model.xml</model> 

OR

<model type="string">Aircraft/sopwithCamel-Bombable/Models/sopwithCamel-model.xml</model> 

When loading an MP aircraft, FlightGear first looks for the (typically smaller/simpler) aircraft file in FGDATA/AI/Aircraft.

If it doesn't find the aircraft there, it then searches FGDATA/Aircraft.

How FG matches Multiplayer Aircraft with your local AI aircraft models

As of version 2.4.0, when FG is looking for the local AI aircraft model to display for a remote aircraft over Multiplayer, FG searches first the AI Aircraft directories, then the Aircraft directories.

It searches for a match by looking for the file with a name exactly matching the MP aircraft's model (this is typically in the aircraft's Models subdirectory and ends with .ac, though this may vary) and if that fails, FG looks for a matching -set.xml file.

The important points for making AI models that will work over MP with Bombable:

  • Make sure the main aircraft and the AI version of the aircraft have the exact same names for the aircraft's model file and the aircraft's -set.xml
  • If you're modding an existing but non-bombable-compatible aircraft, you need to decide whether you're going to leave all the directories, model XML file names, and -set.xml file names the same as the standard flightgear aircraft (leading to possible frustration as your version overwrites existing aircraft files on users hard drivers) OR rename the aircraft's directory, -set.xml file name, and model file name (which means you're going to have to do a bit of work on the aircraft's XML files to make sure everything still works with all those name changes.
  • You can create a separate, stripped down AI version of the aircraft in the FGDATA/AI/Aircraft directory and add the Bombable additions to it (more work for you but smaller/quicker download and easier on the memory and framerate in FG) OR you can simply add all the Bombable additions to the main aircraft directory in FGDATA/Aircraft.

Bombable will work with any of those options--so it is really up to you.

EXTRA: Making livery change with damage

Once you have Bombable working with your aircraft there is a bonus: bombable.nas will handle setting the livery colors and automatically changing them as the object becomes damaged.

For an example of how this works and looks, take a look at the Bombable scenarios involving the M1 tank and the Jeep.

For this to work your model must have different liveries available and then animate the liveries so that the texture used is the one shown in this path: /ai/model/model[X]/bombable/texture-corps-path. The /ai/model/model[X]/ part is assumed for AI craft so you need to add <texture-prop>bombable/texture-corps-path</texture-prop> in the right place of your XML file.

Example from Jeep.xml in the jeep-bombable directory:

<animation>
  <type>material</type>
  <object-name>jeep-body</object-name>
  <object-name>roof1</object-name>
  <object-name>roof2</object-name>
  <object-name>softroof</object-name>
  <object-name>chassis</object-name>
  <object-name>chassis.002</object-name>
  <object-name>Plane</object-name>
  <object-name>hinge</object-name>
  <object-name>screen</object-name>
  <object-name>wiper.L</object-name>
  <object-name>wiper.R</object-name>
  <object-name>seat.L</object-name>
  <object-name>seat.R</object-name>
  <texture-prop>bombable/texture-corps-path</texture-prop>
  <transparency>
     <alpha>1.0</alpha>
  </transparency>
</animation>
 

Additionally, if you want to change your object's the livery color programmatically (for instance, if you include a menu item to select different liveries) you can use the following code in the -bombableinclude.xml file (see above) to change all liveries, including damage liveries, that the object uses:

Example:

    liveries = [
        "Models/livery_nodamage.png", 
        "Models/livery_slightdamage.png", 
        "Models/livery_highdamage.png");
    ];

    bombable.set_livery (cmdarg().getPath(), liveries); 

You can include liveries for as many different levels of damage (ie, fine gradations of change from undamaged to completely damaged) as you like. For instance:


Example:

    liveries = [
        "Models/livery_nodamage.png", 
        "Models/livery_barelydamaged.png", 
        "Models/livery_justslightlydamaged.png", 
        "Models/livery_alittlemoredamage.png", 
        "Models/livery_fairlydamaged.png",          
        "Models/livery_kindadamaged.png",
        "Models/livery_prettydamaged.png",
        "Models/livery_whoawereintroublenow.png",                   
        "Models/livery_finishedoff.png");
    ];

    bombable.set_livery (cmdarg().getPath(), liveries);  



Related content