An on/off switch is good, but a real radio has multiple stations. To do this, we'll store our station URLs in an LSL list. We'll also need a variable to keep track of the current station index. For this, we'll need to use linked prims for the "Next" and "Previous" buttons.
Setup:
Ctrl+L. The main body is now the "root" prim.// Multi-Station Radio Script
// By Sorin Todys, Alife Virtual School
// --- CONFIGURATION ---
list g_station_urls; // Global list to hold our station URLs
list g_station_names; // Global list to hold station names
// --- SCRIPT STATE ---
integer g_current_station_index = 0; // Index for the current station
integer g_is_playing = FALSE; // Radio on/off state
// --- HELPER FUNCTION ---
// This function updates the media and hover text
update_media()
{
if (g_is_playing)
{
string url = llList2String(g_station_urls, g_current_station_index);
string name = llList2String(g_station_names, g_current_station_index);
llSetPrimMediaParams(0, [PRIM_MEDIA_CURRENT_URL, url, PRIM_MEDIA_CONTROLS, PRIM_MEDIA_CONTROLS_STANDARD]);
llSetText("Now Playing:\n" + name + "\n(Touch main body to turn OFF)", <0,1,0>, 1.0);
}
else
{
// When off, we can show an image or a blank page
llSetPrimMediaParams(0, [PRIM_MEDIA_CURRENT_URL, "", PRIM_MEDIA_CONTROLS, PRIM_MEDIA_CONTROLS_NONE]);
llSetText("Radio is OFF\n(Touch main body to turn ON)", <1,1,1>, 1.0);
}
}
default
{
state_entry()
{
// --- POPULATE OUR STATION LISTS ---
g_station_names = ["Classical Calm", "Rock Anthems", "Jazz Club"];
g_station_urls = ["http://dradio.org:8000/1", "http://dradio.org:8000/2", "http://dradio.org:8000/3"]; // Replace with real URLs!
// Set the link names for our buttons for easy identification
llSetLinkPrimitiveParamsFast(2, [PRIM_NAME, "NextButton"]);
llSetLinkPrimitiveParamsFast(3, [PRIM_NAME, "PrevButton"]);
g_is_playing = FALSE;
update_media();
}
link_message(integer sender_num, integer num, string str, key id)
{
// This event listens for messages from other prims in the linkset
if (str == "touch")
{
// Check which linked prim was touched by its name
string prim_name = llGetLinkName(num);
if (prim_name == "NextButton")
{
g_current_station_index++;
// Loop back to the beginning if we go past the end of the list
if (g_current_station_index >= llGetListLength(g_station_urls))
{
g_current_station_index = 0;
}
llSay(0, "Next station...");
update_media();
}
else if (prim_name == "PrevButton")
{
g_current_station_index--;
// Loop to the end if we go past the beginning
if (g_current_station_index < 0)
{
g_current_station_index = llGetListLength(g_station_urls) - 1;
}
llSay(0, "Previous station...");
update_media();
}
}
}
touch_start(integer total_number)
{
// This event only fires for the root prim
// We use this for the ON/OFF toggle
if (llDetectedLinkNumber(0) == 1) // Ensure it's the root prim being touched
{
g_is_playing = !g_is_playing; // This is a cool shortcut to toggle a boolean
update_media();
}
}
}
// --- SCRIPT FOR BUTTONS ---
// Place this tiny script in EACH of the button prims (Next and Previous)
default
{
touch_start(integer total_number)
{
// When touched, send a message to the root prim
llMessageLinked(LINK_ROOT, 0, "touch", NULL_KEY);
}
}
You might be surprised to learn that a TV is functionally identical to the radio we just built. The only difference is the media URL and a few extra parameters. Instead of an audio stream, you provide a video stream URL. This could be a link to a .mp4 file or a live video feed.
The llSetPrimMediaParams function can take many more arguments to control the video playback. Here are some of the most useful:
PRIM_MEDIA_WIDTH and PRIM_MEDIA_HEIGHT: Integers that set the resolution of the media. This helps prevent distortion.PRIM_MEDIA_AUTO_PLAY: Set to TRUE to make the video play automatically.PRIM_MEDIA_AUTO_LOOP: Set to TRUE to make the video loop when it finishes.PRIM_MEDIA_FIRST_CLICK_INTERACT: Set to TRUE to allow users to click through the video to the webpage it's on.This script will play a public domain movie on a loop. We'll use a URL from the Internet Archive.
// Simple Looping Movie Player
// By Sorin Todys, Alife Virtual School
// Public domain movie: "Night of the Living Dead" from archive.org
string MOVIE_URL = "http://www.archive.org/download/night_of_the_living_dead/night_of_the_living_dead_512kb.mp4";
default
{
state_entry()
{
// Set the media on face 0.
// We specify resolution, auto play, and looping.
llSetPrimMediaParams(0, [
PRIM_MEDIA_CURRENT_URL, MOVIE_URL,
PRIM_MEDIA_WIDTH, 640,
PRIM_MEDIA_HEIGHT, 480,
PRIM_MEDIA_AUTO_PLAY, TRUE,
PRIM_MEDIA_AUTO_LOOP, TRUE,
PRIM_MEDIA_CONTROLS, PRIM_MEDIA_CONTROLS_MINI
]);
llSetText("Now Showing:\nNight of the Living Dead", <1,1,0>, 1.0);
}
}
Your media player is amazing, but what if you don't want just anyone changing the station at your club? You need to add security. We can easily modify our touch events to check who is clicking the prim.
To do this, we'll use llDetectedKey(0) to get the unique key of the avatar who touched the prim, and llGetOwner() to get the key of the object's owner. We can also check if the user is in the same group as the object.
Let's modify the touch_start event from our simple On/Off radio to be owner-only.
touch_start(integer total_number)
{
// Check if the person who touched is the owner of the object
if (llDetectedKey(0) == llGetOwner())
{
// All the on/off logic from before goes inside this 'if' block
if (is_playing == FALSE)
{
// ... turn on radio ...
is_playing = TRUE;
}
else
{
// ... turn off radio ...
is_playing = FALSE;
}
}
else
{
// If it's not the owner, send them a message
llInstantMessage(llDetectedKey(0), "Sorry, only the owner can operate this radio.");
}
}
This is extremely useful for clubs and businesses. First, you must set the object to the correct group and "Share" it. Then, use llDetectedGroup(0).
touch_start(integer total_number)
{
// llDetectedGroup returns TRUE if the toucher is in the same group as the prim
if (llDetectedGroup(0) == TRUE)
{
// ... all your radio logic here ...
}
else
{
llInstantMessage(llDetectedKey(0), "Sorry, only group members can operate this radio.");
}
}
llSetText to show the current status (On/Off, station name). Use llSay or llInstantMessage to confirm actions. A silent, unresponsive object is confusing.state_entry.Time to put your knowledge into practice. These exercises are designed to be completed on your own land or in a sandbox area where you have permission to rez and run scripts.
World > Parcel Details > Sound, and set the stream. Invite