ObjectNMLGenerator is a scripting tool that generates NML code for OpenTTD's Object NewGRFs via a graphical user interface (GUI).
It is designed for users with little or no experience in NML or coding, with the main focus on making the process comprehensible.
This manual provides the essential information needed to get started. For deeper understanding of NML, refer to these resources:
Although the generated NML code covers basic functionality (object dimensions, number of views, options for snow sprites and ground sprites, etc.), experienced users can still benefit from the programatically generated templates. These templates can be extended with advanced features as needed.
The following sections describe the process step by step, starting with setup and continuing through to usage.
1 Setup
2 Sprites
3 Using the app
3.1 Toolbar
3.2 GRF block
3.3 Object properties
3.4 List of objects
3.5 Export
3.5.1 Generate NML
3.5.2 Generate & Compile
4 Settings
Contact
For convenience, a portable Windows release is available in the Releases section. It includes precompiled Lua binaries and other required dependencies, and does not require installation.
It is recommended to create a subfolder named gfx
(for your sprites) in the root folder of your NewGRF project. Extract the contents of ObjectNMLGenerator-winx64-portable.zip
into this root folder as well.
The folder structure matters because:
lang
folder and .nml
file are expected to share a location with gfx
The _files
folder contains internal script files and should not be modified.
You can start the program by running START.bat
.
After extraction:
After running the app:
Add your sprites to the gfx
folder. The images must follow these rules:
Additional notes:
To illustrate usage, this section follows a practical example, which can be found in the _example
folder.
New list
Resets all input data (all unsaved entries will be lost!).
Hotkey: Ctrl + N
Open/Save list
ObjectNMLGenerator uses a YAML-like format to store your projects as lists of objects and their parameters.
The saved .yaml
file can be reopened in the GUI (or even edited directly in a text editor).
Hotkeys: Ctrl + O and Ctrl + S
Example of a saved object:
1:
bpp: 8
snow: ON
classname: Example objects
image_height: 85
bpp_snow: 8
name: Example 1x1
file: 1x1.png
file_snow: 1x1_snow.png
class: EXAM
ground: 2
file_ground: ground.png
image_width: 64
views: 1
Ydim: 1
Xdim: 1
Tip: You can drag and drop a YAML file directly onto the GUI.
Settings
Opens a dialog window for configuring the app's behavior.
See Settings for details.
Hotkey: Ctrl + K
Help
Opens Manual.html
in your default browser.
If the file is not found locally, the app will offer to open the online version instead.
Hotkeys: Ctrl + H or F1
Tip: You can use Ctrl + Q or ESC in the main dialog window to close the app.
The fields inside the GRF block represent values that will be inserted into the "header" of your NewGRF.
The basics are explained below; for more details, see NML Tutorial: Starting an NML file.
Grf ID
GRFID is a four-byte string that uniquely identifies your NewGRF.
If two NewGRFs share the same GRFID, only one can be loaded in-game, also the other cannot be uploaded to the game's online content manager.
Examples of valid GRFID (backslash indicates that the next two characters represent one byte, i.e. two hexadecimal digits):
SF\1A\01
, HTT\1F
, OTTD
, etc.
More details: TT-Wiki: Grfid
Version
The current version of your NewGRF. Increase this number with each release.
Min. comp. version
The minimum compatible version. Set this to the current version whenever backward compatibility is broken.
More details: TT-Wiki: Starting an NML file and TT-Wiki: NewGRF compatibility
NewGRF name
The name displayed in the NewGRF list in the main menu.
NewGRF description
The description displayed in the NewGRF list in the main menu.
Supports multiline strings. For information about special formatting and tags, see TT-Wiki: Language files
NewGRF url
Optional, but useful.
Usually this is a link to your project’s GitHub page or TT-Forums thread.
This is how the example GRF block looks like in-game:
In this section, you define all properties necessary to generate a functional NML code.
Tip: Click and hold the left or right mouse button on the eye icon next to a filename to display its preview.
To enable on-hover previews, see Settings.
File
Each object definition begins by loading a PNG file with sprites. The file location is arbitrary, but the script assumes that all sprites will be in the gfx
folder at the time of compilation.
The filename serves as the identifier in the List of objects.
W - H - bpp
Width, height, and color depth of the loaded PNG.
This is display-only: if the source file changes, you must reload it so the algorithm can process it correctly.
Snow
Adds a snow variant of the sprite. Enable the toggle and select a PNG containing snow sprites.
The snow PNG resolution must match the "regular" variant:
Ground
Choose from a list of predefined base set ground sprites:
Or browse for a custom file. Custom ground sprites must be a single tile with 32 bpp color depth:
Note: If you select
but
ground.png
is not found in thegfx
folder, this example sprite will be generated automatically.
Name
The display name shown in the in-game purchase menu.
Dimensions
The X and Y dimensions of the object, measured in tiles (maximum: 15 × 15 tiles).
A key parameter that determines the correct spritelayout in-game.
To prevent a common mistake, here is how OpenTTD's coordinate system works, shown on a 3x1 object:
Important: Notice how the 2nd and 4th views swap the X and Y coordinates.
Number of views
The number of "options" in an object's submenu. See Sprites for instructions on preparing images.
Class
A string literal of exactly 4 characters (allowed characters are A-Z
, 0-9
).
Defines the category in the in-game objects menu.
Objects with the same class will be grouped together in the menu (even across different NewGRFs!).
Examples: SF11
, HTT1
, OTTD
, etc.
Classname
The actual name of a class that will be displayed in the objects menu.
Currently, the classname of the first occurrence of a class is used (although it is recommended to keep the same classname for all members of the same class to avoid confusion).
Add object
Adds the defined object to the List of objects.
If an object with the same filename already exists, the app will prompt you to overwrite it.
This allows you to update an existing object:
Important: Without clicking on Add object, the changes will not be added.
This screenshot illustrates how the defined properties appear in-game:
This section displays all currently defined objects.
Since filenames are unique, the sprite filename serves as the identifier. The Class string indicates the object category.
The order of entries here determines the in-game order.
Use the ↑ and ↓ buttons to change the order, or the Remove object button to delete a selected item.
.nml
and .lng
files, or Generate & Compile to also produce a .grf
.nmlc.exe
is placed in the app’s root folder..grf
to
...\Documents\OpenTTD\newgrf
to use it in the game.Note: If you change the output filename in the Save as text box, the name entered here will be remembered as the new default (unless changed in Settings).
Below is a more detailed description of the two export options:
If all fields are filled in correctly, the app generates the following output in the root folder:
example.nml
(filename can be changed in the Save as text box)english.lng
in the lang
subfolderIf you want to add another language, you have to do so before the compilation.
For instructions, go to NML Tutorial: Language files.
These files are then ready to be used by the NML Compiler (NMLC).
If you prefer to compile the code yourself but are unsure how, follow the instructions here:
NML Tutorial: Compiler.
Note: Remember the folder structure mentioned in Setup.
The generatedlang
folder and.nml
file must share a location withgfx
.
This option performs the same code-generation step as Generate NML, but then also automatically compiles the NML code into a .grf
file.
IMPORTANT:
Copy or extract the compiler (nmlc.exe
) into the root folder of the app (i.e., next to START.bat
).
If nmlc.exe
is not found in the root folder, the app will prompt you to download the latest release from the official page: NML Releases on Github.
(look for the nml-standalone-x.x.x-win64.zip
archive).
Note: ObjectNMLGenerator releases do not include the compiler.
This not only reduces the size bloat, but more importantly it ensures that you always obtain the latest version ofnmlc
.
The output of the compiler is displayed in a dedicated popup console, which is helpful for spotting errors, because NMLC typically provides useful hints.
A successful compilation might look like this:
After compilation, the resulting .grf
file will appear in the root folder.
Copy it into ...\Documents\OpenTTD\newgrf
, then enable it in NewGRF Settings within the game (if you can't find it in the list, click Rescan files).
By default, the app is cautious and often prompts for confirmation before performing an operation.
Once you become familiar with the workflow, you may prefer to disable some of these safeguards by adjusting preferences in the Settings menu.
Additionally, you can choose whether to remember the last used folder and output filename, and whether the preview eye icon should also activate on mouse hover.
The dialog window can be opened either from the Toolbar or with the hotkey Ctrl + K.
To reset all settings to their defaults, delete the settings.ini
file in the _files
directory.
If you have questions about the app, you can reach me
@chujo on OpenTTD's Discord (discord.gg/openttd)
For general questions about NML or NewGRF development,
feel free to ask in the # add-on-development
channel.