CyclingLinks in Twine SugarCube

@Commissar64 requested the source to my recent Twine game “The Whispering Thing.” We’ll do that sometime soon, but for now I can easily share the modifications to the CyclingLink macro necessary to make it work with the Sugarcube header without creating JS errors.

The code follows. It’s basically just a modification to how the anchor element is created. I can’t guarantee that this will do everything you want it to, as it’s a bit hacky.

version.extensions.cyclinglinkMacro = {
    major: 3,
    minor: 3,
    revision: 0
};
macros.cyclinglink = {
    handler: function (a, b, c) {
        var rl = "cyclingLink";

        function toggleText(w) {
            w.classList.remove("cyclingLinkInit");
            w.classList.toggle(rl + "Enabled");
            w.classList.toggle(rl + "Disabled");
            w.style.display = ((w.style.display == "none") ? "inline" : "none")
        }
        switch (c[c.length - 1]) {
        case "end":
            var end = true;
            c.pop();
            break;
        case "out":
            var out = true;
            c.pop();
            break
        }
        var v = "";
        if (c.length && c[0][0] == "$") {
            v = c[0].slice(1);
            c.shift()
        }
        var h = state.active.variables;
        if (out && h[v] === "") {
            return
        }
        var l = document.createElement("a");
        a.appendChild(l);
        l.className = "internalLink cyclingLink";
        l.setAttribute("data-cycle", 0);
        for (var i = 0; i < c.length; i++) {
            var on = (i == Math.max(c.indexOf(h[v]), 0));
            var d = insertElement(null, "span", null, "cyclingLinkInit cyclingLink" + ((on) ? "En" : "Dis") + "abled");
            if (on) {
                h[v] = c[i];
                l.setAttribute("data-cycle", i)
            } else {
                d.style.display = "none"
            }
            insertText(d, c[i]);
            if (on && end && i == c.length - 1) {
                l.parentNode.replaceChild(d, l)
            } else {
                l.appendChild(d)
            }
        }
        l.onclick = function () {
            var t = this.childNodes;
            var u = this.getAttribute("data-cycle") - 0;
            var m = t.length;
            toggleText(t[u]);
            u = (u + 1);
            if (!(out && u == m)) {
                u %= m;
                if (v) {
                    h[v] = c[u]
                }
            } else {
                h[v] = ""
            } if ((end || out) && u == m - (end ? 1 : 0)) {
                if (end) {
                    var n = this.removeChild(t[u]);
                    n.className = rl + "End";
                    n.style.display = "inline";
                    this.parentNode.replaceChild(n, this)
                } else {
                    this.parentNode.removeChild(this);
                    return
                }
                return
            }
            toggleText(t[u]);
            this.setAttribute("data-cycle", u)
        }
    }
};

3 thoughts on “CyclingLinks in Twine SugarCube

  1. Hello, the author of SugarCube here.

    For the above to work correctly, you’ll need to change the line:
    var h = state.history[0].variables;
    To:
    var h = state.active.variables;

    SugarCube’s History class, which is what the state variable contains an instance of, is somewhat different from its counterpart in the vanilla headers.

      1. Oh, one thing I should mention for those that do want $variable manipulation. When you call the macro, you’ll need to quote the $variable. This is because all macros in SugarCube get $variable substitution automatically, unlike the old headers where each macro had to perform $variable substitution itself. So, if you don’t quote the $variable, instead of getting the $variable name the macro will get the value instead.

        For example, do this:
        <<cyclinglink “$heat” “off” “low” “high” “fearsome”>>
        Not this:
        <<cyclinglink $heat “off” “low” “high” “fearsome”>>

Comments are closed.