Table of Contents

Tracks and Streets

Tracks and streets are defined by config files in the res/config/track/ or res/config/street/ folders.

Tracks

A track configuration file specifies a set of parameters to define the properties, dimension, features and visuals of tracks. They are stored in .lua files in the folder res/config/track/.

The file has the following format:

function data()
return {
    -- name, description, availability
    -- shape configuration
    -- ballast configuration
    -- sleeper configuration
    -- rail configuration
    -- catenary configuration
    -- track configuration
    -- speed configuration
    -- radius and slope configuration
    -- materials, models, textures configuration
    -- cost configuration
}
end

Name, description, availability

The following properties are used for general purposes:

t.name = _("High-speed tracks")
t.desc = _("Specialized tracks for higher speeds")
 
t.categories = { "1435mm", }
 
t.yearFrom = 1925
t.yearTo = 0

Shape configuration


shapeStep = 5 and shapeStep = 1

Shapes represent the base geometry of the tracks and are used for collision tests, terrain alignment generation and generation of the procedural geometry.

t.shapeWidth = 4.0                -- [m] shape width
t.shapeStep = 4.0                 -- [m] shape step
t.shapeSleeperStep = 8.0 / 13.0   -- [m] distance between sleepers

The width should be high enough to contain the actual procedural geometry. The step size allows for smoother curves (small) or less geometric primitives (high), which speed up collision checks. Tracks that allow a small minimal radius and have a small track width should tend to smaller shapeSteps to avoid corners in the tracks.

Ballast configuration


ballastCutOff = 0.5 and ballastCutOff = 0.1

Ballast is the bed for track usually made from crushed stone. The height and material (see below) can be configured.

t.ballastHeight = .3  -- [m] height of the ballast
t.ballastCutOff = .1  -- [m] cut off profile 

The ballastCutOff can be used to influence the steepness of the ballast sides. 0.1 is relatively steep, 0.5 is not as steep but the horizontal top part is reduced so the ends of sleepers get nearer the ballast bed edges.

Sleeper configuration

static models and procedurally generated ones

Sleepers (or ties) are the rail supports usually made from wood, concrete or steel. The dimension and material (see below) can be configured. These settings are only used for procedurally generated sleepers at switches and crossings. Normal sleepers use the static models (see below).

t.sleeperBase = ballastHeight -- [m] bottom height from ground level
t.sleeperLength = .24         -- [m] length of the sleeper along track
t.sleeperWidth = 2.6          -- [m] width of the sleeper
t.sleeperHeight = .08         -- [m] height of the sleeper
t.sleeperCutOff = .04         -- [m] cut off profile 

The sleeperCutOff property is used to define the cut off angle for the sleepers. Usually it is higher for steel sleepers.

Rail configuration

static models and procedurally generated ones

The rail configuration is used for switches and crossings. Along normal tracks, the static models are used (see below)

t.railTrackWidth = 1.435       -- [m] track gauge (space between rails)
t.railBase = sleeperBase + .08 -- [m] base height from ground level
t.railHeight = .15             -- [m] height of the rail
t.railWidth = .07              -- [m] width of the rail
t.railCutOff = .02             -- [m] cutoff profile

The railCutOff property is used to define the cut off angle for the rail. Usually it is very low. Be aware that changing the railWidth of existing track types may lead to compatibility problems in savegames.

Catenary configuration

Electrified tracks need catenary for the power transfer. The poles are instances of a model, whereas the cable is procedurally generated.

t.catenaryBase = 5.917 + railBase + railHeight -- [m] base height of the cable over ground level
t.catenaryHeight = 1.35                        -- [m] height of the support cable at the poles
t.catenaryPoleDistance = 25.0                  -- [m] target distance between poles
t.catenaryMaxPoleDistanceFactor = 2.0          -- factor for maximum pole distance
t.catenaryMinPoleDistanceFactor = 0.8          -- factor for minimal pole distance (in curves)

Track configuration

It is possible to drag parallel with this distance from an existing track.

    trackDistance = 5.0   -- [m] distance between track centers

Be aware that a trackDistance other than 5 meters might result in problems with the ballast track bed and catenary pole gantry generation.

Speed configuration

The maximum speed on straight segments is speedLimit, and on curved segments calculated according the formula below.

    speedLimit = 300.0 / 3.6        -- [m/s] maximum speed on a straight track
    speedCoeffs = { .9, 15.0, .63 } -- curve speed limit = a * (radius + b) ^ c

Radius and slope configuration

In Transport Fever 2 it is possible to set a minimal radius as well as maximum steepnes of slopes to realize narrow gauge railways with thight curves and steep rails in the mountains.

t.minCurveRadiusBuild = 60.0         -- [m] minimal radius when dragging
t.minCurveRadius = 44.0              -- [m] minimal radius when snapping (and parallel tracks)
 
t.maxSlopeBuild = 0.075
t.maxSlope = t.maxSlopeBuild * 1.6
t.maxSlopeShape = t.maxSlope * 1.25
 
t.slopeBuildSteps = 2                -- [1-4] steps for slope arrow buttons

The minimal radius is set by the two first properties in this section. The first one is used when tracks are dragged free on the map. The second is relevant for the snapping along or to other tracks, e.g. at switches and parallel tracks.

The maximum slope is defined by three values. maxSlopeBuild is the slope of a straight line between start and end point 1. maxSlope is the limit for the track curve that aligns to the slopes of tracks at the start and end point 2. maxSlopeShape is the limit for the actual track that may be displaced by intersecting roads or crossing tracks 3.

slopeBuildSteps is the number of steps that are available with the fixed slope arrow buttons . The more steps, the smaller they are.

Material configuration

The procedurally generated parts of the tracks use the following materials:

t.ballastMaterial =    "track/ballast.mtl"           (1)
t.sleeperMaterial =    "track/sleeper_concrete.mtl"  (2)
t.railMaterial =       "track/rail.mtl"              (3)
t.catenaryMaterial =   "track/catenary.mtl"          (4)
t.tunnelWallMaterial = "track/tunnel_rail_ug.mtl"    (5)
t.tunnelHullMaterial = "track/tunnel_hull.mtl"
 
t.fillGroundTex =      "ballast_fill.lua"            (6)
t.borderGroundTex =    "ballast.lua"                 (7)

fillGroundText is used for the area below the track to blend the ballast better to the terrain. borderGroundTex is the ground texture that is used for the border along the track ballast. tunnelHullMaterial is the material for the outside of the tunnel (that normally is not visible at all).

Model configuration

For normal tracks (except switches and crossings), static models are used. There are additional models for the catenary and bumper and switch signals which are optional.

t.catenaryPoleModel = "railroad/power_pole_us_2.mdl"
t.catenaryMultiPoleModel = "railroad/power_pole_us_1_pole.mdl"
t.catenaryMultiGirderModel = "railroad/power_pole_us_1a_repeat.mdl"
t.catenaryMultiInnerPoleModel = "railroad/power_pole_us_1b_pole2.mdl"
 
t.bumperModel = "railroad/bumper.mdl"
t.switchSignalModel = "railroad/switch_box.mdl"
 
t.railModel ="railroad/tracks/single_rail.mdl"
t.sleeperModel = "railroad/tracks/single_sleeper_base.mdl"
t.trackStraightModel = {
  "railroad/tracks/2m_base.mdl",
  "railroad/tracks/4m_base.mdl",
  "railroad/tracks/8m_base.mdl",
  "railroad/tracks/16m_base.mdl",
}

The catenary uses four different models for different situations:

The track sections are used depending on the length of the section and the radius. Straight tracks use the models from trackStraightModel with appropriate lengths (2, 4, 8 or 16 meters). For very small sections and tight curves, the model is constructed from the single sleeper and two instances of the single rail model. All models have their origin at the terrain height, not the ballast top height and are centered in length and width.

Cost configuration

The two values can be set to adjust the costs of tracks.

    maintenanceCost = 25.0   -- [$/m/M] per meter and month
    cost = 80.0              -- [$/m] per meter

Filter auto generated station modules

The game automatically generates station modules for every non-vanilla track type in the vanilla postRun function. To prevent these modules from appearing, a custom postRun function can be used in the mod to hide them. The below code crawls through the repository of modules and sets the visibility property to false for the modules specified in the list.

postRunFn = function ()
 
  local filteredModules = {      
      ["trainstation_<tracktypename>.lua"]        = 1,
      ["trainstation_<tracktypename>.luacatenary"]      = 1,
  }
 
  local modules = api.res.moduleRep.getAll()
  for index, moduleFileName in ipairs(modules) do
      if filteredModules[moduleFileName] == 1 then
          api.res.moduleRep.setVisible(index - 1,false)
      end
  end
end, 

Streets

A street configuration files specifies a set of parameters to define the properties, dimension, features and visuals of streets. They are stored in .lua files in the folder res/config/street/.

The file consists of three parts:

function data()
return {
  -- property and dimension definitions
  -- ...
 
  materials = {
    -- material definitions
  },
  assets = {	
    -- asset definitions
  },
}
end

Properties and dimensions

The common properties of streets are:

function data()
return {
  numLanes = 2,                              -- number of lanes, see below
 
  streetWidth = 10.0,                        -- [m] width of the street (without sidewalk!)
  sidewalkWidth = 3.0,                       -- [m] width of the sidewalk (must not be 0)
  sidewalkHeight = .3,                       -- [m] height of the sidewalk
 
  aiLock = false,                            -- street type can't be changed by town development [bool]
  country = false,                           -- disallow town buildings [bool]
  speed = 20.0,                              -- [km/h] maximum allowed drive speed
  type = "old small",                        -- legacy type that can be referenced elsewhere
  signalAssetName = "asset/ampel.mdl",       -- traffic light model to be used at intersections
  transportModesStreet = { "BUS", }          -- restriction of allowed street transport mode types
  transportModesSidewalk = { "PERSON", }     -- restriction of allowed sidewalk transport mode types
  busAndTramRight                            -- restriction of the outmost lane to only be used by bus and tram
  priority = 10                              -- priorisation for the visualisation of crossing markings
 
  yearFrom = 0,                              -- available from [year]
  yearTo = 1925,                             -- available until [year]
  name = _("Small street"),                  -- name for the buy menu
  desc = _("Two-lane street with  %2%."),    -- description for the buy menu
  icon = "ui/streets/standard/old_small.tga" -- optional reference to the ui icon
  categories = { "urban" },                  -- category for the buy menu
  cost = 20.0,                               -- building costs per meter
  maintenanceCost = 0.15,                    -- monthly maintenance cost per meter
 
  borderGroundTex = "street_border.lua",     -- ground texture for the borders of the street
  streetFillGroundTex = "",                  -- ground texture for the street
  sidewalkFillGroundTex = "",                -- ground texture for the sidewalks
  lodDistFrom = 700,                         -- distance for switch from LOD 0 to LOD 1
  lodDistTo = 4000,                          -- distance where the street gets visible
 
  maxSlope = 0.4,
  maxSlopeBuild = 0.2,
  maxSlopeShape = 0.4,
 
  slopeBuildSteps = 4,                       -- step size for procedurally generated street section 
  embankmentSlopeLow = 0.75,                 -- less steep slope gradient
  embankmentSlopeHigh = 2.5,                 -- steeper slope gradient
 
  -- material, catenary and assets definitions...
}

Lanes

Streets that have an equal number of lanes in both direction can use the simple property numLanes. The number is divided by two to determine the number of lanes for each of the directions. Streets with an unequal number of lanes per direction require the use of the alternative laneConfig property:

laneConfig = {
  { forward = true }, -- sidewalk left
  { forward = false }, -- left lane
  { forward = true }, -- middle lane
  { forward = true }, -- right lane
  { forward = true }, -- sidewalk right
},

The first and last list entries are the sidewalks. They are used by pedestriants in both directions with a small sideway offset. Be aware that at least 3 entries are required, less entries lead to a crash.

Dimensions

The basic dimensions of streets are defined with three properties:

1 streetWidth is the width of all street lanes. It is equally devided over all lanes.
2 sidewalkWidth is the width of each sidewalk in meters. Must not be 0. 3 sidewalkHeight is the height of the sidewalks in meters.

Functionality

Several properties influence the functionality of the street:

If an intersection consists of different street types, the one that is used most for the street segments meeting at the intersection node is used for the paving and other materials. If several types are used equally often, there is no guranteed order, but usually the type with smaller index in the street type repo is used.

To hide a street type from the menu, use the setVisibility(bool) function in the postRunFn method or set the third parameter for adding street types to false when adding to the street type repository by script.

As an alternative you can set a custom fileFilter to filter the street types.

Metadata

The following properties are used for general purposes:

Misc

There are three properties that can be used for ground textures in the area of streets:

1 borderGroundTex is the ground texture that is used for the border along the street.
2 sidewalkFillGroundTex is used for the area below the sidewalks. If the street does not have a sidewalk material, this ground texture can be seen. This is often used with country roads. 3 streetFillGroundTex is used for the area below the street itself. It is usually not visible at all except the street does not have a paving material.

Other properties are:

Materials

The list of materials defines the materials used for various parts of the street. Every definition contains a link to a .mtl file and its size:

materials = {
  streetPaving = {
    name = "street/country_new_medium_paving.mtl",     -- reference to material file
    size = { 8.0, 8.0 }                                -- the size of the texture tile
  },
 
	-- more material definitions...
},

The material references are relative to the res/models/material/ path. The textures are used as tiled textures wich are layed next to each other to fill the required area. With size, it is possible to specify the size of such a tile in meters for x and y dimension.

Available material definitions:

1 streetPaving is the base texture of streets. It is not orientated along the lane direction.
2 streetBorder is the overlay texture stripe that is used along the outer edges of the outermost lanes.
3 streetLane is an overlay texture of street lanes. It is oriented along the lane.
4 streetArrow is an overlay decal used for arrows in front of crossings.
5 streetStripe is the overlay texture stripe that is used between lanes of the same direction.
6 streetStripeMedian is the overlay texture stripe that is used between lanes of different directions.
7 streetTram is the overlay texture with the tram track basement.
8 streetTramTrack is the overlay texture with the actual tram tracks.
9 streetBus is the overlay texture of bus lanes. It is oriented along the lane.
10 sidewalkPaving is the base texture of sidewalks. It is not orientated along the lane direction.
11 sidewalkLane is the oberlay texture of sidewalk lanes. It is oriented along the lane.
12 sidewalkBorderInner is the overlay texture stripe that is used along the sidewalk edge towards the street lanes.
13 sidewalkBorderOuter is the overlay texture stripe that is used along the outer edge of the sidewalk.
14 sidewalkCurb is the texture that is used for the face at the side of the higher sidewalks towards the street and front faces where sidewalks have different heights. This often happens at railroad crossings and the contact points between town and country roads.
15 crossingLane is an overlay texture of street lanes in intersections. It is oriented along the lane.
16 crossingTram is the overlay texture with the tram track basement in intersections.
17 crossingTramTrack is the overlay texture with the actual tram tracks in intersections.
18 crossingCrosswalk ist the overlay decal for crosswalk markings.

Further material definitions are not shown in the picture above:

If a material is not set for a street type, this part is invisible ingame.

Base Materials

Base materials - like street and sidewalk pavings - require the following parameters:

function data()
return = {
  order = 0
  params = {
    -- more params
    polygon_offset = {
      factor = -2,
      units = -2,
    },
  },
  type = "PHYS_TRANSPARENT_NRML_MAP" -- or non-transparent
}

Overlay Materials

Overlay materials - like markings, borders, bus lanes or tram tracks - require the following parameters:

function data()
return = {
  order = 1    -- for multiple overlays set order appropriately
  params = {
    -- more params
    alpha_test = {
      alphaThreshold = 0.5,
      preferAlphaToCoverage = false,
    },
    polygon_offset = {
      factor = -3,
      units = -3,
    },
  },
  type = "PHYS_TRANSPARENT_NRML_MAP" 
}

Detailed information about material definitions can be found at the material definitions.

Catenary

The catenary models that should be used are referenced in the catenary block.

catenary = {
  pole = { name = "asset/tram_pole.mdl" },
  poleCrossbar = { name = "asset/tram_pole_crossbar.mdl" },
  poleDoubleCrossbar = { name = "asset/tram_pole_double_crossbar.mdl" },
  isolatorStraight = "asset/cable_isolator.mdl";
  isolatorCurve =  "asset/cable_isolator.mdl";
  junction = "asset/cable_junction.mdl";
},

Assets

Streets can be decorated by placing different assets along the street. The assets block contains a list of them:

assets = {
  {
    name = "street/street_light_eu_c.mdl",  -- reference to the asset model
    offset = 10.0,                          -- [m] offset along the street
    distance = 20.0,                        -- [m] distance between assets
    prob = 1.0,                             -- [0.0 - 1.0] placement probability
    offsetOrth = 3.4,                       -- [m] offset perpendicular to street direction
    randRot = false,                        -- [bool] random rotation
    oneSideOnly = true,                     -- [bool] place only on one side of the road
    alignToElevation = false,               -- [bool] align to elevation
    avoidFaceEdges = false,                 -- [bool] asset not placed at street segment border...
                                            -- ... (avoid overlaps with bigger assets, i.e. tree beds)
    placeOnBridge = true,                   -- [bool] place on bridges
  }, 
  -- more asset definitions...
},

Usually assets are not aligned to the elevation when they are trees or (lamp) posts. Aligned assets could be the tree beds.