Custom Macros for SugarCube 2

repository·master·Indexed 41 days ago

https://github.com/chapelr/custom-macros-for-sugarcube-2

A collection of custom macros and systems for Twine games using the SugarCube 2 story format. Version 2.11.1 includes utilities for automatic indefinite articles (<<a>>, <<an>>), click-to-continue interactions (<<cont>>), dynamic CSS styling (<<css>>), and a turn-based time-keeping Cycles System (<<newcycle>>, <<editcycle>>, <<showcycle>>).

Tokens
32.2K
Snippets
111
Records
135
Agent score
52%

What's inside Custom Macros for SugarCube 2

  1. How the Cycles System works

    master

    The Cycles System allows you to introduce rotating states (like time of day, seasons, or days of the week) into your game. You define a cycle with a name, a list of values, and a turn interval. Every time a certain number of turns pass, the cycle moves to the next value in its list, eventually looping back to the start.

    Key Behaviors

    • Independent Tracking: Each cycle tracks its own turns independently. If you create a cycle mid-game, it starts its turn count from zero at that moment. To ensure cycles stay synchronized, it is recommended to declare all <<newcycle>> macros in the same passage (e.g., StoryInit).
    • Resetting/Overwriting: You can overwrite an existing cycle by calling <<newcycle>> with the same name. Note that once a cycle is deleted via <<deletecycle>> or overwritten, it cannot be reclaimed.
    • Suspension: Instead of deleting a cycle you might need later, use <<suspendcycle>> to freeze it in its current state.
    • Data Storage: Cycles are stored in a story variable (defaulting to $cycles), making them compatible with SugarCube's built-in save/load system.
    // Example of creating a synchronized time cycle
    <<newcycle 'time' 'morning' 'noon' 'night' 5>>
  2. Handle import results with the `:import-macro` event

    master

    The :import-macro synthetic event is fired whenever an import attempt completes, regardless of whether it succeeded or failed. You can listen for this event to perform logic based on the outcome of the file loading.

    Event Properties:

    • success (boolean): true if the load completed without errors; false otherwise.
    • data (any): The processed data (converted from Base64 or JSON if applicable).
    • raw (string): The raw, unprocessed file data.
    • storyVar (string): The string name of the variable (including the sigil, e.g., '$player') where the data was stored.
  3. Understand the use of `_is` in macros and widgets

    master
    The collection frequently uses a temporary variable named _is as a return value for widgets, macros, and code chunks. This is primarily intended for testing, debugging, or extending the code. While it allows for a readable scripting style (e.g., <<isBoy>><<if _is>>...), most users can ignore the _is parts for standard day-to-day implementation.
  4. Use the Meter JavaScript API

    master

    The Meter API is available on the setup and window objects. It allows you to create, manage, and interact with meter instances programmatically. Meters created via the JavaScript API are identical to those created via the <<newmeter>> macro, meaning you can use both macros and API methods interchangeably to interact with the same meter.

    // Create a meter via API
    var meter = Meter.add('healthBar', { full: '#00FF00' }, 1);
    
    // Interact with it later via name
    Meter.get('healthBar').val(0.5);
  5. How to preload images outside of `StoryInit`

    master

    The <<preload>> macro and the setup.preload() function are restricted to the StoryInit passage by default to ensure efficient startup. If you have a specific use case that requires preloading at a different time, you can bypass this restriction by setting setup.preload.force to true.

    Warning: This is not recommended and should only be used for exceptional circumstances.

    setup.preload.force = true;
  6. Listen to meter animation events

    master

    Meters trigger two specific events during their animation lifecycle. These events are triggered on the meter's element (meter.$element) and bubble up to the document. The event object contains a meter property which is the Meter instance that triggered the event.

    • :meter-animation-start: Triggered when an animation begins.
    • :meter-animation-complete: Triggered when an animation finishes.

    Usage in JavaScript:

    Meter.get('healthBar').on(':meter-animation-start', function () {
        console.log('Animation started!');
    });

    Usage in TwineScript:

    <<newmeter 'healthBar'>><</newmeter>>
    <<script>>
       Meter.get('healthBar').on(':meter-animation-complete', function () {
            console.log('Animation finished!');
        });
    <</script>>
    var meter = Meter.add('healthBar');
    
    meter.on(':meter-animation-start', function () {
        alert('Your health has changed.');
    });
  7. How the Consumables System works

    master

    The Consumables System is a two-phase system for managing items that can be used and depleted (like potions or spells).

    1. Definition Phase: You define a consumable using the <<newconsumable>> macro. This should typically be done in your StoryInit special passage. A definition includes a display name, a unique ID, the code to run when used, and an optional description.
    2. Manipulation Phase: Once defined, you can add items to the player's inventory, remove them, use them, or list them using various macros and functions.

    Key Constraints:

    • Consumables are not widgets. While they fire code chunks, they are less functional than widgets and should not be used as a direct replacement for them.
    • The consumable inventory is a separate entity from the 'Simple Inventory' system; they cannot manage each other.
    /* Example of the two-phase workflow */
    
    /* 1. Define in StoryInit */
    <<newconsumable 'health potion' 'hpPot'>>
    	<<set $hp += 20>>
    <<description 'hp-desc'>>
    <</newconsumable>>
    
    /* 2. Manipulate in game passages */
    <<addconsumable 'hpPot' 1>>
    <<useconsumable 'hpPot'>>
  8. Configure the Playtime System

    master

    The Playtime System relies on specific internal names that may conflict with your own code. You can modify these via configuration options at the top of the unminified script.

    Potential Conflicts:

    • Story Variable: Uses $playtime by default. Avoid overwriting this variable.
    • Passage Tag: Uses pausetimer by default. Avoid using this tag for other purposes.
    • Task Objects: Creates a postdisplay task named start-playtime and a prehistory task named pause-playtime. Avoid using these names for your own task objects.
  9. How the Cycles System works

    master

    The Cycles System is a time-keeping mechanism based on passage transitions (turns). Each transition typically adds a value to a cycle's 'stack'. When the stack reaches a defined period, the cycle advances to the next phase.

    Key Concepts:

    • Turn: A single passage transition.
    • Stack: A counter that tracks progress toward the next phase.
    • Period: The threshold value the stack must reach to trigger a phase change.
    • Increment: The amount added to the stack per turn. While usually 1, increasing the increment allows you to effectively shorten the period without changing the fixed period value.
    • Phase: A named state (e.g., 'morning', 'night') that the cycle cycles through.

    Note: This version is not compatible with code written for version 1.x of the system.

    /* Concept Example: A cycle that changes phase every 4 turns */
    <<newcycle 'time' 4>>
        <<phase 'morning' 'midday' 'evening' 'night'>>
    <</newcycle>>
  10. Setup the Speech Box System

    master

    The Speech Box System provides macros and functions to generate character dialogue boxes with portraits and names.

    Important Requirements:

    • CSS is required: This system relies on external CSS files to function. You must download and install the relevant CSS files along with the JavaScript.
    • Initialization: To use the <<character>> macro (which creates custom macros for each character), you must run it before the story starts. The StoryInit special passage is the recommended location.
    • Typed.js Compatibility: If you use the typed.js integration module, you must use a specific custom JavaScript implementation instead of the standard one provided by the module (see the documentation for the specific Gist link).
  11. Install and use the Notify macro

    master

    The <<notify>> macro displays a non-distracting message box that slides in from the top right of the screen. It is ideal for transient updates like inventory changes, experience gains, or achievements.

    Important: This macro requires both JavaScript and CSS to function. You must install the CSS code into your story's Stylesheet section in addition to the JavaScript.

    /* Example usage in SugarCube passage */
    <<notify>>Achievement unlocked!<</notify>>
    
    /* Example with custom delay and class */
    <<notify 1s 'inventory-update'>>Found gold.<</notify>>