How To Make NPC Ships Flyable

Intro

In this tutorial I'm going to take you along for the ride while I convert an enemy ship into a flyable player ship.

I hope that after following the steps in this tutorial, everybody interested will be able to mod the game on their own, and that we'll see more actual mods for the game, not just simple ship skins (ok, they're not that simple, in fact not at all, but you know what I mean).

Updates & Contact

The latest version of this tutorial should always be available on the Github repository:
https://github.com/sp00n/rgo-tutorials

Contact is possible over Github, or over e-mail: sp.00.n@gmx.net. I might also be in the RGO Discord channel.

The LUA source for this mod can be downloaded here:
Flyable_Zandt_LUA_source.zip

My other mods are available on Nexus Mods:
https://www.nexusmods.com/rebelgalaxyoutlaw

Requirements

Of course you need the game Rebel Galaxy Outlaw. You also need the RGO LUA utils, which you can find here (originally created by hhrhhr, extended and modified by me):
https://github.com/sp00n/rgo-lua-utils/

These tools require at least LUA 5.3 and some libraries, hhrhhr has made a package for them, which I've uploaded here:
https://github.com/sp00n/rgo-lua-pack

Alternative link, directly uploaded by hhrhhr (source):
https://mega.nz/file/e4xmWCQZ#NmDjowuExvA7NAV6ZO1CIXeFTzAisQiHUzvyhuFuHuM

I have also created a couple of batch files that will help you with extracting all of the DATAx.PAK file, and also help you with quickly creating a new mod file, without going through the hassle of manually converting each file separately.
You can find these batch files here:
https://github.com/sp00n/rgo-mod-helpers

Both the LUA executable and the batch helpers should be placed in a directory that is globally accessible, e.g. one that is in your PATH variable.
See the relevant Github project pages for a more detailed explanation.

You will also need a text editor. Notepad has received some upgrades with Windows 10, so it's not completely useless anymore, but if you want something better, I can recommend Notepad++, it's free:
https://notepad-plus-plus.org/

Next you need to unpack all the DATAx.PAK files from the game and convert their content to LUA files. Hopefully you have installed and set up the batch helper tools, so basically all you need to do is to run rgo-convert-all <optional_target_directory>.
See the Github project page for a more detailled description of what the helper files do for you.

If not, you'll have to manually extract each .PAK file and convert all the included files yourself. Have fun.

If you want to edit graphics, you will need a way to open, edit, and save .DDS (DirectDraw Surface) files. Most graphic programs don't support this by default, but there are plugins and specialized tools for it.

The Nexus Mods Wiki has a good overview of all the available tools and plugins you can use:
http://wiki.tesnexus.com/index.php/DDS_texture_tools

For example, Adobe Photoshop + Intel DDS Plugin, or GIMP + Plugin.

As far as editing the LUA files themselves goes, I haven't created a dedicated tutorial for this. I hope that the examples I give here are sufficient enough so that anybody can follow along.
There is a modding guide out there for the predecessor game, Rebel Galaxy (without "Outlaw"). And much of the info there still holds true for this game as well:
https://steamcommunity.com/sharedfiles/filedetails/?id=551447922

Step 1: The Bare Minimum

First we need some preparations.
We're going to use the Steel Rats Zandt Fighter, because it includes basically every obstacle we could encounter when we convert a ship:
grouped weapon hardpoints, non-working missile slots, non-selectable turrets, moving the cockpit camera, chaning the ship's scale.

Let's create our mod folder somewhere, and call it x99_Flyable_Zandt (I like to prepend my mod names with x99 to make them easily identifiable). Now create another folder named LUA inside it, which will contain all the files we will include in our mod.
The folder structure will need to mirror the one of the extracted DATAx.PAK files, so create a couple more folders with the following directory structure, like so: MEDIA\SHIPS\PLAYERSHIPS.

The final directory structure should look something like this:
D:\Games\RGO\_MODS\x99_Flyable_Zandt\LUA\MEDIA\SHIPS\PLAYERSHIPS

Now navigate to the extracted and converted files folder, and into the MEDIA/SHIPS folder. There you will see a couple of folders. We're using the Steel Rats Zandt ship in this example, so go to the STEELRATSFIGHTER folder. The Zandt is a Gunship, so it uses the 15_PIRATEGUNSHIP.DAT.lua file. Open this file in your text editor.

Now navigate to the MEDIA/SHIPS/PLAYERSHIPS folder. We will need to use one of these already existing entries as the template for our new ship. There is no Gunship class for the player, so we're looking for something heavy and bulky. The Durston comes to mind, which is defined in the 15_DURSTON.DAT.lua file.

Copy & paste this file into your x99_Flyable_Zandt\LUA\MEDIA\SHIPS\PLAYERSHIPS folder and rename it to 15_ZANDT_PLAYER.DAT.lua.

It's now time to edit that file.

1.1 The Ship File

15_ZANDT_PLAYER.DAT.lua

We need to have open both the original 15_PIRATEGUNSHIP.DAT.lua file and the new 15_ZANDT_PLAYER.DAT.lua so that we can move properties from one file to the other.

Some basics first, at the top of the file there is a line with local L = {, which initiates the definition of the L table variable, which contains all the string values that appear in the file. These strings are then later referenced by the v property parameters in the following content variable.
Numbers (integers and floating points) and true/false values (boolean) will instead be edited directly in the property entries.

Note that in line 7 of 15_PIRATEGUNSHIP.DAT.lua there's a reference to a .layout file:

[2] = {    3, "MEDIA/SHIPS/SHIP_SET_1/pirate3_gunship_loadout.layout" },

So navigate to that directory and copy and paste the 16_PIRATE3_GUNSHIP_LOADOUT.LAYOUT.lua into out mod directory, again mirroring the directory structure, so into x99_Flyable_Zandt\LUA\MEDIA\SHIPS\SHIP_SET_1. Rename the file to 16_ZANDT_LOADOUT_PLAYER.LAYOUT.lua.

And yes, capitalization is bit all over the place in our original files, we don't seem to do anything wrong if we stick either to all lowercase or all uppercase letters. I've chosen all uppercase, since all the files themselves seem to be in uppercase.
Just try to don't mix upper- and lowercase for the name and file extension, I've found this to indeed cause a problem in at least one instance.

We now need to transfer some values from the original 15_PIRATEGUNSHIP.DAT.lua file to the new 15_ZANDT_PLAYER.DAT.lua file. Certain entries that are required for the ship to work as a player ship are missing in the NPC ship files, so we needed to use an existing player ship file as a template.

Below are all the entries that I changed for the L table:

Entry Old Value New Value
[0] = { 1,
Durston Zandt
[1] = { 2,
Cargo Gunship
[2] = { 3,
FIGHTER GUNSHIP
[3] = { 4,
MEDIA/SHIPS/SHIP_SET_1/bigcargo_loadout_player.layout MEDIA/SHIPS/SHIP_SET_1/ZANDT_LOADOUT_PLAYER.LAYOUT
[4] = { 5,
MEDIA/SHIPS/SHIP_SET_1/bigcargo01_low.mdl MEDIA/SHIPS/SHIP_SET_1/pirate3_gunship01A_LOD0.mdl
[5] = { 6,
MEDIA/SHIPS/SHIP_SET_1/bigcargo01_LOD0.mdl MEDIA/SHIPS/SHIP_SET_1/pirate3_gunship01A_ultra.mdl
[6] = { 7,
MEDIA/SHIPS/SHIP_SET_1/big_cargo01_low_animated.mdl MEDIA/SHIPS/SHIP_SET_1/pirate3_gunship01A_LOD0.mdl
[7] = { 8,
MEDIA/SHIPS/SHIP_SET_1/big_cargo01_animated.mdl MEDIA/SHIPS/SHIP_SET_1/pirate3_gunship01A_ultra.mdl
[8] = { 9,
MEDIA/SHIPS/SHIP_SET_1/bigcargo01_collision.mdl MEDIA/SHIPS/SHIP_SET_1/pirate3_gunship01_hull.mdl
[9] = { 10,
MEDIA/SHIPS/SHIP_SET_1/bigcargo01_hull.mdl MEDIA/SHIPS/SHIP_SET_1/pirate3_gunship01_hull.mdl
[12] = { 13,
MEDIA/SHIPS/SHIP_SET_1/bigcargo01_paint.mdl MEDIA/SHIPS/SHIP_SET_1/pirate3_gunship01A_ultra.mdl
[13] = { 14,
MEDIA/SHIPS/SHIP_SET_1/BigCargo01_CustomPaint.dds MEDIA/SHIPS/SHIP_SET_1/PIRATE3_GUNSHIP01A_PAINT.DDS
[14] = { 15,
BigCargo01_CustomPaint.dds PIRATE3_GUNSHIP01A_PAINT.DDS
[15] = { 16,
MEDIA/SHIPS/SHIP_SET_1/BIGCARGO_DETAIL.DDS MEDIA/SHIPS/SHIP_SET_1/PIRATE3_GUNSHIP01A_PAINT.DDS

1_1-15_ZANDT_PLAYER.DAT.lua_Changes.jpg

As you can see, not all of the player ship entries to another file (.mdl, .dds) have a direct counterpart for an NPC ship, and some of the player ship entries also don't have an equivalent in the NPC ship file, so you have to look through the extracted files if you can find one.

Also some functionality may not work 100% or as expected, the paint shop is such an example, the mouse cursor seems to be offset by some margin there.
I tried to match the .mdl and .dds files as closely as possible, and it seems to work good enough.

The ship stats themselves are still that of the original player template ship, so we change these next.

Entry Old Value New Value
SCALE 2.0 2.0
TOP_SPEED 300.0 320.0
PITCH_ACCELERATION 60.0 110.0
YAW_ACCELERATION 60.0 110.0
ROLL_ACCELERATION 90.0 130.0
MAX_PITCH_RATE 60.0 70.0
MAX_YAW_RATE 70.0 90.0
MAX_ROLL_RATE 90.0 80.0
PITCH_DECAY 0.0099999997764826 0.019999999552965
YAW_DECAY 0.0099999997764826 0.019999999552965
ROLL_DECAY 0.0099999997764826 0.019999999552965
INERTIAL_DAMP 0.014999999664724 0.0099999997764826

There are also a couple of additional setting that could be changed and are basically the editor's choice.
Some of these entries don't have a counterpart in NPC ships, and some are deliberately lower than in player ships.

Entry Old Value New Value
HOLD 24 (probably something like 10 or 12?)
MAX_ENGINE_RANK 4 (probably keep)
MAX_SHIELD_RANK 4 (probably keep)
MAX_CARGO_RANK 3 (probably 1, it's no transport ship)
ACCELERATION 120.0 (choose)
HULL_MULT 1.5 (1.0 = LIGHT, 1.25 = MEDIUM, 1.5 = HEAVY)
CORE_HEALTH 550.0 (choose)
MASS 80.0 (choose)

See section 8.3 for an overview of all the original player ships and their properties, which could help you with these decisions.

We also need to copy the WEAPON_BANK and MISSILE_BANK entries from the tags section (for now).

The original entries:

      tags = {
        {    --SHIP[1]
          n="WEAPON_BANK",
          vars = {
            { n="BANK", t="INTEGER", v=0 },
          }
        }, { --SHIP[2]
          n="WEAPON_BANK",
          vars = {
            { n="BANK", t="INTEGER", v=1 },
          }
        }, { --SHIP[3]
          n="WEAPON_BANK",
          vars = {
            { n="BANK", t="INTEGER", v=2 },
          }
        }, { --SHIP[4]
          n="WEAPON_BANK",
          vars = {
            { n="BANK", t="INTEGER", v=3 },
          }
        }, { --SHIP[5]
          n="MISSILE_BANK",
          vars = {
            { n="BANK", t="INTEGER", v=8 },
          }
        }, { --SHIP[6]
          n="MISSILE_BANK",
          vars = {
            { n="BANK", t="INTEGER", v=9 },
          }
        }, { --SHIP[7]

Replace that with:

      tags = {
        {    --SHIP[1]
          n="WEAPON_BANK",
          vars = {
            { n="BANK", t="INTEGER", v=0 },
          }
        }, { --SHIP[2]
          n="WEAPON_BANK",
          vars = {
            { n="BANK", t="INTEGER", v=1 },
          }
        }, { --SHIP[3]
          n="MISSILE_BANK",
          vars = {
            { n="BANK", t="INTEGER", v=3 },
          }
        }, { --SHIP[4]
          n="MISSILE_BANK",
          vars = {
            { n="BANK", t="INTEGER", v=4 },
          }
        }, { --SHIP[5]

1_1-15_ZANDT_PLAYER.DAT.lua_Weapons_Missiles.jpg

Here we can already see that only two weapon hardpoints are defined for the ship, although it has a total of 6 guns according to the wiki page. This means that multiple weapons are grouped into a single slot, which we will need to break up. But more on that later.

We also see that the hardpoint number for missiles is 3 and 4, which will not work for a player ship either. We will also need to change this, but that also requires editing the .LAYOUT file, so we postpone it for now.

There's one more entry that we need to remove in this file. The player ships have a "weathering" effect overlay, which means that it looks damaged when it, well, has been damaged. Unfortunately the overlay file doesn't exist for NPC ships, so we need to remove this effect. Otherwise the ship will look just black if it's damaged.

We can do so by searching for the string DAMAGED_OVERLAY and commenting out the whole line (or simply remove it). So in our example the line 109:
{ n="DAMAGED_OVERLAY", t="STRING", v=16 }, --> "MEDIA/SHIPS/SHIP_SET_1/BIGCARGO_WEATHERING.DDS"
becomes this:
-- { n="DAMAGED_OVERLAY", t="STRING", v=16 }, --> "MEDIA/SHIPS/SHIP_SET_1/BIGCARGO_WEATHERING.DDS"

We simply added two -- in front of the line, which means it's a comment now and will not have any functional meaning.

1_1-15_ZANDT_PLAYER.DAT.lua_Weathering_Effect.jpg

1.2 The Component File

32_SHIPS_PLAYER_MERC_MEDIUM.WDAT.lua

Next up is the component file, which is needed to make the ship available at the Ship Dealer. This file is found in the MEDIA\COMPONENTS directory and is called 32_SHIPS.WDAT.lua, so copy and paste it into our mirrored x99_Flyable_Zandt_sp00n\MEDIA\COMPONENTS directory (which of course you just created, didn't you?). Rename the file to 32_SHIPS_PLAYER_ZANDT.WDAT.lua.

This file contains all of the originally available player ships. However, we don't want to overwrite any of the already existing ships, so we need to delete most of the content in our mod file.
Remove anything in the local L = {...} table with an index that is higher than 10, this variable should now look like this:

32_SHIPS_PLAYER_ZANDT.WDAT.lua Strings

As you can see, the size = 61 entry doesn't match the actual size of the L table variable anymore (since we deleted most of its entries). This size value needs to match the actual number of entries in that table, so count them, and you should end up with 11. Change the entry accordingly from 61 to 11.

We also need to remove all of the existing ship definitions except for one, which we will then edit.
In line 64 (after deleting all the above mentioned entries), the first entry ends, and a new one begins. Select the comma before the opening curly bracket in that line and delete everything from there up to the end of the file, except for the last three lines.

32_SHIPS_PLAYER_ZANDT.WDAT.lua Selections

You now have a single entry, and now we need to set the correct id, name, description, manufacturer, DAT file, price, class, and conversation ship identifier strings.

Like before, the string values are defined in the "L" table, while float, integer, and boolean values are directly set.

We use Zandt as the name, Steel Rats as the manufacturer, some text for the description, and "GUNSHIP" as the class.

None of these "TRANSLATE" strings are actually that important, they can be freely changed (and are also treated as translatable).

The following strings are important however, as they have an internal meaning. We need to set the path to our .DAT file we created in step 1.1 (where we didn't actually create a .dat file, but a .lua file. However this file will be converted to a .dat file later). So enter MEDIA/SHIPS/PLAYERSHIPS/ZANDT_PLAYER.DAT which will be referenced in the UNIT entry. The next entry is the reference string that will be used for the Ship Dealer. It's not necessary to use this, but we at least need to change it to something different than what is there currently, or we'll see the conversation for the Platypus, which of course we do not want. I changed it to SHIP_ZANDT.
We will add a Ship Dealer conversation later.

Entry Old Value New Value
[0] = { 1, \"Platypus\" Zandt
[1] = { 2, Gravin Starfaring Steel Rats
[2] = { 3, The Pathfinder Plus began [...] This is the description for the Zandt gunship.
[4] = { 5 ADAPTED SCOW GUNSHIP
[3] = { 4, MEDIA/SHIPS/PLAYERSHIPS/platypus.dat MEDIA/SHIPS/PLAYERSHIPS/ZANDT_PLAYER.DAT
[10] = { 11, SHIP_PLATYPUS SHIP_ZANDT

When we now scroll down to the "SHIP" entry, we can see the references to the above table. But we also need to change some values here, the most important being the "ID" entry. This id needs to be a unique value, if an id is used twice in the game, the game will crash during startup or when you try to purchase the component. I'm using 99xxxxxxx as the "namespace" for my mods, which seem to be free. For this ship, I've used 990000001.

The next value we want to change is the "PRICE", I've set it to 500, just so that we can easily buy it during testing. Feel free to use any other value.

The last value we need to change here is the "STARTING" entry. This defines if this ship should be used as the starting ship for a player, so we need to set it to false.

Entry Old Value New Value
ID 847649 990000001
PRICE 45000 500
STARTING true false

The values in the "tags" section that are labeled "AVAILABILITY" are used to define which factions have access to the ship, resp. will be selling the ship. We can leave it as is for now, we're going to take a closer look at them in Part 5.

Here's a screenshot of what the file looks like now:

32_SHIPS_PLAYER_ZANDT.WDAT.lua Final

This is the absolute minimum that you need to to convert a ship. Of course it will not be fully functional by now, but at least you could test it out now and take it for a spin, as Juno would say.

If you've installed the rgo-mod-helpers (which you should), you can simply run rgo-deploy from inside your mod directory to automatically create the .pak file and have it moved to your game's PAKS directory.

Here are some screenshots of our current state:

Zandt Ship Dealer
Zandt Equipment Bay
Zandt Launch Pad
Zandt in Space

As you can see, we could also experiment with the SCALE value a bit, to make it fit better inside the station rooms.
But that's something we're going to deal with later. Much later (in step 7.3 to be precise).

Things that still will need to be done:

  • Make the Missile Slots work
  • Split up the Hardpoint Slots
  • Make the Turrets work
  • Set the correct MFD display graphic and weapon placement
  • Set the correct VUD display graphic and weapon placement
  • Set the correct recticle active weapon dots
  • See if we need to move the cockpit camera

Step 2: Modifying the .LAYOUT

In this step we're going to modify the .LAYOUT file so that we can actually use the missile slots and the turrets slots.
We're also going to break apart the grouped weapon slots so that each weapon will have its own selectable hardpoint, both in the Ship Dealer and in the Gun selection.

2.1 Missiles

16_ZANDT_LOADOUT_PLAYER.LAYOUT.lua

This one is pretty easy.
Missiles for player ships only work if they have the hardpoint number 8, 9, 10, 11 or 12. By default NPC ships seem to have missile hardpoints 3 and 4, so we need to change this.

In our 16_ZANDT_LOADOUT_PLAYER.LAYOUT.lua file, search for MISSILE HARDPOINT, it should appear twice. Once with the HARDPOINT_NUMBER_1 entry being set 3, and once with 4.
Now all we need to do is change these values to 8 and 9 respectively.

2_1-16_ZANDT_LOADOUT_PLAYER.LAYOUT.lua Missiles

To make this work in the game, these hardpoint numbers need to match the MISSILE_BANK entries in our ship definition. So switch back to our 15_ZANDT_PLAYER.DAT.lua file and edit the MISSILE_BANK entries to also point to 8 and 9.

This should have made the missile slots available in the Equipment Bay. You could now compile the mod again with rgo-deploy and check if it works.

2.2 Turrets

16_ZANDT_LOADOUT_PLAYER.LAYOUT.lua

Turrets are pretty similar to Missiles. The difference here is that they do actually all appear in the Equipment Bay, however they are (probably) not in the correct order (Alpha, Beta, Gamma, Delta, etc).

This doesn't seem to be much of an issue at first sight, however the game has a limitation in that it cannot cycle through all of the turrets if there's a "gap" between the turret numbering. So if our ship for example goes from the Alpha Turret directly to the Eta and Nu Turret, like our Zandt does, we won't be able to switch to these turrets during flight.

Another limitation is that only the first 5 turrets will be selectable during flight, i.e. those with a HARDPOINT_NUMBER_1 value of 1 (see below).
The other turrets, with a HARDPOINT_NUMBER_1 value of 2 or 3 will still show up in the Equipment Bay, but you will not be able to manually control them.

The non-selectable turrets will still work with auto-fire, but you cannot manually control them. So if you actually wanted to add bot-turrets, let's say for a big freighter with multiple automated turrets, assigning them to the "second row" of turrets (HARDPOINT_NUMBER_1 value of 2) would be a way to achieve this.

2_2-Zandt Turrets before

In total there are 18 possible turret slots, and they are defined by a combination of the HARDPOINT_NUMBER_1 and HARDPOINT_NUMBER_2 property. Here's a list:

HARDPOINT_NUMBER_1 HARDPOINT_NUMBER_2 # Turret
101ALPHA Turret
112BETA Turret
123GAMMA Turret
134DELTA Turret
145EPSILON Turret
156ZETA Turret
207ETA Turret
218THETA Turret
229IOTA Turret
2310KAPPA Turret
2411LAMBDA Turret
2512MU Turret
3013NU Turret
3114XI Turret
3215OMICRON Turret
3316PI Turret
3417RHO Turret
3518SIGMA Turret

So you can see that the first three turrets would need to have their HARDPOINT_NUMBER_1 value set to 1 and their HARDPOINT_NUMBER_2 value to 0, 1, and 2.

So when we look in our 16_ZANDT_LOADOUT_PLAYER.LAYOUT.lua file, and search for CONTROLLED TURRET, we find three instances, however each of them only has the HARDPOINT_NUMBER_1 value defined, the HARDPOINT_NUMBER_2 is completely missing.
Which means two things: we will need to change the HARDPOINT_NUMBER_1 value and we will need to add the HARDPOINT_NUMBER_2 entry.

The reason why these turrets still show up in the game is because a missing HARDPOINT_NUMBER_2 entry just counts as "0".

Here's a before and after image:
2_2-16_ZANDT_LOADOUT_PLAYER.LAYOUT.lua Turrets before and after

As you can see, we've changed the HARDPOINT_NUMBER_1 value from 2 to 1 and added a new entry:

[6] = {
    ["HARDPOINT_NUMBER_2"] = 1,
},

As the HARDPOINT_NUMBER_1 value before was 2, we treat this as the second turret (Beta), although it appeared as the first entry in the lua file. Of course you could also treat it as the first turret (Alpha), but I wanted to stick to the original ordering.
The mounting locations in the .layout/.lua files don't necessarily appear in the order in that they're actually defined, and only the definition is important, not the actual location in the file.

We'll do the same change for the next two turrets:
2_2-16_ZANDT_LOADOUT_PLAYER.LAYOUT.lua Turrets before and after
2_2-16_ZANDT_LOADOUT_PLAYER.LAYOUT.lua Turrets before and after

All turrets entries have now been modified, and have been assigned to the Alpha (1 + 0), Beta (1 + 1), and Gamma (1 + 2) locations.

For the Alpha turret (the last entry in the file) we actually wouldn't have needed to add the HARDPOINT_NUMBER_2 entry, as a missing entry already is interpreted as 0. We still added it though, just for clarity.

Here's a list of the changes in text form:

Entry Old Value New Value
ENTRY [5]
["name"] = "LeftTurret"
[5] = {
    ["HARDPOINT_NUMBER_1"] = 2,
},
[5] = {
    ["HARDPOINT_NUMBER_1"] = 1,
},
[6] = {
    ["HARDPOINT_NUMBER_2"] = 1,
},
ENTRY [10]
["name"] = "RightTurret"
[5] = {
    ["HARDPOINT_NUMBER_1"] = 3,
},
[5] = {
    ["HARDPOINT_NUMBER_1"] = 1,
},
[6] = {
    ["HARDPOINT_NUMBER_2"] = 2,
},
ENTRY [11]
["name"] = "BotTurret"
[5] = {
    ["HARDPOINT_NUMBER_1"] = 1,
},
[5] = {
    ["HARDPOINT_NUMBER_1"] = 1,
},
[6] = {
    ["HARDPOINT_NUMBER_2"] = 0,
},

If we now compile the mod and switch back into the game, we should see the changes.
2_2-Zandt Turrets after

2.3 Weapons (Guns)

16_ZANDT_LOADOUT_PLAYER.LAYOUT.lua

It's now time to split up the weapon (gun) groups. For NPC ships with more than around 3 weapons, multiple individual weapon hardpoints are grouped together, so that instead of equipping one gun per hardpoint, you're equipping two, three, or even four of the same guns for a single weapon slot.
Nominally our Zandt has six weapon hardpoints, but in the Equipment Bay we can only see two of them: HARDPOINT A and HARDPOINT B

2_3-Zandt Weapons before

Weapons are pretty much the same as missiles and turrets. They need a HARDPOINT_NUMBER_1 and a HARDPOINT_NUMBER_2 entry, and you can have a maximum of 8 weapon slots (anything after that will be treated as a missile slot, as explained before).

Here's a breakdown of the weapon and missile slots:

HARDPOINT_NUMBER_1 HARDPOINT_NUMBER_2 Type In-Game Slot
01WeaponHardpoint A
11WeaponHardpoint B
21WeaponHardpoint C
31WeaponHardpoint D
41WeaponHardpoint E
51WeaponHardpoint F
61WeaponHardpoint G
71WeaponHardpoint H
81MissileLauncher A
91MissileLauncher B
101MissileLauncher C
111MissileLauncher D
121MissileLauncher E

As you can see, the only difference is the value of the HARDPOINT_NUMBER_1 entry, whereas the HARDPOINT_NUMBER_2 value is always set to 1.

When we now look through our 16_ZANDT_LOADOUT_PLAYER.LAYOUT.lua file and search for "HARDPOINT" (the quotes are important here, otherwise you'll find unrelated entries), you'll find four entries that have a HARDPOINT_NUMBER_2 value of 1 and two entries that have a HARDPOINT_NUMBER_1 value of 1 & a HARDPOINT_NUMBER_2 value of 1.
Which means we have two groups, one with four guns, and one with two guns (where the group with only the HARDPOINT_NUMBER_2 value present means that the missing HARDPOINT_NUMBER_1 value is interpreted as 0).
0 + 1 and 1 + 1 means that we should see Hardpoint A and Hardpoint B, what is indeed the case.

Also note the weapon groups have a name of bk0 and bk1 (and so on for each group). You can change that name, but you don't need to, it has no functional meaning.

We're now going to break up these groups and define a dedicated hardpoint for each of these entries.
We'll start with the group where already both the HARDPOINT_NUMBER_1 and the HARDPOINT_NUMBER_2 entries are present, which is Hardpoint B in our game (1 + 1, see the table above). There are two guns in this group and four in the other, and since this group represents Hardpoint B, we're going to assign the Hardpoints E and F to these, which are represented by the HARDPOINT_NUMBER_1 values of 4 and 5.

The reason we're not starting with the other group is that if we'd first change the group for Hardpoint A, we'd suddenly have overlapping entries, as Hardpoint B is already defined (that's the one we're going to change now). So it's better if we start from the back with the last group to make space for the changes to come.

We may later find that the order of the weapon slots is not optimal, i.e. they jump from one side to the other and back when cycling through the weapons. So we may need to change it later, but for now we're just trying to break the groups apart.

Before and after images:
2_3-16_ZANDT_LOADOUT_PLAYER.LAYOUT.lua Weapons before and after
2_3-16_ZANDT_LOADOUT_PLAYER.LAYOUT.lua Weapons before and after

We can now do the same for the other group with its four entries. Do note however that here we need to add the HARDPOINT_NUMBER_1 entry, which is missing so far. We add it before the already existing HARDPOINT_NUMBER_2 entry and adjust the index key in the square brackets accordingly.
We'll add the HARDPOINT_NUMBER_1 values 0, 1, 2 and 3 for this group.

2_3-16_ZANDT_LOADOUT_PLAYER.LAYOUT.lua Weapons before and after
2_3-16_ZANDT_LOADOUT_PLAYER.LAYOUT.lua Weapons before and after
2_3-16_ZANDT_LOADOUT_PLAYER.LAYOUT.lua Weapons before and after
2_3-16_ZANDT_LOADOUT_PLAYER.LAYOUT.lua Weapons before and after

Here are the changes in text form.

Entry Old Value New Value
ENTRY [17] [4]
["name"] = "bk1"
[4] = {
    ["HARDPOINT_NUMBER_1"] = 1,
},
[5] = {
    ["HARDPOINT_NUMBER_2"] = 1,
},
[4] = {
    ["HARDPOINT_NUMBER_1"] = 4,
},
[5] = {
    ["HARDPOINT_NUMBER_2"] = 1,
},
ENTRY [17] [5]
["name"] = "bk1"
[4] = {
    ["HARDPOINT_NUMBER_1"] = 1,
},
[5] = {
    ["HARDPOINT_NUMBER_2"] = 1,
},
[4] = {
    ["HARDPOINT_NUMBER_1"] = 5,
},
[5] = {
    ["HARDPOINT_NUMBER_2"] = 1,
},
ENTRY [17] [1]
["name"] = "bk0"
[4] = {
    ["HARDPOINT_NUMBER_2"] = 1,
},
[4] = {
    ["HARDPOINT_NUMBER_1"] = 0,
},
[5] = {
    ["HARDPOINT_NUMBER_2"] = 1,
},
ENTRY [17] [2]
["name"] = "bk0"
[4] = {
    ["HARDPOINT_NUMBER_2"] = 1,
},
[4] = {
    ["HARDPOINT_NUMBER_1"] = 1,
},
[5] = {
    ["HARDPOINT_NUMBER_2"] = 1,
},
ENTRY [17] [3]
["name"] = "bk0"
[4] = {
    ["HARDPOINT_NUMBER_2"] = 1,
},
[4] = {
    ["HARDPOINT_NUMBER_1"] = 2,
},
[5] = {
    ["HARDPOINT_NUMBER_2"] = 1,
},
ENTRY [17] [6]
["name"] = "bk0"
[4] = {
    ["HARDPOINT_NUMBER_2"] = 1,
},
[4] = {
    ["HARDPOINT_NUMBER_1"] = 3,
},
[5] = {
    ["HARDPOINT_NUMBER_2"] = 1,
},

Here's a composite image of all the weapon hardpoints. As you can see, it's probably not the most intuitive order now. A more "natural" order might be A - D - B - C - E - F for example.
Or going simply from left to right with E - A - B - D - C - F. That's totally up to you and what seems intuitive to you.
We'll also have to check our cockpit HUD, MFD and VUD display.

2_3-Zandt Weapons Slots Composite Image

Part 3: The Cockpit

It's time we take our new ship for a spin!
So compile the mod and go into the game. Buy the ship if you haven't done so already, and equip a different weapon to each weapon hardpoint, and also equip the missile launchers and all the turrets.
We want to test the weapon assignment in the game while we're also checking out the cockpit itself.

3_0-Zandt Initial Cockpit Firing Guns

When we fire our guns, we notice that the cockpit is not centered, despite our location that appears to be centerd when viewed from the 3rd person view. So maybe it's time to use a different cockpit setting, that of a fighter probably.

3.1 Changing a Cockpit

The used cockpit is defined in the 15_ZANDT_PLAYER.DAT.lua file. So open it up and scroll to the top, where you should find these entries:

3_1-15_ZANDT_PLAYER.DAT.lua_Selections.jpg

[10] = {   11, "MEDIA/SHIPS/COCKPIT_SET_1/cockpit_durston_low.layout" },
[11] = {   12, "MEDIA/SHIPS/COCKPIT_SET_1/cockpit_durston.layout" },
...
[18] = {   19, "MEDIA/UI/MFDBIGCARGO.DAT" },
[19] = {   20, "MEDIA/UI/HUDBIGCARGO.DAT" },
[20] = {   21, "HUD_BIGCARGO" },

The first two files define which cockpit we're using for our ship, and the lower three the screens for our cockpit. Let's change them to something different.
When we scroll through our MEDIA\SHIPS\PLAYERSHIPS directory in our extracted files, we see all the player ships.
Let's see which cockpit the Blood Eagle uses.

So open the 15_BLOODEAGLE.DAT.lua file, and we see that it uses these files instead:

[10] = {   11, "MEDIA/SHIPS/COCKPIT_SET_1/cockpit_mediumb_low.layout" },
[11] = {   12, "MEDIA/SHIPS/COCKPIT_SET_1/cockpit_mediumb.layout" },
...
[17] = {   18, "MEDIA/UI/MFDMEDFIGHTERB.DAT" },
...
[19] = {   20, "MEDIA/UI/HUDMEDFIGHTERB.DAT" },
...
[23] = {   24, "HUD_COYOTE" },

So we're going to ise these files as well.
At this point it's important to not just copy the whole entries, instead we're only going to copy the strings themselves into our file.

Entry Old Value New Value
[10] MEDIA/SHIPS/COCKPIT_SET_1/cockpit_durston_low.layout MEDIA/SHIPS/COCKPIT_SET_1/cockpit_mediumb_low.layout
[11] MEDIA/SHIPS/COCKPIT_SET_1/cockpit_durston.layout MEDIA/SHIPS/COCKPIT_SET_1/cockpit_mediumb.layout
[18] MEDIA/UI/MFDBIGCARGO.DAT MEDIA/UI/MFDMEDFIGHTERB.DAT
[19] MEDIA/UI/HUDBIGCARGO.DAT MEDIA/UI/HUDMEDFIGHTERB.DAT
[20] HUD_BIGCARGO HUD_COYOTE

Be aware that we'll always have to change these entries in tandem, otherwise the displays might not work correctly (wrong position, cut off, etc).
Also I don't know exactly for what the _low file is being used, maybe for low resolutions. I'm going to assume so, and I'm not going to bother with it from here on, instead I will only describe the changes for the "regular" cockpit file (i.e. COCKPIT_MEDIUMB.LAYOUT).

Firing another test shot with the new cockpit:

3_1-Zandt_BloodEagle_Cockpit_Fire_Guns.jpg

Yeah, that looks better. Although still not optimal.

There are still a couple of things to fine tune:

  • We can see only 4 weapons in our displays, although we have 6 of them
  • Also we only see one missile launcher instead of 2
  • The recticle also only shows 4 weapon "dots" (fun fact: I didn't even know these were a thing before I started modding)
  • The ship outline in the displays doesn't match the one we're flying
  • It seems our cockpit is too "low", all the gun fire should actually apear below our cockpit

3.2 Changing the Vertical Position of our Cockpit

This step is kind of optional and certainly doesn't need to be done for every ship. But here it seems to be worthwile, since the guns are a bit irritating when being fired, and the cockpit position doesn't match the one we'd expect.

So, as we're now going to customize the cockpit, we need to copy and rename the cockpit file(s) that we have changed to in the previos step.
As always, this requires mirroring the directory structure of the original files. So we need to create a new directory, D:\Games\RGO\_MODS\x99_Flyable_Zandt\LUA\MEDIA\SHIPS\COCKPIT_SET_1, and copy the relevant file there, which is:
16_COCKPIT_MEDIUMB.LAYOUT.lua
Rename the file to 16_COCKPIT_ZANDT.LAYOUT.lua, and also don't forget to change our entry in 15_ZANDT_PLAYER.DAT.lua to point to this new file instead.

Entry Old Value New Value
[11] MEDIA/SHIPS/COCKPIT_SET_1/cockpit_durston.layout MEDIA/SHIPS/COCKPIT_SET_1/COCKPIT_ZANDT.LAYOUT

(Theoretically we would also need to do all this for 16_COCKPIT_MEDIUMB_LOW.LAYOUT.lua as well, but as I've said, I'm not going to bother with that file in this tutorial. Pesky low graphic users!)

As with most cockpit stuff, this is kind of a PITA. We're going to need to change a lot of values here.

First, we need to find the entry where the model file (MDL) for the cockpit graphics itself is being defined. In our case, this is ["MDL"] = "MEDIA/SHIPS/COCKPIT_SET_1/COCKPIT_MEDIUMFIGHTERB.MDL", which is found in entry 22.
Then, we have to add a COORDINATES property to this entry, so that we can actually move it. Most other elements already have this entry, but this one does not. So we need to add the entry and set the Y-value to 5.

3_2-16_COCKPIT_ZANDT.LAYOUT.lua_adding_coordinates_entry.jpg

Then begins the fun part. We have to modify a lot of the entries' Y value to their current value + 5 to match this shift upwards.
There doesn't seem to be that one singly property that controls the whole cockpit, they're all individual pieces that must be tied together. At least I have found no other way, I'd be really happy if anyone found a simpler method!

These are the entries where the Y value in their COORDINATES property needs to be modified, roughly sorted by importance:

EntryComment
COCKPIT CAMERAThis moves the cockpit camera upwards so that it's back in line with the cockpit model
LightsYes, all 21 of them. This makes your more or less important buttons/text light up
GAME_PILOTThis moves the pilot's body up, so that you can see the hands pressing buttons, etc
GlassDistortionThis is the slight distortion of the cockpit glass
CrackedGlassDistortionThis is the distortion when the cockpit glass is cracked
CrackedGlassThis is the cracked glass graphic itself
Entries with ["DDS_1"] = "media/textures/damage/shipdamageI think these are the small explosions when your ship is being damaged
GLASS_PARTICLESNot entirely sure, maybe some glass particles when it's cracking?
Entries with "flair" or "postcard"If you're a fan of the "flair" stuff, you're going to need to adjust these values as well

There are more entries in the file, for which I have no idea what they're doing or if they need to be changed.

Which means in the end I just changed every single COORDINATES property to Y + 5 in that file, but you can certainly exclude the "flair" and "postcard" entries if you don't care about them.
(This section may change in the future once I or somebody else has figured out what the other entries do.)

As we can see, now all of our guns fire beneath our cockpit:

3_2-Zandt_Cockpit_Moved.jpg

3.3 Changing the Ship Image in the Displays

This step is kind of optional as well and could be skipped. But we want our cockpit to actually display the ship we're flying in, don't we?

To see which files we need to change, we need to take another look in our 15_ZANDT_PLAYER.DAT.lua file.
There we can see that the entries with the value MFD and HUD point to the string entries 18 and 19, which, when we scroll up, point to:

[18] = {   19, "MEDIA/UI/MFDMEDFIGHTERB.DAT" },
[19] = {   20, "MEDIA/UI/HUDMEDFIGHTERB.DAT" },

So these are the files we're going to need to edit our displays.

3_3-15_ZANDT_PLAYER.DAT.lua_MFD_HUD.jpg

Also, remember that anything behind a "--" will count as a comment, so the indications you see in the image that point to MFDBIGCARGO.DAT and HUDBIGCARGO.DAT are just exactly that: an indication, but they have no functional meaning here.
Eventually we may opt to change the comments as well to point to the actual, updated files, just for clarity. That's up to you. I'd advise to do so, but first we have to change their name anyway.

So go ahead and copy these files to our new x99_Flyable_Zandt\LUA\MEDIA\UI directory, which we need to create.
Rename the files to 15_MFD_ZANDT.DAT.lua and 15_HUD_ZANDT.DAT.lua (yes, I added an underscore there, it's fine), and change the strings in the 15_ZANDT_PLAYER.DAT.lua to point to these files instead.

Entry Old Value New Value
[18]
MEDIA/UI/MFDMEDFIGHTERB.DAT MEDIA/UI/MFD_ZANDT.DAT
[19]
MEDIA/UI/HUDMEDFIGHTERB.DAT MEDIA/UI/HUD_ZANDT.DAT

3.3.1 The Displays File

15_MFD_ZANDT.DAT.lua

Now things become a bit messy, since the file is so big.

Search for the string MFDWEAPONS in the file, and you should find two ocurrences. The first being the actual string, and the second one the entry where this string is used:

3_3_1-15_MFD_ZANDT.DAT.lua_MFDWEAPONS.jpg

We can see that it points to an "IMAGE" with the value 53, which seems to be MEDFIGHTERB_VDU.
And indeed, when we scroll back up and look at the entry with the key 53 in our strings, we find that string.

3_3-15_ZANDT_PLAYER.DAT.lua_MEDFIGHTERB_VDU.jpg

So this is the image that is being used for our VDU (the shield display). But it's a string and not a file location, so we need to search for the string in our extracted and converted files.
In our case, we can find the definition for MEDFIGHTERB_VDU in the file 12_HUDIMAGES_MEDFIGHTERB.IMAGESET.lua inside the MEDIA\UI\TEXTURESHEETS\ directory.

.IMAGESET files are defining the images of the coresponding .DDS files with the same name, and if we open 3_HUDIMAGES_MEDFIGHTERB.DDS in the same directory, we can see a bunch of images (an image "set").

IrfanView with plugins can open and display .DDS files, but it cannot edit them, so it's good for quickly viewing the file, but for editing you need another program (see Requirements).

3_3_1-3_HUDIMAGES_MEDFIGHTERB.DDS.jpg

On the right you can see the two images we want to replace (I've highlighted them).
The upper one is the one we've searched for, and if we open up 12_HUDIMAGES_MEDFIGHTERB.IMAGESET.lua, we see the definition for the MEDFIGHTERB_VDU image:

3_3_1-12_HUDIMAGES_MEDFIGHTERB.IMAGESET.lua.jpg

And right below it we can also see the definition for the other image we want to replace, apparently its internal name is medfighterb_status.
And indeed, if we search for this string back in our 15_MFD_ZANDT.DAT.lua, we do find this string as well:

3_3-15_ZANDT_PLAYER.DAT.lua_MEDFIGHTERB_STATUS.jpg

It seems to be connected to HARDPOINTs, which is exactly what we want. Another way to find this second internal image name would've been to search for HARDPOINT in the 15_MFD_ZANDT.DAT.lua file, which would've brought us eventually to this entry as well.
Note that the other image, MEDFIGHTERB_VDU, also has hardpoint entries following it, but they're called VDUHARDPOINT_x there (instead of only HARDPOINT_x).
Later, in step 3.4, we will need to adjust these hardpoints for both image entries, but for now, we're just trying to replace the images themselves.

So now that we have found our images to replace, it's time to create their replacements.
This is where your image editing skills come into play, there's no way around this I'm afraid.

We now need to create a new .DDS file that will contain our changed images.

3.3.2 Creating a DDS and IMAGESET file

Since apparently the game engine can't use two different imagesets for one ship, we're going to need to make a full copy of the 12_HUDIMAGES_MEDFIGHTERB.IMAGESET.lua and 3_HUDIMAGES_MEDFIGHTERB.DDS file.

Copy both files into the x99_Flyable_Zandt\LUA\MEDIA\UI\TEXTURESHEETS mod directory, and rename them 12_HUDIMAGES_ZANDT.IMAGESET.lua resp. 3_HUDIMAGES_ZANDT.DDS.

Open the 15_MFD_ZANDT.DAT.lua file, and do a mass search & replace in this file.
Search for MEDFIGHTERB and replace it with ZANDT.

12_HUDIMAGES_ZANDT.IMAGESET.lua

Then do the same for the 12_HUDIMAGES_ZANDT.IMAGESET.lua file, but this time use the lowercase strings: replace medfighterb with zandt.
(Yes, capitalization is all over the place in these files...)

There's one adjustment we need to make in this IMAGESET file.
The content variable has an n property, which was originally set to IMAGESET_HUDIMAGES_MEDFIGHTERB and should now, after replacing the string, read IMAGESET_HUDIMAGES_zandt.

There issue here is a bit complicated, basically the imageset file needs to have its own id. The id was "masked" behind the original string IMAGESET_HUDIMAGES_MEDFIGHTERB, which, when converting the file back to a .dat file, is internally translated into the id value 253179603.
We need a new id for this file, and since I've chosen to the 99xxxxxxx "namespace" for my mod ids, and since the ship itself has the id 990000001, the imageset receives the id 990000002.
We enter this as n="$990000002" for the content variable (the $ denotes that an id is following for the lua2dat converter).

3_3_2-12_HUDIMAGES_ZANDT.IMAGESET.lua.ID.value.jpg

Since we only want to replace two images, that's basically it for now for these two files.

3_HUDIMAGES_ZANDT.DDS

We now need to replace the images themselves. Open the 3_HUDIMAGES_ZANDT.DDS with your favorite image editor program that supports saving to DDS.

The way I did this is that for the "shield" image (the lower one, MEDFIGHTERB_STATUS) replacement, is that I looked through the 12_VDU.IMAGESET.lua and 12_VDU.IMAGESET.lua files, looking for the target display of the Zandt fighter, which, as we recall, was internally originally named PIRATE3GUNSHIP.

We find this target display image already in the first of the VDU imageset files, 12_VDU.IMAGESET.lua, which means we can now open up the corresponding 3_VDU.DDS file and copy our image from there.

3_3_2-12_VDU.IMAGESET.lua_pirate3gunship.jpg

It's actually the one of the two in the bottom left corner (the other one being the "damaged" state).

3_3_1-3_VDU.DDS_Zandt.jpg

Now begins the fun part (part 1), where you need to isolate the ship and remove everything on the outside, so that only the ship itself remains.
Then you open the 3_HUDIMAGES_MEDFIGHTERB.DDS file and try to fit your isolated image inside the shield section. You may need to rotate, skew, stretch, etc a bit to make it a good fit.

If you have enough time on your hands, you could also adjust the form of the hull and shield indicators to create a much better fit, but so far I have shied away from doing this due to it requiring so much effort.

If you're successful, it should look something like this:

3_3_1-3_HUDIMAGES_MEDFIGHTERB.DDS_Zandt_replaced_Shields.jpg

Good enough.
We want to leave some space to the top for our weapon icons to display and not overlap the hull indicators.

For replacing the other image, we need to create an outline of our ship.
There is no easy way to do this, and there are no images to recycle. I've decided to create a vector path outline of the ship, with the target image as the model. There might be better ways, I haven't found one.

Our final new imageset (cut off on the bottom):

3_3_2-3_HUDIMAGES_ZANDT.DDS_final.jpg

Yeah, I can live with that.

We need to save it as a DDS file now, this is where the plugins or special editing tools come in.
Save it as 3_HUDIMAGES_ZANDT.DDS in our x99_Flyable_Zandt\LUA\MEDIA\UI\TEXTURESHEETS mod directory.

That should be it.
Save the file, compile the mod with rgo-deploy, and test it. We should now see the new images in our cockpit!

3_3_2-ZANDT_Cockpit_MFD_Status.jpg

As you can see, the weapon hardpoints now don't fit anymore. And they're still only 4 instead of 6 (and 1 missile launcher instead of 2).
We're going to fix this next.

3.4 Fixing the Amount and Position of the Weapons in the Displays

15_MFD_ZANDT.DAT.lua

We need to think about how our general layout for the weapons should look like.
I've decided for the following approach: inside to outside, left to right. This would give us the following arrangement, as viewed from the front:

3_4-Ship_Weapon_Positioning_Layout.jpg

So we need to change our hardpoint numbering for the ship as well, but in this step, we're going to change the displayed weapons in the MFD and shield status first.

For this we're going back to our 15_MFD_ZANDT.DAT.lua file. Remember those HARDPOINT_ and VDUHARDPOINT_ entries? We're going to change them now.

The first thing we do here is to add three more hardpoints, two guns and one missile hardpoint. The strings are in the L table as always:

3_4-15_MFD_ZANDT.DAT.lua_HARDOINTS.jpg

We're going to add HARDPOINT_4 and HARDPOINT_5 for the guns, and HARDPOINT_9 for the missile launcher, so that they can be displayed in the MFD display.
Accordingly we add VDUHARDPOINT_4, VDUHARDPOINT_5, and VDUHARDPOINT_9 for the display in the VDU/Shield Status.

So we go to the very end of the L table, right after [266] = { 267, "WAYPOINTREDSMALL" },, but before the closing }, and there we add the following entries:

  [267] = {  268, "HARDPOINT_4" },
  [268] = {  269, "HARDPOINT_5" },
  [269] = {  270, "HARDPOINT_9" },
  [270] = {  271, "VDUHARDPOINT_4" },
  [271] = {  272, "VDUHARDPOINT_5" },
  [272] = {  273, "VDUHARDPOINT_9" },

3_4-15_MFD_ZANDT.DAT.lua_HARDOINTS_STRINGS_ADDED.jpg

Remember that weapons/guns go from hardpoint 0 to 7 for a maximum of 8 slots, and that missiles go from 8 to 11, for a maximum of 5 missile launchers. This is why we gave our second missile launcher the number 9, the first, already existing one, has the number 8.

We also need to adjust the size property of our L table now (something I like to forget), so change it from 268 to...
wait a minute, when scrolling back up, we see another entry at the very top:
[4294967295] = { 268, "" },

3_4-15_MFD_ZANDT.DAT.lua_Another_Entry_before.jpg

So that means that there's already an out-of-line entry "occupying" the key 268 that we have now assigned to our new [267] = { 268, "HARDPOINT_4" }, entry.
I don't know why this value is so out of line, but to fix this, we simply change it's key value of 268 to 274.

Which then is also our new value for the size property, so change this also from 268 to 274:

3_4-15_MFD_ZANDT.DAT.lua_Another_Entry_after.jpg

Entry Old Value New Value
size
268, 274,
[4294967295]
{ 268, "" }, { 274, "" },
[267]
{ 268, "HARDPOINT_4" },
[268]
{ 269, "HARDPOINT_5" },
[269]
{ 270, "HARDPOINT_9" },
[270]
{ 271, "VDUHARDPOINT_4" },
[271]
{ 272, "VDUHARDPOINT_5" },
[272]
{ 273, "VDUHARDPOINT_9" },

Now we're going to add the hardpoints to the actual displays. Search in the file for HARDPOINT_, you'll eventually reach the entry for VDUHARDPOINT_8, which is fine, let's start here.
That's the entry for the first missile launcher in the weapon selection display (the left one / MFD).

Let's just copy the whole entry and paste it below. After doing so, change the

{ n="NAME", t="STRING", v=54 }, --> "VDUHARDPOINT_8"

entry to

{ n="NAME", t="STRING", v=269 }, --> "VDUHARDPOINT_9"

to point to our new missile hardpoint.

Do the same three times for the new gun hardpoints with the VDUHARDPOINT_3 entry, pointing to 267 and 268 respectively.
Don't forget the comma!

We can also already prepare the positioning of our hardpoints. I like to iterate from 0 upwards for the X and Y values to get a feeling where I would need to position them.

A graphical interface with drag & drop would be really helpful here, but we don't have it, so we need to change the values, compile the mod, load up the game, check the positioning, quit the game, change the values, compile the mod, load up the game, check the positioning, ...

Before:

  tags = {
    {    --CONTAINER[1]
      n="SPRITE",
      vars = {
        { n="NAME", t="STRING", v=54 }, --> "VDUHARDPOINT_8"
        { n="WIDTH", t="INTEGER", v=42 },
        { n="HEIGHT", t="INTEGER", v=51 },
        { n="X", t="INTEGER", v=123 },
        { n="Y", t="INTEGER", v=152 },
        { n="IMAGE", t="STRING", v=55 }, --> "VDUWEAPON_DFLAUNCHER"
        { n="BATCH", t="INTEGER", v=3 },
      }
    }, { --CONTAINER[2]
      n="SPRITE",
      vars = {
        { n="NAME", t="STRING", v=56 }, --> "VDUHARDPOINT_0"
        { n="WIDTH", t="INTEGER", v=22 },
        { n="HEIGHT", t="INTEGER", v=84 },
        { n="X", t="INTEGER", v=39 },
        { n="Y", t="INTEGER", v=75 },
        { n="IMAGE", t="STRING", v=57 }, --> "VDUWEAPON_LASER"
        { n="BATCH", t="INTEGER", v=3 },
      }
    }, { --CONTAINER[3]
      n="SPRITE",
      vars = {
        { n="NAME", t="STRING", v=58 }, --> "VDUHARDPOINT_1"
        { n="WIDTH", t="INTEGER", v=22 },
        { n="HEIGHT", t="INTEGER", v=84 },
        { n="X", t="INTEGER", v=227 },
        { n="Y", t="INTEGER", v=75 },
        { n="IMAGE", t="STRING", v=57 }, --> "VDUWEAPON_LASER"
        { n="BATCH", t="INTEGER", v=3 },
      }
    }, { --CONTAINER[4]
      n="SPRITE",
      vars = {
        { n="NAME", t="STRING", v=59 }, --> "VDUHARDPOINT_2"
        { n="WIDTH", t="INTEGER", v=22 },
        { n="HEIGHT", t="INTEGER", v=84 },
        { n="X", t="INTEGER", v=17 },
        { n="Y", t="INTEGER", v=76 },
        { n="IMAGE", t="STRING", v=57 }, --> "VDUWEAPON_LASER"
        { n="BATCH", t="INTEGER", v=3 },
      }
    }, { --CONTAINER[5]
      n="SPRITE",
      vars = {
        { n="NAME", t="STRING", v=60 }, --> "VDUHARDPOINT_3"
        { n="WIDTH", t="INTEGER", v=22 },
        { n="HEIGHT", t="INTEGER", v=84 },
        { n="X", t="INTEGER", v=249 },
        { n="Y", t="INTEGER", v=76 },
        { n="IMAGE", t="STRING", v=57 }, --> "VDUWEAPON_LASER"
        { n="BATCH", t="INTEGER", v=3 },
      }
    }
  }

After:

  tags = {
    {    -- MISSILE 1
      n="SPRITE",
      vars = {
        { n="NAME", t="STRING", v=54 }, --> "VDUHARDPOINT_8"
        { n="WIDTH", t="INTEGER", v=42 },
        { n="HEIGHT", t="INTEGER", v=51 },
        { n="X", t="INTEGER", v=100 },
        { n="Y", t="INTEGER", v=150 },
        { n="IMAGE", t="STRING", v=55 }, --> "VDUWEAPON_DFLAUNCHER"
        { n="BATCH", t="INTEGER", v=3 },
      }
    },
    {    -- MISSILE 2
      n="SPRITE",
      vars = {
        { n="NAME", t="STRING", v=269 }, --> "VDUHARDPOINT_9"
        { n="WIDTH", t="INTEGER", v=42 },
        { n="HEIGHT", t="INTEGER", v=51 },
        { n="X", t="INTEGER", v=200 },
        { n="Y", t="INTEGER", v=150 },
        { n="IMAGE", t="STRING", v=55 }, --> "VDUWEAPON_DFLAUNCHER"
        { n="BATCH", t="INTEGER", v=3 },
      }
    },
    {   -- WEAPON 1
      n="SPRITE",
      vars = {
        { n="NAME", t="STRING", v=56 }, --> "VDUHARDPOINT_0"
        { n="WIDTH", t="INTEGER", v=22 },
        { n="HEIGHT", t="INTEGER", v=84 },
        { n="X", t="INTEGER", v=0 },
        { n="Y", t="INTEGER", v=0 },
        { n="IMAGE", t="STRING", v=57 }, --> "VDUWEAPON_LASER"
        { n="BATCH", t="INTEGER", v=3 },
      }
    },
    {   -- WEAPON 2
      n="SPRITE",
      vars = {
        { n="NAME", t="STRING", v=58 }, --> "VDUHARDPOINT_1"
        { n="WIDTH", t="INTEGER", v=22 },
        { n="HEIGHT", t="INTEGER", v=84 },
        { n="X", t="INTEGER", v=50 },
        { n="Y", t="INTEGER", v=50 },
        { n="IMAGE", t="STRING", v=57 }, --> "VDUWEAPON_LASER"
        { n="BATCH", t="INTEGER", v=3 },
      }
    },
    {   -- WEAPON 3
      n="SPRITE",
      vars = {
        { n="NAME", t="STRING", v=59 }, --> "VDUHARDPOINT_2"
        { n="WIDTH", t="INTEGER", v=22 },
        { n="HEIGHT", t="INTEGER", v=84 },
        { n="X", t="INTEGER", v=100 },
        { n="Y", t="INTEGER", v=100 },
        { n="IMAGE", t="STRING", v=57 }, --> "VDUWEAPON_LASER"
        { n="BATCH", t="INTEGER", v=3 },
      }
    },
    {   -- WEAPON 4
      n="SPRITE",
      vars = {
        { n="NAME", t="STRING", v=60 }, --> "VDUHARDPOINT_3"
        { n="WIDTH", t="INTEGER", v=22 },
        { n="HEIGHT", t="INTEGER", v=84 },
        { n="X", t="INTEGER", v=150 },
        { n="Y", t="INTEGER", v=150 },
        { n="IMAGE", t="STRING", v=57 }, --> "VDUWEAPON_LASER"
        { n="BATCH", t="INTEGER", v=3 },
      }
    },
    {   -- WEAPON 5
      n="SPRITE",
      vars = {
        { n="NAME", t="STRING", v=267 }, --> "VDUHARDPOINT_4"
        { n="WIDTH", t="INTEGER", v=22 },
        { n="HEIGHT", t="INTEGER", v=84 },
        { n="X", t="INTEGER", v=200 },
        { n="Y", t="INTEGER", v=200 },
        { n="IMAGE", t="STRING", v=57 }, --> "VDUWEAPON_LASER"
        { n="BATCH", t="INTEGER", v=3 },
      }
    },
    {   -- WEAPON 6
      n="SPRITE",
      vars = {
        { n="NAME", t="STRING", v=268 }, --> "VDUHARDPOINT_5"
        { n="WIDTH", t="INTEGER", v=22 },
        { n="HEIGHT", t="INTEGER", v=84 },
        { n="X", t="INTEGER", v=250 },
        { n="Y", t="INTEGER", v=250 },
        { n="IMAGE", t="STRING", v=57 }, --> "VDUWEAPON_LASER"
        { n="BATCH", t="INTEGER", v=3 },
      }
    }
  }

I also changede the comments here, you don't need to do that, but it makes things more clear.

This is how it now looks in the game, I've markede the hardpoint numbers and coordinates:

3_4-MFD_Weapon_Positioning_1.jpg

Now begins the fun process of shuffling the positions around.
The two most inner ones should be 1 (left) and 2 (right), then followed by 3 and 4, and the two most outer should be 5 and 6.
And the missiles should fit somehwere between there as well.

Shuffle, shuffle.

3_4-MFD_Weapon_Positioning_2.jpg

Yeah, that seems about right.

These are the final coordinates:

WeaponHardpointXY
Gun 1VDUHARDPOINT_01200
Gun 2VDUHARDPOINT_11500
Gun 3VDUHARDPOINT_290 15
Gun 4VDUHARDPOINT_318015
Gun 5VDUHARDPOINT_46050
Gun 6VDUHARDPOINT_521050
Missile 1VDUHARDPOINT_880110
Missile 2VDUHARDPOINT_9170110

And this is the final code:

  tags = {
    {    -- MISSILE 1
      n="SPRITE",
      vars = {
        { n="NAME", t="STRING", v=54 }, --> "VDUHARDPOINT_8"
        { n="WIDTH", t="INTEGER", v=42 },
        { n="HEIGHT", t="INTEGER", v=51 },
        { n="X", t="INTEGER", v=80 },
        { n="Y", t="INTEGER", v=110 },
        { n="IMAGE", t="STRING", v=55 }, --> "VDUWEAPON_DFLAUNCHER"
        { n="BATCH", t="INTEGER", v=3 },
      }
    },
    {    -- MISSILE 2
      n="SPRITE",
      vars = {
        { n="NAME", t="STRING", v=269 }, --> "VDUHARDPOINT_9"
        { n="WIDTH", t="INTEGER", v=42 },
        { n="HEIGHT", t="INTEGER", v=51 },
        { n="X", t="INTEGER", v=170 },
        { n="Y", t="INTEGER", v=110 },
        { n="IMAGE", t="STRING", v=55 }, --> "VDUWEAPON_DFLAUNCHER"
        { n="BATCH", t="INTEGER", v=3 },
      }
    },
    {   -- WEAPON 1
      n="SPRITE",
      vars = {
        { n="NAME", t="STRING", v=56 }, --> "VDUHARDPOINT_0"
        { n="WIDTH", t="INTEGER", v=22 },
        { n="HEIGHT", t="INTEGER", v=84 },
        { n="X", t="INTEGER", v=120 },
        { n="Y", t="INTEGER", v=0 },
        { n="IMAGE", t="STRING", v=57 }, --> "VDUWEAPON_LASER"
        { n="BATCH", t="INTEGER", v=3 },
      }
    },
    {   -- WEAPON 2
      n="SPRITE",
      vars = {
        { n="NAME", t="STRING", v=58 }, --> "VDUHARDPOINT_1"
        { n="WIDTH", t="INTEGER", v=22 },
        { n="HEIGHT", t="INTEGER", v=84 },
        { n="X", t="INTEGER", v=150 },
        { n="Y", t="INTEGER", v=0 },
        { n="IMAGE", t="STRING", v=57 }, --> "VDUWEAPON_LASER"
        { n="BATCH", t="INTEGER", v=3 },
      }
    },
    {   -- WEAPON 3
      n="SPRITE",
      vars = {
        { n="NAME", t="STRING", v=59 }, --> "VDUHARDPOINT_2"
        { n="WIDTH", t="INTEGER", v=22 },
        { n="HEIGHT", t="INTEGER", v=84 },
        { n="X", t="INTEGER", v=90 },
        { n="Y", t="INTEGER", v=15 },
        { n="IMAGE", t="STRING", v=57 }, --> "VDUWEAPON_LASER"
        { n="BATCH", t="INTEGER", v=3 },
      }
    },
    {   -- WEAPON 4
      n="SPRITE",
      vars = {
        { n="NAME", t="STRING", v=60 }, --> "VDUHARDPOINT_3"
        { n="WIDTH", t="INTEGER", v=22 },
        { n="HEIGHT", t="INTEGER", v=84 },
        { n="X", t="INTEGER", v=180 },
        { n="Y", t="INTEGER", v=15 },
        { n="IMAGE", t="STRING", v=57 }, --> "VDUWEAPON_LASER"
        { n="BATCH", t="INTEGER", v=3 },
      }
    },
    {   -- WEAPON 5
      n="SPRITE",
      vars = {
        { n="NAME", t="STRING", v=267 }, --> "VDUHARDPOINT_4"
        { n="WIDTH", t="INTEGER", v=22 },
        { n="HEIGHT", t="INTEGER", v=84 },
        { n="X", t="INTEGER", v=60 },
        { n="Y", t="INTEGER", v=50 },
        { n="IMAGE", t="STRING", v=57 }, --> "VDUWEAPON_LASER"
        { n="BATCH", t="INTEGER", v=3 },
      }
    },
    {   -- WEAPON 6
      n="SPRITE",
      vars = {
        { n="NAME", t="STRING", v=268 }, --> "VDUHARDPOINT_5"
        { n="WIDTH", t="INTEGER", v=22 },
        { n="HEIGHT", t="INTEGER", v=84 },
        { n="X", t="INTEGER", v=210 },
        { n="Y", t="INTEGER", v=50 },
        { n="IMAGE", t="STRING", v=57 }, --> "VDUWEAPON_LASER"
        { n="BATCH", t="INTEGER", v=3 },
      }
    }
  }

We need to do the same for the HARDPOINT_ values, which appear further below.
Don't forget that we need to use HARDPOINT_ instead of VDUHARDPOINT_ here, so change the NAME entries accordingly (270, 271, and 272).

And unfortunately we cannot re-use the same coordinates here, because the are is smaller area available.
Shuffle, shuffle.

3_4-Display_Weapon_Positioning_final.jpg

That's ok!

WeaponHardpointXY
Gun 1HARDPOINT_012648
Gun 2HARDPOINT_114448
Gun 3HARDPOINT_211055
Gun 4HARDPOINT_316055
Gun 5HARDPOINT_49575
Gun 6HARDPOINT_517575
Missile 1HARDPOINT_8110110
Missile 2HARDPOINT_9145110

Before:

 tags = {
    {    --CONTAINER[1]
      n="SPRITE",
      vars = {
        { n="NAME", t="STRING", v=82 }, --> "HARDPOINT_8"
        { n="WIDTH", t="INTEGER", v=26 },
        { n="HEIGHT", t="INTEGER", v=34 },
        { n="X", t="INTEGER", v=125 },
        { n="Y", t="INTEGER", v=127 },
        { n="IMAGE", t="STRING", v=55 }, --> "VDUWEAPON_DFLAUNCHER"
        { n="BATCH", t="INTEGER", v=3 },
      }
    }, { --CONTAINER[2]
      n="SPRITE",
      vars = {
        { n="NAME", t="STRING", v=83 }, --> "HARDPOINT_0"
        { n="WIDTH", t="INTEGER", v=13 },
        { n="HEIGHT", t="INTEGER", v=50 },
        { n="X", t="INTEGER", v=84 },
        { n="Y", t="INTEGER", v=85 },
        { n="IMAGE", t="STRING", v=57 }, --> "VDUWEAPON_LASER"
        { n="BATCH", t="INTEGER", v=3 },
      }
    }, { --CONTAINER[3]
      n="SPRITE",
      vars = {
        { n="NAME", t="STRING", v=84 }, --> "HARDPOINT_1"
        { n="WIDTH", t="INTEGER", v=13 },
        { n="HEIGHT", t="INTEGER", v=50 },
        { n="X", t="INTEGER", v=179 },
        { n="Y", t="INTEGER", v=85 },
        { n="IMAGE", t="STRING", v=57 }, --> "VDUWEAPON_LASER"
        { n="BATCH", t="INTEGER", v=3 },
      }
    }, { --CONTAINER[4]
      n="SPRITE",
      vars = {
        { n="NAME", t="STRING", v=85 }, --> "HARDPOINT_2"
        { n="WIDTH", t="INTEGER", v=13 },
        { n="HEIGHT", t="INTEGER", v=50 },
        { n="X", t="INTEGER", v=71 },
        { n="Y", t="INTEGER", v=87 },
        { n="IMAGE", t="STRING", v=57 }, --> "VDUWEAPON_LASER"
        { n="BATCH", t="INTEGER", v=3 },
      }
    }, { --CONTAINER[5]
      n="SPRITE",
      vars = {
        { n="NAME", t="STRING", v=86 }, --> "HARDPOINT_3"
        { n="WIDTH", t="INTEGER", v=13 },
        { n="HEIGHT", t="INTEGER", v=50 },
        { n="X", t="INTEGER", v=192 },
        { n="Y", t="INTEGER", v=87 },
        { n="IMAGE", t="STRING", v=57 }, --> "VDUWEAPON_LASER"
        { n="BATCH", t="INTEGER", v=3 },
      }
    }
  }

After:

  tags = {
    {   -- Missile 1
      n="SPRITE",
      vars = {
        { n="NAME", t="STRING", v=82 }, --> "HARDPOINT_8"
        { n="WIDTH", t="INTEGER", v=26 },
        { n="HEIGHT", t="INTEGER", v=34 },
        { n="X", t="INTEGER", v=110 },
        { n="Y", t="INTEGER", v=110 },
        { n="IMAGE", t="STRING", v=55 }, --> "VDUWEAPON_DFLAUNCHER"
        { n="BATCH", t="INTEGER", v=3 },
      }
    },
    {   -- Missile 2
      n="SPRITE",
      vars = {
        { n="NAME", t="STRING", v=272 }, --> "HARDPOINT_9"
        { n="WIDTH", t="INTEGER", v=26 },
        { n="HEIGHT", t="INTEGER", v=34 },
        { n="X", t="INTEGER", v=145 },
        { n="Y", t="INTEGER", v=110 },
        { n="IMAGE", t="STRING", v=55 }, --> "VDUWEAPON_DFLAUNCHER"
        { n="BATCH", t="INTEGER", v=3 },
      }
    },
    {   -- Weapon 1
      n="SPRITE",
      vars = {
        { n="NAME", t="STRING", v=83 }, --> "HARDPOINT_0"
        { n="WIDTH", t="INTEGER", v=13 },
        { n="HEIGHT", t="INTEGER", v=50 },
        { n="X", t="INTEGER", v=126 },
        { n="Y", t="INTEGER", v=48 },
        { n="IMAGE", t="STRING", v=57 }, --> "VDUWEAPON_LASER"
        { n="BATCH", t="INTEGER", v=3 },
      }
    },
    {   -- Weapon 2
      n="SPRITE",
      vars = {
        { n="NAME", t="STRING", v=84 }, --> "HARDPOINT_1"
        { n="WIDTH", t="INTEGER", v=13 },
        { n="HEIGHT", t="INTEGER", v=50 },
        { n="X", t="INTEGER", v=144 },
        { n="Y", t="INTEGER", v=48 },
        { n="IMAGE", t="STRING", v=57 }, --> "VDUWEAPON_LASER"
        { n="BATCH", t="INTEGER", v=3 },
      }
    },
    {   -- Weapon 3
      n="SPRITE",
      vars = {
        { n="NAME", t="STRING", v=85 }, --> "HARDPOINT_2"
        { n="WIDTH", t="INTEGER", v=13 },
        { n="HEIGHT", t="INTEGER", v=50 },
        { n="X", t="INTEGER", v=110 },
        { n="Y", t="INTEGER", v=55 },
        { n="IMAGE", t="STRING", v=57 }, --> "VDUWEAPON_LASER"
        { n="BATCH", t="INTEGER", v=3 },
      }
    },
    {   -- Weapon 4
      n="SPRITE",
      vars = {
        { n="NAME", t="STRING", v=86 }, --> "HARDPOINT_3"
        { n="WIDTH", t="INTEGER", v=13 },
        { n="HEIGHT", t="INTEGER", v=50 },
        { n="X", t="INTEGER", v=160 },
        { n="Y", t="INTEGER", v=55 },
        { n="IMAGE", t="STRING", v=57 }, --> "VDUWEAPON_LASER"
        { n="BATCH", t="INTEGER", v=3 },
      }
    },
    {   -- Weapon 5
      n="SPRITE",
      vars = {
        { n="NAME", t="STRING", v=270 }, --> "HARDPOINT_4"
        { n="WIDTH", t="INTEGER", v=13 },
        { n="HEIGHT", t="INTEGER", v=50 },
        { n="X", t="INTEGER", v=95 },
        { n="Y", t="INTEGER", v=75 },
        { n="IMAGE", t="STRING", v=57 }, --> "VDUWEAPON_LASER"
        { n="BATCH", t="INTEGER", v=3 },
      }
    },
    {   -- Weapon 6
      n="SPRITE",
      vars = {
        { n="NAME", t="STRING", v=271 }, --> "HARDPOINT_5"
        { n="WIDTH", t="INTEGER", v=13 },
        { n="HEIGHT", t="INTEGER", v=50 },
        { n="X", t="INTEGER", v=175 },
        { n="Y", t="INTEGER", v=75 },
        { n="IMAGE", t="STRING", v=57 }, --> "VDUWEAPON_LASER"
        { n="BATCH", t="INTEGER", v=3 },
      }
    }
  }

That's it for the weapon displays.
We still need to update our weapon recticle indicators/dots and the actual mounting position of our weapons. First the indicators.

3.5 Fixing the Amount and Position of Weapon Indicators in the Recticle

This is arguably the least important step, as I didn't even know these things existed before I started modding.

Next to your targeting recticle there are little indicators ("dots"), representing the amount of your weapons that are currently activated. There are also indicators for your missile launchers, and their remaining ammo level.

3_5-Recticle-Explanation.jpg

As you can see, there are only four weapon "dots" display, although we have six on our ship. So we need to add two more.
Luckily the missiles are correct, so we won't need to anything there, but the principle would be the same.

I can see two logical ways to extend the layout here, either add a row to the top, or to the bottom.
I think I'll go with bottom, and also re-order the hardpoints, so that 1 & 2 are the bottom row, 3 & 4 the middle, and 5 & 6 the top row. This matches our "inside to outside, left to right" approach.

Let's get to it.

15_HUD_ZANDT.DAT.lua

We have already copied the 15_HUD_ZANDT.DAT.lua file to our mod directory, but haven't touched it so far. Now we will.

Right at the top we can already see the things we'll be changing: HARDPOINT_x and HARDPOINTACTIVE_x. And of course we'll need to add two more of these to our L strings table, which we'll do right away.

3_5-15_HUD_ZANDT.DAT.lua_HARDPOINTS.jpg

You should know the drill by now, add the following to the bottom of the L table:

  [60] = {   61, "HARDPOINT_4" },
  [61] = {   62, "HARDPOINTACTIVE_4" },
  [62] = {   63, "HARDPOINT_5" },
  [63] = {   64, "HARDPOINTACTIVE_5" },

And also adjust the size property to match our added entries.

Entry Old Value New Value
size
60, 64,
[60]
{ 61, "HARDPOINT_4" },
[61]
{ 62, "HARDPOINTACTIVE_4" },
[62]
{ 63, "HARDPOINT_5" },
[63]
{ 64, "HARDPOINTACTIVE_5" },

Then search for HARDPOINT_3 to find the entries we're looking for.
Select both the HARDPOINT_3 and HARDPOINTACTIVE_3 and insert it twice below, to add the two new hardpoints.

3_5-15_HUD_ZANDT.DAT.lua_HARDPOINT_3_Selection.jpg

Here's the whooole section, including the ECM hardpoint (which we won't touch) and the missiles (which we won't need to touch), before adding the new entries:

 tags = {
    {    --SPRITEANIM[1]
      n="SPRITEANIM",
      vars = {
        { n="NAME", t="STRING", v=9 }, --> "ECMHARDPOINT"
        { n="WIDTH", t="INTEGER", v=32 },
        { n="HEIGHT", t="INTEGER", v=32 },
        { n="X", t="INTEGER", v=80 },
        { n="Y", t="INTEGER", v=100 },
        { n="VERT_ALIGN", t="STRING", v=5 }, --> "TOP"
        { n="HORZ_ALIGN", t="STRING", v=6 }, --> "LEFT"
        { n="IMAGE", t="STRING", v=10 }, --> "VDUECM_"
        { n="LOOP", t="BOOL", v=false },
        { n="FRAMES", t="INTEGER", v=3 },
        { n="SPEED", t="FLOAT", v=0.0 },
        { n="BATCH", t="INTEGER", v=3 },
      }
    }, { --SPRITEANIM[2]
      n="SPRITEANIM",
      vars = {
        { n="NAME", t="STRING", v=11 }, --> "HARDPOINT_0"
        { n="WIDTH", t="INTEGER", v=32 },
        { n="HEIGHT", t="INTEGER", v=32 },
        { n="X", t="INTEGER", v=32 },
        { n="Y", t="INTEGER", v=96 },
        { n="VERT_ALIGN", t="STRING", v=5 }, --> "TOP"
        { n="HORZ_ALIGN", t="STRING", v=6 }, --> "LEFT"
        { n="IMAGE", t="STRING", v=12 }, --> "VDUHARDPOINT_"
        { n="LOOP", t="BOOL", v=false },
        { n="FRAMES", t="INTEGER", v=32 },
        { n="SPEED", t="FLOAT", v=0.0 },
        { n="BATCH", t="INTEGER", v=3 },
      }
    }, { --SPRITEANIM[3]
      n="SPRITE",
      vars = {
        { n="NAME", t="STRING", v=13 }, --> "HARDPOINTACTIVE_0"
        { n="WIDTH", t="INTEGER", v=32 },
        { n="HEIGHT", t="INTEGER", v=32 },
        { n="X", t="INTEGER", v=32 },
        { n="Y", t="INTEGER", v=96 },
        { n="VERT_ALIGN", t="STRING", v=5 }, --> "TOP"
        { n="HORZ_ALIGN", t="STRING", v=6 }, --> "LEFT"
        { n="IMAGE", t="STRING", v=2 }, --> "VDUHARDPOINT_ACTIVE"
        { n="BATCH", t="INTEGER", v=3 },
      }
    }, { --SPRITEANIM[4]
      n="SPRITEANIM",
      vars = {
        { n="NAME", t="STRING", v=14 }, --> "HARDPOINT_1"
        { n="WIDTH", t="INTEGER", v=32 },
        { n="HEIGHT", t="INTEGER", v=32 },
        { n="X", t="INTEGER", v=129 },
        { n="Y", t="INTEGER", v=96 },
        { n="VERT_ALIGN", t="STRING", v=5 }, --> "TOP"
        { n="HORZ_ALIGN", t="STRING", v=6 }, --> "LEFT"
        { n="IMAGE", t="STRING", v=12 }, --> "VDUHARDPOINT_"
        { n="LOOP", t="BOOL", v=false },
        { n="FRAMES", t="INTEGER", v=32 },
        { n="SPEED", t="FLOAT", v=0.0 },
        { n="BATCH", t="INTEGER", v=3 },
      }
    }, { --SPRITEANIM[5]
      n="SPRITE",
      vars = {
        { n="NAME", t="STRING", v=15 }, --> "HARDPOINTACTIVE_1"
        { n="WIDTH", t="INTEGER", v=32 },
        { n="HEIGHT", t="INTEGER", v=32 },
        { n="X", t="INTEGER", v=129 },
        { n="Y", t="INTEGER", v=96 },
        { n="VERT_ALIGN", t="STRING", v=5 }, --> "TOP"
        { n="HORZ_ALIGN", t="STRING", v=6 }, --> "LEFT"
        { n="IMAGE", t="STRING", v=2 }, --> "VDUHARDPOINT_ACTIVE"
        { n="BATCH", t="INTEGER", v=3 },
      }
    }, { --SPRITEANIM[6]
      n="SPRITEANIM",
      vars = {
        { n="NAME", t="STRING", v=16 }, --> "HARDPOINT_2"
        { n="WIDTH", t="INTEGER", v=32 },
        { n="HEIGHT", t="INTEGER", v=32 },
        { n="X", t="INTEGER", v=41 },
        { n="Y", t="INTEGER", v=113 },
        { n="VERT_ALIGN", t="STRING", v=5 }, --> "TOP"
        { n="HORZ_ALIGN", t="STRING", v=6 }, --> "LEFT"
        { n="IMAGE", t="STRING", v=12 }, --> "VDUHARDPOINT_"
        { n="LOOP", t="BOOL", v=false },
        { n="FRAMES", t="INTEGER", v=32 },
        { n="SPEED", t="FLOAT", v=0.0 },
        { n="BATCH", t="INTEGER", v=3 },
      }
    }, { --SPRITEANIM[7]
      n="SPRITE",
      vars = {
        { n="NAME", t="STRING", v=17 }, --> "HARDPOINTACTIVE_2"
        { n="WIDTH", t="INTEGER", v=32 },
        { n="HEIGHT", t="INTEGER", v=32 },
        { n="X", t="INTEGER", v=41 },
        { n="Y", t="INTEGER", v=113 },
        { n="VERT_ALIGN", t="STRING", v=5 }, --> "TOP"
        { n="HORZ_ALIGN", t="STRING", v=6 }, --> "LEFT"
        { n="IMAGE", t="STRING", v=2 }, --> "VDUHARDPOINT_ACTIVE"
        { n="BATCH", t="INTEGER", v=3 },
      }
    }, { --SPRITEANIM[8]
      n="SPRITEANIM",
      vars = {
        { n="NAME", t="STRING", v=18 }, --> "HARDPOINT_3"
        { n="WIDTH", t="INTEGER", v=32 },
        { n="HEIGHT", t="INTEGER", v=32 },
        { n="X", t="INTEGER", v=120 },
        { n="Y", t="INTEGER", v=113 },
        { n="VERT_ALIGN", t="STRING", v=5 }, --> "TOP"
        { n="HORZ_ALIGN", t="STRING", v=6 }, --> "LEFT"
        { n="IMAGE", t="STRING", v=12 }, --> "VDUHARDPOINT_"
        { n="LOOP", t="BOOL", v=false },
        { n="FRAMES", t="INTEGER", v=32 },
        { n="SPEED", t="FLOAT", v=0.0 },
        { n="BATCH", t="INTEGER", v=3 },
      }
    }, { --SPRITEANIM[9]
      n="SPRITE",
      vars = {
        { n="NAME", t="STRING", v=19 }, --> "HARDPOINTACTIVE_3"
        { n="WIDTH", t="INTEGER", v=32 },
        { n="HEIGHT", t="INTEGER", v=32 },
        { n="X", t="INTEGER", v=120 },
        { n="Y", t="INTEGER", v=113 },
        { n="VERT_ALIGN", t="STRING", v=5 }, --> "TOP"
        { n="HORZ_ALIGN", t="STRING", v=6 }, --> "LEFT"
        { n="IMAGE", t="STRING", v=2 }, --> "VDUHARDPOINT_ACTIVE"
        { n="BATCH", t="INTEGER", v=3 },
      }
    }, { --SPRITEANIM[10]
      n="SPRITEANIM",
      vars = {
        { n="NAME", t="STRING", v=20 }, --> "HARDPOINT_8"
        { n="WIDTH", t="INTEGER", v=32 },
        { n="HEIGHT", t="INTEGER", v=32 },
        { n="X", t="INTEGER", v=60 },
        { n="Y", t="INTEGER", v=46 },
        { n="VERT_ALIGN", t="STRING", v=5 }, --> "TOP"
        { n="HORZ_ALIGN", t="STRING", v=6 }, --> "LEFT"
        { n="IMAGE", t="STRING", v=21 }, --> "VDUMHARDPOINT_"
        { n="LOOP", t="BOOL", v=false },
        { n="FRAMES", t="INTEGER", v=29 },
        { n="SPEED", t="FLOAT", v=0.0 },
        { n="BATCH", t="INTEGER", v=3 },
      }
    }, { --SPRITEANIM[11]
      n="SPRITE",
      vars = {
        { n="NAME", t="STRING", v=22 }, --> "HARDPOINTACTIVE_8"
        { n="WIDTH", t="INTEGER", v=32 },
        { n="HEIGHT", t="INTEGER", v=32 },
        { n="X", t="INTEGER", v=60 },
        { n="Y", t="INTEGER", v=46 },
        { n="VERT_ALIGN", t="STRING", v=5 }, --> "TOP"
        { n="HORZ_ALIGN", t="STRING", v=6 }, --> "LEFT"
        { n="IMAGE", t="STRING", v=23 }, --> "VDUMHARDPOINT_ACTIVE"
        { n="BATCH", t="INTEGER", v=3 },
      }
    }, { --SPRITEANIM[12]
      n="SPRITEANIM",
      vars = {
        { n="NAME", t="STRING", v=24 }, --> "HARDPOINTRELOAD_8"
        { n="WIDTH", t="INTEGER", v=32 },
        { n="HEIGHT", t="INTEGER", v=32 },
        { n="X", t="INTEGER", v=60 },
        { n="Y", t="INTEGER", v=46 },
        { n="VERT_ALIGN", t="STRING", v=5 }, --> "TOP"
        { n="HORZ_ALIGN", t="STRING", v=6 }, --> "LEFT"
        { n="IMAGE", t="STRING", v=25 }, --> "VDUMCONTAINER_"
        { n="FRAMES", t="INTEGER", v=4 },
        { n="BATCH", t="INTEGER", v=3 },
      }
    }, { --SPRITEANIM[13]
      n="SPRITEANIM",
      vars = {
        { n="NAME", t="STRING", v=26 }, --> "HARDPOINT_9"
        { n="WIDTH", t="INTEGER", v=32 },
        { n="HEIGHT", t="INTEGER", v=32 },
        { n="X", t="INTEGER", v=100 },
        { n="Y", t="INTEGER", v=46 },
        { n="VERT_ALIGN", t="STRING", v=5 }, --> "TOP"
        { n="HORZ_ALIGN", t="STRING", v=6 }, --> "LEFT"
        { n="IMAGE", t="STRING", v=21 }, --> "VDUMHARDPOINT_"
        { n="LOOP", t="BOOL", v=false },
        { n="FRAMES", t="INTEGER", v=29 },
        { n="SPEED", t="FLOAT", v=0.0 },
        { n="BATCH", t="INTEGER", v=3 },
      }
    }, { --SPRITEANIM[14]
      n="SPRITE",
      vars = {
        { n="NAME", t="STRING", v=27 }, --> "HARDPOINTACTIVE_9"
        { n="WIDTH", t="INTEGER", v=32 },
        { n="HEIGHT", t="INTEGER", v=32 },
        { n="X", t="INTEGER", v=100 },
        { n="Y", t="INTEGER", v=46 },
        { n="VERT_ALIGN", t="STRING", v=5 }, --> "TOP"
        { n="HORZ_ALIGN", t="STRING", v=6 }, --> "LEFT"
        { n="IMAGE", t="STRING", v=23 }, --> "VDUMHARDPOINT_ACTIVE"
        { n="BATCH", t="INTEGER", v=3 },
      }
    }, { --SPRITEANIM[15]
      n="SPRITEANIM",
      vars = {
        { n="NAME", t="STRING", v=28 }, --> "HARDPOINTRELOAD_9"
        { n="WIDTH", t="INTEGER", v=32 },
        { n="HEIGHT", t="INTEGER", v=32 },
        { n="X", t="INTEGER", v=100 },
        { n="Y", t="INTEGER", v=46 },
        { n="VERT_ALIGN", t="STRING", v=5 }, --> "TOP"
        { n="HORZ_ALIGN", t="STRING", v=6 }, --> "LEFT"
        { n="IMAGE", t="STRING", v=25 }, --> "VDUMCONTAINER_"
        { n="FRAMES", t="INTEGER", v=4 },
        { n="BATCH", t="INTEGER", v=3 },
      }
    }
  }

And here after adding our two new hardpoints:

  tags = {
    {    --SPRITEANIM[1]
      n="SPRITEANIM",
      vars = {
        { n="NAME", t="STRING", v=9 }, --> "ECMHARDPOINT"
        { n="WIDTH", t="INTEGER", v=32 },
        { n="HEIGHT", t="INTEGER", v=32 },
        { n="X", t="INTEGER", v=80 },
        { n="Y", t="INTEGER", v=100 },
        { n="VERT_ALIGN", t="STRING", v=5 }, --> "TOP"
        { n="HORZ_ALIGN", t="STRING", v=6 }, --> "LEFT"
        { n="IMAGE", t="STRING", v=10 }, --> "VDUECM_"
        { n="LOOP", t="BOOL", v=false },
        { n="FRAMES", t="INTEGER", v=3 },
        { n="SPEED", t="FLOAT", v=0.0 },
        { n="BATCH", t="INTEGER", v=3 },
      }
    },
    {   -- Weapon 1 Inactive
      n="SPRITEANIM",
      vars = {
        { n="NAME", t="STRING", v=11 }, --> "HARDPOINT_0"
        { n="WIDTH", t="INTEGER", v=32 },
        { n="HEIGHT", t="INTEGER", v=32 },
        { n="X", t="INTEGER", v=32 },
        { n="Y", t="INTEGER", v=96 },
        { n="VERT_ALIGN", t="STRING", v=5 }, --> "TOP"
        { n="HORZ_ALIGN", t="STRING", v=6 }, --> "LEFT"
        { n="IMAGE", t="STRING", v=12 }, --> "VDUHARDPOINT_"
        { n="LOOP", t="BOOL", v=false },
        { n="FRAMES", t="INTEGER", v=32 },
        { n="SPEED", t="FLOAT", v=0.0 },
        { n="BATCH", t="INTEGER", v=3 },
      }
    },
    {   -- Weapon 1 Active
      n="SPRITE",
      vars = {
        { n="NAME", t="STRING", v=13 }, --> "HARDPOINTACTIVE_0"
        { n="WIDTH", t="INTEGER", v=32 },
        { n="HEIGHT", t="INTEGER", v=32 },
        { n="X", t="INTEGER", v=32 },
        { n="Y", t="INTEGER", v=96 },
        { n="VERT_ALIGN", t="STRING", v=5 }, --> "TOP"
        { n="HORZ_ALIGN", t="STRING", v=6 }, --> "LEFT"
        { n="IMAGE", t="STRING", v=2 }, --> "VDUHARDPOINT_ACTIVE"
        { n="BATCH", t="INTEGER", v=3 },
      }
    },
    {   -- Weapon 2 Inactive
      n="SPRITEANIM",
      vars = {
        { n="NAME", t="STRING", v=14 }, --> "HARDPOINT_1"
        { n="WIDTH", t="INTEGER", v=32 },
        { n="HEIGHT", t="INTEGER", v=32 },
        { n="X", t="INTEGER", v=129 },
        { n="Y", t="INTEGER", v=96 },
        { n="VERT_ALIGN", t="STRING", v=5 }, --> "TOP"
        { n="HORZ_ALIGN", t="STRING", v=6 }, --> "LEFT"
        { n="IMAGE", t="STRING", v=12 }, --> "VDUHARDPOINT_"
        { n="LOOP", t="BOOL", v=false },
        { n="FRAMES", t="INTEGER", v=32 },
        { n="SPEED", t="FLOAT", v=0.0 },
        { n="BATCH", t="INTEGER", v=3 },
      }
    },
    {   -- Weapon 2 Active
      n="SPRITE",
      vars = {
        { n="NAME", t="STRING", v=15 }, --> "HARDPOINTACTIVE_1"
        { n="WIDTH", t="INTEGER", v=32 },
        { n="HEIGHT", t="INTEGER", v=32 },
        { n="X", t="INTEGER", v=129 },
        { n="Y", t="INTEGER", v=96 },
        { n="VERT_ALIGN", t="STRING", v=5 }, --> "TOP"
        { n="HORZ_ALIGN", t="STRING", v=6 }, --> "LEFT"
        { n="IMAGE", t="STRING", v=2 }, --> "VDUHARDPOINT_ACTIVE"
        { n="BATCH", t="INTEGER", v=3 },
      }
    },
    {   -- Weapon 3 Inactive
      n="SPRITEANIM",
      vars = {
        { n="NAME", t="STRING", v=16 }, --> "HARDPOINT_2"
        { n="WIDTH", t="INTEGER", v=32 },
        { n="HEIGHT", t="INTEGER", v=32 },
        { n="X", t="INTEGER", v=41 },
        { n="Y", t="INTEGER", v=113 },
        { n="VERT_ALIGN", t="STRING", v=5 }, --> "TOP"
        { n="HORZ_ALIGN", t="STRING", v=6 }, --> "LEFT"
        { n="IMAGE", t="STRING", v=12 }, --> "VDUHARDPOINT_"
        { n="LOOP", t="BOOL", v=false },
        { n="FRAMES", t="INTEGER", v=32 },
        { n="SPEED", t="FLOAT", v=0.0 },
        { n="BATCH", t="INTEGER", v=3 },
      }
    },
    {   -- Weapon 3 Active
      n="SPRITE",
      vars = {
        { n="NAME", t="STRING", v=17 }, --> "HARDPOINTACTIVE_2"
        { n="WIDTH", t="INTEGER", v=32 },
        { n="HEIGHT", t="INTEGER", v=32 },
        { n="X", t="INTEGER", v=41 },
        { n="Y", t="INTEGER", v=113 },
        { n="VERT_ALIGN", t="STRING", v=5 }, --> "TOP"
        { n="HORZ_ALIGN", t="STRING", v=6 }, --> "LEFT"
        { n="IMAGE", t="STRING", v=2 }, --> "VDUHARDPOINT_ACTIVE"
        { n="BATCH", t="INTEGER", v=3 },
      }
    },
    {   -- Weapon 4 Inactive
      n="SPRITEANIM",
      vars = {
        { n="NAME", t="STRING", v=18 }, --> "HARDPOINT_3"
        { n="WIDTH", t="INTEGER", v=32 },
        { n="HEIGHT", t="INTEGER", v=32 },
        { n="X", t="INTEGER", v=120 },
        { n="Y", t="INTEGER", v=113 },
        { n="VERT_ALIGN", t="STRING", v=5 }, --> "TOP"
        { n="HORZ_ALIGN", t="STRING", v=6 }, --> "LEFT"
        { n="IMAGE", t="STRING", v=12 }, --> "VDUHARDPOINT_"
        { n="LOOP", t="BOOL", v=false },
        { n="FRAMES", t="INTEGER", v=32 },
        { n="SPEED", t="FLOAT", v=0.0 },
        { n="BATCH", t="INTEGER", v=3 },
      }
    },
    {   -- Weapon 4 Active
      n="SPRITE",
      vars = {
        { n="NAME", t="STRING", v=19 }, --> "HARDPOINTACTIVE_3"
        { n="WIDTH", t="INTEGER", v=32 },
        { n="HEIGHT", t="INTEGER", v=32 },
        { n="X", t="INTEGER", v=120 },
        { n="Y", t="INTEGER", v=113 },
        { n="VERT_ALIGN", t="STRING", v=5 }, --> "TOP"
        { n="HORZ_ALIGN", t="STRING", v=6 }, --> "LEFT"
        { n="IMAGE", t="STRING", v=2 }, --> "VDUHARDPOINT_ACTIVE"
        { n="BATCH", t="INTEGER", v=3 },
      }
    },
    {   -- Weapon 5 Inactive
      n="SPRITEANIM",
      vars = {
        { n="NAME", t="STRING", v=60 }, --> "HARDPOINT_4"
        { n="WIDTH", t="INTEGER", v=32 },
        { n="HEIGHT", t="INTEGER", v=32 },
        { n="X", t="INTEGER", v=120 },
        { n="Y", t="INTEGER", v=113 },
        { n="VERT_ALIGN", t="STRING", v=5 }, --> "TOP"
        { n="HORZ_ALIGN", t="STRING", v=6 }, --> "LEFT"
        { n="IMAGE", t="STRING", v=12 }, --> "VDUHARDPOINT_"
        { n="LOOP", t="BOOL", v=false },
        { n="FRAMES", t="INTEGER", v=32 },
        { n="SPEED", t="FLOAT", v=0.0 },
        { n="BATCH", t="INTEGER", v=3 },
      }
    },
    {   -- Weapon 5 Active
      n="SPRITE",
      vars = {
        { n="NAME", t="STRING", v=61 }, --> "HARDPOINTACTIVE_4"
        { n="WIDTH", t="INTEGER", v=32 },
        { n="HEIGHT", t="INTEGER", v=32 },
        { n="X", t="INTEGER", v=120 },
        { n="Y", t="INTEGER", v=113 },
        { n="VERT_ALIGN", t="STRING", v=5 }, --> "TOP"
        { n="HORZ_ALIGN", t="STRING", v=6 }, --> "LEFT"
        { n="IMAGE", t="STRING", v=2 }, --> "VDUHARDPOINT_ACTIVE"
        { n="BATCH", t="INTEGER", v=3 },
      }
    },
    {   -- Weapon 6 Inactive
      n="SPRITEANIM",
      vars = {
        { n="NAME", t="STRING", v=62 }, --> "HARDPOINT_5"
        { n="WIDTH", t="INTEGER", v=32 },
        { n="HEIGHT", t="INTEGER", v=32 },
        { n="X", t="INTEGER", v=120 },
        { n="Y", t="INTEGER", v=113 },
        { n="VERT_ALIGN", t="STRING", v=5 }, --> "TOP"
        { n="HORZ_ALIGN", t="STRING", v=6 }, --> "LEFT"
        { n="IMAGE", t="STRING", v=12 }, --> "VDUHARDPOINT_"
        { n="LOOP", t="BOOL", v=false },
        { n="FRAMES", t="INTEGER", v=32 },
        { n="SPEED", t="FLOAT", v=0.0 },
        { n="BATCH", t="INTEGER", v=3 },
      }
    },
    {   -- Weapon 6 Active
      n="SPRITE",
      vars = {
        { n="NAME", t="STRING", v=63 }, --> "HARDPOINTACTIVE_5"
        { n="WIDTH", t="INTEGER", v=32 },
        { n="HEIGHT", t="INTEGER", v=32 },
        { n="X", t="INTEGER", v=120 },
        { n="Y", t="INTEGER", v=113 },
        { n="VERT_ALIGN", t="STRING", v=5 }, --> "TOP"
        { n="HORZ_ALIGN", t="STRING", v=6 }, --> "LEFT"
        { n="IMAGE", t="STRING", v=2 }, --> "VDUHARDPOINT_ACTIVE"
        { n="BATCH", t="INTEGER", v=3 },
      }
    },
    {   -- Missile 1 Inactive
      n="SPRITEANIM",
      vars = {
        { n="NAME", t="STRING", v=20 }, --> "HARDPOINT_8"
        { n="WIDTH", t="INTEGER", v=32 },
        { n="HEIGHT", t="INTEGER", v=32 },
        { n="X", t="INTEGER", v=60 },
        { n="Y", t="INTEGER", v=46 },
        { n="VERT_ALIGN", t="STRING", v=5 }, --> "TOP"
        { n="HORZ_ALIGN", t="STRING", v=6 }, --> "LEFT"
        { n="IMAGE", t="STRING", v=21 }, --> "VDUMHARDPOINT_"
        { n="LOOP", t="BOOL", v=false },
        { n="FRAMES", t="INTEGER", v=29 },
        { n="SPEED", t="FLOAT", v=0.0 },
        { n="BATCH", t="INTEGER", v=3 },
      }
    },
    {   -- Missile 1 Active
      n="SPRITE",
      vars = {
        { n="NAME", t="STRING", v=22 }, --> "HARDPOINTACTIVE_8"
        { n="WIDTH", t="INTEGER", v=32 },
        { n="HEIGHT", t="INTEGER", v=32 },
        { n="X", t="INTEGER", v=60 },
        { n="Y", t="INTEGER", v=46 },
        { n="VERT_ALIGN", t="STRING", v=5 }, --> "TOP"
        { n="HORZ_ALIGN", t="STRING", v=6 }, --> "LEFT"
        { n="IMAGE", t="STRING", v=23 }, --> "VDUMHARDPOINT_ACTIVE"
        { n="BATCH", t="INTEGER", v=3 },
      }
    },
    {   -- Missile 1 Reloading
      n="SPRITEANIM",
      vars = {
        { n="NAME", t="STRING", v=24 }, --> "HARDPOINTRELOAD_8"
        { n="WIDTH", t="INTEGER", v=32 },
        { n="HEIGHT", t="INTEGER", v=32 },
        { n="X", t="INTEGER", v=60 },
        { n="Y", t="INTEGER", v=46 },
        { n="VERT_ALIGN", t="STRING", v=5 }, --> "TOP"
        { n="HORZ_ALIGN", t="STRING", v=6 }, --> "LEFT"
        { n="IMAGE", t="STRING", v=25 }, --> "VDUMCONTAINER_"
        { n="FRAMES", t="INTEGER", v=4 },
        { n="BATCH", t="INTEGER", v=3 },
      }
    },
    {   -- Missile 1 Inactive
      n="SPRITEANIM",
      vars = {
        { n="NAME", t="STRING", v=26 }, --> "HARDPOINT_9"
        { n="WIDTH", t="INTEGER", v=32 },
        { n="HEIGHT", t="INTEGER", v=32 },
        { n="X", t="INTEGER", v=100 },
        { n="Y", t="INTEGER", v=46 },
        { n="VERT_ALIGN", t="STRING", v=5 }, --> "TOP"
        { n="HORZ_ALIGN", t="STRING", v=6 }, --> "LEFT"
        { n="IMAGE", t="STRING", v=21 }, --> "VDUMHARDPOINT_"
        { n="LOOP", t="BOOL", v=false },
        { n="FRAMES", t="INTEGER", v=29 },
        { n="SPEED", t="FLOAT", v=0.0 },
        { n="BATCH", t="INTEGER", v=3 },
      }
    },
    {   -- Missile 1 Active
      n="SPRITE",
      vars = {
        { n="NAME", t="STRING", v=27 }, --> "HARDPOINTACTIVE_9"
        { n="WIDTH", t="INTEGER", v=32 },
        { n="HEIGHT", t="INTEGER", v=32 },
        { n="X", t="INTEGER", v=100 },
        { n="Y", t="INTEGER", v=46 },
        { n="VERT_ALIGN", t="STRING", v=5 }, --> "TOP"
        { n="HORZ_ALIGN", t="STRING", v=6 }, --> "LEFT"
        { n="IMAGE", t="STRING", v=23 }, --> "VDUMHARDPOINT_ACTIVE"
        { n="BATCH", t="INTEGER", v=3 },
      }
    },
    {   -- Missile 1 Reloading
      n="SPRITEANIM",
      vars = {
        { n="NAME", t="STRING", v=28 }, --> "HARDPOINTRELOAD_9"
        { n="WIDTH", t="INTEGER", v=32 },
        { n="HEIGHT", t="INTEGER", v=32 },
        { n="X", t="INTEGER", v=100 },
        { n="Y", t="INTEGER", v=46 },
        { n="VERT_ALIGN", t="STRING", v=5 }, --> "TOP"
        { n="HORZ_ALIGN", t="STRING", v=6 }, --> "LEFT"
        { n="IMAGE", t="STRING", v=25 }, --> "VDUMCONTAINER_"
        { n="FRAMES", t="INTEGER", v=4 },
        { n="BATCH", t="INTEGER", v=3 },
      }
    }
  }

I have added some comments again, and also again, you don't need to.

What we can also see here, is that if we wanted to add missile hardpoints, we would need to copy three entries instead of two per hardpoint:
HARDPOINT_x, HARDPOINTACTIVE_x, and HARDPOINTRELOAD_x.
This is because the missile hardpoints have an additional "reloading" animation. Other than that the procedure would be exactly the same.

Now we need to adjust the positions.
Again, the only real way here is to change the X and Y value, compile the mod, and test the changes in game.
I've come up with the following values:

WeaponHardpointXY
Gun 1HARDPOINT_055125
Gun 2HARDPOINT_1105125
Gun 3HARDPOINT_240113
Gun 4HARDPOINT_3120113
Gun 5HARDPOINT_43196
Gun 6HARDPOINT_512996

3_5-Recticle-Final.jpg
I thought I could just reuse the coordinates for the upper two rows, but it turned out the left indicators were shifted by 1 pixel, which made the third one look awkward. So I had to fix this.

As mentioned, we don't need to adjust our missile indicators here.
If we had to, we would perform the exact same procedure, except with the HARDPOINT_8, HARDPOINTACTIVE_8, and HARDPOINTRELOAD_8 (and _9) entries.

The final code block:

  tags = {
    {    --SPRITEANIM[1]
      n="SPRITEANIM",
      vars = {
        { n="NAME", t="STRING", v=9 }, --> "ECMHARDPOINT"
        { n="WIDTH", t="INTEGER", v=32 },
        { n="HEIGHT", t="INTEGER", v=32 },
        { n="X", t="INTEGER", v=80 },
        { n="Y", t="INTEGER", v=100 },
        { n="VERT_ALIGN", t="STRING", v=5 }, --> "TOP"
        { n="HORZ_ALIGN", t="STRING", v=6 }, --> "LEFT"
        { n="IMAGE", t="STRING", v=10 }, --> "VDUECM_"
        { n="LOOP", t="BOOL", v=false },
        { n="FRAMES", t="INTEGER", v=3 },
        { n="SPEED", t="FLOAT", v=0.0 },
        { n="BATCH", t="INTEGER", v=3 },
      }
    },
    {   -- Weapon 1 Inactive
      n="SPRITEANIM",
      vars = {
        { n="NAME", t="STRING", v=11 }, --> "HARDPOINT_0"
        { n="WIDTH", t="INTEGER", v=32 },
        { n="HEIGHT", t="INTEGER", v=32 },
        { n="X", t="INTEGER", v=55 },
        { n="Y", t="INTEGER", v=125 },
        { n="VERT_ALIGN", t="STRING", v=5 }, --> "TOP"
        { n="HORZ_ALIGN", t="STRING", v=6 }, --> "LEFT"
        { n="IMAGE", t="STRING", v=12 }, --> "VDUHARDPOINT_"
        { n="LOOP", t="BOOL", v=false },
        { n="FRAMES", t="INTEGER", v=32 },
        { n="SPEED", t="FLOAT", v=0.0 },
        { n="BATCH", t="INTEGER", v=3 },
      }
    },
    {   -- Weapon 1 Active
      n="SPRITE",
      vars = {
        { n="NAME", t="STRING", v=13 }, --> "HARDPOINTACTIVE_0"
        { n="WIDTH", t="INTEGER", v=32 },
        { n="HEIGHT", t="INTEGER", v=32 },
        { n="X", t="INTEGER", v=55 },
        { n="Y", t="INTEGER", v=125 },
        { n="VERT_ALIGN", t="STRING", v=5 }, --> "TOP"
        { n="HORZ_ALIGN", t="STRING", v=6 }, --> "LEFT"
        { n="IMAGE", t="STRING", v=2 }, --> "VDUHARDPOINT_ACTIVE"
        { n="BATCH", t="INTEGER", v=3 },
      }
    },
    {   -- Weapon 2 Inactive
      n="SPRITEANIM",
      vars = {
        { n="NAME", t="STRING", v=14 }, --> "HARDPOINT_1"
        { n="WIDTH", t="INTEGER", v=32 },
        { n="HEIGHT", t="INTEGER", v=32 },
        { n="X", t="INTEGER", v=105 },
        { n="Y", t="INTEGER", v=125 },
        { n="VERT_ALIGN", t="STRING", v=5 }, --> "TOP"
        { n="HORZ_ALIGN", t="STRING", v=6 }, --> "LEFT"
        { n="IMAGE", t="STRING", v=12 }, --> "VDUHARDPOINT_"
        { n="LOOP", t="BOOL", v=false },
        { n="FRAMES", t="INTEGER", v=32 },
        { n="SPEED", t="FLOAT", v=0.0 },
        { n="BATCH", t="INTEGER", v=3 },
      }
    },
    {   -- Weapon 2 Active
      n="SPRITE",
      vars = {
        { n="NAME", t="STRING", v=15 }, --> "HARDPOINTACTIVE_1"
        { n="WIDTH", t="INTEGER", v=32 },
        { n="HEIGHT", t="INTEGER", v=32 },
        { n="X", t="INTEGER", v=105 },
        { n="Y", t="INTEGER", v=125 },
        { n="VERT_ALIGN", t="STRING", v=5 }, --> "TOP"
        { n="HORZ_ALIGN", t="STRING", v=6 }, --> "LEFT"
        { n="IMAGE", t="STRING", v=2 }, --> "VDUHARDPOINT_ACTIVE"
        { n="BATCH", t="INTEGER", v=3 },
      }
    },
    {   -- Weapon 3 Inactive
      n="SPRITEANIM",
      vars = {
        { n="NAME", t="STRING", v=16 }, --> "HARDPOINT_2"
        { n="WIDTH", t="INTEGER", v=32 },
        { n="HEIGHT", t="INTEGER", v=32 },
        { n="X", t="INTEGER", v=40 },
        { n="Y", t="INTEGER", v=113 },
        { n="VERT_ALIGN", t="STRING", v=5 }, --> "TOP"
        { n="HORZ_ALIGN", t="STRING", v=6 }, --> "LEFT"
        { n="IMAGE", t="STRING", v=12 }, --> "VDUHARDPOINT_"
        { n="LOOP", t="BOOL", v=false },
        { n="FRAMES", t="INTEGER", v=32 },
        { n="SPEED", t="FLOAT", v=0.0 },
        { n="BATCH", t="INTEGER", v=3 },
      }
    },
    {   -- Weapon 3 Active
      n="SPRITE",
      vars = {
        { n="NAME", t="STRING", v=17 }, --> "HARDPOINTACTIVE_2"
        { n="WIDTH", t="INTEGER", v=32 },
        { n="HEIGHT", t="INTEGER", v=32 },
        { n="X", t="INTEGER", v=40 },
        { n="Y", t="INTEGER", v=113 },
        { n="VERT_ALIGN", t="STRING", v=5 }, --> "TOP"
        { n="HORZ_ALIGN", t="STRING", v=6 }, --> "LEFT"
        { n="IMAGE", t="STRING", v=2 }, --> "VDUHARDPOINT_ACTIVE"
        { n="BATCH", t="INTEGER", v=3 },
      }
    },
    {   -- Weapon 4 Inactive
      n="SPRITEANIM",
      vars = {
        { n="NAME", t="STRING", v=18 }, --> "HARDPOINT_3"
        { n="WIDTH", t="INTEGER", v=32 },
        { n="HEIGHT", t="INTEGER", v=32 },
        { n="X", t="INTEGER", v=120 },
        { n="Y", t="INTEGER", v=113 },
        { n="VERT_ALIGN", t="STRING", v=5 }, --> "TOP"
        { n="HORZ_ALIGN", t="STRING", v=6 }, --> "LEFT"
        { n="IMAGE", t="STRING", v=12 }, --> "VDUHARDPOINT_"
        { n="LOOP", t="BOOL", v=false },
        { n="FRAMES", t="INTEGER", v=32 },
        { n="SPEED", t="FLOAT", v=0.0 },
        { n="BATCH", t="INTEGER", v=3 },
      }
    },
    {   -- Weapon 4 Active
      n="SPRITE",
      vars = {
        { n="NAME", t="STRING", v=19 }, --> "HARDPOINTACTIVE_3"
        { n="WIDTH", t="INTEGER", v=32 },
        { n="HEIGHT", t="INTEGER", v=32 },
        { n="X", t="INTEGER", v=120 },
        { n="Y", t="INTEGER", v=113 },
        { n="VERT_ALIGN", t="STRING", v=5 }, --> "TOP"
        { n="HORZ_ALIGN", t="STRING", v=6 }, --> "LEFT"
        { n="IMAGE", t="STRING", v=2 }, --> "VDUHARDPOINT_ACTIVE"
        { n="BATCH", t="INTEGER", v=3 },
      }
    },
    {   -- Weapon 5 Inactive
      n="SPRITEANIM",
      vars = {
        { n="NAME", t="STRING", v=60 }, --> "HARDPOINT_4"
        { n="WIDTH", t="INTEGER", v=32 },
        { n="HEIGHT", t="INTEGER", v=32 },
        { n="X", t="INTEGER", v=31 },
        { n="Y", t="INTEGER", v=96 },
        { n="VERT_ALIGN", t="STRING", v=5 }, --> "TOP"
        { n="HORZ_ALIGN", t="STRING", v=6 }, --> "LEFT"
        { n="IMAGE", t="STRING", v=12 }, --> "VDUHARDPOINT_"
        { n="LOOP", t="BOOL", v=false },
        { n="FRAMES", t="INTEGER", v=32 },
        { n="SPEED", t="FLOAT", v=0.0 },
        { n="BATCH", t="INTEGER", v=3 },
      }
    },
    {   -- Weapon 5 Active
      n="SPRITE",
      vars = {
        { n="NAME", t="STRING", v=61 }, --> "HARDPOINTACTIVE_4"
        { n="WIDTH", t="INTEGER", v=32 },
        { n="HEIGHT", t="INTEGER", v=32 },
        { n="X", t="INTEGER", v=31 },
        { n="Y", t="INTEGER", v=96 },
        { n="VERT_ALIGN", t="STRING", v=5 }, --> "TOP"
        { n="HORZ_ALIGN", t="STRING", v=6 }, --> "LEFT"
        { n="IMAGE", t="STRING", v=2 }, --> "VDUHARDPOINT_ACTIVE"
        { n="BATCH", t="INTEGER", v=3 },
      }
    },
    {   -- Weapon 6 Inactive
      n="SPRITEANIM",
      vars = {
        { n="NAME", t="STRING", v=62 }, --> "HARDPOINT_5"
        { n="WIDTH", t="INTEGER", v=32 },
        { n="HEIGHT", t="INTEGER", v=32 },
        { n="X", t="INTEGER", v=129 },
        { n="Y", t="INTEGER", v=96 },
        { n="VERT_ALIGN", t="STRING", v=5 }, --> "TOP"
        { n="HORZ_ALIGN", t="STRING", v=6 }, --> "LEFT"
        { n="IMAGE", t="STRING", v=12 }, --> "VDUHARDPOINT_"
        { n="LOOP", t="BOOL", v=false },
        { n="FRAMES", t="INTEGER", v=32 },
        { n="SPEED", t="FLOAT", v=0.0 },
        { n="BATCH", t="INTEGER", v=3 },
      }
    },
    {   -- Weapon 6 Active
      n="SPRITE",
      vars = {
        { n="NAME", t="STRING", v=63 }, --> "HARDPOINTACTIVE_5"
        { n="WIDTH", t="INTEGER", v=32 },
        { n="HEIGHT", t="INTEGER", v=32 },
        { n="X", t="INTEGER", v=129 },
        { n="Y", t="INTEGER", v=96 },
        { n="VERT_ALIGN", t="STRING", v=5 }, --> "TOP"
        { n="HORZ_ALIGN", t="STRING", v=6 }, --> "LEFT"
        { n="IMAGE", t="STRING", v=2 }, --> "VDUHARDPOINT_ACTIVE"
        { n="BATCH", t="INTEGER", v=3 },
      }
    },
    {   -- Missile 1 Inactive
      n="SPRITEANIM",
      vars = {
        { n="NAME", t="STRING", v=20 }, --> "HARDPOINT_8"
        { n="WIDTH", t="INTEGER", v=32 },
        { n="HEIGHT", t="INTEGER", v=32 },
        { n="X", t="INTEGER", v=60 },
        { n="Y", t="INTEGER", v=46 },
        { n="VERT_ALIGN", t="STRING", v=5 }, --> "TOP"
        { n="HORZ_ALIGN", t="STRING", v=6 }, --> "LEFT"
        { n="IMAGE", t="STRING", v=21 }, --> "VDUMHARDPOINT_"
        { n="LOOP", t="BOOL", v=false },
        { n="FRAMES", t="INTEGER", v=29 },
        { n="SPEED", t="FLOAT", v=0.0 },
        { n="BATCH", t="INTEGER", v=3 },
      }
    },
    {   -- Missile 1 Active
      n="SPRITE",
      vars = {
        { n="NAME", t="STRING", v=22 }, --> "HARDPOINTACTIVE_8"
        { n="WIDTH", t="INTEGER", v=32 },
        { n="HEIGHT", t="INTEGER", v=32 },
        { n="X", t="INTEGER", v=60 },
        { n="Y", t="INTEGER", v=46 },
        { n="VERT_ALIGN", t="STRING", v=5 }, --> "TOP"
        { n="HORZ_ALIGN", t="STRING", v=6 }, --> "LEFT"
        { n="IMAGE", t="STRING", v=23 }, --> "VDUMHARDPOINT_ACTIVE"
        { n="BATCH", t="INTEGER", v=3 },
      }
    },
    {   -- Missile 1 Reloading
      n="SPRITEANIM",
      vars = {
        { n="NAME", t="STRING", v=24 }, --> "HARDPOINTRELOAD_8"
        { n="WIDTH", t="INTEGER", v=32 },
        { n="HEIGHT", t="INTEGER", v=32 },
        { n="X", t="INTEGER", v=60 },
        { n="Y", t="INTEGER", v=46 },
        { n="VERT_ALIGN", t="STRING", v=5 }, --> "TOP"
        { n="HORZ_ALIGN", t="STRING", v=6 }, --> "LEFT"
        { n="IMAGE", t="STRING", v=25 }, --> "VDUMCONTAINER_"
        { n="FRAMES", t="INTEGER", v=4 },
        { n="BATCH", t="INTEGER", v=3 },
      }
    },
    {   -- Missile 1 Inactive
      n="SPRITEANIM",
      vars = {
        { n="NAME", t="STRING", v=26 }, --> "HARDPOINT_9"
        { n="WIDTH", t="INTEGER", v=32 },
        { n="HEIGHT", t="INTEGER", v=32 },
        { n="X", t="INTEGER", v=100 },
        { n="Y", t="INTEGER", v=46 },
        { n="VERT_ALIGN", t="STRING", v=5 }, --> "TOP"
        { n="HORZ_ALIGN", t="STRING", v=6 }, --> "LEFT"
        { n="IMAGE", t="STRING", v=21 }, --> "VDUMHARDPOINT_"
        { n="LOOP", t="BOOL", v=false },
        { n="FRAMES", t="INTEGER", v=29 },
        { n="SPEED", t="FLOAT", v=0.0 },
        { n="BATCH", t="INTEGER", v=3 },
      }
    },
    {   -- Missile 1 Active
      n="SPRITE",
      vars = {
        { n="NAME", t="STRING", v=27 }, --> "HARDPOINTACTIVE_9"
        { n="WIDTH", t="INTEGER", v=32 },
        { n="HEIGHT", t="INTEGER", v=32 },
        { n="X", t="INTEGER", v=100 },
        { n="Y", t="INTEGER", v=46 },
        { n="VERT_ALIGN", t="STRING", v=5 }, --> "TOP"
        { n="HORZ_ALIGN", t="STRING", v=6 }, --> "LEFT"
        { n="IMAGE", t="STRING", v=23 }, --> "VDUMHARDPOINT_ACTIVE"
        { n="BATCH", t="INTEGER", v=3 },
      }
    },
    {   -- Missile 1 Reloading
      n="SPRITEANIM",
      vars = {
        { n="NAME", t="STRING", v=28 }, --> "HARDPOINTRELOAD_9"
        { n="WIDTH", t="INTEGER", v=32 },
        { n="HEIGHT", t="INTEGER", v=32 },
        { n="X", t="INTEGER", v=100 },
        { n="Y", t="INTEGER", v=46 },
        { n="VERT_ALIGN", t="STRING", v=5 }, --> "TOP"
        { n="HORZ_ALIGN", t="STRING", v=6 }, --> "LEFT"
        { n="IMAGE", t="STRING", v=25 }, --> "VDUMCONTAINER_"
        { n="FRAMES", t="INTEGER", v=4 },
        { n="BATCH", t="INTEGER", v=3 },
      }
    }
  }

That's it for the cockpit! Hooray!

Part 4: The Weapon Hardpoints Revisited

Now that we created our cockpit hardpoints, it's time we match our actual weapon hardpoints to the order that we decided upon.
Remember, this was the current order:

2_3-Zandt_Weapons_composite.jpg

And this is how we would like to have it:

3_4-Ship_Weapon_Positioning_Layout.jpg

Our missile launchers are also in the wrong place, they should switch positions.

We now have two options to solve this:
The first one is to just swap the HARDPOINT_NUMBER_1 values around, and the second one is to swap the COORDINATES entries around.
Which one you do doesn't matter much, just don't do both, or you'll end up in the same situation as before.
I've chosen to just swap the HARDPOINT_NUMBER_1, it's a bit less work.

With this out of the way, we need to swap the following:

Current Hardpoint New Hardpoint
HARDPOINT A = Gun 1 = HARDPOINT_NUMBER_1 #0 HARDPOINT A = Gun 1 = HARDPOINT_NUMBER_1 #0
HARDPOINT B = Gun 2 = HARDPOINT_NUMBER_1 #1 HARDPOINT C = Gun 3 = HARDPOINT_NUMBER_1 #2
HARDPOINT C = Gun 3 = HARDPOINT_NUMBER_1 #2 HARDPOINT D = Gun 4 = HARDPOINT_NUMBER_1 #3
HARDPOINT D = Gun 4 = HARDPOINT_NUMBER_1 #3 HARDPOINT B = Gun 2 = HARDPOINT_NUMBER_1 #1
HARDPOINT E = Gun 5 = HARDPOINT_NUMBER_1 #4 HARDPOINT E = Gun 5 = HARDPOINT_NUMBER_1 #4
HARDPOINT F = Gun 6 = HARDPOINT_NUMBER_1 #5 HARDPOINT F = Gun 6 = HARDPOINT_NUMBER_1 #5
LAUNCHER A = Missile 1 = HARDPOINT_NUMBER_1 #8 LAUNCHER B = Missile 2 = HARDPOINT_NUMBER_1 #9
LAUNCHER B = Missile 2 = HARDPOINT_NUMBER_1 #9 LAUNCHER A = Missile 1 = HARDPOINT_NUMBER_1 #8

So basically we need to shift gun 2, 3, and 4 around, plus our two missile launchers.

4.1 Modifying the Hardpoints

16_ZANDT_LOADOUT_PLAYER.LAYOUT

It's time to go back to our 16_ZANDT_LOADOUT_PLAYER.LAYOUT.lua file.

Find the entry with a ["TYPE_STRING"] = "HARDPOINT" that has the HARDPOINT_NUMBER_1 value of 1. This is our second gun, and it should become our new gun 3, so we assign a value of 2 instead.

Be cautios now! Right now we have two hardpoints that are assigned to the slot #2. Don't confuse them when editing, it's easy to mix them up! Try to remember the line numbers and maybe the other values when editing to make sure you're editing the correct entry.

For the missiles it's not so bad, we search for ["TYPE_STRING"] = "MISSILE HARDPOINT" and just swap their positions.

Entry Old Value New Value
ENTRY [17] [2] / Line 1682 ["HARDPOINT_NUMBER_1"] = 1 ["HARDPOINT_NUMBER_1"] = 2
ENTRY [17] [3] / Line 1716 ["HARDPOINT_NUMBER_1"] = 2 ["HARDPOINT_NUMBER_1"] = 3
ENTRY [17] [6] / Line 1818 ["HARDPOINT_NUMBER_1"] = 3 ["HARDPOINT_NUMBER_1"] = 1
ENTRY [17] [8] / Line 1872 ["HARDPOINT_NUMBER_1"] = 9 ["HARDPOINT_NUMBER_1"] = 8
ENTRY [17] [9] / Line 1906 ["HARDPOINT_NUMBER_1"] = 8 ["HARDPOINT_NUMBER_1"] = 9

4_1-16_ZANDT_LOADOUT_PLAYER.LAYOUT.lua_Changes-1
4_1-16_ZANDT_LOADOUT_PLAYER.LAYOUT.lua_Changes-2
4_1-16_ZANDT_LOADOUT_PLAYER.LAYOUT.lua_Changes-3
4_1-16_ZANDT_LOADOUT_PLAYER.LAYOUT.lua_Changes-4
4_1-16_ZANDT_LOADOUT_PLAYER.LAYOUT.lua_Changes-5

When we check back in game, everything seems to be as it should now. The weapon hardpoint correlate with the display in the MFD and Shield status, as well as with the recticle indicators.

Good work!

Part 5: Factions, or "Who Sells This Stuff?"

So far we haven't changed where we can actually buy our ship. Currently it's still set to the original value of the Durston, our ship's template.

Here's an overview of all the factions in the game. Some are only there for specific events, some could maybe one day be used as an actual faction.
Currently only those faction with a "Yes" are actually reasonable when defining where you can buy your ship.
The factions with a "No" should not be used as an actual faction, because they are used for the story / for the general gameplay.

And no, I have no idea why some of these factions with no stations do show up in the AVAILABILITY entries for some ships / equipment. Maybe it was planned to add more stations later, maybe it's just an oversight, I don't know.

I'd really like the idea of a Mercenaries' or Merchant's Guild station...

Faction String Display Name Has a Station Comment
DOUBLEJACK DoubleJacks Yes Only one station: Jesse's Den
HUMAN NEUTRAL Commonwealth Yes The main civilian faction
PLAYER Independents Yes Only one station: Bountiful Vista, your player base
POLICE Police Yes Every (regular) police station and ship
RED DEVIL Red Devils Yes Pirate faction with some stations & missions
SMUGGLERS Independents Yes The other main civilian faction
INVIOLATE Inviolates Partial Only one station: the "Chapel" - no Ship Dealer
CABALLEROS Caballeros Inc. No (but potentially)Caballero Refill Stations without Ship Dealer
HUMAN PIRATE Pirate No (but potentially)Pirate faction - no station exists
INFECTED Infected No (but potentially)Hostile Robot faction - no station exists
MERCENARY GUILDMercenaries' Guild No (but potentially)No station exists
MERCHANT GUILD Merchant's Guild No (but potentially)No station exists
STEEL RATS Steel Rats No (but potentially)Pirate faction - no station exists
ALWAYSHOSTILE (none) No Only for mines
ANTIPLAYER (none) No Only for mines and asteroid turrets
BRUST ARMS Brust Arms No No station exists / used for the story
CORRUPT POLICE Police No Canterville station / used for the story
DOUBLEJACKBAD DoubleJacks No Durgan seems to be the only member of this faction
FRIENDLY PIRATEPirate No Only Sandar and Tatiana
NEUTRAL Neutral No Used for general destroyable objects

5.1 Changing the factions that sell our ship

32_SHIPS_PLAYER_ZANDT.WDAT.lua

The factions that out ship is available to are defined in the 32_SHIPS_PLAYER_ZANDT.WDAT.lua file, all entries with the tag AVAILABILITY define one faction that will be able to sell the ship.

...or any other component if you wanted to add faction-specific weapons or shield generators or whatever.

Here's our current list of factions:

Faction StringDisplay Name
NEUTRAL Neutral
HUMAN NEUTRAL Commonwealth
PLAYER Independents (Player Base)
SMUGGLERS Independents
RED DEVIL Red Devils

5_1-32_SHIPS_PLAYER_ZANDT.WDAT.lua_Factions_before.jpg

As you can see, the NEUTRAL faction shows up there. And I have no clue why, they have no dockable station, where you could buy stuff from.
So we could safely remove this entry. Or keep it. It doesn't really matter.

One thing I will remove though is the HUMAN NEUTRAL entry, which is the Commonwealth faction, which is one of the main civilian faction in the game. It doesn't seem right to me that you would be able to buy a pirate ship in a "lawful" station.

The player base (PLAYER) we can leave in, every other ship is available there, so ours should as well.

And I think I will also leave SMUGGLERS / Independents in. They're not as lawful as the other civilian faction, so it does kind of make sense that you could buy some "different" hardware there.

RED DEVIL / Red Devils is a bit complicated. As we can see in the overview above, they're the only pirate faction that actually has stations (besides the DoubleJacks). So I guess it would make sense if they were able to sell a pirate ship.
... but the Zandt is a Steel Rats ship! They're not the Red Devils!

So we have a pro and a counter argument, so maybe let's take a look at the actual file that defines the factions and their relationship: MEDIA\FACTIONS\15_FACTIONS.DAT.lua. There we can see that the Red Devils and the Steel Rats are actually friendly to each other, so I guess we should indeed allow them to sell our ship.

5_1-15_FACTIONS.DAT.lua_Steel_Rats.jpg

Next, should we add a faction? The DoubleJacks for example? They're also a sort-of-pirate faction with a base.
But when we look at the faction file again, we can see they they are hostile towards the Steel Rats, so I guess that's a no then.

So in the end we have three factions that will sell our ship: SMUGGLERS, PLAYER, and RED DEVIL. Let's change our file.

5_1-32_SHIPS_PLAYER_ZANDT.WDAT.lua_Factions_after.jpg

  tags = {
    { --SHIP[3]
      n="AVAILABILITY",
      vars = {
        { n="FACTION", t="STRING", v=7 }, --> "PLAYER"
      }
    }, { --SHIP[4]
      n="AVAILABILITY",
      vars = {
        { n="FACTION", t="STRING", v=8 }, --> "SMUGGLERS"
      }
    }, { --SHIP[5]
      n="AVAILABILITY",
      vars = {
        { n="FACTION", t="STRING", v=9 }, --> "RED DEVIL"
      }
    }
  }

And that's basically it for the factions.

I have made some efforts to try to maybe set different prices for different factions (i.e. an "extra fee" for purchases in the non-pirate faction), but unfortunately with no luck.
I could add the ship as another id with a different price, and set the factions accordingly, but then you'd see the ship twice if you already owned one version of the ship and visited a station where the "other" ship was available.

Part 6: Ship Dealer Conversation

This step is also optional. If you now would go the Ship Dealer and select our ship, you would receive it immediately, without any further confirmation message. I find this a bit unintuitive and also it adds more flair to the game if you have an actual conversation with Stan... I mean the very reputable Ship Dealer.

Of course we won't have a speech output for our text (we could though if we recorded one...), but at least there'll be some text and a choice if you actually want to buy the ship.

The Ship Dealer conversations are in the MEDIA\CONVERSATIONS\SHIPYARD directory, each ship has its own file there. It doesn't really matter which file you choose as a template, I'll just use the first one, 15_SHIP_BLOODEAGLE.DAT.lua.

So go ahead and create a new directory structure x99_Flyable_Zandt\LUA\MEDIA\CONVERSATIONS\SHIPYARD and copy the file in there, then rename it to 15_SHIP_ZANDT.DAT.lua.

6.1 Setting the Text

15_SHIP_ZANDT.DAT.lua

We won't need to change much in this file. Entry [12] in the L table is the custom text we're going to edit, and entry [0] will be our ship's internal string.
If we go waaaay back to section 1.2, we had already defined this internal string to be SHIP_ZAND. So we need to use this here as well.

The last thing we need to do is to set the id of our new ship in the entry where the text line Yeah, let's make a deal. [BUY FOR %CREDITS CREDITS] appears (entry INTRO[6]). This id is currently set to the Blood Eagle, so we need to change it to the id of our Zandt, which was 990000001.

Oh, and of course we'll have to remove the sound that is playing for our custom text.

6_1-15_SHIP_ZANDT.DAT.lua_edit_1.jpg
6_1-15_SHIP_ZANDT.DAT.lua_edit_2.jpg

Entry Old Value New Value
[12] You've got a keen eye! The Bloodeagle... Choose something
[0] SHIP_BLOODEAGLE SHIP_ZANDT
INTRO[5] / Line 125 { n="SOUND", t="STRING", v=14 }, -- { n="SOUND", t="STRING", v=14 },
INTRO[5] / Line 130 { n="ID_OF_SHIP_TO_BUY", t="INTEGER", v=7847621 }, { n="ID_OF_SHIP_TO_BUY", t="INTEGER", v=990000001 },

6_1-15_SHIP_ZANDT.DAT.lua_edit_1_after.jpg
6_1-15_SHIP_ZANDT.DAT.lua_edit_2_after.jpg

As you can see, we just commented out the SOUND line, that's sufficient. We could've also just remove the line entirely.

When you now compile the mod, you should see the conversation when you try to buy the ship.

... Except when you're on your player base, the Bountiful Vista. For whatever reason there is no Ship Dealer, so you're always just getting any ship without conversation. So to test this, you'll have to be on another station, if you're not already.
And also keep in mind the faction of the station, we've limited this to Red Devils and Independents, so it has to be one of their stations.

6_1-Ship_Dealer_Conversation_1.jpg
6_1-Ship_Dealer_Conversation_2.jpg

Also note that we're actually getting money for the ship now when we're buying. Our ships' price is still set to 500 credits, but this shouldn't be the final price for such a powerful ship.
In the next section we're going to finish the mod (finally!).

Part 7: Finishing Touches

So we're almost finished now, what's left to do? We haven't added a real description for the ship yet, when browsing through the ships in the Ship Yard. We also haven't set the correct price yet, instead we used 500 credits so that we can easily test things.
And lastly the ship looks a bit too big for the stations, so we might want to play around with the scale a bit.

7.1 Ship Description

32_SHIPS_PLAYER_ZANDT.WDAT.lua

The ship description can be found in the 32_SHIPS_PLAYER_ZANDT.WDAT.lua file inside the COMPONENTS directory. Just think of something that fits the ship.

7_1-32_SHIPS_PLAYER_ZANDT.WDAT.lua_Ship_Description.jpg
7_1-32_SHIPS_PLAYER_ZANDT.WDAT.lua_Ship_Description_after.jpg

Entry Old Value New Value
[2] This is the description for the Zandt gunship. Choose something

7.2 Price

32_SHIPS_PLAYER_ZANDT.WDAT.lua

Conveniently the price is in the exact same file, just a few lines below.

Since this is a pretty good ship, I consider it an end-game ship, so I'll set the price to One Million Dollars... ehm, credits.
All your money has to go somewhere, doesn't it?

7_2-32_SHIPS_PLAYER_ZANDT.WDAT.lua_Price_before.jpg
7_2-32_SHIPS_PLAYER_ZANDT.WDAT.lua_Price_after.jpg

Entry Old Value New Value
n="PRICE" 500 1000000

Now, there's an optional tag where you could define the selling price for your ship. All of the regular ships do not have this tag set, so they sell for the exact same price as for what they can be bought (which is unrealistic in my opinion), so if you wanted to let's say add a 25% loss in value for the selling price, you'd add the following property right below the PRICE property: { n="PRICE_SELL", t="INTEGER", v=750000 },

7_2-32_SHIPS_PLAYER_ZANDT.WDAT.lua_Sell_Price.jpg

But I'm not going to actually use it, I just wanted to mention the possibility for such a feature.

7.3 Scale

15_ZANDT_PLAYER.DAT.lua

The scale can be set in 15_ZANDT_PLAYER.DAT.lua inside the SHIPS\PLAYERSHIPS directory.

Here's a comparison between different scales.

Scale 2.0 Scale 1.0 Scale 0.5
7_3-Scale_2.0_1.jpg 7_3-Scale_1.0_1.jpg 7_3-Scale_0.5_1.jpg
7_3-Scale_2.0_2.jpg 7_3-Scale_1.0_2.jpg 7_3-Scale_0.5_2.jpg
7_3-Scale_2.0_3.jpg 7_3-Scale_1.0_3.jpg 7_3-Scale_0.5_3.jpg
7_3-Scale_2.0_4.jpg 7_3-Scale_1.0_4.jpg 7_3-Scale_0.5_4.jpg
7_3-Scale_2.0_5.jpg 7_3-Scale_1.0_5.jpg 7_3-Scale_0.5_5.jpg

As you can see, also the camera position in cockpit and especially third person view is affected by changing the SCALE value. Therefore you shouldn't deviate too far from the original value, otherwise you would need to reconfigure your camera settings as well.

The thing is, we would need to go down to a SCALE of around 1.5 to make the ship somewhat comfortably fit into the station rooms:

7_3-Scale_1.5_1.jpg 7_3-Scale_1.5_2.jpg 7_3-Scale_1.5_3.jpg
7_3-Scale_1.5_4.jpg 7_3-Scale_1.5_5.jpg

Which then moves our cockpit and third person camera a bit too far down.

At this point you have three choices: ignore this, revert to the 2.0 scale, or adjust the camera positions (again).

I'm going to adjust the camera positions.

7.4 Third Person Camera Position (Chase Camera)

15_ZANDT_PLAYER.DAT.lua

This is relatively easy, in our 15_ZANDT_PLAYER.DAT.lua file there is a CHASE_CAM_VERTICAL_MULT property, which currently has the value 2.5.
Changing this to 1.7 seems to work pretty well.

7_4-15_ZANDT_PLAYER.DAT.lua_Chase_Cam_1,7.jpg

Entry Old Value New Value
n="CHASE_CAM_VERTICAL_MULT" 2.5 1.7

SCALE 2.0 / CHASE_CAM_VERTICAL_MULT 2.5 SCALE 1.5 / CHASE_CAM_VERTICAL_MULT 2.5 SCALE 1.5 / CHASE_CAM_VERTICAL_MULT 1.7
7_3-Scale_2.0_4.jpg 7_3-Scale_1.5_4.jpg 7_3-Scale_1.5_4_CHASE_CAM_VERTICAL_MULT_1.7.jpg

Another value that might be interesting here is the DOLLY_MULT property, which seems to define distance to the craft when in third person view.
I don't know if it has any other effect, the name of the property is ambiguous.

7_4-15_ZANDT_PLAYER.DAT.lua_DOLLY_MULT.jpg

DOLLY_MULT 0.75 (Original) DOLLY_MULT 0.30 (Closer) DOLLY_MULT 1.50 (Further Away)
7_3-DOLLY_MULT_0.75.jpg 7_3-DOLLY_MULT_0.30.jpg 7_3-DOLLY_MULT_1.50.jpg

So we might increase our DOLLY_MULT slightly. But as I discovered the effect of this property only after I had already finished the tutorial (and the mod), I just left it at 0.75. It's fine, although maybe not optimal.

7.5 Cockpit Camera

16_COCKPIT_ZANDT.LAYOUT.lua

The cockpit camera is not as easy, we've already discussed this in step 3.2.

So we need to go back to 16_COCKPIT_ZANDT.LAYOUT.lua and change the Y-value again for each entry.
Instead of +5, I'm going for +7 now, so add another 2 to each Y-value in there (that you care about).

See step 3.2 for more details.

So with that out of the way, this basically means our mod is finished!
Compile the mod with `rgo-deploy`, or alternatively, just create the .pak with `rgo-pack 1.0.0`, zip the file and publish your mod!

Part 8: More Information

Here will be some more information and fine tuning possibilities.

8.1 Vertical Position of the Ship in a Station

15_ZANDT_PLAYER.DAT.lua

Some ships need an additional property to set to display correctly in the station, otherwise they may float in the air or clip with the floor, aptly named SHIP_ABOVE_STATION_FLOOR in 15_ZANDT_PLAYER.DAT.lua.

7_4-15_ZANDT_PLAYER.DAT.lua_Station_Floor_8.5.jpg

SCALE 8.5 - Original SCALE 0.0 - Clipping the Floor SCALE 20.0 - Hovering
7_4-Station_Floor_8.5_1.jpg 7_4-Station_Floor_0.0_1.jpg 7_4-Station_Floor_20.0_1.jpg
7_4-Station_Floor_8.5_2.jpg 7_4-Station_Floor_0.0_2.jpg 7_4-Station_Floor_20.0_2.jpg
7_4-Station_Floor_8.5_3.jpg 7_4-Station_Floor_0.0_3.jpg 7_4-Station_Floor_20.0_3.jpg

A value of 8.5 seems to have been a pretty good fit for us to begin with, so we're leaving it this way.

8.2 Rotation

LAYOUT files

In .LAYOUT.lua files you will find ROTATIONS entries, with 4 sub entries.
The rotation is divided up in 4 entries, which is not what you might have expected (if you don't have a 3D-modelling background). This is called a Quaternion, where [1] is the Quaternion's X entry, [2] is Y, [3] is Z, and [4] is W.

For example, this rotation:

["ROTATIONS"] = {  -- X, Y, Z, W (Quaternion)
    [1] = -0.57589799165726,
    [2] = 0.40224999189377,
    [3] = 0.38844799995422,
    [4] = 0.59636002779007,
},

Would represent the following human-readable 3-coordinate system (in degrees):

X: -88.000012078056°
Y:  -0.000011737393°
Z:  68.000034790779°

Or in a different notation:

ROLL:  -88.000012078056°
PITCH:  -0.000011737393°
YAW:    68.000034790779°

The math for converting a Quaternion into a human-readable 3-coordinate system is non-trivial, you can read up on it here:
http://www.opengl-tutorial.org/intermediate-tutorials/tutorial-17-quaternions/
https://en.wikipedia.org/wiki/Conversion_between_quaternions_and_Euler_angles
https://www.euclideanspace.com/maths/geometry/rotations/conversions/quaternionToEuler/index.htm
https://www.euclideanspace.com/maths/geometry/rotations/conversions/eulerToQuaternion/index.htm

One of these calculators could help when you want to do a rotation:
https://quaternions.online/
https://www.andre-gaschler.com/rotationconverter/
https://danceswithcode.net/engineeringnotes/quaternions/conversion_tool.html

I actually experimented with adding a conversion function that would display the so called "Euler Angles" instead (in form of X, Y, Z, or resp. YAW, PITCH, ROLL), however when converting between a Quaternion and Euler Angles there's always the possibility of ambiguity, and so a "bit-perfect" conversation between the LAYOUT and LUA file wasn't possible anymore, which is why I decided against it.

So if you want to change the rotation of something, you'll have to do it the hard way by using one of the calculators yourself (or copying already existing rotations).

8.3 Properties of all Player Ships

Here I collected the values for each player ship, so that you have a reference when creating new ones.

Property Beluga SPZ Coyote Blood Eagle Dingo Durston Foxbat Mattock Medium Platypus Sequoia Sonora
$246127522 38 38 0 124 253 209 174 32 0 38 0 255
$246127527 167 167 132 209 111 108 97 150 132 167 241 134
$246127538 53 53 255 107 77 0 82 255 255 53 196 136
$406838784 28 26 32 26 32 28 32 24 24 22 22 22
$975523302 1 1 1 1 1 1 1 1 1 1 1 1
$975523302 9 16 3 7 3 4 16 5 2 8 6
$975523302 16 10 16 16 16 16 11 12 16 16 16 16
$1326435861 120 120 140 70 140 120 140 150 70 100 100 100
$1571785301 1 1 1 1 1 1 1 1 1 1 1 1
$1571785301 4 2 2 2 2 4 2 2 2 2 2 2
$1632421509 2.5 2.5 2.5 2.5 2.5 2.5 2.5 2.5 2.5 2.5 2.5 2.5
$2970562126 true true true true true true true true true true true true
ACCELERATION 120 150 150 180 150 120 150 150 180 150 150 150
CAN_USE_AFTERBURNER true true true true true true true true true true true true
CARGOCOUNTMAX 1 1 1 1 1 1 1
CARGOCOUNTMIN 1 1 1 1 1 1 1
CHASE_CAM_VERTICAL_MULT 2.5 1.2000000476837 2 1.6499999761581 2 2.5 2 2 1.6499999761581 1.2000000476837 2.5 2.5
CORE_HEALTH 550 450 400 450 440 550 350 480 450 300 450 450
CRUISE_SPEED_PERCENTAGE 0 0 0 0 0 0 0 0 0 0 0 0
DEFLECTOR_DRAIN 1 1 1 1 1 1 1 1 1 1 1 1
DEFLECTOR_ENERGY 0 0 0 0 0 0 0 0 0 0 0 0
DEFLECTOR_RECHARGE 0 0 0 0 0 0 0 0 0 0 0 0
DOLLY_MULT 0.75 1.6000000238419 0.85000002384186 1.0499999523163 0.85000002384186 0.75 0.85000002384186 0.85000002384186 1.0499999523163 1.6000000238419 0.92500001192093 0.92500001192093
HOLD 20 12 5 6 8 24 5 15 6 10 16 12
HULL_MAX 0 0 0 0 0 0 0 0 0 0 0 0
HULL_MULT 1.5 1.25 1.5 1.25 1.3999999761581 1.2000000476837 1.2000000476837
INERTIAL_DAMP 0.014999999664724 0.014999999664724 0.004999999888241 0.004999999888241 0.004999999888241 0.014999999664724 0.004999999888241 0.014999999664724 0.004999999888241 0.014999999664724 0.014999999664724 0.014999999664724
LINKED_QUADRANTS false false false false false false false
MASS 80 58 60 50 65 80 56 72 50 50 67 67
MAX_BANK 40 40 40 40 40
MAX_CARGO_RANK 3 2 1 0 2 3 1 3 1 1 3 2
MAX_ENGINE_RANK 4 2 4 4 4 4 4 4 2 2 3 2
MAX_PITCH_RATE 60 85 100 110 95 60 100 80 110 70 85 80
MAX_ROLL_RATE 90 100 160 180 140 90 150 130 180 120 150 140
MAX_SHIELD_RANK 4 3 4 3 4 4 4 4 2 2 3 2
MAX_YAW_RATE 70 90 100 110 95 70 95 80 110 80 85 80
PITCH_ACCELERATION 60 100 110 120 100 60 110 120 120 100 140 130
PITCH_DECAY 0.009999999776483 0.009999999776483 0.009999999776483 0.009999999776483 0.009999999776483 0.009999999776483 0.009999999776483 0.009999999776483 0.009999999776483 0.009999999776483 0.009999999776483 0.009999999776483
ROLL_ACCELERATION 90 160 200 220 180 90 200 140 220 160 160 160
ROLL_DECAY 0.009999999776483 0.009999999776483 0.009999999776483 0.009999999776483 0.009999999776483 0.009999999776483 0.009999999776483 0.009999999776483 0.009999999776483 0.009999999776483 0.009999999776483 0.009999999776483
SCALE 2 2 2 2 2 2 2 2 2 2 2 2
SHIELD_MAX 0 0 0 0 0 0 0 0 0 0 0 0
SHIELD_MULT 1.5 1.25 1.5 1.3999999761581 1.2000000476837 1.2000000476837
SHIELD_RECHARGE 0 0 0 0 0 0 0 0 0 0 0 0
SHIELD_RECHARGE_DELAY 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5
SHIP_ABOVE_STATION_FLOOR 8.5 4.5999999046326 4.0999999046326 8.5 4.5999999046326 4.0999999046326 4.5999999046326 4.5999999046326 4.5999999046326
SUGGESTED_SHIELD_RADIUS 24 12 24 20 24 24 24 12 20 12 12 12
THROTTLE_SPEED 1 1 1 1 1 1 1 1 1 1 1 1
TOP_SPEED 300 370 430 440 400 300 400 350 440 360 380 370
TRAIL_SIZE 6 6 6 6 6 6 6 6 6 6 6 6
TRAIL_TYPE 0 0 0 0 0 0 0 0 0 0 0 0
WARP_MULT 800 800 800 800 800 800 800 800 800 800 800 800
YAW_ACCELERATION 60 100 110 120 100 60 110 120 120 100 140 130
YAW_DECAY 0.009999999776483 0.009999999776483 0.009999999776483 0.009999999776483 0.009999999776483 0.009999999776483 0.009999999776483 0.009999999776483 0.009999999776483 0.009999999776483 0.009999999776483 0.009999999776483
Weapon Hardpoints 4 1 6 4 4 4 5 4 4 2 3 3
Missile Hardpoints 2 1 2 2 4 2 1 2 1 1 2 1

As you can see, the meaning of some values are still unknown, and not all ship has all the properties set. The missing properties probably fall back to some default value.

Credits

  • hhrhhr for creating the original mod tools, without him none of this would've been possible
  • Ross_R of the RGO Discord channel, who made me double check the weapon hardpoints
  • DoubleDamage for creating the game
  • Anybody reading this lengthy tutorial

Changelog

  • 2022-10-28
    Fixed two broken internal links.
  • 2022-08-01
    Added DOLLY_MULT and more information about turrets.
  • 2022-07-30
    Initial Release