Menu System 2 (Second Life)
From Grigbertz
Menu System 2 is a note-card-configured system for making easily interchangeable and configurable menu trees in second Life objects.
Roles
The avatars that use the menu system can have one or more of the following roles in the menu system:
- Privileged
- Operator
- Owner
- Other
What role(s) an avatar has can be used to decide what version of a menu to show, or whether to show a button or not.
The roles of various avatars are based on linked messages sent to the menu system by other scripts in the object.
Privileged
Only a single user can be privileged. That user has done something to earn her special rights, such as being the owner of the single key to an object.
Operator
Operator is anyone that has more than normal rights to operate an object, such as being the only ones that can change its configurations. Normally, a list of operators is configured in a separate note card.
Owner
Owner is the SL owner of the object in question.
Other
Other is anyone that has none of the other roles above.
Note Card Format
The note card may contain the following type of lines:
- Blank lines
- Comments
- Configuration Variable Settings
- Menu Definitions.
Blank lines and comment lines are ignored when reading the notecard, and not stored in memory.
The name of the note card to be read is taken from the name of the menu system script itself, so to change what card is used, just change the name of the script and reset it. The note card name is appended to the script name after a colon, like this:
MenySystem:MenuConfig
This enables more than one menu system to be used in the same object, running side-by-side.
Comment Lines
Comment lines starts with '#' in the first position.
Configuration Varables
Configuration Variable lines are defined as name '=' value. Names are case independent.
The following variables are currently defined:
- defaultanimation
- animationclientname
Configuration variables are for the menu system itself, not for its contents, so they should not be confused with the display variables defined later.
Menu Definitions
Menu Definitions consist of:
- Menu Name
- Description
- Button Definitions
Menu Name
The definition starts with the menu name surrounded by triple hyphens, like this:
---main---
The definition ends with the start of the next menu definition, or by just three hyphens on their own:
---
Menu Names and Roles
When a menu has a special definion for only a given role of users, that role can be given after the menu name itself, like this:
---main operator---
When the user has a specific role, the system first looks for menu name with role, and if it cannot find it, it looks for just the menu name.
The following roles are defined:
- owner
- operator
- other
Description
Description lines start with an asterisk, like this:
* This is a * multi-line * description
Newlines are significant, so the three lines above will show as three lines in the dialog box.
Descriptions and variable substitution
Descriptions can have display variables in them. These variables are sent to the menu system by the other scripts in the object as link messages. When the menu dialog box is to be shown, the variables are looked up and inserted into the description.
Variables are written into the description as dollar-brace name brace-dollar, like this:
${name}$
A short number of variables are predefined, and not sent by other scripts. Those are:
- owner - object owner name
- object - object name
Like this:
* ${object}$ is owned by ${owner}$
Conditional variable substitution
Conditionals (see below) can also be used in menu descriptions, using this construction:
${condition?string if true:string if false}$
This allows you to write things like this in descriptions
* Choose operator's buttons settings. * Current settings: * - ${isLocked?The button is not detachable.:The button is detachable.}$ * - ${isPublic?The button's on/off-messages are public.:The button's on/off-messages are private.}$ * - ${isPressSelf?The wearer can self press the button.:The wearer can not press the button.}$
Note the different strings for true and false conditions.
Button definitions
Buttons are defined by first a single button line, followed by any number of command lines.
The button line consists of the button label within brackets, followed by a number of modifiers separated by vertical bar:
[Lock] ifnot locked | hideinactive | keepmenu
The command lines consist of a command, followed by a list of arguments, separated by vertical bars.
regionsay | 0 | Hello World!
Both button lines and command lines can have any number of spaces surrounding the vertical bars.
Button Modifiers
Button modifiers consists of an optional condition expression, an optional "endmenu", and/or an optional "hideinactive". These may come in any order.
Button Condition Expression Modifier
The button condition expression governs whether the button should be displayed in the menu. The other scripts in the onject can send named conditions to the menu system, indicating any state of the object that should reflect in the buttons. The condition expression combines these named conditions, and use that combination to choose if the button is shown.
The possible expressions are:
- if condition
- ifnot condition
- ifanyof condition condition ... condition
- ifallof condition condition ... condition
- ifnoneof condition condition ... condition
If any more complex logical combination is needed than those above, the state-maintaining script better define that combination as a single new condition and send that one.
Negating a Condition
A condition can be negated by preceding it with a "!". This is useful when writing toggle buttons. For example:
[Free] if isLocked messagelinkedset | setLockOn [Lock] if !isLocked messagelinkedset | setLockOff
Special role conditions
The following conditions can be used in expressions above, even if they have not been sent to the menu system through linked messages. They are instead derived from the menu user's role(s).
- isPrivileged
- isOperator
- isOwner
- isOther
For example, the below button pair is only available if the current user is an operator:
[Lock] ifallof isOperator !isLocked messagelinkset | lock [Unlock] ifallof isOperator isLocked messagelinkset | unlock
Hide Inactive Modifier
This modifier chooses how a button whose condition is not met is displayed.
If the "hideinactive" modifier is given, then the menu system totally removes the button. If it is not there, a blank button is instead shown when the condition is not met.
End Menu Modifier
The "endmenu" modifier governs the menu persistence. If it is present, the menu will not be re-displayed after after the button is pressed.
Commands
The following commands are available:
Name | Argument 1 | Argument 2 | Function |
menu | menu name | Replaces this menu with the named one (optionally modified by the user role, see menu name above) | |
none | A no-op. | ||
animateuser | animation name | Animates the agent using the menu. | |
animatesitter | animation name | Animates the agent sitting on this object. | |
stopanimation | Stops the latest animation this object activated on the agent using the menu. | ||
stopallanimations | Stops the all animations on the agent using the menu. | ||
messagelinkset | message | Send a message to all scripts in all prims in the same objects. | |
messagelinkthis | message | Send a message to all scripts in the same prim in the same objects. | |
regionsay | channel | message | Shout a message all over the region. |
say | channel | message | Say a message in the local area. |
rlv | rlv string | Send a RLV string to the client of the object's owner, if RLV is activated. |
Communication
Channels Listened to
The Menu system sets up a random channel to listen to for each menu definition. This makes it able to separate buttons with the same label, but in different menus, from each other.
Touch
The Menu System does not itself listen to touch events. Other scripts in the object must send a linked message (see below) to display the first menu.
Linked Messages Listened to
The menu system listens to a number of linked messages
Name | Argument(s) | Function | Example Call |
menu | menuname | Display the given menu | llMessageLinked(LINK_THIS, 0, "menu " + menuName, agentKey); llMessageLinked(LINK_THIS, 0, "menu main", agentKey); |
setSitter | Set the key of the agent sitting on this object. | llMessageLinked(LINK_THIS, 0, "setSitter", agentKey); | |
removeSitter | Remove the key of the agent sitting on this object. | llMessageLinked(LINK_THIS, 0, "removeSitter", NULL_KEY); | |
setConditions | space-separated list of conditions | Set all conditions that apply. | llMessageLinked(LINK_THIS, 0, "setConditions " + llDumpList2String(conditionList, " "), NULL_KEY); llMessageLinked(LINK_THIS, 0, "setConditions locked seated muted", NULL_KEY); |
addConditions | space-separated list of conditions | Add these conditions to those that apply. | llMessageLinked(LINK_THIS, 0, "addConditions " + llDumpList2String(conditionList, " "), NULL_KEY); llMessageLinked(LINK_THIS, 0, "addConditions bound hogtied", NULL_KEY); |
removeConditions | space-separated list of conditions | Remove these conditions from those that apply. | llMessageLinked(LINK_THIS, 0, "removeConditions " + llDumpList2String(conditionList, " "), NULL_KEY); llMessageLinked(LINK_THIS, 0, "removeConditions bound locked", NULL_KEY); |
setVariableValue | name and URL-encoded value, separated by space. | Set this display variable for inclusion in menu descriptions. | llMessageLinked(LINK_THIS, 0, "setVariableValue" + name + " " + llEscapeURL(value), NULL_KEY); llMessageLinked(LINK_THIS, 0, "setVariableValue region Lugubris", NULL_KEY); |
useDefaultAnimation | Use the animation configured as default on the supplied avatar. | llMessageLinked(LINK_THIS, 0, "useDefaultAnimation", avatarKey); | |
addOperator | givenname familyname | Gives the named avatar the operator role. | llMessageLinked(LINK_THIS, 0, "addOperator " + name, NULL_KEY); llMessageLinked(LINK_THIS, 0, "addOperator Tuft Meili", NULL_KEY); |
removeOperator | givenname familyname | Revokes the operator role from the named avatar. | llMessageLinked(LINK_THIS, 0, "removeOperator " + name, NULL_KEY); llMessageLinked(LINK_THIS, 0, "removeOperator Tuft Meili", NULL_KEY); |
deleteOperators | Revokes all operator roles. | llMessageLinked(LINK_THIS, 0, "deleteOperators", NULL_KEY); | |
setPrivileged | givenname familyname | Gives the named avatar the privileged role. | llMessageLinked(LINK_THIS, 0, "setPrivileged" + name, NULL_KEY); llMessageLinked(LINK_THIS, 0, "setPrivilegedTuft Meili", NULL_KEY); |
removePrivileged | Revokes the privileged role from the avatar currently having it. | llMessageLinked(LINK_THIS, 0, "removePrivileged", NULL_KEY); |
Examples
Handing over to another instance
You can have several instances of the menu system running in the same object, handling different branches of the menu tree.
Normally, you hand over to another submenu with:
[button] menu | newmenu
To call another menu system, instead use a linked message:
[button] endmenu messagelinkset | menu newmenu
Sinde we want this menu system to stop its menus, we use the button modifier "endmenu".