Skip to content
Stefano Balietti edited this page Oct 22, 2021 · 4 revisions

Stager API

  • status: complete
  • version: 7.x

Overview

The stager defines the game sequence using blocks, stages, and steps.

Creating the sequence

  • stage(id):

    Adds a stage with a given id.

    • id {string} The id of the stage.

    Alias: next(id).

  • step(id):

    Adds a step with a given id to the enclosing stage.

  • repeat(id, rounds):

    Adds a stage with a given id to be repeated a certain number of rounds.

    • id {string} The id of the stage.

    • round {number} The number of repetitions.

    Alias: repeatStage(id, rounds).

  • loop(id, cb):

    Adds a stage with a given id to be repeated as long as a condition is true.

    • id {string} The id of the stage.

    • cb {function} A function returning TRUE to execute the stage or FALSE to continue to the next one.

    Alias loopStage(id, cb).

  • doLoop(id, cb):

    Adds a stage with a given id to be repeated as long as a condition is true.

    • id {string} The id of the stage.

    • cb {function} A function returning TRUE to execute the stage or FALSE to continue to the next one.

    Alias doLoopStage(id, cb).

All the methods above return an instance of the stager itself for chaining.

Examples

Adding steps to a stage.

Assuming you have access to a Stager object named stager (e.g., in file game.stages.js), you can build the game sequence by adding stages, steps and blocks to the stager sequentially. Important: the order in which you add them matters! For example:

stager.stage('stage 1');

stager.step('step_1');
stager.step('step_2');

create a sequence of one stage with id stage 1 that contains two steps with id step_1 and step_2.

When the game runs, it executes step_1 first, and step_2 second. In this example stage 1 is just a container for the two steps.

Repeating a stage

It is also possible to repeat a stage a certain number of times. For example:

stager.repeatStage('stage 1', 3);

stager.step('step_1');
stager.step('step_2');

will repeat stage 1 3 times, leading to the following game sequence:

  • step_1, step_2, step_1, step_2, step_1, step_2.

Adding more stages

To add more stages just use the stage or repeatStage multiple times. For example:

stager.stage('stage 1');

stager.repeatStage('stage 2', 3);

stager.step('step2_1');
stager.step('step2_2');

stager.stage('stage 3');

leads to the following game sequence:

  • stage 1, step2_1, step2_2, step2_1, step2_2, step2_1, step2_2, stage 3.
Default steps

In the last example, no step was explicitly added to stage 1 and stage 3. In fact, a default step named with the same name of the containing stage is added automatically.

Looping a stage

When you want to repeat stage, but you do not know in advance how many times, you can specify a loop or a doLoop:

// Evaluates condition **before** entering the stage,
// the whole stage can be skipped if the condition is false.
stager.loopStage('stage 2', function() {
   // Returns true for executing one more iteration of the loop.

   // In this example, the game has a custom variable totEarnings,
   // and we want to terminate the stage if it has reached 1000.
   return node.game.totEarnings < 1000;
});


// doLoop executes the stage at least once, then it behaves like loop.
stager.doLoopStage('stage 2', function() {
    // Returns true for executing one more iteration of the loop.

    // In this example, the game has a custom variable totEarnings,
    // and we want to terminate the stage if it has reached 1000.
    return node.game.totEarnings < 1000;
});

The loop callback is executed with node.game as context. In the above example the variable LOOP_ENDED must be created and set it to true in the logic file to end the loop. For example:

stager.extendStep('stage 2', {
    cb: function() {
        // Example of pseudo-code condition.
        if (TOTAL_PLAYER_PAYOFF > 100) this.LOOP_ENDED = true;
    }
});

Chaining

The stager commands return the stager itself, so it is possible to chain methods together for a more compact script. The following snippets are equivalent:

stager.next('stage1').next('stage2').repeat('stage3', 2);

// is equivalent to:

stager.next('stage1');
stager.next('stage2');
stager.repeat('stage3', 2);

// is equivalent to:

stager.stage('stage1').stage('stage2').repeatStage('stage3', 2)

// is equivalent to:

stager.stage('stage1');
stager.stage('stage2');
stager.repeatStage('stage3', 2);

Splitting Stage definitions across files.

To better organize your code you may use the methods require and share.

  • require(file):

    Requires a file (must export a function) and executes it.

    • file {string} The path to the required file.
  • share(obj):

    Requires a file (must export a function) and executes it.

    • file {string} The path to the required file.

Examples

const SCALE = [
    [ 'No', 'Not a problem<br/>at all' ],
    [ 'Small', 'A small<br/>problem' ],
    [ 'Problem', 'A problem' ],
    [ 'Serious', 'A serious problem' ],
    [ 'Very Serious', 'A very serious problem' ]
];

const MIN = 10;
const MAX = 100;

stager.share({ SCALE, MIN, MAX });

// Split questions in two files.
stager.require('includes/initial_questions.js');
stager.require('includes/additional_questions.js');

Each required file receives an object containing all shared variables, some defined by the user and a few defaults.

// File includes/initial_questions.js
module.exports = function(shared) {

    // Deconstructed shared object includes a reference to the stager itself
    // and to JSUS, in addition to custom variables.
    let { stager, J, SCALE, MIN, MAX } = shared;

    // ...
}

Init and Gameover

  • setOnInit(cb):

    Sets the init function.

    • cb {function} The init function.

    This function will be called as soon as the game is instantiated, i.e. at stage 0.0.0. Event listeners defined here stay valid throughout the whole game, unlike event listeners defined inside a stage / step, which are valid only within the specific stage / step.

  • setOnGameover(cb):

    Sets the gameover function.

    • cb {function} The gameover function.

    This function is called after the last stage of the game-sequence is terminated. Possible actions here are:

    • Storing results
    • Moving clients to another room
    • Destroying the game room

    This function can also be explicitly triggered by gameover().

stager.stage('stage 1')

stager.repeatStage('stage 2', 3);

stager.step('step2_1');
stager.step('step2_2');

stager.stage('stage 3');

stager.gameover();

After the last stage is done, the game state is set to GAME_OVER, and it is not possible to step back and forth through the game, unless it is re-initialized.

Extending stages and steps

  • extendStage(id, update)

    Extends the stage with given id.

    • id {string} The id of the stage to extend.

    • update {object|function} The object or function update.

  • extendStep(id, update)

    Extends the step with given id.

    • id {string} The id of the step to extend.

    • update {object|function} The object or function update.

The update object simply add new properties to existing stage/step object. If a property with the same name already exists it will overwritten.

The update function allows the creation of more complex inheritance patterns, retaining the existing properties of the extended object. For example:

Note! The id of a stage/step cannot be updated, else an error is thrown.

Examples

Object Update
// Create a stage with one default step called 'instructions'.
stager.stage('instructions');

// Extend step with an update object.
stager.extendStep('instructions', {
    cb: function() {
        console.log('Instructions displayed');
    },
    timer: 2000
});
Function Update
// Update stage

// Extend step with an update function.
stager.extendStep('instructions', function(o) {

    // Copy the original callback under a new property named _cb.
    o._cb = o.cb;

    o.cb: function() {
        // Call existing parent callback function.
        this.getCurrentStepObj()._cb();
        // Do something else.
        console.log('I am even more interesting!');
    },
    o.timer: 10000; // More time.

    // Return the updated object.
    return o;
});

Extending more stages/steps at once.

  • extendAllStages(update):

    Extends all stages in the sequence.

    • update {object|function} The object or function update.
  • extendAllSteps(update):

    Extends all steps in the sequence.

    • update {object|function} The object or function update.
  • extendStages(stages, update):

    Extends selected stages.

    • stages {array} Array with ids of the stages to extend.

    • update {object|function} The object or function update.

  • extendSteps(steps, update): extend all steps in the steps array.

    Extends selected steps.

    • steps {array} Array with ids of the steps to extend.

    • update {object|function} The object or function update.

Skipping stages and steps.

  • Game.getProperty(property, nf)

    Returns the requested step property from the game plot.

    • property {string} The name of the property.

    • nf {mixed} Optional. The return value in case the requested property is not found. Default: null.

    Returns {mixed} The value of the requested step property.

  • skip(stageId, stepId):

    Removes a stage or a step from the sequence.

    • stageId {string} The id of the stage

    • stepId {string} Optional. The id of the step

  • skip(stageId, stepId):

    Re-inserts a previously skipped stage or a step into the sequence.

    • stageId {string} The id of the stage

    • stepId {string} Optional. The id of the step

  • isSkipped(stageId, stepId):

    Checks if a stage or a step is currently skipped.

    • stageId {string} The id of the stage

    • stepId {string} Optional. The id of the step

    Returns {boolean} TRUE, if the stage/step is currently skipped.

See also

Clone this wiki locally