Boolean Logic
Before we can make decisions, we need to understand boolean logic. A boolean is simply TRUE or FALSE — yes or no. In LSL, TRUE = 1 and FALSE = 0 (they're just integer constants).
You create boolean expressions using comparison operators. These compare two values and return TRUE or FALSE:
- ==
- Equal to.
5 == 5is TRUE - !=
- Not equal to.
5 != 3is TRUE - < >
- Less than / greater than
- <= >=
- Less than or equal / greater than or equal
Don't confuse = (assignment — sets a value) with == (comparison — tests equality). Using = inside an if is a bug that's hard to spot.
The if Statement
The if statement runs a block of code only when a condition is TRUE:
default
{
touch_start(integer num_detected)
{
integer score = 75;
if (score >= 50)
{
llSay(0, "You passed!");
}
}
}
The curly braces { } wrap the code that runs when the condition is true. For a single line, the braces are optional — but using them is good practice because it prevents bugs when you add more lines later.
if / else
Add an else block to handle the case when the condition is FALSE:
default
{
touch_start(integer num_detected)
{
key toucher = llDetectedKey(0);
key owner = llGetOwner();
if (toucher == owner)
{
llOwnerSay("Welcome back, owner.");
}
else
{
llSay(0, "Sorry, only the owner can use this.");
}
}
}
This is one of the most common patterns in all of LSL — checking whether the person interacting with your object is its owner. You'll write this dozens of times.
else if Chains
When you have more than two possible outcomes, chain multiple conditions with else if. LSL checks them from top to bottom and runs the first one that matches:
default
{
touch_start(integer num_detected)
{
integer score = 82;
if (score >= 90)
{
llSay(0, "Grade: A — Excellent!");
}
else if (score >= 80)
{
llSay(0, "Grade: B — Good work.");
}
else if (score >= 70)
{
llSay(0, "Grade: C — Passing.");
}
else if (score >= 60)
{
llSay(0, "Grade: D — Barely.");
}
else
{
llSay(0, "Grade: F — Try again.");
}
}
}
Once a condition matches, the rest of the chain is skipped. So when score is 82, the second condition (score >= 80) matches and the script says "Grade: B". The remaining checks don't run.
Logical Operators
You can combine multiple conditions into one expression using logical operators:
- && (AND)
- Both conditions must be TRUE.
age > 18 && verified == TRUE - || (OR)
- At least one condition must be TRUE.
isOwner || isAdmin - ! (NOT)
- Inverts the result.
!activeis TRUE when active is FALSE
default
{
touch_start(integer num_detected)
{
key toucher = llDetectedKey(0);
key owner = llGetOwner();
integer sameGroup = llSameGroup(toucher);
if (toucher == owner || sameGroup)
{
llOwnerSay("Access granted.");
// do the thing
}
else
{
llSay(0, "Access denied.");
}
}
}
Practical: Owner-Only Lock
Let's build a complete, practical example: an object with a toggle that only the owner can activate. It demonstrates everything from this class working together.
integer isActive = FALSE;
default
{
state_entry()
{
llOwnerSay("Object ready. Touch to toggle (owner only).");
}
touch_start(integer num_detected)
{
key toucher = llDetectedKey(0);
key owner = llGetOwner();
// Guard: reject non-owners immediately
if (toucher != owner)
{
llSay(0, "Only the owner can control this.");
return; // Stop executing the rest of this event
}
// Owner: toggle the state
if (!isActive)
{
isActive = TRUE;
llSetColor(<0.0, 1.0, 0.0>, ALL_SIDES); // Green = on
llOwnerSay("Activated.");
}
else
{
isActive = FALSE;
llSetColor(<1.0, 0.0, 0.0>, ALL_SIDES); // Red = off
llOwnerSay("Deactivated.");
}
}
}
Notice the return statement — it exits the event handler early. This "guard clause" pattern keeps the main logic clean by handling the rejection case first and returning, rather than wrapping everything in an extra else block.