Skip to content

06. Level sequence

Note: features discussed here were added in 1.1.0, update if you're using 1.0.0.

So far, we focused on generating just 1 level, but usually we want the run to have more. Various things related to how and how many levels are created are defined by the level sequence. We'll start with the code from the previous part.

What the level sequence does

Things like 1-2 coming after 1-1 aren't actually hardcoded and can be changed by altering the level sequence. The sequence itself is an array of LibLevelGen.LevelGenerationOptions objects, and there's one entry for every level in the run. This object type has a lot of fields, but most of them don't actually need to be set - this is because there's another object of this type that's used as a base, and the values of individual entries from the sequence are merged into the base one.

Typically, the "base" object will contain things such as mode ID, initial starting characters etc, while the level-specific objects will contain floor/zone/depth numbers, and any additional overrides if applicable. But it is perfectly valid to put floor 3 before floor 2 in the level sequence, even if it doesn't make too much sense.

Generating the level sequence

We can specify the level sequence gemerator with the sequenceClb field of the configuration of our generator like so:

libLevelGen.registerGenerator("LibLevelGen Playground", myGenerator, {
    sequenceClb = function (ev, cfg)
        ev.sequence[#ev.sequence + 1] = {
            floor = 1,
            zone = 1,
            depth = 1
        }
    end
})
The ev parameter is an object of type Event.LevelSequenceUpdate (kinda; it uses LibLevelGen.LevelGenerationOptions instead of LevelGenerator.Options in this context), while cfg is a LibLevelGen.Config. If not specified, a default sequence generator is used, which just puts a bunch of levels with depth=1 and zone=1 where the floor number keeps increasing.

With the sequence in the example, the run has only 1 level and then goes to the run summary screen. 1 level is a little boring, so let's add some more... Actually, let's add 2 more requires first:

-- Do not confuse with levelSequence module of the base game.
local levelSequence = require "LibLevelGen.LevelSequence"
local boss = require "necro.game.level.Boss"
Now we can do the thing:
libLevelGen.registerGenerator("LibLevelGen Playground", myGenerator, {
    maxLevel = 3,
    sequenceClb = function (ev, cfg)
        for i = 1, cfg.maxLevel - 1 do
            ev.sequence[#ev.sequence + 1] = {
                floor = i,
                zone = 1,
                depth = 1
            }
        end
        ev.sequence[#ev.sequence + 1] = {
            type = levelSequence.BuiltinGenerators.BOSS,
            boss = boss.Type.CONDUCTOR,

            floor = cfg.maxLevel,
            zone = 1,
            depth = 1
        }
    end
})
So now, since maxLevel is 3, the level sequence consists of floors 1-1 and 1-2 followed by a boss level. But we didn't define a boss generator anywhere, so how is it possible? The secret lies in the type field of a sequence entry, which can completely change what level generator is used, as it overrides the type field in the base object. In this case, we're redirecting the level generation to the built-in boss generator and telling it to generate the conductor fight. And if we head to 1-3...
the-conductor.png
We are, in fact, welcomed by the conductor fight!

Sequence templates

In the LevelSequence module from LibLevelGen there are some premade level sequence generators that you can use.
At the time of writing there are only 2 basic ones, because I just added this feature
Let's try using one!

libLevelGen.registerGenerator("LibLevelGen Playground", myGenerator, {
    levelsPerZone = 2,
    zones = 4,
    sequenceClb = levelSequence.templateAllZones()
})
So now we have 1 floor of our generator followed by a boss, repeated 4 times before the run ends. Pretty neat!

And that's about it as far as the level sequence goes. Next time, we'll talk a bit about some built-in LibLevelGen features, generating random numbers and altering generation based on the floor. See you there!