Modulare Konstruktionen¶
Modulare Konstruktionen lassen sich nach dem Bau noch verändern: Der Spieler setzt Module in Slots ein und entfernt sie wieder. Dazu gehören Bahnhöfe, Flughäfen, Häfen, Lager, das Hauptquartier und Industrien mit ihren Feldern. Die Konstruktion selbst ist eine gewöhnliche .con.lua mit einer Update-Funktion, wie unter Konstruktionen beschrieben. Diese Seite behandelt Slots, Module, die Reihenfolge, in der ihre Skripte laufen, und Vorlagen, die einer neuen Konstruktion ihre ersten Module mitgeben. Am Ende steht unter Eine minimale modulare Konstruktion eine kleine Konstruktion mit einem Modul, mit der du anfangen kannst. Das offizielle Wiki behandelt dasselbe Thema auf Modular Constructions und Construction Templates.
Wie die Skripte laufen¶
Jedes Mal, wenn eine modulare Konstruktion in der Vorschau erscheint oder gebaut wird, führt construction.constructWithModules in base/content/scripts/scripts/construction/construction.script.tl die Skripte in dieser Reihenfolge aus:
updateFn(captureParams, params)der Konstruktion baut das Grundergebnis, einschließlichresult.slots.costundbulldozeCostder Konstruktion werden mitcosts.infrastructureCostScaleaus den Skriptparametern multipliziert. Das Basisspiel setzt diesen Wert aus der Einstellung „Infrastrukturkosten“ (Infrastructure Costs) (base/content/base/base/mod.script.tl). IstmaintenanceCost0 oder nicht gesetzt, wird darauscost / 6, berechnet vor der Skalierung. Die Modulpreise kommen später dazu und werden nicht skaliert.- Sind
params.modulesundresult.slotsvorhanden, werden die Module nach aufsteigender Slot-ID sortiert. Für jedes Modul wird der Slot mit dieser ID inresult.slotsgesucht. Fehlt er und istresult.callInvalidModulesnichttrue, wird das Modul übersprungen. - Hat das Modul ein Update-Skript, wird dessen
updateFnmit dem Ergebnis, der Transformation des Slots und dem Tag"__module_<slotId>"aufgerufen. Während es läuft, istparams.seedder Seed der Konstruktion plus die Slot-ID. - Direkt nach diesem Aufruf addiert
modulesutil.addCosts(result, module)die Wertemetadata.price,metadata.maintenanceCostundmetadata.bulldozePricedes Moduls zum Ergebnis. - Nach dem letzten Modul läuft
result.terminateConstructionHook(), falls die Konstruktion diese Funktion gesetzt hat. Wie die Schritte 3 bis 5 passiert das nur, wennparams.modulesundresult.slotsbeide vorhanden sind.
constructionScript in der Basiskonfiguration zeigt auf constructWithModules (base/content/base/base/mod.script.tl). Für Konstruktionen ohne Module hat die Konfiguration kein eigenes Skript. Vermutlich nimmt das Spiel diesen Weg also für alle Konstruktionen, samt Skalierung der Kosten.
Weil die Module nach der Konstruktion und in der Reihenfolge der Slot-IDs laufen, sieht ein Modul alle Slots und Daten, die die Konstruktion und alle früheren Module in result abgelegt haben. Es kann auch neue Slots für spätere Module anlegen. Konstruktionen legen außerdem eigene Hilfsfunktionen in result ab, die die Module aufrufen. Der Bahnhof macht das mit GetCoord und GetRoofAt.
Die Update-Funktion der Konstruktion¶
Neben den Parametern des Spielers ordnet params.modules jeder Slot-ID das Modul zu, das dort sitzt (ModuleUpdateFnParams.Module):
modules = {
[10001000] = {
metadata = {},
name = "airfield_main_building.module",
updateScript = { fileName = "", params = {} },
variant = 0,
},
},
metadata ist eine Kopie der Tabelle metadata des Moduls, name die Moduldatei und updateScript seine Update-Funktion. variant ändert sich, wenn der Spieler beim Platzieren eines Moduls M oder N drückt, und kann negativ werden. Der Standardwert ist 0. Das Hauptquartier nutzt den Wert als Drehung in Vierteldrehungen (base/content/landmarks/hq/hq/headquarter_addon.script.tl).
result.cost sind die Kosten der Konstruktion allein. Das Spiel skaliert sie in Schritt 2 und addiert in Schritt 5 die Modulpreise.
Slots¶
result.slots listet die Slots, die gerade existieren (Slot):
| Feld | Bedeutung |
|---|---|
id |
nicht negative, eindeutige ID; sie ist der Schlüssel in params.modules |
type |
hier lassen sich nur Module mit demselben type bauen |
transf |
Position relativ zum Ursprung der Konstruktion |
spacing |
Größe des Slots um transf, { -x, x, -y, y } |
height |
Höhe über transf; dient zusammen mit spacing zum Auswählen und Abreißen |
shape |
Markierungssymbol: 0 Quadrat, 1 Dreieck, 2 Rechteck quer, 3 Rechteck längs |
autofill |
der Slot gilt als belegt, wenn eine Industrie zum ersten Mal gebaut wird (Felder und Satelliten) |
alignToTerrain |
der Slot folgt der Geländehöhe |
replaceable |
ein Modul desselben Typs kann das Modul im Slot ersetzen |
Das Wiki und der ausgelieferte Code (base/content/industries/fieldutil.lua) schreiben autofill, die Teal-Definition schreibt autoFill.
Viele Basiskonstruktionen kodieren eine Rasterposition und den Slot-Typ in die ID. Das Lager, aus base/content/warehouses/warehouses/warehouse.script.lua:
local EncodeSlotId = function(coord, type)
return typesNum * (coordNum * (coord.y + coordOffset) + (coord.x + coordOffset)) + type2id[type]
end
Seine Slots legt es in updateFn mit table.insert(result.slots, { id = ..., transf = ..., type = type, spacing = {...}, height = ..., replaceable = true }) an.
result.slotConfig setzt Grenzen pro Slot-Typ (SlotConfig). maxModules ist die Höchstzahl an Modulen dieses Typs in der ganzen Konstruktion, message der Text, der im Menü auf dem Modul erscheint, wenn es sich nicht bauen lässt. Mit skipCollisionCheck = true werden die Slot-Markierungen nicht mehr rot, wenn etwas im Weg steht (die Collider des Moduls zählen trotzdem). Laut Wiki hat maxModules = -2 eine besondere Bedeutung: Der Modul-Knopf ist aktiv, solange message leer ist, und gesperrt, sobald eine Meldung gesetzt ist. Der Flughafen verlangt damit eine zweite Landebahn, bevor Terminal B gebaut werden kann (base/content/stations/air/air/airport.script.lua):
result.slotConfig = {
["2nd_runway"] = { maxModules = -1, message = "" },
terminal_B = {
maxModules = -2,
message = hasSecondRunway and "" or _("You Need a 2nd Runway"),
},
}
Mit result.callInvalidModules = true laufen Module auch dann, wenn ihre Slot-ID nicht in result.slots steht. Ihr transform ist dann nil.
Module¶
Ein Modul ist eine .module.lua-Datei (121 im Basisspiel), beschrieben durch ModuleDesc. Aus base/content/warehouses/warehouses/wh_bulk.module.lua (gekürzt):
function data()
return {
menuCategory = {
categories = {
{ category = "modules_warehouse", order = 100, },
},
},
description = {
name = _("WAREHOUSE_BULK_NAME"),
description = _("WAREHOUSE_BULK_DESCRIPTION"),
icon = "::/warehouses/wh_bulk_module.tga",
},
availability = { yearFrom = 1850, yearTo = 0, },
type = "warehouse_large",
metadata = {
type = "bulk",
specialization = "BULK",
price = 300000,
maintenanceCost = 50000,
},
updateScript = {
fileName = "modules.script@bulk.updateFn",
params = {}
},
builderAudioRes = "::/gui/construction/sound/buildoze_module.builder_audio",
getModelsScript = {
fileName = "modules.script@bulk.getModelsFn",
params = {}
},
}
end
| Feld | Bedeutung |
|---|---|
description, availability, menuCategory |
wie bei Konstruktionen; Modul-Tabs sind die Kategorien modules_* (siehe Baumenü) |
type |
„a module of a specific type can be built only on slots with the same type“ (Kommentar in der Definition) |
metadata |
freie Daten für die Konstruktion und andere Module; price, maintenanceCost und bulldozePrice werden zu den Kosten addiert |
autoRemovable |
wird entfernt, wenn etwas anderes darüber gebaut wird, wie bei Feldern von Farmen (Standard false) |
updateScript |
„Script function that gets called once per build module after the updateScript of the construction has run“ |
getModelsScript |
„Script function used to generate module preview when building with module builder“ |
builderAudioRes |
das Bau-Audioset, das beim Bauen spielt; alle 121 Basismodule nutzen ::/gui/construction/sound/buildoze_module.builder_audio (der Dateiname ist tatsächlich so geschrieben) |
Alle 121 Basismodule setzen menuCategory. Ohne das Feld hat das Modul keinen Tab im Modulmenü.
Das Modulbeispiel im Wiki enthält außerdem buildMode = "SINGLE". Dieses Feld gibt es in ModuleDesc nicht, und kein ausgeliefertes Modul nutzt es.
getModelsFn¶
getModelsFn(captureParams) gibt die Modelle zurück, die dem Mauszeiger folgen, solange das Modul über keinem Slot ist: eine Liste von { id = "<model>.mdl", transf = ... }. Wenn die Modelle des Moduls relativ zu einem Slot sitzen, der gegenüber der Konstruktion versetzt ist, schiebst du sie hier zurück. Das Lokschuppen-Beispiel im Wiki gibt seine drei Schuppenmodelle mit transf.transl(vec3.new(-30, 0, 0)) zurück, weil seine Slots 30 m von der Mitte der Drehscheibe entfernt liegen.
updateFn¶
Das Spiel ruft die Update-Funktion des Moduls mit sieben Argumenten auf:
| Argument | Inhalt |
|---|---|
captureParams |
die params der updateScript-Referenz des Moduls |
result |
das Ergebnis der Konstruktion und aller Module davor |
transform |
die Transformation des Slots; wende sie auf alles an, was relativ zum Slot platziert wird. Mit callInvalidModules ist sie nil |
tag |
"__module_<slotId>"; setze ihn auf die Modelle des Moduls, damit sie mit dem Modul entfernt werden |
slotId |
die Slot-ID |
addModelFn |
addModel(name, transf, tag?, models?): multipliziert transf mit der Transformation des Slots, setzt den Tag und hängt an models an (Standard result.models); gibt den Index zurück |
constrParams |
die params, die die Update-Funktion der Konstruktion bekommen hat, einschließlich modules |
Hintere Argumente darfst du weglassen. Laut Wiki soll die Funktion result zurückgeben. constructWithModules ignoriert den Rückgabewert aber. Das Modul muss result also direkt verändern. Das Wiki-Beispiel für das Hallendach des Bahnhofs deklariert ein achtes Argument params, das constructWithModules gar nicht übergibt.
Eine kurze Fassung aus dem Wiki, die ein Hangarmodell und eine Bodenfläche hinzufügt:
updateFn = function(captureParams, result, transform, tag)
local sub = result.subconstructions[1]
sub.models[#sub.models + 1] = { id = "hangar.mdl", transf = transform, tag = tag }
local faces = { {-25.0, -25.0, 0.0, 1.0}, {25.0, -25.0, 0.0, 1.0}, ... }
modulesutil.TransformFaces(transform, faces)
sub.groundFaces[#sub.groundFaces + 1] = {
face = faces,
modes = { { type = "FILL", key = "airfield_hangar.gtex.lua" } },
}
end,
In den Lagermodulen lautet die Signatur (captureParams, result, transform, tag, slotId, addModelFn, params). Sie fügen dem result, das die Konstruktion gebaut hat, Modelle und neue Slots hinzu.
Über constrParams.modules können Module auf ihre Nachbarn reagieren. Das Lokschuppen-Beispiel im Wiki berechnet die IDs der Nachbarslots aus slotId und setzt eine Seitenwand nur dort, wo der Nachbar kein Schuppen ist:
local moduleLeft = constrParams.modules[leftIndex]
if not (moduleLeft ~= nil and moduleLeft.metadata ~= nil and moduleLeft.metadata.type == "shed") then
addModel("shed_wall_left.mdl", transf.transl(vec3.new(-30, 0, 0)), tag, result.subconstructions[1].models)
end
Eine Skriptdatei kann die Funktionen mehrerer Module in einer verschachtelten Tabelle enthalten. Das Modul gibt sie dann als "roundhouse_modules.script@shed.updateFn" an:
function data()
return {
shed = { updateFn = updateFnShed, getModelsFn = getModelsFnShed },
empty = { updateFn = updateFnEmpty, getModelsFn = getModelsFnEmpty },
}
end
Ein neues Modul für eine Basiskonstruktion braucht nur einen Slot-type dieser Konstruktion. Das Hallendach-Beispiel im Wiki hat type = "passenger_platform_roof", den Typ der Bahnsteigdächer aus dem Basisspiel. Es passt daher überall dorthin, wo auch diese hinpassen.
Die Preprocess-Funktion¶
Wird ein Modul hinzugefügt oder entfernt, passt eine Preprocess-Funktion die Parameter der Konstruktion an, bevor das Update läuft. Weder ConstructionDesc noch das Wiki dokumentieren sie. 60 .con.lua-Dateien des Basisspiels setzen preProcessScript. Die Standardfunktion steht in base/content/base/base/base_config.lua:
defaultPreprocessFn = function(captureParams, params, change)
local modules = params.modules
if change.added then
modules[change.slotId] = change.module
else
modules[change.slotId] = nil
end
return params
end
warehouse.con.lua setzt mit preProcessScript = { fileName = "warehouse.script@preProcessFn" } eine eigene, ebenso airport.con.lua und modular_terminal.con.lua.
Upgrade-Skript¶
Bei einer modularen Konstruktion erhält upgradeFn(captureParams, params, slotId, constructionConfig) die ID des Slots, auf den der Mauszeiger zeigte, als der Spieler das Werkzeug angewendet hat. Sonst funktioniert es wie unter Konstruktionen beschrieben.
Vorlagen¶
Eine Vorlage ist ein Menüeintrag, der eine Konstruktion mit einer Anfangsausstattung an Modulen baut. In den Spieldateien gibt es zwei Formen.
Im Basisspiel kommt eine modulare Konstruktion über ihre Vorlagen ins Baumenü. airfield.con.lua, airport.con.lua, harbor_modular.con.lua und warehouse.con.lua haben kein menuCategory. Ihre Einträge sind die .metacon.tl-Dateien. In den 11 Dateien mit constructionTemplates trägt jede Vorlage ihr eigenes menuCategory, und das Baumenü übergeht das menuCategory der .con.lua: Es legt einen Eintrag pro Vorlage an (getConstructionDefinitions in base/content/gui/gui/construction/construction_react_util.tl). Eine .con.lua ohne Vorlagen bekommt einen eigenen Eintrag, wenn sie ein menuCategory hat, wie die Industrien. Eine Metakonstruktion, die sie baut, fügt einen zweiten hinzu. Das createTemplateFn der Industrien ist leer. Was der eigene Eintrag einer Konstruktion platziert, wenn ihr createTemplateScript Module zurückgibt, geht aus den Dateien deshalb nicht hervor.
Eine Metakonstruktion ist eine .metacon.tl-Datei (26 im Basisspiel), beschrieben durch MetaConstructionDesc. Laut dem Kommentar dieses Typs ersetzt sie die veralteten Konstruktionsvorlagen („replaces the deprecated construction templates“). Sie hat die Menüfelder einer Konstruktion (availability, description, menuCategory, soundConfig, params, order, heightModView, ...) und ein createTemplateScript. Die Flugplätze sind ein Beispiel, hier base/content/stations/air/air/airfield_era_a.metacon.tl:
local airfield = ug_require "::airfield.tl"
return airfield.makeTemplate(airfield.eraAStart, airfield.eraBStart)
Eine .metacon.tl gibt ihre Beschreibungstabelle auf oberster Ebene zurück, ohne function data(). Alle 26 im Basisspiel enden mit so einem return. .metacon.lua-Dateien gibt es im Spiel nicht, schreib diese Dateien also in Teal.
airfield.tl gibt pro Epoche eine Beschreibungstabelle mit createTemplateScript = { fileName = "airfield.script@createTemplateFn", params = { } } zurück. Die Einträge der Lager funktionieren genauso über warehouse.makeTemplate.
Die ältere Form ist eine Liste constructionTemplates in der .con.lua. Jeder Eintrag ist ein ConstructionTemplate mit type = "DYNAMIC", availability, description, data.params und menuCategory. ConstructionDesc markiert das Feld mit „[DEPRECATED] Use metaconstructions instead“, trotzdem nutzen es noch 11 Basisdateien, darunter der Bahnhof (modular_station.con.lua), die Depots und die modulare Straßenhaltestelle. Diese .con.lua-Dateien setzen außerdem selbst ein createTemplateScript, ebenso Industrien wie forest.con.lua. 68 .con.lua-Dateien des Basisspiels haben eines.
Die Wiki-Seite Construction Templates vermischt beide Formen. Sie sagt, Vorlagen würden in metacon.lua-Dateien definiert, und zeigt sie als Liste von Einträgen mit type = "DYNAMIC". Im Basisspiel heißen die Dateien .metacon.tl, und jede gibt eine einzelne Beschreibungstabelle ohne type zurück. Die Liste mit type = "DYNAMIC" hat die Form der veralteten constructionTemplates.
createTemplateFn¶
createTemplateFn(captureParams, params) legt fest, welche Konstruktion mit welchen Modulen gebaut wird. Laut Wiki enthält params die Werte paramX und paramY (die Hotkeys), einen seed, der mit jeder Platzierung oder jedem Vorschlag steigt, year, templateIndex (welche Vorlage benutzt wurde) und die eigenen Parameter der Vorlage. Der Flugplatz, aus base/content/stations/air/air/airfield.script.lua:
createTemplateFn = function(captureParams, params)
local result = {}
local hangar = params.hangar == 1
local terminals = params.terminals and params.terminals or 1
if hangar then
result[terminalSlotId + 0 ] = "airfield/af_hangar.module"
end
local offset = hangar and 2 or 0
result[terminalSlotId + offset ] = "airfield/af_main.module"
result[terminalSlotId + offset + 2 ] = "airfield/af_terminal.module"
-- ... weitere Terminals für params.terminals > 1 ...
return {
constructions = {
{
modules = result,
constructionFileName = "airfield.con",
},
}
}
end,
Jeder Eintrag von constructions hat modules (ordnet Slot-IDs Moduldateien zu; {} für eine Konstruktion ohne Module) und constructionFileName, optional außerdem transf (Versatz zum Ursprung der Vorlage, standardmäßig keiner) und params (Parameter für die Konstruktion, standardmäßig die params der Vorlage). Das createTemplateFn des Lagers in warehouse.script.lua setzt ein Modul aus seinen captureParams in einen Slot:
Eine minimale modulare Konstruktion¶
Die modularen Konstruktionen des Basisspiels sind groß (modular_terminal.script.lua hat über 3.000 Zeilen). Die Dateien unten ergeben zusammen die kleinste funktionierende Form: eine Konstruktion mit einem Slot, ein Modul für diesen Slot und eine Metakonstruktion, die die Konstruktion mit bereits platziertem Modul ins Baumenü bringt. Sie folgen dem Lager (base/content/warehouses/warehouses/), das seine Dateien genauso aufteilt. Die Mod-ID jdoe_yard ist ausgedacht, und das Beispiel wurde im Spiel nicht getestet. Alle fünf Dateien liegen in einem Ordner, content/jdoe_yard/, damit die relativen Namen zwischen ihnen so funktionieren wie im Ordner des Lagers.
yard.con.lua hat keinen eigenen Menüeintrag und nennt nur die Update-Funktion:
function data()
return {
order = 1000,
params = {},
updateScript = {
fileName = "yard.script@updateFn",
params = {},
},
}
end
yard.script.lua baut die Grundlage: eine Unterkonstruktion mit einem Modell, einer Bodenfläche und Geländeanpassung sowie einen Slot eines neuen Typs. Auf Bodenfläche und Geländeanpassung kommt es an: Eine Konstruktion mit einer einzigen Unterkonstruktion, die nur Modelle enthält, wird als lose Modelle platziert, und die nehmen keine Module auf (siehe Konstruktionsarten). createTemplateFn nennt das Modul für Slot 1:
local transf = require "::/scripts/mat4.tl"
local vec3 = require "::/scripts/vec3.tl"
local SHED_SLOT = 1
local area = { { -12, -6, 0 }, { 12, -6, 0 }, { 12, 6, 0 }, { -12, 6, 0 } }
function data()
return {
createTemplateFn = function(captureParams, params)
return {
constructions = {
{
modules = { [SHED_SLOT] = "yard_shed.module" },
constructionFileName = "yard.con",
},
}
}
end,
updateFn = function(captureParams, params)
return {
subconstructions = {
{
tag = 1,
models = {
{ id = "::/assets/buildings/ind/aeration/aeration_06.mdl", transf = transf.transl(vec3.new(-8, 0, 0)) },
},
groundFaces = {
{ face = area, modes = { { type = "FILL", key = "::/warehouses/wh_universal/wh_universal.gtex" } } },
},
terrainAlignmentLists = {
{ type = "EQUAL", faces = { area } },
},
},
},
slots = {
{
id = SHED_SLOT,
type = "jdoe_yard_shed",
transf = transf.transl(vec3.new(5, 0, 0)),
spacing = { -5, 5, -5, 5 },
height = 6,
},
},
cost = 50000,
}
end,
}
end
yard_shed.module.lua deklariert das Modul. Sein type passt zum Slot, menuCategory gibt ihm einen Tab im Modulmenü, und metadata.price wird zu den Kosten der Konstruktion addiert:
function data()
return {
menuCategory = {
categories = {
{ category = "modules_misc", order = 100, },
},
},
description = {
name = _("JDOE_YARD_SHED_NAME"),
description = _("JDOE_YARD_SHED_DESCRIPTION"),
icon = "yard_shed.tga",
},
availability = { yearFrom = 0, yearTo = 0, },
type = "jdoe_yard_shed",
metadata = {
price = 20000,
maintenanceCost = 2000,
},
updateScript = {
fileName = "yard_modules.script@shed.updateFn",
params = {},
},
getModelsScript = {
fileName = "yard_modules.script@shed.getModelsFn",
params = {},
},
builderAudioRes = "::/gui/construction/sound/buildoze_module.builder_audio",
}
end
yard_modules.script.lua platziert das Modell des Moduls mit addModelFn. Die Funktion multipliziert die Transformation mit der des Slots und setzt den Tag des Moduls. Gib die Modellliste der Unterkonstruktion als viertes Argument mit. Sonst hängt addModelFn an result.models an, eine Liste, die das Ergebnis der Konstruktion nicht hat.
local transf = require "::/scripts/mat4.tl"
local vec3 = require "::/scripts/vec3.tl"
local shedModel = "::/warehouses/wh_universal/wh_universal_shack.mdl"
function data()
return {
shed = {
updateFn = function(captureParams, result, transform, tag, slotId, addModelFn, params)
addModelFn(shedModel, transf.transl(vec3.new(0, 0, 0)), tag, result.subconstructions[1].models)
end,
getModelsFn = function(captureParams)
return { { id = shedModel, transf = transf.transl(vec3.new(0, 0, 0)) } }
end,
},
}
end
yard.metacon.tl ist der Eintrag im Baumenü. Die Datei gibt ihre Tabelle auf oberster Ebene zurück und verweist auf createTemplateFn:
local desc : MetaConstructionDesc = {
description = {
name = _("JDOE_YARD_NAME"),
description = _("JDOE_YARD_DESCRIPTION"),
icon = resolve("yard.tga"),
},
availability = { yearFrom = 0, yearTo = 0 },
menuCategory = {
categories = {
{ category = "road_buildings", order = 9000 },
},
},
order = 9000,
params = {},
createTemplateScript = {
fileName = "yard.script@createTemplateFn",
params = {},
},
}
return desc
Die beiden .tga-Icons und die Übersetzungsschlüssel (siehe Übersetzungen) musst du selbst ergänzen. Die Modelle und die Bodentextur sind Dateien des Basisspiels und werden mit ::/ angesprochen.
Das ausgelieferte Beispiel für einen Mod, der einer Basiskonstruktion ein Modul hinzufügt, ist dlcs/urbangames_deluxe_upgrade_pack/content/landmarks/landmarks/hq/modules/hq_maze.module.lua. Es bringt kein eigenes Skript mit. Es nutzt den Slot-Typ hq_fountain_l des Hauptquartiers und das Modulskript des Basisspiels und übergibt diesem Skript seine generierten Daten für Modelle und Bodentexturen über captureParams:
type = "hq_fountain_l",
-- ...
updateScript = {
fileName = "::/landmarks/hq/headquarter_addon.script@updateFn",
params = {
generatedData = generatedData
}
},
Pfade in generatedData tragen die ID des DLCs ("urbangames_deluxe_upgrade_pack::/landmarks/hq/modules/hq_maze.mdl"). Vermutlich löst das Basisskript sie auf, und ein Pfad ohne die ID würde ins Basisspiel zeigen.
Offizielles Wiki: Modular Constructions, Construction Templates, Construction Basics, Construction Menu.