JavaScript must be enabled to play.
Browser lacks capabilities required to play.
Upgrade or switch to another browser.
Loading…
<div id='cardGrid'> <<for _i, _row range Game.Rows>> <<row _row>> <<for _card range _row.cards>> <<printCard _card '' 'noID'>> <</for>> <</row>> <</for>> </div> <<on 'refreshCards'>> <div id='cardbox'> <<for _i, _card range Game.Players[Game.activePlayer].cards>> <<printCard _card `'translate:'+(_i*70)+'%'`>> <</for>> </div> <div id='scoreBox'> <<= Game.Players[Game.activePlayer].score>> </div> <</on>> <span id='senseChanged'/> <<done>> <<run setup.rowIsPlayable()>> <</done>>
<<script>> Macro.add(['a','adel','but','butdel'], { isAsync : true, tags : ['rep','prep','app'], handler() { const type = (this.name[0] === 'b') ? 'button' : 'link', attributes = this.args.slice(1), payload = this.payload[0].contents.trim(); const Rep = this.payload.find(pay => pay.name === 'rep'), Prep = this.payload.find(pay => pay.name === 'prep'), App = this.payload.find(pay => pay.name === 'app'); //Broad errors if (this.args.length === 0) { return this.error(`No ${type} text specified.`); } const error = []; Rep && !Rep.args[0] ? error.push(`<<rep>>`) : null; Prep && !Prep.args[0] ? error.push(`<<prep>>`) : null; App && !App.args[0] ? error.push(`<<app>>`) : null; if (error.length){ return this.error(`Invalid selector supplied to ${error.join(', ')}.`); } // Create element let link = $(document.createElement(type === 'button'? type : 'a')); // Turn argument pairs into attribute/value pairs for (let i = 0; i < attributes.length;i+=2) { if (typeof attributes[i] === 'object'){// jQuery style object link.attr(attributes[i]); i--; } else { //Simple pair link.attr( attributes[i], attributes[i+1]); } } //Built-in event trigger if (link.attr('trigger')){ var trig = link.attr('trigger').split(','); trig = trig.map(event => event.trim()); link.removeAttr('trigger'); } // Goto attribute if (link.attr('goto')){ var passage = link.attr('goto'); link.removeAttr('goto'); // Default link processing if (Story.has(passage)) { link.addClass('link-internal'); if (Config.addVisitedLinkClass && State.hasPlayed(passage)) { link.addClass('link-visited'); } } else { link.addClass('link-broken'); } } // Key attribute if (link.attr('key')){ let keyArray = link.attr('key').split(','); keyArray = keyArray.map(key => key.trim()); // Event handler $(document).on('keyup', function(e) { keyArray.every(key => { if (e[isNaN(Number(key)) ? 'key' : 'keyCode'] == key){ e.preventDefault(); link.click(); return false; //Stops the every() //Makes sure it runs only once even if redundant keys are given } return true; }) }) } //Doesn't take special link syntax so core profile it is link.wikiWithOptions({ profile : 'core' }, this.args[0]) .addClass(`macro-${this.name}`); link.ariaClick({ namespace : '.macros', role : type , one : (this.name.length > 3 || passage !== undefined) ? true : false}, this.createShadowWrapper( function() { payload ? $.wiki(payload) : null ; Rep ? $(Rep.args[0]).empty().wiki(Rep.contents) : null ; Prep ? $(document.createDocumentFragment()) .wiki(Prep.contents).prependTo(Prep.args[0]) : null ; App ? $(App.args[0]).wiki(App.contents) : null ; trig ? trig.forEach(event => {$(document).trigger(event)}) : null ; }, () => { if (passage != null){ //Go to passage Engine.play(passage) } else if (this.name.length > 3){ //Remove link link.remove() } })).appendTo(this.output); } }); /*! <<checkvars>> macro for SugarCube 2.x */ // version check ! function() { "use strict"; if ("undefined" == typeof version || "undefined" == typeof version.title || "SugarCube" !== version.title || "undefined" == typeof version.major || version.major < 2) throw new Error("<<checkvars>> macro requires SugarCube 2.0 or greater, aborting load"); Macro.add("checkvars", { handler: function() { // toString function, processes the objects and indents them function toString(value, indent) { var baseType = typeof value; switch (baseType) { case "number": return isNaN(value) ? `NaN: ${String(value)}` : isFinite(value) ? String(value) : "Infinity"; case "string": return JSON.stringify(value); default: if ("object" !== baseType || null == value) return String(value); var objType = Object.prototype.toString.call(value); if ("[object Date]" === objType) return '(object: Date, value: "' + value.toISOString() + '")'; if ("[object RegExp]" === objType) return "(object: RegExp, value: " + value.toString() + ")"; var opener, closer, result = [],indentText = " "; return indent || (indent = ""), ("[object Set]" === objType || value instanceof Set) && (value = Array.from(value)), Array.isArray(value) ? (opener = "[\n", closer = "\n" + indent + "]", value.forEach(function(p, i) { result.push(indent + indentText + i + " ⇒ " + toString(value[i], indent + indentText)) }), Object.keys(value).forEach(function(p) { /^\d+$/.test(p) || result.push(indent + indentText + toString(p) + " ⇒ " + toString(value[p], indent + indentText)) })) : "[object Map]" === objType || value instanceof Map ? (opener = "{\n", closer = "\n" + indent + "}", Array.from(value).map(function(kv) { result.push(indent + indentText + toString(kv[0], indent + indentText) + " ⇒ " + toString(kv[1], indent + indentText)) })) : (opener = "{\n", closer = "\n" + indent + "}", Object.keys(value).forEach(function(p) { result.push(indent + indentText + toString(p) + " ⇒ " + toString(value[p], indent + indentText)) })), opener + result.join(",\n") + closer } } // Var types setup var dialog, storyvars = Object.keys(State.variables), tempvars = Object.keys(State.temporary), setupvars = Object.keys(setup), settvars = Object.keys(settings); const v = { type: [State.variables, State.temporary, setup, settings], keys: [storyvars, tempvars, setupvars, settvars], but: ['State variables','Temporary variables','Setup objects','Setting objects'], name: [`State variables: ${storyvars.length}`,`Temporary variables: ${tempvars.length}`,`Setup objects: ${setupvars.length}`,`Setting objects: ${settvars.length}`], sigil: ['$','_','setup.','settings.'] }; // Display function function displayVars(index){ var tbody = dialog.querySelector('table tbody'); $(tbody).empty(); v.keys[index].sort(function(a, b) { return Util.isNumeric(a) && Util.isNumeric(b) ? Number(a) - Number(b) : a.localeCompare(b) }); for (var i = -1; i < v.keys[index].length; i++) { if (i === -1) { var tr = document.createElement("tr"), td = document.createElement("td"); $(td).attr('colspan', '2') .attr('text-align', 'center').attr('style', 'width:50em;'); td.innerHTML = '<h3>'+v.name[index]+'</h3>', tr.appendChild(td), tbody.appendChild(tr); } else { var tr = document.createElement("tr"), tdName = document.createElement("td"), tdValue = document.createElement("td"); tdName.textContent = v.sigil[index] + v.keys[index][i], tdValue.textContent = toString(v.type[index][v.keys[index][i]]), tr.appendChild(tdName), tr.appendChild(tdValue), tbody.appendChild(tr) } } }; if (dialog = UI.setup("Variables", "checkvars"), 0 === Object.keys(v.keys).length) return dialog.innerHTML = "<p><em>No $variables currently set…</em></p>", void UI.open(); //Populates dialog with buttons + table let container = jQuery(document.createElement('div')); container.attr('id','macro-checkvars-buttons'); $(dialog).append(container); for (let i = 0; i < v.name.length; ++i) { jQuery(document.createElement('button')) .addClass(`macro-${this.name}-btn-${i}`) .ariaClick( { namespace : '.macros', role : 'button' }, (i => () => displayVars(i))(i) ) .text(v.but[i]) .appendTo(container); } $(dialog).append('<table><tbody></tbody></table>') + (/applewebkit|chrome/.test(Browser.userAgent) ? "" : '<div class="scroll-pad"> </div>'); //Calls for default display of state variables displayVars(0); UI.open() } }) }(); <</script>>
<<if passage() === 'Game'>> <<but 'CheckVars'>> <<checkvars>> <</but>> <</if>> <<but 'Restart'>><<run Engine.restart()>><</but>>
<div id='side' data-passage='SideContent'></div> <div id="passages"></div>
<p> Number of rows: <<numberbox '_rows' 5>> </p> <p> Number of starting cards: <<numberbox '_handSize' 15>> </p> <p> Max number of cards: <<numberbox '_maxRowLength' 5>> </p> <p> Total number of cards: <<numberbox '_totCards' 104>> </p> <p> Number of players: <<numberbox '_players' 2>> </p> <<a 'To game' goto 'Game'>> <<run setup.GameInit(_totCards, _rows, _maxRowLength, _players, _handSize), $(':root').css('--cardSize', Math.min((45/_rows)-.25 , 12)+'rem')>> <<set Game.activePlayer = random(0,Game.Players.length-1)>> <</a>>
<<widget 'printCard'>> <<capture _i>> <div @id="_args[2] === 'noID' ? '' : 'card'+_i" @class="'card val'+_args[0].value" @style='_args[1] ?? ""' @data-number='_args[0].number' @data-value='_args[0].value'> <<= _args[0].number>> <br> <<= _args[0].value>> </div> <<done>> /* Pass event target to the select function */ <<run $('#card'+_i).click(function (e) { setup.selectCard($(e.target)); })>> <</done>> <</capture>> <</widget>>
<<widget 'row' container>> <<capture _i>> <div class='row' @id="'row'+_i" @style="'grid-template-columns:repeat('+_row.maxLength+',1fr)'"> _contents </div> <<done>> <<run $('#row'+_i).click(function (e) { setup.selectRow($(e.target)); })>> <</done>> <</capture>> <</widget>>
<<script>> Macro.add('on', { tags : null, handler() { if (this.args[0] === undefined || this.args[0] === '') { return this.error(`Missing event name.`); } else if (typeof this.args[0] !== 'string'){ return this.error(`Event name must be a string, reading: ${typeof this.args[0]}.`); } let trig = this.args[0].split(','); const content = this.payload[0].contents, attributes = this.args.slice(2); trig = trig.map(event => event.trim()); // Create element, apply attributes let container = $(document.createElement(this.args[1] ? this.args[1] : 'span')).addClass(`macro-${this.name}`); for (let i = 0; i < attributes.length;i+=2) { if (typeof attributes[i] === 'object'){ //JQuery style object container.attr(attributes[i]); i--; } else { // Simple pairs container.attr(attributes[i], attributes[i+1]); } } // Append to passage container.wiki(content).appendTo(this.output); // Apply listeners for each event name trig.forEach(event => { if (Config.debug) { console.log(`Listener added for ${event}.`); } customEvents.pushUnique(event); $(document).on(event, function() { container.empty().wiki(content); }); }) } }); // Triggers custom event Macro.add('trigger', { handler() { if (this.args[0] === undefined || this.args[0] === '') { return this.error(`Missing event name.`); } else if (typeof this.args[0] !== 'string'){ return this.error(`Event name must be a string, reading: ${typeof this.args[0]}.`); } let trig = this.args[0].split(','); trig = trig.map(event => event.trim()); // Triggers each event supplied trig.forEach(event => { $(document).trigger(event); if (Config.debug) { console.log(`Triggered custom event: ${event}.`); } }) } }); // Cleans custom events on passage transition (stops them from stacking) window.customEvents = []; $(document).on(':passageinit', function () { customEvents.forEach(event => $(document).off(event)); customEvents = []; }); <</script>>