// --------------------------------------------------------------------------- // UNDUM game library. Games and other modules using it should require it: // var undum = require('undum'); // // Version: 3.2.0-oreolek // --------------------------------------------------------------------------- var Random = require('./random.js'); var languages = require('./localize.coffee'); // --------------------------------------------------------------------------- // Infrastructure implementations /* Crockford's inherit function */ /* (Exported globally) */ Function.prototype.inherits = function(Parent) { var d = {}, p = (this.prototype = new Parent()); this.prototype.uber = function(name) { if (!(name in d)) d[name] = 0; var f, r, t = d[name], v = Parent.prototype; if (t) { while (t) { v = v.constructor.prototype; t -= 1; } f = v[name]; } else { f = p[name]; if (f == this[name]) { f = v[name]; } } d[name] += 1; r = f.apply(this, Array.prototype.slice.apply(arguments, [1])); d[name] -= 1; return r; }; return this; }; // Feature detection var hasLocalStorage = function() { var hasStorage = false; try { hasStorage = ('localStorage' in window) && window.localStorage !== null && window.localStorage !== undefined; } catch (err) { // Firefox with the "Always Ask" cookie accept setting // will throw an error when attempting to access localStorage hasStorage = false; } return hasStorage; }; // Assertion var AssertionError = function(message) { this.message = message; this.name = AssertionError; }; AssertionError.inherits(Error); var assert = function(expression, message) { if (!expression) { throw new AssertionError(message); } }; // ----------------------------------------------------------------------- // Types for Author Use // ----------------------------------------------------------------------- /* The game is split into situations, which respond to user * choices. Situation is the base type. It has three methods: * enter, act and exit, which you implement to perform any * processing and output any content. The default implementations * do nothing. * * You can either create your own type of Situation, and add * enter, act and/or exit functions to the prototype (see * SimpleSituation in this file for an example of that), or you * can give those functions in the opts parameter. The opts * parameter is an object. So you could write: * * var situation = Situation({ * entering: function(character, system, from) { * ... your implementation ... * } * }); * * If you pass in enter, act and/or exit through these options, * then they should have the same function signature as the full * function definitions, below. * * Note that SimpleSituation, a derived type of Situation, calls * passed in enter, act and exit functions AS WELL AS their normal * action. This is most often what you want: the normal behavior * plus a little extra custom behavior. If you want to override * the behavior of a SimpleSituation, you'll have to create a * derived type and set the enter, act and/or exit function on * their prototypes. In most cases, however, if you want to do * something completely different, it is better to derive your * type from this type: Situation, rather than one of its * children. * * In addition to enter, exit and act, the following options * related to implicit situation selection are available: * * optionText: a string or a function(character, system, * situation) which should return the label to put in an * option block where a link to this situation can be * chosen. The situation passed in is the situation where the * option block is being displayed. * * canView: a function(character, system, situation) which should * return true if this situation should be visible in an * option block in the given situation. * * canChoose: a function(character, system, situation) which should * return true if this situation should appear clickable in an * option block. Returning false allows you to present the * option but prevent it being selected. You may want to * indicate to the player that they need to collect some * important object before the option is available, for * example. * * tags: a list of tags for this situation, which can be used for * implicit situation selection. The tags can also be given as * space, tab or comma separated tags in a string. Note that, * when calling `getSituationIdChoices`, tags are prefixed with * a hash, but that should not be the case here. Just use the * plain tag name. * * priority: a numeric priority value (default = 1). When * selecting situations implicitly, higher priority situations * are considered first. * * frequency: a numeric relative frequency (default = 1), so 100 * would be 100 times more frequent. When there are more * options that can be displayed, situations will be selected * randomly based on their frequency. * * displayOrder: a numeric ordering value (default = 1). When * situations are selected implicitly, the results are ordered * by increasing displayOrder. */ var Situation = function(opts) { if (opts) { if (opts.entering) this._entering = opts.entering; if (opts.act) this._act = opts.act; // Options related to this situation being automatically // selected and displayed in a list of options. this._optionText = opts.optionText; this._canView = opts.canView || true; this._canChoose = opts.canChoose || true; this._priority = (opts.priority !== undefined) ? opts.priority : 1; this._frequency = (opts.frequency !== undefined) ? opts.frequency : 1; this._displayOrder = (opts.displayOrder !== undefined) ? opts.displayOrder : 1; // Tag are not stored with an underscore, because they are // accessed directy. They should not be context sensitive // (use the canView function to do context sensitive // manipulation). if (opts.tags !== undefined) { if ($.isArray(opts.tags)) { this.tags = opts.tags; } else { this.tags = opts.tags.split(/[ \t,]+/); } } else { this.tags = []; } } else { this._canView = true; this._canChoose = true; this._priority = 1; this._frequency = 1; this._displayOrder = 1; this.tags = []; } }; /* A function that takes action when we enter a situation. The * last parameter indicates the situation we have just left: it * may be null if this is the starting situation. Unlike the * exit() method, this method cannot prevent the transition * happening: its return value is ignored. */ Situation.prototype.entering = function(character, system, from) { if (this._entering) this._entering(character, system, from); }; /* A function that takes action when we carry out some action in a * situation that isn't intended to lead to a new situation. */ Situation.prototype.act = function(character, system, action) { if (this._act) this._act(character, system, action); }; /* Determines whether this situation should be contained within a * list of options generated automatically by the given * situation. */ Situation.prototype.canView = function(character, system, situation) { if ($.isFunction(this._canView)) { return this._canView(character, system, situation); } else { return this._canView; } }; /* Determines whether this situation should be clickable within a * list of options generated automatically by the given situation. */ Situation.prototype.canChoose = function(character, system, situation) { if ($.isFunction(this._canChoose)) { return this._canChoose(character, system, situation); } else { return this._canChoose; } }; /* Returns the text that should be used to display this situation * in an automatically generated list of choices. */ Situation.prototype.optionText = function(character, system, situation) { if ($.isFunction(this._optionText)) { return this._optionText(character, system, situation); } else { return this._optionText; } }; /* Returns the priority, frequency and displayOrder for this situation, * when being selected using `system.getSituationIdChoices`. */ Situation.prototype.choiceData = function(character, system, situation) { return { priority: this._priority, frequency: this._frequency, displayOrder: this._displayOrder }; }; /* Instances of this class define the qualities that characters * may possess. The title should be a string, and can contain * HTML. Options are passed in in the opts parameter. The * following options are available. * * priority - A string used to sort qualities within their * groups. When the system displays a list of qualities they * will be sorted by this string. If you don't give a * priority, then the title will be used, so you'll get * alphabetic order. Normally you either don't give a * priority, or else use a priority string containing 0-padded * numbers (e.g. "00001"). * * group - The Id of a group in which to display this * parameter. The corresponding group must be defined in * your `undum.game.qualityGroups` property. * * extraClasses - These classes will be attached to the
of the first paragraph, and ends with the
of * the last. So "Foo
" is valid, but "foo" is not. * * The content goes to the end of the page, unless you supply the * optional selector argument. If you do, the content appears * after the element that matches that selector. */ System.prototype.write = function(content, elementSelector) { doWrite(content, elementSelector, 'append', 'after'); }; /* Outputs the given content in a heading on the page. The content * supplied must be valid "Display Content". * * The content goes to the end of the page, unless you supply the * optional selector argument. If you do, the content appears * after the element that matches that selector. */ System.prototype.writeHeading = function(headingContent, elementSelector) { var heading = $("