I made some additions to oc_titler.lsl to make the Titler a bit smarter in busy locations or if you are sitting with someone.
These features don't replace anything, Or break OC behavior.
Runs if the user turns it on off by default
If this is useful to others, feel free to merge it.
string g_sSubMenu="Titler";
string g_sVersion="8.3";
integer LINK_CMD_DEBUG=1999;
integer g_iNoB64=FALSE;
integer g_iWasUpgraded=FALSE;
integer CMD_OWNER=500;
integer CMD_WEARER=503;
integer NOTIFY=1002;
integer REBOOT=-1000;
integer LM_SETTING_SAVE=2000;
integer LM_SETTING_REQUEST=2001;
integer LM_SETTING_RESPONSE=2002;
integer LM_SETTING_DELETE=2003;
integer LM_SETTING_EMPTY=2004;
integer MENUNAME_REQUEST=3000;
integer MENUNAME_RESPONSE=3001;
integer DIALOG=-9000;
integer DIALOG_RESPONSE=-9001;
integer DIALOG_TIMEOUT=-9002;
string UPMENU="BACK";
integer bool(integer a){return a;}
list g_lCheckboxes=["□","▣"];
string Checkbox(integer v,string l){return llList2String(g_lCheckboxes,bool(v))+" "+l;}
list g_lMenuIDs;
integer g_iMenuStride;
list g_lOwner;
list g_lTrust;
list g_lBlock;
string g_sTitle="";
vector g_vColor=<1,1,1>;
integer g_iShow=FALSE;
integer g_iOffset=8;
integer g_iTextPrim;
key g_kWearer;
integer g_iLocked=FALSE;
integer g_iProximityHide=TRUE;
integer g_iAgentNear=FALSE;
float g_fDetectRange=2.0;
Dialog(key k,string p,list c,list u,integer page,integer auth,string name){
key id=llGenerateKey();
llMessageLinked(LINK_SET,DIALOG,(string)k+"|"+p+"|"+(string)page+"|"+llDumpList2String(c,"`")+"|"+llDumpList2String(u,"`")+"|"+(string)auth,id);
integer i=llListFindList(g_lMenuIDs,[k]);
if(~i)g_lMenuIDs=llListReplaceList(g_lMenuIDs,[k,id,name],i,i+g_iMenuStride-1);
else g_lMenuIDs+=[k,id,name];
}
Menu(key k,integer a){
Dialog(
k,
"\n[Titler]\nUse Up/Down, Title, Color, Show/Hide, AutoHide, Range.",
["UP","DOWN","Set Title","Color","Set Range",Checkbox(g_iShow,"Show"),Checkbox(g_iProximityHide,"AutoHide")],
[UPMENU],
0,
a,
"Menu~Titler"
);
}
ColorMenu(key k,integer a){
Dialog(k,"\n[Titler]\nColor selection",["colormenu please"],[UPMENU,"Custom"],0,a,"Menu~Colors");
}
integer validvector(string s){
list t=llParseString2List(s,[",","<",">"," "],[]);
if(llGetListLength(t)!=3)return FALSE;
t=llParseString2List(s,[",","<",">"," ","."],[]);
string x=(string)t;
integer i=llStringLength(x);
while(i){--i;if(llGetSubString(x,i,i)!="0"&&(integer)llGetSubString(x,i,i)==0)return FALSE;}
return TRUE;
}
vector text2col(string s){
list t=llParseString2List(s,[",","<",">"," "],[]);
integer n;
integer i;
integer v;
while(i<3){
v=llList2Integer(t,i);
if(v<0)t=llListReplaceList(t,[0],i,i);
else if(v>1)n=TRUE;
if(v>255)t=llListReplaceList(t,[255],i,i);
++i;
}
vector o=(vector)("<"+llList2CSV(t)+">");
if(n)o/=255;
return o;
}
integer SAVE_SHOW_HIDE=1;
integer SAVE_OFFSET=2;
integer SAVE_TITLE=4;
integer SAVE_COLOR=8;
Save(integer w){
if(w&SAVE_SHOW_HIDE){
if(g_iShow)llMessageLinked(LINK_SET,LM_SETTING_SAVE,"titler_show=1","");
else llMessageLinked(LINK_SET,LM_SETTING_DELETE,"titler_show","");
}
if(w&SAVE_OFFSET)llMessageLinked(LINK_SET,LM_SETTING_SAVE,"titler_offset="+(string)g_iOffset,"");
if(w&SAVE_TITLE){
if(!g_iNoB64)
llMessageLinked(LINK_SET,LM_SETTING_SAVE,"titler_title="+llStringToBase64(g_sTitle),"");
else
llMessageLinked(LINK_SET,LM_SETTING_SAVE,"titler_title="+g_sTitle,"");
}
if(w&SAVE_COLOR)llMessageLinked(LINK_SET,LM_SETTING_SAVE,"titler_color="+(string)g_vColor,"");
Titler();
}
Titler(){
if(g_iProximityHide && g_iAgentNear){
llSetLinkPrimitiveParams(g_iTextPrim,[PRIM_TEXT,"",ZERO_VECTOR,0]);
return;
}
if(g_iShow){
string o="";
integer i;
while(i<g_iOffset){o+=" \n";++i;}
llSetLinkPrimitiveParams(g_iTextPrim,[PRIM_TEXT,g_sTitle+o,g_vColor,1]);
}else{
llSetLinkPrimitiveParams(g_iTextPrim,[PRIM_TEXT,"",ZERO_VECTOR,0]);
}
}
ScanFloatText(){
integer i;
integer e=llGetNumberOfPrims();
for(i=0;i<=e;i++){
list p=llGetLinkPrimitiveParams(i,[PRIM_NAME,PRIM_DESC]);
if(~llSubStringIndex(llList2String(p,0),"FloatText")){g_iTextPrim=i;return;}
if(~llSubStringIndex(llList2String(p,1),"FloatText")){g_iTextPrim=i;return;}
}
g_iTextPrim=LINK_THIS;
}
NukeOtherText(){
integer i=1;
integer e=llGetNumberOfPrims();
for(;i<=e;i++)llSetLinkPrimitiveParamsFast(i,[PRIM_TEXT,"",ZERO_VECTOR,0]);
}
UserCommand(integer n,string s,key k){
if(n<CMD_OWNER||n>CMD_WEARER)return;
if(n==CMD_OWNER&&s=="runaway"){
g_lOwner=g_lTrust=g_lBlock=[];
return;
}
if(llToLower(s)==llToLower(g_sSubMenu)||llToLower(s)=="menu "+llToLower(g_sSubMenu)){
Menu(k,n);
return;
}
if(n!=CMD_OWNER)return;
list L=llParseString2List(s,[" "],[]);
string t=llList2String(L,0);
string v=llToLower(llList2String(L,1));
string p=llList2String(L,2);
if(t=="title"){
if(v==""){
Dialog(k,"What should the title say?",[],[],0,n,"Textbox~Title");
return;
}
g_sTitle=llDumpList2String(llList2List(L,1,-1)," ");
Save(SAVE_TITLE);
}
else if(t=="titler"){
if(v=="color"){
if(!validvector(p))ColorMenu(k,n);
else{g_vColor=text2col(p);Save(SAVE_COLOR);}
}
else if(v=="show"){g_iShow=TRUE;Save(SAVE_SHOW_HIDE);}
else if(v=="hide"){g_iShow=FALSE;Save(SAVE_SHOW_HIDE);}
else if(v=="up"){++g_iOffset;Save(SAVE_OFFSET);}
else if(v=="down"){--g_iOffset;if(g_iOffset<0)g_iOffset=0;Save(SAVE_OFFSET);}
else if(v=="plain"){
g_iNoB64=!g_iNoB64;
string m="0Titler plain text mode is now set to ";
if(g_iNoB64){
llMessageLinked(LINK_SET,LM_SETTING_SAVE,"titler_plain=1","");
m+="PLAIN";
} else {
m+="BASE64";
llMessageLinked(LINK_SET,LM_SETTING_DELETE,"titler_plain","");
}
llMessageLinked(LINK_SET,NOTIFY,m,k);
}
else if(v=="autohide"){
if(p=="on")g_iProximityHide=TRUE;
else if(p=="off")g_iProximityHide=FALSE;
Titler();
}
else if(v=="range"){
float d=(float)p;
if(d<0.5)d=0.5;
if(d>10)d=10;
g_fDetectRange=d;
llSensorRepeat("",NULL_KEY,AGENT,g_fDetectRange,TWO_PI,5.0);
}
else if(v=="title"){
g_sTitle=llDumpList2String(llList2List(L,2,-1)," ");
UserCommand(n,"title "+g_sTitle,k);
}
}
}
integer ALIVE=-55;
integer READY=-56;
integer STARTUP=-57;
default{
on_rez(integer n){llResetScript();}
state_entry(){llMessageLinked(LINK_SET,ALIVE,llGetScriptName(),"");}
link_message(integer s,integer n,string st,key k){
if(n==REBOOT&&st=="reboot")llResetScript();
else if(n==READY)llMessageLinked(LINK_SET,ALIVE,llGetScriptName(),"");
else if(n==STARTUP)state active;
}
}
state active{
on_rez(integer t){llResetScript();}
state_entry(){
if(llGetStartParameter()!=0)llResetScript();
llSetMemoryLimit(40000);
g_kWearer=llGetOwner();
NukeOtherText();
llSensorRepeat("",NULL_KEY,AGENT,g_fDetectRange,TWO_PI,5.0);
}
changed(integer c){
if(c&CHANGED_LINK){
integer o=g_iTextPrim;
ScanFloatText();
if(g_iTextPrim!=o)NukeOtherText();
Titler();
}
}
sensor(integer n){
if(!g_iAgentNear){
g_iAgentNear=TRUE;
Titler();
}
}
no_sensor(){
if(g_iAgentNear){
g_iAgentNear=FALSE;
Titler();
}
}
link_message(integer s,integer n,string st,key k){
if(n>=CMD_OWNER&&n<=CMD_WEARER)UserCommand(n,st,k);
else if(n==MENUNAME_REQUEST&&st==g_sParentMenu)
llMessageLinked(s,MENUNAME_RESPONSE,g_sParentMenu+"|"+g_sSubMenu,"");
else if(n==DIALOG_RESPONSE){
integer i=llListFindList(g_lMenuIDs,[k]);
if(i!=-1){
string m=llList2String(g_lMenuIDs,i+1);
g_lMenuIDs=llDeleteSubList(g_lMenuIDs,i-1,i-2+g_iMenuStride);
list P=llParseString2List(st,["|"],[]);
key av=llList2Key(P,0);
string msg=llList2String(P,1);
integer a=llList2Integer(P,3);
integer r=TRUE;
if(a!=CMD_OWNER){
llMessageLinked(LINK_SET,NOTIFY,"0%NOACCESS% to titler options",av);
llMessageLinked(LINK_SET,a,"menu "+g_sParentMenu,av);
return;
}
if(m=="Menu~Titler"){
if(msg==UPMENU){
r=FALSE;
llMessageLinked(LINK_SET,a,"menu "+g_sParentMenu,av);
}
else if(msg=="UP"){++g_iOffset;Save(SAVE_OFFSET);}
else if(msg=="DOWN"){--g_iOffset;if(g_iOffset<0)g_iOffset=0;Save(SAVE_OFFSET);}
else if(msg==Checkbox(g_iShow,"Show")){g_iShow=!g_iShow;Save(SAVE_SHOW_HIDE);}
else if(msg==Checkbox(g_iProximityHide,"AutoHide")){g_iProximityHide=!g_iProximityHide;Titler();}
else if(msg=="Set Title"){
r=FALSE;
Dialog(av,"What should the title say?",[],[],0,a,"Textbox~Title");
}
else if(msg=="Color"){
r=FALSE;
ColorMenu(av,a);
}
else if(msg=="Set Range"){
r=FALSE;
Dialog(av,"Enter proximity distance in meters (0.5–10):",[],[],0,a,"Textbox~Range");
}
if(r)Menu(av,a);
}
else if(m=="Menu~Colors"){
if(msg==UPMENU){
Menu(av,a);
r=FALSE;
}
else if(msg=="Custom"){
Dialog(av,"[Titler Custom Color]\nType R,G,B",[],[],0,a,"Textbox~Color");
r=FALSE;
}
else g_vColor=(vector)msg;
if(r)ColorMenu(av,a);
Save(SAVE_COLOR);
}
else if(m=="Textbox~Title"){
g_sTitle=msg;
Menu(av,a);
Save(SAVE_TITLE);
}
else if(m=="Textbox~Color"){
if(!validvector(msg)){
llRegionSayTo(av,0,"Not a valid vector!");
Dialog(av,"[Titler Custom Color]\nTry again:",[],[],0,a,"Textbox~Color");
return;
}
g_vColor=text2col(msg);
ColorMenu(av,a);
Save(SAVE_COLOR);
}
else if(m=="Textbox~Range"){
float v=(float)msg;
if(v<0.5)v=0.5;
if(v>10)v=10;
g_fDetectRange=v;
llSensorRepeat("",NULL_KEY,AGENT,g_fDetectRange,TWO_PI,5.0);
Menu(av,a);
}
}
}
else if(n==DIALOG_TIMEOUT){
integer i=llListFindList(g_lMenuIDs,[k]);
g_lMenuIDs=llDeleteSubList(g_lMenuIDs,i-1,i+3);
}
else if(n==LM_SETTING_RESPONSE){
list L=llParseString2List(st,["_","="],[]);
if(llList2String(L,0)=="global"){
if(llList2String(L,1)=="locked")g_iLocked=llList2Integer(L,2);
else if(llList2String(L,1)=="checkboxes")g_lCheckboxes=llCSV2List(llList2String(L,2));
}
else if(llList2String(L,0)=="titler"){
integer o=g_iTextPrim;
ScanFloatText();
if(g_iTextPrim!=o)NukeOtherText();
string v=llList2String(L,1);
if(v=="show")g_iShow=TRUE;
else if(v=="offset")g_iOffset=(integer)llList2String(L,2);
else if(v=="title"){
if(!g_iNoB64)g_sTitle=llBase64ToString(llList2String(L,2));
else g_sTitle=llList2String(L,2);
if(g_iWasUpgraded){
g_sTitle=llList2String(L,2);
if(!g_iNoB64)
llMessageLinked(LINK_SET,LM_SETTING_SAVE,"titler_title="+llStringToBase64(g_sTitle),"");
else
llMessageLinked(LINK_SET,LM_SETTING_SAVE,"titler_title="+g_sTitle,"");
g_iWasUpgraded=FALSE;
}
}
else if(v=="color")g_vColor=(vector)llList2String(L,2);
else if(v=="on"){
g_iWasUpgraded=TRUE;
llMessageLinked(LINK_SET,LM_SETTING_REQUEST,"ALL","");
llMessageLinked(LINK_SET,LM_SETTING_DELETE,"titler_auth","");
llMessageLinked(LINK_SET,LM_SETTING_DELETE,"titler_on","");
llMessageLinked(LINK_SET,LM_SETTING_DELETE,"titler_height","");
g_iShow=(integer)llList2String(L,2);
llMessageLinked(LINK_SET,LM_SETTING_SAVE,"titler_show="+(string)g_iShow,"");
}
else if(v=="plain"){
g_iNoB64=TRUE;
llMessageLinked(LINK_SET,LM_SETTING_REQUEST,"ALL","");
}
Titler();
}
}
else if(n==LM_SETTING_DELETE){
list L=llParseString2List(st,["_"],[]);
if(llList2String(L,0)=="global"&&llList2String(L,1)=="locked")g_iLocked=FALSE;
}
else if(n==LINK_CMD_DEBUG){
if(st=="ver"){
llInstantMessage(k,llGetScriptName()+" "+g_sVersion);
return;
}
llInstantMessage(k,"SHOW "+(string)g_iShow);
}
else if(n==REBOOT&&st=="reboot")llResetScript();
}
}
I made some additions to oc_titler.lsl to make the Titler a bit smarter in busy locations or if you are sitting with someone.
Added AutoHide option
Hides the title automatically when another avatar/agent comes close
Toggle button in the Titler menu
Added adjustable distance for the hide sensor
New “Set Range” button
Wearer can type any value 0.5m–10m
Updates the sensor instantly
These features don't replace anything, Or break OC behavior.
Runs if the user turns it on off by default
If this is useful to others, feel free to merge it.