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.
2404 lines
104 KiB
Markdown
2404 lines
104 KiB
Markdown
# XML syntax
|
|
Sample:
|
|
|
|
```xml
|
|
<Action>
|
|
<Name><![CDATA[Examine]]></Name>
|
|
<OverrideName><![CDATA[]]></OverrideName>
|
|
<actionparent><![CDATA[None]]></actionparent>
|
|
<Active><![CDATA[True]]></Active>
|
|
<FailOnFirst><![CDATA[True]]></FailOnFirst>
|
|
<InputType><![CDATA[None]]></InputType>
|
|
<CustomChoiceTitle><![CDATA[]]></CustomChoiceTitle>
|
|
<EnhancedInputData>
|
|
<BackgroundColor><![CDATA[-1929379841]]></BackgroundColor>
|
|
<TextColor><![CDATA[-16777216]]></TextColor>
|
|
<Imagename><![CDATA[]]></Imagename>
|
|
<UseEnhancedGraphics><![CDATA[True]]></UseEnhancedGraphics>
|
|
<AllowCancel><![CDATA[True]]></AllowCancel>
|
|
<NewImage><![CDATA[]]></NewImage>
|
|
<TextFont><![CDATA[Microsoft Sans Serif, 12pt]]></TextFont>
|
|
</EnhancedInputData>
|
|
<PassCommands>
|
|
<Command>
|
|
<CmdType><![CDATA[CT_DISPLAYPICTURE]]></CmdType>
|
|
<CommandText><![CDATA[]]></CommandText>
|
|
<Part2><![CDATA[Toybox.jpg]]></Part2>
|
|
<Part3><![CDATA[]]></Part3>
|
|
<Part4><![CDATA[]]></Part4>
|
|
<EnhancedInputData>
|
|
<BackgroundColor><![CDATA[-1929379841]]></BackgroundColor>
|
|
<TextColor><![CDATA[-16777216]]></TextColor>
|
|
<Imagename><![CDATA[]]></Imagename>
|
|
<UseEnhancedGraphics><![CDATA[True]]></UseEnhancedGraphics>
|
|
<AllowCancel><![CDATA[True]]></AllowCancel>
|
|
<NewImage><![CDATA[]]></NewImage>
|
|
<TextFont><![CDATA[Microsoft Sans Serif, 12pt]]></TextFont>
|
|
</EnhancedInputData>
|
|
</Command>
|
|
</PassCommands>
|
|
</Action>
|
|
```
|
|
|
|
## Action
|
|
* `Name`: `string`
|
|
* `OverrideName`: `string`, default `""`
|
|
* `actionparent`: `string`, default `"None"`
|
|
* `Active`: `bool` (`True` / `False`)
|
|
* `FailOnFirst`: `bool`, default `True`
|
|
* `InputType`: `ActionInputType` (`None`, `Object`, `Character`,
|
|
`ObjectOrCharacter`, `Text`, `Custom`, `Inventory`)
|
|
* `CustomChoiceTitle`: `string`, default `""`
|
|
* `CustomChoices`: `CustomChoice[]`, only if array not empty
|
|
* `EnhancedInputData`: `EnhancedInputData`
|
|
* `Conditions`: `Condition[]`, only if array not empty
|
|
* `PassCommands`: `variant<Command, Condition>[]`, only if array not empty
|
|
* `FailCommands`: `variant<Command, Condition>[]`, only if array not empty
|
|
|
|
## CustomChoice
|
|
* `Name`: `string`
|
|
|
|
## EnhancedInputData
|
|
* `BackgroundColor`: `color`: `color.ToArgb() == 0xaarrggbb` reinterpret_casted
|
|
to `int32_t`, default `rgba(255, 255, 255, 140)`
|
|
* `TextColor`: `color`, default `rgba(0, 0, 0, 255)`
|
|
* `Imagename`: `string`, default `""`. Ignored?
|
|
* `UseEnhancedGraphics`: `bool`, default true. Called `Use Overlay Graphics` in
|
|
GUI. When true, replace image + choices overlaid, when false, `NewImage`
|
|
ignored and popup window with normal winforms table and ok/cancel button (even
|
|
when `AllowCancel` is false).
|
|
* `AllowCancel`: `bool`, default true
|
|
* `NewImage`: `string`, default `""`
|
|
* `TextFont`: `font`, default `Times New Roman Bold, 12pt`. Ignored/buggy?
|
|
|
|
## Condition
|
|
* `Name`: `string`, default `""`
|
|
* `Checks`: `Check[]`, only if array not empty
|
|
* `PassCommands`: only if array not empty
|
|
* `FailCommands`: only if array not empty
|
|
|
|
## Check
|
|
* `CondType`: `ConditionType`, default `CT_Item_Held_By_Player`
|
|
* `CkType`: `CheckType` (`CT_Uninitialized`, `And`, `Or`)
|
|
* `Step2`: `string`, default `""`
|
|
* `Step3`: `string`, default `""`
|
|
* `Step4`: `string`, default `""`
|
|
|
|
## Command
|
|
* `CmdType`: `CommandType`
|
|
* `CommandText`: `string`, default `""`
|
|
* `Part2`: `string`, default `""`
|
|
* `Part3`: `string`, default `""`
|
|
* `Part4`: `string`, default `""`
|
|
* `CustomChoices`: `CustomChoice[]`, only if not empty.
|
|
* `EnhancedInputData`: `EnhancedInputData`.
|
|
|
|
# Action
|
|
* `ActionParent`: used to generate submenus in right-click menu (yet another
|
|
ad-hoc grouping). If parent is inactive, action is inactive too.
|
|
* `FailOnFirst`: pseudocode, `c.Check()` runs PassCommands for each iteration
|
|
when it is a loop (yes, when `FailOnFirst` is false, `PassCommands` is
|
|
executed one more time)
|
|
```c++
|
|
bool success = FailOnFirst || Conditions.empty();
|
|
for (c : Conditions)
|
|
{
|
|
if (c.Check()) // check succeeded or it was a loop
|
|
{
|
|
if (!FailOnFirst) success = true;
|
|
if (!FailOnFirst || !c.loop) c.PassCommands.Run();
|
|
}
|
|
else
|
|
{
|
|
c.FailCommands.Run();
|
|
if (FailOnFirst) { success = false; break; }
|
|
}
|
|
}
|
|
(success ? PassCommands : FailCommands).Run();
|
|
```
|
|
* `PassCommands`, `FailCommands`: one of them is executed based on the
|
|
conditions' result, see above for exact semantics, but generally, with
|
|
`FailOnFirst` it means all checks passed (so `and` with short-circuit), and
|
|
without `FailOnFirst` it means at least one check passed (so `or` without
|
|
short-circuit).
|
|
* `EnhancedData`: only used when `InputType != None && InputType != Text &&
|
|
UseEnhancedGraphics && !HideMainPicDisplay`
|
|
* `InputType`: ask a question at the beginning of the action if not None.
|
|
* `Object`: select an object currently visible in the player GUI. In practice,
|
|
this means any object in the inventory, any object in the current room
|
|
(including portals), any subobject of any of them; or any object held by a
|
|
character in the current room with allow inventory interactions. (Subobjects
|
|
inside characters don't appear but subobjects inside subobjects do, albeit
|
|
buggy! Just what did you expect?) List items: object DisplayNames, no tag
|
|
when `!UseEnhancedGraphics`. `AdditionalData` value: object's name (override
|
|
ignored).
|
|
* `Character`: select a character in the current room. List object: character
|
|
DisplayName with tag. `AdditionalData` value: character's name (override
|
|
ignored).
|
|
* `ObjectOrCharacter`: union of the previous two, except characters lack tag
|
|
with `UseEnhancedGraphics`...
|
|
* `Text`: input is not a selection from a list, but a free form text.
|
|
`EnhancedData` is ignored in this case.
|
|
* `Custom`: `CustomChoices` contains a list of choices. When not using overlay
|
|
graphics, the color of the text can be changed with `[c r,g,b]...[/c]`
|
|
(except the actual ranges are ignored, `foo[c 0,255,0]bar` sets the full
|
|
text to green, in case of multiple `[c]` tags, the last one wins. When using
|
|
overlay graphics, these tags are displayed as-is, without any processing.
|
|
Did you expect any logic behind this?)
|
|
* `Inventory`: objects in the player's inventory. No tag when
|
|
`!UseEnhancedGraphics`.
|
|
* Note that this doesn't nest properly. Executing an action inside an action
|
|
means that after returning to the parent action, the selection is lost.
|
|
* `action_object`: a hidden parameter. This is set to the object when executing
|
|
an action on an object, null otherwise (this is nesting properly).
|
|
* `player_moving`: another hidden parameter, only available in `<<On Player
|
|
Leave First Time>>` and `<<On Player Leave>>` actions, when triggered by a the
|
|
player (the 3DPD) trying to leave the current room. It is set to invalid in
|
|
other cases.
|
|
* Execution:
|
|
1. Clear `AdditionalData`
|
|
2. When there is an `EhancedData` with an image, `ShowMainImage` and
|
|
`OverlayGraphics` is true, and `InputType` is not `None` or `Text`, set the
|
|
image to that.
|
|
3. When `InputType` is not `None`, ask the input. If canceled, return (action
|
|
result is false). Otherwise get the `AdditionalData` value to set, then
|
|
print it, unless it is an uuid and there is an object with that uuid,
|
|
because in that case it prints that object's name.
|
|
4. Execute conditions
|
|
5. Execute pass/fail commands
|
|
|
|
# Command
|
|
* `CustomChoices`: can be set on `CT_SETVARIABLEBYINPUT`
|
|
* `EnhancedData`: can be set on `CT_SETVARIABLEBYINPUT`
|
|
* Exception handling: exceptions are caught when executing commands. Rags
|
|
displays a message, then continues with the next command.
|
|
|
|
## Generic command info
|
|
* `Part2`, `Part3`, `Part4` and `Text` values are always run through the [text
|
|
replacement function][] before usage.
|
|
* Object/room UUID or name: this generally means rags first tries to find a
|
|
room/object with the given UUID, and if there's no one, it tries to find one
|
|
with the name. In this case everything is processed as strings, so if you end
|
|
up with an object whose UUID is in fact not a valid UUID, it will still find
|
|
it. On the other hand, this requires exact match, i.e. 8-4-4-4-12 format
|
|
without white spaces. However, there are a few cases when Rags actually tries
|
|
to parse the given string as a UUID and somehow work differently depending on
|
|
the outcome, but they're clearly marked as "room UUID (**can be parsed**) or
|
|
name". In this case you can ue other formats, see [allowed GUID formats][guid]
|
|
[(archive)][guid_archive] for details. (And undocumented details: except the
|
|
last format, spaces are not allowed, but the string is trimmed before use, so
|
|
`" {123..."` is valid, but `"{ 123..."` is not).
|
|
* Aborts the command list: subsequent items in the currently executing
|
|
`PassCommands`/`FailCommands` will not run, but it does not affect commands
|
|
above. So for example,
|
|
```
|
|
Action
|
|
\-PassCommands
|
|
. |-Condition
|
|
. | |-PassCommands
|
|
. | | |-Command cmd0
|
|
. | | |-Command cmd1
|
|
. | | \-Command cmd2
|
|
. | \-FailCommands
|
|
. | . \-Command cmd3
|
|
. |-Command cmd4
|
|
. \-Command cmd5
|
|
```
|
|
If `cmd1` aborts, `cmd2` won't be executed (and neither `cmd3`), but instead
|
|
it will continue with `cmd4` and `cmd5`. This means that a `CT_LOOP_BREAK` not
|
|
directly in the loop's `PassCommands` can act weird.
|
|
|
|
[guid]: https://docs.microsoft.com/en-us/dotnet/api/system.guid.-ctor?view=net-5.0#System_Guid__ctor_System_String_
|
|
[guid_archive]: https://archive.md/wtYUh
|
|
|
|
### Set custom property commands {#set-custom-property}
|
|
* `Part2`: `name:property_name`
|
|
* `Part3`: `Equals` / `Add` / `Subtract` / `Multiply` / `Divide` (**case
|
|
sensitive**)
|
|
* `Part4`: value (**double replaced**)
|
|
* `Text`: ignored
|
|
|
|
The exact interpretation of `Part2` varies, but generally if it doesn't have
|
|
exactly one colon, or if the entity doesn't exists, it doesn't do anything. If
|
|
the entity doesn't have a property with name `property_name` (**case
|
|
sensitively**), it also doesn't do anything.
|
|
|
|
`Part4` is double evaluated, then in case of `*_JS` commands, it is evaluated as
|
|
a JavaScript code (whatever dialect Microsoft's JScript supports), unless it is
|
|
an empty string anfter trimming. In this case, it is replaced with `-1`. If the
|
|
return value is `null`, it is replaced with `"Null value returned from
|
|
evaluate."` string, otherwise it is converted to a string, using whatever rules
|
|
this [this shit][jscript] [(archive)][jscript_archive] uses.
|
|
|
|
If `Part3` is not one of the allowed values, it doesn't do anything. If `Part3`
|
|
is `Equals`, set the property's value to `Part4`. Otherwise it tries to
|
|
interpret both the property's current value and `Part4` as a double and do the
|
|
arithmetic operation. If one of the values are not a number, it doesn't do
|
|
anything, except that with `Subtract` if `Part4` is not a double, it **throws an
|
|
exception**.
|
|
|
|
[jscript]: https://docs.microsoft.com/en-us/dotnet/api/microsoft.jscript.eval.jscriptevaluate?view=netframework-4.8
|
|
[jscript_archive]: https://archive.md/YhYP6
|
|
|
|
### Room enter procedure {#room-enter-procedure}
|
|
This is used by multiple commands. Action and timer executions are skipped in
|
|
some cases.
|
|
|
|
* Prints an empty line to the log.
|
|
* Sets room & main image (inline or to the main image area, handling layered
|
|
images) to the room's image (removes it if the room doesn't have one).
|
|
* When not skipping actions: when the room's `EnterFirstTime` is false, set it
|
|
to true and execute inner procedure with `<<On Player Enter First Time>>`.
|
|
Afterwards, execute inner procedure with `<<On Player Enter>>`.
|
|
* If the actions changed the player's room, don't do anything else.
|
|
* Prints the player's room description.
|
|
* If notifications are enabled:
|
|
* If the room has visible objects, it prints `"You can see "`, for each
|
|
visible object preposition + `" "` + display name (if preposition after
|
|
trimming is empty, preposition + space is skipped), separated by `", "`, all
|
|
on one line.
|
|
* For each character in the room, it prints display name + `" is here."`
|
|
* When not skipping timers: execute [multi timer
|
|
procedure](general.md#timer-multi).
|
|
|
|
#### Inner procedure
|
|
* There's a try-catch around the whole stuff, silently discarding any error
|
|
inside (but action execution already contains a try-catch inside, so nothing
|
|
should throw in this shit).
|
|
* First save the player's current room (original room)
|
|
* If the player's room has the specified action, execute it without
|
|
`action_object`.
|
|
* If the player has the specified action, execute it without `action_object`.
|
|
* Go through all objects in the player's current room.
|
|
* If the object's `EnterFirstTime` flag is false, set it to true and execute
|
|
its `<<On Player Enter First Time>>` action if it exists with object as
|
|
`action_object`.
|
|
* When the inner procedure is called with `<<On Player Enter>>` and the object
|
|
has an action with that name, and the player is still in the original room,
|
|
execute it with object as `action_object`.
|
|
* If the object is a `Container` and it is `Open` or not `Openable`, go
|
|
through all subobjects and do the previous two points for these subobjects.
|
|
Note that this operation is not recursive, so subobjects of the subobjects
|
|
are not considered.
|
|
* Go through all characters in the player's current room.
|
|
* If the character's `EnterFirstTime` flag is false, set it to true and
|
|
execute its `<<On Player Enter First Time>>` action if it exists without
|
|
`action_object`.
|
|
* When the inner procedure is called with `<<On Player Enter>>` and the
|
|
character has an action with that name, and the player is still in the
|
|
original room, execute it without `action_object`.
|
|
|
|
This means that for example if the player in entering the room for the first
|
|
time, object/character enter first time events are executed before the room's
|
|
``<<On Player Enter>>`, but after if the player is entering a second time...
|
|
|
|
## Available CommandTypes
|
|
### CT_UNINITIALIZED
|
|
### CT_ACTION_ADD_CUSTOMCHOICE {#CT_ACTION_ADD_CUSTOMCHOICE}
|
|
* `Part2`: `type:name:action_name`
|
|
* `Part3`: ignored
|
|
* `Part4`: ignored
|
|
* `Text`: choice to add (**case sensitive**)
|
|
* FIXUP: none
|
|
|
|
If `Part2` doesn't contain a colon, this action doesn't do anything. If it only
|
|
contains one colon, it is parsed as `type:action_name` and name is treated as
|
|
empty. A third colon and everything after it is ignored.
|
|
|
|
`type` is **case sensitively** one of the following:
|
|
* `Chr`: `name` is a character name (case insensitive). If the character does
|
|
not exists, it **throws an exception**.
|
|
* `Obj`: `name` is an object UUID or name (case insensitive). If the object does
|
|
not exist, it doesn't do anything.
|
|
* `Player`: `name` is ignored.
|
|
* `Room`: `name` is a room UUID (**can be parsed**) or name (case insensitive).
|
|
If the room doesn't exist, it doesn't do anything.
|
|
* `Timer`: `name` is a timer (case insensitive). If the timer doesn't exist, it
|
|
doesn't do anything.
|
|
* Anything else: it doesn't do anything.
|
|
|
|
`action_name` names an action inside the specified entity (case insensitive). If
|
|
it doesn't exists, this action doesn't do anything. If the action already has a
|
|
custom choice named `Text`, it doesn't do anything. Otherwise it adds `Text` to
|
|
the end of the custom choices.
|
|
|
|
### CT_ACTION_CLEAR_CUSTOMCHOICE
|
|
* `Part2`: `type:name:action_name`
|
|
* `Part3`: ignored
|
|
* `Part4`: ignored
|
|
* `Text`: ignored
|
|
* FIXUP: none
|
|
|
|
See [CT_ACTION_ADD_CUSTOMCHOICE](#CT_ACTION_ADD_CUSTOMCHOICE) for `Part2`
|
|
handling. If it specifies a valid action, this action removes all custom choices
|
|
from it.
|
|
|
|
### CT_ACTION_REMOVE_CUSTOMCHOICE
|
|
Same as [CT_ACTION_ADD_CUSTOMCHOICE](#CT_ACTION_ADD_CUSTOMCHOICE), except
|
|
this action removes `Text` from the custom choices, if the custom choice exists.
|
|
|
|
### CT_DISPLAYCHARDESC
|
|
* `Part2`: character name (case insensitive)
|
|
* `Part3`: ignored
|
|
* `Part4`: ignored
|
|
* `Text`: ignored
|
|
* FIXUP: none
|
|
|
|
If the specified character does not exist, it **throws an exception**.
|
|
Otherwise, it prints the characters description to the log.
|
|
|
|
Additionally, if notifications are not turned off, and the character has any
|
|
`Visible` and `Worn` object in it's inventory, it prints `<character display
|
|
name> is wearing:`, then the display names of all worn objects in separate
|
|
lines. If the character has any `Visible` but not `Worn` objects, it prints
|
|
`<character display name> is carrying:`, then the display names of all not worn
|
|
objects, separated by newlines.
|
|
|
|
### CT_CHAR_DISPLAYPORT
|
|
* `Part2`: character name (case insensitive)
|
|
* `Part3`: ignored
|
|
* `Part4`: ignored
|
|
* `Text`: ignored
|
|
* FIXUP: none
|
|
|
|
If the specified character does not exist, it doesn't do anything. Otherwise
|
|
what it does depends on the value of `HideMainPicDisplay` and `UseInlineImages`:
|
|
* `HideMainPicDisplay` and `UseInlineImages`: if the character doesn't have a
|
|
portrait, **throw an exception**. If the portrait is an image, paste it into
|
|
the log (without scaling and buggily, so sometimes it will just insert an
|
|
empty line...). If it is an audio/video, print the full path of the temporary
|
|
file to the log (where rags extracted the media file)...
|
|
* `HideMainPicDisplay` and not `UseInlineImages`: it doesn't do anything.
|
|
* Else: if the character doesn't have a portrait, or it is not an image, it
|
|
doesn't do anything. Otherwise, it sets the main picture and its overlay(!)
|
|
(right to the log) to character's portrait, including layered images. (Since
|
|
file overlays are over the main overlay, this will work, but if the base image
|
|
has transparency, it will be weird because of the double draw.) (I think rags
|
|
author wanted to support videos here based on the code, he just fucked it up.)
|
|
|
|
### CT_MOVECHAR
|
|
* `Part2`: character name (case insensitive)
|
|
* `Part3`: room UUID (**can be parsed**) or name (case insensitive). Special
|
|
values (not parsed, must match exactly):
|
|
* `00000000-0000-0000-0000-000000000001`: player's current room
|
|
* `00000000-0000-0000-0000-000000000002`: "void" room
|
|
* `Part4`: ignored
|
|
* `Text`: ignored
|
|
* FIXUP: if `Part3` is `<CurrentRoom>` (**case sensitively**), replace it with
|
|
`00000000-0000-0000-0000-000000000001`. If `Part3` is `<Void>`, replace it
|
|
with `00000000-0000-0000-0000-000000000002`. Otherwise, if it can't be parsed
|
|
as an UUID and there is a room with that name, replace it with the room's
|
|
UUID.
|
|
|
|
If the specified character does not exist, **throws an exception**. If the
|
|
character is in the same room as the player, and it has an action named `<<On
|
|
Character Leave>>`, execute that (without a `loop_item`).
|
|
|
|
If `Part3` is `00000000-0000-0000-0000-000000000001`, move the character to the
|
|
same room as the character, and if it has an action named `<<On Character
|
|
Enter>>`, execute it. If `Part3` is `00000000-0000-0000-0000-000000000002`, move
|
|
the character nowhere.
|
|
|
|
If `Part3` is not one of those special values, check if it **can be parsed** as
|
|
a UUID. If yes, use that as-is, otherwise look up the room with that name. If
|
|
there is no room with that name, **DISPLAY A FUCKING MESSAGE BOX** (<code>"Error
|
|
in command CT_MoveChar. Could not locate a room called "</code> + `Part3`)
|
|
and returns. (But UUIDs are not checked for validity, so it's possible to move
|
|
someone to a not existing room.) Otherwise, move the character to the specified
|
|
room. If the room is the player's current room, and the character has an `<<On
|
|
Character Enter>>` action, execute it.
|
|
|
|
### CT_MOVECHARINVTOPLAYER
|
|
* `Part2`: character name (case insensitive)
|
|
* `Part3`: ignored
|
|
* `Part4`: ignored
|
|
* `Text`: ignored
|
|
* FIXUP: none
|
|
|
|
If the specified character does not exist, it doesn't do anything. Otherwise
|
|
take all `Carryable` and `Visible` objects from the character's inventory and
|
|
move them to the player's inventory.
|
|
|
|
### CT_CHAR_MOVETOOBJ
|
|
* `Part2`: character name (case insensitive)
|
|
* `Part3`: object UUID (case insensitive)
|
|
* `Part4`: ignored
|
|
* `Text`: ignored
|
|
* FIXUP: none
|
|
|
|
If the specified character or object doesn't exist, it doesn't do anything. If
|
|
the object is in a room, move the character to that room. If the object's
|
|
location's UUID (after move) is the same as the player's room UUID (this can be
|
|
actually true when the object is in a character, but the character's UUID is the
|
|
same as the player's room's UUID...), [execute room enter
|
|
procedure](#room-enter-procedure) without actions.
|
|
|
|
### CT_CHAR_SETPORT
|
|
* `Part2`: character name (case insensitive)
|
|
* `Part3`: file name
|
|
* `Part4`: ignored
|
|
* `Text`: ignored
|
|
* FIXUP: none
|
|
|
|
If the specified character doesn't exist, it doesn't do anything. Otherwise set
|
|
the character's image to the specified file name, without error checking (so it
|
|
is possible to set it to a non-existing file).
|
|
|
|
### CT_SETCHARACTION
|
|
* `Part2`: character name (case insensitive)
|
|
* `Part3`: `action_name-state`
|
|
* `Part4`: ignored
|
|
* `Text`: ignored
|
|
* FIXUP: none
|
|
|
|
If the specified character doesn't exist, it doesn't do anything. If `Part3`
|
|
doesn't contain a hyphen, it **throws an exception**. Otherwise everything until
|
|
the last hyphen is the `action_name`. If the character doesn't have an action
|
|
with that name (case insensitively), it doesn't do anything. Otherwise it sets
|
|
its active flag, to true if `state` is `Active` (**case sensitively**), to false
|
|
otherwise.
|
|
|
|
### CT_CHAR_SET_CUSTOM_PROPERTY {#CT_CHAR_SET_CUSTOM_PROPERTY}
|
|
* `Part2`: `character_name:property_name`
|
|
* `Part3`: `Equals` / `Add` / `Subtract` / `Multiply` / `Divide` (**case
|
|
sensitive**)
|
|
* `Part4`: value (**double replaced**)
|
|
* `Text`: ignored
|
|
* FIXUP: none
|
|
|
|
[See for more info on setting custom properties](#set-custom-property). If a
|
|
character named `character_name` doesn't exists (case insensitively) it doesn't
|
|
do anything.
|
|
|
|
### CT_CHAR_SET_CUSTOM_PROPERTY_JS
|
|
Same as [CT_CHAR_SET_CUSTOM_PROPERTY](#CT_CHAR_SET_CUSTOM_PROPERTY), but with
|
|
JavaScript.
|
|
|
|
### CT_SETCHARDESC
|
|
* `Part2`: character name (case insensitive)
|
|
* `Part3`: ignored
|
|
* `Part4`: ignored
|
|
* `Text`: new character description
|
|
* FIXUP: none
|
|
|
|
If the specified character does not exist, **throws an exception**. Otherwise
|
|
sets the character's description to `Text`.
|
|
|
|
### CT_CHAR_SET_GENDER
|
|
* `Part2`: character name (case insensitive)
|
|
* `Part3`: `Male` / `Female` / `Other` (**case sensitive**)
|
|
* `Part4`: ignored
|
|
* `Text`: ignored
|
|
* FIXUP: none
|
|
|
|
If the specified character doesn't exist, it doesn't do anything. If `Part3`
|
|
after trimming is not one of the allowed values, it **throws an exception**.
|
|
Otherwise it sets the character's gender.
|
|
|
|
### CT_CHAR_SET_NAME
|
|
* `Part2`: character name (case insensitive)
|
|
* `Part3`: ignored
|
|
* `Part4`: new character name override
|
|
* `Text`: ignored
|
|
* FIXUP: none
|
|
|
|
If the specified character doesn't exist, it doesn't do anything. Otherwise it
|
|
sets the character's name override.
|
|
|
|
### CT_COMMENT
|
|
* `Part2`: ignored
|
|
* `Part3`: ignored
|
|
* `Part4`: ignored
|
|
* `Text`: ignored
|
|
* FIXUP: none
|
|
|
|
This doesn't do anything.
|
|
|
|
### CT_DEBUGTEXT
|
|
* `Part2`: ignored
|
|
* `Part3`: ignored
|
|
* `Part4`: ignored
|
|
* `Text`: debug text
|
|
* FIXUP: none
|
|
|
|
If the second command line argument is `DEBUG` (**case sensitively**), it prints
|
|
`Text` to the log.
|
|
|
|
### CT_JAVA_SET_RAGS
|
|
* `Part2`: ignored
|
|
* `Part3`: ignored
|
|
* `Part4`: ignored
|
|
* `Text`: JavaScript code (**double replaced**)
|
|
* FIXUP: none
|
|
|
|
If the JavaScript code does not return an array, it does nothing. Otherwise it
|
|
iterates through the returned array:
|
|
* non array elements are skipped
|
|
* if the element array doesn't have at least 2 items, it **throws an exception**
|
|
* otherwise the element is `[key, value]`
|
|
* convert them to strings
|
|
* if `value` is an empty string, replace it with a space (i.e. `" "`)
|
|
* call [text replacement function][] in set mode with `"[" + key + "]`
|
|
|
|
### CT_DISPLAYTEXT
|
|
* `Part2`: ignored
|
|
* `Part3`: ignored
|
|
* `Part4`: ignored
|
|
* `Text`: text
|
|
* FIXUP: none
|
|
|
|
Prints `Text` to the log.
|
|
|
|
### CT_EXPORTVARIABLE
|
|
* `Part2`: variable name (case insensitive)
|
|
* `Part3`: ignored
|
|
* `Part4`: ignored
|
|
* `Text`: ignored
|
|
* FIXUP: none
|
|
|
|
If the specified variable doesn't exist, it doesn't do anything. Otherwise it
|
|
pops up a save file dialog, and if the user doesn't cancel it, it serializes the
|
|
full variable state to a file. If the save fails, it **displays a message box**.
|
|
|
|
### CT_IMPORTVARIABLE
|
|
* `Part2`: ignored
|
|
* `Part3`: ignored
|
|
* `Part4`: ignored
|
|
* `Text`: ignored
|
|
* FIXUP: none
|
|
|
|
Pops up a file load dialog. If the user cancels it, it doesn't do anything. If
|
|
the load fails, it **displays a message box**. If there is already a variable
|
|
with the given name, it is removed, then the imported variable is added.
|
|
|
|
_Note_: this means it is possible to create a new variable by importing an
|
|
unrelated game's exported variable...
|
|
|
|
### CT_PAUSEGAME
|
|
* `Part2`: ignored
|
|
* `Part3`: ignored
|
|
* `Part4`: ignored
|
|
* `Text`: ignored
|
|
* FIXUP: none
|
|
|
|
Prints `--------------------------------` (32 hyphens), then pauses the game.
|
|
|
|
### CT_DISPLAYLAYEREDPICTURE
|
|
* `Part2`: file name (case insensitive)
|
|
* `Part3`: ignored
|
|
* `Part4`: ignored
|
|
* `Text`: ignored
|
|
* FIXUP: none
|
|
|
|
When `HideMainPicDisplay`, it doesn't do anything. Otherwise, it sets the
|
|
temporary overlay image, it sets it to `Part2` if it exist, removes the overlay
|
|
otherwise.
|
|
|
|
Temporary overlay is something that is drawn on top of the base image, but below
|
|
other overlay images and removed when a different image is displayed. Doesn't
|
|
work with videos.
|
|
|
|
_Note_: base image is set as `BackgroundImage` on a `PictureBox`, this action
|
|
sets the `Image` of the same `PictureBox` temporarily, Other overlays are drawn
|
|
from a paint event handler on top of this. This also has a weird side effect
|
|
that gif animations only work when set with this action, and only if the game is
|
|
not paused in an action.
|
|
|
|
### CT_DISPLAYPICTURE
|
|
* `Part2`: file name (case insensitive)
|
|
* `Part3`: ignored
|
|
* `Part4`: ignored
|
|
* `Text`: ignored
|
|
* FIXUP: none
|
|
|
|
What it does depends on the value of `HideMainPicDisplay` and `UseInlineImages`:
|
|
* `HideMainPicDisplay` and `UseInlineImages`: if the file doesn't exist, **throw
|
|
an exception**. If it is an image, paste it into the log (without scaling and
|
|
buggily, so sometimes it will just insert an empty line...). If it is an
|
|
audio/video, print the full path of the temporary file to the log (where rags
|
|
extracted the media file)...
|
|
* `HideMainPicDisplay` and not `UseInlineImages`: it doesn't do anything.
|
|
* Else: If the file is an image, it sets the main picture (right to the log),
|
|
including layered images. If it is something else, it switches to a windows
|
|
media player control and tries to open it. If the file doesn't exist, it still
|
|
switches to WMP, but doesn't load anything into it.
|
|
|
|
### CT_MM_SET_BACKGROUND_MUSIC {#CT_MM_SET_BACKGROUND_MUSIC}
|
|
* `Part2`: file name (case insensitive)
|
|
* `Part3`: ignored
|
|
* `Part4`: ignored
|
|
* `Text`: ignored
|
|
* FIXUP: none
|
|
|
|
If the file exists and it is an image, it doesn't do anything. Otherwise it sets
|
|
the background music volume to zero by decreasing it by 1% every 15ms (so it
|
|
will take 1.5s, and it blocks the execution while doing this (it looks like it
|
|
blocks the whole fucking GUI thread, but I'm not 100% sure on this). Then it
|
|
sets the WMP control to the file if it exists, it unloads whatever was loaded if
|
|
it doesn't exist.
|
|
|
|
### CT_MM_STOP_BACKGROUND_MUSIC
|
|
* `Part2`: ignored
|
|
* `Part3`: ignored
|
|
* `Part4`: ignored
|
|
* `Text`: ignored
|
|
* FIXUP: none
|
|
|
|
It sets the background music volume to zero in the same way as in
|
|
[CT_MM_SET_BACKGROUND_MUSIC](#CT_MM_SET_BACKGROUND_MUSIC), then it stops the
|
|
playback. This doesn't unload anything.
|
|
|
|
### CT_MM_PLAY_SOUNDEFFECT
|
|
* `Part2`: file name (case insensitive)
|
|
* `Part3`: ignored
|
|
* `Part4`: ignored
|
|
* `Text`: ignored
|
|
* FIXUP: none
|
|
|
|
If the file exists and it is an image, it doesn't do anything. Otherwise it sets
|
|
the background sound effect to `Part2` if it exists, it unloads it otherwise.
|
|
There is no fiddling with the volume like with background music and you can't
|
|
play more than one sound effect at the same time.
|
|
|
|
### CT_MM_SET_MAIN_COMPASS {#CT_MM_SET_MAIN_COMPASS}
|
|
* `Part2`: file name or `<Default>`
|
|
* `Part3`: ignored
|
|
* `Part4`: ignored
|
|
* `Text`: ignored
|
|
* FIXUP: none
|
|
|
|
If `Part2` is `<Default>` (**case sensitively**), it sets the compass image back
|
|
to rags' built-in default. Otherwise, it is a (case insensitive) filename. If
|
|
the file doesn't exists, or if it is not an image, it doesn't do anything.
|
|
Otherwise it sets the compass image (anim gifs and layered images not
|
|
supported).
|
|
|
|
### CT_MM_SET_UD_COMPASS
|
|
Same as [CT_MM_SET_MAIN_COMPASS](#CT_MM_SET_MAIN_COMPASS), except it sets the
|
|
up-down compass image on success.
|
|
|
|
### CT_LAYEREDIMAGE_ADD
|
|
* `Part2`: base image file name (case insensitive)
|
|
* `Part3`: layer file name
|
|
* `Part4`: ignored
|
|
* `Text`: ignored
|
|
* FIXUP: none
|
|
|
|
If the base image specified by `Part2` doesn't exist (or it's not an image), it
|
|
doesn't do anything. Otherwise it adds `Part3` to the end of the layered images
|
|
list (so it will be on the top) (even if it doesn't exist, it will simply be
|
|
ignored when drawing).
|
|
|
|
### CT_LAYEREDIMAGE_CLEAR
|
|
* `Part2`: base image file name (case insensitive)
|
|
* `Part3`: ignored
|
|
* `Part4`: ignored
|
|
* `Text`: ignored
|
|
* FIXUP: none
|
|
|
|
If the base image specified by `Part2` doesn't exist (or it's not an image), it
|
|
doesn't do anything. Otherwise it clears all layered images.
|
|
|
|
### CT_LAYEREDIMAGE_REMOVE
|
|
* `Part2`: base image file name (case insensitive)
|
|
* `Part3`: layer file name (**case sensitive**)
|
|
* `Part4`: ignored
|
|
* `Text`: ignored
|
|
* FIXUP: none
|
|
|
|
If the base image specified by `Part2` doesn't exist (or it's not an image), it
|
|
doesn't do anything. Otherwise, remove the first (i.e. most bottom) occurrence of
|
|
`Part3` from `Part2`'s layered images.
|
|
|
|
### CT_LAYEREDIMAGE_REPLACE
|
|
* `Part2`: base image file name (case insensitive)
|
|
* `Part3`: layer to replace file name (**case sensitive**)
|
|
* `Part4`: layer to add file name (case insensitive)
|
|
* `Text`: ignored
|
|
* FIXUP: none
|
|
|
|
If the image specified by `Part2` or `Part4` doesn't exist (or not an image), it
|
|
doesn't do anything. Otherwise it removes the first occurrence of `Part3` from
|
|
`Part2`'s layers, and if found, add `Part4` to the end of the layers.
|
|
|
|
### CT_DISPLAYITEMDESC
|
|
* `Part2`: object UUID or name (case insensitive). Special values:
|
|
* `00000000-0000-0000-0000-000000000004` :: use `action_object`
|
|
* `Part3`: ignored
|
|
* `Part4`: ignored
|
|
* `Text`: ignored
|
|
* FIXUP: if `Part2` is `<<Self>>` (**case sensitively**), replace it with
|
|
`00000000-0000-0000-0000-000000000004`. Otherwise, if it can't be parsed as an
|
|
UUID, and there is an object with that name, replace `Part2` with the object's
|
|
UUID.
|
|
|
|
When `Part2` is `00000000-0000-0000-0000-000000000004`: if there is a
|
|
`action_object`, it displays that object's description, otherwise it does
|
|
nothing.
|
|
|
|
When `Part2` is not a special value, try to get an object with than UUID,
|
|
failing that name. If it exists, it displays the description, otherwise it does
|
|
nothing.
|
|
|
|
Display description: if notifications are turned off, it just prints the
|
|
object's description. Otherwise, it prints the object's description, then:
|
|
* `". It is open."` (double space!) if it is `Openable` and `Open`.
|
|
* `". It is closed."` (double space!) if it is `Openable` and not `Open`.
|
|
* `". It contains:"` (double space!) if it is a `Container`, and (not
|
|
`Openable` or `Open`), and it is not a portal. Then it prints every visible
|
|
subobject's preposition + space + name on a new line, where every line except
|
|
the first is prefixed with `"and "`. If there are no visible subobjects, it
|
|
prints `"Nothing"`.
|
|
|
|
### CT_ITEM_LAYERED_REMOVE {#CT_ITEM_LAYERED_REMOVE}
|
|
* `Part2`: object UUID or name (case insensitive)
|
|
* `Part3`: ignored
|
|
* `Part4`: ignored
|
|
* `Text`: ignored
|
|
* FIXUP: none
|
|
|
|
If the specified object doesn't exist, it doesn't do anything. Otherwise it
|
|
iterates over all other `Worn` objects in the same location (actually it's
|
|
buggy: if the object is not in a character/player, it iterates over all objects
|
|
in the same location *type*). If the two objects share a clothing zone, and if
|
|
`Part2's level <= other's level`, it fails.
|
|
|
|
The action collects all failures, and print a message to the log and returns. If
|
|
the object is in a character's inventory, the message prefix is: character name
|
|
(override ignored!) + `" cannot remove "` + `Part2`'s display name + `". "` +
|
|
character name + `" will need to remove "`, otherwise the message prefix is:
|
|
`"You cannot remove "` + `Part2`'s display name + `". You need to remove "`. The
|
|
message continues with the display names of all conflicting objects, separated
|
|
by `" and "`, and the message suffix is `" first."`.
|
|
|
|
If there are no failures, it prints a confirmation message. If the object is in
|
|
a character, it prints: character name (override ignored) + `" takes off "` +
|
|
`Part2`'s display name + `"."`, otherwise it prints `"You take off "` +
|
|
`Part2`'s display name + `"."`. Finally, it set's `Part2`'s `Worn` to false.
|
|
|
|
Display name in this case: if preposition not empty, prefix is `preposition` +
|
|
`" "`. If name override after trim is not empty, name override without trim,
|
|
otherwise name.
|
|
|
|
### CT_ITEM_LAYERED_WEAR
|
|
Same as [CT_ITEM_LAYERED_REMOVE](#CT_ITEM_LAYERED_REMOVE), except it sets `Worn`
|
|
to true and the messages are different. `You/character_name cannot wear` on fail
|
|
and `You put on/character_name puts on` on failure.
|
|
|
|
### CT_MOVEITEMTOCHAR
|
|
* `Part2`: object UUID or name (case insensitive). Special values:
|
|
* `00000000-0000-0000-0000-000000000004` :: use `action_object`
|
|
* `Part3`: character name
|
|
* `Part4`: ignored
|
|
* `Text`: ignored
|
|
* FIXUP: if `Part2` is `<<Self>>` (**case sensitively**), replace it with
|
|
`00000000-0000-0000-0000-000000000004`. Otherwise, if it can't be parsed as an
|
|
UUID, and there is an object with that name, replace `Part2` with the object's
|
|
UUID.
|
|
|
|
It the specified object doesn't exists, or in case of
|
|
`00000000-0000-0000-0000-000000000004` there is no `action_object`, it does
|
|
nothing. Otherwise it sets the character's location to be inside `Part3` without
|
|
any checking (so it is possible to move the object into a non-existing
|
|
character).
|
|
|
|
### CT_MOVEITEMTOINV
|
|
* `Part2`: object UUID or name (case insensitive). Special values:
|
|
* `00000000-0000-0000-0000-000000000004` :: use `action_object`
|
|
* `Part3`: ignored
|
|
* `Part4`: ignored
|
|
* `Text`: ignored
|
|
* FIXUP: if `Part2` is `<<Self>>` (**case sensitively**), replace it with
|
|
`00000000-0000-0000-0000-000000000004`. Otherwise, if it can't be parsed as an
|
|
UUID, and there is an object with that name, replace `Part2` with the object's
|
|
UUID.
|
|
|
|
It the specified object doesn't exists, or in case of
|
|
`00000000-0000-0000-0000-000000000004` there is no `action_object`, it does
|
|
nothing. Otherwise, if the player has enforce weight limit set, checks if the
|
|
recursive sum of the carried items + the recursive weight of the new item does
|
|
not exceed the limit. If it does, it **DISPLAY A FUCKING MESSAGE BOX** with the
|
|
text `"The "` + object name (override ignored) + <code>" is too heavy to lift at
|
|
the moment. unload some stuff first."</code> (with two spaces before
|
|
unload and a lower case character at the beginning of the sentence), then
|
|
**CANCELS LOOP BREAK** and **ABORTS THE FUCKING COMMAND LIST**.
|
|
|
|
Otherwise it sets the object location to the player.
|
|
|
|
### CT_MOVEITEMTOOBJ
|
|
* `Part2`: object UUID or name (case insensitive). Special values:
|
|
* `00000000-0000-0000-0000-000000000004` :: use `action_object`
|
|
* `Part3`: object UUID (**can be parsed**) or name (case insensitive).
|
|
* `Part4`: ignored
|
|
* `Text`: ignored
|
|
* FIXUP: if `Part2` is `<<Self>>` (**case sensitively**), replace it with
|
|
`00000000-0000-0000-0000-000000000004`. Otherwise, if it can't be parsed as an
|
|
UUID, and there is an object with that name, replace `Part2` with the object's
|
|
UUID. Same with `Part3`.
|
|
|
|
It the object specified by `Part2` doesn't exists, or in case of
|
|
`00000000-0000-0000-0000-000000000004` there is no `action_object`, it does
|
|
nothing. If `Part3` **can be parsed** as a UUID, set `Part2`s location to
|
|
`Part3` without any checking (so it is possible to move the object into a
|
|
non-existing object). Otherwise, it tries to find an object with the name given
|
|
in `Part3`, if it finds one, it moves `Part2` into it, otherwise it does
|
|
nothing.
|
|
|
|
### CT_MOVEITEMTOROOM
|
|
* `Part2`: object UUID or name (case insensitive). Special values:
|
|
* `00000000-0000-0000-0000-000000000004` :: use `action_object`
|
|
* `Part3`: room UUID (**can be parsed**) or name (case insensitive). Special
|
|
values:
|
|
* `00000000-0000-0000-0000-000000000001`: player's current room
|
|
* `00000000-0000-0000-0000-000000000002`: "void" room
|
|
* `Part4`: ignored
|
|
* `Text`: ignored
|
|
* FIXUP: if `Part2` is `<<Self>>` (**case sensitively**), replace it with
|
|
`00000000-0000-0000-0000-000000000004`. Otherwise, if it can't be parsed as an
|
|
UUID, and there is an object with that name, replace `Part2` with the object's
|
|
UUID. If `Part3` is `<CurrentRoom>` (**case sensitively**), replace it with
|
|
`00000000-0000-0000-0000-000000000001`. If `Part3` is `<Void>`, replace it
|
|
with `00000000-0000-0000-0000-000000000002`. Otherwise, if it can't be parsed
|
|
as an UUID and there is a room with that name, replace it with the room's
|
|
UUID.
|
|
|
|
It the object specified by `Part2` doesn't exists, or in case of
|
|
`00000000-0000-0000-0000-000000000004` there is no `action_object`, it does
|
|
nothing. Get a room depending on `Part3`:
|
|
* `00000000-0000-0000-0000-000000000001`: get the player's current room.
|
|
* `00000000-0000-0000-0000-000000000002`: no room (i.e. move the object to
|
|
nowhere)
|
|
* **can be parsed** as a UUID: use the specified UUID directly without any
|
|
checking (so it is possible to move the object to a non-existing room).
|
|
* anything else: find a room with the specified name. If the room doesn't
|
|
exists, it **DISPLAY A FUCKING MESSAGE BOX** (<code>"Error in command
|
|
CT_MoveItemToRoom. Could not locate a room called "</code> + `Part3`)
|
|
and returns.
|
|
|
|
It sets the object location to the room.
|
|
|
|
### CT_SETOBJECTACTION
|
|
* `Part2`: object UUID or name (case insensitive). Special values:
|
|
* `00000000-0000-0000-0000-000000000004` :: use `action_object`
|
|
* `Part3`: `action_name-state`
|
|
* `Part4`: ignored
|
|
* `Text`: ignored
|
|
* FIXUP: if `Part2` is `<<Self>>` (**case sensitively**), replace it with
|
|
`00000000-0000-0000-0000-000000000004`. Otherwise, if it can't be parsed as an
|
|
UUID, and there is an object with that name, replace `Part2` with the object's
|
|
UUID.
|
|
|
|
It the object specified by `Part2` doesn't exists, or in case of
|
|
`00000000-0000-0000-0000-000000000004` there is no `action_object`, it does
|
|
nothing. If `Part3` doesn't contain a hyphen, it **throws an exception**.
|
|
Otherwise everything until the last hyphen is the `action_name`. If the
|
|
object doesn't have an action with that name (case insensitively), it doesn't
|
|
do anything. Otherwise it sets its active flag, to true if `state` is `Active`
|
|
(**case sensitively**), to false otherwise.
|
|
|
|
### CT_ITEM_SET_CUSTOM_PROPERTY {#CT_ITEM_SET_CUSTOM_PROPERTY}
|
|
* `Part2`: `object_name:property_name`
|
|
* `Part3`: `Equals` / `Add` / `Subtract` / `Multiply` / `Divide` (**case
|
|
sensitive**)
|
|
* `Part4`: value (**double replaced**)
|
|
* `Text`: ignored
|
|
* FIXUP: none
|
|
|
|
[See for more info on setting custom properties](#set-custom-property). If
|
|
object name is `<Self>` (**case sensitively**, single `<>`), it operates on
|
|
`action_object`, otherwise it finds an object with name `object_name` (case
|
|
insensitively). If it doesn't exist, it doesn't do anything.
|
|
|
|
### CT_ITEM_SET_CUSTOM_PROPERTY_JS
|
|
Same as [CT_ITEM_SET_CUSTOM_PROPERTY](#CT_ITEM_SET_CUSTOM_PROPERTY), but with
|
|
JavaScript.
|
|
|
|
### CT_SETITEMDESC
|
|
* `Part2`: object UUID or name (case insensitive). Special values:
|
|
* `00000000-0000-0000-0000-000000000004` :: use `action_object`
|
|
* `Part3`: ignored
|
|
* `Part4`: ignored
|
|
* `Text`: new description
|
|
* FIXUP: if `Part2` is `<<Self>>` (**case sensitively**), replace it with
|
|
`00000000-0000-0000-0000-000000000004`. Otherwise, if it can't be parsed as an
|
|
UUID, and there is an object with that name, replace `Part2` with the object's
|
|
UUID.
|
|
|
|
It the object specified by `Part2` doesn't exists, or in case of
|
|
`00000000-0000-0000-0000-000000000004` there is no `action_object`, it does
|
|
nothing. Otherwise it sets the object's description to `Text`.
|
|
|
|
### CT_ITEM_SET_NAME_OVERRIDE
|
|
* `Part2`: object UUID or name (case insensitive).
|
|
* `Part3`: ignored
|
|
* `Part4`: new name override
|
|
* `Text`: ignored
|
|
* FIXUP: none
|
|
|
|
It the object specified by `Part2` doesn't exists, it does nothing. Otherwise it
|
|
sets the object's name override to `Part4`.
|
|
|
|
### CT_SETLOCKEDUNLOCKED
|
|
* `Part2`: object UUID or name (case insensitive). Special values:
|
|
* `00000000-0000-0000-0000-000000000004` :: use `action_object`
|
|
* `Part3`: `Locked` / anything else (**case sensitive**)
|
|
* `Part4`: ignored
|
|
* `Text`: ignored
|
|
* FIXUP: if `Part2` is `<<Self>>` (**case sensitively**), replace it with
|
|
`00000000-0000-0000-0000-000000000004`. Otherwise, if it can't be parsed as an
|
|
UUID, and there is an object with that name, replace `Part2` with the object's
|
|
UUID.
|
|
|
|
It the object specified by `Part2` doesn't exists, or in case of
|
|
`00000000-0000-0000-0000-000000000004` there is no `action_object`, it does
|
|
nothing. Otherwise if `Part3` is `Locked`, it sets the object's `Locked`
|
|
property to true, false otherwise.
|
|
|
|
### CT_SETOPENCLOSED
|
|
* `Part2`: object UUID or name (case insensitive). Special values:
|
|
* `00000000-0000-0000-0000-000000000004` :: use `action_object`
|
|
* `Part3`: `Open` / anything else (**case sensitive**)
|
|
* `Part4`: ignored
|
|
* `Text`: ignored
|
|
* FIXUP: if `Part2` is `<<Self>>` (**case sensitively**), replace it with
|
|
`00000000-0000-0000-0000-000000000004`. Otherwise, if it can't be parsed as an
|
|
UUID, and there is an object with that name, replace `Part2` with the object's
|
|
UUID.
|
|
|
|
It the object specified by `Part2` doesn't exists, or in case of
|
|
`00000000-0000-0000-0000-000000000004` there is no `action_object`, it does
|
|
nothing. Otherwise if `Part3` is `Open`, it sets the object's `Open` property to
|
|
true, false otherwise.
|
|
|
|
### CT_SETITEMTOWORN
|
|
* `Part2`: object UUID or name (case insensitive). Special values:
|
|
* `00000000-0000-0000-0000-000000000004` :: use `action_object`
|
|
* `Part3`: `Worn` / anything else (**case sensitive**)
|
|
* `Part4`: ignored
|
|
* `Text`: ignored
|
|
* FIXUP: if `Part2` is `<<Self>>` (**case sensitively**), replace it with
|
|
`00000000-0000-0000-0000-000000000004`. Otherwise, if it can't be parsed as an
|
|
UUID, and there is an object with that name, replace `Part2` with the object's
|
|
UUID.
|
|
|
|
It the object specified by `Part2` doesn't exists, or in case of
|
|
`00000000-0000-0000-0000-000000000004` there is no `action_object`, it does
|
|
nothing. Otherwise if `Part3` is `Worn`, it sets the object's `Worn` property to
|
|
true, false otherwise.
|
|
|
|
### CT_ITEM_SET_VISIBILITY
|
|
* `Part2`: object UUID or name (case insensitive). Special values:
|
|
* `00000000-0000-0000-0000-000000000004` :: use `action_object`
|
|
* `Part3`: `Visible` / anything else (**case sensitive**)
|
|
* `Part4`: ignored
|
|
* `Text`: ignored
|
|
* FIXUP: if `Part2` is `<<Self>>` (**case sensitively**), replace it with
|
|
`00000000-0000-0000-0000-000000000004`. Otherwise, if it can't be parsed as an
|
|
UUID, and there is an object with that name, replace `Part2` with the object's
|
|
UUID.
|
|
|
|
It the object specified by `Part2` doesn't exists, or in case of
|
|
`00000000-0000-0000-0000-000000000004` there is no `action_object`, it does
|
|
nothing. Otherwise if `Part3` is `Visible`, it sets the object's `Visible`
|
|
property to true, false otherwise.
|
|
|
|
### CT_ITEMS_MOVE_CONTAINER_TO_CONTAINER
|
|
* `Part2`: object UUID or name (case insensitive). Special values:
|
|
* `00000000-0000-0000-0000-000000000004` :: use `action_object`
|
|
* `Part3`: object UUID or name (case insensitive). Special values:
|
|
* `00000000-0000-0000-0000-000000000004` :: use `action_object`
|
|
* `Part4`: ignored
|
|
* `Text`: ignored
|
|
* FIXUP: none
|
|
|
|
It the object specified by `Part2` or `Part3` doesn't exists, or in case of
|
|
`00000000-0000-0000-0000-000000000004` there is no `action_object`, it does
|
|
nothing. Otherwise it moves all objects directly in `Part2` to `Part3`.
|
|
|
|
### CT_LOOP_BREAK
|
|
* `Part2`: ignored
|
|
* `Part3`: ignored
|
|
* `Part4`: ignored
|
|
* `Text`: ignored
|
|
* FIXUP: none
|
|
|
|
Schedules a loop break and **aborts the current command list**.
|
|
|
|
### CT_CANCELMOVE
|
|
* `Part2`: ignored
|
|
* `Part3`: ignored
|
|
* `Part4`: ignored
|
|
* `Text`: ignored
|
|
* FIXUP: none
|
|
|
|
Sets a flag to cancel the player's current move. This can be called anywhere,
|
|
but only has an effect inside `<<On Player Leave First Time>>` and `<<On Player
|
|
Leave>>` player actions when executed as a result of the player (the 3DPD one)
|
|
selecting a move target on the GUI.
|
|
|
|
### CT_DISPLAYPLAYERDESC
|
|
* `Part2`: ignored
|
|
* `Part3`: ignored
|
|
* `Part4`: ignored
|
|
* `Text`: ignored
|
|
* FIXUP: none
|
|
|
|
Prints the player's description after replacement (without `loop_item`) to the
|
|
log.
|
|
|
|
### CT_SETLAYEREDPLAYERPORTRAIT
|
|
* `Part2`: file name or `<None>`
|
|
* `Part3`: ignored
|
|
* `Part4`: ignored
|
|
* `Text`: ignored
|
|
* FIXUP: none
|
|
|
|
If `Part2` is `<None>` (**case sensitively**), it is treated as an empty string.
|
|
This sets the player's overlay image to `Part2` without any checking (so it is
|
|
possible to set it to a non-existing file, it will be ignored when drawing).
|
|
|
|
### CT_MOVEINVENTORYTOCHAR
|
|
* `Part2`: character name
|
|
* `Part3`: ignored
|
|
* `Part4`: ignored
|
|
* `Text`: ignored
|
|
* FIXUP: if `Part2` is `<<Self>>` (**case sensitively**), replace it with
|
|
`00000000-0000-0000-0000-000000000004`. Otherwise, if it can't be parsed as an
|
|
UUID, and there is an object with that name, replace `Part2` with the object's
|
|
UUID. (This is completely pointless, as `Part2` must be a character name, not
|
|
an object UUID).
|
|
|
|
Moves every item from the player's inventory to `Part2`'s inventory without any
|
|
checking (so it is possible to move it into a non-existing character).
|
|
|
|
### CT_MOVEINVENTORYTOROOM
|
|
* `Part2`: room's UUID. Special values (not parsed, must match exactly):
|
|
* `00000000-0000-0000-0000-000000000001` :: player's current room
|
|
* `00000000-0000-0000-0000-000000000002` :: "void" room
|
|
* `Part3`: ignored
|
|
* `Part4`: ignored
|
|
* `Text`: ignored
|
|
* FIXUP: if `Part2` is `<CurrentRoom>` (**case sensitively**), replace it with
|
|
`00000000-0000-0000-0000-000000000001`. If `Part2` is `<Void>`, replace it
|
|
with `00000000-0000-0000-0000-000000000002`. Otherwise, if it can't be parsed
|
|
as an UUID and there is a room with that name, replace it with the room's
|
|
UUID.
|
|
|
|
Moves every item from the player's inventory to the specified location:
|
|
* `00000000-0000-0000-0000-000000000001`: move to the player's current room.
|
|
* `00000000-0000-0000-0000-000000000002`: move to nowhere.
|
|
* anything else: move to the room with the specified UUID without any checking
|
|
(so it is possible to move items to a not existing room).
|
|
|
|
### CT_MOVEPLAYER
|
|
* `Part2`: room uuid (**can be parsed**) or name (case insensitive).
|
|
* `Part3`: ignored
|
|
* `Part4`: ignored
|
|
* `Text`: ignored
|
|
* FIXUP: if `Part2` is `<CurrentRoom>` (**case sensitively**), replace it with
|
|
`00000000-0000-0000-0000-000000000001`. If `Part2` is `<Void>`, replace it
|
|
with `00000000-0000-0000-0000-000000000002`. Otherwise, if it can't be parsed
|
|
as an UUID and there is a room with that name, replace it with the room's
|
|
UUID.
|
|
|
|
If `Part2` **can be parsed** as a UUID, find a room with that UUID, else find a
|
|
room with that name, and move the player there. If the room doesn't exist, move
|
|
the player to nowhere instead (which is a surefire way to fuck up rags and
|
|
receive exceptions from everywhere). Otherwise, [execute room enter
|
|
procedure](#room-enter-procedure) with actions but without timers.
|
|
|
|
### CT_MOVETOCHAR {#CT_MOVETOCHAR}
|
|
* `Part2`: character name (case insensitive).
|
|
* `Part3`: ignored
|
|
* `Part4`: ignored
|
|
* `Text`: ignored
|
|
* FIXUP: none
|
|
|
|
If the character doesn't exist, or the character is nowhere or in the same room
|
|
as the player, it doesn't do anything. Otherwise it moves the player to the same
|
|
room as the character is in, if it exists, it moves the player to nowhere if it
|
|
doesn't exist. Finally, if the player is in a room, it [executes room enter
|
|
procedure](#room-enter-procedure) with actions but without timers.
|
|
|
|
*Note*: this action catches any inner exceptions and silently discards them.
|
|
|
|
### CT_MOVETOOBJ
|
|
* `Part2`: object UUID (case insensitive).
|
|
* `Part3`: ignored
|
|
* `Part4`: ignored
|
|
* `Text`: ignored
|
|
* FIXUP: none
|
|
|
|
If the object doesn't exist, it doesn't do anything. If the object is in a room,
|
|
moves the player to that room, or nowhere if it doesn't. Finally, if the player
|
|
is in a room, it [executes room enter procedure](#room-enter-procedure) with
|
|
actions but without timers.
|
|
|
|
*Note*: this action catches any inner exceptions and silently discards them.
|
|
|
|
*Note*: unlike [CT_MOVETOCHAR](#CT_MOVETOCHAR), this executes room enter actions
|
|
when the object is not in a room or it is already in the same room as the
|
|
player.
|
|
|
|
### CT_PLAYER_SET_CUSTOM_PROPERTY {#CT_PLAYER_SET_CUSTOM_PROPERTY}
|
|
* `Part2`: `property_name`
|
|
* `Part3`: `Equals` / `Add` / `Subtract` / `Multiply` / `Divide` (**case
|
|
sensitive**)
|
|
* `Part4`: value (**double replaced**)
|
|
* `Text`: ignored
|
|
* FIXUP: none
|
|
|
|
[See for more info on setting custom properties](#set-custom-property). Since
|
|
there is only one player, `Part2` is treated as `property_name`, even if it
|
|
contains colons.
|
|
|
|
### CT_PLAYER_SET_CUSTOM_PROPERTY_JS
|
|
Same as [CT_PLAYER_SET_CUSTOM_PROPERTY](#CT_PLAYER_SET_CUSTOM_PROPERTY), but
|
|
with JavaScript.
|
|
|
|
### CT_SETPLAYERACTION
|
|
* `Part2`: ignored
|
|
* `Part3`: `action_name-state`
|
|
* `Part4`: ignored
|
|
* `Text`: ignored
|
|
* FIXUP: none
|
|
|
|
If `Part3` doesn't contain a hyphen, it **throws an exception**. Otherwise
|
|
everything until the last hyphen is the `action_name`. If the player doesn't
|
|
have an action with that name (case insensitively), it doesn't do anything.
|
|
Otherwise it sets its active flag, to true if `state` is `Active` (**case
|
|
sensitively**), to false otherwise.
|
|
|
|
### CT_SETPLAYERDESC
|
|
* `Part2`: ignored
|
|
* `Part3`: ignored
|
|
* `Part4`: ignored
|
|
* `Text`: new description
|
|
* FIXUP: none
|
|
|
|
Set the player's description to `Text`.
|
|
|
|
### CT_SETPLAYERGENDER
|
|
* `Part2`: `Male` / `Female` / `Other` (**case sensitive**)
|
|
* `Part3`: ignored
|
|
* `Part4`: ignored
|
|
* `Text`: ignored
|
|
* FIXUP: none
|
|
|
|
If `Part2` is not one of the allowed values, it **throws an exception**,
|
|
otherwise it sets the player's gender.
|
|
|
|
### CT_SETPLAYERNAME
|
|
* `Part2`: ignored
|
|
* `Part3`: ignored
|
|
* `Part4`: new player name (**double replaced**)
|
|
* `Text`: ignored
|
|
* FIXUP: none
|
|
|
|
Sets the player's name.
|
|
|
|
### CT_SETPLAYERPORTRAIT
|
|
* `Part2`: file name
|
|
* `Part3`: ignored
|
|
* `Part4`: ignored
|
|
* `Text`: ignored
|
|
* FIXUP: none
|
|
|
|
Sets the player's image to `Part2` without any checking (so it is possible to
|
|
set it to a non-existing file).
|
|
|
|
### CT_DISPLAYROOMDESCRIPTION
|
|
* `Part2`: room UUID (**can be parsed**) or name (case insensitive). Special
|
|
values:
|
|
* `00000000-0000-0000-0000-000000000001`: player's current room
|
|
* `Part3`: ignored
|
|
* `Part4`: ignored
|
|
* `Text`: ignored
|
|
* FIXUP: if `Part2` is `<CurrentRoom>` (**case sensitively**), replace it with
|
|
`00000000-0000-0000-0000-000000000001`. If `Part2` is `<Void>`, replace it
|
|
with `00000000-0000-0000-0000-000000000002`. Otherwise, if it can't be parsed
|
|
as an UUID and there is a room with that name, replace it with the room's
|
|
UUID.
|
|
|
|
If `Part2` is `00000000-0000-0000-0000-000000000001` it uses the player's
|
|
current room, otherwise it finds a room with the given UUID if it **can be
|
|
parsed** as a UUID, by a name otherwise. If the room doesn't exists it doesn't
|
|
do anything, otherwise it prints its description (and just the description, and
|
|
not 28472 unrelated things).
|
|
|
|
### CT_DISPLAYROOMPICTURE
|
|
* `Part2`: room UUID (**can be parsed**) or name (case insensitive). Special
|
|
values:
|
|
* `00000000-0000-0000-0000-000000000001`: player's current room
|
|
* `Part3`: ignored
|
|
* `Part4`: ignored
|
|
* `Text`: ignored
|
|
* FIXUP: if `Part2` is `<CurrentRoom>` (**case sensitively**), replace it with
|
|
`00000000-0000-0000-0000-000000000001`. If `Part2` is `<Void>`, replace it
|
|
with `00000000-0000-0000-0000-000000000002`. Otherwise, if it can't be parsed
|
|
as an UUID and there is a room with that name, replace it with the room's
|
|
UUID.
|
|
|
|
If `Part2` is `00000000-0000-0000-0000-000000000001` it uses the player's
|
|
current room, otherwise it finds a room with the given UUID if it **can be
|
|
parsed** as a UUID, by a name otherwise. If the room doesn't exists it doesn't
|
|
do anything. What it does depends on the value of `HideMainPicDisplay` and
|
|
`UseInlineImages`:
|
|
* `HideMainPicDisplay` and `UseInlineImages`: if the file doesn't exist, **throw
|
|
an exception**. If it is an image, paste it into the log (without scaling and
|
|
buggily, so sometimes it will just insert an empty line...). If it is an
|
|
audio/video, print the full path of the temporary file to the log (where rags
|
|
extracted the media file)...
|
|
* `HideMainPicDisplay` and not `UseInlineImages`: it doesn't do anything.
|
|
* Else: If the file is an image, it sets the main picture (right to the log),
|
|
including (single) layered image. If both of them are images, it works
|
|
correctly. If any of them missing, they're not set. If one is an image and and
|
|
the other is a video, the last one wins (so overlay beats normal image).
|
|
|
|
### CT_ROOM_MOVE_ITEMS_TO_PLAYER
|
|
* `Part2`: room UUID (case insensitive). Special values (not parsed, must match
|
|
exactly):
|
|
* `00000000-0000-0000-0000-000000000001`: player's current room
|
|
* `Part3`: ignored
|
|
* `Part4`: ignored
|
|
* `Text`: ignored
|
|
* FIXUP: none
|
|
|
|
If `Part2` is not a valid UUID, it **throws an exception**. Otherwise, if it is
|
|
`00000000-0000-0000-0000-000000000001` uses the player's current room, otherwise
|
|
it finds the room with the given UUID. If there is no such room, it doesn't do
|
|
anything. Otherwise it moves all `Carryable` and `Visible` in the room to the
|
|
player's inventory.
|
|
|
|
### CT_SETROOMACTION
|
|
* `Part2`: room UUID (**can be parsed**) or name (case insensitive). Special
|
|
values:
|
|
* `00000000-0000-0000-0000-000000000001`: player's current room
|
|
* `Part3`: `action_name-state`
|
|
* `Part4`: ignored
|
|
* `Text`: ignored
|
|
* FIXUP: if `Part2` is `<CurrentRoom>` (**case sensitively**), replace it with
|
|
`00000000-0000-0000-0000-000000000001`. If `Part2` is `<Void>`, replace it
|
|
with `00000000-0000-0000-0000-000000000002`. Otherwise, if it can't be parsed
|
|
as an UUID and there is a room with that name, replace it with the room's
|
|
UUID.
|
|
|
|
It the room specified by `Part2` doesn't exists, it does nothing. If `Part3`
|
|
doesn't contain a hyphen, it **throws an exception**. Otherwise everything until
|
|
the last hyphen is the `action_name`. If the room doesn't have an action with
|
|
that name (case insensitively), it doesn't do anything. Otherwise it sets its
|
|
active flag, to true if `state` is `Active` (**case sensitively**), to false
|
|
otherwise.
|
|
|
|
### CT_ROOM_SET_CUSTOM_PROPERTY {#CT_ROOM_SET_CUSTOM_PROPERTY}
|
|
* `Part2`: `room_name:property_name`
|
|
* `Part3`: `Equals` / `Add` / `Subtract` / `Multiply` / `Divide` (**case
|
|
sensitive**)
|
|
* `Part4`: value (**double replaced**)
|
|
* `Text`: ignored
|
|
* FIXUP: none
|
|
|
|
[See for more info on setting custom properties](#set-custom-property). If room
|
|
name is `<CurrentRoom>` (**case sensitively**), it operates on the player's
|
|
current room, otherwise it finds a room with name `room_name` (case
|
|
insensitively). If it doesn't exist, it doesn't do anything.
|
|
|
|
### CT_ROOM_SET_CUSTOM_PROPERTY_JS
|
|
Same as [CT_ROOM_SET_CUSTOM_PROPERTY](#CT_ROOM_SET_CUSTOM_PROPERTY), but with
|
|
JavaScript.
|
|
|
|
### CT_SETROOMDESCRIPTION
|
|
* `Part2`: room UUID (**can be parsed**) or name (case insensitive). Special
|
|
values:
|
|
* `00000000-0000-0000-0000-000000000001`: player's current room
|
|
* `Part3`: ignored
|
|
* `Part4`: ignored
|
|
* `Text`: new description
|
|
* FIXUP: if `Part2` is `<CurrentRoom>` (**case sensitively**), replace it with
|
|
`00000000-0000-0000-0000-000000000001`. If `Part2` is `<Void>`, replace it
|
|
with `00000000-0000-0000-0000-000000000002`. Otherwise, if it can't be parsed
|
|
as an UUID and there is a room with that name, replace it with the room's
|
|
UUID.
|
|
|
|
If `Part2` is `00000000-0000-0000-0000-000000000001`, it operates on the
|
|
player's current room, otherwise if it **can be parsed** as a UUID, it finds a
|
|
room with that UUID, else it find a room with that name. If the specified room
|
|
doesn't exist, it doesn't do anything, otherwise it sets the room's description.
|
|
|
|
### CT_SETEXIT
|
|
* `Part2`: room UUID (**can be parsed**) or name (case insensitive).
|
|
* `Part3`: `direction-active` (**case sensitive**)
|
|
* `Part4`: ignored
|
|
* `Text`: ignored
|
|
* FIXUP: if `Part2` is `<CurrentRoom>` (**case sensitively**), replace it with
|
|
`00000000-0000-0000-0000-000000000001`. If `Part2` is `<Void>`, replace it
|
|
with `00000000-0000-0000-0000-000000000002`. Otherwise, if it can't be parsed
|
|
as an UUID and there is a room with that name, replace it with the room's
|
|
UUID. (*Note*: the action doesn't hande these values...)
|
|
|
|
If `Part2` **can be parsed** as a UUID, it finds a room with that UUID, else it
|
|
find a room with that name. If the specified room doesn't exist, it doesn't do
|
|
anything. If `Part3` doesn't contain a hyphen, it **throws an exception**,
|
|
otherwise everything until the first hyphen is the `direction`. If there is a
|
|
second hyphen, it and everything after it is ignored. `active` is trimmed of
|
|
white-space, but `direction` is not (unlike other enum parsing places...).
|
|
|
|
If `direction` does not refer to a valid direction (`North`, `South`,
|
|
`NorthEast`, ...), it doesn't do anything. Otherwise it sets its `Active`
|
|
status, to true if `active` is `Active`, false otherwise.
|
|
|
|
### CT_SETEXITDESTINATION
|
|
* `Part2`: room UUID (**can be parsed**) or name (case insensitive).
|
|
* `Part3`: direction (**case sensitive**)
|
|
* `Part4`: `<None>` or destination room UUID (**can be parsed**) or name
|
|
* `Text`: ignored
|
|
* FIXUP: none
|
|
|
|
If `Part2` **can be parsed** as a UUID, it finds a room with that UUID, else it
|
|
find a room with that name. If the specified room doesn't exist, it doesn't do
|
|
anything. If `direction` does not refer to a valid direction (without trimming),
|
|
it doesn't do anything.
|
|
|
|
If `Part4` is `<None>` (**case sensitively**), it sets the exit's destination to
|
|
nowhere and sets its `Active` flag to false. Otherwise, if `Part4` **can be
|
|
parsed** as a UUID, it finds a room with that UUID, otherwise it finds a room
|
|
with that name. If the room does not exists, it does nothing, otherwise it sets
|
|
the exit's destination to the room and the exit's `Active` status to true.
|
|
|
|
### CT_ROOM_SET_NAME_OVERRIDE
|
|
* `Part2`: room UUID (**can be parsed**) or name (case insensitive).
|
|
* `Part3`: ignored
|
|
* `Part4`: name override
|
|
* `Text`: ignored
|
|
* FIXUP: none
|
|
|
|
If `Part2` **can be parsed** as a UUID, it finds a room with that UUID, else it
|
|
find a room with that name. If the specified room doesn't exist, it doesn't do
|
|
anything, otherwise it sets the room's name override.
|
|
|
|
### CT_SETROOMLAYEREDPIC
|
|
* `Part2`: room UUID (**can be parsed**) or name (case insensitive). Special
|
|
values:
|
|
* `00000000-0000-0000-0000-000000000001` :: player's current room
|
|
* `Part3`: file name
|
|
* `Part4`: ignored
|
|
* `Text`: ignored
|
|
* FIXUP: none
|
|
|
|
If `Part2` is `00000000-0000-0000-0000-000000000001`, it operates on the
|
|
player's current room, otherwise if it **can be parsed** as a UUID, it finds a
|
|
room with that UUID, else it find a room with that name. If the specified room
|
|
doesn't exist, it doesn't do anything.
|
|
|
|
If `Part3` is `<None>`, it is treated as empty string, then it sets the room's
|
|
overlay image to `Part3` without any checking (so it can be set to a
|
|
non-existing image).
|
|
|
|
If the room is the current player's room, and `HideMainPicDisplay` is false, it
|
|
updates the main image and room image, but without handling videos.
|
|
|
|
### CT_SETROOMPIC
|
|
* `Part2`: room UUID (**can be parsed**) or name (case insensitive). Special
|
|
values:
|
|
* `00000000-0000-0000-0000-000000000001` :: player's current room
|
|
* `Part3`: file name
|
|
* `Part4`: ignored
|
|
* `Text`: ignored
|
|
* FIXUP: if `Part2` is `<CurrentRoom>` (**case sensitively**), replace it with
|
|
`00000000-0000-0000-0000-000000000001`. If `Part2` is `<Void>`, replace it
|
|
with `00000000-0000-0000-0000-000000000002`. Otherwise, if it can't be parsed
|
|
as an UUID and there is a room with that name, replace it with the room's
|
|
UUID.
|
|
|
|
If `Part2` is `00000000-0000-0000-0000-000000000001`, it operates on the
|
|
player's current room, otherwise if it **can be parsed** as a UUID, it finds a
|
|
room with that UUID, else it find a room with that name. If the specified room
|
|
doesn't exist, it doesn't do anything, otherwise it sets the room's image
|
|
without any checking (so it can be set to a non-existing image).
|
|
|
|
If the room is the current player's room, it tries to redisplay the room image:
|
|
* If `HideMainPicDisplay` and `UseInlineImages`: paste the room image into the
|
|
log with the usual bugs.
|
|
* If `HideMainPicDisplay`: no further actions.
|
|
* Else: it updates the main image (but not the room image), without handling
|
|
videos.
|
|
|
|
### CT_Status_ItemVisibleInvisible
|
|
* `Part2`: status bar item name (case insensitive)
|
|
* `Part3`: `Visible` / anything else (case insensitive)
|
|
* `Part4`: ignored
|
|
* `Text`: ignored
|
|
* FIXUP: none
|
|
|
|
If the status bar item specified by `Part2` doesn't exist, it doesn't do
|
|
anything. Otherwise it sets its `Visible` flag, to true if `Part3` is `Visible`,
|
|
to false otherwise.
|
|
|
|
### CT_EXECUTETIMER {#CT_EXECUTETIMER}
|
|
* `Part2`: timer name (case insensitive)
|
|
* `Part3`: ignored
|
|
* `Part4`: ignored
|
|
* `Text`: ignored
|
|
* FIXUP: none
|
|
|
|
If the timer with the given name doesn't exist, or it doesn't have an action
|
|
with name `<<On Each Turn>>`, it doesn't do anything. Otherwise it executes the
|
|
action (without an `action_object`), repeating it as many times as it is reset.
|
|
|
|
### CT_RESETTIMER
|
|
* `Part2`: timer name (case insensitive)
|
|
* `Part3`: ignored
|
|
* `Part4`: ignored
|
|
* `Text`: ignored
|
|
* FIXUP: none
|
|
|
|
If the timer with the given name doesn't exist, it doesn't do anything.
|
|
|
|
Otherwise it sets the timer's `TurnNumber` to zero. If `Part2` is the currently
|
|
executing timer, it queues a reset (which will cause
|
|
[CT_EXECUTETIMER](#CT_EXECUTETIMER) to execute it again, or when normally
|
|
executing timers, it will skip subsequent On ... Turn actions), otherwise it
|
|
**clears the queued reset**. In any case it **CANCELS LOOP BREAK** and **ABORTS
|
|
THE FUCKING COMMAND LIST**.
|
|
|
|
### CT_TIMER_SET_CUSTOM_PROPERTY {#CT_TIMER_SET_CUSTOM_PROPERTY}
|
|
* `Part2`: `timer_name:property_name` (case insensitive)
|
|
* `Part3`: `Equals` / `Add` / `Subtract` / `Multiply` / `Divide` (**case
|
|
sensitive**)
|
|
* `Part4`: value (**double replaced**)
|
|
* `Text`: ignored
|
|
* FIXUP: none
|
|
|
|
[See for more info on setting custom properties](#set-custom-property). It finds
|
|
a timer with name `timer_name` (case insensitively). If it doesn't exist, it
|
|
doesn't do anything.
|
|
|
|
### CT_TIMER_SET_CUSTOM_PROPERTY_JS
|
|
Same as [CT_TIMER_SET_CUSTOM_PROPERTY](#CT_TIMER_SET_CUSTOM_PROPERTY), but with
|
|
JavaScript.
|
|
|
|
### CT_SETTIMER
|
|
* `Part2`: timer name (case insensitive)
|
|
* `Part3`: `Active` / anything else (case insensitive)
|
|
* `Part4`: ignored
|
|
* `Text`: ignored
|
|
* FIXUP: none
|
|
|
|
If the timer with the given name doesn't exist, it doesn't do anything.
|
|
Otherwise it sets the timer's `Active` flag, to true if `Part3` is `Active`, to
|
|
false if it is anything else.
|
|
|
|
### CT_DISPLAYVARIABLE
|
|
* `Part2`: variable name + optional indices (case insensitive)
|
|
* `Part3`: `Display Date & Time` / `Display Date Only` / `Display Time Only` /
|
|
`Display Weekday Only` (**case sensitive**)
|
|
* `Part4`: ignored
|
|
* `Text`: ignored
|
|
* FIXUP: none
|
|
|
|
If the variable specified by `Part2` doesn't exist, it doesn't do anything. Here
|
|
is what happens, when the number of indices specified doesn't match the variable
|
|
type:
|
|
| Var type | 0 idx | 1 idx | 2 idx |
|
|
|------------|------------|--------------------------------|---------------|
|
|
| Single | single val | single val | single val |
|
|
| 1D | nothing | value | **exception** |
|
|
| Num/Str 2D | nothing | `System.Collections.ArrayList` | value |
|
|
| DT 2D | nothing | **exception** | value |
|
|
|
|
(Array indices are completely ignored with non-array variables.) Out-of-range
|
|
accesses generate exceptions except in "single val" and "nothing" cells.
|
|
|
|
In case of number or string variables, `Part3` is ignored, they're converted to
|
|
string normally and printed. With DateTime variables it specifies a date format:
|
|
* `Display Date & Time`: `dddd, MMMM, dd yyyy hh:mm:ss tt`, except in case of 2D
|
|
arrays, where it just prints whatever string representation the date is stored
|
|
in (so it doesn't throw if you only specify one index, it prints
|
|
`System.Collections.ArrayList`).
|
|
* `Display Date Only`: `dddd, MMMM, dd yyyy`
|
|
* `Display Time Only`: `hh:mm:ss tt`
|
|
* `Display Weekday Only`: `dddd`
|
|
If `Part3` is not one of the allowed values, it doesn't print anything.
|
|
|
|
### CT_SETVARIABLE {#CT_SETVARIABLE}
|
|
* `Part2`: variable name + optional indices (case insensitive)
|
|
* `Part3`: `Equals` / `Add` / `Subtract` / `Multiply` / `Divide` / `Add Days` /
|
|
`Add Hours` / `Add Minutes` / `Add Seconds` / `Subtract Days` / `Subtract
|
|
Hours` / `Subtract Minutes` / `Subtract Seconds` / `Set Day Of Month To` /
|
|
`Set Hours To` / `Set Minutes To` / `Set Seconds To` (**case sensitive**)
|
|
* `Part4`: value (**double replaced**)
|
|
* `Text`: also value (**double replaced**)
|
|
* FIXUP: none
|
|
|
|
If `Part2` contains the string `Array:` (anywhere, **case sensitive**), the
|
|
first 6 characters of `Part2` is removed and it will be an array set, otherwise
|
|
a normal set. The rest is parsed for variable name and indices as usual, if the
|
|
variable doesn't exists, this action does nothing.
|
|
|
|
In case of a JavaScript set
|
|
([CT_VARIABLE_SET_JAVASCRIPT](#CT_VARIABLE_SET_JAVASCRIPT)), it runs `Part4`
|
|
through the JavaScript interpreter (after double replace), and converts the
|
|
result to string.
|
|
|
|
Here is what happens generally when the number of indices doesn't match, but
|
|
watch out for exceptions below.
|
|
| Var type | 0 idx | 1 idx | 2 idx |
|
|
|----------|------------|--------------------------------|----------------------|
|
|
| Single | set single | ignore/**exception** | ignore/**exception** |
|
|
| 1D | set single | set | **exception** |
|
|
| 2D | set single | **fuckup** | set |
|
|
* ignore/**exception**: this means that the code will try to overwrite the array
|
|
part of the variable, which depending on what leftover garbage is there, might
|
|
actually work, but you're more likely to get an exception.
|
|
* **fuckup**: in this case you'll end up with an array where a row is replaced
|
|
by a string/number/dt, and... you can expect things to break left and right if
|
|
you do this.
|
|
|
|
With number and datetime variables, array set is only working when `Part3` is
|
|
`Equals`, but for string variables `Part3` is ignored. An array set is
|
|
only working with JS set, without JS it just clears the variable (it will be 0
|
|
rows, indefinite columns, it leaves single value alone).
|
|
|
|
With a normal set, with a number variable, if `Part4` is not a number, it
|
|
**throws an exception**, otherwise it just sets the specified cell with the
|
|
error handling above. In case of `Add`, `Subtract`, `Multiply` and `Divide` only
|
|
normal sets are possible, `Array:` is ignored and **fuckup** changes into
|
|
**exception**. If `Part3` has any other value, the value is not updated.
|
|
|
|
If the variable has `EnforceRestrictions`, the set (or not set in case `Part3`
|
|
is invalid...) value is validated. If it is smaller than replaced and converted
|
|
to double min, it is set to min, and if after it is larger than max, it is set
|
|
to max (if the result of replacement is not a number, it **throws an
|
|
exception**). In case of `Equals` and **fuckup**, this will end up in an
|
|
exception, but only after fucking up the variable...
|
|
|
|
In case of string variables, `Part3` is ignored (only simple settings is
|
|
supported) and the value is read from `Text` instead of `Part4` (`Text` is also
|
|
evaluated with JS, but only with string variables). Array set and normal set is
|
|
supported.
|
|
|
|
DateTime works similarly to numbers, except: every possible value of `Part3` is
|
|
supported except `Add`, `Subtract`, `Multiply`, `Divide`, and there are no
|
|
min-max checks. `Equals` expects a date time, parsed by .NET's super permissive
|
|
parser, everything else an int32, if the conversion fails it **throws an
|
|
exception**.
|
|
|
|
### CT_ITEM_GETRANDOMGROUP {#CT_ITEM_GETRANDOMGROUP}
|
|
* `Part2`: variable name (without indices!) (case insensitive)
|
|
* `Part3`: group name (case insensitive)
|
|
* `Part4`: ignored
|
|
* `Text`: ignored
|
|
* FIXUP: none
|
|
|
|
If the variable specified by `Part2` doesn't exist, it doesn't do anything.
|
|
|
|
**This operates directly on SQL**, not the in-memory structures (that gets
|
|
serialized into savegames). If `Part3` doesn't name a valid object group, it is
|
|
treated as being empty. Otherwise it collects all objects recursively in the
|
|
object group.
|
|
|
|
It sets the variable's single string value (even if it is not a string variable)
|
|
to the name of a random object in this set, or to the empty string if the object
|
|
group is empty.
|
|
|
|
### CT_MM_GETRANDOMGROUP
|
|
* `Part2`: variable name (without indices!) (case insensitive)
|
|
* `Part3`: group name (case insensitive)
|
|
* `Part4`: ignored
|
|
* `Text`: ignored
|
|
* FIXUP: none
|
|
|
|
Exactly the same as [CT_ITEM_GETRANDOMGROUP](#CT_ITEM_GETRANDOMGROUP), except it
|
|
gets a random file name from a file group.
|
|
|
|
### CT_VARIABLE_SET_JAVASCRIPT {#CT_VARIABLE_SET_JAVASCRIPT}
|
|
See [CT_SETVARIABLE](#CT_SETVARIABLE) for details. I'm only going to document
|
|
how JavaScript arrays are turned into rags variable arrays:
|
|
|
|
If the returned value is not a JavaScript array, the result is an empty array.
|
|
Otherwise each item of the array is converted as follows:
|
|
* it is not an array and variable type is number: the value is converted to a
|
|
string, then to a double. If any of this fails, the value is `-1`.
|
|
* it is not an array and variable type is string: the value is converted to a
|
|
string. If this fails, the exception is quietly swallowed and it leaves the
|
|
array in a half-set state.
|
|
* it is not an array and variable type is DateTime: it is converted to a string,
|
|
then parsed with .net's super permissive parser. If this fails somehow, it is
|
|
set to `0001-01-01 00:00:00` unspecified timezone (can be treated as local).
|
|
* it is an array: if it is an empty array, it is skipped, otherwise each item of
|
|
this inner array is simply converted to a string. (2D arrays are always stored
|
|
as strings in rags.) (If it is not a 2D array, **fuckup**.)
|
|
|
|
### CT_SETVARIABLEBYINPUT {#CT_SETVARIABLEBYINPUT}
|
|
* `Part2`: input type: `Text` / `Characters` / `Characters And Objects` /
|
|
`Objects` / `Custom` / `Inventory` (**case sensitive**)
|
|
* `Part3`: variable name + optional indices (case insensitive)
|
|
* `Part4`: custom choice title (**double replaced**)
|
|
* `Text`: ignored
|
|
* `EnhancedData`: one of the few functions that use it
|
|
* FIXUP: none
|
|
|
|
If input type is not one of the allowed values, it is treated as being `None`
|
|
(which means an empty selection list. Interestingly, without ovelays, you can
|
|
still click on OK even with zero items, overlay forces a cancel button in this
|
|
case). In case of a custom choice, custom values are taken from `EnhancedData`,
|
|
after replacement, otherwise the same as with normal action input.
|
|
|
|
When using overlay input, the title is taken from `Part4`, or if it empty after
|
|
replace, it is `Please make a selection:`. Without overlay, it is always taken
|
|
from `Part4`, even if it is empty. Non overlay query is never cancelable, while
|
|
overlay input is cancelable if the list is empty or `EnhancedData.AllowCancel`.
|
|
|
|
Without overlay, it never uses tags, with overlay it's same as the normal
|
|
action. There's no post-processing of the selected tag. If the selection is
|
|
canceled, it **CANCELS LOOP BREAK** and **ABORTS THE FUCKING COMMAND LIST**.
|
|
|
|
If the variable does not exists, or if input type is `None`, it doesn't do
|
|
anything (but it only checks this after the user made a selection...). This
|
|
action expects the variable to be a string, it sets single and array string
|
|
values without checking, ending up in ignore/fuckup cases when done. With `Text`
|
|
input, the selection is simply stored. Otherwise, first the single value is set
|
|
to an empty string, and if the selection is not an empty string, the normal
|
|
value is set. Here is what happens when the number of indices doesn't match the
|
|
variable type:
|
|
|
|
| Var type | 0 idx | 1 idx | 2 idx |
|
|
|----------|------------|--------------------------------|----------------------|
|
|
| Single | set single | ignore/**exception** | ignore/**exception** |
|
|
| 1D | set single | set | **exception** |
|
|
| 2D | set single | **fuckup** | set |
|
|
|
|
### CT_SETVARIABLE_NUMERIC_BYINPUT
|
|
* `Part2`: input type: `Text` / `Custom` (**case sensitive**)
|
|
* `Part3`: variable name + optional indices (case insensitive)
|
|
* `Part4`: custom choice title (**double replaced**)
|
|
* `Text`: ignored
|
|
* `EnhancedData`: one of the few functions that use it
|
|
* FIXUP: none
|
|
|
|
If input type is not one of the allowed values, it is treated as being `None`.
|
|
Largely the same as [CT_SETVARIABLEBYINPUT](#CT_SETVARIABLEBYINPUT), except it
|
|
shows a `Sorry, you must enter a valid number.` message with `Text` input when
|
|
you enter an invalid input (custom choices are not checked, you get an
|
|
**exception** when the code actually tries to set the value.
|
|
|
|
It sets the variable's number fields (with a possibility to **fuckup**), except
|
|
that it also handles `EnforceRestrictions`.
|
|
|
|
### CT_VARIABLE_SET_CUSTOM_PROPERTY {#CT_VARIABLE_SET_CUSTOM_PROPERTY}
|
|
* `Part2`: `variable_name:property_name` (case insensitive)
|
|
* `Part3`: `Equals` / `Add` / `Subtract` / `Multiply` / `Divide` (**case
|
|
sensitive**)
|
|
* `Part4`: value (**double replaced**)
|
|
* `Text`: ignored
|
|
* FIXUP: none
|
|
|
|
[See for more info on setting custom properties](#set-custom-property). It finds
|
|
a variable with name `variable_name` (case insensitively, without indices). If
|
|
it doesn't exist, it doesn't do anything.
|
|
|
|
### CT_VARIABLE_SET_CUSTOM_PROPERTY_JS
|
|
Same as [CT_VARIABLE_SET_CUSTOM_PROPERTY](#CT_VARIABLE_SET_CUSTOM_PROPERTY), but
|
|
with JavaScript.
|
|
|
|
### CT_VARIABLE_SET_RANDOMLY
|
|
* `Step2`: variable name + optional indices (case insensitive)
|
|
* `Step3`: ignored
|
|
* `Step4`: ignored
|
|
* `Text`: ignored
|
|
* FIXUP: none
|
|
|
|
If the variable doesn't exist, it doesn't do anything. It will always set number
|
|
fields, so using this on a non-number variable allows a **fuckup**. It generates
|
|
an integer random number between `[int32(double(min)), int32(double(max))+1)`
|
|
(string is first converted to double, then converted to int32 by rounding to
|
|
zero). Throws an error if the upper bound is smaller than the lower, returns min
|
|
when they're equal. Here is what happens when the number of indices doesn't
|
|
match the variable type:
|
|
|
|
| Var type | 0 idx | 1 idx | 2 idx |
|
|
|----------|------------|--------------------------------|----------------------|
|
|
| Single | set single | ignore/**exception** | ignore/**exception** |
|
|
| 1D | set single | set | **exception** |
|
|
| 2D | set single | **fuckup** | set |
|
|
|
|
### CT_VARIABLE_SET_WITH_CHARPROPERTYVALUE {#CT_VARIABLE_SET_WITH_CHARPROPERTYVALUE}
|
|
* `Step2`: variable name + optional indices (case insensitive)
|
|
* `Step3`: `character_name:property_name`
|
|
* `Step4`: ignored (**double replaced**)
|
|
* `Text`: ignored
|
|
* FIXUP: none
|
|
|
|
If the specified variable doesn't exist, it doesn't do anything. If `Step3`
|
|
doesn't exactly have one colon, or the character (case insensitively) doesn't
|
|
exist, or the custom property (**case sensitively**) doesn't exist, it is
|
|
treated as being an empty string. If the variable is a DateTime variable, it
|
|
doesn't do anything.
|
|
|
|
Here is what happens when the number of indices doesn't match the variable type:
|
|
| Var type | 0 idx | 1 idx | 2 idx |
|
|
|----------|------------|--------------------------------|----------------------|
|
|
| Single | set single | ignore/**exception** | ignore/**exception** |
|
|
| 1D | set single | set | **exception** |
|
|
| 2D | set single | **fuckup** | set |
|
|
|
|
In case of a number variable, if it is a "set single", the string value is
|
|
converted to a double, if it fails it prints some kind of debug log and does
|
|
nothing. In case of arrays, it just stores the string into the array (even in
|
|
case of an 1D array), for random **fuckup**s in the future.
|
|
|
|
### CT_VARIABLE_SET_WITH_ITEMPROPERTYVALUE
|
|
* `Step2`: variable name + optional indices (case insensitive)
|
|
* `Step3`: `object_name:property_name`
|
|
* `Step4`: ignored (**double replaced**)
|
|
* `Text`: ignored
|
|
* FIXUP: none
|
|
|
|
Copy-paste of
|
|
[CT_VARIABLE_SET_WITH_CHARPROPERTYVALUE](#CT_VARIABLE_SET_WITH_CHARPROPERTYVALUE),
|
|
but with objects instead of characters. Additionally, `object_name` can be
|
|
`<Self>` (**case sensitive**) to mean `action_object` if it is specified, it
|
|
uses empty string if it is not specified.
|
|
|
|
### CT_VARIABLE_SET_WITH_PLAYERPROPERTYVALUE
|
|
* `Step2`: variable name + optional indices (case insensitive)
|
|
* `Step3`: `property_name` (**case sensitive**)
|
|
* `Step4`: ignored (**double replaced**)
|
|
* `Text`: ignored
|
|
* FIXUP: none
|
|
|
|
Copy-paste of
|
|
[CT_VARIABLE_SET_WITH_CHARPROPERTYVALUE](#CT_VARIABLE_SET_WITH_CHARPROPERTYVALUE),
|
|
but with player instead of characters. `Step3` is treated as a property name,
|
|
even if it contains colons.
|
|
|
|
### CT_VARIABLE_SET_WITH_ROOMPROPERTYVALUE
|
|
* `Step2`: variable name + optional indices (case insensitive)
|
|
* `Step3`: `room_name:property_name`
|
|
* `Step4`: ignored (**double replaced**)
|
|
* `Text`: ignored
|
|
* FIXUP: none
|
|
|
|
Copy-paste of
|
|
[CT_VARIABLE_SET_WITH_CHARPROPERTYVALUE](#CT_VARIABLE_SET_WITH_CHARPROPERTYVALUE),
|
|
but with rooms instead of characters. Additionally, `room_name` can be
|
|
`<CurrentRoom>` (**case sensitively**) to mean the player's current room.
|
|
|
|
### CT_VARIABLE_SET_WITH_TIMERPROPERTYVALUE
|
|
* `Step2`: variable name + optional indices (case insensitive)
|
|
* `Step3`: `timer_name:property_name`
|
|
* `Step4`: ignored (**double replaced**)
|
|
* `Text`: ignored
|
|
* FIXUP: none
|
|
|
|
Copy-paste of
|
|
[CT_VARIABLE_SET_WITH_CHARPROPERTYVALUE](#CT_VARIABLE_SET_WITH_CHARPROPERTYVALUE),
|
|
but with timers instead of characters.
|
|
|
|
### CT_VARIABLE_SET_WITH_VARIABLE
|
|
* `Step2`: variable to set name + optional indices (case insensitive)
|
|
* `Part3`: `Equals` / `Add` / `Subtract` / `Multiply` / `Divide` / `Add Days` /
|
|
`Add Hours` / `Add Minutes` / `Add Seconds` / `Subtract Days` / `Subtract
|
|
Hours` / `Subtract Minutes` / `Subtract Seconds` / `Set Day Of Month To` /
|
|
`Set Hours To` / `Set Minutes To` / `Set Seconds To` (**case sensitive**)
|
|
* `Step4`: variable to read name + optional indices (case insensitive)
|
|
* `Text`: ignored
|
|
|
|
If the variable specified by `Step4` doesn't exist, it **throws an exception**.
|
|
Here is what happens when the number of indices doesn't match the variable type:
|
|
| Var type | 0 idx | 1 idx | 2 idx |
|
|
|----------|------------|-----------------------|-----------------------|
|
|
| Single | single val | garbage/**exception** | garbage/**exception** |
|
|
| 1D | single val | OK | **exception** |
|
|
| 2D | single val | **exception** | OK |
|
|
|
|
The variable is also treated as a number variable, even if not: in case of
|
|
single values, this will read garbage, with 1D it **throws an exception**, and
|
|
with 2D it tries to parse the stored string as a number and **throws an
|
|
excepton** if it fails.
|
|
|
|
With two indices, if the value is not an integer, it **throws an exception**. If
|
|
the value can not be represented as an int32 (after tuncation), it also **throws
|
|
an exception**.
|
|
|
|
If the variable specified by `Step2` doesn't exist, or it is a string variable,
|
|
it doesn't do anything.
|
|
|
|
Here is what happens generally when the number of indices doesn't match with
|
|
`Step2`:
|
|
| Var type | 0 idx | 1 idx | 2 idx |
|
|
|----------|------------|--------------------------------|----------------------|
|
|
| Single | set single | ignore/**exception** | ignore/**exception** |
|
|
| 1D | set single | set | **exception** |
|
|
| 2D | set single | **fuckup** | set |
|
|
|
|
With number variables, `Step4` is treated as a double, except with 2D arrays and
|
|
`Equal`, or single values and `Divide`, where it is treated as an integer. If
|
|
`Part2` is not `Equals`, `Add`, `Subtract`, `Multiply` or `Divide`, it doesn't
|
|
update the variable. `EnforceRestrictions` are handled on number variables, even
|
|
if there was no update.
|
|
|
|
DateTime with `Equals` is a buggy piece of shit. With not 2D arrays, it just
|
|
**throws an exception**, with 2D arrays, it sets the the number converted to
|
|
string, which rags later won't be able to parse back (so it's a kind of
|
|
**fuckup**). The rest date-related operations actually work though, but they
|
|
operate on the truncated integers (so you can't add 1.5 days to a DT).
|
|
|
|
### CT_VARIABLE_SET_WITH_VARIABLEPROPERTYVALUE
|
|
* `Step2`: variable name + optional indices (case insensitive)
|
|
* `Step3`: `timer_name:property_name`
|
|
* `Step4`: ignored (**double replaced**)
|
|
* `Text`: ignored
|
|
* FIXUP: none
|
|
|
|
Copy-paste of
|
|
[CT_VARIABLE_SET_WITH_CHARPROPERTYVALUE](#CT_VARIABLE_SET_WITH_CHARPROPERTYVALUE),
|
|
but with variables instead of characters.
|
|
|
|
### CT_ENDGAME
|
|
* `Step2`: ignored
|
|
* `Step3`: ignored
|
|
* `Step4`: ignored
|
|
* `Text`: display text
|
|
* FIXUP: none
|
|
|
|
Prints `Text` to the log and ends the game. It also displays a dialog box
|
|
<code>The game has ended. Would you like to play again?</code> (with two
|
|
spaces between the sentences) and buttons `Restart`, `Load` and `No`. Unless
|
|
selecting `Restart`, the remaining commands will be run.
|
|
|
|
# Condition
|
|
It has two subtypes, loop and if.
|
|
## Loop
|
|
* It has a single check, `CT_Loop_*`
|
|
* `PassCommands` will be called for each iteration, setting `loop_item`
|
|
* `FailCommands` are ignored
|
|
* `CT_LOOP_BREAK` can be used to break out of the innermost loop. However, if
|
|
break is inside a Condition's `PassCommands` or `FailCommads`, and there are
|
|
subsequent Commands in the same list, some later commands can cancel the
|
|
break. See the individual command documentations.
|
|
## If
|
|
* Normally it has one or more checks, neither of them being `CT_Loop_*`
|
|
* Rags designer doesn't allow you to create a condition with zero checks, but if
|
|
you manage to create one it will be regarded as true.
|
|
* However you can create an if with loops inside, if you want a bugfest: first,
|
|
the loop body will be executed when the check is evaluated. Second, they don't
|
|
modify the variable used to store the return value, so their "value" will be
|
|
whatever before them produced (or true if they're the first in the list).
|
|
Third, since they're not loops, `PassCommands` or `FailCommands` will be
|
|
executed after them, but without `loop_item`. For example, having an if with
|
|
"loop exits and loop exits", PassCommands will be executed 25 times (unless it
|
|
breaks): 12 times with the exits of the first room, 12 times with the exits of
|
|
the second room, then one more time without `loop_item`.
|
|
* `PassCommands` or `FailCommands` are executed depending on the check
|
|
* Handling multiple checks: every check has a `CkType`, but it's ignored for the
|
|
first check. For the rest, they kinda also short-circuit:
|
|
* `Or` check following a true: result is true, no other checks are executed.
|
|
* `And` check following a false: executing the `And` check is skipped, but
|
|
subsequent checks are still executed
|
|
This (I think) corresponds to `And` having higher precedence, so a list of
|
|
`Ignored, A`, `And, B`, `Or, C`, `And, D` is parsed as `(A && B) || (C && D)`.
|
|
|
|
## Generic check info
|
|
`Step2`, `Step3` and `Step4` values are always run through the [text replacement
|
|
function][] before usage.
|
|
|
|
Note for X in Y checks: rags store the location of the objects/characters by
|
|
string, so it's possible for an object/character to be in a
|
|
room/object/character that doesn't exists. Unfortunately this information is
|
|
lost during import to scraps.
|
|
|
|
### CustomPropertyChecks {#CustomPropertyChecks}
|
|
* `Step2`: colon separated pair: `name:custom_property_name`
|
|
* `Step3`: `Equals` / `Not Equals` / `Contains` / `Greater Than` / `Greater Than
|
|
or Equals` / `Less Than` / `Less Than or Equals` (**case sensitive**)
|
|
* `Step4`: value to compare with. **Double replaced!**
|
|
|
|
Interpretation of `name` varies, but generally if `Step2` doesn't have exactly
|
|
one colon, or the named entity doesn't exists, or it doesn't have a custom
|
|
property named `custom_property_name` (**case insensitively**), the check
|
|
**doesn't return anything**. If `Step3` is not one of the allowed values, it
|
|
**returns true**.
|
|
|
|
If both the custom property's value and `Step4` can be converted to a double,
|
|
they're treated as numbers otherwise as strings, except `Contains` which is
|
|
always string based. (This means that for example `012` equals to `12` but
|
|
`012x` doesn't equal to `12x`.) String compare is **REVERSED** and case
|
|
insensitive (i.e. `1 < 2` but `1x > 2x`). Returns the result of the comparison.
|
|
|
|
## Available ConditionTypes
|
|
### CT_Uninitialized
|
|
Not exactly a valid check, Rags will treat it as any other invalid option:
|
|
**don't return anything**.
|
|
|
|
### CT_AdditionalDataCheck
|
|
* `Step2`: object/character name to compare with (case insensitive)
|
|
* `Step3`: ignored
|
|
* `Step4`: text value to compare with (case insensitive)
|
|
|
|
Checks the value selected at the beginning of the action. If `InputType` is
|
|
`Text`, it compares the entered string with `Step4` (`Step2` is ignored in this
|
|
case). Otherwise, `Step4` is ignored and:
|
|
1. If selection and `Step2` equals, return true.
|
|
2. If there is an object named selection, returns `object.uuid == Step2`.
|
|
3. If there is a character named selection, returns `character.ToString() ==
|
|
Step2`, where `ToString` is `Name` if `NameOverride` is not empty, else
|
|
`Name` if we're outside a game (?), else `NameOverride` with text
|
|
replacements (!!).
|
|
4. If there is an object uuid matching the selection, returns `object.name ==
|
|
Step2`.
|
|
5. Otherwise returns false.
|
|
### CT_Character_CustomPropertyCheck
|
|
* `Step2`: `character_name:custom_property_name` (case insensitive)
|
|
* `Step3`: comparison type
|
|
* `Step4`: value
|
|
|
|
[See for more info on CustomPropertyChecks](#CustomPropertyChecks).
|
|
`character_name` is a name of a character.
|
|
|
|
### CT_Character_Gender
|
|
* `Step2`: character's name (case insensitive)
|
|
* `Step3`: `Male` / `Female` / anything else (**case sensitive**)
|
|
* `Step4`: ignored
|
|
|
|
If the character doesn't exist, **doesn't return anything**. If `Step3` is
|
|
neither `Male` nor `Female`, it's treated as `Other`. Returns whether the
|
|
character's gender equals to `Step3`.
|
|
|
|
### CT_Character_In_Room
|
|
* `Step2`: character's name (case insensitive)
|
|
* `Step3`: room's uuid (**case sensitive**). Special values (not parsed, must
|
|
match exactly):
|
|
* `00000000-0000-0000-0000-000000000001` :: player's current room
|
|
* `00000000-0000-0000-0000-000000000002` :: "void" room
|
|
* `Step4`: ignored
|
|
|
|
If the character doesn't exists, **throws an exception**. Returns whether the
|
|
character is currently in the specified room (see special values above).
|
|
|
|
### CT_Character_In_RoomGroup {#CT_Character_In_RoomGroup}
|
|
* `Step2`: character's name (case insensitive)
|
|
* `Step3`: room group or `None` (**case sensitive**)
|
|
* `Step4`: ignored
|
|
|
|
If the character doesn't exists, **throws an exception**. If the character is
|
|
not in a room, returns false. Returns whether character's current room's group's
|
|
name equals to `Step3` (use `None` to check if the room is not in any group).
|
|
|
|
_Note_: in rags, room groups are not recursive, but they are in scraps. To be
|
|
consistent with `CT_Item_InGroup` and `CT_MultiMedia_InGroup`, scraps does a
|
|
recursive check here aswell.
|
|
|
|
### CT_Item_CustomPropertyCheck
|
|
* `Step2`: `object_name:custom_property_name` (case insensitive)
|
|
* `Step3`: comparison type
|
|
* `Step4`: value
|
|
|
|
[See for more info on CustomPropertyChecks](#CustomPropertyChecks). If
|
|
`object_name` is `<Self>` (**case sensitively**), it refers to the hidden object
|
|
parameter, otherwise it is an object's name (case insensitively).
|
|
|
|
### CT_Item_InGroup {#CT_Item_InGroup}
|
|
* `Step2`: name of the object (case insensitive)
|
|
* `Step3`: group name (**case sensitive**)
|
|
* `Step4`: ignored
|
|
|
|
**This is buggy in designer!** Rags designer puts the object's uuid into
|
|
`Step2`, but the player expects an object name. To fix it, you have to *type*
|
|
the object name into the `Choose Item` box, and not select from the drop-down
|
|
menu.
|
|
|
|
**This operates directly on SQL**, not the in-memory structures (that gets
|
|
serialized into savegames). If there is no such object in the SQL, it is treated
|
|
as having an empty group name. If the object's group name equals to `Step3`,
|
|
returns true. Otherwise it gets the children of the specified group and
|
|
recursively checks all of them (same as getting the parent of the object group,
|
|
and recursively checking the parent groups, except much more inefficient).
|
|
Returns false if not found.
|
|
|
|
### CT_Item_Held_By_Character
|
|
* `Step2`: character name (**case sensitive**)
|
|
* `Step3`: object UUID or name (case insensitive)
|
|
* `Step4`: ignored
|
|
* FIXUP: if `Step3` can't be parsed as an UUID, and there is an object with that
|
|
name, replace `Step3` with the object's UUID.
|
|
|
|
If the object doesn't exist, returns false. Otherwise returns whether the
|
|
object's location is directly a character with the specified name (not
|
|
subobject).
|
|
|
|
### CT_Item_Held_By_Player
|
|
* `Step2`: object UUID or name (case insensitive)
|
|
* `Step3`: ignored
|
|
* `Step4`: ignored
|
|
* FIXUP: if `Step2` can't be parsed as an UUID, and there is an object with that
|
|
name, replace `Step2` with the object's UUID.
|
|
|
|
If the object doesn't exist, returns false. Otherwise returns whether the
|
|
object's location is a player with the specified name **or it is recursively
|
|
inside an object held by the player**.
|
|
|
|
### CT_Item_In_Object
|
|
* `Step2`: object UUID or name (case insensitive)
|
|
* `Step3`: other object's UUID (**case sensitive**)
|
|
* `Step4`: ignored
|
|
* FIXUP: if `Step2` can't be parsed as an UUID, and there is an object with that
|
|
name, replace `Step2` with the object's UUID.
|
|
|
|
If the object specified by `Step2` doesn't exists, return false. Otherwise
|
|
returns whether `Step2` is directly inside `Step3`.
|
|
|
|
### CT_Item_In_Room
|
|
* `Step2`: object UUID or name (case insensitive)
|
|
* `Step3`: room UUID (**case sensitive**). Special values (not parsed, must
|
|
match exactly):
|
|
* `00000000-0000-0000-0000-000000000001` :: player's current room
|
|
* `Step4`: ignored
|
|
* FIXUP: if `Step2` can't be parsed as an UUID, and there is an object with that
|
|
name, replace `Step2` with the object's UUID. Same with `Step3` and room.
|
|
|
|
If the object doesn't exists, returns false. Otherwise returns whether the
|
|
object is currently in the specified room (see special values above) directly
|
|
(i.e. not subobjects).
|
|
|
|
### CT_Item_In_RoomGroup
|
|
* `Step2`: object UUID (case insensitive)
|
|
* `Step3`: room group or `None` (**case sensitive**)
|
|
* `Step4`: ignored
|
|
|
|
If the object doesn't exists or it is not in a room, returns false. Returns
|
|
whether the object's current room's group's name equals to `Step3`.
|
|
|
|
[See also CT_Character_In_RoomGroup](#CT_Character_In_RoomGroup).
|
|
|
|
### CT_Item_Not_Held_By_Player
|
|
* `Step2`: object UUID or name (case insensitive)
|
|
* `Step3`: ignored
|
|
* `Step4`: ignored
|
|
* FIXUP: if `Step2` can't be parsed as an UUID, and there is an object with that
|
|
name, replace `Step2` with the object's UUID.
|
|
|
|
If the object doesn't exists, return false. Otherwise returns whether the object
|
|
is not in the player's inventory **DIRECTLY**. Consistency, where the fuck are
|
|
you!?
|
|
|
|
### CT_Item_Not_In_Object
|
|
* `Step2`: object UUID or name (case insensitive)
|
|
* `Step3`: other object's UUID (**case sensitive**)
|
|
* `Step4`: ignored
|
|
|
|
If the object specified by `Step2` doesn't exists, return false. Otherwise
|
|
returns whether `Step2` is not directly inside `Step3`.
|
|
|
|
### CT_Item_State_Check
|
|
* `Step2`: object UUID or name (case insensitive)
|
|
* `Step3`: `Open` / `Closed` / `Locked` / `Unlocked` / `Worn` / `Removed` /
|
|
`Read` / `Unread` / `Visible` / `Invisible` (**case sensitive**)
|
|
* `Step4`: ignored
|
|
* FIXUP: if `Step2` can't be parsed as an UUID, and there is an object with that
|
|
name, replace `Step2` with the object's UUID.
|
|
|
|
If the object doesn't exists, it returns false. Otherwise, if `Step3` is not one
|
|
of the allowed values, it **doesn't return anything**. Otherwise, returns
|
|
whether the object is in the specified state. (Every second item in the list is
|
|
the negation of the previous one, so `Closed` is checking for not `Open`,
|
|
`Removed` is checking for not `Worn`, etc.)
|
|
|
|
### CT_Loop_While
|
|
Parameters are the same as [CT_Variable_Comparison](#CT_Variable_Comparison),
|
|
execute `PassCommands` until variable comparison is true. `loop_item` is passed
|
|
through unmodified.
|
|
|
|
### CT_Loop_Characters
|
|
* `Step2`: ignored
|
|
* `Step3`: ignored
|
|
* `Step4`: ignored
|
|
|
|
Iterate through each character in the game (skipping player, since player is not
|
|
a character in rags), setting `loop_item`.
|
|
|
|
### CT_Loop_Items
|
|
* `Step2`: ignored
|
|
* `Step3`: ignored
|
|
* `Step4`: ignored
|
|
|
|
Iterate through each object in the game, setting `loop_item`.
|
|
|
|
### CT_Loop_Item_Group
|
|
* `Step2`: object group name (**case sensitive**)
|
|
* `Step3`: ignored
|
|
* `Step4`: ignored
|
|
|
|
Iterate through each object in the game. If the object is in the specified
|
|
object group directly, call `PassCommands` setting `loop_item`.
|
|
|
|
### CT_Loop_Item_Container
|
|
* `Step2`: object UUID (**case sensitive**)
|
|
* `Step3`: ignored
|
|
* `Step4`: ignored
|
|
|
|
Iterate through each object in the game. If the object is in the specified
|
|
object, call `PassCommands` setting `loop_item`.
|
|
|
|
### CT_Loop_Item_Room
|
|
* `Step2`: room UUID (**case sensitive**)
|
|
* `Step3`: ignored
|
|
* `Step4`: ignored
|
|
|
|
Iterate through each object in the game. If the object is in the specified
|
|
room, call `PassCommands` setting `loop_item`.
|
|
|
|
### CT_Loop_Item_Inventory
|
|
* `Step2`: ignored
|
|
* `Step3`: ignored
|
|
* `Step4`: ignored
|
|
|
|
Iterate through each object in the game. If the object is in the player's
|
|
inventory, call `PassCommands` setting `loop_item`.
|
|
|
|
### CT_Loop_Item_Char_Inventory
|
|
* `Step2`: character name (**case sensitive**)
|
|
* `Step3`: ignored
|
|
* `Step4`: ignored
|
|
|
|
Iterate through each object in the game. If the object is in the specified
|
|
character's inventory, call `PassCommands` setting `loop_item`.
|
|
|
|
### CT_Loop_Rooms
|
|
* `Step2`: ignored
|
|
* `Step3`: ignored
|
|
* `Step4`: ignored
|
|
|
|
Iterate through each room in the game, setting `loop_item`.
|
|
|
|
### CT_Loop_Exits
|
|
* `Step2`: room UUID (**can be parsed**) or name (case insensitive)
|
|
* `Step3`: ignored
|
|
* `Step4`: ignored
|
|
|
|
If the specified room doesn't exists, doesn't do anything. Otherwise call
|
|
`PassCommands` settings `loop_item` with each exit of the room (including
|
|
disabled ones, i.e. the loop will be executed exactly 12 times, unless broken).
|
|
|
|
### CT_MultiMedia_InGroup
|
|
* `Step2`: name of the object (case insensitive)
|
|
* `Step3`: group name (**case sensitive**)
|
|
* `Step4`: ignored
|
|
|
|
Works similarly to [CT_Item_InGroup](#CT_Item_InGroup).
|
|
|
|
### CT_Player_CustomPropertyCheck
|
|
* `Step2`: `custom_property_name`
|
|
* `Step3`: comparison type
|
|
* `Step4`: value
|
|
|
|
[See for more info on CustomPropertyChecks](#CustomPropertyChecks). Since there
|
|
is only one player in rags, `Step2` only contains a custom property name. Colons
|
|
are treated as part of the property name!
|
|
|
|
### CT_Player_Gender
|
|
* `Step2`: `Male` / `Female` / anything else (**case sensitive**)
|
|
* `Step3`: ignored
|
|
* `Step4`: ignored
|
|
|
|
If `Step2` is neither `Male` nor `Female`, it's treated as `Other`. Returns
|
|
whether the player's gender equals to `Step2`.
|
|
|
|
### CT_Player_In_Room
|
|
* `Step2`: room's UUID (**case sensitive**). Special values (not parsed, must
|
|
match exactly):
|
|
* `00000000-0000-0000-0000-000000000002` :: "void" room (crashes rags if you
|
|
actually manage to put the player here, so probably can be ignored)
|
|
* `Step3`: ignored
|
|
* `Step4`: ignored
|
|
* FIXUP: if `Step2` can't be parsed as an UUID, and there is a room with that
|
|
name, replace `Step2` with the room's UUID.
|
|
|
|
Returns whether the player is currently in the specified room.
|
|
|
|
### CT_Player_In_RoomGroup
|
|
* `Step2`: room group or `None` (**case sensitive**)
|
|
* `Step3`: ignored
|
|
* `Step4`: ignored
|
|
|
|
(If the player is not in a room, throws an exception.) Returns whether player's
|
|
current room's group's name equals to `Step2`.
|
|
|
|
[See also CT_Character_In_RoomGroup](#CT_Character_In_RoomGroup).
|
|
|
|
### CT_Player_In_Same_Room_As
|
|
* `Step2`: character name (case insensitive)
|
|
* `Step3`: ignored
|
|
* `Step4`: ignored
|
|
|
|
If the character doesn't exists, **throws an exception**. Returns whether the
|
|
player and the specified character is in the same room.
|
|
|
|
### CT_Player_Moving
|
|
* `Step2`: `Empty` / `North` / `South` / ... (**case sensitive**)
|
|
* `Step3`: ignored
|
|
* `Step4`: ignored
|
|
|
|
If `Step2` is not a valid direction, **throws an exception**. Otherwise checks
|
|
whether the player currently moves in the specified direction (only in room's on
|
|
player leave events, otherwise the player is moving in the `Empty` direction).
|
|
|
|
### CT_Room_CustomPropertyCheck
|
|
* `Step2`: `room_uuid:custom_property_name` (case insensitive)
|
|
* `Step3`: comparison type
|
|
* `Step4`: value
|
|
|
|
[See for more info on CustomPropertyChecks](#CustomPropertyChecks). `room_uuid`
|
|
can be `<CurrentRoom>` (**case sensitively!**) to mean the player's room,
|
|
otherwise it is a room uuid.
|
|
|
|
### CT_Timer_CustomPropertyCheck
|
|
* `Step2`: `timer_name:custom_property_name` (case insensitive)
|
|
* `Step3`: comparison type
|
|
* `Step4`: value
|
|
|
|
[See for more info on CustomPropertyChecks](#CustomPropertyChecks). `timer_name`
|
|
is a name of a timer.
|
|
|
|
### CT_Variable_Comparison {#CT_Variable_Comparison}
|
|
* `Step2`: variable name + optional indices (case insensitive)
|
|
* `Step3`: `Equals` / `Not Equals` / `Greater Than` / `Greater Than or Equals` /
|
|
`Less Than` / `Less Than or Equals` / `Contains` / `DayOfWeek Is` / `Hour
|
|
Equals` / `Hour Is Greater Than` / `Hour Is Less Than` / `Minute Equals` /
|
|
`Minute Is Greater Than` / `Minute Is Less Than` / `Seconds Equals` / `Seconds
|
|
Is Greater Than` / `Seconds Is Less Than` (**case sensitive**)
|
|
* `Step4`: value to compare with. **Double replaced!**
|
|
|
|
Optional index handling: everything before the first `(` is the variable name,
|
|
without trimming. (No `(` -> full string is the variable name.) There is a `(`
|
|
and a `)` afterwards: everything between them is converted to int32, if fails
|
|
treat as no index. There is a second `(` and a `)` afterwards: do the same
|
|
conversion. Examples: `foo(0)(0)` -> name `"foo"`, indices 0 and 0. `foo((2)` ->
|
|
name `"foo "`, indices invalid and 2.
|
|
|
|
If the variable does not exists, **returns true**. Here is what happens when the
|
|
number of indices specified doesn't match the variable type (invalid first and
|
|
valid second indices: 2 idx, but later exception due to out of range):
|
|
| Var type | 0 idx | 1 idx | 2 idx |
|
|
|------------|---------|--------------------------------|-----------------------|
|
|
| Num single | OK | garbage/**exception** | garbage/**exception** |
|
|
| Num 1D | garbage | OK | **exception** |
|
|
| Num 2D | garbage | **exception** | OK |
|
|
| Str single | OK | garbage/**exception** | garbage/**exception** |
|
|
| Str 1D | garbage | OK | **exception** |
|
|
| Str 2D | garbage | `System.Collections.ArrayList` | OK |
|
|
| DT single | OK | garbage/**exception** | garbage/**exception** |
|
|
| DT 1D | garbage | OK | **exception** |
|
|
| DT 2D | garbage | **exception** | OK |
|
|
|
|
Explanations:
|
|
* Garbage in 0 idx column: rags doesn't store variable values in a union, and
|
|
selecting a different type in rags designer doesn't clear out the values
|
|
stored for other types. It also treats array and single as separate types.
|
|
Thus when not specifying any index, rags will use this single type's value
|
|
with whatever garbage value left behind. Scraps emulates this behavior.
|
|
* garbage/exception: similar to the previous. If the variable happen to have a
|
|
garbage array data, it will use it, otherwise exception. Scraps always throws
|
|
an exception in this case.
|
|
* `System.Collections.ArrayList`: rags will treat the variable as having this
|
|
value.
|
|
|
|
If the index is out of range, it **throws an exception**. If `Step2` has an
|
|
index, the value used to store single number values (refer to garbage in 0 idx
|
|
column above) is **overwritten** with the current array cell value. (Unlike
|
|
`CT_Variable_To_Variable_Comparison`, this is done for every type, not just
|
|
numbers).
|
|
|
|
If an unknown/invalid comparison type is specified, it **returns true**.
|
|
Different variable types support an arbitrary subset of the possible comparisons
|
|
(O=supported, X=not supported):
|
|
| Comparison | Num | Str | DT |
|
|
|---------------------------|-----|-----|----|
|
|
| `Equals` | O | O | O |
|
|
| `Not Equals` | O | O | O |
|
|
| `Greater Than` | O | O | O |
|
|
| `Greater Than or Equals` | O | X | O |
|
|
| `Less Than` | O | O | O |
|
|
| `Less Than or Equals` | O | X | O |
|
|
| `Contains` | X | O | X |
|
|
| `DayOfWeek Is` | X | X | O |
|
|
| `Hour Equals` | X | X | O |
|
|
| `Hour Is Greater Than` | X | X | O |
|
|
| `Hour Is Less Than` | X | X | O |
|
|
| `Minute Equals` | X | X | O |
|
|
| `Minute Is Greater Than` | X | X | O |
|
|
| `Minute Is Less Than` | X | X | O |
|
|
| `Seconds Equals` | X | X | O |
|
|
| `Seconds Is Greater Than` | X | X | O |
|
|
| `Seconds Is Less Than` | X | X | O |
|
|
|
|
In case of a number variable, `Step4` is converted to a double, if it fails it
|
|
**throws an exception**. In case of a string variable, formatting macros are
|
|
stripped from the variable's value ([see text.md for
|
|
details](text.md#strip-format)), but not from `Step4`. Comparison is case
|
|
insensitive. In case of a DateTime variable, normal comparisons are parsed with
|
|
.NET's super permissive parser, hour/minute/second checks are parsed as int32,
|
|
if it fails it **throws an exception**. DayOfWeek check is special, `Step4` is
|
|
one of `Sunday` / `Monday` / `Tuesday` / `Wednesday` / `Thursday` / `Friday` /
|
|
`Saturday` (checked case insensitively).
|
|
|
|
Finally it returns the result of the comparison.
|
|
|
|
### CT_Variable_To_Variable_Comparison
|
|
* `Step2`: variable name + optional indices (case insensitive)
|
|
* `Step3`: `Equals` / `Not Equals` / `Greater Than` / `Greater Than or Equals` /
|
|
`Less Than` / `Less Than or Equals` (**case sensitive**)
|
|
* `Step4`: variable name + optional indices (case insensitive)
|
|
|
|
If the variable specified by `Step4` doesn't exists, **throws an exception**. If
|
|
`Step4` is a DateTime variable, it is treated as having an empty string as
|
|
value. Here is what happens, when the number of indices specified in `Step4`
|
|
doesn't match the variable type:
|
|
| Var type | 0 idx | 1 idx | 2 idx |
|
|
|----------|---------|--------------------------------|-----------------------|
|
|
| Single | OK | garbage/**exception** | garbage/**exception** |
|
|
| 1D | garbage | OK | **exception** |
|
|
| 2D | garbage | `System.Collections.ArrayList` | OK |
|
|
|
|
See [the previous section for explanations](#CT_Variable_Comparison). Rags
|
|
converts number values to string, this is why you have
|
|
`System.Collections.ArrayList` even with numbers.
|
|
|
|
If the variable specified by `Step2` doesn't exists or it is a DateTime
|
|
variable, it **doesn't return anything**. Here is what happens when the indices
|
|
don't match, this time for `Step2`:
|
|
|
|
| Var type | 0 idx | 1 idx | 2 idx |
|
|
|------------|---------|--------------------------------|-----------------------|
|
|
| Num single | OK | garbage/**exception** | garbage/**exception** |
|
|
| Num 1D | garbage | OK | **exception** |
|
|
| Num 2D | garbage | **exception** | OK |
|
|
| Str single | OK | garbage/**exception** | garbage/**exception** |
|
|
| Str 1D | garbage | OK | **exception** |
|
|
| Str 2D | garbage | `System.Collections.ArrayList` | OK |
|
|
|
|
If `Step3` does not have an allowed value (string variables only support
|
|
`Equals` and `Not Equals`), it **doesn't return anything**.
|
|
|
|
In case of a number variable, the string representation of whatever that was
|
|
read from `Step4` is converted to a double, if this fails it is treated as
|
|
`0.0`. If `Step2` has an index, the value used to store single number values
|
|
(refer to garbage in 0 idx column above) is **overwritten** with the current
|
|
array cell value. (This does not happen with string vars!) Afterward, it returns
|
|
the value of the comparison.
|
|
|
|
In case of a string variable, formatting macros are stripped from `Step2`'s
|
|
value ([see text.md for details](text.md#strip-format)), but not from `Step4`,
|
|
then they're compared for equality. (Less than, greater than not supported).
|
|
|
|
### CT_Variable_CustomPropertyCheck
|
|
* `Step2`: `variable_name:custom_property_name` (case insensitive)
|
|
* `Step3`: comparison type
|
|
* `Step4`: value
|
|
|
|
[See for more info on CustomPropertyChecks](#CustomPropertyChecks).
|
|
`variable_name` is a name of a variable and can contain indices, but they're
|
|
ignored.
|
|
|
|
[text replacement function]: text.md#replacement
|