Advertisement
salahzar

Salahzar Map Wiki3d

May 19th, 2013
275
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. // This source is "OpenSource"
  2. // It can be freely used under the following CC license
  3. // by: you need to state it was originally written by Salahzar Stenvaag
  4. // nc: you cannot use for commercial products
  5. // sa: you can extend it but you must redistribute it under the same license
  6. // This software is specifically written to be used by GPLv3 licenced software
  7.  
  8. // Wiki3DBuilder (MindMap)
  9. // This had been built following the ideas (but not the code) of similar
  10. // object "SpatialMap.org (MindMap 3D) v1.0.18" written by Jonny Bee Cioc and Vision Raymaker
  11. // which was under a CC by,nc,sa license itself
  12.  
  13. // What it is
  14. // ==========
  15. // You can build rich 3D wiki architectures made up of NODES, connected with particles BEANS
  16. // Each NODE can be customized changing its NAME, COLOR, SIZE, FORM and possibly inserting in it
  17. // 1 Notecard, 1 Landmark, 1 Object, 1 Script, 1 Texture, URL that can be given
  18. // The network is completely open to the participation of a group of people who can change the
  19. // newtwork, the position of each node, and freely add or remove portions of the graph
  20.  
  21. // Being a Wiki there is no limitation on who can do what. If you don't want that the work can be furtherly
  22. // changed please set to NOT RUNNING the scripts. To save the mindmap you need to select all the nodes
  23. // and manually link them together or take in the inventory as aggregate
  24.  
  25.  
  26. // How it works
  27. // Initially you have a NODE, i.e. a cube which must be touched to start the process
  28. // Touching it you have a menu specifying color, name, size, content, move, rez, ...
  29. // * clicking on name you can type the name on the local chat and other menu for resizing, recoloring...
  30. // * clicking rez you rez a new node when choosing this option you must touch one of the faces of the cube:
  31. //   new node will be rezzed 50cm on that direction.
  32. // * similarly applies to move clicking on a face will pull the node towards that direction
  33. // * content. Everybody can move objects, textures and so from their inventory to a node (CTRL-Dragging them).
  34. //   at each moment only one type of object can be in the node and it can be given to whom is asking for content
  35. //   changing the texture will also change the texture of the node
  36.  
  37.  
  38. // Internal architecture
  39. // This is done in ONLY one script named "Salahzar Map" and an internal object named "nodo"
  40. // The "Salahzar Map" is implementing a quite interesting mechanism for dealing with "multi-threading", i.e. multiple
  41. // avatars touching the object at the same time. This is accomplished using an Array of RECORDs representing
  42. // the waiting avatars and what they were waiting for. So listen(), touch(), and other events can query this QUEUE
  43. // and understand what is to be made next.
  44. // This also allows for an interesting handling of MULTI MENU
  45. // A part from this the rest is relatively simple, except for the communication between the various nodes.
  46. // A node communicates with its children for example to propagate the DELETE message
  47. // A node communicates with its parent to emit the particles connector
  48. // A node receives messages from its parent to llDie and with alert when other related objects are changing UUID
  49. //        the latter happens when objects are re-rezzed from inventory
  50. // To accomplish this object listens to a
  51. // channelPublic (taken from Owner key) for transmitting and receiving changes of UUIDs,
  52. // or to channelPrivate (taken from the object key) for receiving commands from parent
  53.  
  54.  
  55. // CUSTOMIZABLE PARAMETERS
  56. integer TIMEOUT=30;       // menu will be obsolesced after this period of time
  57. integer CLEANTIMERSEC=30; // timer will run once every this period of time for cleaning timers
  58. integer DEBUG=2;        // 2 maximum level
  59.  
  60.  
  61. // PARTICLES CUSTOMIZATION
  62. integer PART_COUNT=5;
  63. float PART_RATE=0.01;
  64. float PART_AGE=3;
  65. vector PART_COLOR1=<1,0,0>;
  66. vector PART_COLOR2=<1,1,0>;
  67. string PART_TARGET=NULL_KEY;
  68.  
  69.  
  70. // Particles customization
  71.  
  72.  
  73. // END OF CUSTOMIZABLE PARAMETERS
  74.  
  75.  
  76. string url=""; // url associated with this node
  77.  
  78.  
  79.  
  80. // 0) General utility functions
  81.  
  82. // debug this string only if DEBUG is at least 1
  83. debug(string str)
  84. {
  85.     if(DEBUG>=1)llSay(999,str);
  86. }
  87.  
  88. // trace the string only if DEBUG is 2
  89. trace(string str)
  90. {
  91.     if(DEBUG>=2)llSay(998,str);
  92. }
  93. // will put on the hover string
  94. notify(string str)
  95. {
  96.     llSetText(str,<1,1,1>,1);
  97. }
  98.  
  99.  
  100.  
  101. // 1) RECORD STACK
  102. // handling. We keep a "queue" or RECORDS for understanding
  103. // multi-avatar touching and remember prompts and menu and let them expire
  104. //
  105.  
  106. integer STRIDE=6; // we hold 6 field in the waiting list
  107. list waiting=[]; // this is where we actually keep the queue
  108.  
  109. // this will be the RECORD with the 6 fields
  110. string theType;     // it is something like MENUxxxx or PROMPTyyyy
  111. key theAv;          // which avatar is waiting
  112. integer theTime;    // when the RECORD has been stacked
  113. integer theMenu;    // the menu handle so we can clean up it
  114. integer theChannel; // which channel
  115. string theRest;     // some further information on this RECORD (prompt string?)
  116.  
  117. // count how many RECORDS are being stacked waiting to be served
  118. integer howManyRecords()
  119. {
  120.     integer ret= llGetListLength(waiting)/STRIDE;
  121.     trace("howManyRecords returning: "+(string)ret);
  122.     return ret;
  123. }
  124. // load the record in theXXX variables to ease handling of it
  125. integer loadTheRecord(integer index)
  126. {
  127.     if(index>=0)
  128.     {
  129.        theType=llList2String(waiting,index);
  130.        theAv=llList2Key(waiting,index+1);
  131.        theTime=llList2Integer(waiting,index+2);
  132.        theMenu=llList2Integer(waiting,index+3);
  133.        theChannel=llList2Integer(waiting,index+4);
  134.        theRest=llList2String(waiting,index+5);
  135.        debug("Loading the record: \n   type: "+theType+"\n   Av: "+(string)theAv
  136. +"\n   time: "+(string)theTime+"\n   menu: "+(string)theMenu+"\n   channel:"
  137. +(string)theChannel+"\n   rest:"+theRest);
  138.        return index;
  139.     }
  140.     else
  141.     {
  142.         theType="";
  143.         theAv=NULL_KEY;
  144.         theTime=-1;
  145.         theMenu=-1;
  146.         theChannel=-1;
  147.         theRest="";
  148.         trace("No record returned");
  149.         return -1;
  150.     }
  151. }
  152.  
  153. // look in our stack for this avatar return the index AND loading in theXXX variables
  154.  
  155. integer findWaitingAvatar(key av)
  156. {
  157.     debug("Looking for avatar: "+(string)av);
  158.    integer pos=llListFindList(waiting,[av]);
  159.    integer index;
  160.    if(~pos) index=pos-1; else index=-1;
  161.    return loadTheRecord(index);
  162. }
  163. // change the time of the event at position index
  164. updateTimer(integer index)
  165. {
  166.     if(index<0 || index>=howManyRecords()) return;
  167.     trace("Updating timer for index: "+(string)index);
  168.     integer posTime=index*STRIDE+2;
  169.     waiting=llListReplaceList(waiting,[ llGetUnixTime() ], posTime, posTime);
  170. }
  171.  
  172. // remove a record
  173. integer deleteRecord(integer index)
  174. {
  175.     if(index>=0 && index<howManyRecords())
  176.     {
  177.         integer i=index*STRIDE;
  178.         waiting=llDeleteSubList(waiting,i,i+STRIDE-1);
  179.         trace("deleteRecord "+(string)index+" array: "+llList2CSV(waiting));
  180.     }
  181.     return TRUE;
  182. }
  183.  
  184. // PSEUDO record containing the avatar for detecting key and message
  185. key detected_key=NULL_KEY;
  186. string detected_type="";
  187.  
  188. // add a MENU stack in the queue
  189. addMenu(string type, key av, string title, list options)
  190. {
  191.     trace("Adding menu "+type+" for "+(string)av);
  192.     integer channel=-1000000-(integer)llFrand(1000000);
  193.     integer menuid=llListen(channel,"",av,"");
  194.     waiting+=[ type, av, llGetUnixTime(), menuid, channel,"" ];
  195.     //debug("List in touch: "+llList2CSV(waiting));
  196.     llDialog(av,title,options,channel);
  197.  
  198. }
  199. // add a PROMPT stack in the queue
  200. addPrompt(string type, key av, string title)
  201. {
  202.     trace("Adding prompt "+type+" for "+(string)av);
  203.     integer menuid=llListen(0,"",av,"");
  204.     waiting+=[ type, av, llGetUnixTime(), menuid, 0, title];
  205.  
  206.     llInstantMessage(av,"Please chat: "+title);
  207.  
  208.  
  209. }
  210. // add in queue detect option to be able square is TRUE if we only allow boxed movement
  211. addDetected(string type, key av, string title)
  212. {
  213.     trace("Adding detected "+type+" for "+(string)av);
  214.     detected_key=av;
  215.     detected_type=type;
  216.  
  217.  
  218. }
  219. remove_detected()
  220. {
  221.     trace("remove detected");
  222.     detected_key=NULL_KEY;
  223.     detected_type="";
  224. }
  225.  
  226. // 2) INVENTORY HANDLING
  227.  
  228. list currentInventory=[]; // will keep note of current inventory
  229. // return a list of strings in ls1 NOT in ls2
  230. // actually implementing set difference : [ a,b,c ] - [a, b] => [c]
  231. // useful to understan which elements have been added deleted in the inventory
  232. list diffList(list ls1, list ls2)
  233. {
  234.     //llSay(0,"ls1: "+llList2CSV(ls1)+" ls2:"+llList2CSV(ls2));
  235.     list ret=[];
  236.     integer i=0;
  237.     for(i=0;i<llGetListLength(ls1);i++)
  238.     {
  239.         list el=llList2List(ls1,i,i);
  240.         // if not found in ls2 add to residual
  241.         if(llListFindList(ls2, el)<0)
  242.         {
  243.             ret+=el;
  244.         }
  245.     }
  246.     return ret;
  247. }
  248.  
  249. // find out the first inventory object of the specified type
  250. string getFromListOfType(list lst,integer type)
  251. {
  252.     integer i;
  253.     for(i=0;i<llGetListLength(lst);i++)
  254.     {
  255.         string name=llList2String(lst,i);
  256.         if(name != "nodo" && name != llGetScriptName() && name != "llSetPin")
  257.         {
  258.             if(llGetInventoryType(name)==type) return name;
  259.         }
  260.     }
  261.     return "";
  262. }
  263.  
  264. // will check if inventory changed and make sure that we have JUST one elemento
  265. // for each type
  266. inventoryUpdate()
  267. {
  268.     //llSay(0,"inventory update");
  269.     integer i=0; integer j=0; string ret="";
  270.     integer num=llGetInventoryNumber(INVENTORY_ALL);
  271.     //if(num==llGetListLength(currentInventory)) return;
  272.  
  273.     list newInventory=[];
  274.     for(i=0;i<num;i++)
  275.     {
  276.         string name=llGetInventoryName(INVENTORY_ALL,i); integer found=0;
  277.         newInventory+=[name];
  278.     }
  279.     // now find added inventory
  280.     list added=diffList(newInventory,currentInventory);
  281.     list removed=diffList(currentInventory,newInventory);
  282.  
  283.     //llSay(0,"==>Added "+llList2CSV(added));
  284.     //llSay(0,"==>Removed "+llList2CSV(removed));
  285.  
  286.     // now check for each added if there was a duplicate in currentInventory
  287.     for(i=0;i<llGetListLength(added);i++)
  288.     {
  289.        string name=llList2String(added,i);
  290.        string already=getFromListOfType(currentInventory,llGetInventoryType(name));
  291.        if(already!="")
  292.        {
  293.            llRemoveInventory(already);
  294.            llSay(0,name+" replaced "+already);
  295.        }
  296.        else
  297.            llSay(0,name+" inserted in content");
  298.  
  299.        if(llGetInventoryType(name)==INVENTORY_TEXTURE)
  300.         llSetTexture(name,ALL_SIDES);
  301.     }
  302.  
  303.     currentInventory=newInventory;
  304.     return;
  305. }
  306.  
  307. // 3) handles particles
  308. key target=NULL_KEY;
  309. particles()
  310. {
  311.  
  312.       trace("making particles to "+(string)target);
  313.         integer pattern = PSYS_SRC_PATTERN_EXPLODE;
  314.         integer flags= PSYS_PART_EMISSIVE_MASK
  315.                         | PSYS_PART_INTERP_COLOR_MASK
  316.                         //| PSYS_PART_FOLLOW_SRC_MASK
  317.                         //| PSYS_PART_FOLLOW_VELOCITY_MASK
  318.                         | PSYS_PART_INTERP_SCALE_MASK
  319.                         | PSYS_PART_TARGET_LINEAR_MASK
  320.                         | PSYS_PART_TARGET_POS_MASK;
  321.         // set particles
  322.         llParticleSystem([  PSYS_PART_MAX_AGE,PART_AGE,
  323.                         PSYS_PART_FLAGS, flags,
  324.                         PSYS_PART_START_COLOR, PART_COLOR1,
  325.                         PSYS_PART_END_COLOR, PART_COLOR2,
  326.                         PSYS_PART_START_SCALE,<0.1,.1,FALSE>,
  327.                         PSYS_PART_END_SCALE,<0.1,.1,FALSE>,
  328.                         PSYS_SRC_PATTERN, pattern,
  329.                         PSYS_SRC_BURST_RATE,PART_RATE,
  330.                         //PSYS_SRC_ACCEL, <0,0,0>,
  331.                         PSYS_SRC_BURST_PART_COUNT,PART_COUNT,
  332.                         //PSYS_SRC_BURST_RADIUS,0.0,
  333.                         PSYS_SRC_BURST_SPEED_MIN,0,
  334.                         PSYS_SRC_BURST_SPEED_MAX,0,
  335.                         PSYS_SRC_TARGET_KEY,target,
  336.                         PSYS_SRC_ANGLE_BEGIN,0.0,
  337.                         PSYS_SRC_ANGLE_END,0.0,
  338.                         PSYS_SRC_OMEGA, <0,0,0>, // no swirling
  339.                         PSYS_SRC_MAX_AGE, 0.0, // particles last for ever
  340.                         PSYS_SRC_TEXTURE, PART_TARGET,
  341.                         PSYS_PART_START_ALPHA, 1.0,
  342.                         PSYS_PART_END_ALPHA, 1.0
  343.                             ]);
  344.  
  345.  
  346. }
  347. // 4) This will convert an id to an integer same id => same key
  348. // used to easily set up a not easy way to deposit scripts with a PIN
  349. integer key2int(key id)
  350. {
  351.     string idstring = (string)id;
  352.     integer ret = 0;
  353.     integer i = 0;
  354.     for(; i < llStringLength(idstring); ++i)
  355.     {
  356.         ret = ret * 10 + (((integer)("0x8"+llGetSubString(idstring, i, i)) - 2) % 17);
  357.     }
  358.     return ret;
  359. }
  360.  
  361. integer isroot=TRUE; // are we the MAIN object? Useful to avoid being deleted
  362. list children=[]; // will keep the keys of ALL depending children
  363.  
  364. // 5) propagate message to all children
  365. propagate(string message)
  366. {
  367.     debug("Received message propagating to children: "+llList2CSV(children));
  368.     // received a message from my parent
  369.     // propagate message to my children
  370.     integer i;
  371.     for(i=0;i<llGetListLength(children);i++)
  372.     {
  373.         integer channel=key2int(llList2Key(children,i));
  374.         debug("Saying on channel "+(string)channel+" "+message);
  375.         llSay(channel,message);
  376.     }
  377.     if(message=="DELETE")
  378.     {
  379.       // we must die IF we are not ROOT
  380.  
  381.       if(isroot==0) llDie();
  382.       else debug("Cannot delete master cube");
  383.     }
  384.  
  385. }
  386.  
  387. // ============================== MAIN =========================
  388.  
  389. integer lstPrivate;
  390. integer lstPublic;
  391. integer channelPublic;
  392. integer channelPrivate;
  393.  
  394. key parent=NULL_KEY;
  395. default
  396. {
  397.     state_entry()
  398.     {
  399.         llParticleSystem([]);
  400.         llSetText("",<1,1,1>,1);
  401.         // setting the communication channel identity private can change when re-rezzing
  402.         channelPrivate=key2int(llGetKey());
  403.         channelPublic=key2int(llGetOwner());
  404.         debug("My local channel: "+(string)channelPrivate);
  405.         debug("My public channel: "+(string)channelPublic);
  406.  
  407.         // if we are the main node go directly to ready
  408.         // we know that because we don't have the llSetPin on main Ball
  409.         inventoryUpdate(); // setup inventory
  410.         if(llGetInventoryType("llSetPin")==INVENTORY_NONE)
  411.         {
  412.             isroot=TRUE;
  413.             //llRequestPermissions(llGetOwner(), PERMISSION_CHANGE_LINKS);
  414.             state ready;
  415.         }
  416.  
  417.         isroot=FALSE;    
  418.         // we are in a child node,
  419.         notify("child...");  
  420.         trace("child ready");    
  421.         // else rezzed by parent wait to listen who is the parent
  422.         // parent will send a message on a special channel computed starting from
  423.         // the child key
  424.  
  425.         // waiting for knowing who is my parent
  426.         lstPrivate=llListen(channelPrivate,"",NULL_KEY,"");
  427.     }
  428.     on_rez(integer rez)
  429.     {
  430.         if(isroot) return;
  431.        
  432.         // allow inventory dropping (for content dropping)
  433.         llAllowInventoryDrop(TRUE);
  434.         trace("Object rezzed with new taskUUID");
  435.         // this happens ONLY if I come back from the inventory my UUID has changed
  436.         // then will broadcast my old UUID
  437.         string what="OUID:"+llGetObjectDesc();
  438.         debug("Saying "+what+" in public channel "+(string)channelPublic);
  439.         llSay(channelPublic,what);
  440.  
  441.         // private channel has to be reset!
  442.         llListenRemove(lstPrivate);
  443.         channelPrivate=key2int(llGetKey());
  444.         trace("Listening to new privateChannel "+(string)channelPrivate);
  445.         lstPrivate=llListen(channelPrivate,"",NULL_KEY,"");
  446.  
  447.         // reset the description
  448.         llSetObjectDesc((string)llGetKey());
  449.  
  450.     }
  451.  
  452.     // this listen only waits until my parent talks to me
  453.     // this happens when rezzing avatar stops the menu
  454.     listen(integer channel,string name, key id, string str)
  455.     {
  456.         debug("received "+str+" on channel "+(string)channel);
  457.  
  458.         // set my parent to whom is talking to me first
  459.         parent=id;
  460.         // llListenRemove(lstparent);
  461.  
  462.         // emits the beam towards my parent
  463.         target=id;
  464.         particles();
  465.  
  466.         // remove listener before leaving this state
  467.         llListenRemove(lstPrivate);    
  468.  
  469.         state ready;
  470.     }
  471.  
  472.  
  473. }
  474.  
  475. // =========================== READY =========================
  476.  
  477.  
  478. state ready
  479. {
  480.     state_entry()
  481.     {    
  482.         // reset waiting list
  483.         waiting=[]; children=[]; notify(llGetObjectName());        
  484.         llSetTimerEvent(CLEANTIMERSEC); // garbage collector
  485.  
  486.         // listen on private channel (for messages from parent -- delete)
  487.         lstPrivate=llListen(channelPrivate,"",NULL_KEY,"");
  488.  
  489.         // listen on public channel (for UUID changing)
  490.         lstPublic=llListen(channelPublic,"",NULL_KEY,"");
  491.  
  492.         // allow inventory dropping (for content dropping)
  493.         llAllowInventoryDrop(TRUE);
  494.        
  495.         llSetText("...",<1,1,1>,1);
  496.  
  497.         // If here it means I'm being creating from scratch... Mark my UUID on the description
  498.         llSetObjectDesc((string)llGetKey());
  499.     }
  500.  
  501.     on_rez(integer rez)
  502.     {
  503.         trace("Object rezzed with new taskUUID");
  504.         // this happens ONLY if I come back from the inventory my UUID has changed
  505.         // then will broadcast my old UUID
  506.         string what="OUID:"+llGetObjectDesc();
  507.         debug("Saying "+what+" in public channel "+(string)channelPublic);
  508.         llSay(channelPublic,what);
  509.  
  510.         // private channel has to be reset!
  511.         llListenRemove(lstPrivate);
  512.         channelPrivate=key2int(llGetKey());
  513.         trace("Listening to new privateChannel "+(string)channelPrivate);
  514.         lstPrivate=llListen(channelPrivate,"",NULL_KEY,"");
  515.  
  516.         // reset the description
  517.         llSetObjectDesc((string)llGetKey());
  518.  
  519.     }
  520.     // If we changed owner or inventory
  521.     changed(integer change)
  522.     {
  523.         //llSay(0,"change: "+(string)change);
  524.         if(change & CHANGED_OWNER)
  525.         {
  526.             debug("Changed owner, resetting");
  527.             llResetScript();
  528.         }
  529.         // handle changing of the inventory or somebody dropped
  530.         if(change & CHANGED_INVENTORY || change & CHANGED_ALLOWED_DROP)
  531.         {
  532.             inventoryUpdate();
  533.         }
  534.     }
  535.  
  536.  
  537.     // timer is trying to get all the menu listener clean
  538.     // if they are exhausted then proceed to cancel them
  539.     timer()
  540.     {
  541.         integer i;
  542.         for(i=0;i<howManyRecords();i++)
  543.         {
  544.             loadTheRecord(i); // into theXXXX fields
  545.  
  546.             // check if timeout (60 seconds
  547.             if( (llGetUnixTime() - theTime ) > TIMEOUT )
  548.             {
  549.                 debug("Removing listener for "+llKey2Name(theAv));
  550.                 // if we were on  particular menu should also delete the
  551.                 llListenRemove(theMenu);
  552.                 deleteRecord(i);
  553.  
  554.                 // if timeout something related to the detected avatar need to remove from list
  555.                 if(detected_key==theAv) remove_detected();
  556.  
  557.             }
  558.         }
  559.         //debug("List in timer exit: "+llList2CSV(waiting));
  560.     }
  561.  
  562.  
  563.     // main menu listening for waiting avatars
  564.     // we answer only to
  565.     touch_start(integer total_number)
  566.     {
  567.         integer i;
  568.         for(i=0;i<total_number;i++)
  569.         {
  570.             key av=llDetectedKey(i);
  571.             debug("touched by "+llKey2Name(av));
  572.  
  573.             // check if we already have this avatar waiting. Don't allow touches if in a menu or a prompt!!!!
  574.             integer index=findWaitingAvatar(av);
  575.             if(index>=0)
  576.             {  
  577.                 debug("Has already a menu waiting");
  578.                 // we have a menu for this avatar.. Check if we have it in detected_key
  579.                 // in such case we allow touching for detecting
  580.                 if(av==detected_key)
  581.                 {
  582.                     trace("We have a detected_key for this avatar  type:"+detected_type);
  583.                     // handle this event
  584.                     if(detected_type=="DETECTMOVE")
  585.                     {
  586.                         debug("Moving the prim");
  587.                         llSetPos(llGetPos()+llDetectedTouchNormal(i)*0.2);      
  588.                     }
  589.  
  590.                    if(detected_type=="DETECTPOSREZ")
  591.                    {
  592.                         debug("rezzing a new cube");
  593.                         vector posrez=llDetectedTouchNormal(i);
  594.                         llRezAtRoot("nodo",llGetPos()+posrez,ZERO_VECTOR,ZERO_ROTATION,1);
  595.                         // execution is going on at rez_object
  596.  
  597.                     }
  598.                     //upgrade time for this event extend it so that timer won't remove it for next 60 secs
  599.                     updateTimer(index);
  600.  
  601.                     // do NOT consume this event will be ended by ctimeout
  602.                     return;
  603.                 }                
  604.  
  605.                 // touch this when avatar has already a queue, will remove the queue
  606.                 deleteRecord(index);
  607.  
  608.                 // informing the avatar the menu has been reset
  609.                 llInstantMessage(av,"Removing pending menu/promt");
  610.                 return;
  611.             }
  612.  
  613.             // avatar hasn't any pending menu so start with main menu
  614.             // start the initial menu
  615.             addMenu("MENUMAIN",av,"Main menu:\nDELETE: delete this and children,\nNAME: you can type the new name,\nCOLOR: change the color,\nSIZE: change the scale,\nREZ: rez another node (click next on face for where to rez)\nMOVE: pull the object in a direction (click next on face for where to rez),\nTYPE: changes the object type,\nHELP: go to online help,\nUNLINK: remove the connecting beam",
  616.             ["DELETE","NAME","COLOR",
  617.              "SIZE","REZ","MOVE",
  618.              "TYPE","HELP","UNLINK",
  619.              "CONTENT" ]);
  620.              trace("List in touch exit: "+llList2CSV(waiting));
  621.             return;
  622.         }
  623.     }
  624.  
  625.  
  626.     // listen must understand if this avatar already has pending menu
  627.     // and correctly sort out of them
  628.     listen(integer channel,string name, key id, string message)
  629.     {
  630.         debug("receiving a message in channel "+(string)channel+" message "+message);
  631.  
  632.         // PRIVATE CHANNEL
  633.         if(channel==channelPrivate)
  634.         {
  635.             debug("Received a message for me from my parent "+message);
  636.             propagate(message);
  637.             return;
  638.         }
  639.  
  640.         // PUBLIC CHANNEL
  641.         if(channel==channelPublic)
  642.         {
  643.             // on channel public we ONLY receive OLD UUID in the format
  644.             // UUID:
  645.             if(llGetSubString(message,0,4)=="OUID:")
  646.             {
  647.                 key olduuid=(key)llGetSubString(message,5,-1);
  648.                 debug("Received from "+(string)id+" UUID change from old "+(string)olduuid);
  649.  
  650.                 // need to understand if it was MY target
  651.                 if(target==olduuid){
  652.                   target=id;
  653.                   particles(); // change the beam to this new target
  654.                 }
  655.                 // check my children
  656.                 integer pos=llListFindList(children,[olduuid]);
  657.                 if(pos>=0)
  658.                 {
  659.                   debug("Replacing in children olduuid: "+(string)olduuid+" with "+(string)id);
  660.                   children=llListReplaceList(children,[id],pos,pos);
  661.                 }
  662.  
  663.             }
  664.             return;
  665.         }
  666.  
  667.         // if not channel public or private then it shoudl be on stack        
  668.         integer index=findWaitingAvatar(id);
  669.         debug("listen index found on waiting list: "+(string)index);
  670.         if(index<0) return;
  671.  
  672.         // only here if we found on the stack
  673.         integer elapsed=llGetUnixTime()-theTime;
  674.  
  675.         // remove handle AND the record from waiting list
  676.         llListenRemove(theMenu);
  677.         deleteRecord(index);
  678.         debug("Found listen menu type: "+theType+" mesg "+message);
  679.  
  680.  
  681.         // stopping menus          
  682.         if(theType=="MENUSTOPMOVE")
  683.         {
  684.              remove_detected();
  685.              llInstantMessage(id,"Stop moving");
  686.              return;
  687.         }
  688.         if(theType=="MENUSTOPREZ")
  689.         {
  690.              remove_detected();
  691.              llInstantMessage(id,"Stop rezzing");
  692.              return;
  693.         }
  694.  
  695.         // handling menu content allow for setting content
  696.         if(theType=="MENUCONTENT")
  697.         {
  698.           // allows for specifying a URL
  699.           if(message=="SETURL")
  700.           {
  701.               addPrompt("PROMPTURL",id,"Say in chat the url where to go");
  702.               return;
  703.           }
  704.           // just send help on how ctrl-dragging objects
  705.           if(message=="SETCONTENT")
  706.           {
  707.               // send help              
  708.               llInstantMessage(id,"Please ctrl-drag something from your inventory on me. You can change the texture dragging a texture");
  709.               return;
  710.           }
  711.  
  712.           // going to stored URL
  713.           if(message=="GIVE URL")
  714.           {
  715.               if(url!="")
  716.               {
  717.                   llLoadURL(id,"Go to webpage",url);
  718.               }
  719.               return;
  720.           }
  721.           // handle all GETXXX buttons
  722.           string name1; string desc;
  723.           if(message=="GIVE NOTE")
  724.           {
  725.               name1=getFromListOfType(currentInventory,INVENTORY_NOTECARD);
  726.               desc="notecard";
  727.           }
  728.           if(message=="GIVE LMARK")
  729.           {
  730.               name1=getFromListOfType(currentInventory,INVENTORY_LANDMARK);
  731.               desc="landmark";
  732.           }
  733.           if(message=="GIVE OBJECT")
  734.           {
  735.               name1=getFromListOfType(currentInventory,INVENTORY_OBJECT);
  736.               desc="object";
  737.           }
  738.           if(message=="GIVE TEXTURE")
  739.           {
  740.               name1=getFromListOfType(currentInventory,INVENTORY_TEXTURE);
  741.               desc="texture";
  742.           }
  743.  
  744.           if(name1=="")
  745.           {
  746.                   llInstantMessage(id,"No "+desc+" to give you");
  747.                   return;
  748.           }
  749.           // giving actually the object
  750.           llGiveInventory(id,name1);
  751.           llInstantMessage(id,"You have been given a "+desc+" named "+name1);
  752.           return;
  753.  
  754.  
  755.         }
  756.  
  757.         // Handling of the options in MAIN MENU
  758.         if(theType=="MENUMAIN")
  759.         {
  760.            if(message=="HELP")
  761.            {
  762.                llLoadURL(id,"Load this page for help","http://opensimita.org/lsl/mindmap/README.html");
  763.                 return;
  764.            }
  765.            if(message=="CONTENT")
  766.            {
  767.                integer i;
  768.                string texture=getFromListOfType(currentInventory,INVENTORY_TEXTURE);
  769.                string object=getFromListOfType(currentInventory,INVENTORY_OBJECT);
  770.                string note=getFromListOfType(currentInventory,INVENTORY_NOTECARD);
  771.                string landmark=getFromListOfType(currentInventory,INVENTORY_LANDMARK);
  772.                string prompt = "Choose an action:\nSETCONTENT: explains how to insert an object\nSETURL: allows for specifying a url";
  773.                list buttons=["SETCONTENT","SETURL" ];
  774.                if(url!="")
  775.                {
  776.                    prompt+="\nGIVE URL: go to the url "+url;
  777.                    buttons+=["GIVE URL"];
  778.                }
  779.                if(note!="")
  780.                {
  781.                    prompt+="\nGIVE NOTE: get the note "+note;
  782.                    buttons+=["GIVE NOTE"];
  783.                }
  784.  
  785.                if(object!="")
  786.                {
  787.                    prompt+="\nGIVE OBJECT: get the object "+object;
  788.                    buttons+=["GIVE OBJECT"];
  789.                }                  
  790.  
  791.                if(landmark!="")
  792.                {
  793.                    prompt+="\nGIVE LMARK: get the landmark "+landmark;
  794.                    buttons+=["GIVE LMARK"];
  795.                }
  796.                if(texture!="")
  797.                {
  798.                    prompt+="\nGETTEXTURE: get the texture "+texture;
  799.                    buttons+=["GIVE TEXTURE"];
  800.                }
  801.  
  802.  
  803.                addMenu("MENUCONTENT",id,prompt,buttons);
  804.                return;
  805.            }
  806.            if(message=="NAME")
  807.            {
  808.                addPrompt("PROMPTNAME",id,"Say in chat name of this concept");
  809.                return;
  810.             }
  811.             if(message=="DELETE")
  812.             {
  813.                 addPrompt("PROMPTDELETE",id,"Say DELETE in chat to be absolutely sure to delete from here");
  814.                 return;
  815.             }
  816.             if(message=="COLOR")
  817.             {
  818.                addMenu("MENUCOLOR",id,"Enter color",["RED","GREEN","BLUE","WHITE","BLACK","VIOLET","TURQUESE","YELLOW"]);
  819.                return;
  820.             }
  821.             if(message=="SIZE")
  822.             {
  823.                addMenu("MENUSIZE",id,"Enter size",["HALF", "DOUBLE", "+0.2","-0.2","DEFAULT"]);
  824.                return;
  825.             }
  826.  
  827.             if(message=="UNLINK")
  828.             {
  829.                 llParticleSystem([]); target=NULL_KEY;
  830.                 llInstantMessage(id,"Removed particles");
  831.                 return;
  832.             }
  833.             // detected category
  834.             if(message=="REZ")
  835.             {
  836.                 addDetected("DETECTPOSREZ",id,"Enter position where rez");
  837.                 addMenu("MENUSTOPREZ",id,"Click on a face of the concept to rez a new cube in that direction.\nClick 'stop' after chosing",["STOP"]);
  838.                 return;
  839.             }
  840.             if(message=="MOVE")
  841.             {
  842.                 addDetected("DETECTMOVE",id,"Click on a face of the concept and the cube will move 20cm in that direction.");
  843.                 addMenu("MENUSTOPMOVE",id,"Click to stop moving",["STOP"]);
  844.                 return;
  845.             }
  846.             if(message=="TYPE")
  847.             {
  848.                 addMenu("MENUTYPE",id,"Select type of this concept",["SPHERE","CUBE","FLAT","CYLINDER","PYRAMID","POINT","STAR","ENDTYPE"]);
  849.                 return;
  850.             }
  851.         }
  852.  
  853.         // change the type of this prim    
  854.         if(theType=="MENUTYPE")
  855.         {
  856.             if(message=="ENDTYPE")
  857.             {
  858.                 llInstantMessage(id,"Finished with typing");
  859.                 return;
  860.             }
  861.             list typ=[];
  862.             if(message=="FLAT")
  863.             {
  864.                vector scale=llGetScale();
  865.               llSetScale(<0.01,scale.y,scale.z>);
  866.               return;
  867.             }
  868.  
  869.             if(message=="POINT")
  870.             {
  871.               llSetScale(<0.01,0.01,0.01>);
  872.               return;
  873.             }
  874.             if(message=="STAR")
  875.             {
  876.               llInstantMessage(id,"STAR not yet implemented");
  877.               return;
  878.             }
  879.  
  880.  
  881.             if(message=="SPHERE") typ=[ PRIM_TYPE, PRIM_TYPE_SPHERE, 0, <0,1,0>, 0.0, <0,0,0>,<0,1,0> ];
  882.             if(message=="CUBE") typ=[ PRIM_TYPE, PRIM_TYPE_BOX,0, <0.0, 1.0, 0.0>, 0.0, <0.0, 0.0, 0.0>, <1.0, 1.0, 0.0>, <0.0, 0.0, 0.0>];
  883.             if(message=="CYLINDER") typ=[ PRIM_TYPE, PRIM_TYPE_CYLINDER, 0, <0.0, 1.0, 0.0>, 0.0, <0.0, 0.0, 0.0>, <1.0, 1.0, 0.0>, <0.0, 0.0, 0.0>];
  884.             if(message=="PYRAMID") typ=[ PRIM_TYPE, PRIM_TYPE_BOX,0, <0.0, 1.0, 0.0>, 0.0, <0.0, 0.0, 0.0>, <0.0, 0.0, 0.0>, <0.0, 0.0, 0.0>];
  885.  
  886.             llSetPrimitiveParams(typ);
  887.  
  888.             addMenu("MENUTYPE",id,"Select type of this concept",["SPHERE","CUBE","FLATBOX","CYLINDER","PYRAMID","POINT","STAR","ENDTYPE"]);
  889.             return;            
  890.  
  891.         }
  892.  
  893.  
  894.         // change the size of this prim
  895.         if(theType=="MENUSIZE")
  896.         {
  897.             vector current=llGetScale();
  898.             if(message=="HALF") current=current/2;
  899.             if(message=="DOUBLE") current=current*2;
  900.             if(message=="+0.2") current=current+<0.2,0.2,0.2>;
  901.             if(message=="-0.2") current=current-<0.2,0.2,0.2>;
  902.             if(message=="DEFAULT") current=<0.5,0.5,0.5>;
  903.             llSetScale(current);
  904.             llInstantMessage(id,"Size changed to '"+(string)current+"'");
  905.             return;
  906.  
  907.         }
  908.  
  909.         // change the color of this prim
  910.         if(theType=="MENUCOLOR")
  911.         {
  912.             if(message=="RED") llSetColor(<1,0,0>,ALL_SIDES);
  913.             if(message=="GREEN") llSetColor(<0,1,0>,ALL_SIDES);
  914.             if(message=="BLUE") llSetColor(<0,0,1>,ALL_SIDES);
  915.             if(message=="WHITE") llSetColor(<1,1,1>,ALL_SIDES);
  916.             if(message=="BLACK") llSetColor(<0,0,0>,ALL_SIDES);
  917.             if(message=="VIOLET") llSetColor(<1,0,1>,ALL_SIDES);
  918.             if(message=="TURQUESE") llSetColor(<0,1,1>,ALL_SIDES);
  919.             if(message=="YELLOW") llSetColor(<1,1,0>,ALL_SIDES);
  920.             llInstantMessage(id,"Color changed to '"+message+"'");
  921.             return;
  922.         }
  923.  
  924.         // change the name
  925.         if(theType=="PROMPTNAME")
  926.         {
  927.             notify(message);
  928.             llSetObjectName(message);
  929.             llInstantMessage(id,"Name changed to '"+message+"'");
  930.             return;
  931.         }
  932.         if(theType=="PROMPTDELETE")
  933.         {
  934.             if(message=="DELETE")
  935.             {
  936.                 // handle delete message
  937.                 propagate(message);
  938.                 return;
  939.             }
  940.         }  
  941.  
  942.         // change the url
  943.         if(theType=="PROMPTURL")
  944.         {
  945.             url=message;
  946.             llInstantMessage(id,"URL accepted: "+url);
  947.             return;
  948.         }  
  949.  
  950.  
  951.     }
  952.     // when new node is rezzed then we give this script running and tell it
  953.     // my id so that it can emit particles
  954.     object_rez(key id)
  955.     {
  956.  
  957.         integer childchannel=key2int(id);
  958.  
  959.        
  960.         // memorize this channel so to be able to speak to all my children in case of die
  961.         children+=[id];
  962.         llGiveInventory(id,"nodo");
  963.  
  964.         debug("Chatting "+(string)llGetKey()+" on channel "+(string)key2int(id)+ "children: "+llList2CSV(children));
  965.         llSay(childchannel,(string)llGetKey());
  966.  
  967.         //llInstantMessage("Node created");
  968.     }
  969. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement