Skip to content

Custom Roles

XtraCube edited this page Feb 27, 2026 · 16 revisions

To create a custom role, you need to do two things:

  1. Create a class that inherits from a base game role (such as CrewmateRole, ImpostorRole, etc.)
  2. Implement the ICustomRole interface from Mira API.

Note: Make sure your plugin class has the [ReactorModFlags(ModFlags.RequireOnAllClients)] attribute, otherwise roles will not register correctly.

For neutral roles it is recommended to inherit from CrewmateRole. You can also inherit directly from RoleBehaviour, but you must override the IsDead property, otherwise Il2Cpp will throw an error.

Mira API handles everything else: adding options to the settings menu, managing role assignment at the start of the game, and more. There are no extra registration steps required.

Example Role

public class FreezerRole : ImpostorRole, ICustomRole
{
    public string RoleName => "Freezer";
    public string RoleLongDescription => "Freeze another player for a duration of time.";
    public string RoleDescription => RoleLongDescription;
    public Color RoleColor => Palette.Blue;
    public ModdedRoleTeams Team => ModdedRoleTeams.Impostor;

    public CustomRoleConfiguration Configuration => new CustomRoleConfiguration(this)
    {
        OptionsScreenshot = ExampleAssets.Banner,
        MaxRoleCount = 2,
    };
}

And an in-game screenshot of the role:
freezeButton

Using Custom Roles

Since custom roles inherit from the vanilla RoleBehaviour class, you can usually use them in the same way you would use a vanilla role. For example, you can check a player's role like this:

PlayerControl player = ...;
if (player.Data.Role is FreezerRole freezer)
{
    // Do something with the freezer role
}

However, there are some issues due to strange Il2Cpp behavior. One notable example is accessing the RoleManager.Instance.AllRoles list. Checking the type of the role using the same code as above will fail. Instead, you can compare the RoleId using the RoleId utility.

foreach (var role in RoleManager.Instance.AllRoles)
{
    if ((RoleTypes)RoleId.Get<FreezerRole>() == role.Role)
    {
        // Do something with the freezer role
    }
}

Role Utilities

Mira API provides a few utilities to help you with your role development.

CustomRoleSingleton

The CustomRoleSingleton class is a singleton that gives you access to any custom role you registered with Mira. This will not give you a PLAYER's role, this is simply the INSTANCE of the role inside the RoleManager class. Example uses for this are getting the role's configuration, color, name, or the Chance and Count of the role.

It is used like this:

var role = CustomRoleSingleton<FreezerRole>.Instance;
Logger<MyPlugin>.Info($"Role Name: {role.RoleName}");
Logger<MyPlugin>.Info($"Role Color: {role.RoleColor}");
Logger<MyPlugin>.Info($"Role Chance: {role.GetChance()}");
Logger<MyPlugin>.Info($"Role Count: {role.GetCount()}");

RoleId

The RoleId class is a utility class that helps you get the id as a ushort of a role. The base game uses IDs in various locations related to roles, so this class is useful for converting your custom role to an ID. You will likely have to cast the ushort returned by this class to a RoleTypes enum.

RoleId provides two methods to get an ID:

  • Get<T>() - Gets the ID of a role as a type parameter.
  • Get(Type type) - Gets the ID of a role by its type object.

Example usage:

var roleID = RoleId.Get<FreezerRole>();
var roleType = (RoleTypes)roleID;
RoleManager.Instance.SetRole(somePlayer, roleType); // Set the role of somePlayer to the FreezerRole using the ID.

ICustomRole Interface

The ICustomRole interface contains various properties and methods that can be implemented to customize your role.

Keep in mind that since custom roles are required to inherit from the vanilla RoleBehaviour class, you can also override any of the methods from RoleBehaviour to further customize your role.

The following properties can be implemented to customize your role:

Property Type Required Default Value Description
RoleName string Yes None The name of the role.
RoleDescription string Yes None A short description of the role. Used in the intro cutscene.
RoleLongDescription string Yes None A longer description. Used in the role tab and role options screen.
RoleColor Color Yes None The color of the role.
Team ModdedRoleTeams Yes None The team of the role. Valid values: Crewmate, Impostor, Custom.
Configuration CustomRoleConfiguration Yes None Advanced configuration for the role. Must be initialized with new CustomRoleConfiguration(this).
OptionsMenuColor Color No RoleColor The color used in the options menu. Defaults to RoleColor.
RoleOptionsGroup RoleOptionsGroup No Crewmate/Impostor/Neutral based on Team The group this role is placed under in the role settings screen.
IntroConfiguration TeamIntroConfiguration? No TeamIntroConfiguration.Neutral for Custom, else null Customizes the team screen shown during the intro cutscene.
ParentMod MiraPluginInfo No Resolved automatically The plugin that registered this role. Read only.

The following methods exist to customize and interact with your role:

Method Signature Required Default Behavior Description
void BindConfig(ConfigFile config) No Binds the count and chance config entries for this role. Called internally to bind role config. Override to add custom config binding.
void SaveToPreset(ConfigFile presetConfig, bool useDefault=false) No Saves the role's count and chance to a preset ConfigFile. Override to save additional role config to presets.
void LoadFromPreset(ConfigFile presetConfig) No Loads count and chance from a preset ConfigFile. Override to load additional role config from presets.
int? GetChance() No Returns the current chance from the plugin's config file. Returns DefaultChance if CanModifyChance is false. Gets the 0-100 chance for this role to appear in role selection.
int? GetCount() No Returns the current count from the plugin's config file. Gets the number of players that will receive this role.
void SetChance(int chance) No Sets the chance in the plugin's config file. Clamps between 0 and 100. Sets the chance for this role to appear in role selection.
void SetCount(int count) No Sets the count in the plugin's config file. Clamps between 0 and MaxRoleCount. Sets how many players will receive this role.
bool CanLocalPlayerSeeRole(PlayerControl player) No Impostors can see other impostors. Dead players can see all roles. Determines whether the local player can see the role name color.
bool SetupIntroTeam(IntroCutscene instance, ref Il2CppSystem.Collections.Generic.List<PlayerControl> yourTeam) No Vanilla team setup, except Custom team roles display alone. Return false to skip the original intro team code. Controls which players appear on the team screen during the intro cutscene.
string? GetCustomEjectionMessage(NetworkedPlayerInfo player) No Returns "{player.PlayerName} was The {RoleName}" for Impostor roles. Returns null for all other teams. Gets a custom ejection message when a player with this role is voted out.
StringBuilder SetTabText() No Returns CustomRoleUtils.CreateForRole(this) Gets the text displayed for this role on the role tab.
bool IsModifierApplicable(BaseModifier modifier) No Returns true. Determines whether a given modifier can be applied to this role.
bool CanSpawnOnCurrentMode() No Returns true unless the current game mode is Hide and Seek. Determines whether this role can spawn given the current game mode.
Func<bool> VisibleInSettings No Returns () => true A function that controls whether this role is shown in the game settings.

CustomRoleConfiguration Struct

CustomRoleConfiguration must be constructed with new CustomRoleConfiguration(this), passing the role as the argument. The constructor sets sensible defaults based on the role's team. You can then override individual properties using object initializer syntax.

Property Type Default (based on team) Description
MaxRoleCount int 15 The hard limit of players that can have this role in the Role Options menu. If set to 0, the role will not be assigned at the start of the game.
DefaultRoleCount int 0 The default number of players that will have this role.
DefaultChance int 0 The default chance (0-100) of this role being assigned to a player.
CanModifyChance bool true Whether the chance can be changed in the Role Options menu.
OptionsScreenshot LoadableAsset<Sprite>? null The sprite displayed as a screenshot in the role options screen.
Icon LoadableAsset<Sprite>? null The sprite used as the role's icon.
IntroSound LoadableAsset<AudioClip>? Crewmate or Impostor intro sound based on team The audio clip played during the role intro cutscene.
AffectedByLightOnAirship bool true for Crewmate, false otherwise Whether the role is affected by light effects on Airship.
CanGetKilled bool true for non-ghost, non-Impostor roles Whether the role can be killed by the vanilla murder system.
UseVanillaKillButton bool true for Impostor, false otherwise Whether the role uses the vanilla kill button.
KillButtonOutlineColor Color Palette.ImpostorRed for Impostor, Palette.CrewmateBlue for Crewmate, RoleColor for Custom The outline color on the kill button when UseVanillaKillButton is true.
CanUseVent bool true for Impostor, false otherwise Whether the role can use vents.
CanUseSabotage bool true for Impostor, false otherwise Whether the role can use the sabotage button.
TasksCountForProgress bool true for Crewmate, false otherwise Whether the role's tasks count toward task completion progress.
HideSettings bool true for ghost roles (IsDead == true), false otherwise Whether the role is hidden in the role settings menu.
ShowInFreeplay bool true for non-ghost roles (IsDead == false), false otherwise Whether the role appears in the freeplay role selection menu.
FreeplayFolder string Team folder name ("Crewmate", "Impostor", or "Neutral") The folder this role is placed in within the freeplay role selection menu.
RoleHintType RoleHintType RoleHintType.RoleTab The style of hint shown to the player. None disables hints, TaskHint uses the vanilla task-hint style, RoleTab uses Mira's custom role tab.
GhostRole RoleTypes ImpostorGhost for Impostor, CrewmateGhost otherwise The ghost role assigned to the player when they die.

Additional CustomRoleUtils Methods

The following static methods in CustomRoleUtils are available for querying active roles:

Method Description
CustomRoleUtils.GetActiveRolesOfTeam(ModdedRoleTeams team) Returns all active role instances belonging to the given team.
CustomRoleUtils.GetActiveRolesOfType<T>() Returns all active role instances of type T.
CustomRoleUtils.GetIntroSound(RoleTypes roleType) Returns the intro sound for any role (custom or vanilla) by its RoleTypes value.
role.IsCustomRole() Extension method on RoleBehaviour. Returns true if the role is a Mira custom role.
// Get all active impostor roles
var impostors = CustomRoleUtils.GetActiveRolesOfTeam(ModdedRoleTeams.Impostor);

// Get all active instances of a specific role type
var killers = CustomRoleUtils.GetActiveRolesOfType<NeutralKillerRole>();

// Check if a role behaviour is a custom Mira role
if (someRole.IsCustomRole()) { /* ... */ }

Clone this wiki locally