RogueLibs' logo

Creating a Custom Disaster

You can create your own custom disasters using the CustomDisaster class, provided by RogueLibs. You can configure the disaster's name, description and both of the messages that are displayed at the beginning of the floor. And, of course, you can determine the conditions that the disaster can (or must) happen under, and what happens at the start of and during this disaster. Additionally, you can quickly and easily create a removal mutator that removes your disaster from the pool.

CustomDisaster class

To make a custom disaster, you need to create a class deriving from CustomDisaster:

/MyAwesomeProject/MyAwesomeDisaster.cs
public class MyAwesomeDisaster : CustomDisaster{    /* ... */}

There are 4 methods that you can implement:

/MyAwesomeProject/MyAwesomeDisaster.cs
public class MyAwesomeDisaster : CustomDisaster{    public override void Start() { /* ... */ }    public override void StartAfterNotification() { /* ... */}    public override void Finish() { /* ... */ }    public override IEnumerator? Updating() { /* ... */ }}

Start is called when the disaster starts. Finish is called when the disaster ends. StartAfterNotification is called after the disaster notification message.

Start and Finish methods

These methods are called in-between levels, so some stuff might not be available at the time they're called.

Updating returns the updating coroutine for the disaster. It starts after the disaster's notification. It is stopped automatically, when the disaster ends. If your disaster doesn't need updating, you can just return null.

Disaster Conditions

If you want your disaster to appear only under certain conditions, override the Test method:

/MyAwesomeProject/MyAwesomeDisaster.cs
public class MyAwesomeDisaster : CustomDisaster{    public override bool Test()    {        // for example, if it's a Park level        return CurrentDistrict == 2;    }}
District and Floor Conditions
  • CurrentDistrict - index of the current level's district:

    • 0 - Slums;
    • 1 - Industrial;
    • 2 - Park;
    • 3 - Downtown;
    • 4 - Uptown;
    • 5 - Mayor Village;
  • CurrentFloor - index of the current level's floor of the district.

    • 0, 1 or 2 in a normal playthrough,
    • and 0 or 1 with "Quick Game" mutator on.
  • CurrentLevel - index of the current level.

    • 0–2 - Slums;
    • 3–5 - Industrial;
    • 6–8 - Park;
    • 9–11 - Downtown;
    • 12–14 - Uptown;
    • 15 - Mayor Village;
      (or 0-1, 2-3, 4-5, 6-7, 8-9, 10 if Quick Game is on, and more in Endless mode)

And, if you want to force your disaster onto a level, override the TestForced method.

/MyAwesomeProject/MyAwesomeDisaster.cs
public class MyAwesomeDisaster : CustomDisaster{    public override bool TestForced()    {        // for example, if there's a Mayor on the level        return gc.agentList.Exists(a => a.agentName === VanillaAgents.Mayor);    }}

Disaster Settings

Normally, you can't teleport during disasters, but you can change that by overriding the AllowTeleport property:

/MyAwesomeProject/MyAwesomeDisaster.cs
public class MyAwesomeDisaster : CustomDisaster{    public override bool AllowTeleport => true;}

The property is accessed constantly, so you can change the return value with time.

Initialization

Just call the CreateCustomDisaster method with your disaster's type as a parameter:

/MyAwesomeProject/MyAwesomeDisaster.cs
public class MyAwesomeDisaster : CustomDisaster{    [RLSetup]    public static void Setup()    {        RogueLibs.CreateCustomDisaster<MyAwesomeDisaster>();    }}
note

See more about the RLSetup attribute here.

You can set your disaster's name and description using WithName and WithDescription methods:

/MyAwesomeProject/MyAwesomeDisaster.cs
public class MyAwesomeDisaster : CustomDisaster{    [RLSetup]    public static void Setup()    {        RogueLibs.CreateCustomDisaster<MyAwesomeDisaster>()            .WithName(new CustomNameInfo("My Awesome Disaster"))            .WithDescription(new CustomNameInfo("My Awesome Disaster is very cool and does a lot of great stuff, and it's also awesome."));    }}

Plus, you can add two messages (they are displayed at the same time, on two lines):

/MyAwesomeProject/MyAwesomeDisaster.cs
public class MyAwesomeDisaster : CustomDisaster{    [RLSetup]    public static void Setup()    {        RogueLibs.CreateCustomDisaster<MyAwesomeDisaster>()            .WithName(new CustomNameInfo("My Awesome Disaster"))            .WithDescription(new CustomNameInfo("My Awesome Disaster is very cool and does a lot of great stuff, and it's also awesome."))            .WithMessage(new CustomNameInfo("My Awesome Disaster!"))            .WithMessage(new CustomNameInfo("Watch out for... uh, something.. awesome?!"));    }}
info

See Custom Names for more info.

You can also create a removal mutator automatically:

/MyAwesomeProject/MyAwesomeDisaster.cs
public class MyAwesomeDisaster : CustomDisaster{    [RLSetup]    public static void Setup()    {        RogueLibs.CreateCustomDisaster<MyAwesomeDisaster>()            .WithName(new CustomNameInfo("My Awesome Disaster"))            .WithDescription(new CustomNameInfo("My Awesome Disaster is very cool and does a lot of great stuff, and it's also awesome."))            .WithMessage(new CustomNameInfo("My Awesome Disaster!"))            .WithMessage(new CustomNameInfo("Watch out for... uh, something.. awesome?!"))            .WithRemovalMutator();    }}

Examples

A simple disaster that just gives everyone Resurrection after the notification.

/MyAwesomeProject/NewHealthOrder.cs
using System.Collections;using RogueLibsCore;namespace MyAwesomeMod{    public class NewHealthOrder : CustomDisaster    {        [RLSetup]        public static void Setup()        {            RogueLibs.CreateCustomDisaster<NewHealthOrder>()                     .WithName(new CustomNameInfo                     {                         English = "New Health Order",                     })                     .WithDescription(new CustomNameInfo                     {                         English = "Where is this line used?!",                     })                     .WithMessage(new CustomNameInfo                     {                         English = "N.H.O. - New Health Order",                     })                     .WithMessage(new CustomNameInfo                     {                         English = "Resurrection for everyone!",                     })                     .WithRemovalMutator();        }        public override void Start() { }        public override void Finish() { }        public override IEnumerator Updating()        {            foreach (Agent agent in gc.agentList)                if (!agent.dead && !agent.electronic && !agent.inhuman)                {                    agent.statusEffects.AddStatusEffect(VanillaEffects.Resurrection, false);                }            yield break;        }    }}