// SPDX-License-Identifier: MIT // Copyright (c) 2026 Incoprea // Notecard-captioned sound player // Not compiled or tested in-world // Setup: Add cues with lines sound_name|caption plus the licensed sounds. Owner-touch advances one cue. // Stop / restore: Disable/remove; Stop sound in this prim can silence current audio. Captions are owner chat, not persistent text. // Notes: Caption precedes playback and remains readable when sound is muted. Only inventory sound names are accepted. Keep example captions and notecard lines short, preferably ASCII. Character clipping is not UTF-8 byte-budget clipping: multibyte text may reach hover-text or chat limits sooner and be truncated. // License: see LICENSE in this distribution. // Original Incoprea. MIT. Not compiled or tested in-world. integer line; key request; default { touch_start(integer n) { if(llDetectedKey(0)!=llGetOwner()||request!=NULL_KEY)return; if(llGetInventoryType("cues")!=INVENTORY_NOTECARD)return; request=llGetNotecardLine("cues",line); llSetTimerEvent(15.0); } dataserver(key id,string data) { if(id!=request)return; request=NULL_KEY; llSetTimerEvent(0.0); if(data==EOF) { line=0; llOwnerSay("End of sound cues."); return; } ++line; list pair=llParseStringKeepNulls(data,["|"],[]); if(llGetListLength(pair)!=2) { llOwnerSay("Expected sound_name|caption."); return; } string name=llStringTrim(llList2String(pair,0),STRING_TRIM); llOwnerSay(llGetSubString(llList2String(pair,1),0,800)); if(llGetInventoryType(name)==INVENTORY_SOUND)llPlaySound(name,0.3); else llOwnerSay("Missing sound "+name); } timer() { request=NULL_KEY; llSetTimerEvent(0.0); } changed(integer change) { if(change&CHANGED_INVENTORY) { request=NULL_KEY; line=0; llSetTimerEvent(0.0); } } }