Writing:Reference Section
Writing |
---|
Introduction |
Property types
- Text
- A block of text which is interpreted “wiki-style” – square brackets indicate special behavior.
- Code
- A block of text which is interpreted as Python (actually TworldPy) code.
- Code (args)
- Same as
Code
, but with an extra field for arguments. These are treated as formal parameters. A code property with argumentsx, y
is like a function definedfunc(x, y): ...
You can also specify default values:x=1, y="foo"
.
- GenText
- A structure used for procedural text generation.
- Move
- A special property which moves the player to another location (in the same world).
- Event
- A special property which sends a message to the player’s event pane (and possibly to other players in the same location).
- Panic
- A special property which throws the player out of the world. May optionally send an event message to the player and/or to nearby players.
- EditStr
- A special property which allows the player to edit a text property in the location. The first field must be the name of a string value (or text) property (which acts as a default value). When edited, an instance property is written with a new string value.
- The label is displayed above the edit field. The two messages at the end appear to the editing player, and nearby players, when a change occurs. By default only players with
member
access may edit this field, but you may set access tovisitor
(everybody) or a higher level.
- DateTime
- Interpreted as a Python
datetime
. The value must look like “YYYY-MM-DD” or “YYYY-MM-DD HH:MM:SS” or “YYYY-MM-DD HH:MM:SS.UUUUUU” (the last field is microseconds). It is always interpreted in UTC (not your local time zone). Leave the field blank to get a timestamp of right now.
- Value
- Interpreted as a Python native value.
- (Delete)
- Selecting this and confirming will delete the property entirely.
Python native values can be any of:
- Integers or floating-point numbers
- Quoted strings (single or double quotes are okay, but not curly quotes)
True
,False
: Booleans (must be capitalized)None
: Python null value (must be capitalized)[1, "Foo", True]
: A list (array) of Python values in square brackets{"foo": 1, "bar": 2}
: A dictionary (hash) written in curly braces. The keys must be strings; the values can be any Python values.
Caveats:
- Python tuples are accepted but stored as lists. (So
(1,2,3)
will be stored as[1,2,3]
.) - Python set literals
{1,2,3}
are rejected. - Python bytes objects
b"foo"
are accepted, but are probably not good for anything. - Integers are limited to 64 bits. (Values much beyond
±9.2e18
cannot be stored.) (Float values have a much wider range, but less precision.) - Python
datetime
objects must be entered with theDateTime
property type, not withValue
. - Python
ObjectId
objects cannot currently be entered in the build interface.
The special property types (
Text
,Code
, etc) are actually represented in the property database as Python dictionaries. For example, aText
value “Foo.” is really{"type": "text", "text": "Foo."}
You will probably never need to know this, but if you do, the formats are defined here.
Text formatting and substitutions
Text is converted to HTML, so whitespace is generally not significant. Extra spaces, indentation, and single newlines are collapsed into single spaces. (Double newlines are taken as true paragraph breaks.)
All text, except when in square brackets, is displayed directly. You may freely enter Unicode characters as-is; you don’t have to escape them or use HTML character constants.
We’ve seen several different syntaxes for square-bracket substitutions in text.
Here’s the complete list. It can be broken down into three major groups: [hyperlinks]
, [[interpolations]]
, and [$magic]
codes.
- The
[$magic]
cases, with the dollar signs, are not hyperlinks; they mostly interpolate text. You might therefore expect them to be written[[$magic]]
. In fact that will work, but we also accept the single-square-bracket form – it’s easier to type.
Hyperlinks
[prop]
- Displays a hyperlink “prop”, which invokes the
prop
property. If that’sText
, it is displayed as a close-up pop-up. If it’sCode
, it’s executed.Move
,Event
, etc properties take effect as defined.Value
properties are displayed as events (to the player only).
[Text in brackets.]
- A hyperlink; the contents are sluggified, then invokes a property as above. This example would display as “Text in brackets,” but invoke a property named
text_in_brackets
.
[single|bar]
- A hyperlink that displays “single” but invokes the property named
bar
.
[single bar|code()]
- A hyperlink that displays “single bar”, and executes the given line of code.
- This is really the same as the previous case.
bar
as a code statement means “invoke the property namedbar
.”
- This is really the same as the previous case.
[single bar|http://whatever/]
- A hyperlink that displays “single bar” and opens an external web page (in a new browser window). The URL after the bar must begin with
http:
to be recognized this way.
[with double||bar]
- A hyperlink that displays “with double bar” and invokes the property named
bar
.
[with double||bar words]
- A hyperlink that displays “with double bar words” and invokes the property named
bar_words
. The text after the double bar is sluggified, so it may not contain arbitrary code.
Interpolations
[[interpolation]]
- Evaluates the
interpolation
symbol and inserts the result in-line. This is not a hyperlink.
[[code()]]
- Executes the line of code and inserts the result in-line. The code doesn’t have to be a function call; it could be an expression, such as
foo+3
. However, it may not be an assignment (a property change).
[ [[symbol]] | bar]
- Displays
symbol
as the text of a hyperlink which invokesbar
.- This nests an interpolation inside a hyperlink. You may not nest a hyperlink inside a hyperlink!
$ codes
Substitutions
[$para]
- A paragraph break. This is the same as putting a blank line (two line-breaks) in the text.
[$openbracket], [$closebracket]
- Literal square brackets.
[$name]
- The name of the acting player.
[$they], [$we]
- One of “he”, “she”, “it”, “they”, as appropriate for the acting player.
[$them], [$us]
- One of “him”, “her”, “it”, “them”.
[$their], [$our]
- One of “his”, “her”, “its”, “their”.
[$theirs], [$ours]
- One of “his”, “hers”, “its”, “theirs”.
[$themself], [$ourself]
- One of “himself”, “herself”, “itself”, “themself”.
- The pronouns are available in capital forms:
[$They]
for “He”, “She”, “It”, etc. - You can use
[$name player]
or[$they player]
to refer to the name or pronoun of a given player object. Currently there is no easy way to get any player object other than the acting player, so this is not interesting. - Why not also accept
[$he]
,[$she]
,[$his]
, etc? First, it would be a lot of pronoun variants. Second, the male and female pronouns are ambiguous! Notice that “his” appears in two of the above lists. If you put[$his]
in your code, the system would not be able to figure out whether you meant[$their]
or[$theirs]
. “Her” also appears in two lists, but not the same lists. English is wacky.
- The pronouns are available in capital forms:
Formatting
[$em]emphasis[$/em]
- Emphasized text (italics).
[$fixed]fixed[$/fixed]
- Fixed-width text (monospace font).
[[style("dni")]].Sora[[endstyle("dni")]]
- D’ni font. Notice that this is handled with double square brackets and function calls, rather than a dollar-sign notation. Sorry about the ugliness.
- D’ni text must be encoded in ASCII (mostly) using the D'ni Font Encoding.
- These style tags may be nested. However, if you screw up the nesting or fail to close a tag, you'll see an error message when Seltani tries to print your text.
Conditional statements
[$if ...] Text [$end]
- Displays the text if the
$if
expression is true. Otherwise, displays nothing. A Python expression is considered false if it isNone
,False
, zero, the empty string, the empty list, or the empty dictionary. Anything else is considered true.
- A property-not-found error in an
$if
expression is also considered false.
[$if ...] A [$else] B [$end]
- If the expression is true, display
A
; otherwise, displayB
.
[$if ...] A [$elif ...] B [$else] C [$end]
- The same, with an if... else-if... else chain.
Functions and references
global (top-level) symbols
_
- The underscore always refers to the namespace of built-in functions, as described in this section. This can be useful if a property has shadowed one of these functions. For example, if you defined a location property named
text
, it would replace thetext()
function in that location. But you could still refer to_.text()
.
If you are silly enough to define a property called
_
, it will be ignored. The global_
cannot be replaced.
len(val)
- The length of a list, or the length of a string, or the number of entries in a dict.
min(list), max(list)
min(X, Y, Z), max(X, Y, Z)
- Return the smallest or greatest of a list or bunch of arguments.
int(), str(), bool(), dict(), list(), set()
- Standard Python type constructors.
text(str)
- Convert a Python string into a chunk of wiki-style text.
Square-bracket interpolations in the text are not performed immediately; they will be performed when the text is displayed.
code(str, args=None)
- Convert a Python string into a code object. The optional
args
specify parameters to be passed in to the code. - If the code object appears on a line by itself, it is executed immediately. In an expression, it is executed when written as a function call in the usual way (followed by arguments in parentheses).
ObjectId(obj)
- Find the database key for a player or location. If obj is not given, this generates a new unique database key (but does not store it in the database). If obj is a string with the correct form (a 24-character hex string), this generates a database key with that value.
isinstance(object, typ)
- Test whether the object is an instance of the given type.
locals()
- Return a Python dictionary that reflects the current set of local variables. (Not properties or builtins.) This dict is “live”; modifying it affects the locals in the environment.
style(str), endstyle(str)
- Begin or end a style span with a named style. Currently only supports three values:
"emph"
(same as[$em]
),"fixed"
(same as[$fixed]
), and"dni"
.
link(target, external=False), endlink(external=False)
- Begin or end a hyperlink span. (Note that
endlink()
does not need a target argument.) - The
target
must be a string, containing code or the name of a property. - If
external
isTrue
, thetarget
must be an http: URL.
style(), endstyle(), link(), endlink()
calls must occur in matched pairs, properly nested. If you do not arrange them correctly, error messages will appear in the displayed output.
parabreak()
- Print a paragraph break. This is equivalent to the
[$para]
interpolation in aText
property.
print(str)
- Print a string. A
print()
call in aCode
property is generally equivalent to putting plain text in aText
property. - You may include several arguments; they will be displayed with spaces between them.
- If the argument is
Text
, it will be interpolated according to the usual rules. For example,print(text("[$para]"))
generates a paragraph break.
event(you)
event(you, others)
- Display a message in the event pane of the acting player, and (optionally) other players in the same location.
If the message contains square-bracket tokens, remember to wrap it in
text()
.
event(you, others, player)
- Display a message in the the event pane of the given player, and (optionally) other players in the same location. The given player must be in the current instance.
eventloc(loc, str)
- Display a message to everybody in the given location. This may be given as a location reference (
locations.shortname
) or a short name string ("shortname"
). If you passrealm
as the first argument, the message will go to every player in the instance.
move(dest)
move(dest, you, oleave, oarrive)
move(dest, you, oleave, oarrive, player)
- Move a player to a location. This may be given as a location reference (
locations.shortname
) or a short name string ("shortname"
). The optional other arguments are event messages for the moving player, other players in the start room, and other players in the destination room. The final (optional) argument is a player reference; if not given, the acting player moves. (Must be a player in the same instance as the executing code.)
panic()
panic(you, others, player)
- Cause a player to panic-link out. The optional you and others arguments are event messages for the player and other players in the same room. The final (optional) argument is a player reference; if not given, the acting player moves. (Must be a player in the same instance as the executing code.)
player
- The acting player. This can be used to get or set player properties; e.g.,
player.foo
.
location()
- The acting player’s location.
location(objid)
- The location with the given database key (an ObjectId).
location("shortname")
- The location with the given short name.
location(player)
- The location of the given player.
locations.shortname
- The location with the given short name. Same as
location("shortname")
, but you don’t use the parentheses or quotes.
realm
- A reference which can be used to get or set realm-level (instance) properties; e.g.,
realm.foo
.
lastlocation
- The location (in this world) which the player was in before moving here. If the player arrived in this location by linking,
lastlocation
isNone
.
You might use
lastlocation
to display a description conditionally as “Halfway up the stairs” or “Halfway down the stairs.”
setfocus("prop")
- Set the current player’s focus to the given string. This must name a text or code property:
setfocus("sign")
, notsetfocus(sign)
.
setfocus("prop", player)
setfocus("prop", loc)
- Set a given player’s focus, or the focus of every player in a location. If the
loc
argument isrealm
, this sets the focus of every player in the current instance.
The focus property must be accessible in the player’s location. So if you use the
realm
form, you’ll have to make sure the property is available realm-wide.
unfocus()
- Clear the current player’s focus (if set).
unfocus("prop")
- Clear the current player’s focus, but only if it’s currently set to the given (named) property.
unfocus(None, player)
unfocus(None, loc)
- Clear the focus of the given player, or all players in a location, or all players in the instance.
unfocus("prop", player)
unfocus("prop", loc)
- Clear the focus of the given players, but only those whose focus is currently set to the given (named) property.
sched(delay, func, repeat=False, cancel=None)
- Schedule the given function to be called after a delay. The delay argument is the number of seconds, or a
datetime.timedelta
value. The func argument must be a function orCode
property. The delay must be at least 1 second, or at least 10 seconds if the timer is repeating. - If the (optional) repeat argument is
True
, the function will be called repeatedly, every N seconds, until the instance is abandoned. - If the (optional) cancel argument is given, the timer can be cancelled later by the
unsched()
function.
See the warning in “Timers” about scheduled code.
unsched(cancel=None)
- Cancel all upcoming events for this instance, if they were launched with the same cancel argument. If you call
unsched()
with no arguments, all upcoming events for the instance are cancelled.
access module
access.FOUNDER, access.OWNER, access.MEMBER, access.VISITOR, access.BANNED
- Access level constants. These are integers, so they can be compared with
>
and>=
.FOUNDER
is 4, from there values descend down to 0 forBANNED
.
access.level()
access.level(player)
- Return the access level of the acting or given player to the current instance. The current implementation says that a player has
FOUNDER
access to his personal instances, and to the global instance of a world he created. All other cases returnVISITOR
. - (Planned feature: a way to give your friends access to your personal scope.)
- (Planned feature: once group scopes are in, you will be able to give people various levels of access to the group.)
access.level(player, level)
- Returns True if the player’s access level to the current instance is at least
level
.
players module
players.player()
players.player(player)
- Returns the player object for the acting player, or the player with the given database key (an ObjectId). If the argument is a player object, this returns it unchanged.
players.name()
players.name(player)
- Returns the name of the acting player, or the given player, as a string.
players.pronoun()
players.pronoun(player)
- Returns the preferred pronoun of the acting player, or the given player. This will be one of the strings
"he", "she", "it", "they", "name"
.
players.location()
players.location(player)
- Same as
location()
.
players.builder()
players.builder(player)
- Return whether the player has Age-building permission. (This is False for new accounts until they go to the builder interface and request it. It is always False for guest accounts.)
players.isguest()
players.isguest(player)
- Return whether the player is an (anonymous) guest. Guest accounts cannot build, and are reset after each use.
players.ishere()
players.ishere(player)
- Returns
True
if the acting/given player is in this instance.
players.focus()
players.focus(player)
- Returns the focus of the acting/given player. This is normally a string (the name of a text property, if the player has it as a close-up window) or
None
(if the player has no close-up window). However, there are special cases where this will return a list. (When the focus is another player, a linking book, a bookshelf, etc.)
players.count(loc)
- Returns the number of players in the given location. If
loc
isrealm
, it’s the number of players in the entire instance.
players.list(loc)
- Returns a list of players in the given location. If
loc
isrealm
, it’s the players in the entire instance.
gentext module
gentext.gentext(str)
- Convert a Python string into a gentext data structure.
gentext.display(obj, cooked=None, seed=None)
- Display a symbol (text, gentext, or code) with different printing parameters. The
cooked
flag (True
orFalse
) controls auto-spacing and auto-capitalization. Theseed
parameter controls the pseudo-random behavior of generated text. For details, see Writing:The Ways of Printing.
gentext.Para(), gentext.Stop(), gentext.Semi(), gentext.Comma(), gentext.RunOn()
- Generate a break (or lack of break) in a cooked text stream.
gentext.A(), gentext.An()
- Generate the word "a" or "an" in a cooked text stream, whichever matches the next printed word. (You may use either
gentext.A()
orgentext.An()
-- they produce the same result.)
gentext.AForm(), gentext.AnForm()
- Resolve a pending
gentext.A()
orgentext.An()
, as if a following word started with a consonant (gentext.AForm()
) or vowel (gentext.AnForm()
).
pronoun module
pronoun.they(), pronoun.them(), pronoun.their(), pronoun.theirs(), pronoun.themself()
pronoun.we(), pronoun.us(), pronoun.our(), pronoun.ours(), pronoun.ourself()
- Returns the appropriate pronoun for the acting player. You may supply a player argument to specify a different player. All of these functions also exist in capitalized form.
pronoun.resolve(pronoun)
pronoun.resolve(pronoun, player)
- Returns the appropriate pronoun for the given or acting player. The
pronoun
argument must be one of the strings"We", "we", "Us", "us", "Our", "our", "Ours", "ours", "Ourself", "ourself"
. (The third-person forms don’t work here.)
random module
random.choice(list)
- A randomly-selected entry in the list.
random.randint(A, B)
- A random number from A to B, inclusive. (That is,
random.randint(4, 6)
will return either 4, 5, or 6, with equal probability.)
random.randrange(A)
- A random number from 0 to A-1.
random.randrange(A, B)
- A random number from A to B-1. (That is, the result will be at least A but always less than B.)
random.randrange(A, B, step)
- A random number which is at least A, less than B, and a multiple of step above A. (That is,
random.randrange(0, 10, 2)
will return 0, 2, 4, 6, or 8.)
datetime module
datetime.now
- The current time, as a
datetime.datetime
object. Always in UTC.
datetime.datetime(year, month, day, hour=0, minute=0, second=0, microsecond=0)
- Create an object representing a date and time. (This can be stored in the database.)
- A datetime object has these attributes:
year
,month
,day
,hour
,minute
,second
,microsecond
. - This differs from the Python datetime constructor in that the result is always timezone-aware and in UTC. If you try to pass in a
tzinfo
argument, it will be ignored.
datetime.timedelta(days=0, seconds=0, microseconds=0, milliseconds=0, minutes=0, hours=0, weeks=0)
- Create an object representing an interval of time. (Cannot be stored in the database. You may instead store
timedelta.total_seconds()
, which is a float.) - A timedelta object has these attributes:
days
,seconds
,microseconds
,total_seconds()
.
functools module
functools.partial(func, *args, **keywords)
- “Wraps up” a function with arguments, producing a new function.
- This may be helpful for timer events. For example, if
func
is a code property that takes one argument, then this code will schedule a timer event that callsfunc("foo")
:
sched(1, functools.partial(func, "foo"))
Hooks
The on_wake
property (from our example with timers) is one type of hook: a specially-named property that the server invokes in certain circumstances. There are several of these.
on_init
- (Realm property) Invoked exactly once when the instance is created, which is the first time a player ever links in. This is immediately followed by an
on_wake
call.
on_wake
- (Realm property) Invoked when the instance is awakened; that is, if the instance is asleep (or freshly created) and a player links in. The temporary variable
_slept
will be the timestamp that the instance was put to sleep, orNone
if the instance has never been awake before.
on_sleep
- (Realm property) Invoked when the instance has been uninhabited for ten minutes. After this call, all outstanding timers are cancelled.
- Warning: the
on_sleep
does not occur if the server crashes or is rebooted by the administrator. In these cases, the server restarts with all instances “asleep” and immediately callson_wake
for the inhabited ones. (The_slept
argument in this case will be the crash time.) So you should regard theon_sleep
hook as unreliable; you may see twoon_wake
calls in a row with noon_sleep
between them.
on_enter
- (Location property) Invoked when a player enters a room, either by moving or linking. The temporary variable
_from
will be the previous location (orNone
for linking);_to
will be the new location.
on_leave
- (Location property) Invoked when a player leaves a room, either by moving, linking, or panic-linking. The temporary variable
_from
will be the current location;_to
will be the new location (orNone
for linking).
Debugging commands
The in-game chat prompt offers a few helpful debugging commands. With the exception of /playstate
, these can only be used in worlds you created.
/playstate
- Displays the database keys (ObjectId) of your avatar, world, instance, scope, and location.
/move loc
- Teleport yourself to the location (in this instance) with the given short name.
/getprop prop
- Check for a property named
prop
in the current location. If found, display its value, and whether it was a world or instance property.
/getprop .prop
- Display the value of a realm property named
prop
(world or instance).
/getprop loc.prop
- Display the value of a location property named
prop
in the location namedloc
.
Note that this syntax does not match script code. In script code, you’d be writing
realm.prop
andlocations.loc.prop
.
/setprop prop value
/setprop .prop value
/setprop loc.prop value
- Set a property in the current location, realm, or the named location. This sets an instance property, like script code would, not the world property. (Again, world properties are defined solely by the world-building interface.)
- The value can be any simple Python literal:
None
,True
,False
, integers, quoted strings, lists, dictionaries. - To set a text property, you have to use the ugly spelled-out form:
{"type": "text", "text": "Foo."}
/delprop prop
/delprop .prop
/delprop loc.prop
- Delete an (instance) property in the current location, realm, or the named location. If there is a world property with the same name, this will allow it to shine through again.
/eval code
- Run the line of code in the current location, as if it were an action that you had clicked on.
So
/eval foo=1
is the same as/setprop foo 1
, really.
Local variables in an
/eval
(variables beginning with underscores, i.e.,_x
) live in a special environment which will persist as long as your connection is active. These locals will never spill over from your/eval
commands into running world code.
/bootinstance
- Kick everybody out of the current instance, including yourself. Then put the instance to sleep. The next time someone enters the instance, the
on_wake
hook will run. (See the “Hooks” section for more details.)