markdown = require('./markdown.coffee') ### fcall() (by analogy with fmap) is added to the prototypes of both String and Function. When called on a Function, it's an alias for Function#call(); when called on a String, it only returns the string itself, discarding any input. ### Function.prototype.fcall = Function.prototype.call; String.prototype.fcall = function() { return this; } # Utility functions parseFn = (str) -> unless str? return str fstr = """ (function(character, system, situation) { #{str} #}) """ return eval(fstr) # Scrolls the top of the screen to the specified point scrollTopTo = (value) -> $('html,body').animate({scrollTop: value}, 500) # Scrolls the bottom of the screen to the specified point scrollBottomTo = (value) -> scrollTopTo(value - $(window).height()) # Scrolls all the way to the bottom of the screen scrollToBottom = () -> scrollTopTo($('html').height() - $(window).height()); # Regular expression to catch every link action. # Salet's default is a general URL-safe expression. linkRe = /^([0-9A-Za-z_-]+|\.)(\/([0-9A-Za-z_-]+))?$/ # Returns HTML from the given content with the non-raw links wired up. augmentLinks = (content) -> output = $(content) # Wire up the links for regular tags. output.find("a").each((index, element) -> a = $(element) href = a.attr('href') if (!a.hasClass("raw")|| href.match(/[?&]raw[=&]?/)) if (href.match(linkRe)) a.click((event) -> event.preventDefault() # If we're a once-click, remove all matching links. if (a.hasClass("once") || href.match(/[?&]once[=&]?/)) system.clearLinks(href) processClick(href) return false ) else a.addClass("raw") ) return output ### This is the control structure, it has minimal amount of data and this data is volatile anyway (as in, it won't get saved). ### Salet = { rnd: null time: 0 # Corresponding room names to room objects. rooms: {} # The unique id of the starting room. start: "start" # --- Hooks --- ### This function is called at the start of the game. It is normally overridden to provide initial character creation (setting initial quality values, setting the character-text. This is optional, however, as set-up processing could also be done by the first situation's enter function. If this function is given it should have the signature function(character, system). ### init: null ### This function is called before entering any new situation. It is called before the corresponding situation has its `enter` method called. ### entering: (character, system, oldSituationId, newSituationId) -> ### Hook for when the situation has already been carried out and printed. ### afterEnter: (character, system, oldSituationId, newSituationId) -> ### This function is called before carrying out any action in any situation. It is called before the corresponding situation has its `act` method called. If the function returns true, then it is indicating that it has consumed the action, and the action will not be passed on to the situation. Note that this is the only one of these global handlers that can consume the event. ### beforeAction: (character, system, situationId, actionId) -> ### This function is called after carrying out any action in any situation. It is called after the corresponding situation has its `act` method called. ### afterAction: (character, system, situationId, actionId) -> ### This function is called after leaving any situation. It is called after the corresponding situation has its `exit` method called. ### exit: (character, system, oldSituationId, newSituationId) -> ### Removes all content from the page, clearing the main content area. If an elementSelector is given, then only that selector will be cleared. Note that all content from the cleared element is removed, but the element itself remains, ready to be filled again using System.write. ### clearContent: (elementSelector) -> document.querySelector(elementSelector).innerHTML = "" # jQuery was confused by this point where's the context so I did it vanilla-way write: (content, elementSelector) -> if content == "" return if typeof content == "function" content = content() block = document.getElementById("current-situation") if block block.innerHTML = block.innerHTML + markdown(content) else console.error("No current situation found.") ### Turns any links that target the given href into plain text. This can be used to remove action options when an action is no longer available. It is used automatically when you give a link the 'once' class. ### clearLinks: (code) -> $("a[href='" + code + "']").each((index, element) -> a = $(element) a.replaceWith($("").addClass("ex_link").html(a.html())) ) ### Given a list of situation ids, this outputs a standard option block with the situation choices in the given order. The contents of each choice will be a link to the situation, the text of the link will be given by the situation's outputText property. Note that the canChoose function is called, and if it returns false, then the text will appear, but the link will not be clickable. Although canChoose is honored, canView and displayOrder are not. If you need to honor these, you should either do so manually, ot else use the `getSituationIdChoices` method to return an ordered list of valid viewable situation ids. ### writeChoices: (listOfIds, elementSelector) -> if (listOfIds.length == 0) return currentSituation = getCurrentSituation(); $options = $("