Difference between revisions of "User:Kephra Nurmi/lsDialog"

From Second Life Wiki
Jump to navigation Jump to search
Line 253: Line 253:
The .lsDialog notecard defines the menu dialog tree. A typical simple notecard could look like:
The .lsDialog notecard defines the menu dialog tree. A typical simple notecard could look like:


<pre>
<ini>
# default is to ask repeating ... remove comment if  
# default is to ask repeating ... remove comment if  
#Dialog=Once
#Dialog=Once
Line 281: Line 281:
Ivory=link 0 glass,color,Ivory
Ivory=link 0 glass,color,Ivory
Cyan=link 0 glass,color,Cyan
Cyan=link 0 glass,color,Cyan
</pre>
</ini>


This notecard will define a single prim dialog system with one top menu called 'Reset' and two sub menus called 'Size' and 'Color' with link action on channel 0 and default permissions. The object description defines the name for the top menu dialog. Each menu starts with a section header in brackets followed lines to define the dialog entries. Each entry has a name equal to an action, a channel and a string.
This notecard will define a single prim dialog system with one top menu called 'Reset' and two sub menus called 'Size' and 'Color' with link action on channel 0 and default permissions. The object description defines the name for the top menu dialog. Each menu starts with a section header in brackets followed lines to define the dialog entries. Each entry has a name equal to an action, a channel and a string.

Revision as of 18:22, 3 May 2009

lsDialog

lsDialog is an universal notecard driven menu dialog system. lsDialog could be used in a HUD or rezzed objects, providing one prim dialog trees or multi prim button dialogs. You can restrict usage to owner, group, named avatars or everybody. lsDialog is using llSay or llMessageLinked to comunicate with other scripts.

Script: .lsDialog 09124

<lsl> // .lsDialog 09124 (c) 2007-2009 by Kephra Nurmi under Creative Commons Attribution-Share Alike 3.0 License

string configName = ".lsDialog"; string configKey = NULL_KEY; integer configLine = 0; key configReq = NULL_KEY; integer avChannel;

list dialogNames = []; list dialogLines = []; string currentName = ""; string currentLines = "";

string currentMenu = ""; list currentOptions = []; list currentValues = []; list simpleOptions = []; list simpleActions = [];

integer djChannel = 0; integer djListen = 0; key djKey = NULL_KEY; string djName = ""; list guests = [ ]; integer everybody = FALSE; integer samegroup = FALSE; integer again = TRUE; integer linked = FALSE;

integer permissions(key id) {

   return (everybody
       || (samegroup && llSameGroup(id))
       || (llGetOwner() == id)
       || ((NULL_KEY != djKey) && (djKey == id))
       || (llListFindList(guests, [ llKey2Name(id) ])>=0));

}

configRestart() {

   configName = ".lsDialog";
   key conf = llGetInventoryKey(configName);
   if ((string)conf == configKey) return;
   if ((NULL_KEY != configKey) && (llGetFreeMemory() < 6000)) llResetScript();
   dialogNames = [];
   dialogLines = [];
   simpleOptions = [];
   simpleActions = [];
   currentName = "";
   currentLines = "";
   djChannel = 0;
   djKey = NULL_KEY;
   djName = "";
   guests = [ ];
   everybody = FALSE;
   samegroup = FALSE;
   if (conf == NULL_KEY) return;
   configKey = conf;
   configLine = 0;
   configReq = llGetNotecardLine(configName,configLine);

}

flushDialog() {

   if ("" == currentName) return;
   if ("" == currentLines) return;
   integer i = llListFindList(dialogNames,[ currentName ]);
   if (i>=0) {
       dialogNames = llDeleteSubList(dialogNames,i,i);
       dialogLines = llDeleteSubList(dialogLines,i,i);
   }
   dialogNames = dialogNames + [ currentName ];
   dialogLines = dialogLines + [ currentLines ];
   currentName = "";
   currentLines = "";

}

parseDialogRC(string data) {

   if (llStringLength(data) == 0) return;
   if (llGetSubString(data,0,0) == "#") return;
   if ((llGetSubString(data,0,0) == "[") && (llSubStringIndex(data,"]") >= 0)) {
       flushDialog();
       currentName = llGetSubString(data,1,llSubStringIndex(data,"]")-1);
       return;
   }
   if ("" == currentName) {
       if ("Allow=Owner" == data) { everybody = FALSE; samegroup = FALSE; }
       else
       if ("Allow=Group" == data) { everybody = FALSE; samegroup = TRUE; }
       else
       if ("Allow=All" == data) { everybody = TRUE; samegroup = FALSE; }
       else
       if ("Allow=" == llGetSubString(data,0,5)) { guests = guests + [ llGetSubString(data,6,-1) ]; }
       else
       if ("LSDJ=" == llGetSubString(data,0,4)) { djChannel = (integer)llGetSubString(data,5,-1); }
       else
       if ("Dialog=Again" == data) { again = TRUE; }
       else
       if ("Dialog=Once" == data) { again = FALSE; }
       else
       if ("Dialog=Link" == data) { linked = TRUE; }
   } else
   if ("*" == currentName) {
       integer p = llSubStringIndex(data,"=");
       if (0 < p) {
           simpleOptions = simpleOptions + [ llGetSubString(data, 0, p-1) ];
           simpleActions = simpleActions + [ llGetSubString(data, p+1, -1) ];
       }
   } else
   if (llSubStringIndex(data,"=") >= 0) {
       if ("" == currentLines)
           currentLines = data;
       else
           currentLines = currentLines+"\n"+data;
   }

}

parseDialogLines(string menu) {

   currentMenu = menu;
   currentOptions = [];
   currentValues = [];
   integer i = llListFindList(dialogNames, [ menu ]);
   if (i < 0) return;
   list l = llParseString2List(llList2String(dialogLines,i),[ "\n" ], []);
   integer n = llGetListLength(l);
   integer k;
   string s;
   for (i = 0; i<n; i++) {
       s = llList2String(l, i);
       k = llSubStringIndex(s,"=");
       if (k>0) {
           currentOptions = currentOptions + [ llGetSubString(s,0,k-1) ];
           currentValues = currentValues + [ llGetSubString(s,k+1,-1) ];
       }
   }

}

action(string s, key id) {

   integer q = -1;
   integer r = -1;
   q = llSubStringIndex(s," ");
   if (0 <  q) { r = q+llSubStringIndex(llGetSubString(s,q+1,-1)," ")+1; }
   if (q <  r) {
       string cmd = llGetSubString(s,0,q-1);
       integer ch = (integer)llGetSubString(s,q+1,r-1);
       string val = llGetSubString(s,r+1,-1);
       if ("say" == cmd) llSay(ch,val);
       if ("shout" == cmd) llShout(ch,val);
       if ("whisper" == cmd) llWhisper(ch,val);
       if ("region" == cmd) llRegionSay(ch,val);
       if ("root" == cmd) llMessageLinked(LINK_ROOT,ch,val,id);
       if ("link" == cmd) llMessageLinked(LINK_SET,ch,val,id);
       if ("this" == cmd) llMessageLinked(LINK_THIS,ch,val,id);
   }

}

default {

   state_entry() {
       configRestart();
       avChannel = 1000+(integer)llFrand(3000.0);
       llListen( avChannel, "", NULL_KEY, "" );
   }
   changed(integer type) {
       if (type & CHANGED_OWNER) llResetScript();
       if (type & CHANGED_INVENTORY) configRestart();
   }
   dataserver(key queryId, string data) {
       if (queryId != configReq) return;
       if (data != EOF) {
           llSetText("parsing line "+(string)configLine,<1,0,0>,1);
           parseDialogRC(data);
           configReq = llGetNotecardLine(configName,++configLine);
       } else {
           if (0 != djListen)
               llListenRemove(djListen);
           if (0 != djChannel)
               djListen = llListen( djChannel, "", NULL_KEY, "" );
           llSetText("",<1,0,0>,1);
           flushDialog();
           llOwnerSay("ready, "+(string)llGetFreeMemory()+" free memory, listen on channel: "+(string)avChannel);
       }
   }
   touch_start(integer num) {
       key id = llDetectedKey(0);
       if (!permissions(id)) return;
       if (linked) {
           integer l = llDetectedLinkNumber(0);
           integer p = llListFindList(simpleOptions, [ llGetLinkName(l) ]);
           if (0 <= p)
               action(llList2String(simpleActions, p), id);
           else {
               p = llListFindList(dialogNames, [ llGetLinkName(l) ]);
               if (p >= 0) {
                   parseDialogLines(llList2String(dialogNames,p));
                   llDialog(id,llList2String(dialogNames,p),currentOptions,avChannel);
               }
           }
       } else
       if ((llGetListLength(dialogNames) > 1) || (llGetListLength(simpleActions) > 0)) {
           currentMenu = "";
           string s = llGetObjectDesc();
           if ("" == s) s = "your command?";
           llDialog(id,s,dialogNames+simpleOptions,avChannel);
       } else
       if (llGetListLength(dialogNames) == 1) {
           parseDialogLines(llList2String(dialogNames,0));
           llDialog(id,llList2String(dialogNames,0),currentOptions,avChannel);
       }
   }
   listen(integer channel, string name, key id, string message) {
       if (djChannel == channel) {
           key k = id;
           if (llGetAgentInfo(id)<=0) k = llGetOwnerKey(k);
           if (k != llGetOwner()) return;
           list tmp = llCSV2List(message);
           if ("DJ" == llList2String(tmp,0))
               djKey = llList2String(tmp,1);
           return;
       }
       if (!permissions(id)) return;
       if ("" == currentMenu) {
           integer i = llListFindList(simpleOptions,[ message ]);
           if (i>=0) action(llList2String(simpleActions, i), id);
           else {
               parseDialogLines(message);
               llDialog(id,currentMenu,currentOptions + [ "Back" ],avChannel);
           }
       } else 
       if ("Back" == message) {
           currentMenu = "";
           string s = llGetObjectDesc();
           if ("" == s) s = "your command?";
           llDialog(id,s,dialogNames+simpleOptions,avChannel);
       } else {
           integer i = llListFindList(currentOptions,[ message ]);
           if (i>=0) action(llList2String(currentValues, i), id);
           if (again) {
               if (llGetListLength(dialogNames) > 1)
                   llDialog(id,currentMenu,currentOptions + [ "Back" ],avChannel);
               else
                   llDialog(id,currentMenu,currentOptions,avChannel);
           }
       }
   }

} </lsl>

Notecard: .lsDialog

The .lsDialog notecard defines the menu dialog tree. A typical simple notecard could look like:

<ini>

  1. default is to ask repeating ... remove comment if
  2. Dialog=Once
  3. Dialog=Link
  1. allow only one of the following
  2. Allow=Owner
  3. Allow=Group
  4. Allow=All
  1. and in addition several named avatars
  2. Allow=Kephra Nurmi
  3. Allow=Alez Ember

[*] Reset=link 0 reset

[Size] 90%=link 0 *,size,90 95%=link 0 *,size,95 100%=link 0 *,size,100 105%=link 0 *,size,105 110%=link 0 *,size,110

[Color] Lime=link 0 glass,color,Lime Ivory=link 0 glass,color,Ivory Cyan=link 0 glass,color,Cyan </ini>

This notecard will define a single prim dialog system with one top menu called 'Reset' and two sub menus called 'Size' and 'Color' with link action on channel 0 and default permissions. The object description defines the name for the top menu dialog. Each menu starts with a section header in brackets followed lines to define the dialog entries. Each entry has a name equal to an action, a channel and a string.

Possible actions are:

  • say - llSay(ch,val);
  • shout - llShout(ch,val);
  • whisper - llWhisper(ch,val);
  • region - llRegionSay(ch,val);
  • root - llMessageLinked(LINK_ROOT,ch,val,id);
  • link - llMessageLinked(LINK_SET,ch,val,id);
  • this - llMessageLinked(LINK_THIS,ch,val,id);

The top of the notecard, before any sections in brackets start, defines the permission and behavior. The hash marks lines as comments. Uncommenting Dialog=Once will cause to ask only one once, and not repeatingly. Dialog=Linked would need a 4 prim object, with buttons named 'Reset', 'Size' and 'Color'. The Allow= statements change the default permissions.