Construction Basics
The concept of constructions allows to configure and create a lot of different building types and assets in just one format. This includes stations, depots, industries, town buildings and different kinds of assets. They are stored in .con.lua files and are usually grouped in folders for specific purposes like depots/ or industries/.
Construction Definition
The format mainly consists of meta information, parameter definitions and several functions for different purposes:
function data() return { availability = { yearFrom = 1900, yearTo = 1950 }, description = { name = _("DEPOTS_RAIL_DEPOT_NAME"), description = _("DEPOTS_RAIL_DEPOT_DESCRIPTION"), icon = "rail_depot.tga", previewIcon = "rail_depot_preview@2x.tga", attributes = { noise = { 50, -1 }, pollution = { 100, -1 }, maintenanceCost = { 100000 * yearCoefficient, -1 }, cost = { 600000 * yearCoefficient, -1 }, } }, menuCategory = { categories = { { category = "rail_buildings", filterCategories = {"building"}, order = 5000, }, }, },
The availability is set by yearFrom for the year from when the construction should be available. Unset or values below 1900 mean from start. The end limit is set by yearTo. It is the year until when the construction should be available. Unset or value 0 means unlimited availability, values below 1900 result in a never available construction.
The description struct contains data used for the menu entry in the construction menu. This covers:
namefor the display name. It should not be longer than 32 characters.descriptionfor a short descriptive text showcasing the most important feature. It should not be longer than 320 characters.iconis a reference to a small@2x.tgaicon which has a resolution of 240×150 pixels shown in the menu.previewIconis reference to a.tgaimage that is used as background image for the info box. It has a resolution of 720×405 pixels.attributescontains values to be displayed as metadata in the info box:noiseis the display interval for the noise emission. If the second value is -1, only one value is shown.pollutionis the display interval for the pollution emission. If the second value is -1, only one value is shown.maintenanceCostis the display interval for the yearly maintenance cost. If the second value is -1, only one value is shown.costis the display interval for the build cost. If the second value is -1, only one value is shown.
The menuCategory struct is used to provide the construction in the right menu. See the construction menu for more details about the menu tags.
namePrefix = _("{townName} Train Depot"), subConstructionNamePrefix = "{constructionName}", soundConfig = { soundSet = { name = "sound/raildepot.snd" }, effects = { select = { "sound/selected_traindepot3.wav" } }, builderAudioRes = "::/gui/construction/sound/buildoze_construction_large.builder_audio", }, keepBuildingsAndFields = false, heightModView = true,
Some constructions have names for the user interface window, these can be templated by providing namePrefix and subConstructionNamePrefix.
The environment and click sounds are configured in the soundConfig. The soundSet.name is a reference to a soundset file. The path is relative to the .con.lua file. effects is a mapping of event names to file names. The path is relative to the .con.lua as well.
With the keepBuildingsAndFields property, it is possible to prevent the construction from bulldozing town buildings, farm fields and other satellites. The heightModView property allows disabling the grid like terrain modification preview pattern. This is usually switched off for very large constructions.
Contructions may have additional properties and functionality for gameplay purposes. See the construction types documentation for further details.
Parameters
Parameters can be used to let the user set some preferences and influence the outcome of the construction script:
... params = { { key = "postbox_type", name = _("Postbox"), tooltip = _("Choose the type of postbox you'd like to place."), uiType = "Button", values = { _("Germany"), _("Switzerland"), _("Austria"), }, defaultIndex = 0, }, ... }, ...
Each parameter struct has several properties:
| Property | Value | Default | Description |
|---|---|---|---|
| key | String | mandatory | Unique identifier for the parameter |
| name | String | "" (empty) | Display name for the parameter menu |
| group | String | "" (empty) | Assignment to group, groups are divided by horizontal lines |
| tooltip | String | "" (empty) | Tooltip that is displayed above the parameter name when hovering |
| tooltips | {String,String,…} | {"", "", … } | Tooltip texts for the individual options |
| values | {String,String,…} | mandatory | Display values for the parameter menu, see below |
| numbers | {Number,Number,…} | {1, 2, 3, …} | Return values for each option of the parameter |
| defaultIndex | Integer | 1 | Pre-selected option on first call |
| uiType | "Button" or "Slider" or "ComboBox" or "IconButton" or "CheckBox" | "Button" | Type of parameter, see below |
| yearFrom | Integer | 0 | Parameter is displayed from |
| yearTo | Integer | infinite | Parameter is displayed until |
| hideLabel | Boolean | false | The name is not shown |
| location | "Default" or "Toolbar" | "Default" | The parameter is shown in the left or right menu |
| displayMode | "Default" or "Compact" | "Default" | The name is shown normal or as button with popup menu |
| checkEnabledScript | Script reference, see below | none | Optional script function that decides if this parameter should be shown, see below |
| postConstructionModifiable | Boolean | false | The parameter can be changed after the construction is already built |
The checkEnabledScript function allows to define conditional functions for certain parameters:
... { key = "additional_param", name = _("Additional Parameter"), uiType = "ComboBox", values = { _("ABC"), _("DEF") }, checkEnabledScript = { fileName = "custom_construction.script@checkEnabledFn", params = { key = "other_param", threshold = 100, }, }, } ...
A .script.lua / .script.tl file contains this function:
... checkEnabledFn = function(capturedParams, params) return params[capturedParams.key] < capturedParams.threshold and "Disabled" or "Enabled" end, ...
The referenced function receives three parameters:
captureParamsis the struct attached in the parameter definition in the.con.lua.paramsis the list containing the return values of all the params of this construction.scriptRefParamscontains the custom keys and values provided next to the script reference, likekeyandthresholdin the example above.
It is not possible to access other scripting interfaces in this function.
The function may return one of the following strings:
"Enabled"when the parameter should be offered."Hidden"when the parameter should be disabled and invisible."Disabled"when the parameter should be disabled but visible and greyed out.
It is recommended to choose key names that are totally unique, not only on mod level. Otherwise it could happen, that a preselected parameter value from another third-party construction is used once your construction is loaded. This could result in unintended behavior, if you do not check for the parameter range.
In the updateFn function of the construction, the selected options can be called up with params.<key>. Numbers starting from 1 are returned. The first entry of a dropdown, for example, returns a 1. For a checkbox, 1 corresponds to the non-activated state, 2 to the activated state.
Be aware that in comparison to Transport Fever 2, the return values are 1-based, not 0-based.
The individual characteristics of the different types are shown below.
Button
Simple text buttons are lined up in the menu as a centered list. The labels of the buttons are passed as a string list in the values parameter, they can also be translated in ''strings.json''.
{ key = "postbox_type", name = _("Postbox"), uiType = "Button", values = { _("Germany"), _("Switzerland"), _("Austria"), }, tooltip = _("Choose the type of postbox you'd like to place."), },
Slider
Especially for many linear values, such as numerical series or size increments, sliders can be used as easy-to-use controllers. The name of the currently selected position is displayed to the right of the slider. The display names of the buttons are passed as a string list in the values parameter, these can also be translated in ''strings.json''.
{ key = "parcelstation_length", name = _("Parcel Station Length"), uiType = "Slider", values = { _("5m"), _("8m"), _("10m"), _("12m"), _("15m"), _("20m"), }, tooltip = _("Choose the length of the parcel station."), },
Combo Box
If a large number of text options should be available, a simple list of buttons is not sufficient. Then a combo box, also known as a drop-down menu, can be used to offer a compact number of options. The entries of the list are passed as a string list in the values parameter, they can also be translated in ''strings.json''.
{ key = "post_assets", name = _("Post Assets"), uiType = "ComboBox", values = { _("Few Parcels"), _("Many Parcels"), _("Oversized Parcels"), _("Letterboxes"), _("Empty"), }, tooltip = _("Choose the decoration that should lay around."), },
Icon Button
Unlike the text buttons, the icon buttons display small images in TGA format. If the list of buttons becomes wider than the parameter menu, it will wrap to another line. It is therefore advisable that the images for the buttons all have the same height. Also, the border of the buttons should be transparent so that you can see which option is currently selected. The file paths to the images are passed as a string list in the values parameter, the paths are relative to the .con.lua. The tooltip is used for hovering over the parameter name. It is not possible to add tooltips for the individual icons.
{ key = "post_horns", name = _("Post Horns"), uiType = "IconButton", values = { "ui/parameters/post_de.tga", "ui/parameters/post_ch.tga", "ui/parameters/post_at.tga", }, tooltip = _("Choose the post horn that should be displayed."), },
Check Box
If only one value is assigned with yes or no, a check box is also suitable as parameter type. Only the name is displayed, but the values parameter must still be defined with two values, but it's values are never shown.
{ key = "post_box_open", name = _("post box is open"), uiType = "CheckBox", values = {"1", "2"}, tooltip = _("Choose if the post box is shown in opened state."), },
Construction Scripts
Each construction may have references for some of the following functions to provide different functionality. The following scripts are used to build or update the construction:
updateScriptis the most important function reference. The function assembles the construction that is placed in the 3D world.createTemplateScriptis the function that is called to put the initial modules in slots according to the selected template.isAffectedByToolScriptis the function that is called when road or rail tools are active to check if they can be applied on the construction.upgradeScriptis used when a modular construction is changed by such a tool to swap out modules.
The updateScript is the only mandatory one for constructions, the others are only required for individual use cases.
The following optional scripts control the UI behavior:
hudIconScriptis used to specify a hud icon for the construction.configureHudIconsScriptis used to specify which hud icons shall be shown in the 3D world while the construction is selected.configureLayerScriptis used to specify which data layer shall be shown in the 3D world while the construction is selected.entityWindowScriptis used to control the content of the entity window for this construction.
If one of these scripts is not specified for a construction, the game will fall back to the default variant which might be nothing in some cases.
Update Script
The updateScript references a function in a .script.tl or .script.lua file:
... updateScript = { fileName = "rail_depot.script@updateFn", params = { ["param_key_1"] = "value_1", }, }, ...
The fileName is referencing the function updateFn in the rail_depot.script.lua file. In this function, the construction is configured and specified. It has the following structure:
... updateFn = function(captureParams, params) ... -- logic return { cost = 10000, bulldozeCost = 1000, maintenanceCost = 1000, costMultiplier = 1.0, noCostAtAll = false, snapPoint = { ... }, subconstructions = { ... }, edgeLists = { ... }, edgeObjects = { ... }, } end
The captureParams contains the params data that is provided with the script reference in the .con.lua.
You can use the content of the struct params to configure the construction. It also contains the selection of the user parameters you have specified in the params list of the .con.lua definition and the templates. See the list of construction types to find out, which additional properties are available in the params struct depending on the construction type.
The updateFn returns a large result data struct with several mandatory and many optional properties.
There are five properties that can be used to set the costs of the construction:
costis paid when the construction is built.bulldozeCostis paid when the construction is demolished.maintenanceCostis paid monthly to maintain the infrastructure.costMultiplieris a factor that can be applied on top of the cost values, e.g. depending on time.noCostAtAllis a boolean value that allows supressing all costs including terrain alignment.
To fine tune the positioning of the construction, it is possible to provide a snapPoint:
... snapPoint = { transf = { 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1 }, transportModes = { "TRAIN", "ELECTRIC_TRAIN" }, snapToBaseEdgeTypes = { "TRACK", "STREET"}, allowSnapToBaseEdgeEnds = true, alignWithCoast = false, placeAtTerrainHeight = false, forceSnapToWaterSurfaceHeight = false, snapHeightOffsetAboveWater = 0.0, onlySnapToWaterSurfaceHeightWhenInWater = false, allowSnapToMesh = false, } ...
The properties of the snapPoint are:
transfis the position of the construction that is below the mouse cursor while placing the construction.transportModesis a list of lane transport modes to which the construction may snap.snapToBaseEdgeTypesis a list of all edge types where the construction will align with the base edges.allowSnapToBaseEdgeEndsis a boolean value that enables snapping at crossings and ends of base edges.alignWithCoastis a boolean value that enables snapping along the coastline.placeAtTerrainHeightis a boolean value that forces placement at the height of the terrain when snapping to transport network or base edges.forceSnapToWaterSurfaceHeightis a boolean value that forces the construction to the height of the water.snapHeightOffsetAboveWateris a numeric value used as offset in meters from water surface whenforceSnapToWaterSurfaceHeightis enabled.onlySnapToWaterSurfaceHeightWhenInWateris a boolean value that softens the restriction offorceSnapToWaterSurfaceHeightto only be active while pointing on water.allowSnapToMeshis a boolean value that enables snapping to mesh geometry of models. To activate this snapping behavior, the player needs to press ALT once.
Subconstructions
Almost all things that actually affect the 3D world and have a gameplay function are assigned to a subconstruction in the subconstructions list:
... { tag = 1, -- generic properties models = { ...}, groundFaces = { ...}, colliders = { ...}, terrainAlignmentLists = { ...}, laneLists = { ... }, runways = { ... }, labelText = { ... }, metadata = { ... }, emissionEmitter = { ... }, stocks = { ... }, rules = { ... }, personCapacity = { ... }, -- game mechanic relevant properties: industry = { ... }, field = { ... }, warehouse = { ... }, maintenanceStation = { ... }, depot = { ... }, station = { ... }, townBuilding = { ... }, } ...
The tag integer is used to map the subconstructions consistently when the construction is updated.
Each subconstruction may have have multiple of the generic properties described below, but in practice there is often a primary subconstruction that has most of the properties and the others only have a subset, e.g. models.
Additionally the subconstruction may have some out of the game mechanic relevant properties. Some of them cannot be combined in the same subconstruction though, so to combine e.g. a station and a depot in the same construction, there has to be a subconstruction for each of them. See the details about the construction types for more details.
Models
It is possible and very common to add models to a construction. Almost every model can be added by adding it to the list of models in the subconstruction data struct.
models = { { id = "building_small.mdl", transf = transf.transl(vec3.new(20, -10 , 0)) } } -- alternative with dynamic index depending on the already existing list local models = { } ... models[#result.models + 1] = { id = "building_small.mdl", transf = transf.transl(vec3.new(20, -10 , 0)), tag = "office", }
Each entry contains some properties:
idis the path to the.mdlfile relative to the.con.lua.transfis the transformation matrix relative to the origin of the construction. It may either be provided as a 16 value list or by use of one of the functions frommat4.tlthat can be found in thescriptsfolder.tagis an optional property to label the model with a certain string. It can be used as reference in code elsewhere to map models to the ones from earlier executions of theupdateFn.
The game offers two pairs of hotkeys as additional inputs for custom parameters. Per default the keys are O/P and Ü/+ or [/] (depending on keyboard layout). They each have steps of 2π/32 so that 32 steps can be mapped to a full rotation around an axis.
To support rotation around all three axis, add paramsutil.makeRotationParam("constructOpt56", _("Rotation X")), and paramsutil.makeRotationParam("constructOpt78", _("Rotation Y")), to the construction parameters and encapsulate the transformation matrix of the model with the rotateTransf function
transf = constructionutil.rotateTransf(params, { 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1 }).Make sure to import the paramsutil with local paramsutil = require "::/scripts/construction/param_util.tl" in the .con.lua and the constructionutil with local constructionutil = require "::/scripts/construction/constructionutil.lua" at the begin of the script file (before function data()).
Ground Faces
Ground faces are used to paint the terrain below the construction to blend in with the construction.
groundFaces = { { face = { { -10, -10, 0 }, { 10, -10, 0 }, { 10, 10, 0 } }, modes = { { type = "FILL", key = "industry_floor.gtex", texCoords = { { 0, 0 }, { 0, 1 }, { 1, 1 }, { 1, 0 }, } } }, loop = true, alignmentOffsetMode = "OBJECT", alignmentDirMode = "OBJECT", alignmentOffset = { -2.0, -1.0 }, }, ... }
The groundFaces list contains 0 or more structs with the following attributes:
faceis the list of coordinates that span the surface which should be painted. Each point has a value relative to the construction origin for x, y and z axis, but the z axis is ignored. At least three points are required and they shall be in counterclockwise order.modesis a list of paint modes that should be applied to the face:typeis the actual painting mode."FILL"fills the whole face,"STROKE"paints a line with soft sides along the face edge,"STROKE_INNER"paints a line with a soft side to the inside of the face and"STROKE_OUTER"paints a line with a soft side to the outside of the face.texCoordsis a list of positions on the ground texture. The x and y coordinates are in the range between 0.0 and 1.0. The number of positions needs to match the number offacecoordinates.
loopis a boolean value used to describe if the face is closed. If set tofalse, the edge between last and first coordinate will not get a stroke paint.alignmentOffsetModespecifies whether the offset is applied relative to the construction orientation ("OBJECT") or the game world orientation ("WORLD").alignmentOffsetcontains the offset values in x and y direction.alignmentDirModespecifies if the uv direction setting is applied relative to the construction orientation ("OBJECT") or the game world orientation ("WORLD").alignmentDircontains the direction rotation values in x and y axis. They are computed astan2(y,x)to calculate the actual rotation.
Collider
Colliders are used to define the areas where no other object can be built.
colliders = { { params = { halfExtents = { 1.5, 1.5, 1.5, }, }, transf = { 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, }, type = "BOX", }, { colliderutil.createBox({ 0, 0, 0 }, { 1.5, 1.5, 1.5 }) } }
The colliders list contains 0 or more structs with the following properties:
paramsis a list of parameters. These depend on thetypeused.- For
"BOX"the required parameter is provided inhalfExtents. That is a 3 value vector with the half box lengths for all three axis. - For
"CYLINDER"it is provided inhalfExtentstoo. The 3 values represent the half sizes for all three axis. - For
"POINT_CLOUD", a list of points is provided in thepointsparameter. Each point has three values for the position on all three axis relative to the construction origin. Thetransfparameter is ignored.
transfis transformation matrix that point on the center of the collider. It is relative to the construction origin.typeis the type of collider. It can be either"BOX","CYLINDER"or"POINT_CLOUD"for constructions.
The collider_util.tl in the scripts/construction folder provides some useful functions to prepare the collider definition based on some parameters.
Terrain Alignment List
The adjustment of terrain height to the construction is done with the terrain alignment. If the required alignment can't be done due to other nearby constructions or infrastructure, the construction can't be built.
terrainAlignmentLists = { { type = "EQUAL", -- accepted values: "EQUAL", "LESS" and "GREATER" faces = { { { -10, -10, 0 }, { 10, -10, 0 }, { 10, 10, 0 } } }, -- a list of polygons slopeLow = 0.3, slopeHigh = 0.6, triangles = { { -10, -10, 0 }, { 10, -10, 0 }, { 10, 10, 0 }, } optional = false, }, ... }
The terrainAlignmentLists list contains 0 or more structs with several properties:
typeis the policy that should be used for terrain alignment. With"EQUAL"the terrain is aligned exactly to the specified faces, with"LESS"only higher areas are taken down, with"GREATER"areas below the faces will be filled up.facesis a list of polygons. Each polygon consists of at least three points with three coordinates relative to the construction origin each.slopeLowis the gradient for the slope on the outside of the construction that is needed to make the transition to the modified terrain when the surrounding terrain is lower or higher than the construction area.slopeHighis the steeper gradient for the slope if the height difference is too big and the slope would get too wide or when another object constraints the sloping.trianglesis a list of points. The number of points needs to be a multiple of 3. Every three points are considered as the corners of triangles. This property is an alternative to thefacesproperty.optionalshould be set to true if the alignment should not throw collision errors when competing against other terrain alignments in the same construction.
Lane Lists
The laneLists struct contains 0 or more lists for vehicle and passenger lane definitions :
laneLists = { { transf = { 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, }, nodes = { { { 0, -20, -2.1, }, { 0, 20, 0, }, 30, }, { { 0, 0, -2.1, }, { 0, 20, 0, }, 30, }, { { 0, 0, -2.1, }, { 0, 20, 0, }, 30, }, { { 0, 20, -2.1, }, { 0, 20, 0, }, 30, }, }, speedLimit = 20, transportModes = { "SHIP", "SMALL_SHIP" }, linkable = false, }, ... },
Each line list has several properties:
transfis a transformation matrix that defines the origin location of this lane list relative to the construction origin. This can be used to define lanes relative to module positions or model positions.nodesis a list of nodes which are used to define the edges. Every two nodes form one edge. Each node has three properties:- The coordinate relative to the model origin.
- The tangent at the node position. Please note that the length of the vector must be equal to the length of the edge. Otherwise negative side effects like compression and stretching of vehicles may occur.
- The width of the edge. It is only used for the capacity calculation.
speedLimitis the maximum speed on all edges defined by the nodes above in meter per second.transportModesis a list of allowed modes on the edges defined by the nodes above. Possible values are"PERSON","CARGO","CAR","BUS","TRUCK","TRAM","ELECTRIC_TRAM","TRAIN","ELECTRIC_TRAIN","AIRCRAFT","SHIP","SMALL_AIRCRAFT"and"SMALL_SHIP".
For lanes that are used by vehicles, two additional properties are available:
needsReservationis a boolean value that decides if the lane can be only used when a proper reservation is possible (similar to trains on train tracks).forwardOnlyis a boolean value that tells if the lane is only usable in the direction it is defined or not.
For lanes that are used by pedestrians, two additional properties are available:
linkableis a boolean value that decides if the lane can be targeted by the small automatically generated footpath links.pedestrianWalkPenaltyis a boolean value that tells if the usage of these lanes leads to reduced happiness for pedestrians.
The laneutil in scripts/construction provides some useful helper function to ease the definition of lanes.
Runways
The runways struct contains 0 or more runways which have several properties related to the entry and exit points of the freely moving planes and ships:
runways = { { edges = { { 0, 0 }, }, node = { 0, 0 } type = "LANDING", }, { edges = { { 1, 0 }, }, node = { 0, 0 } type = "TAKEOFF", }, },
Each runway has three properties:
edgesis a list of indices pairs where the first value is the index of the lane List inlaneListsof the same subconstruction and the second value is the index of the lane in this lane list. If the first value is -1, then the n-th edge from theedgeListsof the construction is used. All edges/lanes referenced this way are part of the runway.nodeis an indices pair where the first value is the index of the lane list inlaneListsof the subconstruction and the second value is the index of the node in this lane list. It is the point where the vehicle is slowed down after landing or starting speedup for takeoff. It must be the node where the runway connects to the non-runway edges or lanes. If the first value is -1, then the n-th node from theedgeListsof the construction is used.typeis either"LANDING"or"TAKEOFF"depending on the type of runway.
An aircraft tries to land and slow down in front of the landing node. After passing it, it will taxi to the terminal. On departure, it will speed up and take off after passing the takeoff node. The landing/takeoff direction is given by the tangent of the first/last edge in the edges list. Same holds for ships.
Label List
For models with "CUSTOM" typed labels, the content can be provided here:
labelText = { [12] = { "Label", "SomeText"} }
The labelText list contains a mapping of keys to value lists. The key number equals the id of the model in the models of the same subconstruction that should be provided with some custom label texts. The list contains the strings. The first string is for the first label of the model, the second for the second label of this model and so on.
Edge Lists
Edge lists are used to add streets and tracks to a construction. The following code adds a street segment and a track segment to the construction:
result.edgeLists = { -- specify a street segment { type = "STREET", params = { type = "::/infrastructure/street/country/country_new_small.street_template", tramTrackType = "YES" }, edgeType = "BRIDGE", -- optional edgeTypeName = "::/infrastructure/bridge/steel.bridge", -- optional edges = { -- one entry refers to a position and a tangent { { .0, -79.0, .0 }, { .0, 15.0, .0 }, "tag1" }, -- node 0 (snap node) { { .0, -64.0, .0 }, { .0, 15.0, .0 }, "tag2" } -- node 1 }, snapNodes = { 0 } , -- node 0 is allowed to snap to other edges of the same type freeNodes = {}, tag2Nodes = {}, }, -- specify a track segment { type = "TRACK", params = { type = "::/infrastructure/track/standard/standard.street_template", catenary = true }, edgeType = "BRIDGE", -- optional edgeTypeName = "::/infrastructure/bridge/steel.bridge", -- optional edges = { { { -19.1, .0, .0 }, { -20.0, .0, .0 } }, -- node 0 { { -39.1, .0, .0 }, { -20.0, .0, .0 } }, -- node 1 (snap node) }, snapNodes = { 1 }, -- node 1 is allowed to snap to other edges of the same type freeNodes = {}, } }
Each struct in the edgeList has several properties:
typeselects if the edges should be"STREET"or"TRACK"edges.paramsis a struct with two properties:typeis a reference to a street template for the track or street to use. It is recommended to use absolute references.tramTrackTypeis a string value only considered for actual streets. If set to"NO", no tramtracks will be built. If set to"YES", tram tracks will be built. If set to"ELECTRIC", tram tracks with catenary will be built.
edgeTypedecides if the segment is built as a"BRIDGE","TUNNEL"or normal (unset).edgeTypeNameselects the type of bridge or tunnel to be used. It is recommended to use absolute references.edgesis a list. Every two entries form an edge. The first entry is the start node of the edge, the second entry is the end node of the edge. Every node has two vectors with three values and an optional third string parameter:- the first vector is the point relative to the construction origin with values for x, y and z axis.
- the second vector is the tangent in this point with values for x, y, and z axis.
- the optional string parameter can be used to merge nodes that do not have exactly the same coordinates into one node, allowing off-center intersection. If there are untagged nodes at the same location as a tagged one, they won't be merged.
snapNodesis a list of node indizes from theedgeslist. These nodes can be used to snap streets or tracks while manually building later.freeNodesis a list of nodes, that are not part of the construction. Edges with two free nodes can be deleted or modified independently.trafficLightNodePreferenceis an array of pairs with integers and strings. The integers refer to nodes of the construction edgeLists, the strings specify the preference:YESwill force traffic lights at the intersectionNOwill force the abscence of traffic lights at the intersectionAUTOwill build traffic lights if possible/available.
alignTerrainis a boolean value. If set to true, the terrain aligns to the built edge like normal track/street building would do.addNoisePollutionEmitteris a boolean value. If set to true, the tracks/street in the construction have their own pollution emitter as well. Default isfalse.
The constructionutil in scripts/construction offers a helper function to add edges.
Edge Objects
Some game objects can be attached to edges, for example signals. This is not only possible by the player, but also possible in constructions for edges contained by the constructions, as shown in the following code sample:
-- we need some edges to attach edge objects to them taxiway = { } -- edge 0 taxiway[#taxiway + 1] = { { 180.0, 20.0, .0 }, { .0, -20.0, .0 } } taxiway[#taxiway + 1] = { { 180.0, 0.0, .0 }, { .0, -20.0, .0 } } -- edge 1 taxiway[#taxiway + 1] = { { 180.0, 0.0, .0 }, { .0, -47.1, .0 } } taxiway[#taxiway + 1] = { { 150.0, -30.0, .0 }, { -47.1, 0.0, .0 } } -- add taxi way to edge lists... -- attach a signal to one of the above defined edges result.edgeObjects = { { edge = 1, -- attach object to edge 1 param = .5, -- param along the edge left = false, model = "::/stations/airport/asset/signal_runway_old.mdl" } }
The edgeObjects list contains all object attachments with properties:
edgeis the number of the edge. Edge 0 is between node 0 and 1, edge 1 is between node 2 and 3, …paramis the offset along the edge from the start node in meter.leftis set to false, if the object should be placed on the right side of the edge.trueleads to objects on the left side.modelis a reference to a.mdlfile.
Please be aware that it is not possible to add more than one object per edge by script.
Is Affected By Tool Script
When the player uses the electrification tool or wants to upgrade tracks or streets, the isAffectedByToolScript is used as a callback to determine if the construction can be upgraded:
... isAffectedByToolFn = function(captureParams, params, conConfigAdd, conConfigRevert) ... -- some logic return false -- or true end, ...
The function receives the following parameters:
capturedParamscontains the parameters forwarded with the script reference in the.con.lua.paramscontains the parameter values from when the construction update function was executed previously.conConfigAddcontains info about what the tool wants to do.conConfigRevertcontains info about what the tool would do if it was already applied before.
Depending on the used tool, different data is available in conConfigAdd and conConfigRevert:
| Tool | Parameter | Value |
|---|---|---|
| Electrification | catenary | 1 = false 2 = true |
| Track Modification | catenary | 1 = false 2 = true |
| Track Modification | streetTemplate | resource name of selected template |
| Street Modification | streetTemplate | resource name of selected template |
| Bus Lane Tool | busLane | 1 = false 2 = true |
| Tram Lane Tool | tramTrack | 1 = false 2 = true |
| Tram Lane Tool | tramCatenary | 1 = false 2 = true |
It shall return true when the tool can be applied onto the construction and false if it may not. If the function is not set for a construction, true is assumed.
The function may use api.res functions, but no other functions from api.
Upgrade Script
The upgradeScript function is called when an existing construction shall be changed with one of the tools.
It receives the previous params of the construction as well as the info what shall be changed and returns the modified params which are then forwarded to the update script.
... upgradeFn = function(captureParams, params, slotId, constructionConfig) ... -- edit params return params end ...
The capturedParams contains the parameters forwarded with the script reference in the .con.lua. Beside that, params contains the parameter values from when the construction update function was executed previously. slotId is -1 for non-modular constructions and constructionConfig contains values as described for the conConfigAdd above.
The function may use api.res functions, but no other functions from api.
In practice this could e.g. be changing a param tramCatenary to a new value or replacing a param like streetType with another.
HUD Icon Script
The hudIconScript function allows defining the hud icon that shall be shown by the construction:
... hudIconFn = function(_captureParams : any, params : Builtin.HudIconParam, _userParam : HudIconToolbox.HudIconMasterUserParam) : TreeNodeId return hud_icon_toolbox.PerkHudIcon{ class = "landmark", path = "::/gui/hud/icons/building_temple_32.tga", } end, ...
The capturedParams contains the parameters forwarded with the script reference in the .con.lua. Beside that, params contains info about the entity itself and userParam contains some additional context info related to notifications.
It is expected that the function returns a valid BoxLayout. The ::/gui/main/hud_icon_toolbox.tl provides helper functions to create such a BoxLayout.
Configure HUD Icons Script
The configureHudIconsScript function allows defining which hud icons shall be displayed while the construction is being placed:
... configureWarehouseHudIconsFn = function() : ConstructionActionHudIcons return { componentTypes = { api.type.ComponentType.TOWN, api.type.ComponentType.STATION_GROUP, api.type.ComponentType.WAREHOUSE, api.type.ComponentType.INDUSTRY, }, showDistricts = true, showTownBorders = true, showPerksAndTowns = true, params = { stationType = "CARGO", }, } end, ...
It is expected that the function returns a valid ConstructionActionHudIcons configuration. The componentTypes is a list that may contain zero or more component types for which the icons shall be displayed. If the type api.type.ComponentType.TOWN is included, it is possible to use:
showDistrictsto highlight residential, commercial and industrial districts of townsshowTownBordersto display the zones around the townsshowPerksAndTownsto show landmarks
Further information can be found in the scripting api reference.
The usual defaults for different construction types are provided in the ::/gui/construction/construction_desc_hud_icons.script.tl script file.
Configure Layer Script
The configureLayerScript function allows defining a custom layer state that shall be displayed when the entity window of this construction is open
... upgradeFn = function(captureParams, layerConfig) return layerPollution.getConfig() end ...
The capturedParams contains the parameters forwarded with the script reference in the .con.lua. Beside that, layerConfig contains the currently visible layerConfig on the screen.
It is expected that the function returns a valid layer configuration.
Entity Window Script
The entityWindowScript function allows defining custom content for the entity window that is visible when the construction is selected.
... entityWindowFn = function( captureParams : table, entity : Engine.Entity, tag : string, gameCtx : GameContext, isMapEditor : boolean, isSandboxMode : boolean, setActionFnAndProxy : {function(actionFn? : (function() : TreeNodeId), key2? : string), any}, entityRevisionCloseConditionAndProxy : ({(function() : boolean), any})) : ViewManager.MakeEntityWindowResult ... return { recipe = make_entity_window.ConstructionWindow, param = { meta = { tag = tag .. "con" }, keyEntity = entity, gameCtx = gameCtx, isMapEditor = isMapEditor, isSandboxMode = isSandboxMode, setActionFn = actionFnAndProxy.fn, setActionFn_compareProxy = actionFnAndProxy.proxy, customTabs = customTabs, } as ConstructionWindowParam, fallbackTitle = _("Construction"), replacedEntity = entity, autoCloseCondition = entityRevisionCloseConditionAndProxy[1], autoCloseCondition_compareProxy = entityRevisionCloseConditionAndProxy[2], } end ...
The capturedParams contains the parameters forwarded with the script reference in the .con.lua. The other parameters provide additional info about the current game state and proxies. Most of them can be forwarded in the default make_entity_window.ConstructionWindow function in the ::/gui/entity_window/make_entity_window.tl.
The result structure of the entityWindowScript contains:
recipewith a react recipy that returns a list of tab contents for each subconstruction and optionally some custom ones.paramsthat are forwarded to the recipy when it is called.fallbackTitlefor the window name.
and some other optional properties.