### Sugarcube Newmeter Macro Examples
Source: https://github.com/chapelr/custom-macros-for-sugarcube-2/blob/master/docs/meter-macros.md
Examples demonstrating the setup of various meters using the <> macro, including health bars, experience bars, and timers.
```sugarcube
<><><><>
```
```sugarcube
<><><> <>
```
```sugarcube
<><> <>
```
--------------------------------
### First Macro Usage Examples
Source: https://github.com/chapelr/custom-macros-for-sugarcube-2/blob/master/docs/first-macro.md
Demonstrates various ways to use the <>, <>, and <> macros to control content display based on passage visit history. Includes examples for first visits, subsequent visits, and multiple conditional displays.
```sugarcube
<>Show only on first visit.<>
```
```sugarcube
<><>Show me on every visit except the first.<>
```
```sugarcube
<>\n\tFirst visit text.\n<>\n\tSecond visit text.\n<>\n\tThird visit text.\n<>
```
```sugarcube
<>\n\tFirst visit text.\n<>\n\tSecond visit text.\n<>\n\tThird visit and subsequent visits text.\n<>
```
--------------------------------
### SugarCube 2 Installation Guide
Source: https://github.com/chapelr/custom-macros-for-sugarcube-2/blob/master/docs/README.md
Instructions for installing custom SugarCube 2 macros across different Twine versions (Twine 2, Twine 1, Twee2, Tweego) and IDEs. It details how to include JavaScript and CSS files, and mentions configuration for VSCode extensions.
```javascript
// For Twine 2 users: copy and paste the JavaScript code into your story JavaScript area.
// Some macros may also require CSS code, which goes in your story stylesheet.
```
```javascript
// For Twine 1, you'll need to copy and paste the JavaScript portions into a script-tagged passage,
// and the CSS portions (if any) into a stylesheet-tagged passage.
```
```javascript
// For Twee2, refer to its documentation for how to create the tagged passages you need.
```
```javascript
// For Tweego, simply place the code in .js and .css files as appropriate and include them
// in your directory / command line options just as you would any other code files.
```
--------------------------------
### Mouseover Macro Usage Examples
Source: https://github.com/chapelr/custom-macros-for-sugarcube-2/blob/master/docs/mouseover-macro.md
Provides examples of using the mouseover macro for creating tooltips, playing sounds on hover, and navigating on mouseover.
```twine
/% create a link with a "tooltip" %/
<> <><>
<>
<>: Do the thing.>
<>
<><>
<>
@@#tooltip;@@
/% play a sound on mouseover %/
<>Spooooooooky<><>
/% navigate on mouseover %/
Watch the <>[[pit!|fell in a pit]]<><><>
```
--------------------------------
### Troubleshooting SugarCube 2 Macro Installation
Source: https://github.com/chapelr/custom-macros-for-sugarcube-2/blob/master/docs/README.md
Provides solutions for common installation issues with custom SugarCube 2 macros, such as using the 'raw' GitHub button for code and using text editors instead of word processors.
```javascript
<>
```
```javascript
<>
```
--------------------------------
### SugarCube 2 Macro Options Configuration
Source: https://github.com/chapelr/custom-macros-for-sugarcube-2/blob/master/docs/v1-docs.md
Demonstrates how to configure options for SugarCube 2 macros, such as setting story variable names and tags for systems like the Cycles System. This is typically done via a setup object.
```javascript
setup.cycSystem.options = {
storyVar : 'cycles',
resetTag : 'resetcycles',
pauseTag : 'pausecycles',
menuTag : 'menupause',
runNew : true,
tryGlobal : true
};
```
--------------------------------
### Instance Method Usage Example
Source: https://github.com/chapelr/custom-macros-for-sugarcube-2/blob/master/docs/meter-macros.md
Shows how to access and use instance methods like val() on a meter object obtained via Meter.get() or the return value of Meter.add().
```javascript
var meter = Meter.add('myMeter', {}, 0.6);
meter.val(); // 0.6
Meter.get('myMeter').val(); // 0.6
```
--------------------------------
### Dialog Management
Source: https://github.com/chapelr/custom-macros-for-sugarcube-2/blob/master/docs/demo/index.html
Handles dialog opening, closing, and resizing events. It also includes a deprecated setup function.
```javascript
Dialog = function() {
var Dialog = {
close: function() {
triggerEvent(":dialogclose", document.body);
triggerEvent(":dialogclosed", document.body);
},
resize: {
value: function(options) {
return onResize("object" === typeof options ? options.top : undefined);
}
},
wiki: {
value: wiki
},
wikiPassage: {
value: function(name) {
return wiki(Story.get(name).processText());
}
},
setup: {
value: function(title, classNames) {
return console.warn("[DEPRECATED] Dialog.setup() is deprecated."), create(title, classNames), getBody();
}
}
};
return Dialog;
}();
```
--------------------------------
### AJAX Helper Functions (get, post, getJSON, getScript)
Source: https://github.com/chapelr/custom-macros-for-sugarcube-2/blob/master/docs/demo/index.html
Provides convenient wrapper functions for common AJAX request types. These functions simplify making GET, POST, JSONP, and script requests by abstracting away much of the configuration details.
```javascript
getJSON:function(e,t,n){return ce.get(e,t,n,"json")},getScript:function(e,t){return ce.get(e,void 0,t,"script")}}),ce.each(["get","post"],function(e,i){ce[i]=function(e,t,n,r){return v(t)&&(r=r||n,n=t,t=void 0),ce.ajax(ce.extend({url:e,type:i,dataType:r,data:t,success:n},ce.isPlainObject(e)&&e))}}),ce.ajaxPrefilter(function(e){var t;for(t in e.headers)"content-type"===t.toLowerCase()&&(e.contentType=e.headers[t]||"")}),ce._evalUrl=function(e,t,n){return ce.ajax({url:e,type:"GET",dataType:"script",cache:!0,async:!1,global:!1,converters:{"text script":function(){}},dataFilter:function(e){ce.globalEval(e,t,n)}})}
```
--------------------------------
### Resetswap Macro Usage Examples
Source: https://github.com/chapelr/custom-macros-for-sugarcube-2/blob/master/docs/swap-macro-set.md
Demonstrates how to use the `<>` macro to create buttons or links that reset all swappable elements on the page to their initial state.
```sugarcube
<>
<>
```
--------------------------------
### Meter.add() Usage Examples
Source: https://github.com/chapelr/custom-macros-for-sugarcube-2/blob/master/docs/meter-macros.md
Demonstrates how to use the Meter.add() method to create new meter instances with different configurations.
```javascript
Meter.add('healthBar', {}, 1);
Meter.add('timer', { animate : 10000 }, 0);
Meter.add('xpBar');
```
--------------------------------
### SugarCube UI Macro Usage Examples
Source: https://github.com/chapelr/custom-macros-for-sugarcube-2/blob/master/docs/ui-macro.md
Demonstrates practical usage of the SugarCube UI macro for creating custom buttons, managing UI bar visibility, and updating displayed information.
```sugarcube
:: PassageHeader
<>
<>
:: some passage
You took 15 damage!
<>
<>
```
--------------------------------
### Sugarcube Continue Macro (`<>`) Examples
Source: https://github.com/chapelr/custom-macros-for-sugarcube-2/blob/master/docs/continue-macro.md
Demonstrates various uses of the `<>` macro, including basic continuation, triggering on keypress, appending content, and nesting for sequential interaction.
```sugarcube
<><><>
```
```sugarcube
<>The ghost is behind you!<>
```
```sugarcube
<>
<>
<>
However, all but King Arthur fell in the ensuing battle.
<>
<>
<>
King Arthur swore revenge, and set out from his castle!
<>
<>
<>
<>
```
--------------------------------
### SugarCube 2 Initialization and Event Handling
Source: https://github.com/chapelr/custom-macros-for-sugarcube-2/blob/master/docs/demo/index.html
Handles the initial setup of the SugarCube 2 engine, including DOM manipulation, event triggering, and state management. It also manages the saving and restoring of game states.
```javascript
function(){if(null==Config.passages.start)throw new Error("starting passage not selected");if(!Story.has(Config.passages.start))throw new Error('starting passage ("'.concat(Config.passages.start,'") not found'));if(_state=States.Idle,document.documentElement.focus(),State.restore())engineShow();else{var autoloadType=_typeof(Config.saves._internal)
```
--------------------------------
### <> Usage Examples
Source: https://github.com/chapelr/custom-macros-for-sugarcube-2/blob/master/docs/cycles-system.md
Illustrates various ways to use the <> macro, including setting periods, increments, suspending cycles, and defining phases across multiple <> tags.
```sugarcube
/* create a cycle for time that changes phases every 4 turns */
<>
<>
<>
```
```sugarcube
/* create a cycle for a turn-based game */
<>
<>
<>
<>
```
```sugarcube
/* another example, with period and increment set to give an effective period of 4 turns */
<>
<>
<>
```
```sugarcube
/* you can use multiple child tags and multiple phaseNames per child tag, the order will still be preserved */
<>
<>
<>
<>
<>
```
--------------------------------
### Swap Macro Usage Examples
Source: https://github.com/chapelr/custom-macros-for-sugarcube-2/blob/master/docs/swap-macro-set.md
Demonstrates various ways to use the `<>` macro, including simple text swapping, using the `<>` block with conditional logic and DOM manipulation, and creating interactive puzzles.
```sugarcube
/% simple example %/
He picked up the <>picture<> the victim kept on the nightstand, next to the <>alarm clock<>. The <>pillow<> on the bed was cocked at an odd angle--the <>blanket<> was on the floor.
/% example using <> %/
<>
I <>own<>
<>
<>
<>
<>
<>
<>_catsPred<>
<> cats. _catsPred I <>love<> dogs. I <>hate<> birds, though.
/% a puzzle %/
<>
Enter the code:
<>1<>
<>
<>
<>
<>
<>
<>
<>2<>
<>
<>
<>
<>
<>
<>
<>3<>
<>
<>
<>
<>
<>
<>
@@#not-right;@@
<>
<>
```
--------------------------------
### JavaScript Meter API - Overview
Source: https://github.com/chapelr/custom-macros-for-sugarcube-2/blob/master/docs/meter-macros.md
The Meter API provides JavaScript methods to interact with meters, whether created via the API or the <> macro. It is accessible on the `setup` and `window` objects.
```javascript
Meter.create(name, options)
Meter.get(name)
Meter.destroy(name)
```
--------------------------------
### Configuring Default Link Text for Message Macro
Source: https://github.com/chapelr/custom-macros-for-sugarcube-2/blob/master/docs/message-macro.md
Demonstrates how to configure the default link text for the 'message' macro using SugarCube's setup object in JavaScript.
```javascript
setup.messageMacro.default = 'YAY';
// <> macros without linkText arguments will display `YAY`:
```
--------------------------------
### meter.val() Usage Examples
Source: https://github.com/chapelr/custom-macros-for-sugarcube-2/blob/master/docs/meter-macros.md
Provides examples of using the meter.val() method to get the current value and to set a new value, which also triggers animation.
```javascript
Meter.add('blah', {}, 0.4);
Meter.get('blah').val(); // 0.4
Meter.get('blah').val(0.1); // sets the meter to 0.1, and returns 0.1
```
--------------------------------
### Sugarcube 2 setup.preload() Function Usage
Source: https://github.com/chapelr/custom-macros-for-sugarcube-2/blob/master/docs/preload.md
Shows how to use the `setup.preload()` JavaScript function in Sugarcube 2 to preload image resources, similar to the `<>` macro.
```javascript
setup.preload('assets/lisa/jpg', 'assets/bob.jgp');
// you can also provide the arguments as an array if you prefer
setup.preload(['assets/lisa/jpg', 'assets/bob.jgp'])
```
--------------------------------
### _getCodePointStartAndEnd - Get Unicode Character Start and End
Source: https://github.com/chapelr/custom-macros-for-sugarcube-2/blob/master/docs/demo/index.html
A utility function to determine the start and end positions of a Unicode character at a given position in a string. It correctly handles surrogate pairs for characters outside the Basic Multilingual Plane.
```javascript
function _getCodePointStartAndEnd(str, pos) {
var code = str.charCodeAt(pos);
if (Number.isNaN(code)) return { char: "", start: -1, end: -1 };
if (code < 55296 || code > 57343) return { char: str.charAt(pos), start: pos, end: pos };
if (code >= 55296 && code <= 56319) {
var nextPos = pos + 1;
if (nextPos >= str.length) throw new Error("high surrogate without trailing low surrogate");
var nextCode = str.charCodeAt(nextPos);
if (nextCode < 56320 || nextCode > 57343) throw new Error("high surrogate without trailing low surrogate");
return { char: str.charAt(pos) + str.charAt(nextPos), start: pos, end: nextPos }
}
if (0 === pos) throw new Error("low surrogate without leading high surrogate");
var prevPos = pos - 1,
prevCode = str.charCodeAt(prevPos);
if (prevCode < 55296 || prevCode > 56319) throw new Error("low surrogate without leading high surrogate");
return { char: str.charAt(prevPos) + str.charAt(pos), start: prevPos, end: pos }
}
```
--------------------------------
### SugarCube Initialization and Core Components
Source: https://github.com/chapelr/custom-macros-for-sugarcube-2/blob/master/docs/demo/index.html
This snippet outlines the initialization process of SugarCube, including locking the load screen, initializing the engine, setting up storage (session and persistent), and the core structure of the SugarCube object exposed to the window.
```javascript
TempState = {},
session = null,
settings = Setting.create(),
setup = {},
storage = null,
macros = {},
postdisplay = {},
postrender = {},
predisplay = {},
prehistory = {},
prerender = {};
Object.defineProperty(window, "SugarCube", {
value: Object.seal(Object.assign(Object.create(null), {
Browser: Browser,
Config: Config,
Dialog: Dialog,
Engine: Engine,
Fullscreen: Fullscreen,
Has: Has,
L10n: L10n,
Macro: Macro,
Passage: Passage,
Save: Save,
Scripting: Scripting,
Setting: Setting,
SimpleAudio: SimpleAudio,
State: State,
Story: Story,
UI: UI,
UIBar: UIBar,
DebugBar: DebugBar,
Util: Util,
Visibility: Visibility,
Wikifier: Wikifier,
session: session,
settings: settings,
setup: setup,
storage: storage,
version: version
}))
});
jQuery((function() {
var lockId = LoadScreen.lock();
LoadScreen.init();
document.normalize && document.normalize();
new Promise((function(resolve) {
Story.init();
try {
SugarCube.storage = storage = SimpleStore.create(Story.id, !0);
SugarCube.session = session = SimpleStore.create(Story.id, !1)
} catch (ex) {
throw new Error(L10n.get("warningNoStorage"))
}
Dialog.in
```
--------------------------------
### Defining Meters with SugarCube's newmeter Macro
Source: https://github.com/chapelr/custom-macros-for-sugarcube-2/blob/master/docs/demo/index.html
Provides an example of defining custom meters (health bars, timers, progress bars) using the `newmeter` macro and its child tags like `colors`, `sizing`, `animation`, and `label`. Meters must be defined before the story starts.
```sugarcube
<>
<>
<>
<>
<>
<>
<>
<>
<><>
```
--------------------------------
### Wikifier Class Initialization and Core Functionality
Source: https://github.com/chapelr/custom-macros-for-sugarcube-2/blob/master/docs/demo/index.html
Demonstrates the initialization of the Wikifier class, including setting source text, options, and handling output destinations. It also covers the core `subWikify` method for processing text based on defined parsers and terminators, and the `outputText` method for appending text nodes to the DOM.
```javascript
Object.defineProperties(this, {
source: { value: String(source) },
options: { writable: !0, value: Object.assign({ profile: "all" }, options) },
nextMatch: { writable: !0, value: 0 },
output: { writable: !0, value: null },
_rawArgs: { writable: !0, value: "" }
});
this.output = null == destination ? document.createDocumentFragment() : destination instanceof jQuery ? destination[0] : destination;
try {
++_callDepth;
this.subWikify(this.output);
1 === _callDepth && (Object.hasOwn(this.options, "cleanup") && null != this.options.cleanup ? this.options.cleanup : Config.cleanupWikifierOutput) && convertBreaks(this.output);
} finally {
--_callDepth;
}
return _createClass(Wikifier, [{
key: "subWikify",
value: function(output, terminator, options) {
var newOptions, oldOptions, oldOutput = this.output;
this.output = output;
Wikifier.Option.length > 0 && (newOptions = Object.assign(newOptions || {}, Wikifier.Option.options));
null !== options && "object" === _typeof(options) && (newOptions = Object.assign(newOptions || {}, options));
newOptions && (oldOptions = this.options, this.options = Object.assign({}, this.options, newOptions));
var terminatorMatch, parserMatch, parsersProfile = Wikifier.Parser.Profile.get(this.options.profile), terminatorRegExp = terminator ? new RegExp("(?:" + terminator + ")", this.options.ignoreTerminatorCase ? "gim" : "gm") : null;
do {
if (parsersProfile.parserRegExp.lastIndex = this.nextMatch, terminatorRegExp && (terminatorRegExp.lastIndex = this.nextMatch), parserMatch = parsersProfile.parserRegExp.exec(this.source), (terminatorMatch = terminatorRegExp ? terminatorRegExp.exec(this.source) : null) && (!parserMatch || terminatorMatch.index <= parserMatch.index)) return terminatorMatch.index > this.nextMatch && this.outputText(this.output, this.nextMatch, terminatorMatch.index), this.matchStart = terminatorMatch.index, this.matchLength = terminatorMatch[0].length, this.matchText = terminatorMatch[0], this.nextMatch = terminatorRegExp.lastIndex, this.output = oldOutput, void (oldOptions && (this.options = oldOptions));
if (parserMatch) {
parserMatch.index > this.nextMatch && this.outputText(this.output, this.nextMatch, parserMatch.index), this.matchStart = parserMatch.index, this.matchLength = parserMatch[0].length, this.matchText = parserMatch[0], this.nextMatch = parsersProfile.parserRegExp.lastIndex;
for (var matchingParser = void 0, i = 1, iend = parserMatch.length; i < iend; ++i) if (parserMatch[i]) {
matchingParser = i - 1;
break;
}
parsersProfile.parsers[matchingParser].handler(this), null != TempState.break && break;
}
} while (terminatorMatch || parserMatch);
null == TempState.break ? this.nextMatch < this.source.length && (this.outputText(this.output, this.nextMatch, this.source.length), this.nextMatch = this.source.length) : this.output.lastChild && this.output.lastChild.nodeType === Node.ELEMENT_NODE && "BR" === this.output.lastChild.nodeName.toUpperCase() && jQuery(this.output.lastChild).remove();
this.output = oldOutput, oldOptions && (this.options = oldOptions);
}
}, {
key: "outputText",
value: function(destination, startPos, endPos) {
jQuery(destination).append(document.createTextNode(this.source.substring(startPos, endPos)));
}
}, {
key: "rawArgs",
value: function() {
return console.warn("[DEPRECATED] Wikifier.rawArgs() is deprecated."), this._rawArgs;
}
}, {
key: "fullArgs",
value: function() {
return console.warn("[DEPRECATED] Wikifier.fullArgs() is deprecated."), Scripting.desugar(this._rawArgs);
}
}], [{
key: "wikifyEval",
value: function(text) {
var output = document.createDocumentFragment();
new Wikifier(output, text);
var errors = output.querySelector(".error");
if (null !== errors) throw new Error(errors.textContent.replace(errorPrologRegExp, ""));
return output;
}
}, {
key: "createInternalLink",
value: function(destination, passage, text, callback) {
var $link = jQuery(document.createElement("a"));
return null != passage && ($link.attr("data-passage", passage), Story.has(passage) ? ($link.addClass("link-internal"), Config.addVisitedLinkClass && State.hasPlayed(passage) && $link.addClass("link-visited")) : $link.addClass("link-broken"), $link.ariaClick({ one: !0 }, (function() {
"function" == typeof callback && callback();
Engine.play(passage);
}))), text && $link.append(document.createTextNode(text)), destination && $link.appendTo(destination), $link[0];
}
}, {
key: "createExternalLink",
value: function(destination, url, text) {
var $link = jQuery(document.createElement("a")).attr("target", "_blank").addClass("link-external").text(text).appendTo(destination);
return null != url && $link.attr({ href: url, tabindex: 0 }), $link[0];
}
}]);
```
--------------------------------
### Blockquote and Line Quote Handlers
Source: https://github.com/chapelr/custom-macros-for-sugarcube-2/blob/master/docs/demo/index.html
Implements two blockquote handlers: 'quoteByBlock' for multi-line blockquotes starting and ending with '<<<', and 'quoteByLine' for blockquotes indicated by one or more '>' characters at the start of a line. These handlers manage nested blockquotes and line breaks appropriately.
```javascript
Wikifier.Parser.add({name:"quoteByBlock",profiles:["block"],match:"^<<<\\n",terminator:"^<<<\\n",handler:function(w){Wikifier.helpers.hasBlockContext(w.output.childNodes)?w.subWikify(jQuery(document.createElement("blockquote")).appendTo(w.output).get(0),this.terminator):jQuery(w.output).append(document.createTextNode(w.matchText))}}),Wikifier.Parser.add({name:"quoteByLine",profiles:["block"],match:"^>+",lookahead:/^>+/gm,terminator:"\\n",handler:function(w){if(Wikifier.helpers.hasBlockContext(w.output.childNodes)){var matched,i,destStack=[w.output],curLevel=0,newLevel=w.matchLength;do{if(newLevel>curLevel)for(i=curLevel;inewLevel;--i)destStack.pop();curLevel=newLevel,w.subWikify(destStack[destStack.length-1],this.terminator),jQuery(document.createElement("br")).appendTo(destStack[destStack.length-1]),this.lookahead.lastIndex=w.nextMatch;var match=this.lookahead.exec(w.source);(matched=match&&match.index===w.nextMatch)&&(newLevel=match[0].length,w.nextMatch+=match[0].length)}while(matched)}else jQuery(w.output).append(document.createTextNode(w.matchText))}})
```
--------------------------------
### UI Bar Initialization and Interaction Setup
Source: https://github.com/chapelr/custom-macros-for-sugarcube-2/blob/master/docs/demo/index.html
Configures the initial state of the UI bar, including stowing it based on window width and setting up click handlers for the toggle button. It also configures navigation buttons (backward, jumpto, forward) and updates story elements based on game events.
```javascript
start:{value:function(){if(_$uiBar){("boolean"==typeof Config.ui.stowBarInitially?Config.ui.stowBarInitially:jQuery(window).width()<=Config.ui.stowBarInitially)&&stow(!0),jQuery("#ui-bar-toggle").ariaClick({label:L10n.get("uiBarLabelToggle")},(function(){return _$uiBar.toggleClass("stowed")})),Config.history.controls?(jQuery("#history-backward").ariaDisabled(State.length<2).ariaClick({label:L10n.get("uiBarLabelBackward")},(function(){return Engine.backward()})),Story.filter((function(passage){return passage.tags.includes("bookmark")})).length>0?jQuery("#history-jumpto").ariaClick({label:L10n.get("uiBarLabelJumpto")},(function(){return UI.jumpto()})):jQuery("#history-jumpto").remove(),jQuery("#history-forward").ariaDisabled(State.length===State.size).ariaClick({label:L10n.get("uiBarLabelForward")},(function(){return Engine.forward()}))):jQuery("#ui-bar-history").remove();var storyTitleHandler,addUiUpdateHandler=function(handler){return jQuery(document)[Config.ui.updateStoryElements?"on":"one"](":uiupdate".concat(".ui-bar"),handler)},addUpdaterOrRemove=function(selector,passageName){var $el=jQuery(selector);Story.has(passageName)?addUiUpdateHandler((function(){var frag=document.createDocumentFragment();new Wikifier(frag,Story.get(passageName).processText().trim()),$el.empty().append(frag)})):$el.remove()};if(storyTitleHandler=Story.has("StoryDisplayTitle")?function(){return setDisplayTitle(Story.get("StoryDisplayTitle").processText())}:function(){return setDisplayTitle(Story.name,!0)},addUiUpdateHandler(storyTitleHandler),addUpdaterOrRemove("#story-banner","StoryBanner"),addUpdaterOrRemove("#story-subtitle","StorySubtitle"),addUpdaterOrRemove("#story-author","StoryAuthor"),addUpdaterOrRemove("#story-caption","StoryCaption"),Story.has("StoryMenu")){var $menuStory=jQuery("#menu-story");jQuery(document).on(":uiupdate".concat(".ui-bar"),(function(){try{var frag=UI.assembleLinkList("StoryMenu",document.createDocumentFragment());$menuStory.empty().append(frag)}catch(ex){console.error(ex),Alert.error("StoryMenu",ex.message)}}))}else jQuery("#menu-story").remove();Save.browser.size>0?(jQuery("#menu-item-continue a").ariaClick({role:"button"},(function(ev){ev.preventDefault(),Save.browser.continue().then((function(){jQuery(document).off(".menu-item-continue"),jQuery("#menu-item-continue").remove(),Engine.show()}),(function(ex){return UI.alert("".concat(ex.message.toUpperFirst(),".
").concat(L10n.get("textAborting"),"."))}))})).text(L10n.get("continueTitle")),jQuery(document).on(":passagestart.menu-item-continue",(function(){State.turns>1&&(jQuery(document).off(".menu-item-continue"),jQuery("#menu-item-continue").remove())}))):jQuery("#menu-it"
```
--------------------------------
### Playtime Macro Usage
Source: https://github.com/chapelr/custom-macros-for-sugarcube-2/blob/master/docs/playtime-system.md
Demonstrates the different ways to use the <> macro, including basic display, formatted display, and automatic updates using <>.
```sugarcube
<>
<>
<>
<>
<>
```
--------------------------------
### String.prototype.substr Polyfill
Source: https://github.com/chapelr/custom-macros-for-sugarcube-2/blob/master/docs/demo/index.html
Provides a polyfill for String.prototype.substr to ensure correct handling of negative start indices.
```javascript
var xr=f.substr;var Or="".substr&&"0b".substr(-1)!=="b";P(f,{substr:function substr(t,r){var e=t;if(t<0){e=w(this.length+t,0)}return xr.call(this,e,r)}},Or);
```
--------------------------------
### <> Macro
Source: https://github.com/chapelr/custom-macros-for-sugarcube-2/blob/master/docs/v1-docs.md
Resumes a cycle that was suspended by `<>`, allowing it to start collecting turns again.
```javascript
<>
// Example 1: Resumes the cycle named 'timeOfDay', if it is suspended.
<>
// Example 2: Resumes the cycles 'day' and 'seasons', if either is suspended.
<>
```
--------------------------------
### SugarCube 2 Audio Runner Initialization
Source: https://github.com/chapelr/custom-macros-for-sugarcube-2/blob/master/docs/demo/index.html
Initializes the AudioRunner with track descriptions, handling properties like sources, own, and volume. Includes error handling for invalid inputs and initialization failures. Supports cloning tracks and setting initial volumes.
```javascript
function _newTrack(sources) {
// Placeholder for actual track initialization logic
console.log('Initializing new track with sources:', sources);
return {
hasSource: () => true,
clone: () => ({ ...this }),
volume: () => 1.0,
loop: () => false,
mute: () => false,
isPaused: () => false,
isPlaying: () => true,
isStopped: () => false
};
}
function _runnerParseSelector(selector) {
// Placeholder for selector parsing logic
console.log('Parsing selector:', selector);
return [{ id: selector }];
}
function masterMute(mute) {
// Placeholder for master mute logic
console.log('Master mute called with:', mute);
return mute;
}
function publish(event, value) {
// Placeholder for publish logic
console.log('Publish event:', event, 'with value:', value);
}
const Config = { debug: true };
const Visibility = {
isEnabled: () => true,
changeEvent: 'visibilitychange',
isHidden: () => false
};
const jQuery = { off: () => {}, on: () => {} };
const momentCreate = () => ({});
const clone = (obj) => JSON.parse(JSON.stringify(obj));
const historyDeltaEncode = (history) => history;
const _tracks = new Map();
_tracks.set('track1', {
hasSource: () => true,
clone: () => ({ ...this }),
volume: () => 0.8,
loop: () => false,
mute: () => false,
isPaused: () => false,
isPlaying: () => true,
isStopped: () => false
});
_tracks.set('track2', {
hasSource: () => true,
clone: () => ({ ...this }),
volume: () => 0.5,
loop: () => true,
mute: () => true,
isPaused: () => true,
isPlaying: () => false,
isStopped: () => false
});
const _lists = new Map();
const _groups = new Map();
let _masterMuteOnHidden = false;
let _masterRate = 1.0;
let _masterVolume = 0.9;
// Example usage within a larger structure
const AudioRunner = function(trackIds) {
this.trackIds = trackIds;
console.log('AudioRunner created with trackIds:', this.trackIds);
};
const SimpleAudio = Object.defineProperties({}, {
playlists: {
value: Object.defineProperties({}, {
add: {
value: function(id, desc) {
let track = null;
let own = null;
let volume = null;
const what = 'playlist';
try {
if (Object.hasOwn(desc, 'racks')) {
track = _tracks.get(desc.racks.get(desc.id));
} else if (Object.hasOwn(desc, 'sources')) {
if (!Array.isArray(desc.sources) || desc.sources.length === 0) {
throw new Error('"sources" property must be a non-empty array');
}
if (Object.hasOwn(desc, 'own')) {
throw new Error('"own" property is not allowed with the "sources" property');
}
try {
track = _newTrack(desc.sources);
own = true;
} catch (ex) {
throw new Error("error during track initialization: ".concat(ex.message));
}
}
if (Object.hasOwn(desc, 'own')) {
if (typeof desc.own !== 'boolean') {
throw new Error('"own" property must be a boolean');
}
own = desc.own;
if (own) {
track = track.clone();
}
}
if (Object.hasOwn(desc, 'volume')) {
if (typeof desc.volume !== 'number' || Number.isNaN(desc.volume) || !Number.isFinite(desc.volume) || desc.volume < 0) {
throw new Error('"volume" property must be a non-negative finite number');
}
volume = desc.volume;
}
_lists.has(id) && _lists.get(id)._destroy();
_lists.set(id, { _destroy: () => console.log('Destroying playlist:', id), own: null != own && own, track: track, volume: null != volume ? volume : track.volume() });
} catch (ex) {
throw new Error("".concat(what, ": error during playlist initialization: ").concat(ex.message));
}
}
},
delete: {
value: function(id) {
_lists.has(id) && _lists.get(id)._destroy();
return _lists.delete(id);
}
},
clear: {
value: function() {
_lists.forEach(function(list) {
return list._destroy();
});
_lists.clear();
}
},
has: {
value: function(id) {
return _lists.has(id);
}
},
get: {
value: function(id) {
return _lists.get(id) || null;
}
}
})
},
select: {
value: function() {
if (arguments.length === 0) {
throw new Error("no track selector specified");
}
var selector = String(arguments[0]).trim();
var trackIds = new Set();
try {
var renderIds = function renderIds(idObj) {
var ids, id = idObj.id;
switch (id) {
case ":all":
ids = Array.from(_tracks.keys());
break;
case ":looped":
ids = Array.from(_tracks.keys()).filter(function(id) {
return _tracks.get(id).loop();
});
break;
case ":muted":
ids = Array.from(_tracks.keys()).filter(function(id) {
return _tracks.get(id).mute();
});
break;
case ":paused":
ids = Array.from(_tracks.keys()).filter(function(id) {
return _tracks.get(id).isPaused();
});
break;
case ":playing":
ids = Array.from(_tracks.keys()).filter(function(id) {
return _tracks.get(id).isPlaying();
});
break;
case ":stopped":
ids = Array.from(_tracks.keys()).filter(function(id) {
return _tracks.get(id).isStopped();
});
break;
default:
if (id.startsWith(":")) {
var group = _groups.get(id);
if (!group) {
throw new Error('group "'.concat(id, '" does not exist'));
}
ids = group;
} else {
ids = [id];
}
}
if (Object.hasOwn(idObj, "not")) {
var negated = idObj.not.map(function(idObj) {
return renderIds(idObj);
}).flat(1 / 0);
ids = ids.filter(function(id) {
return !negated.includes(id);
});
}
return ids;
};
var allIds = Array.from(_tracks.keys());
_runnerParseSelector(selector).forEach(function(idObj) {
return renderIds(idObj).forEach(function(id) {
if (!_tracks.has(id)) {
throw new Error('track "'.concat(id, '" does not exist'));
}
trackIds.add(id);
});
});
} catch (ex) {
throw new Error("error during runner initialization: ".concat(ex.message));
}
return new AudioRunner(trackIds);
}
},
load: {
value: function() {
publish("load");
}
},
loadWithScreen: {
value: function() {
publish("loadwithscreen");
}
},
mute: {
value: masterMute
},
muteOnHidden: {
value: function(mute) {
if (!Visibility.isEnabled()) {
return false;
}
if (null == mute) {
return _masterMuteOnHidden;
}
var namespace = ".SimpleAudio_masterMuteOnHidden";
if (_masterMuteOnHidden = !!mute) {
var visibilityChange = "".concat(Visibility.changeEvent).concat(namespace);
jQuery(document).off(namespace).on(visibilityChange, function() {
return masterMute(Visibility.isHidden());
});
Visibility.isHidden() && masterMute(true);
} else {
jQuery(document).off(namespace);
}
}
},
rate: {
value: function(rate) {
if (null == rate) {
return _masterRate;
}
if (typeof rate !== 'number' || Number.isNaN(rate) || !Number.isFinite(rate)) {
throw new Error("rate must be a finite number");
}
publish("rate", _masterRate = Math.clamp(rate, 0.2, 5));
}
},
stop: {
value: function() {
publish("stop");
}
},
unload: {
value: function() {
publish("unload");
}
},
volume: {
value: function(volume) {
if (null == volume) {
return _masterVolume;
}
if (typeof volume !== 'number' || Number.isNaN(volume) || !Number.isFinite(volume)) {
throw new Error("volume must be a finite number");
}
publish("volume", _masterVolume = Math.clamp(volume, 0, 1));
}
}
});
// Math.clamp polyfill if not available
if (!Math.clamp) {
Math.clamp = function(value, min, max) {
return Math.min(Math.max(value, min), max);
};
}
```
--------------------------------
### String.prototype.count
Source: https://github.com/chapelr/custom-macros-for-sugarcube-2/blob/master/docs/demo/index.html
Counts the number of non-overlapping occurrences of a substring within the string. An optional starting position can be provided.
```javascript
Object.defineProperty(String.prototype, "count", {
configurable: !0,
writable: !0,
value: function() {
if (null == this) throw new TypeError("String.prototype.count called on null or undefined");
var needle = String(arguments[0] || "");
if ("" === needle) return 0;
for (var indexOf = String.prototype.indexOf, step = needle.length, pos = Number(arguments[1]) || 0, count = 0; -1 !== (pos = indexOf.call(this, needle, pos));) ++count, pos += step;
return count;
}
});
```