manual:subwaysim:map_construction:create_maplua
Differences
This shows you the differences between two versions of the page.
| Both sides previous revisionPrevious revisionNext revision | Previous revision | ||
| manual:subwaysim:map_construction:create_maplua [2026/01/14 14:08] – [7.2.7 Pattern D — Sending Trains to a Depot] dcs | manual:subwaysim:map_construction:create_maplua [2026/01/27 11:27] (current) – dcs | ||
|---|---|---|---|
| Line 7: | Line 7: | ||
| * linking the Unreal Engine level to the map | * linking the Unreal Engine level to the map | ||
| * defining stations and platforms | * defining stations and platforms | ||
| - | * defining | + | * **loading |
| * configuring dispatching and depot logic | * configuring dispatching and depot logic | ||
| * providing optional career mode data | * providing optional career mode data | ||
| Line 112: | Line 112: | ||
| self: | self: | ||
| + | |||
| + | -- Timetables define AI service patterns. | ||
| + | -- Full guide: manual: | ||
| self: | self: | ||
| + | |||
| self: | self: | ||
| Line 150: | Line 154: | ||
| --- Loads the default timetables for this map | --- Loads the default timetables for this map | ||
| + | --- Full guide: manual: | ||
| function TestMap: | function TestMap: | ||
| - | + | -- (Implementation depends on your map and service patterns) | |
| - | ---@type Timetable[] | + | end |
| - | self.timetables = {}; | + | |
| - | + | ||
| - | -- Direction 1 (TS -> TSA) | + | |
| - | self.TestLine_Dir1 = Timetable: | + | |
| - | : | + | |
| - | : | + | |
| - | : | + | |
| - | : | + | |
| - | : | + | |
| - | : | + | |
| - | : | + | |
| - | station = self.stations.TS, | + | |
| - | platform = 2, | + | |
| - | departure = 0, | + | |
| - | speedLimit = 70, | + | |
| - | routeSettingMaxETA = 0.5, -- Fahrstraße stellt sich erst 0.5 Minuten vor Abfahrt | + | |
| - | }) | + | |
| - | :addStop({ | + | |
| - | station = self.stations.TSD, | + | |
| - | platform = 2, | + | |
| - | departure = 0, | + | |
| - | speedLimit = 70, | + | |
| - | }) | + | |
| - | : | + | |
| - | station = self.stations.TSA, | + | |
| - | platform = 1, | + | |
| - | departure = 0, | + | |
| - | speedLimit = 70, | + | |
| - | altPlatform = { " | + | |
| - | }) | + | |
| - | + | ||
| - | -- Direction 2 (TSA -> TS) | + | |
| - | self.TestLine_Dir2 = Timetable: | + | |
| - | : | + | |
| - | : | + | |
| - | : | + | |
| - | : | + | |
| - | : | + | |
| - | : | + | |
| - | : | + | |
| - | station = self.stations.TSA, | + | |
| - | platform = 1, | + | |
| - | departure = 0, | + | |
| - | speedLimit = 70, | + | |
| - | routeSettingMaxETA = 0.5, -- Fahrstraße stellt sich erst 0.5 Minuten vor Abfahrt | + | |
| - | }) | + | |
| - | : | + | |
| - | station = self.stations.TSD, | + | |
| - | platform = 1, | + | |
| - | departure = 0, | + | |
| - | speedLimit = 70, | + | |
| - | }) | + | |
| - | : | + | |
| - | station = self.stations.TS, | + | |
| - | platform = 2, | + | |
| - | departure = 0, | + | |
| - | speedLimit = 70, | + | |
| - | altPlatform = { " | + | |
| - | }) | + | |
| - | + | ||
| - | -- List of templates by line, then by direction | + | |
| - | ---@type Timetable[][] | + | |
| - | self.templatesByLine = { | + | |
| - | [1] = { | + | |
| - | [1] = self.TestLine_Dir1, | + | |
| - | [2] = self.TestLine_Dir2, | + | |
| - | }, | + | |
| - | }; | + | |
| - | + | ||
| - | ---@type table< | + | |
| - | self.templatesByDirection = { | + | |
| - | [1] = { | + | |
| - | self.TestLine_Dir1, | + | |
| - | }, | + | |
| - | [2] = { | + | |
| - | self.TestLine_Dir2, | + | |
| - | }, | + | |
| - | }; | + | |
| - | + | ||
| - | local DM = DayMask; | + | |
| - | + | ||
| - | -- Repeating interval example | + | |
| - | TableUtil.insertList(self.timetables, | + | |
| - | TableUtil.insertList(self.timetables, | + | |
| - | + | ||
| - | ---@type table< | + | |
| - | self.depots = { | + | |
| - | }; | + | |
| - | + | ||
| - | ---@type table< | + | |
| - | self.dispatchingStrategies = { | + | |
| - | + | ||
| - | -- Turnaround logic at TS | + | |
| - | | + | |
| - | { | + | |
| - | sourceStation = self.stations.TS, | + | |
| - | targetStation = self.stations.TS, | + | |
| - | sourcePlatforms = { " | + | |
| - | targetPlatforms = { " | + | |
| - | replaceFirstPlatform = true, | + | |
| - | keepLine = false, | + | |
| - | minLayover = 4, | + | |
| - | }, | + | |
| - | }, | + | |
| - | + | ||
| - | -- Turnaround logic at TSA | + | |
| - | [self.stations.TSA] = { | + | |
| - | { | + | |
| - | sourceStation = self.stations.TSA, | + | |
| - | targetStation = self.stations.TSA, | + | |
| - | sourcePlatforms = { " | + | |
| - | targetPlatforms = { " | + | |
| - | replaceFirstPlatform = true, | + | |
| - | keepLine = false, | + | |
| - | minLayover = 4, | + | |
| - | }, | + | |
| - | }, | + | |
| - | }; | + | |
| - | end; | + | |
| --- Initializes data for career mode | --- Initializes data for career mode | ||
| Line 291: | Line 177: | ||
| The DataTable registers the map in the ContentManager. | The DataTable registers the map in the ContentManager. | ||
| Without it the map will not appear in the map selection menu and cannot be loaded. | Without it the map will not appear in the map selection menu and cannot be loaded. | ||
| - | |||
| ==== DataTable Fields ==== | ==== DataTable Fields ==== | ||
| Line 305: | Line 190: | ||
| | description | Longer description shown in UI. | | | description | Longer description shown in UI. | | ||
| | previewFilename | Path to the preview image used in the main menu. | | | previewFilename | Path to the preview image used in the main menu. | | ||
| - | |||
| ==== Registering the DataTable ==== | ==== Registering the DataTable ==== | ||
| Line 323: | Line 207: | ||
| The runtime class is responsible for everything that happens when the map is loaded: | The runtime class is responsible for everything that happens when the map is loaded: | ||
| * defining stations and their platforms | * defining stations and their platforms | ||
| - | * defining | + | * loading |
| * configuring dispatching / turnaround rules | * configuring dispatching / turnaround rules | ||
| * optional career mode setup | * optional career mode setup | ||
| Line 340: | Line 224: | ||
| The constructor creates the map instance and prepares the runtime data. | The constructor creates the map instance and prepares the runtime data. | ||
| - | |||
| ==== Core Properties ==== | ==== Core Properties ==== | ||
| Line 350: | Line 233: | ||
| | self.longitude | Used for sun position and environment lighting. | | | self.longitude | Used for sun position and environment lighting. | | ||
| | self.timezone | Timezone offset for day/time simulation (UTC+1 = 1). | | | self.timezone | Timezone offset for day/time simulation (UTC+1 = 1). | | ||
| - | |||
| ==== Loading Runtime Data ==== | ==== Loading Runtime Data ==== | ||
| Line 357: | Line 239: | ||
| * `loadStations()` must run first (timetables reference stations) | * `loadStations()` must run first (timetables reference stations) | ||
| - | * `loadTimetables()` | + | * `loadTimetables()` |
| * `loadCareerMode()` is optional | * `loadCareerMode()` is optional | ||
| Line 385: | Line 267: | ||
| By loading this prepared level, mod maps can use the full weather and lighting system | By loading this prepared level, mod maps can use the full weather and lighting system | ||
| **without accessing license-protected core code**. | **without accessing license-protected core code**. | ||
| - | |||
| - | The environment level is loaded **in addition** to the map level and runs alongside it. | ||
| ⚠️ **Current limitation: | ⚠️ **Current limitation: | ||
| Line 392: | Line 272: | ||
| At the moment, only one loaded level should contain Railtool infrastructure. | At the moment, only one loaded level should contain Railtool infrastructure. | ||
| This limitation will be resolved in future updates. | This limitation will be resolved in future updates. | ||
| - | |||
| ---- | ---- | ||
| Line 399: | Line 278: | ||
| Stations defined in `loadStations()` must match **BP_StationDefinition** actors placed in the Unreal Editor. | Stations defined in `loadStations()` must match **BP_StationDefinition** actors placed in the Unreal Editor. | ||
| - | |||
| ==== 5.1 How Lua Stations Connect to BP_StationDefinition ==== | ==== 5.1 How Lua Stations Connect to BP_StationDefinition ==== | ||
| Line 457: | Line 335: | ||
| Platform numbers are not “free”. They must match exactly the platform configuration inside BP_StationDefinition. | Platform numbers are not “free”. They must match exactly the platform configuration inside BP_StationDefinition. | ||
| - | + | ----- | |
| - | ==== 5.5 Example: Depot Platforms ==== | + | |
| - | + | ||
| - | The depot station `DP` uses multiple platform numbers: | + | |
| - | + | ||
| - | * 51–54 | + | |
| - | * 60 | + | |
| - | + | ||
| - | This is a common pattern to represent multiple depot tracks. | + | |
| - | + | ||
| - | ---- | + | |
| ===== 6) Timetables ===== | ===== 6) Timetables ===== | ||
| - | Timetables define: | + | Timetables define |
| - | | + | |
| - | | + | |
| - | | + | |
| - | | + | |
| - | ==== 6.1 Timetable:new() ==== | + | They control: |
| + | * which trains are spawned | ||
| + | * which routes they drive | ||
| + | * which stations and platforms are used | ||
| + | * when and how services operate | ||
| - | A timetable template is created | + | In **Map.lua**, |
| - | <code lua> | + | * `function |
| - | Timetable:new(" | + | |
| - | </ | + | |
| - | ^ Parameter ^ Description ^ | + | This function acts as the **integration point** |
| - | | `" | + | It typically references or initializes: |
| - | | `0` | Variant / index value (map-specific usage). | | + | |
| - | Templates are usually created | + | * the final list of active services (`self.timetables`) |
| - | * Direction 1: TS → TSA | + | * timetable templates (e.g. per line and direction) |
| - | * Direction 2: TSA → TS | + | * depot definitions (`self.depots`) |
| + | * dispatching strategies (`self.dispatchingStrategies`) | ||
| - | ==== 6.2 Train Compositions ==== | + | The **complete timetable workflow** — including templates, stops, composition weights, |
| + | service repetition, depot handling, and dispatching logic — is documented separately: | ||
| - | Train compositions define | + | |
| - | Each composition is referenced by its `contentName`, exactly as it is registered in the | + | This page intentionally does **not** describe timetable creation in detail, |
| - | ContentManager (e.g. in `Vehicle.lua` or `Composition.lua`). | + | to keep the Map.lua documentation focused on structure and integration. |
| - | Example: | + | ----- |
| - | contentName = " | + | |
| - | The name must match **exactly**. | + | ===== 7) Career Mode (Optional) ===== |
| - | If a composition is not registered or the name is incorrect, no train will spawn for it. | + | |
| - | ==== Adding Compositions to a Timetable ==== | + | Career Mode configuration is optional. |
| - | Compositions are added directly to the timetable template: | + | If your map does not support career mode, `loadCareerMode()` may remain empty. |
| - | <code lua> | + | If implemented, |
| - | :addTrainComposition(" | + | * where the player can take over a train |
| - | </ | + | * optional route closures for scenario logic |
| + | * which train compositions are available | ||
| + | * which timetable templates are used for pathfinding | ||
| - | A weight can optionally be provided: | + | All career mode logic is **map-specific** and independent from timetable creation. |
| - | <code lua> | + | ----- |
| - | : | + | |
| - | </ | + | |
| - | If no weight is specified, a default weight of `1.0` is assumed. | + | ===== 8) Registering Stations and Timetables ===== |
| - | ==== Composition Weights ==== | + | After stations and timetables |
| - | + | ||
| - | Weights control how likely a composition is selected **relative to other compositions** | + | |
| - | within the same timetable. | + | |
| - | + | ||
| - | They only affect **AI spawning behavior** for this timetable. | + | |
| - | + | ||
| - | ^ Weight ^ Meaning ^ | + | |
| - | | **1.0** | Standard usage. The composition is commonly selected. | | + | |
| - | | **0.5** | Reduced probability. The composition is used less frequently. | | + | |
| - | | **0.0** | The composition is excluded from AI spawning for this timetable. | | + | |
| - | + | ||
| - | ==== Important Behavior of Weight = 0.0 ==== | + | |
| - | + | ||
| - | A weight of `0.0` prevents the composition from being selected when AI trains | + | |
| - | by this timetable. | + | |
| - | + | ||
| - | The composition itself remains a valid registered | + | |
| - | * exist in the content system | + | |
| - | * appear in the vehicle selection menu | + | |
| - | + | ||
| - | This behavior is intentional and allows a composition to be: | + | |
| - | * available to the player | + | |
| - | * but excluded from AI traffic on a specific line or timetable | + | |
| - | + | ||
| - | ==== 6.3 addStop() (Route Definition) ==== | + | |
| - | + | ||
| - | Stops define | + | |
| - | Each stop is a table passed into `addStop({ ... })`. | + | |
| - | + | ||
| - | Example: | + | |
| <code lua> | <code lua> | ||
| - | :addStop({ | + | controlCenter:setStationList(self.stations); |
| - | station = self.stations.TS, | + | controlCenter:setTimetableList(self.timetables, |
| - | platform = 2, | + | |
| - | departure = 0, | + | |
| - | speedLimit = 70, | + | |
| - | routeSettingMaxETA = 0.5, | + | |
| - | }) | + | |
| - | </ | + | |
| - | + | ||
| - | ^ Field ^ Type ^ Description ^ | + | |
| - | | station | Station | Reference to a station defined in `loadStations()`. | | + | |
| - | | platform | number | Platform number the train uses at this station. Must exist in BP_StationDefinition. | | + | |
| - | | departure | number | Minutes after service start/spawn when the train departs this stop. | | + | |
| - | | speedLimit | number | Speed limit applied after departing this stop (signal logic dependent). | | + | |
| - | | routeSettingMaxETA | number (optional) | How many minutes before departure the route (Fahrstraße) should be requested/ | + | |
| - | | altPlatform | table< | + | |
| - | + | ||
| - | + | ||
| - | ==== 6.4 altPlatform (Alternative Platforms) ==== | + | |
| - | + | ||
| - | Example: | + | |
| - | + | ||
| - | <code lua> | + | |
| - | altPlatform = { " | + | |
| - | </ | + | |
| - | + | ||
| - | ⚠️ Use string values (`" | + | |
| - | + | ||
| - | This allows AI to select another platform if: | + | |
| - | * the preferred platform is blocked | + | |
| - | * dispatching assigns an alternative | + | |
| - | + | ||
| - | ==== 6.5 routeSettingMaxETA (Route Pre-Setting) ==== | + | |
| - | + | ||
| - | Example: | + | |
| - | + | ||
| - | <code lua> | + | |
| - | routeSettingMaxETA = 0.5 | + | |
| - | </ | + | |
| - | + | ||
| - | Meaning: | + | |
| - | * the route will be requested/ | + | |
| - | + | ||
| - | This can help avoid early route locking and improves traffic handling at busy stations. | + | |
| - | + | ||
| - | ==== 6.6 clone() + DayMask (Creating Services) ==== | + | |
| - | + | ||
| - | A timetable template does not spawn trains by itself. | + | |
| - | It must be cloned into **real timetable entries** and inserted into `self.timetables`. | + | |
| - | + | ||
| - | For day-based schedules, use `DayMask`: | + | |
| - | + | ||
| - | <code lua> | + | |
| - | local DM = DayMask; | + | |
| - | </ | + | |
| - | + | ||
| - | ^ DayMask ^ Meaning ^ | + | |
| - | | DM.Weekdays | Monday to Friday | | + | |
| - | | DM.Weekends | Saturday and Sunday | | + | |
| - | | DM.Sat | Saturday only | | + | |
| - | | DM.Sun | Sunday only | | + | |
| - | | DM.Always | Every day | | + | |
| - | + | ||
| - | The typical workflow is: | + | |
| - | * Create a timetable template | + | |
| - | * Clone it for a start time (optionally with a day mask) | + | |
| - | * Either insert a single trip, or generate a repeating service | + | |
| - | + | ||
| - | ==== 6.6.1 Repeating Services (Interval Based) ==== | + | |
| - | + | ||
| - | This creates a repeating service between two times: | + | |
| - | + | ||
| - | <code lua> | + | |
| - | TableUtil.insertList( | + | |
| - | self.timetables, | + | |
| - | self.TestLine_Dir1: | + | |
| - | ); | + | |
| - | + | ||
| - | TableUtil.insertList( | + | |
| - | self.timetables, | + | |
| - | self.TestLine_Dir2: | + | |
| - | ); | + | |
| </ | </ | ||
| ^ Call ^ Description ^ | ^ Call ^ Description ^ | ||
| - | | clone(daytime(HH, | + | | setStationList |
| - | | repeatUntil(daytime(HH, MM), interval) | Repeats every X minutes until the end time. | | + | | setTimetableList |
| - | | TableUtil.insertList(list, | + | |
| - | Result: | + | If this step is missing or incomplete: |
| - | * a full service pattern is generated automatically | + | * AI traffic will not operate |
| + | * station-based routing may fail | ||
| - | ==== 6.6.2 Single Timetable Entries (Manual Trips) ==== | + | ----- |
| - | If you want to schedule **individual trips** (first/last train, gaps, special runs), | + | ===== Final Step – Build & Test the Map ===== |
| - | insert a single cloned entry: | + | |
| - | <code lua> | + | Continue with: |
| - | table.insert(self.timetables, | + | * [[manual:subwaysim:map_construction:build_mod|Build Mod (.pak)]] |
| - | table.insert(self.timetables, | + | |
| - | </ | + | |
| - | + | ||
| - | This creates exactly one departure at the given time. | + | |
| - | + | ||
| - | Use this approach when you need full control over: | + | |
| - | * exact departure times | + | |
| - | * exceptions or gaps | + | |
| - | * different patterns on different days | + | |
| - | + | ||
| - | + | ||
| - | ==== 6.7 Useful Variations (Based on the TestMap) ==== | + | |
| - | + | ||
| - | The following patterns are commonly used when building more advanced schedules. | + | |
| - | They are shown here using the **TestMap stations** (`TS`, `TSD`, `TSA`, `DP`). | + | |
| - | + | ||
| - | + | ||
| - | ==== 6.7.1 Short Runs (Start or Terminate Early) ==== | + | |
| - | + | ||
| - | Sometimes a service should start later or terminate earlier than the full route. | + | |
| - | This is useful for: | + | |
| - | * depot in/out runs | + | |
| - | * special services | + | |
| - | * partial line operations | + | |
| - | + | ||
| - | Example: terminate at `TSD` (short turn / depot related movement): | + | |
| - | + | ||
| - | <code lua> | + | |
| - | local TS_to_TSD = self.TestLine_Dir1: | + | |
| - | + | ||
| - | table.insert(self.timetables, | + | |
| - | </ | + | |
| - | + | ||
| - | Example: start at `TSD` (depot insertion into service): | + | |
| - | + | ||
| - | <code lua> | + | |
| - | local TSD_to_TSA = self.TestLine_Dir1: | + | |
| - | + | ||
| - | table.insert(self.timetables, | + | |
| - | </ | + | |
| - | + | ||
| - | + | ||
| - | ==== 6.7.2 Platform Overrides (TestMap Example) ==== | + | |
| - | + | ||
| - | If you want to use the same template but spawn on a different platform, | + | |
| - | you can override platform numbers after cloning. | + | |
| - | + | ||
| - | Example: force first stop to use platform 1 instead of 2 at TS: | + | |
| - | + | ||
| - | <code lua> | + | |
| - | local TS_Platform1 = self.TestLine_Dir1: | + | |
| - | TS_Platform1: | + | |
| - | + | ||
| - | table.insert(self.timetables, | + | |
| - | </ | + | |
| - | + | ||
| - | This is useful if: | + | |
| - | * multiple platforms exist | + | |
| - | * you want different patterns at different times of day | + | |
| - | * you temporarily reroute services during testing | + | |
| - | + | ||
| - | ==== 6.7.3 Service Runs (Non-Passenger Moves) ==== | + | |
| - | + | ||
| - | A service run is a trip that should not be treated as a normal passenger service. | + | |
| - | + | ||
| - | Example: a depot-related move to TS marked as service run: | + | |
| - | + | ||
| - | <code lua> | + | |
| - | local DP_to_TS_SR = self.TestLine_Dir2: | + | |
| - | : | + | |
| - | : | + | |
| - | : | + | |
| - | + | ||
| - | table.insert(self.timetables, | + | |
| - | </ | + | |
| - | + | ||
| - | ==== 6.7.4 Force Unique Stop Lists (Safe Editing) ==== | + | |
| - | + | ||
| - | If you modify stop properties (platforms, PIS text, flags), | + | |
| - | it can be helpful to ensure the stop list is unique: | + | |
| - | + | ||
| - | <code lua> | + | |
| - | local Variant = self.TestLine_Dir1: | + | |
| - | Variant: | + | |
| - | </ | + | |
| - | + | ||
| - | This prevents accidental shared stop references when creating multiple variants. | + | |
| ---- | ---- | ||
| - | ===== 7) Depots and Dispatching | + | ===== Additional Resources |
| - | + | ||
| - | This section defines: | + | |
| - | * depot storage spaces (optional) | + | |
| - | * turnaround / dispatch behavior at stations | + | |
| - | + | ||
| - | ==== 7.1 Depots (Parking Tracks / Depot Spaces) ==== | + | |
| - | + | ||
| - | Depots define **where AI trains are allowed to park** when they are not in service. | + | |
| - | They are also used by the ControlCenter for dispatching and (later) career mode. | + | |
| - | + | ||
| - | In the TestMap, the depot station is: | + | |
| - | + | ||
| - | * `DP` (Depot) | + | |
| - | + | ||
| - | And it provides these depot tracks: | + | |
| - | + | ||
| - | * 51, 52, 53, 54 (long depot tracks) | + | |
| - | * 60 (short depot / test track) | + | |
| - | + | ||
| - | ==== 7.1.1 Depot Table Structure ==== | + | |
| - | + | ||
| - | `self.depots` is a table that groups depot tracks into named blocks (groups). | + | |
| - | Each group contains a list of `Depot_DepotSpace` entries. | + | |
| - | + | ||
| - | ^ Field ^ Meaning ^ | + | |
| - | | station | Station reference (must exist in `self.stations`) | | + | |
| - | | platform | Track / platform ID as defined in the BP_StationDefinition | | + | |
| - | | direction | Which direction trains should park/spawn facing (1 or 2) | | + | |
| - | | noParkingTimetable | If true: no dedicated parking timetable should be generated for this track (useful to keep a track free) | | + | |
| - | + | ||
| - | ==== 7.1.2 TestMap Example (DP 51–54 + 60) ==== | + | |
| - | + | ||
| - | <code lua> | + | |
| - | ---@type table< | + | |
| - | self.depots = { | + | |
| - | + | ||
| - | -- Main depot area (long tracks) | + | |
| - | [" | + | |
| - | { station = self.stations.DP, | + | |
| - | { station = self.stations.DP, | + | |
| - | { station = self.stations.DP, | + | |
| - | { station = self.stations.DP, | + | |
| - | }, | + | |
| - | + | ||
| - | -- Short depot / test track (useful to keep free or for special moves) | + | |
| - | [" | + | |
| - | { station = self.stations.DP, | + | |
| - | }, | + | |
| - | }; | + | |
| - | </ | + | |
| - | + | ||
| - | Notes: | + | |
| - | * The group keys (`" | + | |
| - | * `platform` must match the platform numbers inside your **BP_StationDefinition** for DP. | + | |
| - | * Use `noParkingTimetable = true` if you want to keep a track free (e.g. for turnarounds or testing). | + | |
| - | + | ||
| - | + | ||
| - | ==== 7.2 Dispatching Strategies ==== | + | |
| - | + | ||
| - | Dispatching Strategies define how trains are handled **outside of normal passenger service**. | + | |
| - | They are used to: | + | |
| - | + | ||
| - | * turn trains around at terminal stations, | + | |
| - | * spawn trains from depots, | + | |
| - | * send trains back to depots, | + | |
| - | * resolve platform conflicts, | + | |
| - | * and keep traffic flowing when timetables alone are not sufficient. | + | |
| - | + | ||
| - | Dispatching is handled by the **ControlCenter** and works in addition to normal timetables. | + | |
| - | + | ||
| - | ===== 7.2.1 Basic Structure ===== | + | |
| - | + | ||
| - | Dispatching strategies are defined as a table, grouped by station: | + | |
| - | + | ||
| - | <code lua> | + | |
| - | ---@type table< | + | |
| - | self.dispatchingStrategies = { | + | |
| - | [self.stations.WA] = { | + | |
| - | -- strategies for this station | + | |
| - | }, | + | |
| - | } | + | |
| - | </ | + | |
| - | + | ||
| - | Each station can have **multiple strategies**. | + | |
| - | They are evaluated **top to bottom**, so order matters. | + | |
| - | + | ||
| - | + | ||
| - | ==== 7.2.2 When Dispatching Is Used ==== | + | |
| - | + | ||
| - | Dispatching strategies are evaluated when: | + | |
| - | + | ||
| - | * a timetable ends at a station, | + | |
| - | * a train needs to turn around, | + | |
| - | * no suitable train is available for a departure, | + | |
| - | * or a train must be moved to or from a depot. | + | |
| - | + | ||
| - | If no strategy matches, the train will remain idle. | + | |
| - | + | ||
| - | + | ||
| - | ===== 7.2.3 Strategy Fields ===== | + | |
| - | + | ||
| - | Each dispatching strategy can define the following fields: | + | |
| - | + | ||
| - | ^ Field ^ Description ^ | + | |
| - | | sourceStation | Station where the train currently is. Use `nil` for depot spawns. | | + | |
| - | | targetStation | Station the train should serve next. Use `nil` for depot despawn. | | + | |
| - | | sourcePlatforms | Allowed platforms the train may come from. | | + | |
| - | | targetPlatforms | Allowed platforms the train may go to. | | + | |
| - | | depotName | Name of the depot (as defined in the depots table). | | + | |
| - | | minLayover | Minimum minutes the train must wait before reuse. | | + | |
| - | | keepLine | Try to keep the train on the same line. | | + | |
| - | | replaceFirstPlatform | Replace the first stop platform if needed. | | + | |
| - | | replaceLastPlatform | Replace the last stop platform if needed. | | + | |
| - | | overrideFirstPlatform | Force a specific first platform. | | + | |
| - | | overrideLastPlatform | Force a specific last platform. | | + | |
| - | | timetable | Optional hidden timetable used for movements. | | + | |
| - | + | ||
| - | Not all fields are required for every strategy. | + | |
| - | + | ||
| - | + | ||
| - | ==== 7.2.4 Pattern A — Simple Turnaround ==== | + | |
| - | + | ||
| - | This is the most common case: | + | |
| - | A train arrives at a station and turns around to serve the opposite direction. | + | |
| - | + | ||
| - | Example (Test Map): | + | |
| - | + | ||
| - | <code lua> | + | |
| - | { | + | |
| - | sourceStation = self.stations.Kbo, | + | |
| - | targetStation = self.stations.Kbo, | + | |
| - | sourcePlatforms = { " | + | |
| - | targetPlatforms = { " | + | |
| - | minLayover = 3, | + | |
| - | } | + | |
| - | </ | + | |
| - | + | ||
| - | What happens: | + | |
| - | + | ||
| - | * a train arriving on platform 1 | + | |
| - | * waits at least 3 minutes | + | |
| - | * and departs again from platform 2 | + | |
| - | + | ||
| - | No depot is involved. | + | |
| - | + | ||
| - | + | ||
| - | ==== 7.2.5 Pattern B — Turnaround with Internal Movement ==== | + | |
| - | + | ||
| - | Some stations require a **shunting move** to turn a train. | + | |
| - | + | ||
| - | In this case, a hidden timetable is attached: | + | |
| - | + | ||
| - | <code lua> | + | |
| - | { | + | |
| - | sourceStation = self.stations.Go, | + | |
| - | targetStation = self.stations.Go, | + | |
| - | sourcePlatforms = { " | + | |
| - | targetPlatforms = { " | + | |
| - | minLayover = 3, | + | |
| - | timetable = Timetable: | + | |
| - | : | + | |
| - | : | + | |
| - | station = self.stations.Go, | + | |
| - | platform = " | + | |
| - | departure = 2, | + | |
| - | turnAround = true, | + | |
| - | }) | + | |
| - | : | + | |
| - | station = self.stations.Go, | + | |
| - | platform = " | + | |
| - | departure = 3, | + | |
| - | }), | + | |
| - | } | + | |
| - | </ | + | |
| - | + | ||
| - | This allows: | + | |
| - | * temporary use of siding or crossover tracks | + | |
| - | * clean turnarounds without blocking passenger platforms | + | |
| - | + | ||
| - | + | ||
| - | ==== 7.2.6 Pattern C — Spawning Trains from a Depot ==== | + | |
| - | + | ||
| - | When no train is available, dispatching can **fetch a train from a depot**. | + | |
| - | + | ||
| - | Example: | + | |
| - | + | ||
| - | <code lua> | + | |
| - | { | + | |
| - | sourceStation = nil, | + | |
| - | targetStation = self.stations.WA, | + | |
| - | targetPlatforms = { " | + | |
| - | depotName = " | + | |
| - | overrideFirstPlatform = " | + | |
| - | timetable = Timetable: | + | |
| - | : | + | |
| - | : | + | |
| - | station = self.stations.WA, | + | |
| - | platform = " | + | |
| - | departure = -5, | + | |
| - | }) | + | |
| - | : | + | |
| - | station = self.stations.WA, | + | |
| - | platform = " | + | |
| - | departure = -3, | + | |
| - | }), | + | |
| - | } | + | |
| - | </ | + | |
| - | + | ||
| - | Key points: | + | |
| - | + | ||
| - | * `sourceStation = nil` means the train comes from a depot | + | |
| - | * the depot name must match the depots table | + | |
| - | * negative departure times happen **before** the actual service | + | |
| - | + | ||
| - | + | ||
| - | ==== 7.2.7 Pattern D — Sending Trains to a Depot ==== | + | |
| - | + | ||
| - | After service ends, trains can be removed from traffic. | + | |
| - | + | ||
| - | Example: | + | |
| - | + | ||
| - | <code lua> | + | |
| - | { | + | |
| - | sourceStation = self.stations.WA, | + | |
| - | sourcePlatforms = { " | + | |
| - | targetStation = nil, | + | |
| - | depotName = " | + | |
| - | timetable = Timetable: | + | |
| - | : | + | |
| - | : | + | |
| - | station = self.stations.WA, | + | |
| - | platform = " | + | |
| - | departure = 2, | + | |
| - | }) | + | |
| - | : | + | |
| - | station = self.stations.WA, | + | |
| - | platform = " | + | |
| - | departure = 6, | + | |
| - | }), | + | |
| - | } | + | |
| - | </ | + | |
| - | + | ||
| - | Here: | + | |
| - | + | ||
| - | * the train leaves passenger service | + | |
| - | * moves into the depot | + | |
| - | * and is no longer available for dispatching | + | |
| - | + | ||
| - | + | ||
| - | ===== 7.2.8 Hidden Timetables ===== | + | |
| - | + | ||
| - | Timetables inside dispatching strategies: | + | |
| - | + | ||
| - | * are not shown to the player | + | |
| - | * are always marked as `setIsServiceRun(true)` | + | |
| - | * are used only for internal movements | + | |
| - | + | ||
| - | They allow precise control over: | + | |
| - | * routing | + | |
| - | * speed limits | + | |
| - | * platform usage | + | |
| - | * turnarounds | + | |
| - | + | ||
| - | + | ||
| - | ===== 7.2.9 Strategy Order ===== | + | |
| - | + | ||
| - | Dispatching strategies are evaluated **in order**. | + | |
| - | + | ||
| - | Recommended structure per station: | + | |
| - | + | ||
| - | 1. normal turnarounds | + | |
| - | 2. depot spawn strategies | + | |
| - | 3. depot despawn strategies | + | |
| - | 4. fallback strategies | + | |
| - | + | ||
| - | This avoids unnecessary depot movements and keeps traffic stable. | + | |
| - | + | ||
| - | + | ||
| - | ===== 7.2.10 Common Pitfalls ===== | + | |
| - | + | ||
| - | * depot names not matching the depots table | + | |
| - | * missing `setIsServiceRun(true)` on hidden timetables | + | |
| - | * conflicting platform definitions | + | |
| - | * wrong strategy order | + | |
| - | + | ||
| - | If dispatching behaves unexpectedly, | + | |
| - | + | ||
| - | + | ||
| - | ---- | + | |
| - | + | ||
| - | ===== 8) Career Mode (Optional) ===== | + | |
| - | + | ||
| - | `loadCareerMode()` is optional and currently empty. | + | |
| - | + | ||
| - | This is where career mode related data can be initialized later. | + | |
| - | + | ||
| - | ---- | + | |
| - | + | ||
| - | ===== 9) Registering Stations and Timetables ===== | + | |
| - | + | ||
| - | The final step is registering runtime data with the ControlCenter: | + | |
| - | + | ||
| - | <code lua> | + | |
| - | controlCenter: | + | |
| - | controlCenter: | + | |
| - | </ | + | |
| - | + | ||
| - | ^ Call ^ Description ^ | + | |
| - | | setStationList | Registers all stations for routing, UI and spawning logic. | | + | |
| - | | setTimetableList | Registers AI services plus dispatching and depot logic. | | + | |
| - | If this function is missing or incomplete: | + | * [[manual:sdk_changelog|SDK Changelog]] |
| - | * AI traffic will not work | + | * [[manual: |
| - | * stations may not be recognized for routing | + | * [[manual: |
| {{page> | {{page> | ||
manual/subwaysim/map_construction/create_maplua.1768396123.txt.gz · Last modified: by dcs
