This is a breakdown of a scripted HUD I created for Secondlife, and the explanation of how its parts work that can be used for the creation of future HUDs.
I am not a professional coder, I learned lsl scripting in June 2023 (with the help of chatGPT that helped explaining some core concepts), but I wanted to create a HUD that works with particle effects during dance choreographies.
If you find this information useful, please make sure to buy the HUD on mp as a token of your appreciation:
If a sound is triggered using llPlaySound(), only the HUD wearer will hear it. If the land parcel they’re over restricts sound entry/exit, the sound will not play.
- If a sound is triggered using llTriggerSound(), the wearer and any bystanders will hear it.
HUD features:

HUD texture (512×512)

HUD in build mode in SL

HUD's structure explanation
The HUD consist of a central prim and many linked prims that function as buttons and also as the container of floating displayed text.
There is one script within each linked button that is triggered when a button is touched:
Button script

When each button is touched,
- the linkNumber (identification number of the linked Prim based on the order of linking when the objects are linked.)
- and the buttonName (linkName)
- are both sent in a Message to the root prim.
All other functions are arranged by the script in the root prim.
default
{
touch_start(integer total_number)
{
integer linkNumber = llGetLinkNumber();
string buttonName = llGetLinkName(LINK_THIS);
llMessageLinked(LINK_ROOT, linkNumber, buttonName, "");
}
}
Naming system for buttons:
Color button names:
- Start_Color
- End_Color
- End_Color_Sample
- Start_Color_Sample
Arrow and Default button names:
Particle parameters types are BurstCount, BurstRate, Glow, Alpha and Acceleration
- “ParticleParameterType”_Default
- “ParticleParameterType”_Increase
- “ParticleParameterType”_Decrease
- “ParticleParameterType”_Activate
Timer and Particle Controller Buttons:
- Timer_Controller_START
- Timer_Controller_STOP
- TimeAndParticles_Controller_START
- TimeAndParticles_Controller_STOP
- Particles_Controller_START
- Particles_Controller_STOP
HUD root script
Global Variables
activeMessage is a string that is parsed each time a button is pressed. Each time a button is pressed, its name is sent to the listener: the main HUD, its channel number is an integer called listen_Channel.
The HUD uses a timer, and we have an integer that stores it state: is_Timer_ON.
For maximizing and miimizing the HUD, we are storing some further variables rleated to rotation: maxRot, minRot and currentRot.
string activeMessage;
integer listen_Channel = 689689;
integer is_Timer_ON;
//HUD rotation variables
rotation maxRot = <0.00000, 0.00000, 0.00000, 1.00000>; // HUD Maximized
rotation minRot = <0.00000, -0.70711, 0.00000, 0.70711>; // HUD Minimized
rotation currentRot = maxRot;
Hover Effects
//Creates a visual effect where the specified link (button or object) briefly appears fully opaque for 0.2 seconds and then becomes fully transparent again.
brief_HoverEffect_Alpha (integer senderNUMBER)
{
//set of button 100% for 0.2 seconds, face 4
llSetLinkAlpha(senderNUMBER, 1.0, 4);
llSleep(0.2);
llSetLinkAlpha(senderNUMBER, 0.0, 4);
}
//Creates a visual effect where the specified link (button or object) briefly changes color for 0.2 seconds and then resets
brief_HoverEffect_Color (integer senderNUMBER)
{
//set of button 100% for 0.2 seconds, face 4
llSetLinkColor(senderNUMBER, <1.0, 1.0, 1.0>, ALL_SIDES);
llSleep(0.1);
llSetLinkColor(senderNUMBER, <0.86, 0.68, 0.36>, ALL_SIDES);
}
Clear/Populate Hover Text
Maybe these two functions could be combined, I will need to look itno this:
clearHoverText()
{
// Get all linked prims
integer linkCount = llGetNumberOfPrims();
// Iterate through each prim
integer linkNum;
for (linkNum = 1; linkNum <= linkCount; linkNum++)
{
// Get the prim name
string primName = llGetLinkName(linkNum);
// Check if the prim is a Display prim
if (llSubStringIndex(primName, "Display") != -1)
{
// Clear the prim's hover text
llSetLinkPrimitiveParamsFast(linkNum, [ PRIM_TEXT, "",ZERO_VECTOR, 0]);
}
}
}
populateHoverText()
{
// Get all linked prims
integer linkCount = llGetNumberOfPrims();
// Iterate through each prim
integer linkNum;
for (linkNum = 1; linkNum <= linkCount; linkNum++)
{
// Get the prim name
string primName = llGetLinkName(linkNum);
// Check if the prim is a Display prim
if (llSubStringIndex(primName, "Display") != -1)
{
// Get the prim's description
list primParamList = llGetLinkPrimitiveParams(linkNum, [ PRIM_DESC, PRIM_COLOR, ALL_SIDES ]);
string primDescription = llList2String(primParamList, 0);
vector tempColor = llList2Vector(primParamList,1);
// Set the prim's hover text to the description text with gained color
llSetLinkPrimitiveParams(linkNum, [ PRIM_TEXT, primDescription, tempColor, 1.0 ]);
}
}
}
Check Prim Name
This is needed to identify which button is pressed on the HUD. You must name the buttons properly and build the relevant functions afterward.
//Allows you to determine if a given string starts with a specific pattern. It returns TRUE (1) if the string starts with the pattern and FALSE (0) if it does not.
//example: check if prim name starts with string pattern ("Acceleration")
integer CheckPrimName(string stringtoTest , string pattern)
{
integer result;
// Get the substring from the start of the string with the same length as the pattern
string substring = llGetSubString(stringtoTest, 0, llStringLength(pattern) - 1);
if (substring == pattern)
{
// The string starts with "Acceleration"
result = TRUE;
}
else
{
// The string does not start with "Acceleration"
result = FALSE;
}
return result;
}
Vector to String
This is needed to be able to display the vectors on the HUD as text.
//Takes a string representation of a vector, parses it into a list, and extracts the desired element (x, y, or z) based on the listNumber parameter. If the parsed list does not have three elements, an error message is sent to the owner, and the function returns 0.0.
//vector component = listNumber: x = 0, y=1, z=2
float ParseStringVector2String(string StringVector2Parse, integer listNumber)
{
// Remove the angle brackets ("<" and ">") from the vector string
string cleanedString = llDeleteSubString(StringVector2Parse, 0,0);
cleanedString = llDeleteSubString(cleanedString, -1,-1);
// Parse the cleaned string into a list using comma (",") as the delimiter
list vectorList = llParseString2List(cleanedString, [","], []);
// Check if the list has three elements (x, y, z)
if (llGetListLength(vectorList) == 3)
{
// Extract the three Float values from the list
float FloatResult = llList2Float(vectorList, listNumber);
return FloatResult;
}
else
{
llOwnerSay("Invalid vector string format: " + StringVector2Parse);
return 0.0;
}
}
Updating part of a Vector data
Some particles parameters like acceleration are expressed in vector format. (three float values together). The HUD allows to modify float values individually, and we will need to update the vector value based on the updated floats.
//Vector updater with new data
//takes a vector, converts it to a list, replaces the float value at the specified index with a new value, and then converts the modified list back to a vector. It returns the modified vector as the result.
vector ReplaceFloatInVector(vector originalVector, float replacementValue, integer index)
{
// Convert the original vector to a list
list vectorList = [originalVector.x, originalVector.y, originalVector.z]; ;
// Replace the Float value at the specified index in the list
vectorList = llListReplaceList(vectorList, [replacementValue], index, index);
// Convert the modified list back to a vector
vector modifiedVector = llList2Vector(vectorList, 0);
return modifiedVector;
}
Formating floats (with rounding)
//converts a float value to a string, extracts the integer and decimal parts, truncates or pads the decimal part to the desired decimal places, concatenates the parts, and returns the formatted string representation of the float value.
string formatFloat(float value, integer decimalPlaces)
{
//llOwnerSay("formatFloat Function Triggered.");
// Convert the Float value to a string
string stringValue = (string)value;
// Find the position of the decimal point
integer decimalPos = llSubStringIndex(stringValue, ".");
// Get the integer part of the Float value
string integerPart = llGetSubString(stringValue, 0, decimalPos - 1);
// Get the decimal part of the Float value
string decimalPart = llGetSubString(stringValue, decimalPos + 1, -1);
// Truncate or pad the decimal part to the desired decimal places
if (llStringLength(decimalPart) > decimalPlaces)
{
decimalPart = llGetSubString(decimalPart, 0, decimalPlaces - 1);
}
else
{
while (llStringLength(decimalPart) < decimalPlaces)
{
decimalPart += "0";
}
}
// Concatenate the parts with a dot
string result = integerPart + "." + decimalPart;
//llOwnerSay("formatFloat Function result: "+result);
return result;
}
Get Prim Number
This is needed to be able to determine the linked prim’s number to be able to target it.
//returns: currentLinkNumber
//searches for a specific prim in the linkset based on the provided parameters and returns the link number of the matching prim
integer GetPrimNumber ( string current_Param, string current_Action, string current_DetailString )
{
//Debug Test message
//llOwnerSay("GetPrimNumber Function Triggered");
integer linkNum = llGetNumberOfPrims();
integer currentLinkNumber = 999; // Default value if no match is found
integer matchFound = FALSE; // Flag to indicate if a match is found
if (current_DetailString != "")
{
current_Action = current_Action+"_"+current_DetailString;
}
integer i = 0;
while (i <= linkNum && !matchFound)
{
string LinkName = llGetLinkName(i);
if (LinkName == current_Param + "_" + current_Action)
{
currentLinkNumber = i;
matchFound = TRUE;
}
i++;
}
//llOwnerSay((string)currentLinkNumber+" primnumber is found.");
if (currentLinkNumber == 999)
{
llOwnerSay("Something is wrong with finding " +current_Param + "_" + current_Action +" button!");
}
return currentLinkNumber;
}
Get Prim Description
We are storing the activated values in the prim descriptions, we need the info when populating the HUD with updated hovering text
// Uses GetPrimNumber to retrieve the link number and then retrieves the primitive description of that prim.
string GetPrimDescription (string current_Param, string current_Action, string current_DetailString )
{
integer linkNumber = GetPrimNumber ( current_Param, current_Action, current_DetailString );
list DescriptionList = llGetLinkPrimitiveParams(linkNumber, [ PRIM_DESC ] );
string Description = llList2String(DescriptionList, 0);
return Description;
}
Defining increments for parameters
//determines the value of the increment based on the provided parameters current_Param and current_Action.
// Burst Count - 1
// StartGlow - 0.01
// all other - 0.1
float GetIncrement(string current_Param, string current_Action)
{
//Debug Test message
//llOwnerSay("increment Function Triggered");
float Increment;
if (current_Param == "BurstCount")
{
Increment = 1;
}
else if (current_Param == "StartGlow")
{
Increment = 0.01;
}
else
{
Increment = 0.1;
}
if (current_Action == "Decrease")
{
Increment = -Increment;
}
return Increment;
}
Display
This is a complex function that determines the match_Value, sets the color for the text based on the matching condition, and displays the text and updates the description for the relevant display prims based on the current_Action.
It is called with the following parameters (variables as input)
- current_Action,
- current_Param,
- current_Value,
- activated_Value,
- current_DetailString
It starts checking if the current_Param is
- Acceleration
and if the current_Action is either
- Increase
- Decrease
This check for Acceleration is needed to be done first, because Acceleration values are vectors and have to be handled a little differently than simple floats.
//determines the match_Value, sets the color for the text based on the matching condition, and sets the text and updates the description for the relevant display prims based on the current_Action.
Display (string current_Action, string current_Param, string current_Value, string activated_Value, string current_DetailString)
{
//Debug Test message
//llOwnerSay("Display Function Triggered. current_Action is: "+current_Action+" current_Param is: "+current_Param+" current_Value is:"+current_Value+" activated_Value is: "+activated_Value+" current_DetailString is: "+current_DetailString);
string match_Value;
//check if primname starts with "Acceleration"
integer currentParam_isAcceleration = CheckPrimName(current_Param, "Acceleration");
if (current_Param == "Acceleration" && (current_Action == "Increase" || current_Action == "Decrease"))
{
//replaces updated component value in vector to match against
string modifiedVectorString = MatchVectorValue(activated_Value, current_Value, current_DetailString);
match_Value = modifiedVectorString;
//llOwnerSay("match_Value is: "+match_Value);
}
This part is needed because there is an activation button. Until the activation is not done, the parameters are not sent to the particles and the numbers are gold, not green. Only when the values get sent (activated) to the particles, then the numbers turn green:
The color of displayed text is defined in local variable “textColor”
- activated color
- display color
depending on the match_Value and activated_Value when the arows are clicked, the color needs to be checked and properly set.
else
{
match_Value = current_Value;
//llOwnerSay("match_Value is: "+match_Value);
}
vector textColor;
//check for matching values
if (match_Value == activated_Value)
{
//define activated color
textColor = <0.478431, 0.815686, 0.043137>;
//llOwnerSay("textColor is: "+(string)textColor);
}
else if (match_Value != activated_Value)
{
//define display color
textColor = <0.871, 0.718, 0.455>;
//llOwnerSay("textColor is: "+(string)textColor);
}
In below part the in case of Default or Activate buttons the text needs to be updated in the Display prims.
//set hover text and description for vector value (all 3 x,y,z floats)
if ((current_Action == "Default" || current_Action == "Activate") && current_Param == "Acceleration" )
{
//gets the relevant Display Primnumber
integer Param_DisplayPrimNumber = GetPrimNumber(current_Param,"Display","0");
//gets the relevant component of the activated value
float currentParsed_Value = ParseStringVector2String(activated_Value, 0);
//truncates the relevant compoment of the activated value
string currentString_Value = formatFloat(currentParsed_Value, 2);
//sets the hover text and the description of the Display Prim to the truncated relevant compoment of the activated value
llSetLinkPrimitiveParamsFast(Param_DisplayPrimNumber, [PRIM_TEXT, currentString_Value, textColor, 1.0, PRIM_DESC, currentString_Value, PRIM_COLOR, ALL_SIDES, textColor, 0.0]);
//repeat for y and z:
integer Param_DisplayPrimNumber1 = GetPrimNumber(current_Param,"Display","1");
float currentParsed_Value1 = ParseStringVector2String(activated_Value, 1);
string currentString_Value1 = formatFloat(currentParsed_Value1, 2);
llSetLinkPrimitiveParamsFast(Param_DisplayPrimNumber1, [PRIM_TEXT, currentString_Value1, textColor, 1.0, PRIM_DESC, currentString_Value1, PRIM_COLOR, ALL_SIDES, textColor, 0.0]);
integer Param_DisplayPrimNumber2 = GetPrimNumber(current_Param,"Display","2");
float currentParsed_Value2 = ParseStringVector2String(activated_Value, 2);
string currentString_Value2 = formatFloat(currentParsed_Value2, 2);
llSetLinkPrimitiveParamsFast(Param_DisplayPrimNumber2, [PRIM_TEXT, currentString_Value2, textColor, 1.0, PRIM_DESC, currentString_Value2, PRIM_COLOR, ALL_SIDES, textColor, 0.0]);
}
else
{
//set hover text and description for standalone float value
integer Param_DisplayPrimNumber = GetPrimNumber(current_Param,"Display",current_DetailString);
llSetLinkPrimitiveParamsFast(Param_DisplayPrimNumber, [PRIM_TEXT, current_Value, textColor, 1.0, PRIM_DESC, current_Value, PRIM_COLOR, ALL_SIDES, textColor, 0.0]);
//Debug Test message
//llOwnerSay (current_Param+" DisplayPrimNumber is: "+(string)Param_DisplayPrimNumber+" Current "+current_Param+" value is: "+(string)current_Value+" textColor is: "+(string)textColor);
}
}
Activate
This function is called when the Activate buttons are pressed.
The end of this function calls the above Display function.
//sets the activated value to the current value, updates the object's description, sends an update message to a channel, outputs debug messages, and calls the Display function to show the current and activated values.
Activate(string current_Action, string current_Param, string current_Value, string current_DetailString )
{
//Debug Test message - check if function was triggered
//llOwnerSay("ACTIVATE Function Triggered. current_Action is: "+current_Action+" current_Param is: "+current_Param+" current_Value is: "+current_Value+" current_DetailString is: "+current_DetailString);
//set activated value to current value
string activated_Value = current_Value;
//store it in object description
integer currentActivate_PrimNumber = GetPrimNumber ( current_Param, "Activate", "" );
llSetLinkPrimitiveParamsFast(currentActivate_PrimNumber, [ PRIM_DESC, activated_Value ] );
//send info to particles
llSay(listen_Channel, "Update_"+current_Param+"_"+activated_Value);
//send time info to chat
if (is_Timer_ON)
{
float time = llGetTime();
llOwnerSay((string)time +"|RS:"+(string)listen_Channel+":Update_"+current_Param+" "+activated_Value);
}
//Debug Test message - check values and parameters
//llOwnerSay("current_Param :"+current_Param+" current_Value: "+current_Value+" activated_Value: "+activated_Value);
llPlaySound("Retro Game Lock",1.0);
llSetLinkAlpha(currentActivate_PrimNumber, 1.0, ALL_SIDES);
llSleep(0.1);
llSetLinkAlpha(currentActivate_PrimNumber, 0.0, ALL_SIDES);
Display (current_Action, current_Param, current_Value, activated_Value, current_DetailString);
}
Change
//performs various operations on the provided parameters, calculates a changed value based on an increment, applies specific rules for certain parameters, retrieves an activated value, and then calls the Display function to show the changed value.
Change(integer linkNumber, string current_Action, string current_Param, string current_Value, string current_DetailString)
{
//check if primname starts with "Acceleration"
integer currentParam_isAcceleration = CheckPrimName(current_Param, "Acceleration");
//Debug Test message - check if function was triggered
//llOwnerSay("Change Function Triggered. "+" linkNumber is: "+(string)linkNumber+" current_Action is: "+current_Action+" Current_Param is: "+current_Param+" current_Value is : "+current_Value+" current_DetailString is :"+current_DetailString);
// Local variables
float changedValue;
string finalValue;
// Convert string current_Value to Float
float FloatValue = (float)current_Value;
// Debug Test message
//llOwnerSay("Current Value (Float): " + (string)FloatValue);
// Call GetIncrement function, add increment
float increment = GetIncrement(current_Param, current_Action);
changedValue = FloatValue + increment;
// Debug Test message - changed value check
//llOwnerSay("increment is: "+(string)increment+", changed value is: "+(string)changedValue );
// Set max, min values
if (current_Param == "BurstCount")
{
if (changedValue > 50)
{
changedValue = 50;
llOwnerSay("Burst Count value cannot be larger than 50");
} else if (changedValue < 0)
{
changedValue = 0;
llOwnerSay("Burst Count value cannot be negative.");
}
finalValue = formatFloat(changedValue, 1);
// Debug Test message - check final value
//llOwnerSay("finalValue is: "+finalValue);
}
else if (current_Param == "StartGlow")
{
if (changedValue > 0.1)
{
changedValue = 0.1;
llOwnerSay("StartGlow value cannot be larger than 0.1");
} else if (changedValue < 0)
{
changedValue = 0;
llOwnerSay("StartGlow value cannot be negative.");
}
finalValue = formatFloat(changedValue, 2);
// Debug Test message - check final value
//llOwnerSay("finalValue is: "+finalValue);
}
else
{
if (changedValue > 1.0)
{
changedValue = 1.0;
llOwnerSay(current_Param+ " value cannot be larger than 1.0");
}
else if (changedValue < 0 && (!currentParam_isAcceleration)) //acceleration can be negative
{
changedValue = 0;
llOwnerSay(current_Param+ " value cannot be negative.");
}
finalValue = formatFloat(changedValue, 2);
// Debug Test message
//llOwnerSay("finalValue is: "+finalValue);
}
// Get activated value from Activate Description for Display function to match it against current value (and set its color)
string activatedValue = GetPrimDescription (current_Param, "Activate" , "");
// Debug Test message - check values
//llOwnerSay("current_Param: "+current_Param+" finalValue: "+finalValue+" activatedValue: "+activatedValue);
brief_HoverEffect_Alpha (linkNumber);
// Call Display function to display changed value (with proper color)
Display(current_Action, current_Param, finalValue, activatedValue, current_DetailString);
}
Color

The color buttons can be individually edited as shown in diagram above.
Color button names:
- Start_Color
- End_Color
- End_Color_Sample
- Start_Color_Sample
Color function
When the user clicks the color buttons, the following functions called:
- a Sound is played
- the button’s color is received in a variable
- a color message is sent to the particle and the sample prim on the HUD that shows the current Start and End colors.
- The position of the pressed button gets stored in a variable
- the Indicator Ring’s color is set to the same color and position.
//current_Param is Start or End: button names: Start_Color, End_Color
Color (integer linkNumber, string current_Param)
{
llPlaySound("Tiny Beep",1.0);
//Debug Test message
//llOwnerSay("Color Function Triggered");
// get color of button prim
list senderColorParams = llGetLinkPrimitiveParams(linkNumber, [PRIM_COLOR, 0]);
vector effect_color = llList2Vector(senderColorParams, 0);
string color_message = llList2String(senderColorParams, 0);
llSay(listen_Channel,"Update_"+current_Param+"Color_"+color_message);
if (is_Timer_ON)
{
float time = llGetTime();
llOwnerSay((string)time +"|RS:"+(string)listen_Channel+":Update_"+current_Param+"Color_"+color_message);
}
llSetLinkColor(linkNumber, <1.0, 1.0, 1.0>, ALL_SIDES);
llSleep(0.05);
llSetLinkColor(linkNumber, effect_color, ALL_SIDES);
//get Color Sample Prim's number, set its color to match pressed Color button's color
integer Display_num = GetPrimNumber ( current_Param, "Color" ,"Sample");
llSetLinkPrimitiveParams(Display_num, [PRIM_COLOR, -1, effect_color,1.0]);
//get pressed Color Button's position (to later set indicator ring's position to this vector)
list TempColorPosParams = llGetLinkPrimitiveParams(linkNumber, [ PRIM_POS_LOCAL ]);
vector TempColorPos = llList2Vector(TempColorPosParams, 0);
//get Indicator Ring's prim number, set its position and color
integer Indicator_num = GetPrimNumber ( current_Param, "Color" ,"Indicator");
llSetLinkPrimitiveParams(Indicator_num, [ PRIM_POS_LOCAL, TempColorPos, PRIM_COLOR, -1, effect_color,0.5]);
}
Controller
This function is called when the Particle and Timer controller buttons are pressed on the top of the HUD.
Timer and Particle Controller Buttons:
- Timer_Controller_START
- Timer_Controller_STOP
- TimeAndParticles_Controller_START
- TimeAndParticles_Controller_STOP
- Particles_Controller_START
- Particles_Controller_STOP
Controller (string current_Param, string current_DetailString)
{
llPlaySound("Upward Bleeps",1.0);
//Debug Test message
//llOwnerSay("Controller Function Triggered");
//Timer stop and start for both cases
if (current_Param == "TimeAndParticles" || current_Param == "Timer")
{
if (current_DetailString == "START")
{
is_Timer_ON = TRUE;
llOwnerSay("Timer Started: 00.00");
llResetTime();
} else if (current_DetailString == "STOP")
{
is_Timer_ON = FALSE;
float time = llGetTime();
llOwnerSay((string)time +"|STOP");
}
}
//Particle stop and start for both cases
if (current_Param == "TimeAndParticles" || current_Param == "Particles")
{
//Send message to Particles to start or stop playing
llSay(listen_Channel,current_DetailString+"Particles");
float time = llGetTime();
llOwnerSay((string)time +"|RS:"+(string)listen_Channel+":"+current_DetailString+"Particles");
}
}
Set Default Values
The first time the default values are set, the Activate function is called.
All other times, when the Default buttons are clicked, the Display functions is called.
//when default buttons are pressed
//retrieves the default value for a specific primitive, and then activates an action using that default value along with other provided parameters.
SetDefaultValue (string current_Action, string current_Param, string current_DetailString)
{
//get default vector value in string format from relevant Default prim's Description
string DefaultValue = GetPrimDescription (current_Param, "Default" ,""); //The Default string names don't have a 3rd component.
string activated_Value= GetPrimDescription ( current_Param, "Activate", current_DetailString ) ;
Display (current_Action, current_Param, DefaultValue, activated_Value, current_DetailString);
}
//used in state entry state and reset
//retrieves the default value for a specific primitive, and then activates an action using that default value along with other provided parameters.
SetDefaultValueFirst (string current_Action, string current_Param, string current_DetailString)
{
//get default vector value in string format from relevant Default prim's Description
string DefaultValue = GetPrimDescription (current_Param, "Default" ,""); //The Default string names don't have a 3rd component.
Activate(current_Action, current_Param, DefaultValue, current_DetailString);
}
Parse Button Name
Button names consist of 2 or 3 parts divided by “_”, these are converted into the following variables:
- current_Param
- current_Action
- current_DetailString
The rest of the functions checks for certain actions:
Default
Activate
Parsing, Default
//extracts relevant information, and performs different actions based on the extracted values
parse_buttonName (string buttonName, integer linkNumber)
{
//Debug Test message
//llOwnerSay("parse_buttonName Function Triggered");
list parsedList = llParseString2List(buttonName, ["_"], []);
string current_Param = llList2String(parsedList, 0);
string current_Action = llList2String(parsedList, 1);
string current_DetailString = llList2String(parsedList, 2);
//Debug Message
//llOwnerSay("Part 0: " + current_Param);
//llOwnerSay("Part 1: " + current_Action);
//llOwnerSay("Part 2: " + current_DetailString);
//call Default function
if (current_Action == "Default")
{
brief_HoverEffect_Color (linkNumber);
SetDefaultValue (current_Action, current_Param, current_DetailString);
}
Call ACTIVATE function
Acceleration vector needs to be combined from 3 button descriptions:
- Acceleration_Display_0
- Acceleration_Display_1
- Acceleration_Display_2
The remaining floats are gathered from the relevant “Display” buttons.
//call Activate function
else if (current_Action == "Activate")
{
//Debug Message
//llOwnerSay("Activate Function is being called from Parse function via Activate buttons");
string current_Value;
if (current_Param == "Acceleration")
{
string AccelerationX = GetPrimDescription("Acceleration", "Display", "0");
string AccelerationY = GetPrimDescription("Acceleration", "Display", "1");
string AccelerationZ = GetPrimDescription("Acceleration", "Display", "2");
current_Value = "<"+AccelerationX+","+AccelerationY+","+AccelerationZ+">";
}
else
{
current_Value = GetPrimDescription(current_Param, "Display", current_DetailString);
}
Activate ( current_Action, current_Param, current_Value, current_DetailString);
}
Call CHANGE function
//call Change function
else if (current_Action == "Increase" || current_Action == "Decrease")
{
if (current_Action == "Increase")
{
llPlaySound("Plastic Switch 13",1.0);
}
else //if Decrease
{
llPlaySound("Plastic Light Switch 2",1.0);
}
string current_Value = GetPrimDescription(current_Param, "Display", current_DetailString);
//Debug Message
//llOwnerSay("Change ("+current_Action+") Function is being called from Parse function. Current passed value for "+current_Param+" is: "+current_Value);
Change (linkNumber, current_Action, current_Param, current_Value, current_DetailString);
}
//call Color function
else if (current_Action == "Color")
{
Color (linkNumber, current_Param);
}
Call CONTROLLER function
//call Controller function
else if (current_Action == "Controller")
{
Controller (current_Param, current_DetailString);
}
else if (current_Param == "Minimize")
{
currentRot = minRot;
clearHoverText();
llSetLocalRot(currentRot); // Set the new rotation
}
//Maximize button
else if (current_Param == "Maximize")
{
currentRot = maxRot;
populateHoverText();
llSetLocalRot(currentRot); // Set the new rotation
}
//Detach button
else if (current_Param == "Detach")
{
llRequestPermissions(llGetOwner(), PERMISSION_ATTACH);
}
}
Core script
Core HUD Script (working with above functions)
The default values are set, any messages are litened to.
default
{
state_entry()
{
SetDefaultValueFirst("Default","BurstRate","");
SetDefaultValueFirst("Default","BurstCount","");
SetDefaultValueFirst("Default","StartAlpha","");
SetDefaultValueFirst("Default","StartGlow","");
SetDefaultValueFirst ("Default","Acceleration","0");
SetDefaultValueFirst ("Default","Acceleration","1");
SetDefaultValueFirst ("Default","Acceleration","2");
llOwnerSay("Ready.");
}
link_message(integer senderNumber, integer linkNumber, string buttonName, key id)
{
//Debug Message
//llOwnerSay("Link message received: "+(string)senderNumber+" "+(string)linkNumber+" "+buttonName);
parse_buttonName(buttonName, linkNumber);
}
run_time_permissions(integer perm)
{
if (perm & PERMISSION_ATTACH)
{
llDetachFromAvatar( );
}
else
{
llOwnerSay("Permission denied!");
}
}
}
PARTICLE script attached to hands
Global Variables
//define listener channel - same as in HUD
integer LISTENER_CHANNEL = 689689;
integer is_ParticleON = FALSE;
integer update_ParticleSystem = FALSE;
//Timer interval
float TIMER_INTERVAL = .5;
// generic declarations:
float ParticleDelay = 0.1;
float ParticleDuration = 10.0;
vector StartColor = <1.000000,1.000000,1.000000>;
vector EndColor = <1.000000,1.000000,1.000000>;
float color_range_variation = 0.2;
float BurstRate = 1.0; // Set starting burst Rate
integer BurstCount = 5;
vector Acceleration = <0.000000,0.000000,0.100000>;
float StartAlpha = 0.6;
float StartGlow = 0.2;
Function: Strings to Vector
//Strings to vector conversion
vector String2Vector_Conversion(string colorString)
{
list colorList = llParseString2List(colorString, [",", "<", ">"], []);
float r = (float)llList2String(colorList, 0);
float g = (float)llList2String(colorList, 1);
float b = (float)llList2String(colorList, 2);
vector colorVector = ;
return colorVector;
}
functions: Particles ON/OFF
//Use Particles_ON() and Particles_OFF() to turn the system on and off
//move the variables from below function to global if needed!!!
Particles_ON()
{
//Particle effect configurations - Individual differences per prim
//Root prim specifications (small twinkle):
list UniqueParticle_Params = [
// Texture Parameters:
PSYS_SRC_PATTERN,PSYS_SRC_PATTERN_DROP,
PSYS_SRC_BURST_RADIUS,0,
PSYS_SRC_ANGLE_BEGIN,0,
PSYS_SRC_ANGLE_END,0,
PSYS_SRC_TARGET_KEY,llGetKey(),
PSYS_PART_START_COLOR,StartColor,
PSYS_PART_END_COLOR,EndColor,
PSYS_PART_START_ALPHA,StartAlpha,
PSYS_PART_END_ALPHA,0,
PSYS_PART_START_GLOW,StartGlow,
PSYS_PART_END_GLOW,0.0,
PSYS_PART_BLEND_FUNC_SOURCE,PSYS_PART_BF_SOURCE_ALPHA,
PSYS_PART_BLEND_FUNC_DEST,PSYS_PART_BF_ONE_MINUS_SOURCE_ALPHA,
PSYS_PART_START_SCALE,<0.500000,0.500000,0.000000>,
PSYS_PART_END_SCALE,<0.500000,4.000000,0.000000>,
PSYS_SRC_TEXTURE,"eace85d3-b142-5a0a-4971-f4063dab483c",
PSYS_SRC_MAX_AGE,0,
PSYS_PART_MAX_AGE,5,
PSYS_SRC_BURST_RATE,BurstRate,
PSYS_SRC_BURST_PART_COUNT,BurstCount,
PSYS_SRC_ACCEL,Acceleration,
PSYS_SRC_OMEGA,<0.000000,0.000000,0.000000>,
PSYS_SRC_BURST_SPEED_MIN,0.5,
PSYS_SRC_BURST_SPEED_MAX,0.5,
PSYS_PART_FLAGS,
0 |
PSYS_PART_EMISSIVE_MASK |
PSYS_PART_INTERP_COLOR_MASK |
PSYS_PART_INTERP_SCALE_MASK
];
llParticleSystem(UniqueParticle_Params);
}
Particles_OFF()
{
llParticleSystem( [ ] );
}
Core Script
The parsing of the message could be done by a separate function too maybe…
default
{
state_entry()
{
Particles_OFF();
llListen(LISTENER_CHANNEL, "", NULL_KEY, "");
}
listen(integer channel, string name, key id, string message)
{
if (llGetOwnerKey(id) == llGetOwner() )
{
list parsedList_fromMessage = llParseString2List(message, ["_"], []);
string active_Action = llList2String(parsedList_fromMessage, 0);
string active_Param = llList2String(parsedList_fromMessage, 1);
string active_Value = llList2String(parsedList_fromMessage, 2);
//llOwnerSay("Message received. Action is :"+active_Action+" Param is: "+active_Param+". Value is: "+active_Value);
if (active_Action == "Update")
{
if (active_Param == "BurstCount")
{
BurstCount = llList2Integer(parsedList_fromMessage, 2);
//llOwnerSay("BurstRate is: "+(string)BurstRate);
}
if (active_Param == "BurstRate")
{
BurstRate = llList2Float(parsedList_fromMessage, 2);
//llOwnerSay("BurstRate is: "+(string)BurstRate);
}
if (active_Param == "StartGlow")
{
StartGlow = llList2Float(parsedList_fromMessage, 2);
//llOwnerSay("StartGlow is: "+(string)StartGlow);
}
if (active_Param == "StartAlpha")
{
StartAlpha = llList2Float(parsedList_fromMessage, 2);
//llOwnerSay("StartAlpha is: "+(string)StartAlpha);
}
if (active_Param == "StartColor")
{
string ColorInfo = llList2String(parsedList_fromMessage, 2);
StartColor = String2Vector_Conversion(ColorInfo);
//llOwnerSay("StartColor is: "+(string)StartColor);
}
if (active_Param == "EndColor")
{
string ColorInfo = llList2String(parsedList_fromMessage, 2);
EndColor = String2Vector_Conversion(ColorInfo);
// llOwnerSay("EndColor is: "+(string)EndColor);
}
if (active_Param == "Acceleration")
{
string accelInfo = llList2String(parsedList_fromMessage, 2);
Acceleration = String2Vector_Conversion(accelInfo);
//llOwnerSay("Acceleration is: "+(string)Acceleration);
}
update_ParticleSystem = TRUE;
}
else if (active_Action == "STARTParticles")
{
//llOwnerSay("Start message received");
Particles_ON();
is_ParticleON = TRUE;
llSetTimerEvent(TIMER_INTERVAL);
}
//check if time is up (for current linknumber prim)
else if (active_Action == "STOPParticles")
{
//llOwnerSay("Stop message received");
Particles_OFF();
is_ParticleON = FALSE;
llSetTimerEvent(0.0);
}
}
}
changed(integer change)
{
// reset script when the owner or the inventory changed
if (change & (CHANGED_OWNER | CHANGED_INVENTORY))
{
llResetScript();
}
}
timer()
{
if (update_ParticleSystem == TRUE)
{
Particles_ON();
update_ParticleSystem = FALSE;
}
}
}