From The DarkMod Wiki
Jump to navigationJump to search

Support for subtitles (or closed captions) was added in TDM 2.10.

How it works

Subtitles work on a very low level: where the engine manages sound samples and sound channels. This approach allows to reliably add subtitles for sounds of any kind, but has some downsides too: the system does not know anything at all about entities, spawnargs, scripts, and other gameplay stuff. The system allows to assign chunks of text directly to sound samples (which are usually .ogg and .wav files), so that when a sound sample is played, the assigned text is shown on the screen.

Subtitles decls

The assignment of text to sound samples is specified in a new type of decl files. These files must:

  1. be in subtitles directory,
  2. have .subs extension,
  3. contain declarations of type subtitles.

For comparison, materials are another type of decls, which must be in materials directory, in files with .mtr extension, and be of type material.

To avoid any conflicts between core game and missions, FM authors should follow the conventions:

  1. Names of subtitles decl files must start with fm_, e.g.: fm_conversations.subs
  2. Names of declarations must start with fm_ too, e.g.: fm_paul_intro_convo

Here is an example of fm_conversations.subs contents:

//note: comments work as they normally do

subtitles fm_intro_convo {
    verbosity story
    inline "sound/voices/paul/sound1.ogg" "My name is Paul, and I'm a city guard."
    inline "sound/voices/bjorn/sound2.ogg" "Welcome to Anonymous City Guards! Call me Bjorn."
    inline "sound/voices/paul/sound3.ogg" "I started cutting thieves' throats when I was 17..."
    inline "sound/voices/paul/sound4.ogg" "... and now I cannot stop doing that!"

    verbosity effect
    inline "sound/voices/paul/sound5.ogg" "(starts weeping)"

    verbosity story
    inline "sound/voices/bjorn/sound6.ogg" "Calm down, Paul! We all were in your shoes!"
    inline "sound/voices/bjorn/sound7.ogg" "Let us first watch an educational video about the harm from cutting throats."

    srt "sound/voices/bjorn/sound8_long.ogg" "sound/voices/bjorn/"

subtitles fm_briefing {
    verbosity story
    srt "fromVideo video/briefing/briefing.mp4" "video/briefing/"

displayed text

There are two ways to specify subtitle text: inline and srt-based.

inline command is followed by a name of sound sample and the text to be displayed while it is being played. In this case, the text is written straight in the decl file, and it is displayed for the whole duration of the sound sample. This way is convenient for short sounds, which are the majority of sound samples, including phrases of a conversation.

srt command is followed by a name of sound sample and a path to .srt file. The .srt file format is described e.g. on Wikipedia. The file must be in engine-native encoding (internationalization is not supported yet anyway) and have no BOM mark. It contains a sequence of text messages to show during the sound sample, with timestamps and durations. It is recommended to use common software to create .srt files for sound samples, instead of writing them manually. This way is more flexible but more complicated, and it is only necessary for long sounds, for instance sound sample of a briefing video.

sound sample

In order to specify sound sample, write path to the file the same way you do e.g. in sound shaders.

One complicated case is when you have an FFmpeg-based video with embedded sound. In this case write path to the video file, prepended with fromVideo keyword and space, just like you do in the sound shader. See fm_briefing in the example above.


Currently there are three verbosity levels for subtitles:

  • story: This level should be applied to all story-related subtitles, everything that player should absolutely notice and understand.
  • speech: This is for subtitles of speech which is usually of little interest to the player, or is repeated too often. For instance, regular AI barks (e.g. "I'll get ya!") belong here.
  • effect: This level is reserved for non-speech subtitles which have little interest to the player, like "(bang)" or "(ding)", etc.

It is not yet clear how exactly these levels will be used. Here are some ideas:

  1. By default, players only see story-level subtitles, although they can enable the other two categories in settings, or disable subtitles entirely.
  2. It is expected that almost all FM-specific subtitles get into story category. The other two exist mostly for core TDM sounds, which include a lot of AI barks (speech level) and trivial sound effects like arrow hit (effect level).

Every subtitles declaration must start with verbosity command. This command applies to all the subsequent commands, until the other verbosity is met or declaration ends (whichever happens first). For instance, all subtitles have story verbosity level in the example above, except for the "(starts weeping)" text, which has effect verbosity.


While the engine parses all declarations that are present in the files, the subtitles system only uses one subtitles decl named tdm_root. Include command is used in order to put other subtitle decls into it.

include command has one argument: the name of the subtitles decl to be included. Note that it is the name of the decl, not the name of the file which contains it! Included decl can in turn include other decls.

FM-specific subtitles are always included from the decl named fm_root, which must be in fm_root.subs file. For instance, the contents of the fm_test.subs file from the example above will have no effect until we add the file fm_root.subs with contents:

 * This file should be overridden in order to provide mission-specific subtitles.
 * When doing so, please follow the conventions:
 *   1) The root decl is called "fm_root" and is located in file "fm_root.subs".
 *   2) All other subtitle decls start with "fm_" prefix and are located in files starting with "fm_".

subtitles fm_root {
    include "fm_intro_convo"
    include "fm_briefing"
    //you can add other includes and add subtitles with "inline"/"srt" commands here

Notice that one decl can be used to do any number of subtitle assignments, so it is not necessary to have many decls and decl files. The easiest way to do FM-specific subtitles is to have one fm_root.subs file with one fm_root decl, and specify all your subtitles right there. Splitting subtitles across decls and files is entirely optional and can be used for grouping subtitles. It was added mainly for core TDM sounds: there are several thousands of them, so keeping all subtitles in single file can become a headache quickly.


The subtitles which should be displayed right now are provided to GUI code as gui::subtitleN variables, where N ranges from 0 to 3. GUI scripts display these variables as non-overlapping text messages. The responsible code is located in tdm_subtitles_common.gui file, and is already used in several places:

  • in the following states of the main menu: briefing, briefing video, and debriefing video
  • in the always-on GUI overlay during gameplay

For example, here is how it is used in mainmenu_briefing.gui:

//note: each include of tdm_subtitles_common must have different name prefix!
#include "guis/tdm_subtitles_common.gui"

Usually, you don't need to do anything about it. However, this information can be relevant if you write some custom GUI and want to see subtitles there.

Note: it is not clear yet which kind of customization is necessary for the subtitles GUI. If you have any ideas, please share them on forums.

See also

TODO: "Tears of Saint Lucia" mission as an example?...