mirror of
https://github.com/Oreolek/raconteur.git
synced 2024-06-26 03:30:47 +03:00
Refactor
This commit is contained in:
parent
f51ae68f57
commit
103c2cbddf
137
lib/situation.js
137
lib/situation.js
|
@ -9,14 +9,36 @@ var undum = require('undum-commonjs'),
|
|||
which coalesce as a DSL for defining Undum stories.
|
||||
----------------------------------------------------------------------------*/
|
||||
|
||||
/* ---------------------------------------------------------------------------
|
||||
situation.js
|
||||
|
||||
Raconteur's core, defines a new Situation prototype.
|
||||
*/
|
||||
|
||||
/* ---------------------------------------------------------------------------
|
||||
Helper functions
|
||||
----------------------------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
Normalises the whitespace on a string.
|
||||
|
||||
1. Disregard empty lines
|
||||
2. Find the indent (leading whitespace) of each line
|
||||
3. Figure out the bottom indentation level (Ie, smallest indent). An empty
|
||||
string is a valid "0 indentation"
|
||||
4. Strip that much indentation out of each line, so that the bottom
|
||||
level is now 0 indentation.
|
||||
|
||||
This is done so that multiline strings in code can be indented along with
|
||||
(And in fact one level deeper than) the surrounding code, for programmer
|
||||
convenience, without all of the code being parsed by markdown-it as a giant
|
||||
<pre> block.
|
||||
|
||||
Note that tabs and spaces are both counted as one character, which is too
|
||||
bad for the guy mixing them.
|
||||
*/
|
||||
|
||||
|
||||
String.prototype.normaliseTabs = function () {
|
||||
var lines = this.split('\n');
|
||||
var indents = lines
|
||||
|
@ -39,13 +61,14 @@ String.prototype.normaliseTabs = function () {
|
|||
/*
|
||||
Many properties in Raconteur can be either a String, or a function that
|
||||
takes some objects from the game state (character, system, and the current
|
||||
situation) and returns a String. Or in Haskell terms:
|
||||
situation) and returns a String. Or in Haskellese:
|
||||
|
||||
String | (CharacterObject -> SystemObject -> SituationString -> String)
|
||||
|
||||
fcall() is added to the prototypes of both String and Function to handle
|
||||
these situations. 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.
|
||||
fcall() (by analogy with fmap) is added to the prototypes of both String and
|
||||
Function to handle these situations. 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;
|
||||
|
@ -63,6 +86,8 @@ var markdown = new md({
|
|||
|
||||
/*
|
||||
Ensures a string is a HTML string, by wrapping it in span tags.
|
||||
|
||||
FIXME: This is not necessarily the best approach.
|
||||
*/
|
||||
|
||||
String.prototype.spanWrap = function () {
|
||||
|
@ -71,6 +96,8 @@ String.prototype.spanWrap = function () {
|
|||
|
||||
/*
|
||||
Adds the "fade" class to a htmlString.
|
||||
|
||||
FIXME: Currently this is an undocumented feature.
|
||||
*/
|
||||
|
||||
String.prototype.fade = function () {
|
||||
|
@ -81,55 +108,14 @@ String.prototype.fade = function () {
|
|||
|
||||
The prototype RaconteurSituation is the basic spec for situations
|
||||
created with Raconteur. It should be able to handle any use case for Undum.
|
||||
|
||||
Properties:
|
||||
|
||||
(In addition to properties inherited from undum.Situation)
|
||||
|
||||
actions :: {key: (character, system, from) -> null}
|
||||
|
||||
An object containing definitions for actions, which are called when an
|
||||
action without a special marker (writer, inserter, replacer) is called
|
||||
when the situation is current, usually by clicking an action link.
|
||||
|
||||
after :: (character, system, from) -> null
|
||||
|
||||
A function that is called right after printing the content of the
|
||||
situation. Useful for housekeeping tasks (Such as changing character
|
||||
stats) or implementing custom behaviour in general.
|
||||
|
||||
before :: (character, system, from) -> null
|
||||
|
||||
Similar to after, but called first
|
||||
|
||||
choices :: [String]
|
||||
|
||||
A list of situation names and/or tags that can be listed as choices for
|
||||
this situation. That list will be further filtered by CanView and
|
||||
CanChoose.
|
||||
|
||||
content :: markdownString | (character, system, from) -> markdownString
|
||||
|
||||
The main content of the situation, printed when the situation is entered.
|
||||
|
||||
visited :: Number
|
||||
|
||||
Defaults to 0. Incremented every time the situation is entered.
|
||||
|
||||
writers :: {key: markdownString | (character, system, from) -> markdownString}
|
||||
|
||||
An object containing definitions for special actions called by inserter,
|
||||
writer, and replacer links. Note that the content of writer links will be
|
||||
interpreted as a regular markdownString, while the content of replacer
|
||||
and inserter links, on the assumption that it's meant to be written into
|
||||
an existing paragraph, will be interpreted as a inline markdown.
|
||||
This prototype is fairly complex; see the API documentation.
|
||||
|
||||
*/
|
||||
|
||||
var RaconteurSituation = function (spec) {
|
||||
undum.Situation.call(this, spec);
|
||||
|
||||
// Add all properties of the spec to the object, indiscriminately.
|
||||
// Add all own properties of the spec to the object, indiscriminately.
|
||||
Object.keys(spec).forEach( key => {
|
||||
if (this[key] === undefined) {
|
||||
this[key] = spec[key];
|
||||
|
@ -185,53 +171,43 @@ RaconteurSituation.prototype.enter = function (character, system, f) {
|
|||
|
||||
RaconteurSituation.prototype.act = function (character, system, action) {
|
||||
var actionClass,
|
||||
self = this;
|
||||
that = this;
|
||||
|
||||
var responses = {
|
||||
writer: function (ref) {
|
||||
var beforeOpts = undefined;
|
||||
if (self.writers[ref] === undefined) {
|
||||
throw new Error("Tried to call undefined writer:" + ref);
|
||||
}
|
||||
let content = that.writers[ref].fcall(that, character, system, action);
|
||||
let output = markdown.render(content).fade();
|
||||
if ($('.options').length) {
|
||||
system.writeBefore(
|
||||
markdown.render(
|
||||
self.writers[ref].fcall(self, character, system, action))
|
||||
.fade(), '.options');
|
||||
// Write before the options list if one is currently shown.
|
||||
system.writeBefore(output, '.options');
|
||||
} else {
|
||||
system.write(
|
||||
markdown.render(
|
||||
self.writers[ref].fcall(self, character, system, action)
|
||||
).fade());
|
||||
system.write(output);
|
||||
}
|
||||
},
|
||||
replacer: function (ref) {
|
||||
if (self.writers[ref] === undefined) {
|
||||
throw new Error("Tried to call undefined replacer:" + ref);
|
||||
}
|
||||
system.replaceWith(
|
||||
markdown.renderInline(
|
||||
self.writers[ref].fcall(self, character, system, action)
|
||||
).spanWrap().fade(), `#${ref}`);
|
||||
let content = that.writers[ref].fcall(that, character, system, action);
|
||||
let output = markdown.renderInline(content).fade();
|
||||
system.replaceWith(output, `#${ref}`);
|
||||
},
|
||||
inserter: function (ref) {
|
||||
if (self.writers[ref] === undefined) {
|
||||
throw new Error("Tried to call undefined inserter:" + ref);
|
||||
}
|
||||
system.writeInto(
|
||||
markdown.renderInline(
|
||||
self.writers[ref].fcall(self, character, system, action)
|
||||
).spanWrap().fade(), `#${ref}`);
|
||||
let content = that.writers[ref].fcall(that, character, system, action);
|
||||
let output = markdown.renderInline(content).fade();
|
||||
system.writeInto(output, `#${ref}`);
|
||||
}
|
||||
};
|
||||
|
||||
if (actionClass = action.match(/^_(\w+)_(.+)$/)) {
|
||||
responses[actionClass[1]](actionClass[2]);
|
||||
} else if (self.actions.hasOwnProperty(action)) {
|
||||
self.actions[action].call(self, character, system, action);
|
||||
// Matched a special action class
|
||||
let [responder, ref] = [actionClass[1], actionClass[2]]
|
||||
|
||||
if(!that.writers.hasOwnProperty(actionClass[2])) {
|
||||
throw new Error(`Tried to call undefined writer: ${action}`);
|
||||
}
|
||||
responses[responder](ref);
|
||||
} else if (that.actions.hasOwnProperty(action)) {
|
||||
that.actions[action].call(that, character, system, action);
|
||||
} else {
|
||||
throw new Err(`Action "${action}" attempted with no corresponding` +
|
||||
'action in current situation.');
|
||||
throw new Error(`Tried to call undefined action: ${action}`);
|
||||
}
|
||||
|
||||
};
|
||||
|
@ -241,6 +217,7 @@ module.exports = function (name, spec) {
|
|||
return (undum.game.situations[name] = new RaconteurSituation(spec));
|
||||
};
|
||||
|
||||
/* Hack. Needed to ensure a single global "Undum" object. FIXME. */
|
||||
module.exports.exportUndum = function () {
|
||||
if (!global.undum) {
|
||||
global.undum = undum;
|
||||
|
|
Loading…
Reference in a new issue