You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
309 lines
18 KiB
Markdown
309 lines
18 KiB
Markdown
# Generic
|
|
* Macro names are case insensitive
|
|
* There's a hidden input called `loopobject`, called `loop_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 to
|
|
`name]`.
|
|
* 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 variable
|
|
`tex` 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 {#replacement}
|
|
* `[V:` var `]`: `var` or `var(0)` or `var(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 variable `foo` set to some valid index in `bar`,
|
|
`[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](https://docs.microsoft.com/en-us/dotnet/standard/base-types/standard-date-and-time-format-strings)
|
|
[(archive)](https://archive.md/jnRFV) and
|
|
[long](https://docs.microsoft.com/en-us/dotnet/standard/base-types/custom-date-and-time-format-strings)
|
|
[(archive)](https://archive.md/s9yIZ) 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 as `d''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 named `asd)`, `[v:asd)(0)]` results in `asd)(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
|
|
value `foo` will be replaced with value `fooyz]`. 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 as `RP`.
|
|
* `[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 as `RP` except no UUID
|
|
handling.
|
|
* `[VP:` name `:` propname `]`: Variable Property. Works as `CP`.
|
|
* `[TP:` name `:` propname `]`: Timer Property. Works as `CP`.
|
|
* `[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` or
|
|
`false`, 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 is `North`, `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 called `len` with length 3, `....[len(foo)]>a` will be replaced
|
|
with `3>a` (if you have one less extra character after the macro, Rags
|
|
throws an exception).
|
|
* `[A/AN]`: expands to `an` if the text following `[A/AN]` after expansion
|
|
(skipping any whitespace characters) starts with any of `aiueo`, `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 {#strip-format}
|
|
Sometimes formatting macros are stripped from the text. The algorithm is the
|
|
following (string comparisons are case insensitive):
|
|
1. 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.
|
|
2. Do the same with `[c` `]` and `[/c]`.
|
|
3. 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]`.
|