User Tools

Site Tools

Urban Games

modding:tracksstreets

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
  • name is the name of the track type that is used in the menu. It can be translated in a strings.lua file.
  • desc is the description of the track type used in the buy menu. It can be translated too.
  • categories is a list of category keys. They are used for the category filters in the menu. A track can be part of more than one category. If left empty, it is only available in the non-filtered view.
  • yearFrom is the year from when the track should be available. Unset or values below 1851 mean from start.
  • yearTo is the year until when the track should be available. Unset or value 0 means unlimited availability, values below 1850 result in a never available track.

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:

  • for a single track, the normal pole is used 1.
  • for a double track section, the poles are rotated so that they are on the outer side of each track.
  • for 3 or 4 tracks, multi poles 2 are used and the middle tracks get girder section models 3.
  • for more than 4 tracks, additional supporting inner poles are placed below the girders 4.

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:

  • the properties that define the technical part of the street
  • the materials block that provides the information for the visualisation
  • the assets block that provides the information for decorative assets like street lamps, posts, …
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:

  • aiLock is a boolean variable. If set to true, built street segments with this street type will not be changed by the town development and this street type is not considered as potential target type for street upgrades by town development.
  • country is another boolean variable. If set to true, no houses will spawn along streets of this type.
  • speed is the maximum allowed drive speed in km/h. In sharp curves, vehicles will slow anyway.
  • type is a key (usually the file name without _ ) that was used for referencing elsewhere. It is legacy in Transport Fever 2.
  • signalAssetName is the model reference relative to res/models/model/ that should be used for traffic lights at intersections.
  • transportModesStreet is a list of keys for transport modes that are allowed on this street. It is possible to use “BUS”, “TRUCK” and “CAR”.
  • transportModesSidewalk is a list of keys for transport modes that are allowed on the sidewalk of this street. It is possible to use “CARGO” and “PERSON”.
  • busAndTramRight restricts the outmost lane to only be used by bus and tram if set to true. This is similar to the addition of a buslane ingame.
  • priority is an integer value used for the priorization of street types when it comes to the visualisation of markings at crossings. The higher the value is, the more likely this streets markings are used for the optic at intersections. This is used for the junction* materials described below.

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:

  • yearFrom is the year from when the street should be available. Unset or values below 1851 mean from start.
  • yearTo is the year until when the street should be available. Unset or value 0 means unlimited availability, values below 1850 result in a never available street.
  • name is the name of the street type that is used in the menu. It can be translated in a strings.lua file.
  • desc is the description of the street type used in the buy menu. It can be translated too.
  • icon is an optional reference to the icon that should be used in the menu. It is relative to the res/textures/ folder.
  • categories is a list of category keys. They are used for the category filters in the menu. A street can be part of more than one category.
  • cost is the building cost per meter. Additional features like tram tracks and bus lanes will raise that value.

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:

  • lodDistFrom is the distance where the level of detail with simpler geometry and less assets becomes visible.
  • lodDistTo is the distance where the street is not visible anymore.
  • maxSlope, maxSlopeBuild and maxSlopeShape are the parameters for the slope gradient limits. They work the same as the ones of the track configuration described above.
  • slopeBuildSteps is a factor for the step size of procedurally generated street sections. Smaller values result in smoother bends but need more performance.
  • embankmentSlopeLow is the slope gradient that usually is tried to be used.
  • embankmentSlopeHigh is used, if the low gradient would require very wide embankments or there are other objects with terrain alignments that prevent the use of the low gradient.

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:

  • sidewalkWall is the texture that is shown at the vertical faces at the outside of the sidewalks.
  • crossingBus is the overlay texture used by buslanes at crossings. This works similar to the other crossing overlays.
  • crossingStripeMedian is the overlay texture stripe that is used between lanes of different directions at crossings.
  • crossingStopline is an overlay decal used for stop lines in front of crossings.
  • junctionBorder is the overlay texture stripe that is used along the outer edges of the outermost lanes at the dead ends of streets and in crossings.
  • junctionLane is an overlay texture of street lanes at the dead ends of streets and in crossings. It is oriented along the lane.
  • junctionEntryLane is an overlay texture of street lanes at the dead ends of streets and in
  • junctionStripe is the overlay texture stripe that is used between lanes of the same direction at the dead ends of streets and crossings with a prioritized street.
  • junctionStripeMedian is the overlay texture stripe that is used between lanes of different directions at crossings when there is a street with higher priority.
  • junctionLine is the overay texture stripe that is only used if there is no prioritized street.
  • catenary is the material used for the tram catenary wires.
  • tunnelWall is the material for the tunnel wall.
  • tunnelHull is the material for the outside of the tunnel (that normally is not visible at all).

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.


modding/tracksstreets.txt · Last modified: 2022/05/13 11:05 by marlon