Skip to content

Custom Clan Mechanic UIs

Brandon edited this page Jun 30, 2026 · 2 revisions

Ever wanted to make your own special UI that appears when playing your custom clan, like Pyreborne's Dragons Hoard, Luna Covens Moon Phase, or Railforged's Forge?

This tutorial will cover how to create one of those. It requires a tiny bit of code to setup, and isn't that much more complicated than creating a new Tracked Value or a Player Resource, so be sure to read the previous two tutorials first.

This tutorial requires Conductor, which should be included in the Mod Template, which has a fully customizable class to display a Class Mechanic UI.

Overview

For a Class Mechanic UI you need a few things

  1. The style of UI, Large or small. Large UIs have an icon and a label, like the Luna Coven's Moon Phase UI. Small UIs just have an icon, like Pyreborne's Dragons Hoard UI.

  2. A TrackedValue representing the value to display in the UI

  3. A sprite for the UI display. For a large Luna Coven like UI the icon should be 124x236. For Small style Pyreborne like UI the icon should be 124x172.

  4. An set of icons to display in the UI (minimum required is 1), these icons should be 92x92 for large style, and 72x88 for small style.

  5. A class inheriting from Conductor.UI.ClassMechanicHud. The subclass can be empty, the default behaviour should handle almost all use cases, it supports basic icon and label display, but does not implement functionality for players to interact with it, like the Dragons Hoard UI does.

All of this information is configured through JSON.

JSON Configuration

Here is an example JSON configuration that defines a small UI that displays during battle only.

{
  "$schema": "https://raw.githubusercontent.com/Monster-Train-2-Modding-Group/Conductor/refs/heads/main/schemas/hud.json",
  "huds": [
    {
      "id": "MyClassMechanicUI",
      "name": "@MyClassMechanicUISubclass",
      "type": "small",
      "background": "@hud_background",
      "icons": [ "@hud_icon" ],
      "class": "@YourClanReference",
      "display": "battle_only",
      "tooltip_titles": {
        "english": "My Class Mechanic"
      },
      "tooltip_texts": {
        "english": "Explanation of the class mechanic."
      }
    }
  ],
  "sprites": [
    {
      "id": "hud_background",
      "path": "textures/ui/hud_background_smell.png"
    },
    {
      "id": "hud_icon",
      "path": "textures/ui/hud_icon_small.png"
    }
  ]
}

Fields

  • $schema - The schema that defines Class Mechanic HUDs is given at this URL.

  • id - The identifier for the UI. We will need this later in our code to setup the UI properly after everything is created

  • name - The subclass of ClassMechanicHud defined in your mod for the UI.

  • type - The UI type. Accepted values are large, small, custom. if type is custom then your subclass must set up its GameObject hierarchy by overriding Construct.

  • background / icons - References to sprites for the background and icons respectively.

  • class - This is used to associate the UI with a specific clan. It is used to display the UI whenever the clan is primary or allied within a run.

  • display - This setting controls when the UI displays. Accepted values are battle_only or run The former gives luna coven behavior where the moon phase only mattered during battle. The latter gives pyreborne behavior where the UI is always present during the run.

  • tooltip_titles/tooltip_texts Configures the tooltip displayed when the player mouses over the UI. These are localizations.

Configuration specific to Large style UIs

  • label_texts/ additional_texts - This for the label displayed below the icon for the Large style UI. additional_texts defines additional label texts just in case if it is needed.

Setting up the UI

There are two steps, after providing the JSON file in your mod to properly wire the UI to display correctly.

  1. The UI class needs to be retrieved from Conductor's HudManager class.

  2. An AbstractTrackedValueHandler subclass needs to be provided to the UI class. This is created when creating a custom TrackedValue. Note that TrackedValueGetter functions are not supported. The SimpleGlobalTrackedValueHandler or PlayerResource class can be provided as both are a subclass of AbstractTrackedValueHandler

Getting the UI

Once the JSON file is read by Conductor it will create the GameObjects necessary to display the UI along with attaching and wiring the UI to the BattleHud.

To get the instance of our UI we request it from the HudManager via a call to GetHUD(string key, string name)

  • key is your Plugin's GUID string.

  • name is the id provided in the JSON file naming the UI.

The call has to be made in a Railend PostAction.

The function will return null if the UI was not found.

Associating with a TrackedValueHandler

ClassMechanicHud has a function to associate with a tracked value handler.

SetTrackedValueHandler(AbstractTrackedValueHandler handler);

Again to reiterate if you have previously associated a TrackedValue with a handler via a call to aTrackedValueType.SetTrackedValueHandler(AbstractTrackedValueHandler handler) You can simply pass the same object to the ClassMechanicHud.

Note that if writing your own AbstractTrackedValue subclass that when the value changes in IncrementValue that you call ValueChanged function after updating the internal value to inform the ClassMechanicHud that the value has changed.

Example

Given both steps and the above JSON file. Here is how to set it up properly with the TrackedValue we created in the Custom Tracked Values tutorial.

        Railend.ConfigurePostAction(
            c =>
            {
                var trackedValueRegister = c.GetInstance<IRegister<CardStatistics.TrackedValueType>>();
                EphemeralCardsPurged = trackedValueRegister.GetValueOrDefault(MyPluginInfo.PLUGIN_GUID.GetId(TemplateConstants.TrackedValueTypeEnum, "EphemeralCardsPurged"));
                var handler = new SimpleGlobalTrackedValueHandler();
                EphemeralCardsPurged.SetTrackedValueHandler(handler);
                var hud = HudManager.GetHUD(MyPluginInfo.PLUGIN_GUID, "MyClassMechanicUI");
                if (hud != null)
                {
                    hud.SetTrackedValueHandler(handler);
                }
            }
        );

ClassMechanicHud

As mentioned a subclass of this abstract class must be created and specified within the JSON. For most purposes simply making a empty subclass is enough for most usecases.

    public class MyClassMechanicUISubclass : ClassMechanicHud
    {
    }

The base class handles updating the value automatically, including animating the value increasing and decreasing

Notable Methods

Here are some methods that can be overridden and their purpose. For a full view of the class See the class in Conductor's repository.

ShouldShowUI

public virtual bool ShouldShowUI(SaveManager saveManager, PlayerManager playerManager, CardManager cardManager, ScreenManager screenManager)

This function determines whether or not to show the UI. This function may need to be overridden, if you choose to have cards that interact with the TrackedValue represented with the UI. Think getting Dragons Hoard cards when you aren't playing as Pyreborne, the function can scan the active deck for a card with an effect, and then if one is found return true.

The base version of ShouldShowUI checks if you are running the clan associated with the UI if you aren't then it immediately returns false. Otherwise it considers the display mode, and which tests which screen is active and returns true when it is appropriate to display the HUD.

Refresh

public virtual void Refresh(SaveManager saveManager, PlayerManager playerManager, CardManager cardManager)

This function is called when the UI should refresh itself. The base classes version does nothing.

Testing

Once you have configured your own UI, just start a run with the configured class.

Clone this wiki locally