gale.sequence

This module is the shared engine behind gale.quest and gale.cutscene: both are, underneath, an ordered series of steps that each run for a while before handing off to the next one. Step is one such step (complete after a fixed duration, as soon as a specific input is pressed, or by whatever custom condition a subclass implements), StepGroup runs several steps side by side, and Sequence drives a list of steps one at a time.

Step

from gale.sequence import Sequence, Step


class ShowBanner(Step):
    def __init__(self, text, font, **kwargs) -> None:
        super().__init__(**kwargs)
        self.text = text
        self.font = font

    def render(self, surface) -> None:
        render_text(surface, self.text, self.font, 400, 300, "white", center=True)


sequence = Sequence([
    # Shown for 2 seconds, or skipped early with the "confirm" input.
    ShowBanner("Chapter 1", font, duration=2.0, advance_on_input="confirm"),
    ShowBanner("A new adventure begins...", font, advance_on_input="confirm"),
])

# In the game loop:
sequence.update(dt)
sequence.render(surface)
# And forward input from wherever your game dispatches it:
sequence.on_input(input_id, input_data)

duration/advance_on_input cover the two most common ways a step finishes on its own. Passing neither leaves is_complete() at its default of “never, on its own” – override it in a subclass instead (a quest objective’s progress is exactly this: see gale.quest). Call super().is_complete() too if duration/advance_on_input should still be able to force it, the same way gale.state.HierarchicalState expects overrides of enter/update/render to call through to keep its own delegation working.

StepGroup

Runs several steps side by side – a character walking across the screen while a line of dialogue plays over it, for instance – completing once all of them are done, or any one of them with require_all=False:

from gale.sequence import StepGroup

StepGroup([
    MoveActor(hero, target=(400, 200), duration=1.5),
    Dialogue("Hero", "This way!", font),
])

A StepGroup is itself a Step, so it can also be given its own duration/advance_on_input, which forcibly completes the whole group regardless of its children (a hard timeout).

Sequence

Sequence is the runner: it enters the first step right away, and every update/render/on_input call is forwarded to whichever step is currently active. on_finished fires once, with no arguments, when the last step completes:

sequence = Sequence(
    [Step(duration=1.0), Step(advance_on_input="confirm")],
    on_finished=lambda: print("done"),
)

sequence.skip_current() forces the active step to end immediately regardless of its own is_complete() – handy for a “hold to skip” input layered on top of whatever the steps themselves already allow.