1
0
Fork 0
mirror of https://github.com/Oreolek/undum-docs.git synced 2024-05-01 16:49:30 +03:00

Initial commit

This commit is contained in:
Alexander Yakovlev 2014-07-24 16:56:29 +07:00
commit 70da504f9f
18 changed files with 1930 additions and 0 deletions

2
LANGS.md Normal file
View file

@ -0,0 +1,2 @@
* [English](en/)
* [Russian](ru/)

2
README.md Normal file
View file

@ -0,0 +1,2 @@
# Undum 2 documentation
Gitbook format

3
book.json Normal file
View file

@ -0,0 +1,3 @@
{
"output": null,
}

690
en/API.md Normal file
View file

@ -0,0 +1,690 @@
# Javascript API
# `Character`
The character is created for you, but is passed into most of the
functions that you define. It consists of an object with no methods
and two properties:
#### `qualities`
The qualities object maps quality identifiers to their current
value. Your code finds the current value associated with a quality by
reading from this object, for example:
var gold = character.qualities.gold;
To set a quality, you have two choices. If you know the quality you
want to set will not appear in the user interface, then you can set it
directly:
character.qualities.gold += 1;
If it does appear on-screen, then this approach will mean that the
character panel doesn't update, and the screen will be out of sync
with the actual value. Instead it is better to use the `System` method
`setQuality`, which also updates the UI:
system.setQuality('gold', character.qualities.gold+1);
It is fine to use `setQuality` if the quality isn't visible, making
this the preferred option for all quality modifications.
#### `sandbox`
Not every bit of data you want to associate with a character fits
nicely into a quality. The sandbox is a general storage space for any
further data you want to store in the course of your game, for
example:
character.sandbox.roomsSearched.push('bathroom');
Sandbox data is never visible to the user, so you can use any data
structures you like here, to any depth.
# `System`
The system represents the interface between your code and the
user-interface. You don't create your own `System` object, it is
passed into your code.
#### `clearContent(elementSelector)`
*Since version 2*
Removes all content from the page, clearing the main content area.
Although Undum is designed to keep the flow of the narrative on one
page, sometimes you do need to start a new page, and this allows you
to do so.
The `elementSelector` is options. If you give it, then the DOM element
matching the selector is cleared, rather than the whole document.
#### `write(content, elementSelector)`
Writes new content to the main flow of the story. The content you pass
in must be either valid DOM elements already, or else be a string
containing text in Display Content format.
The `elementSelector` is optional. If you provide it, then the new
content will be added after the DOM element in the document that
matches the selector. This allows you to do out-of-order addition of
content. Simply add a paragraph with an id in your game, then later
you can give this id as a selector to write, and the new content will
be inserted immediately following that paragraph, regardless of how
much extra content has been added since that point. If no selector is
given then `#content` is used, i.e. the content is added at the end of
the document. The `writeBefore` method inserts content at the start of
the document, or before a selector.
The story will scroll to the start of the insertion point. If you do
not wish to animate this scrolling, but just jump right there, you can
switch off jQuery's animation system by adding `jQuery.fx.off=true` to
your initialization code. This is particularly useful when debugging.
#### `writeHeading(content, elementSelector)`
Writes new content into the story and formats it as a heading. This
method work exactly as `write`, but wraps the content you provide into
a `h1` html tag.
#### `writeBefore(content, elementSelector)`
Writes content into the story. This method is identical to `write`,
above, except that the content is written at the start of the story,
or if a selector is given, inserted before the matching element. On
browsers that support it, the story will be scrolled to the insertion
point.
#### `writeChoices(listOfSituationIds)`
*Since version 2*
Creates a standard block of choices, one for each of the given
situation ids. The text used in the links will be whatever is returned
by the situation's `optionText` method. In addition, if the
situation's `canChoose` method returns `false`, then the option will
be displayed, but will not be clickable.
#### `getSituationIdChoices(listOfIdsOrTags, minChoices, maxChoices)`
*Since version 2*
This function is a complex and powerful way of compiling implicit
situation choices. You give it a list of situation ids and situation
tags. Tags should be prefixed with a hash # to differentiate them from
situation ids. The function then considers all matching situations in
descending priority order, calling their canView functions and
filtering out any that should not be shown, given the current
state. Without additional parameters the function returns a list of
the situation ids at the highest level of priority that has any valid
results. So, for example, if a tag #places matches three situations,
one with priority 2, and two with priority 3, and all of them can be
viewed in the current context, then only the two with priority 3 will
be returned. This allows you to have high-priority situations that
trump any lower situations when they are valid, such as situations
that force the player to go to one destination if the player is out of
money, for example.
If a `minChoices` value is given, then the function will attempt to
return at least that many results. If not enough results are available
at the highest priority, then lower priorities will be considered in
turn, until enough situations are found. In the example above, if we
had a minChoices of three, then all three situations would be
returned, even though they have different priorities. If you need to
return all valid situations, regardless of their priorities, set
minChoices to a large number, such as `Number.MAX_VALUE`, and leave
maxChoices undefined.
If a `maxChoices` value is given, then the function will not return any
more than the given number of results. If there are more than this
number of results possible, then the highest priority resuls will be
guaranteed to be returned, but the lowest priority group will have to
fight it out for the remaining places. In this case, a random sample
is chosen, taking into account the frequency of each situation. So a
situation with a frequency of 100 will be chosen 100 times more often
than a situation with a frequency of 1, if there is one space
available. Often these frequencies have to be taken as a guideline,
and the actual probabilities will only be approximate. Consider three
situations with frequencies of 1, 1, 100, competing for two
spaces. The 100-frequency situation will be chosen almost every time,
but for the other space, one of the 1-frequency situations must be
chosen. So the actual probabilities will be roughly 50%, 50%,
100%. When selecting more than one result, frequencies can only be a
guide.
Before this function returns its result, it sorts the situations in
increasing order of their `displayOrder` properties.
#### `doLink(URL)`
Carries out the action associated with the given URL, as if it had
been the `href` of a HTML link that the user clicked. This allows you
to procedurally change situation and carry out actions from your code.
#### `rnd`
This holds a general purpose random number generator. It is an object
derived from the `Random` prototype, so see `Random` below for details
on its API.
#### `time`
This is a numeric value holding the current time, in seconds, since
the player began playing the game. This value is correctly propagated
across saves, so it is the only way you should track timing. In
particular you should never call `new Date()` and use that value to
determine the outcome of any event. You can use the current date to
display the current date, for example, but not to control what actions
or situations are available. See the section on Loading and Saving for
more details of why this is important.
#### `setQuality(qualityId, newValue)`
Sets the character's given quality to the given value. This function
also updates the character panel, animating the change in value if
that is necessary. Do not directly set quality values in the
character, because the user-interface will not detect and reflect
those changes.
#### `animateQuality(qualityId, newValue, options)`
Like `setQuality`, this function changes the current value of the
given quality. In addition, however, it displays a progress bar that
shows to the user how the value has changed. The `options` parameter
should be an object containing options for how the bar should
display. The available options are:
- `from`: The proportion along the progress bar where the animation
starts. Defaults to 0, valid range is 0-1.
- `to`: The proportion along the progress bar where the animation
ends. Defaults to 1, valid range is 0-1.
- `showValue`: If `true` (the default) then the new value of the
quality is displayed above the progress bar.
- `displayValue`: If this is given, and `showValue` is `true`, then
the given value is used above the progress bar. If this isn't
given, and `showValue` is `true`, then the display value will be
calculated from the `QualityDefinition`, as normal. This option is
useful for qualities that don't have a definition, because they
don't normally appear in the UI.
- `title`: The title of the progress bar. If this is not given, then
the title of the quality is used. As for `displayValue` this is
primarily used when the progress bar doesn't have a
`QualityDefinition`, and therefore doesn't have a title.
- `leftLabel`, `rightLabel`: Underneath the progress bar you can place
two labels at the left and right extent of the track. These can
help to give scale to the bar. So if the bar signifies going from
10.2 to 10.5, you might label the left and right extents with "10"
and "11" respectively and have the `from` and `to` value be 0.2 and
0.5 respectively. If these are not given, then the labels will be
omitted.
#### `setCharacterText(content)`
Sets the block of character text that appears in the character
panel. As for the `write` method, this text should be either valid DOM
elements, or a string meeting the Display Content requirements.
#### `clearLinks(URL)`
Call this function with an Undum link URL (e.g. `ballroom`, or
`ballroom/open-cabinet`). It will remove all occurrences of that link
from the page. This is equivalent to what happens when you change
situation, or when you click a link marked with the `once` CSS
class. It allows you to control what options are available
dynamically, from your code.
## `Random`
The `Random` object provides a set of tools for simple random number
generation, in a way that is guaranteed to work with the Loading and
Saving functionality in Undum. An instance of `Random` is provided in
the `rnd` property of the `System` object, so you will never need to
create your own. It has the following methods:
#### `random()`
Generates a random number between 0 and 1, where 0 is inclusive, and 1
is exclusive. You can use this to check against known probabilities,
such as:
if (system.rnd.random() > 0.5) {
...
}
To check for a 50/50 chance.
#### `randomInt(min, max)`
Return a random number between the given two values, where both values
are inclusive. So `randomInt(2,3)` generates either 2 or 3.
#### `dice(n, dx, plus)`
Rolls _n_ dice with _dx_ sides and adds _plus_ to the result. This
allows you to easily get results for rolls from regular RPG-style
games, such as 3d6+2. The `plus` parameter may be negative or
positive.
#### `aveDice(n, plus)`
Rolls _n_ averaging dice, and adds _plus_ to the result. Averaging dice
are a special type of d6 with sides marked [2,3,3,4,4,5]. They represent
the fact that most people are fairly average, and results should not lie
at the extremes.
#### `diceString(definition)`
Rolls dice according to the given definition string. The string should
be of the form xdy+z, where the x component and z component are
optional. This rolls x dice of with y sides, and adds z to the result,
the z component can also be negative: xdy-z. The y component can be
either a number of sides, or can be the special values 'F', for a
fudge die (with 3 sides, +,0,-), '%' for a 100 sided die, or 'A' for
an averaging die (with sides 2,3,3,4,4,5).
# `Situation`
The `Situation` object is the prototype of all the situations in your
game. It can be used directly, or through its more common derived
type, `SimpleSituation`. The base `Situation` gives you maximum
flexibility, but `SimpleSituation` provides more functionality and can
produce terser code.
#### `new Situation(options)`
Creates a new situation. The options array can specify your
implementation for any or all of the following methods of this class:
- `enter`
- `exit`
- `act`
- `optionText`
- `canView`
- `canChoose`
(see below for explanations of those methods). This allows
you to easily create situations that override certain behaviors with
code such as:
Situation({
enter: function(character, system, from) {
... your implementation ...
}
});
without having to subclass `Situation` to provide your own
implementations.
In addition the following options can be passed in.
- `tags`: A list of tags with which to label this situation. These are
primarily used to generate implicit lists of choices with
`System.getSituationIdChoices`. Tags are arbitrary strings. You can
pass a list of strings, or a single string. If you pass a single
string, it will be split at spaces, commas and tabs to form a list of
tags. For this reason, tags normally do not contain spaces, commas or
tabs (though if you pass in a list, and don't expect Undum to do the
splitting for you, you can include any characters you like in a tag).
- `optionText` (as a string): If given as a string, rather than a
function, this text will be returned whenever `optionText(...)` is
called.
- `displayOrder`: A numeric value, defaults to 1. When displaying
lists of implicitly generated choices, the options be displayed in
increasing value of this parameter.
- `priority`: Can be any number, defaults to 1. When generating lists
of choices implicitly, situations are considered in descending
priority order. If higher priority situations can be displayed, lower
priority situations will be hidden. See `System.getSituationIdChoices`
for details of the algorithm.
- `frequency`: Any number, defaults to 1. When generating lists of
implicit choices, where there are more choices available that slots to
display them, situations will be chosen randomly, with a probability
based on this value. See `System.getSituationIdChoices` for details of
the algorithm.
#### `enter(character, system, from)`
This is called when Undum enters a situation. The `character` and
`system` are instances of `Character` and `System` as described
above. The `from` parameter is a string containing the situation
identifier for the situation that we're arriving from.
This method is the most commonly overridden. It is commonly used to
describe the current situation (by sending content to
`system.write()`) and to update the character (by calling
`system.setQuality()` or by changing data in the character's `sandbox`
object)..
#### `exit(character, system, to)`
This method takes the same `character` and `system` parameters as
`enter`. Its third parameter, `to`, is a string containing the
identifier of the situation we're exiting to.
#### `act(character, system, action)`
This method again takes the same `character` and `system` parameters
as before. Its third parameter is a string containing the action
identifier corresponding to the link the player clicked. It is common
to use an `if` statement or a `switch` to query this action identifier
and decide what to do accordingly. For situations in which many
different actions are possible, consider using the `SimpleSituation`
prototype, which provides this switching behavior for you.
#### `optionText(character, system, hostSituation)`
This method is called by `System.writeChoices` to generate a label for
links to this situation. The `hostSituation` is the situation that has
asked for the choices to be displayed.
#### `canView(character, system, hostSituation)`
This method is called by `System.getSituationIdChoices` to determine
whether this situation can be part of a list of choices in the current
game state. It should return true or false.
#### `canChoose(character, system, hostSituation)`
This method is called by `System.writeChoices` to determine whether a
link should be added to allow the user to enter this situation. If
not, the choice will still appear, but will not be clickable.
## SimpleSituation
This prototype builds on the basic `Situation`, providing tools to
make it easy to output content in the `enter` method, and to switch
between different functions depending on the action identifier passed
into the `act` method. The `exit` method of `SimpleSituation` is
exactly as for the base type `Situation`.
#### `new SimpleSituation(content, options)`
Creates a new simple situation that will display the given content
when its `enter` method is called. The given options dictionary
provides further control of the behavior of this type. Valid options
are:
- `enter`: Providing an enter function in the `options` parameter
allows you to add additional behavior to the enter method. Your
custom function will be called *in addition to* and *after* the
default content is written to the screen. You cannot override
`SimpleSituation`'s `enter` method by providing this function. To
override the method, you would have to create a derived type. If
you provide an `enter` function, it should have the same form as
`Situation.enter`.
- `act`: Pass in a function to add additional behavior to the act
method. As for `enter`, your method is called *in addition to* and
*after* the built-in functionality.
- `exit`: Because `SimpleSituation` has no default behavior for
`exit`, any function you pass in here will be the only exit
behavior for the object you are creating.
- `heading`: The `content` that you specify will be written out
verbatim. You can include headings in this content. Often it is
more convenient to pass in just the text in the `content`
parameter. In that case you may define this `heading` parameter to
display a heading before the text. Unlike `content`, this doesn't
need to conform to the Display Content requirements.
- `actions`: This should be an object that maps action identifiers to
responses. A response should be either some Display Content to
write to the screen, or a function that will process that
request. These functions should have the same signature as the
`Situation.act` method. Each function will only be called if the
situation receives a call to `act` with its corresponding
identifier. This allows you to simply define functions that only
get called when particular actions happen.
- `choices`: An optional list of tags and situation-ids, with tags
prefixed by a has symbol to distinguish them from situation ids. If
given, this will cause the SimpleSituation to output an implicit block
of choices after the content.
- `minChoices`: If you have given a `choices` definition, you can set
this to an integer value to change the number of choices that will
appear. See `System.getSituationIdChoices` for more information on
how this affects the output.
- `maxChoices`: If you have given a `choices` definition, you can set
this to an integer value to change the number of choices that will
appear. See `System.getSituationIdChoices` for more information on
how this affects the output.
An example `SimpleSituation` definition might be:
new SimpleSituation(
"<p>...content...</p>",
{
heading: "Title",
actions: {
listen: function(character, system, action) {
if (character.qualities.hearing > 5) {
system.write("<p>You hear a tinkling inside.</p>");
} else {
system.write("<p>You hear nothing.</p>");
}
},
search: "<p>You find nothing.</p>"
}
}
);
notice how the `listen` function is responsible for its own output,
where the `search` property is a string in Display Content format,
ready for output.
#### Functions in `SimpleSituation`
Both the `content` and the `heading` of a simple situation can be
provided either as plain text, or as a function. If you provide a
function, then it will be called with no arguments, and it should
return a string to use for the output. This enables `SimpleSituation`
to be used with other formatting and templating systems.
# QualityDefinition
Quality definitions tell Undum how and where to display a quality in
the character panel. Each quality definition has one method, `format`,
which is responsible for converting a numeric quality value into a
displayable quantity.
You define your qualities in your `undum.game.qualities` property.
#### `new QualityDefinition(title, options)`
Creates a new `QualityDefinition`. It is rare to call this constructor
yourself, most often one of the derived types of `QualityDefinition`
are used. They are defined below.
The `title` should be a string, and can contain HTML. It is used to
label the quality in the character panel. It can be any string, it
doesn't have to be in Display Content format.
Options are passed in in the `options` 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 identifier of a group in which to display this
parameter. If a group is given, then it must be defined in your
`undum.game.qualityGroups` property.
- `extraClasses`: These classes will be attached to the `<div>` tag
that surrounds the quality when it is displayed. A common use for
this is to add icons representing the quality. In your CSS define a
class for each icon, then pass those classes into the appropriate
quality definitions.
#### `format(character, value)`
This is called by Undum to get a human readable string representing
the given quality value for the given character. The method may return
an empty string if the value has no need to be displayed, or it may
return `null` if the quantity itself shouldn't be displayed. The
difference here is significant. If your `QualityDefinition` returns
the empty string, then the quality will appear in the character panel,
but it will have no value marked. If it returns `null`, then it will
be removed from the character panel entirely.
Most commonly the `character` parameter is ignored, but in your own
derived types you can take advantage of being able to access other
information about the character.
You may call this function yourself, but there is commonly no need. It
will be called by Undum any time the corresponding quality needs to be
displayed.
## `IntegerQuality`
This is a derived type of `QualityDefinition` that displays the
quality value by rounding it down to the nearest integer. This is
ideal for most numeric statistics.
## `NonZeroIntegerQuality`
This is a derived type of `IntegerQuality` that only displays its
value when it is non-zero. If it is non-zero then it formats in the
same way as `IntegerQuality`. Whereas `IntegerQuality` whould show
zero values as '0', this type of quality displays nothing.
## `NumericQuality`
This is a derived type of `QualityDefinition` that displays the
quality value directly, as a full floating point value.
## `WordScaleQuality`
Sometimes you want qualities displayed in words rather than
numbers. This is a derived type of `QualityDefinition` that allows you
to define words corresponding to possible quality values.
#### `new WordScaleQuality(title, words, options)`
The `title` parameter is exactly as for `QualityDefinition`.
The `words` parameter determines what words will be used. It should be
an array of strings. By default the first string will be used to
represent a value of zero (after rounding down), and the second string
a value of 1, and so on to the end of the array. Values outside the
array are treated differently depending on the value of `useBonuses`
in the `options` parameter.
The `options` parameter supports the same three options as
`QualityDefinition`. It also takes the following additional
parameters:
- `offset`: With offset=0 (the default), a quantity value of 0 will
map to the first word, and so on. If offset is non-zero then the
value given will correspond to the first word in the list. So if
offset=4, then the first word in the list will be used for value=4,
the second for value=5. You can specify a non-integer offset value,
in this case the offset is applied *before* the value is rounded
down.
- `useBonuses`: If this is true (the default), then values outside the
range of words will be constructed from the word and a numeric
bonus. So with offset=0 and five words, the last of which is
'amazing', a score of six would give 'amazing+1'. if this is
false, then the bonus would be omitted, so anything beyond
'amazing' is still 'amazing'.
## `FudgeAdjectivesQuality`
This is a derived type of `WordScaleQuality` that doesn't require you
to specify the words you wish to use. It uses the word scale from the
Fudge RPG: "terrible", "poor", "mediocre", "fair", "good", "great" and
"superb".
#### `new FudgeAdjectivesQuality(title, options)`
The parameters `title` and `options` are as for the `WordScaleQuality`
constructor. The `offset` option defaults to -3, however (in
`WordScaleQuality` it defaults to 0), making "fair" the display value
for 0.
## `OnOffQuality`
An `OnOffQuality` returns `null` from its `format` method
(i.e. removes itself from the character panel) when the corresponding
quality value is zero. Otherwise it returns the empty string (i.e. it
is shown in the panel, but doesn't have a value label). See
`QualityDisplay.format` above for more details on this distinction.
#### `new OnOffQuality(title, options)`
The constructor for this type is the same as for `QualityDefinition`
from which it is derived. It accepts one extra option:
- `onDisplay`: If given, then rather than displaying the empty string,
it displays the given string when its corresponding value is
non-zero. This can be used to display a check-mark, for example
(`{onDisplay:"&#10003;"}`), or even a HTML `img` tag.
## YesNoQuality
A `YesNoQuality` displays one of two strings depending whether its
value is zero or not.
#### `new YesNoQuality(title, options)`
The constructor for this type is the same as for `QualityDefinition`
from which it is derived. It accepts two extra options:
- `yesDisplay`, `noDisplay`: Either or both of these may be given. If
they are given, then they should be set to a string, which will be
used to indicate non-zero or zero values, respectively. By default
"yes" and "no" are used.
# `QualityGroup`
A quality group defines a set of qualities that should be displayed
together in the character panel, under an optional subheading. You
could use quality groups to distinguish between qualities representing
a character's innate abilities and their equipment, for example.
You define your quality groups in your `undum.game.qualityGroups`
property.
#### `new QualityGroup(title, options)`
Constructs a new quality group that will have the given `title` for a
subheading. The title may be `null`, indicating that this group does
not need a heading.
The `options` parameter should be an object with the given optional
parameters:
- `priority`: A string used to sort quality groups. When the system
displays more than one quality group, 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").
- `extraClasses`: These classes will be attached to the `<div>` tag
that surrounds the entire quality group when it is displayed. You
can use this in addition to your CSS to radically change the way
certain qualities are displayed.

302
en/HTML.md Normal file
View file

@ -0,0 +1,302 @@
# HTML API
# HTML
All of Undum's output is HTML. This allows you to style your content
in any way you choose. It also allows you to include rich media into
your output, such as images, video or audio.
## Display Content
All HTML output should be in a format we call "Display Content" - this
has particular rules:
* Display Content must always start and end with a HTML tag. It may
consist of more than one tag internally, however. So we can have the
structure: `<p>...</p><img>`, for example, but not `some
text...<img>`.
* It must be a complete snippet of HTML in its own right. So any tags
that represent a range of content must have their closing tags
present. So we can do `<p><em>...</em></p>`, but not
`<p><em>...</p>`.
## CSS Styles
Undum also uses some of HTML's capabilities to control its own
behavior. In particular, it uses a series of CSS classes to control
how content behaves.
#### `class="transient"`
The CSS class `transient` can be used to mark HTML content that should
be removed when the user changes their situation. When a situation
changes, Undum will go back and remove any links from the text
(leaving the text that was in the link). Any HTML content that has the
CSS class `transient` will be completely removed at this time. Undum
uses a fading animation to show the user this is happening, to avoid
the user seeing an abrupt disappearance but being unable to work out
what was removed.
Any HTML tag can be marked as `transient`. It is most commonly used on
a paragraph of text that gives the user a set of options. Undum is
designed to allow game developers to produce beautiful narratives -
you don't want that narrative littered by "You could do X, or you
could do Y." statements. Mark this content as transient, and it will
not form part of the permanent record.
#### `class="sticky"`
When you change situations, links in previous situations will be
removed. This prevents the user backtracking and picking options that
no longer apply. Sometimes you want links to be available for a longer
time, however. In this case mark them with the CSS class
`sticky`. Sticky only applies to links, so should only be added to
`<a>` tags.
#### `class="raw"`
Links can also have the `raw` CSS class. This class prevents Undum
from interpreting the link as an instruction to the game. If you want
to add a link to an external resource, you can add this class to
it. Note that raw links are still removed when you change situations,
so if you want a raw link permanently available, you should also make
it sticky.
For some URLs, Undum can guess that the link is supposed to be an
external link, and will automatically add the `raw` class for
you. This isn't perfect, however, and you are better off not relying
on it. If you have a link that you don't want Undum to capture, always
use the `raw` class.
#### `class="once"`
Although links will be removed when the situation changes, often you
want to remove them before that, as a result of an action within the
current situation. There is an API tool available to do that in your
code.
For convenience, there is also the `once` CSS class. Adding this to a
link means that the link will be removed as soon as it is
clicked. This is mostly useful for action links, because a link that
changes the situation will automatically cause previous links to
disappear.
Note that once is smart about this removal. It removes all links to
the same action, not just the link that was clicked. So if you have
the same action available in two links in your content, both will be
removed.
#### `class="options"`
The options class only works on an unordered list. The default CSS
also styles this differently. The list items will be presented as
options within a table of choices. On devices with a mouse or pointer,
the rows will change color when they are hovered over. The player can
click anywhere on the row and the first link that it contains will be
executed.
This class is intended for smarter presentation of standard option
blocks, if you don't want your choices to be embedded into the
hypertext.
Note that if you use this style, the unordered list will automatically
disappear after being clicked, regardless of whether it is marked as
"`transient`".
### Headings
In the default CSS for Undum, the only heading level expected in the
text is `<h1>`. You can use other headings, but you'll have to create
your own CSS styles. One level of heading is almost always enough (if
not too much) for narrative works.
## Types of Link
Undum captures the links you put into your display content, and uses
them to control the flow of the game. There are three formats of link
that Undum understands, plus raw links, which it ignores.
### Situation Links
Situation links are of the form `situation-id`. They must have no
additional punctuation. As we'll see below, situation identifiers
consist of lower case Latin letters, hyphens and the digits 0-9 only.
Clicking a situation link changes the current situation.
### Action Links
Action links are of the form `./action-id`. As for situations, action
identifiers consist of lower case Latin letters, the digits 0-9 and
hyphens only.
Clicking an action link carries out the specified action in the
current situation.
### Combined Links
Combined links are of the form `situation-id/action-id`. They combine
both the previous steps: they change to the given situation, and then
they carry out the given action once there. They are rarely used.
It is possible to use the combined form to refer to an action in the
current situation. Undum is smart enough to understand that it doesn't
need to change situation in that case, so it is entirely equivalent to
the action link. It is rarely used (because it is so much more
verbose), but can be useful. For example, we might want a sticky link
to always take the character into their study and drink a potion,
having this sticky link point to `bedroom/drink-potion`, achieves
this. If they are already in the bedroom, then Undum notices this and
doesn't try to make them enter it again.
### External Links
As described above, you can add any other links to external content in
your display content, as long as you mark it with the `raw` CSS
class. It is also *highly* recommended that you mark all such links as
opening in a new window or tab (add the `target="_blank"` attribute to
the `<a>` tag). If you link the player to another page, and it
replaces the Undum page, then for most browsers, all progress will be
lost. Chrome appears to keep the progress, so that if you hit the back
button you will be where you left off. Other browsers reset the game
to the last saved location, or back to the beginning if the game
hasn't been saved.
### Link Data
*This section describes a feature that is planned, or in development.
It may not be functional in the current version of the code.*
Undum links are allowed to add query data,
e.g. `./action-id?foo=1&bar=2`. This extra data is URL-encoded content
which will be parsed and passed back to your code. For situation links
the data will be passed into the old situation's `exit` handler, and
the new situation's `enter` handler. For action links, the data will
be passed into the situation's `act` handler. For combined links the
data will be passed into both sets of handlers.
Raw links, as usual, do not have any processing performed. If they
contain query data, it will be passed on to their target as it would
for any link in any HTML document.
# Defining Situations in HTML
*New in Version 2*
From v.2, Undum supports defining situations entirely from HTML. The
tutorial game files show this in action, if you want to see a concrete
example.
### Required Data
Situations defined in HTML should be diven as a `div` with
`class="situation"` set. The content of the `div` will be turned into
a new `SimpleSituation` (see the <a href="./API.html">API
document</a>), with the content of the div output when the situation's
`enter` method is called. In addition to the `class="situation"` and
the HTML content, the `div` also requires its `id` attribute to be
set, and the value of this id will be used as the situation id for the
newly created situation. Situations created from HTML are instances of
the `SimpleSituation` prototype.
The game scans the HTML file for situations, compiles them and adds
them to the main `game.situation` dictionary. Because the situations
end up in the same place, you can freely mix the two methods, defining
some situations in HTML, and others in Javascript. For this reason,
you can't have a situation defined in the HTML with the same id as one
in your Javascript file. This will raise an error.
### Optional Data
In addition to the id and content of the situation, additional options
can be set by defining one or more of the following `data-` attributes
on the `div`. Each is interpreted and passed to a corresponding option
on a `SimpleSituation` object, so to find more information on what
each value means, see the <a href="./API.html">Javascript API</a>.
#### data-option-text
If defined, this specifies the label that will be used when the
situation appears in an choice block. In Javascript, this can be
either fixed text, or a function. In the HTML API, only fixed text is
supported.
#### data-can-view
If defined, this should be the body of a function that will be
compiled and attached to the situation's canView method. The
content of this attribute will be wrapped with:
(function(character, system, situation) {
... HTML attribute ...
})
to make the final function. So, your definition should end with a
`return` statement. For example:
<div id="situation-id-1" class="situation"
data-can-view="return character.qualities.foo == 2">
This is intended to be similar to the way browsers function with event
handlers on HTML tags, such as `onClick`. The actual semantics are
difficult to replicate exactly, and there may be use-cases that are
impossible, but for most uses, this will do the right thing.
#### data-can-choose
If defined, this should be the body of a function that will be
compiled and attached to the situations canChoose method. See the
description of `canView`, above, for details of how the value in this
attribute is interpreted.
#### data-priority
If given, this is parsed as a number and set as the situation's
`priority` value.
#### data-frequency
If given, this is parsed as a number and set as the situation's
`frequency` value.
#### data-display-order
If given, this is parsed as a number and set as the situation's
`displayOrder` value.
#### data-tags
If given this should be a set of tags to label the situation with. The
string is split at commas, spaces and tabs. So "foo, bar cube
dock-trog" is parsed as four tags: "foo", "bar", "cube" and
"dock-trog".
#### data-heading
If given, then this heading will be used as the `heading` property for
the SimpleSituation. If no `data-option-text` is given, the heading
will also be used in choice blocks.
#### data-choices
If given, this should be a list of items to use in generating an
implicit set of situation choices, exactly as for the `choices`
property of `SimpleSituation`. The values of this list is parsed
exactly as for `data-tags`, above, splitting at commas, spaces and
tags.
#### data-min-choices
If `data-choices` is given, this value can also be specified. If so,
it is interpreted as an integer and passed to the `minChoices` option
of `SimpleSituation`.
#### data-max-choices
If `data-choices` is given, this value can also be specified. If so,
it is interpreted as an integer and passed to the `maxChoices` option
of `SimpleSituation`.

1
en/README.md Normal file
View file

@ -0,0 +1 @@
# Undum 2 documentation

4
en/SUMMARY.md Normal file
View file

@ -0,0 +1,4 @@
# Summary
* [Javascript API](api.md)

1
en/api.md Normal file
View file

@ -0,0 +1 @@
# Javascript API

149
en/base.html Normal file
View file

@ -0,0 +1,149 @@
<html>
<head>
<title></title>
<style>
body {
font: 100%/1.5 sans-serif;
margin: 20px;
}
div#content {
margin: 0 auto;
width: 960px;
overflow: hidden;
}
#title {
padding: 0 10px;
}
#title h1 {
font-weight: normal;
text-align: center;
margin-bottom: 0.5em;
font-size: 2.5em;
}
#toc {
float: left;
width: 220px;
padding: 0 10px;
}
#body {
float: left;
width: 700px;
padding: 0 10px;
}
h1, h2, h3, h4 {
color: #777;
margin: 0;
}
h1 {
margin-top: 0.75em;
padding-top: 0.75em;
color: #900;
font-size: 1.6em;
border-top: 1px dotted #999;
}
h1:first-child {
border-top: none;
}
h2 {
color: black;
font-weight: normal;
margin-top: 1.25em;
font-size: 1.4em;
}
h3 {
color: #666;
font-weight: normal;
margin-top: 1em;
font-size: 1.3em;
}
h4 {
color: #666;
font-weight: normal;
margin-top: 0.75em;
font-size: 1.2em;
list-style-type: square;
}
h4:before {
content: "\25A0";
color: #bbb;
padding-right: 0.5em;
}
ul {
padding-left: 1.5em;
}
#toc {
padding-top: 2.4em;
}
ul.toc {
list-style: none;
padding: 0;
margin: 0;
font-size: 0.9em;
}
div.header {
position: relative;
}
div.top {
position: absolute;
right: 0;
bottom: 0;
}
div.top a {
text-decoration: none;
}
li.level_0 { padding-top: 0.5em; font-weight: bold; }
li.level_1 { padding-left: 1em; }
li.level_2 { padding-left: 2em; }
p {
margin: 0 0 0.75em 0;
}
code {
font-size: 1.1em;
}
pre {
padding: 10px;
background: #eed;
}
a {
color: #900;
}
#legal {
float: left;
font-size: 0.75em;
padding-left: 250px;
}
#legal p {
margin-top: 20px;
}
</style>
</head>
<body>
<div id="content">
<div id="title">
<h1>Undum Documentation: {{title}}</h1>
</div>
<div id="toc">
<ul class='toc'>
<li class='level_0'><a href="/">Undum Home</a></li>
<li class='level_0'><a href="/doc/index.html">Documentation Home</a></li>
</ul>
<h2>Contents</h2>
<ul class='toc'>
{% for level,id,text in toc %}
<li class='level_{{level}}'><a href='{{id}}'>{{text}}</a></li>
{% endfor %}
</ul>
</div>
<div id="body">
{{ content }}
</div>
<div id="legal">
<p>
Documentation subject to the <a
href="http://github.com/idmillington/undum/LICENSE">Undum software
license.</a>
</p>
</div>
</div>
</body>
</html>

263
en/creating.md Normal file
View file

@ -0,0 +1,263 @@
# Creating an Undum Game
# File Structure
An Undum game consists of a single HTML file. This imports the game
engine and any supporting files. It also provides the structure needed
for Undum to place content correctly on-screen.
The Undum engine consists of a single Javascript file, `undum.js`. In
order to work, however, it needs supporting files. It requires the
jQuery library (http://jquery.com) to be already imported, and it
requires a game definition file to be imported after it.
The normal pattern of imports in the HTML file is therefore:
<script type="text/javascript" src="media/js/jquery-1.4.2.min.js"></script>
<script type="text/javascript" src="media/js/undum.js"></script>
<script type="text/javascript" src="media/js/mygame.game.js"></script>
By convention, the Javascript files are held in a `media/js`
directory, but this is not enforced, you can arrange these files as
you like, as long as you update the references to match.
In addition to the Javascript files, Undum expects the HTML file that
imports it to have a particular structure. Although there is a good
deal of flexibility, if you need it, you should start with the HTML
file that is provided.
Finally, the HTML file will include a CSS file that controls the look
and feel of the page. There are some elements in the CSS file which
are used by Undum, and so, as for the HTML page, you should start with
the CSS files provided. In most cases you will be able to leave the
CSS file untouched, or else just tweak colors and image imports to
match your game's style.
## The HTML File
The sample HTML file provided shows the key points to edit. They are:
* The game's title.
* The top-left panel title and summary (you can leave this as an
explanation of Undum, or change it to be more game-specific).
* The copyright message. Please note that there is also a message
that acknowledges your game is based on Undum. You can remove this
entirely, but if you do leave it in place, that helps people
find the software and perhaps write their own game.
* The path to your game definition file. By convention, game
definition files are named `yourgamename.game.js`.
In addition, from v.2 onwards, Undum supports defining Situations
entirely within HTML. These situations are scanned and added to
Situations defined in your Javascript Game Definition file, allowing
you to have the best of both worlds. HTML Situations are discussed in
the page on the <a href="./HTML.html">HTML API</a>.
## The Game Definition File
The game definition file where you create your game. To define a game
you must provide the following data:
* A unique ID for the game, which is used to make sure saved games
don't get confused.
* A version number that allows you to manage upgrades to your
content.
* All the Situations that make up your game.
* The identifier of the situation that starts the game.
In addition it is very common to provide the following data:
* Descriptions of each quality your game will use, and how that should
be displayed to the player.
* Definitions of what groups of qualities should appear in the
character panel and what headings to use to label them.
* An Initialization function that sets up the game ready for
playing. This is where you typically assign any starting qualities
to the character, or set their initial character text.
And finally, there are a range of other data you can provide:
* Functions to be called whenever any situation is entered, or exited.
* Functions to be called before or after any action is carried out.
### Identifiers
Identifiers are small snippets of text that allow you to refer to
something in Undum. There are two types of identifier. The Game
identifier represents your whole game, and has its own particular
requirements (described below).
Lots of other things in Undum have identifiers (Situations, Actions,
Qualities, Quality Groups), and they all have the same
requirements. These identifiers must consist of Latin lower-case
letters (i.e. a-z, no accents), hyphens, and the digits 0-9 only.
### Game ID
The game identifier should be a string that is unlikely to be used in
other games. You could use a UUID (my preference), or you could use a
variation on your email `mygame-myname@mydomain.com`, or a URL you
control `http://mydomain.com/undum-games/mygame`. If and when Undum
games end up being re-distributable (as I hope they will), having a
universally unique identifier will mean that saved games don't clash.
As stated previously, the game identifier doesn't have the same
requirements as any other identifier in Undum, you can use any
characters to make up your game ID.
### Version Number
The version number is a string of text that indicates what version of
the content is in the file. There is no set format for this version
text, so you can use any scheme that suits you. I have used the
"major.minor" approach.
Like the Game ID, this value is used to make sure that saved games
don't clash. If you change you content, then previous saved games may
not work correctly. By updating the version number, you allow the
player to be notified of this directly, rather than suffering a
silent crash. The effect of this is that you don't need to update the
version number if you make a change to something that doesn't alter
the structure of the game. If you just change some text, for example,
or add an extra action that merely outputs a piece of description.
### Situation List
Situations are defined in a Javascript object, placed in the
`undum.game.situations` property. Situations in the object use their
situation identifier as a property name, and a `Situation` object as
its value. For example:
undum.game.situations = {
doorway: new Situation(...),
lobby: new SimpleSituation(...),
lobby-upstairs-closed: new MyCustomSituation(...),
... etc ...
};
The situation objects are described more fully below.
### Starting Situation
This is placed in the `undum.game.start` property. It should consist
of the situation identifier as a string. It must be given.
### Qualities
Qualities don't have to be displayed to the user. They can just
function as internal properties for use by your code. Qualities that
will never be displayed don't need to be declared, you can just set
them when you need them (we'll look at the API for setting qualities
below).
Often you want the quality to be displayed, however, and so you need
to tell Undum to display the quality, and how it should be
formatted. The `QualityDefinition` object does that. Any quality that
doesn't have a corresponding quality definition will be invisible to
the player.
Quality definitions are placed in an object in the
`undum.game.qualities` property. Within this object, the property
names are the quality identifiers, and the values they contain are
`QualityDefinition` objects. For example:
undum.game.qualities = {
investigation: new IntegerQuality("Investigation", ...),
"found-mr-black": new OnOffQuality("Found Mr. Black", ...),
... etc ...
};
There are a number of `QualityDefinition` constructors defined which
automatically format in common ways, you can also define your own and
take complete control of the output. We'll return to discussion of the
API, below.
### Quality Groups
Qualities can be assigned to groups, and displayed under a common
heading in the character panel. To define groups, place an object in
the `undum.game.qualityGroups` property. This object should have
properties which are the group identifiers, and values that are
`QualityGroup` objects. For example:
undum.game.qualityGroups = {
stats: new QualityGroup(...),
clues: new QualityGroup(...),
equipment: new QualityGroup(...)
}
A common source of puzzlement is that you don't use this data
structure to define which qualities belong in which group. Instead,
each quality that you want to assign to a group, should be given the
identifier of the group it belongs to. So your `undum.game.qualities`
property will look something like:
undum.game.qualities = {
investigation: new IntegerQuality("Investigation", {group:'stats'}),
"found-mr-black": new OnOffQuality("Found Mr. Black", {group:'clues'}),
... etc ...
};
Again, see the API documentation below for more details about what you
can pass into these constructors.
### Initialization Function
Your initialization function should be placed in the `undum.game.init`
property. Normally its job is to configure the character at the start
of the game. For example:
undum.game.init = function(character, system) {
character.qualities.investigating = 0;
character.qualities.money = 100;
... etc ...
system.setCharacterText(...);
};
Initialization functions can, but normally doesn't, output
text. Instead the starting situation is tasked with outputting the
initial content.
### Global Event Functions
Most of the time you want Situations to handle user
interaction. Occasionally, however, you have to handle something that
spans situations. It would be inconvenient to duplicate the same code
in every situation. So Undum provides a set of hooks for you to
respond globally to user interaction. There are five of these:
`enter`, `afterEnter`, `exit`, `beforeAction` and `afterAction`. You
can define functions in your game file using the properties:
`undum.game.enter`, `undum.game.afterEnter`,
`undum.game.exit`, `undum.game.beforeAction`, and
`undum.game.afterAction`.
The `enter`, `afterEnter`, and `exit` functions look like this:
undum.game.enter = function(character, system, from, to) {
...
};
where `from` and `to` are the identifiers of the situations being left
and entered, respectively. And the `beforeAction` and `afterAction`
functions look like this:
undum.game.beforeAction = function(character, system, situation, action) {
...
};
where `situation` is the current situation identifier, and `action` is
the identifier of the action being carried out.
These functions intentionally look like the `enter`, `exit` and `act`
methods of the `Situation` object. These are described in more detail
in the API reference.

80
en/files.md Normal file
View file

@ -0,0 +1,80 @@
# Loading and Saving
# Loading and Saving
There is no API for you to manually access loading and saving
functionality. The load and save functions are triggered by the
buttons on the user interface. But the way loading and saving work
does have a big impact on the way you write your code.
Undum makes a big feature of the fact that you can scroll back through
the story you've helped create. To save your character's progress you
would have to save not only the current situation and the character's
qualities, but also all the text that has been generated up to that
point. This would not be a problem in a downloaded game, because your
hard-drive is plenty big enough. Unfortunately in a browser game,
there is a limit on how much data you can store. Worse, this data
limit is per-domain. So if you hosted 10 Undum games on a server, the
saved games from all ten would have to fit into the limited
space. This makes it impractical to save the complete text history.
Instead Undum saves all the actions you've taken as a player. It
doesn't save the character's qualities or any other information, just
the actions. It expects to be able to rebuild the complete text, and
the complete current state of the character, by playing back these
actions when the file is loaded. We call this determinism, because the
current state of the character and the content needs to be determined
from just the actions they take.
# Writing with Saving / Loading in Mind
This means that you must take care to write all your code in a way
that will generate *exactly* the same results if the game was played
again in the same way.
There are two major limitations to this, firstly it means you can't
use random events, and secondly you can't use timed events. Both of
these are such serious limitations that Undum provides ways around
them.
If you do not follow these restrictions, then it is likely that saved
games will not load correctly. A player may save their game at one
point and find most of their progress wiped out when they load it
again.
## Random Numbers
Undum provides your code with a random number generator in
`System.rng`, which is an object with the prototype `Random`. This
random number generator works with the loading and saving code to make
sure that, when you load a saved game, the exact same random number
requests will produce the exact same result. This means you get all
the benefits of randomness (i.e. two separate games may have different
results for the same action), but we can always replay a game
exactly. Dealing with random actions is a difficult issue in testing
any interactive fiction game. This approach solves that problem. You
should, therefore, *never* use Javascript's built-in random number
generate (`Math.random`), only ever use the one provided by Undum.
## Timing
Finally, Undum also provides your code timing information in
`System.time`, which is the number of seconds (and fractional seconds)
elapsed since the player began the game. You can use this timing
information to implement puzzles in your game (such as asking the
player to complete a series of tasks in a specified amount of
time). This timing system coordinates with the loading and saving
system to make sure that, when you save and load the game, the timing
picks up where it left off. Feel free to make decisions in your code
based on the current value of `System.time`, but never use
Javascript's `Date` object.
## Detecting Replay When Loading
If your game has elements that should not be triggered while Undum is
replaying a saved game, for example sound effects or popup notifications,
you can use `undum.isInteractive()` to test whether the game is being
played normally (returns `true`) or being loaded from a save game
(returns `false`).

98
en/i18n.md Normal file
View file

@ -0,0 +1,98 @@
# Translation and Internationalization
Undum provides support for translations and internationalization.
In particular, if you feel you want to translate Undum, then a lot
of work has already been done for you. I am very grateful to Oreolek
for this assistance. He translated the Russian version within days
of the code being released, and advised on the tools that would
make translation easier.
To write a game in another language, you need only to write the game
content in that language. The identifiers you use in the game (to
represent situations, actions, qualities and quality groups) must use
only unaccented lower case latin letters and numbers, but the text you
generate can contain any content you choose. Including right to left
content or ideographs.
Undum itself has a small number of error messages and pieces of text
that it uses. These include the default names for the
FudgeAdjectivesQuality values. These strings are all found at the end
of the `undum.js` file. They can be overridden. Simply define a new
language file for your language (e.g. `lang/gk.js`) and override the
appropriate strings. In your HTML file, after importing `undum.js`,
import you strings file. For example, the end of the Russian
translation of the tutorial (`tutorial.ru.html`) has:
<script type="text/javascript" src="media/js/undum.js"></script>
<script type="text/javascript" src="media/js/lang/ru.js"></script>
These translation strings are given as an object mapping the string
name to the translated strings. This object is given as part of the
`undum.translation` object, with a property name equal to the language
name. So, for example, the UK English translation might begin:
undum.lanuage["en-UK"] = {
no_group_definition: "Couldn't find a group definition for {id}.",
Within the translation strings, data to be incorporated later is given
in curly braces.
## Language Codes
Undum uses a simplified version of the IETF standards for language
code. For our purposes this consists of three parts, only the first of
which is required: `language-Script-REGION` where `language` is a two
letter lower-case ISO language code, `Script` is a four letter
title-case script identifier, and `REGION` is a two letter country or
region code, all capitalized. The script is omitted when it is the
default script for a language and locale. You would specify a script
if you were using romaji (Latin letters) to write Japanese, but not if
you were writing it in Kanji and kana.
The major virtue of this standard is that it allows fall through when
a translation is not available. For example a translation into
Brazillian Portuguese `pt-BR` might be different to one into Angolan
Portuguese `pt-AO`, but there may be some strings they have in
common. This allows a translator to create a base file for just plain
Portuguese `pt`, then each country's dialect can define its own file
that just overrides a few of the strings.
## Filename Conventions
It is only a convention, but for all files that occur in language
specific versions, I have used the filename convention of placing the
language code before the extension, e.g. `filename.lang.extension`. The
game file is similar `filename.game.lang.js`. You are free to use any
format you choose, of course, but if you want to contribute back to
the trunk, please follow this convention, to save having to rename
things and connect up the links later.
## API
The translation system provides a simple API based on the `Globalite`
package of Nicolas Merouze (the implementation is unique to Undum). It
adds a `l()` method to the Javascript `String` prototype. This method
has the signature `l(data)`, where data can be any object mapping
strings to other strings.
The method attempts to figure out what the current language is by
looking at the `lang` attribute of the top level HTML tag (you'll
notice in the tutorial games this is defined in all cases, you should
do the same). It then tries to find a matching object containing
translations in `undum.language`. If it finds such an object, then it
looks up the original string in that object to find a translation. It
then merges any data passed into the `l` method into the string,
before returning the result.
The translation look-up honors the IETF rules for language fallback,
so (continuing the previous example) if your game file is in Brazilian
Portuguese `pt-BR`, and a translation isn't found, then generic
Portuguese translation `pt` is also checked. Finally, if no valid
translation is found, then the default version is used. Since Undum
was written in English, this default version is the English
version. This is purely by my convenience, and isn't part of the IETF
spec!

204
en/implicit.md Normal file
View file

@ -0,0 +1,204 @@
# New Choice System
# New Choice System
*New in Version 2*
In version one of Undum, all links from one situation to another had
to be created manually using HTML. If you wanted a set of choices to
offer, you had to create the links yourself, put them in the
appropriate HTML container. If you wanted those choices to depend on
the current state of the game (say, a choice to look behind a secret
panel that was only visible when the panel was discovered), you had to
code that logic yourself in HTML. This meant that, in practice, most
Undum games were simpler, and rarely used branches that depended on
context.
In version 2 both of these issues were addressed: the ability to
quickly build the links to new situations in the standard HTML format
(using the `System.writeChoices` method), and the ability to generate
a list of situations that are available, given the current state of
the game.
# Generating Choice HTML
Thew new `System.writeChoices` method allows you to give a list of
situation id's and have Undum generate a standard looking block of
choices.
It does this by asking each choice how it prefers to be displayed, by
calling its `optionText` method. This allows situtions to change how
they are displayed depending on the current state of the character.
Also called is the situations `canChoose` method. This will normally
return true, but if it returns false, the option will still be
displayed, but not as a link, and will not be clickable. This allows
you to show the player that an option would be available, if they did
something else first, such as increase a quality.
On its own `System.writeChoices` is still mostly manual: it finds the
link text for you, and builds the HTML, but you still have to give it
a set of situation ids that you want for your choices.
# Generating Choices
Undum now also provides the `System.getSituationIdChoices` method
which automatically compiles a list of situation ids, which can then
be passed to `System.writeChoices` for display. This method is
powerful and complex, so we'll explore its use in increasing depth.
## Generating Choices by Tags
Situations now can have one or more tags associated with them. You can
ask `System.getSituationIdChoices` to return the ids of any situtions
that match a tag. This allows you to easily build decisions that you
can extend later. You might have a 'chapter' tag, and you mark each
situation which begins a chapter using this tag, you can then do.
system.getSituationIdChoices(['#chapter'])
to return all chapter choices.
The way tags are processed tries to be intelligent. You can match on
more than one tag, and any situation matching either tag will be
returned, but each situation will be returned no more than once. You
can even mix tags and explicit situation ids:
system.getSituationIdChoices(['#chapter', 'introduction', '#endmatter'])
When you only need to pass one tag to `System.getSituationIdChoices`
you can do so without using a list, so the first example above could
be equally written:
system.getSituationIdChoices('#chapter')
## Ordering Choices
Choices returned by `System.getSituationIdChoices` will be ordered
based on a new `displayOrder` numeric property of situations. This
allows you to make sure situations appear in a logical order,
regardless of whether they were selected by id or by tag.
## Conditional Appearance
So far, any matched situation will always be featured in the list of
choices. A situation can't be visible some times and not others,
depending on the current state of the game. (As we saw with the
`canChoose` method, we can have it be clickable only in some states).
To allow situations to be totally absent in some cases, there is a new
`canView` method on situations. This is only used by
`system.getSituationIdChoices`, and allows a situation to opt out of
being included, if its conditions for appearance are not met. This
allows us to implement the secret panel from the introduction.
We could have a 'go-to-the-basement' situation with tag
'from-the-hallway' available always, while 'go-to-the-secret-room' has
the tag 'from-the-hallway', but a canView method:
secretRoomSituation.canView = function(character, system, host) {
return character.sandbox.has_found_secret_panel;
}
We can then call `system.getSituationIdChoices(['#from-the-hallway'])`
and have the correct choices displayed, depending on the current state
of the game.
## Priority
One common requirement is to have a set of choices which can be
'overrulled' if some condition is true. So we might want the player to
choose where on the island to go to, but if the character is injured,
we might want to only allow the character to go to the hospital.
By default, all situations have a priority of 1. If you give a
situation a higher priority, then it will be considered first. If its
`canView` method returns true, then the high priority situation will
be the only one displayed.
So the injury example might have
- Docks tag:location canView:always priority:1
- Market tag:location canView:always priority:1
- Hospital tag:location canView:when hits < 10 priority:2
- Doctor tag:location canView:when hits < 10 priority:2
Then if the hits quality = 10, we'd see
- Docks
- Market
but if the hits quality dropped to 9, we'd see just
- Hospital
- Doctor
Note that any number of results can be displayed in both cases, but
the higher priorities mask the lower ones.
If you are working with choices that all have a canView function, it
is a good idea to have a 'fallback' situation that can always be
viewed, but has a priority of zero. This will only be visible if none
of the others are available, and will prevent the game from ending at
that point.
## Maximum Choices
When you ask for a list of choices, you can specify a maximum number
to return. If more than this number of choices are available, then the
system will select a random subset to return, to make sure you get the
number you asked for.
By default, all matching situations are equally likely to be returned,
but you can make some situations rarer or more common by setting their
`frequency` value. By default, this value is 1 for a situation.
A situation with a frequency of 100 will be chosen 100 times more
often than a situation with a frequency of 1, if there is one
situation that needs selecting. In cases where more than one situation
needs chosing, the frequencies are a little less intuitive.
Consider three situations with frequencies of 1, 1, 100, competing for
two spaces. The 100-frequency situation will be chosen almost every
time, but for the other space, one of the 1-frequency situations must
be chosen. So the actual probabilities will be roughly 50%, 50%, 100%,
even though the frequencies were 1, 1, 100. When selecting more than
one result, frequencies can only be a guide.
## Minimum Choices
Although rarely used, you can also ask for a minimum number of
choices. This changes the way priority values work. It starts from the
highest priority situations, as normal, but rather than returning only
those at the highest priority level, it checks to see if that set is
enough to meet its minimum. If not, then the next priority level down
will be considered as well, and so on, until the minimum is reached.
If a minimum and a maximum is given (the maximum being at least as
large as the minimum), then only the lowest priority situations will
be randomly selected for any remaining spaces, higher priority
situations will be guaranteed to be chosen.
The most common use of this parameter is to set a very high value,
such as Number.INT_MAX, with no maximum limit. This ensures that all
valid situations are returned, regardless of their priority level.
## Choices and SimpleSituation
`SimpleSituation` provides built-in support for ending its content
with a block of choices, using `System.getSituationIdChoices` to
generate the list and `System.writeChoices` to generate the HTML. To
use this, simply pass in the list of ids and tags as the `choices`
option. You can additionally specify `minChoices` and `maxChoices` if
you need them.
As for `System.getSituationIdChoices`, if you are only using a single
tag or id, you can give this as a string, rather than a single element
list.

71
en/index.md Normal file
View file

@ -0,0 +1,71 @@
# Home
# Contents
## <a href="./introduction.html">High level overview</a>
Describes the concepts that go into an Undum game, and how they
interact.
## <a href="./creating.html">Creating an Undum Game</a>
Describes the files you need to create to make an Undum game, and what
needs to go into them.
## <a href="./implicit.html">Implicit Choices</a>
Version 2 of Undum includes a new framework for automatically
generating choices for the player, based on information stored in
situations.
## <a href="./HTML.html">HTML API</a>
Undum games use HTML to output text and media, but has some
constraints on the HTML you can use. Undum also provides built-in
behavior tied to specific HTML classes that you can use in your
output. In v.2, Undum also added support for defining many kinds of
situation entirely in HTML, with no Javascript needed.
## <a href="./API.html">Javascript API</a>
A complete breakdown of the API exposed to your code via
Javascript. This details the methods that you call to output content,
find random numbers and translate your game.
## <a href="./i18n.html">Translation and Internationalization</a>
Describes Undum's core translation system, and how you can create
games that support multiple languages.
## <a href="./files.html">Loading and Saving</a>
Undum has an unusual way of supporting loading and saving of games, to
support a wide range of browsers, sites and game styles. This document
contains the technical details, and how this affects you as a game
author.
# Undum Changelog
## 2011-05-27
- Added `System.writeBefore` to do out of order insertion. (credit:
ekyrath)
- Added an optional selector to `System.write` and
`System.writeBefore` to support out of order insertion. (credit:
ekyrath)
- Removed the use of `__defineGetter__`, so that the core code now
works on IE7 (thanks for the bug report juhana and bloomengine).
## 2011-08-18
- Added support for functions in the `content` and `header` of a
`SimpleSituation` (credit: David Eyk).
## 2013-09-27
- Updated to v.2, including support for <a
href="./implicit.html">implicit choices</a> and <a
href="./HTML.html">HTML-defined situations</a>.

54
en/introduction.md Normal file
View file

@ -0,0 +1,54 @@
# Introduction
# High Level Overview
Undum games are based around three concepts: Situations, Actions and
Qualities.
## Situations
A situation is a chunk of code that is responsible for adding content
to the screen and responding to user interaction. All user interaction
is performed by clicking links in the content.
Often a link will change the current situation, in which case another
situation is loaded, can write to the screen, and can begin responding
to user interaction. When a situation changes, all links that were
previously available are removed, so that the player can't unfairly go
back and try alternative options after committing to one. It is
possible to override this behavior, see the section on 'Sticky',
below.
There is always exactly one active situation. These situations, and
the links between them, form the structure of the game.
## Actions
A situation may offer the player a series of actions to perform. These
actions are internal to that situation and normally do not cause the
situation to change. Actions may output more content, including new
links for the user to select.
## Qualities
Qualities represent the current state of the character. Internally
they are all numeric values, able to take on any decimal value,
positive or negative. They have no meaning to Undum - they are given
meaning by your code as you perform calculations or make decisions
based on their value.
Qualities display themselves to the user through a formatting
function, which can turn the number into any kind of indicator: a
progress bar, a symbol, a word, an integer, and so on. So as far as
the user is concerned, qualities can represent any kind of value.
## Other Concepts
There are a handful of other elements to an Undum game, but they are
very much in a supporting role. Quality groups allow you to display a
set of qualities under a common heading; and character text is a short
chunk of HTML that you can use to summarize a character's qualities,
or to give hints.

1
ru/README.md Normal file
View file

@ -0,0 +1 @@
# Документация Undum 2

4
ru/SUMMARY.md Normal file
View file

@ -0,0 +1,4 @@
# Summary
* [Javascript API](api.md)

1
ru/api.md Normal file
View file

@ -0,0 +1 @@
# Javascript API