Skip to content

Creating Ship Templates

Xansta edited this page Feb 24, 2022 · 14 revisions

Ships in EmptyEpsilon are defined by ship template scripts, which are located in a set of ship template script files. A ship template script sets a ship's name, class, model, radar icon, speed, maneuverability, weapons, and defenses.

Unlike scenario scripts, ship template scripts are loaded when you launch EmptyEpsilon. While you can modify some traits of an existing ship template in a scenario script, you cannot create new ship types from scratch in a scenario script --- you must create them in a ship template script.

Note: If you want to create a new ship in a single scenario that uses the same model as an existing ship, it might be easier to simply create a variant of an existing ship's template. For details, see Creating a Variant Ship Template.

Locating ship template script files

There are several ship template script files in EmptyEpsilon's scripts directory that define ships:

  • shipTemplates_StarFighters.lua: Light fighter-class ships, such as the MT52 Hornet.
  • shipTemplates_Frigates.lua: Small capital ships, such as the Phobos T3.
  • shipTemplates_Corvette.lua: Medium capital ships, such as the Atlantis X23.
  • shipTemplates_Dreadnaught.lua: Heavy capital ships, such as the Odin. (And for now, only the Odin.)

Each of these files are loaded by the base shipTemplates.lua file. Any modifications you make to ships in these files are loaded when you launch EmptyEpsilon.

Note: There are two more ship template script files that we won't get into here:

  • shipTemplates_Stations.lua: Defines space stations.
  • shipTemplates_OLD.lua: Defines legacy ships.

Ships in the OLD file are deprecated and might be moved or removed in a future version. When making scenarios, avoid using ships in this file as they might not be available in future versions of EmptyEpsilon.

Adding a ship template script file

The easiest way to add new ship templates to EmptyEpsilon is to create a new ship template script file, then add that file to the shipTemplates.lua list.

Note: If you modify the default ship template script files, updating EmptyEpsilon might overwrite or delete your changes.

The shipTemplates.lua file contains lines like this:

require("shipTemplates_StarFighters.lua")

To add a ship template file, add a similar line to shipTemplates.lua with a different file name, such as:

require("shipTemplates_Custom.lua")

Then create a text file by that name in EmptyEpsilon's scripts folder.

Creating a ship template

In your ship template file, create a ship template with this line of code:

template = ShipTemplate():setName("NX-01 Initiative"):setClass("Corvette", "Destroyer"):setModel("battleship_destroyer_1_upgraded")

Let's break this line down piece by piece.

  • template is a variable name that we'll use to set other ship traits.
  • ShipTemplate() defines this variable as a ship template. It's required.
  • setName("NX-01 Initiative") sets the ship template's name. This is what appears as the ship's model everywhere in the game. Note that this is different from a specific ship's callsign, which is either automatically generated when the ship is created, set by a scenario script, or set by the Game Master.
  • setClass("Corvette", "Destroyer") sets the ship template's class (Corvette) and subclass (Destroyer). A ship template can use classes to determine how certain types of ships interact with each other. For instance, to allow Starfighter-class ships to dock with ships of a certain template, you'd add setDockClasses("Starfighter") to the carrier's template. While you can set any class and subclass that you want here, the common classes and subclasses are:
    • "Starfighter"
      • "Interceptor"
      • "Gunship"
      • "Bomber"
    • "Frigate"
      • "Cruiser"
      • "Cruiser: Anti-fighter"
      • "Cruiser: Light Artillery"
      • "Cruiser: Strike ship"
      • "Cruiser: Sniper"
      • "Light transport"
    • "Corvette"
      • "Destroyer"
      • "Support"
      • "Freighter"
    • "Dreadnaught"
      • "Odin"
  • setModel("battleship_destroyer_1_upgraded") sets the 3D model used to depict the ship. Models are defined in the model_data.lua script file in the scripts folder; see Adding 3D Models.

While this line of code creates a new ship template, this ship is incomplete. Let's use the template variable to complete this template:

template:setRadarTrace("radar_dread.png")
template:setHull(100)
template:setShields(200, 200, 200, 200)
template:setSpeed(30, 3.5, 5)

Each of these lines extends the template with a new feature.

  • template:setRadarTrace("radar_dread.png") sets the image that represents this ship on radar screens. This file should be in EmptyEpsilon's resources folder.
  • template:setHull(100) sets the ship's hull value.
  • template:setShields(200, 100, 200, 100) sets the ship's shields. A ship's shields are arranged like equal-sized slices of a pie chart, with the first value representing the front shields and proceeding in clockwise order. For instance, in this example the ship has front, right, rear, and left shields, with stronger front and rear shields (200) than left and right shields (100). If a ship template has a single shield value, shields of ships with that template are reduced equally when attacked from any angle.
  • template:setSpeed(30, 3.5, 5) sets the ship's impulse speed and maneuverability.
    • The first value (30) is the ship's maximum impulse speed.
    • The second value (3.5) is the ship's rotation rate.
    • The third value (5) is the ship's acceleration rate. (TODO: Define these rates better.)

This gives us a minimally functional ship. If you'd like, you can save this ship template script file, load the game, enter a scenario, and enter the Game Master screen. You should be able to add an "NX-01 Initiative" Corvette to the scenario, give it orders, and watch it fly around.

However, this ship is unarmed. Let's give it some firepower:

--                  Arc, Dir, Range, CycleTime, Dmg
template:setBeam(0,100, -20, 1500.0, 6.0, 8)
template:setBeam(1,100,  20, 1500.0, 6.0, 8)
template:setBeam(2,100, 180, 1500.0, 6.0, 8)

template:setBeam(0, 100, -20, 1500.0, 6.0, 8) adds a beam weapon. Each value defines a trait of the weapon. In order, these traits are:

  • Its ID number (0).
  • Its arc in degrees (100).
  • Its direction in degrees relative to the front of the ship (-20). Note that the arc extends with the direction in its center. In this example, the beam weapon is pointed 20 degrees to the left of the ship's forward facing, and its arc extends 50 degrees to each side of that direction.
  • Its range in milliUnits (1500.0). This range of 1500 is equal to 1.5U.
  • Its cycle time in seconds (6.0). Once fired, the beam takes this long to cool down before it can fire again.
  • Its base damage (8). Each hit does this amount of base damage, which might be modified by things like a target's shields, or the degree to which the ship's beam frequency aligns with the target's shield frequency.

Each of these lines adds a new beam weapon. Note that each line has a unique ID number. A ship's beams should be defined in order, starting with 0 for the first beam, 1 for the second beam, and so on.

If you want to test this ship's beams, remember that you can save the template, load a new scenario, and add this ship from the Game Master screen.

Next, let's add some weapon tubes:

template:setTubes(4, 10.0)
template:setWeaponStorage("HVLI", 20)
template:setWeaponStorage("Homing", 4)
template:setTubeDirection(0, -90)
template:setTubeDirection(1, -90)
template:setTubeDirection(2,  90)
template:setTubeDirection(3,  90)

template:setTubes(4, 10.0) adds four weapon tubes (4), and sets the time it takes to load a tube to 10 seconds (10.0).

The next lines define those tubes, as well as the ship's weapon storage capacity:

  • template:setWeaponStorage("HVLI", 20) and template:setWeaponStorage("Homing", 4) set the ship's HVLI and homing missile capacity, respectively, to 20 HVLI and 4 homing missiles.
  • template:setTubeDirection(0, -90) sets the first weapon tube's direction in degrees relative to the front of the ship. In this instance, the first and second weapon tubes are aimed off the left side of the ship (-90), and the third and fourth tubes are aimed off the right side (90).

Finally, let's accessorize and describe our ship:

template:setJumpDrive(true)
template:setDescription([[The NX-01 Initiative is an experimental corvette model.

Only its designers know what it's truly capable of achieving.]])

template:setJumpDrive(true) adds a jump drive to the ship with a default range of 50U. If you want to change its range, use the setJumpDriveRange() script function. For instance, this sets the jump drive range to 100U (100000), and instructs the ship to not engage its jump drive to travel distances of less than 5U (5000):

template:setJumpDriveRange(5000, 100000)

template:setDescription(...) sets the text that appears in the Database View for this ship model. Note that it uses two square brackets ([[), which allows the text to contain line breaks.

Creating Player Ships

TODO

Player ships also need rooms depicting the ship's interior, which are used on the engineering screen for repair crew management. Use the addRoom, addRoomSystem (to make rooms for a ship system), and addDoor functions to accomplish this.

An illustration depicting the relationship between the addRoom, addRoomSystem, and addDoor ship template functions.

Creating a Variant Ship Template

This section describes how to create a ship template on the fly in a scenario script without having to update any of the shipTemplate... files. This allows you to put "new" ships in the game without requiring all the clients to have identical copies of the shipTemplate... files.

Non-Player ships

Find a template to base your new ship on. I usually go by the 3D model since that's something you cannot change when you are creating a variant. You'll want to consider the size of what you're creating, too. Let's look at one of the commonest models, the Adder MK5.
Screen Shot 2022-02-23 at 4 41 30 PM
You can find it in the shipTemplates_StarFighters.lua file. The first line of the definition has the model name: template = ShipTemplate():setName("Adder MK5"):setLocaleName(_("Adder MK5")):setClass(_("Starfighter"), _("Gunship")):setModel("AdlerLongRangeScoutYellow") ... AdlerLongRangeScoutYellow

To get the best from your variant design, it's a good idea to look at the model entry, too. You'll find it in the model_data.lua file. If you search for "AdlerLongRangeScoutYellow" you won't find it. That's because there are several model groups that vary only by color. Search for "AdlerLongRangeScout" instead. The lines we are particularly interested in are these:

-- Visual positions of the beams/missiletubes (blender: -X, Y, Z)
model:addBeamPosition(1.8, 0, 0.03)
model:addBeamPosition(1.8, 0.13, 0.03)
model:addBeamPosition(1.8,-0.13, 0.03)
model:addTubePosition(1.8, 0, 0.03)

These tell us that the model assumes that beams and tubes will appear in a particular place when defined in a particular order. The non-3D screens (eg Helm, Weapons) rely heavily on the Y value. Zero represents the front, center of the ship. Notice that for the beams, the X and Z values are all the same. The first Y value is zero, the second Y value is positive and the third Y value is negative. If all of these values were zero or they were not defined, the beams would come out of the middle of the ship model. These Y values tell us that the first beam defined (index zero) will come out in the center, the second beam defined (index 1) will come out on the positive side of the ship (starboard, angle 5 to 45 would look good) and the third beam defined (index 2) will come out on the negative side of the ship (port, angle 315 to 35 or -5 to -45 would look good). So, when we define the direction of the beams, we should keep these beam positions in mind. The tube exit is in the same position as the first beam exit.

Beam Weapons

Let's modify the Adder MK5 to have a longer, narrower center beam.

local ship = CpuShip():setTemplate("Adder MK5")
--             Index,  Arc, Dir, Range, Cycle, Damage
ship:setBeamWeapon(0,   20,   0,  1000,   5.0, 2.0)	--narrower (vs 35) and longer (vs 800)

Before Screen Shot 2022-02-23 at 5 06 16 PM After Screen Shot 2022-02-23 at 5 06 56 PM
Notice that all the beam weapon parameters were required to be entered. I usually have the original specifications nearby so I can reference the numbers and have an idea of what the results of my changes will be. I also like adding a comment out to the side noting the original value(s). The comment line preceding the setting of the beam weapon values helps me remember which values go in which slots:

Parameter Position Short comment name Example Value Description
1 Index 0 Which beam. Starts numbering at zero
2 Arc 20 Beam coverage in degrees. 360=full coverage
3 Dir 0 Beam facing direction. 0=forward, 180=back
4 Range 1000 How far the beam reaches. 1000=one unit
5 Cycle 5.0 Recharge time in seconds at 100% power
6 Damage 2.0 How much damage the beam inflicts when it hits

It is useful to get visuals for the beams from the GM screen. I recommend the Empty Space scenario in this case.
Select the GM screen via the Game master button: Screen Shot 2022-02-24 at 9 54 48 AM
Spawn your base template with the Create... button: Screen Shot 2022-02-24 at 9 56 49 AM
Choose template, scroll if necessary: Screen Shot 2022-02-24 at 10 01 12 AM
Click in an open area to create an instance of your base template. After it's been created clicking the Cancel button to stop creating additional instances: Screen Shot 2022-02-24 at 10 13 58 AM
Select ship. I recommend a box drag: Screen Shot 2022-02-24 at 10 19 47 AM
Idle ship with the Idle button so that it does not move around: Screen Shot 2022-02-24 at 10 24 54 AM
Tweak the ship with the Tweak button: Screen Shot 2022-02-24 at 10 24 08 AM
Chose the Base tweak options: Screen Shot 2022-02-24 at 10 28 35 AM
Set heading to 360 (0 = 360): Screen Shot 2022-02-24 at 10 29 08 AM
Choose the beams tweak options: Screen Shot 2022-02-24 at 10 34 48 AM
Change parameters on selected beam: Screen Shot 2022-02-24 at 10 35 20 AM
Change selected beam (numbering starts at 1): Screen Shot 2022-02-24 at 10 40 55 AM
Watch the graphic change with the visual parameter changes: Screen Shot 2022-02-24 at 10 44 03 AM

Missile Weapons

Number of Missile Tubes

Use setWeaponTubeCount(number_of_tubes) to change the number of missile tubes. For example, to add two tubes to the Adder MK5's standard one tube would look like this:

local ship = CpuShip():setTemplate("Adder MK5")
ship:setWeaponTubeCount(3)	--more (vs 1)
Missile Tube Facing Direction

By default, a tube points in direction 0 or forward. Use setWeaponTubeDirection(index,direction) to change the direction a tube faces. For example, if we add two tubes to the Adder MK5's standard one tube and we want them to be slightly angle from pointing straight forward, we might do something like this:

local ship = CpuShip():setTemplate("Adder MK5")
ship:setWeaponTubeCount(3)        --more (vs 1)
ship:setWeaponTubeDirection(1, 5)
ship:setWeaponTubeDirection(1,-5)

This example leaves the first tube (index 0) pointing straight forward, points the second tube 5 degrees to the right and the third tube 5 degrees to the left.

Be sure to follow the model placement when you make your variant. The current Phobos templates run counter to the tube placement on the model. From model_data.lua for the AtlasHeavyFighter... model used by the Phobos:

-- Visual positions of the beams/missiletubes (blender: -X, Y, Z)
model:addBeamPosition(2.4, 0.1, -0.25)
model:addBeamPosition(2.4,-0.1, -0.25)
model:addTubePosition(1, 0.4, 0)
model:addTubePosition(1,-0.4, 0)
model:addTubePosition(-1, 0, 0)

Notice that the first tube has a positive Y value and the second tube has a negative Y value. The following lines are the tube definitions for the Phobos T3 from shipTemplates_Frigates.lua:

template:setTubeDirection(0, -1)
template:setTubeDirection(1,  1)

Notice that the negative value (-1) is defined for tube zero where the model places the tube on the positive side. Similarly, the positive value (1) is defined for the second tube which the model places on the negative side. This has the effect of having the missiles cross each other in front of the Phobos when they fire. You can see this when you board the Phobos M3P as a player on Weapons, load up missiles and see the projected missile paths cross in front of the ship. I'm not sure if this is intentional or not, but I suggest you avoid the crossover effect and match the tube definition with the visual placement of the model.

More Missiles

The template defines how many missiles are loaded onto a ship. Use setWeaponStorageMax(type, amount)andsetWeaponStorage(type, amount)` to change the default amount. For example, to give the Adder MK5 more HVLIs, you could do this:

local ship = CpuShip():setTemplate("Adder MK5")
ship:setWeaponStorageMax("HVLI", 20)        --more (vs 4)
ship:setWeaponStorage("HVLI", 20)

Note: The section says more missiles, but you can put fewer missiles on your variation using the same functions

More Missile Types

The template defines what kind of missiles a tube can shoot. By default a tube can shoot any kind of missile. So the simplest way to add a missile type to your variant is to add load those missiles on just like when you added more missiles of a type already in use on the base template:

local ship = CpuShip():setTemplate("Adder MK5")
ship:setWeaponStorageMax("Homing", 4)        --more (vs 0)
ship:setWeaponStorage("Homing", 4)

However, the template may restrict certain tubes to certain missile types or you may want your newly defined tubes to only shoot certain types of missiles. Why? The AI loads missiles in tubes in a particular order. By constraining a tube to a limited number of missile types, you can essentially change that order and get a mixture of missile types flying simultaneously. In the previous example, where we added homing missiles to the Adder MK5, those homing missiles would get loaded and fired first, then the HVLIs would get loaded and fired after the variant ran out of homing missiles.

To limit or expand the types of missiles a tube can fire, use setWeaponTubeExclusiveFor(index, type) or weaponTubeAllowMissle(index, type). If you wanted your variant to fire two kinds of missiles simultaneously, you might, for example, define your variant this way:

local ship = CpuShip():setTemplate("Adder MK5")
ship:setWeaponTubeCount(3)                  --more (vs 1)
ship:setWeaponTubeExclusiveFor(0,"HVLI")    --only HVLI (vs any)
ship:setWeaponStorageMax("Homing", 4)       --more (vs 0)
ship:setWeaponStorage("Homing", 4)

This example does not show the use of weaponTubeAllowMissle(index, type) but you might use that to allow a missile type for a tube that the base template currently restricts that type, or you may want a newly defined tube to shoot two and only two types of missiles while other tubes shoot other types of missiles. Those are the typical use cases for weaponTubeAllowMissle(index, type).

Remember, when you change the number of tubes, the base template definitions still apply. You will need to change those definitions if you want your variant's tubes to behave differently.

Different Missile Sizes

The base template tube zero is defined to shoot small missiles. The default for tubes is to shoot medium sized missiles. Thus, in our previous example, we added two tubes to shoot medium sized homing missiles. Use setTubeSize(index, size) to change the size of missile a tube fires. Based on our previous example, if we wanted the new tubes to also shoot small missiles, we might define our variant like this:

local ship = CpuShip():setTemplate("Adder MK5")
ship:setWeaponTubeCount(3)                  --more (vs 1)
ship:setTubeSize(1, "small")
ship:setTubeSize(2, "small")
ship:setWeaponTubeExclusiveFor(0,"HVLI")    --only HVLI (vs any)
ship:setWeaponStorageMax("Homing", 4)       --more (vs 0)
ship:setWeaponStorage("Homing", 4)

The three valid values for missile sizes are small, medium and large.

Different Tube Loading Time

The base template defines one tube loading time for all tubes. Use setTubeLoadTime(index, seconds) to change a tube's load time. If you wanted to a tube to your Adder MK5 variant that shot medium sizes missiles instead of small sized missiles, but you wanted it to take longer to load, you might do something like this:

local ship = CpuShip():setTemplate("Adder MK5")
ship:setWeaponTubeCount(2)    --more (vs 1)
ship:setTubeLoadTime(1, 20)   --longer (vs 15)
Clone this wiki locally