18 KiB
Generic
-
Macro names are case insensitive
-
There's a hidden input called
loopobject
, calledloop_item
in scraps because it's not necessarily an object: it can be a room, exit, object or character. -
A second hidden input is called
newvalue
, an optional string. If it is a single space, it is treated as an empty string. This is only used by some of the colon macros. -
Replacement is done right-to-left (probably because of
[a/an]
) -
Replacement is repeated if the leftmost macro with a colon in it has a valid name (i.e. starts with
[V:
,[JSA:
,[RP:
,[IP:
,[PP:
,[CP:
,[VP:
,[TP:
,[IA:
,[TA:
,[CA:
,[RA:
,[PA:
).So for example, with a player name
<[playername][v:]>
, the following results in an infinite loop:[playername][v:]
The following ones does not result in an infinite loop:
[a:b][playername][v:]
(expands to[a:b]<[playername][v:]>
)[playername]
(expands to<[playername][v:]>
)
-
If the replaced text forms a valid macro with the text before it, it is replaced. So with playername
name]
,[player[playername]
is expanded toname]
. -
This is also buggy a bit, since macro names without colons are checked with contains instead of ==, but then a fixed number of characters are removed. As a consequence, with playername
[playername]
,[[[[[playername]
expands to[playername]]]]]
. But macros with colon work differently, with a variabletex
set to[v:tex]
,[[[[v:tex]
expands to[[[[v:tex]
. (If you somehow solve the problem of Rags Designer freezing when you set that variable...) -
Some actions call the replacement function multiple times, so they will repeat the replacement even without a colon macro, but without a
loop_item
. -
When adding text to the log, the replacement function is called (without
loop_item
) until the output changes. So with playername[playername]
,[playername]
is expanded to[playername]
, but if the playername is[playername]x
, it's infinite loop. -
Rags author, I hope you fucking die.
Replacements
-
[V:
var]
:var
orvar(0)
orvar(0)(0)
, but indices are substituted again. (Note: this means that due to macros being replaced from right-to-left, indices are essentially expanded twice. So for example having a player name[v:foo]
and a variablefoo
set to some valid index inbar
,[v:bar([playername])]
will work correctly, even though normally[playername]
would be just replaced with[v:foo]
.) Num and string works the same way. Non existing var: empty replacement. In case of date variable, a date format can be specified after a colon:[v:dat:yyyy]
, default if not specified:dddd, MMMM, dd yyyy hh:mm:ss tt
. Invalid format exceptions are not caught. See short (archive) and long (archive) format strings.Some undocumented features of .NET: escape works inside quotes, unmatched quotes or an ending a format string with an escape character results in an exception.
%
only works when it is the first character, and whatever follows it will be treated as a single character, exception otherwise. (A single%
is also invalid,%dd
is interpreted asd''d
.)inval1st: the first index is invalid, second doesn't care
inval2nd: first index is valid, second is not (or 1D array)
var type 0idx 1idx val 1idx inval 2idx val 2idx inval1st 2idx inval2nd num val N/A ""
N/A ""
N/A num ary 1D ""
value ""
N/A ""
"<invalid variable reference>"
num ary 2D ""
"System.Collections.ArrayList"
""
value ""
"<invalid variable reference>"
dt val N/A ""
N/A ""
N/A dt ary 1D ""
value ""
N/A ""
exception dt ary 2D ""
exception ""
valid ""
exception Here exception means that the replacing function throws an exception, in most cases this means Rags player pops up that usual .net uncaught exception window, but they're caugh in some cases (for example, with actions). Scraps duplicates the behaviour of num/str arrays instead of throwing.
Invalid array handling: 1D invalid parentheses:
[v:foo(]
=>foo(]
. 2D is more complicated, if the variable doesn't exists:[v:foo(0)(]
=>foo(0)(]
, but if it exists it's replaced to value with]
appended. If you have an array namedasd)
,[v:asd)(0)]
results inasd)(0)]
. The second(
is not checked,[v:asd(0)(0)]
and[v:asd(0)x0)]
is the same. Extra characters after the)
are not handled, so[v:foo(0)xyz]
or[v:foo(0)(0)xyz]
with valuefoo
will be replaced with valuefooyz]
. A negative index is treated the same way as an invalid index.Whitespace handling: spaces after
[v:
are allowed and before the first(
(or]
when there is no array indexing), but not around the:
separating the variable name and date format. It's also allowed inside the parentheses but not outside (so[v:foo( 0 )( 0 )]
is ok,[v:foo(0) (0)]
is not.newval
handling: the macro expands to nothing. In case of<invalid variable reference>
it doesn't do anything, exceptions are propagated and variable not set. In case of a 2D array it just sets the value to the string (which can cause parse errors later, i.e. fuckup), with 1D array: invalid number throws an exception, invalid dt: store the"bad value"
string as a DateTime value (major fuckup?). With single values, invalid numbers are replaced with -1, invalid DateTimes are replaced with the current time. -
[JSA:
varname]
: "export" to JS array. Non array vars expand to empty string. 1D array =>[1,2,3];
(yes, with a fucking semicolon at the end), 2D =>[[1,2],[3,4]];
. Strings are double quoted (["ab","cd"];
), quotes are escaped (a"b
=>["a\"b"];
), carriage returns/newlines are replaced with\r
and\n
but other characters are not (so\
remains\
). Dates are exported as strings,month/day/year hour:minute:second PM
in 1D array, whatever string representation they're stored in in 2D case...Whitespace handling: spaces around varname are trimmed.
newvalue
is ignored. -
[RP:
name:
propname]
: Room Property. If room name contains a(
, that character and everything after is stripped away and the remaining is an UUID. Otherwise it's a room name. Second name is the custom property name. If the macro has a third:
, it an everything after it is ignored. Non-existing room/property => empty string.newvalue
is handled if the property is found.Whitespace handling: spaces around name and propname are allowed.
-
[IP:
name:
propname]
: object (Item) Property. Works asRP
. -
[PP:
propname]
: Get property from player. Empty if missing.:
is not special in this case, it's treated as a part of propname. -
[CP:
name:
propname]
: Character Property. Same asRP
except no UUID handling. -
[VP:
name:
propname]
: Variable Property. Works asCP
. -
[TP:
name:
propname]
: Timer Property. Works asCP
. -
[IA:
name:
attrname]
: object (Item) Attribute. Name is an UUID, failing that a name. An extra:
and everything after is ignored. Attr can be:attrname value newvalue
NAME object name (override ignored!) set NAMEOVERRIDE name override set CLOTHINGLAYERS [["name","level"], ...]
ignored ID UUID ignored PREPOSITION preposition set DESCRIPTION description set IMPORTANT True/False ToBoolean CARRYABLE True/False ToBoolean WEARABLE True/False ToBoolean WORN True/False ToBoolean CONTAINER True/False ToBoolean OPENABLE True/False ToBoolean OPEN True/False ToBoolean LOCKABLE True/False ToBoolean LOCKED True/False ToBoolean VISIBLE True/False ToBoolean ENTERABLE True/False ToBoolean READABLE True/False ToBoolean WEIGHT object weight (double) ToDouble ACTION Special, see below buggy ToBoolean: after whitespace trimming, it must be case-insensitively
true
orfalse
, otherwise it throws an exception.Conversion errors are catched and have no effect.
Whitespace handling: spaces around name allowed, but not around attrname.
-
[TA:
name:
attrname]
: Timer Attribute. Attr can be:attrname value newvalue
ACTIVE True/False ToBoolean NAME timer name set TIMERTYPE TT_RUNALWAYS/TT_LENGTH enum parse LENGTH integer length ToInt32 TURNNUMBER integer turn ToInt32 TIMERSECONDS integer seconds ToInt32 LIVETIMER True/False ToBool ACTION Special, see below buggy Note that setting LIVETIMER won't start/stop existing background thread! So setting a normal timer to live timer effectively disables it, while setting a live timer to a normal means that it will continue to be a live timer, but also a normal timer that is executed normally after actions. But after saving and loading the game, the threads are recreated normally.
-
[CA:
name:
attrname]
: Character Attribute. Attr can be:attrname value newvalue
NAME char name (override ignored!) set OVERRIDENAME name override set GENDER Male/Female/Other enum parse CURRENTROOM current room's UUID set (no check) ALLOWINVINTERACTION True/False ToBoolean ACTION Special, see below buggy -
[RA:
name:
attrname]
: Room Attribute. Name is an UUID, failing that a name. Attr can be:attrname value newvalue
NAME room name (override ignored!) set DESCRIPTION room description set SDESC name override set ROOMPIC picture filename or None
set (no check) ENTEREDFIRSTTIME True/False ToBoolean LEFTFIRSTTIME True/False ToBoolean ID UUID ignored ACTION Special, see below buggy EXIT Special, see below [RA:
name:EXIT:
dir:
attrname]
: dir isNorth
,SouthEast
, etc. dir is case sensitive! Spaces around dir are allowed. Invalid dir or not specifying dir at all (e.g.[ra:foo:exit]
) results in an empty string, but specifying dir and not specifying attrname results in an exception...exit attrname value newvalue
ACTIVE True/False ToBoolean DESTINATIONID destination room UUID or empty set (no check) DESTINATIONNAME destination room name (override ignored!) or empty set (if exist) PORTAL portal object's UUID or <None>
set (no check) -
[PA:
attrname]
: Player Attribute. Attr can be:attrname value newvalue
NAME player name set GENDER Male/Female/Other enum parse CURROOM current room's UUID or <Null>
set (no check) CURPORTRAIT player image or empty set (no check) ACTION Special, see below buggy -
[PLAYERNAME]
: Player's NameOverride -
[INPUTDATA]
: aka AdditionalData aka last selected shit -
[MAXCARRY]
: Player's WeightLimit -
[TURNS]
: TurnCount -
[CURRENTCARRY]
: sum of weight in Player's inventory -
[MAN/WOMAN]
: Player's gender: man, woman, thing -
[MALE/FEMALE]
: Player's gender: male, female, other -
[BOY/GIRL]
: Player's gender: boy, girl, thing -
[LEN(
varname)]
: String var: string len, array var: number of rows. Only works at the beginning of the replacement string! If there are any characters before the[LEN(
part, it breaks.Error behavior: if variable is a number of datetime (and not an array), expands to empty. If the variable doesn't exists, five characters after the
(
are removed, e.g.[len(nosuch)]
=>[len(h)]
. If there are less than 5 characters after the(
, Rags throws an exception. If the closing)
is missing, Rags removes the[len(
part.[len(
not at the beginning at the string: see the source for exact details, but unless you do that multiple eval trick with[[
, Rags will assume that[len(
is at the beginning of the full string, and the variable name will be taken from the 5th character until the(
. So for example, if you have an array variable calledlen
with length 3,....[len(foo)]>a
will be replaced with3>a
(if you have one less extra character after the macro, Rags throws an exception). -
[A/AN]
: expands toan
if the text following[A/AN]
after expansion (skipping any whitespace characters) starts with any ofaiueo
,a
if something else, nothing if there's no text after it.
These operate on loop_item
if it is a room, player's room otherwise
(loop_item
is unset or it is not a room).
[ROOM.NAME]
: room's name (override ignored!)[ROOM.ID]
: room's UUID
These operate on loop_item
if it is a room exit, expand to nothing otherwise.
[EXIT.ACTIVE]
: Y/N[EXIT.DIRECTION]
: North, South, NorthEast, etc[EXIT.DESTNAME]
: destination room (name override || name) if it exists, empty otherwise[EXIT.DESTID]
: destination room's UUID if it exists, empty otherwise
These operate on loop_item
if it is an object, expand to nothing otherwise.
[ITEM.NAME]
: object's name (override ignored!)[ITEM.ID]
: object's UUID
These operate on loop_item
if it is a character, expand to nothing otherwise.
[CHAR.NAME]
: character's name (override ignored!)
Action attributes
Various [.A:.*]
can take ACTION
as an attrname. For example:
[CA:
name :ACTION:
actname :
attrname ]
: actname is an action name,
attrname can be:
| attrname | value | newvalue
|
|--------------|---------------------------------------------------------------|---------------=|
| ACTIVE | True/False | ToBoolean |
| OVERRIDENAME | override name | set |
| ACTIONPARENT | action's parent name or None
| set (no check) |
| INPUTTYPE | None/Object/Character/ObjectOrCharacter/Text/Custom/Inventory | enum parse |
Not specifying enough colons result in an exception.
newvalue
: because Rags author lacked brain cells, an empty (and as an
extension, originally just a single space) newvalues
are treated as if it
weren't specified.
Rich text
Note: where you see a comma separated list, you can always pass more elements, extra elements are ignored.
[c
num,
num,
num]
...[/c]
: change color to RGB[c
string]
...[/c]
: change to named color[f
string [,
double ]]
...[/f]
: change to font, optionally size.[b]
...[/b]
: bold[i]
...[/i]
: italic[u]
...[/u]
: underline[Middle]
...[/Middle]
: centered
Stripping formatting macros
Sometimes formatting macros are stripped from the text. The algorithm is the following (string comparisons are case insensitive):
-
Find
[f
. If found, find the next]
. If there is no]
and[f
is at the beginning of the string, infinite loop. If there is no]
and[f
is not at the beginning of the string, throw an exception. Otherwise remove[f
]
and everything between.If there is a
[/f]
after this, remove it too.Repeat 1. while there are any
[f
in the string. -
Do the same with
[c
]
and[/c]
. -
Remove any instance of
[middle]
,[/middle]
,[i]
,[/i]
,[b]
,[/b]
,[u]
,[/u]
. Unlike in step 1-2, the end tags don't have to follow an open tag.
Order matters! [[i]b]
after stripping is an empty string, while [[b]i]
is
[i]
.