Easy Chapter Generator
EnglishEspañol

Explicit failure contract

The system does not infer defeat from health, time, player death, or a stalled Objective. Game code must call ChapterManager.TryFailCurrentChapter(reason). The request is accepted only after the Manager is ready, while one Chapter is active, and when no scene transition is running.

Events only

Accepted failure changes state and raises notifications. It does not load a scene, restore a checkpoint, reposition the player, persist Failed, or display UI automatically.

Request results

ResultWhen it occursRecommended response
FailedThe Chapter was Active and accepted failure.Allow listeners to apply the game's policy.
ManagerNotReadyInitialization has not finished.Wait for On Manager Ready.
NoActiveChapterNo current Chapter exists.Review startup selection.
TransitionInProgressAnother scene is already loading.Ignore the request and avoid opening another defeat flow.
ChapterNotActiveThe Chapter is Completed, Failed, or Not Started.Do not replay historical failure.

State and event order

1

Validate

The Manager rejects invalid states without side effects.

2

State

Chapter becomes Failed; its active or waiting Objective becomes Failed.

3

Typed event

ChapterFailed receives ChapterFailureInfo with Chapter, Objective, and reason.

4

UnityEvent

On Failure runs with no arguments for Inspector listeners.

5

External policy

The game chooses UI, retry, reload, or transition behavior.

Reproducible test

  1. 1
    Create a Chapter with an active Objective and run the scene.
  2. 2
    Add a test Button that calls project code containing TryFailCurrentChapter("manual_test").
  3. 3
    Connect Manager > Lifecycle Events > On Failure to activate a hidden panel.
  4. 4
    Also subscribe to ChapterFailed when the listener needs reason or affected Objective data.
  5. 5
    Select the Button once. Confirm Chapter Failed, Objective Failed, one typed event, and one UnityEvent.
  6. 6
    Select it again. The call must return ChapterNotActive and emit no new notifications.

Design recovery policy

After Failed, game code can call TrySelectChapter, ReloadCurrentScene(true), TransitionToScene, or its own loader. Choose one policy and run it from a failure listener. HandleFailure remains for legacy UnityEvents, but its parameter is now diagnostic reason text and no longer chooses a restart point.

Active and Failed are transient and are not restored as historical progress. See Progress State Persistence.

Common mistakes

On Failure does not run

Log the return value. Any result other than Failed means the request was rejected before events.

The scene does not reload

This is expected. Add an external policy and call the chosen transition explicitly.

Two failure screens appear

Check whether the same consequence listens to both ChapterFailed and On Failure.

Failure returns after loading

The product does not persist Failed. Inspect project-owned state or duplicate subscriptions.

Request an explicit Chapter failure

Where to place it
Add this component to the project object that detects player defeat.
When to call it
Call RequestPlayerDefeat once after the defeat condition is final.
Behavior
Inspect ChapterFailureResult. A rejected request does not invoke ChapterFailed or OnFailure and never reloads a scene.
using System;
using System.Collections;
using System.Collections.Generic;
using OverFuture.ChapterObjectiveSystem.Chapters;
using OverFuture.ChapterObjectiveSystem.Events;
using OverFuture.ChapterObjectiveSystem.Objectives;
using OverFuture.ChapterObjectiveSystem.Persistence;
using OverFuture.ChapterObjectiveSystem.Progression;
using UnityEngine;

public sealed class FailureRequestExample : MonoBehaviour
{
    public ChapterFailureResult RequestPlayerDefeat()
    {
        ChapterManager manager = ChapterManager.Instance;
        return manager != null
            ? manager.TryFailCurrentChapter("player_defeated")
            : ChapterFailureResult.ManagerNotReady;
    }
}

Show a project-owned death screen

Where to place it
Add the component to the UI controller and assign the inactive death-screen GameObject.
When to call it
The screen appears only after ChapterFailed confirms final failure state.
Behavior
This example only displays UI. Input locking, animation, restart policy and accessibility remain project responsibilities.
using System;
using System.Collections;
using System.Collections.Generic;
using OverFuture.ChapterObjectiveSystem.Chapters;
using OverFuture.ChapterObjectiveSystem.Events;
using OverFuture.ChapterObjectiveSystem.Objectives;
using OverFuture.ChapterObjectiveSystem.Persistence;
using OverFuture.ChapterObjectiveSystem.Progression;
using UnityEngine;

public sealed class DeathScreenExample : MonoBehaviour
{
    [SerializeField]
    private GameObject deathScreen;

    private ChapterManager manager;

    private void OnEnable()
    {
        manager = ChapterManager.Instance;
        if (manager != null)
        {
            manager.ChapterFailed += ShowDeathScreen;
        }
    }

    private void OnDisable()
    {
        if (manager != null)
        {
            manager.ChapterFailed -= ShowDeathScreen;
        }
    }

    private void ShowDeathScreen(ChapterFailureInfo information)
    {
        if (deathScreen != null)
        {
            deathScreen.SetActive(true);
        }
    }
}

Restart explicitly after failure

Where to place it
Place this on the death-screen controller and bind RememberFailure to the typed failure handler.
When to call it
Invoke TryRestartFailedChapter from the player's Restart button.
Behavior
Restart is an explicit policy. It is rejected during a scene transition or when no exact failed Chapter ID was recorded.
using System;
using System.Collections;
using System.Collections.Generic;
using OverFuture.ChapterObjectiveSystem.Chapters;
using OverFuture.ChapterObjectiveSystem.Events;
using OverFuture.ChapterObjectiveSystem.Objectives;
using OverFuture.ChapterObjectiveSystem.Persistence;
using OverFuture.ChapterObjectiveSystem.Progression;
using UnityEngine;

public sealed class RestartAfterFailureExample : MonoBehaviour
{
    private string failedChapterId = string.Empty;

    public void RememberFailure(ChapterFailureInfo information)
    {
        failedChapterId = information.Chapter != null
            ? information.Chapter.Identifier
            : string.Empty;
    }

    public bool TryRestartFailedChapter()
    {
        ChapterManager manager = ChapterManager.Instance;
        return manager != null && !manager.IsTransitioning &&
               !string.IsNullOrWhiteSpace(failedChapterId) &&
               manager.TrySelectChapter(failedChapterId);
    }
}