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, yis 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
memberaccess 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.2e18cannot be stored.) (Float values have a much wider range, but less precision.) - Python
datetimeobjects must be entered with theDateTimeproperty type, not withValue. - Python
ObjectIdobjects 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, aTextvalue “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
propproperty. 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.Valueproperties 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.
baras 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
interpolationsymbol 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
symbolas 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
$ifexpression 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
$ifexpression 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
argsspecify 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
targetmust be a string, containing code or the name of a property. - If
externalisTrue, thetargetmust 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 aTextproperty.
print(str)- Print a string. A
print()call in aCodeproperty is generally equivalent to putting plain text in aTextproperty. - 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 passrealmas 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,
lastlocationisNone.
You might use
lastlocationto 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
locargument 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
realmform, 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.timedeltavalue. The func argument must be a function orCodeproperty. 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>=.FOUNDERis 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
FOUNDERaccess 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
Trueif 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
locisrealm, it’s the number of players in the entire instance.
players.list(loc)- Returns a list of players in the given location. If
locisrealm, 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
cookedflag (TrueorFalse) controls auto-spacing and auto-capitalization. Theseedparameter 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
pronounargument 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.datetimeobject. 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
tzinfoargument, 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
funcis 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_wakecall.
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
_sleptwill be the timestamp that the instance was put to sleep, orNoneif 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_sleepdoes 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_wakefor the inhabited ones. (The_sleptargument in this case will be the crash time.) So you should regard theon_sleephook as unreliable; you may see twoon_wakecalls in a row with noon_sleepbetween them.
on_enter- (Location property) Invoked when a player enters a room, either by moving or linking. The temporary variable
_fromwill be the previous location (orNonefor linking);_towill 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
_fromwill be the current location;_towill be the new location (orNonefor 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
propin 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
propin the location namedloc.
Note that this syntax does not match script code. In script code, you’d be writing
realm.propandlocations.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=1is 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/evalcommands 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_wakehook will run. (See the “Hooks” section for more details.)