Jump to content

Kaluura Boa

Resident
  • Posts

    179
  • Joined

  • Last visited

Everything posted by Kaluura Boa

  1. Short answer: No. Long answer: Nooooooooo. :matte-motes-big-grin-wink: The name of the object and its owner always appear in a dialog to tell you who is speaking to you. It can neither be removed nor hidden.
  2. La première chose à faire est de vérifier les paramètres s'appliquant à l'onglet "Récent". Je ne sais plus quelle est la durée par défaut. Allonge-la pour voir si quelque-chose apparait. Une autre possibilité est de regarder dans l'onglet principal de ton inventaire, trié par date. Les objects les plus récents seront placés en tête de liste. Ouvre les dossiers "Objects" (pour les boîtes) et tous les autres dossiers dont le nom indique une possible zone d'arrivée pour ce que tu as acheté. Si tu ne trouves toujours rien, vérifie dans ton historique des transactions que tu as bien été débitée pour ce que tu as acheté (Cherche dans les menus, ça dépend des viewers.) et envoie un message au vendeur, le cas échéant. En général, ça se fait en Anglais et par "notecard". (Je n'ai jamais pris la peine d'utiliser l'interface en Français, je ne connais pas la traduction de ce mot qui n'est pas dans le dico.) Sois patiente, donne quelques jours au vendeur pour réagir. Après avoir estimé avoir été ignorée suffisamment longtemps, tu peux re-sortir ton Anglais de sa boîte et envoyer un rapport d'abus à Linden Lab (abuse report) ou un ticket (si tu as un compte premium et s'il y a une catégorie idoine, je ne sais plus.) Mais tu ne devrais pas en arriver là. Il y a parfois des délais, voire des échecs à la livraison. Contacter le vendeur suffit en général.
  3. C'est simple. Tout ce que tu acquières arrive dans ton inventaire. Le plus souvent, c'est dans une boîte mais, parfois, ça peut aussi arriver dans l'un des dossiers dédiés. Une boîte d'arrivée est prévue dans un futur proche mais, pour le moment, le plus simple est d'ouvrir l'onglet "Récent" de ton inventaire. Pour ouvrir une boîte, il faut d'abord la faire glisser de ton inventaire sur le sol. Certains vendeurs auront pensé à donner la possibilité d'utiliser un simple clic gauche. Pour les autres: Clic droit, Ouvrir. Là encore, tu retrouveras tout dans l'onglet "Récent". (Merci de ramasser les boîtes vides !) :smileywink: Si tu achètes dans un magasin dans SL, parfois tu pourras ouvrir tes boîte sur place, parfois non, selon si le vendeur a été trop souvent confronté au problème des boîtes vides qui jonchent le sol ou non. Regarde en haut, à côté du nom de l'endroit où tu te trouves. Un cube barré de rouge signifie "non constructible". Quant aux "zones constructibles", le mot en Anglais est "sandbox" (bac-à-sable). Utilise la carte pour les trouver. (Note: Evite Cordova, Goguen, Wanderton, Sandbox Island. Ces regions se transforment parfois en zones de catastrophes non-naturelles qui ne conviennent pas aux nouveau-venus.) :smileyfrustrated: Et pour finir, un nouveau mot à ajouter à ton vocabulaire: "rezzer" (En Anglais: to rez). Cela signifie faire apparaître quelque chose, dans la plupart des cas grâce à un glisser-déposer depuis ton inventaire. Je rezze, tu rezzes, nous rezzons. :smileyvery-happy:
  4. Before somebody tell it to you in a more rude way: SL is not a game... and you obviously know very little about SL. Let me break it down for you. Games that you can buy on DVD or online are dead things. Their end is already written somewhere in their files and even if you can wander endelessly in the environment, import new vehicles, tune the characters ad nauseam, the game will not evolve. What you get is a finished product from a game studio. The software can be optimized to the very last bit for this specific game and that is why you can have better graphics than in SL and a physics engine to go with them. PS3Home is just like that: A finished product from Sony with nice graphics and a very limited physics engine which kicks in in some limited cases. The choice of avatars is limited, the environment is limited, anything new is decided by Sony and all you can do IIRC is to import some pictures to put in frames in some limited places. SL is nothing like that. Linden Lab provides nothing but a bare ground on which the users build. All the content is user generated. Until a recent date, everything was built with prims. The concept is light for the network but not that much for our computers. Still, it set SL apart from games and PS3Home since the users cannot play with this virtual Lego elsewhere but in SL. And, of course, since not many users have a team of designers at their disposal everytime they rez a prim, the result may vary from unbearable to fabulous. But in the end, it does not matter if the buildings are ugly or beautiful, the users decide, not a company. We, the users, make the world. Things are slowly evolving since LL gave us the possibility to import "real" meshes like the ones used in 3D games and in PS3Home. But meshes are still in their infancy, nowhere near what is ultimately possible. We, the users, will make SL evolve toward graphics comparable to what can be find in games... slowly and even more slowly since there much less people which can do meshes than people which can cope with prims in-world. As for the physics engine, Havok is quite capable and what is available to us is evolving too. The possibilities of "gamification" of SL are coming, step by step. And what is not available yet can be scripted --to some extend. All this does not change the fact that SL is what we, the users, make it. And that "we" includes you. You are not happy with graphics, show us your building skills, improve the world, your world. You miss some mini-games, script them! If you cannot do it yourself, ask or hire somebody to do it. Make the economy work! That helps SL too. SL is not a game, nor PS3Home and will never be because each pixel is user-generated and not the result of the collaboration of a team of designers and programmers who try their best to make sure that this pixel arrives as fast as possible onto your screen. Besides, SL is really big. Several magnitudes bigger than the very limited PS3Home and definitively not comparable to a tiny game, tiny in size. The "marvelous" CryTek or Unreal engine would just collapse under the weight of SL. They are designed for finite games but SL is infinite, constantly changing, evolving. Roll up your sleeves and try to max out the current engine... while it is pulling the rug under your feet at the same time.
  5. In simple words, you want to write an overrider for your Animation Overrider... which means to write your own AO or, at least, a limited one. The fast timer is just the basics. In the timer() event, you use llGetAnimation() to check if you are standing. You use a flag. If the flag is not set and you are standing, set the flag and start your animation. If you are not standing and the flag is set, you reset the flag and stop the anim. In other words, that's the same principle than a typing overrider but for the standing state. I dug into my inventory and I patched a little something from an old typing AO. key OwnerKey;integer Action;integer Previous;string Anim = "new stand"; // The stand anim to use// The stand anims from your AO.list AOStand = ["stand_1", "stand_2", "stand_3", "etc"]; uuReset(){ llSetTimerEvent(0.0); OwnerKey = llGetOwner(); Action = 0; Previous = 0; if (llGetAttached()) // Works only if attached. { llRequestPermissions(OwnerKey, PERMISSION_TAKE_CONTROLS | PERMISSION_TRIGGER_ANIMATION); }}default{ on_rez(integer param) { uuReset(); } state_entry() { uuReset(); } run_time_permissions(integer perms) { if (perms & PERMISSION_TAKE_CONTROLS) { // To ignore no-script parcel setting. llTakeControls(CONTROL_ML_LBUTTON, TRUE, TRUE); } if (perms & PERMISSION_TRIGGER_ANIMATION) { llSetTimerEvent(0.1); } } timer() { Action = (llGetAnimation(OwnerKey) == "Standing"); // Standing? if (Action != Previous) // A change occured. { if (Action) // Start { llStartAnimation(ANIM); integer i = (AOStand != []); // Faster llGetListLength() for (--i; i >= 0; --i) { llStopAnimation(llList2String(AOStand, i)); } } else // End { llStopAnimation(ANIM); } Previous = Action; // Remember what we were doing. } // Remove "/*" and "*/" to see if this part improves things. // WARNING: Untested patch. /* else if (Action) { integer i = (AOStand != []); // Faster llGetListLength() for (--i; i >= 0; --i) { llStopAnimation(llList2String(AOStand, i)); } } */ }} Do not expect miracles. There will be conflicts with your AO. Usually AOs have multiple stand animations which are started at regular interval and will override your overrider. And I am not even starting to talk about animation priorities. No script can fix that. Priorities are carved in the same stone than the animation during upload. Keep us informed...
  6. That is quite easy. You make a list of sentences. list Sentences = ["Blah blah blah","Bleh bleh bleh", "Blih blih blih","Bloh bloh bloh","Bluh bluh bluh"]; And you pick one at random in the touch() event. integer i = llFloor(llFrand( (float)llGetListLength(Sentences) ));llSay(0, llList2String(Sentences, i)); Just like that... Edit: (And Rolig beat me on the finish line...)
  7. I found the bug! touch_start(integer badtouch) { DialogChannel = llGetUnixTime() / -10; // <<<<< Line to change DialogHandle = llListen(DialogChannel, "", llDetectedKey(0), ""); llDialog(llDetectedKey(0), "Please Select A Destination.", NameList, DialogChannel); llOwnerSay(llDumpList2String(NameList, "\n")); // DEBUG } And now it will rez. It will even rez twice with your script. Is there another script in the prim which needs to be made aware of the rezzing? If not, using a link message is just a pure waste of CPU. If yes, remove the llRezObject() in the listen() event. And my comment in the rez_object() event is still valid. To be able to use llRemoteLoadScriptPin(), you must set the pin first with llSetRemoteScriptAccessPin() in the prim which will receive the script. Since you want to be able to rez the object and send a script into it, the pin must be set before you put this object into the inventory of the TP rezzer. There is no way around. Using a dynamic pin based on UnixTime is just impossible... Unless you already have a script in the TP seat which changes the pin on rez and then asks for the script transfer. Besides the whole concept being slow, it is also tortuous... Well, YMMV. Next thing to think about: What happens when somebody clicks "Ignore" instead of chosing a destination?
  8. Here is how I would re-write your script: // ##########// Important: The multiple TP rezzers must have a unique name.// Same script but different names.// ##########integer CAST_CHANNEL;list NameList;list DestList;key TP_Key;integer TP_Channel;integer TP_Handle;vector TP_Dest;integer DialogChannel;integer DialogHandle;default{ state_entry() { CAST_CHANNEL = (integer)("0xF" + llGetSubString((string)llGetOwner(), 0, 6)); // Channel is based on owner UUID // so that you don't need to reset all of them at once. llListen(CAST_CHANNEL, "", NULL_KEY, ""); llRegionSay(CAST_CHANNEL, "whereareyou"); llSetTimerEvent(30.0); } touch_start(integer badtouch) { integer DialogChannel = llGetUnixTime() / -10; DialogHandle = llListen(DialogChannel, "", llDetectedKey(0), ""); llDialog(llDetectedKey(0), "Please Select A Destination.", NameList, DialogChannel); llOwnerSay(llDumpList2String(NameList, "\n")); // DEBUG } listen(integer chan, string name, key id, string msg) { if (chan == TP_Channel) { llRegionSayTo(TP_Key, TP_Channel, (string)TP_Dest); llListenRemove(TP_Handle); // Close TP listener } else if (chan == CAST_CHANNEL) { if (llGetOwnerKey(id) != llGetOwner()) { return; } // if (msg == "whereareyou") { // No need to transmit the UUID, nor store it either. // Let's just keep the name for some corner cases. llRegionSay(CAST_CHANNEL, "loc, " + (string)llGetPos() + ", " + llGetObjectName()); } else { list tmp = llCSV2List(msg); // if (llList2String(tmp, 0) == "loc") { msg = llList2List(tmp, -1, -1); // Name actually integer i = llListFindList(NameList, [msg]); if (i != -1) { // Name already known. Let's replace the pos. DestList = llListReplaceList(DestList, [(vector)llList2String(tmp, 1)], i, i); } else { // Name unknown. Store the name and the pos. NameList += msg; DestList += (vector)llList2String(tmp, 1); } llSetColor(<0.0, 1.0, 0.0>, ALL_SIDES); } } } else if (chan == DialogChannel) { llListenRemove(DialogHandle); // Close dialog listener. // Store the pos matching the name TP_Dest = llList2Vector(DestList, llListFindList(NameList, [msg])); TP_Channel = llGetUnixTime(); llRezObject("~~TPSEAT", llGetPos() + <0, 0, 1>, ZERO_VECTOR, ZERO_ROTATION, TP_Channel); } } object_rez(key id) { TP_Key = id; TP_Handle = llListen(TP_Channel, "", TP_Key, "whereto"); // Using llRemoteLoadScriptPin() can't work if you don't set the pin beforehand. // You can either set a constant pin on the TP seats // or else they must already contain the needed script. } timer() { llRegionSay(CAST_CHANNEL, "whereareyou"); llSetColor(<1.0, 0.0, 0.0>, ALL_SIDES); llSetText((string)llGetListLength(NameList), <0.0, 1.0, 0.0>, 1); // DEBUG }} It works... in theory... Assuming the TP rezzers have different names and the script in the TP seat does what I guessed. Keep me informed.
  9. I have attended almost all the scripting and server UG for years now and I have never heard anything about the disappearance of llRegionSay(). Besides, that would not make much sense, even in the light of LL's sometimes twisted logic. Scripters would resort to the old hackish ways to chat region-wide, multiplying the scripts, the listeners and the chat occurences themselves. Even if the mythical llParcelSay() was suddenly implemented with a flag to spread accross all parcels of the same owner in a region --which would be a nice replacement for llRegionSay() from a scripter point of view at least-- LL just cannot kill functions without also killing the scripts using them. But LL avoids breaking things... in general. So... No, you can assume that llRegionSay() will still be available for a long while. As for llSensor(), yes, if you use a valid UUID, the script will try to find it. However, the flags are a bit tricky. I cannot remember from the top of my head which ones but some combinations prevents llSensor() from finding anything. In general, I stick with only one flag and avoid mixing them. However, if you already have the UUID, it is more efficient to track the object will llGetObjectDetails() in a timer. It is always better to keep an object on leash than to use a butterfly net to try to catch it...
  10. Exactly... llToLower() Functions of which the name begins with "ll" are "system functions" which can be looked up in the wiki. You did not do your homework... Tsk, tsk tsk! :matte-motes-angry: :matte-motes-wink: (Script fixed.) Second edit: And yes... key OWNER_KEY; (Grumble, grumble...)
  11. First thing: llListen(0,"","",""); Take a scalpel, cut around this line, then use a big hammer and hit it until it pops out from the back of your screen. Such a line floods your script with all the chat from all the avatars within range. I really don't think you need it. Next, you use a very negative channel, that's good... Except that the helmet does not listen to this channel. Here are 2 new skeleton scripts: // HUD Script//integer CHANNEL = -1409001000;key OWNER_KEY;integer LASER_BUTTON;integer OTHER_BUTTON_1; // Just as example.integer OTHER_BUTTON_2; // Idem.integer LaserStatus;uuInit(){ OWNER_KEY = llGetOwner(); LaserStatus = TRUE; // integer i = llGetNumberOfPrims(); for (; i > 0; --i) { string name = llToLower(llGetLinkName(i)); if (name == "laser") { LASER_BUTTON = i; } else if (name == "other1") { OTHER_BUTTON_1 = i; } // Just as example. else if (name == "other2") { OTHER_BUTTON_2 = i; } // Idem. }}default{ on_rez(integer param) { uuInit(); } state_entry() { uuInit(); } touch_end(integer num) { if (llDetectedKey(0) == OWNER_KEY) // Paranoid safety measure { integer link = llDetectedLinkNumber(0); if (link == LASER_BUTTON) { LaserStatus = !LaserStatus; // Invert ON/OFF llRegionSayTo(OWNER_KEY, CHANNEL, "l" + (string)LaserStatus); llSetLinkColor(link, <!LaserStatus, LaserStatus, 0>, ALL_SIDES); // Eventually... } else if (link == OTHER_BUTTON_1) { // Do something else... } else if (link == OTHER_BUTTON_2) { // And something different... } } }} // Helmet script//integer CHANNEL = -1409001000;uuLaser(integer flag){ if (flag) // Switch on { llParticleSystem([ // >>>>> // Big list of params goes here... // <<<<< ]); } else // Switch off { llParticleSystem([]); }}uuInit(){ llListen(CHANNEL, "", NULL_KEY, ""); uuLaser(TRUE);}default{ on_rez(integer param) { uuInit(); } state_entry() { uuInit(); } listen(integer channel, string name, key id, string msg) { if (llGetOwnerKey(id) != llGetOwner()) { return; } // if (msg == "l0") { uuLaser(FALSE); } else if (msg == "l1") { uuLaser(TRUE); } }} Use them wisely! ;P Note: The HUD script expects the button commanding the laser to be labelled "laser" (upper or lower case, or both).
  12. Adding the few lines required in the HUD script to issue the chat command is easy, whether it is for a click on a prim or on a part of texture. The big question is: Will the helmet obey to the HUD? What you must check is if the helmet listens to owner only or to his/her objects too. The latter is what you need. First, you need a (wide open) listener on channel 1: llListen(1, "", NULL_KEY, ""); Then you check who or what is talking to you: listen(integer channel, string name, key id, string msg){ if (llGetOwnerKey(id) == llGetOwner()) { // Activate laser... // // It works for both yourself and your objects // because for LSL you also own yourself. }} However, I strongly suggest to change that channel 1. It is a quite busy channel. A very negative channel is what is recommended for object to object communications. It can also be a very large positive number if you want to still be able to give commands directly through chat.
  13. To avoid all unnecessary lag, the best solution is to use llGetObjectDetails() on a slow timer. No chat, no listener, no sensor, just one slow timer. llGetObjectDetails() will return ZERO_VECTOR as position for the rezzer once it has gone MIA. The only problem is that a rezzed object has no direct way to get the key of its rezzer. So let's just make the rezzer give its key to the objects it rezzes by inserting the following blocks: // This block goes at the very beginning of the script integer VERY_NEGATIVE_CHANNEL = -123456789; string PASSWORD = "Password"; // // Make sure the rezzer transmits a non-zero rez param! // For example: llRezObject( blahblah... , 42); // This block goes into the body of the script object_rez(key id) { llSleep(1.0); // To make sure the rezzed object is ready. llRegionSayTo(id, VERY_NEGATIVE_CHANNEL, PASSWORD); // The use of a "password" allows to use a filter on the listener. } And in the rezzed object: // This block goes at the very beginning of the scriptinteger VERY_NEGATIVE_CHANNEL = -123456789;string PASSWORD = "Password";//integer Handle;key MasterKey;default{ on_rez(integer param) { if (param) { // Make sure the rezzer transmits a non-zero rez param! // For example: llRezObject( blahblah... , 42); Handle = llListen(VERY_NEGATIVE_CHANNEL, "", NULL_KEY, PASSWORD); } else { llResetScript(); // Object was dropped from inventory } } listen(integer channel, string name, key id, string msg) { // Just for safety, check that the rezzer // and the rezzee have the same owner. if (llGetOwnerKey(id) == llGetOwner()) { llListenRemove(Handle); // Close the now useless listener. MasterKey = id; llSetTimerEvent(60.0); } } timer() { if (MasterKey) // is valid and != NULL_KEY { vector pos = llList2Vector(llGetObjectDetails(MasterKey, [OBJECT_POS]), 0); if (pos == ZERO_VECTOR) { llOwnerSay("I must die now..."); // DEBUG //llDie(); } } } // Blahblah...} Important: Create the script of the rezzed object in-world so that its state_entry() --even if missing-- runs at least once or else the on_rez() event will not fire. That's all!
  14. €rick The Gang$ta (omfgwhyallnamesaretaken2135842546.resident) Beginner Builder: Hi can i have 300L? LOL <sarcasm> It doesn't fit in the toasts. We will have an icon to see the title and a "more..." link to see the real contents. </sarcasm> Any way, LL should have just restored the drop down menu with the last names on the registration page. It doesn't require much thinking nor explanations. Quite a lot of people managed to go through the registration process when last names were available... I think. No? I guess it is just too easy for LL. They prefer to give us some inflated contraption on which they will put patch after patch for the years to come and to call us names if we don't marvel at everything that comes out of the Lab. ("Vocal minority", "allergic to change", etc, etc) Just like Liisa, (Hello, Honey!) I had a bad feeling when I read that LL was "(...) trying to figure out how to do it in a way which would be excellent rather than just okay.” Too much thinking for a simple problem which already has an easy solution: Just give back the last names on the registration page the way they were. That would make some Residents happy to be able to just drop their "second-class" account. After that, LL can focus on the problem of giving a last name to those who miss one and adding any bling they want --even if noboby asked anything. I guess I'm too smart... or else I just can't see the "big picture" hidden behind closed doors at the Lab. From the Tao of Linden: We are blessed by some of the most informed, passionate, committed customers imaginable. They are our reason for being, they are our world, and we call them Residents. They are an insuperable source of advantage and an awesome responsibility. In every choice you make, consider how your choice will impact their experience. (Emphasis is mine.) The paragraph on communication is another masterpiece of humor. Go and read the Tao of Linden before LL burns it...
  15. That is a typical case of bullets without physics. Go to Edit mode. Rez the bullet on the ground. Do not release it! Set it to PHYSICAL and TEMPORARY. (Do not forget temporary or you will see bullets returned to you by land owners for a week or more...) Take it quickly! Replace the bullet in the gun. Done!
  16. A very simple example: key Allowed; // Defining keys is tricky.default{ state_entry() { Allowed = (key)"INSERT-REAL-UUID-HERE"; // UUID of the avatar } touch_end(integer num) { key toucher = llDetectedKey(0); if (toucher == Allowed) { llRegionSayTo(toucher, 0, "Access granted."); } else { llRegionSayTo(toucher, 0, "Access denied."); } }} It can be simplified if the allowed toucher is the owner... but you did not specify.
  17. Hmmm... It seems I forgot that dimple is quite limited and may not work for the dimensions you need. (I did not test in-world.) Let's do some mathematics instead, assuming a distance of 95m. Pythagore, right rectangle, hypothenuse, Pythagore again, hypothenuse, adjacent side, cosinus, acute angle... sensor arc = acos( distance / sqrt(sqrt( (square_size/2)² + (square_size/2)² )² + distance²) )sensor arc = acos( 95 / sqrt(sqrt(2)² + 95²) )sensor arc = approx. 0.01488535 (This is not LSL code.) In theory, it works. Test it and keep us informed. There is no lower limit to the sensor arc, but like for everything in SL, I would not go below 0.01.
  18. Despite the name "sensor arc", it is better to think of the sensor area as a sphere which can turn into a cone if dimpled enough. Rez a sphere. Set the rotation to 0, 0, 0. Look at Dimple End: 1.0. Multiply by PI and that gives you the sensor arc value for your sensor to scan a full sphere. 0.5 makes a half sphere. 0.25, for example, and it really looks like a cone. Now, working with a sphere of 96m is impractical, so work with a sphere of 9.6m and set a cube of 0.01x0.2x0.2 at the position of the sphere plus <9.6, 0, 0>. Lower the Dimple End until the edge of the wide end of the cone surrounds the cube. (You can enter more decimals than you can see in the floater.) Use this value multiplied by PI as sensor arc. As you will see, the cube must be just a little closer than 9.6m for everything to work. Hope it helps...
  19. 4x4 cells are perfectly fine. You just need to filter the parcels thanks to their UUIDs. The number of parcels in a region is not very high in general, so it is not a problem to store them and compare in order not to check twice the same parcel. Simple example: default{ touch_start(integer total_number) { list parcel; integer entry = (PARCEL_FLAG_ALLOW_ALL_OBJECT_ENTRY | PARCEL_FLAG_ALLOW_GROUP_OBJECT_ENTRY); integer y = 0; for (; y < 64; ++y) { llSetText((string)y, <1.0, 0.0, 0.0>, 1.0); integer x = 0; for (; x < 64; ++x) { vector pos = <2 + (x << 2), 2 + (y << 2), 0>; string uuid = llList2String(llGetParcelDetails(pos, [PARCEL_DETAILS_ID]), 0); if (llListFindList(parcel, [uuid]) == -1) // Parcel UUID not in list... { parcel += uuid; // Point of failure for a large number of parcels if ((llGetParcelFlags(pos) & entry) != entry) { llOwnerSay("Parcel '" + llList2String(llGetParcelDetails(pos, [PARCEL_DETAILS_NAME]), 0) + "' is NO ENTRY"); } else { llOwnerSay("Parcel '" + llList2String(llGetParcelDetails(pos, [PARCEL_DETAILS_NAME]), 0) + "' allows entry"); } } } } llSetText("", <1.0, 0.0, 0.0>, 1.0); parcel = []; }} Compiled and tested in-world. It is reasonably fast.
  20. EDIT: I thought of linking every function to its wiki page... but I am too lazy. Here is the link to the LSL functions wiki. To connect commands with the keyboard press, you must first know where you click. If your keyboard is a single texture on a face of a prim, you can use llDetectedTouchST() or llDetectedTouchUV(). If your keyboard is made of several prims, llDetectedLinkNumber() will tell you which prim was clicked. If you use a single texture on the faces to click, you call also use llDetectedTouchUV() to find where you clicked in the texture without worrying about link number, but with some filtering on the face number obtained with llDetectedTouchFace(), since we can assume that only one face is clickable. Once you know where you click, the work of the script will be to change that position into a single number. That can be the clicked link number. In the case of the texture, if the texture can be divided into a regular grid, that's easy. vector st = llDetectedTouchST(0);integer column = llFloor(st.x * WIDTH);integer line = llFloor(st.y * HEIGHT);integer command = (line * WIDTH) + column; If you want to work with an irregular grid, WIDTH and HEIGHT can be the size of the picture so 'column' and 'line' are integer to speed up the comparisons with a list describing the clickable areas under the form as bottom left and top right corners. That comparison will give you an index. That is your command. Using integer commands is the solution which will use the least memory if you want to store a list of them. Now that we have commands, let's chat! The rule of the "game" here is to narrow the listeners and to use llRegionSayTo() the most as possible. First thing to do: Select a very negative channel. Next, all the sub objects must learn the key of their master. integer CHANNEL = -999666333; integer Handle; key MasterKey; default { state_entry() { Handle = llListen(CHANNEL, "MasterName", NULL_KEY, 0); } listen(integer channel, string name, key id, string msg) { if (llGetOwnerKey(id) != llGetOwner() { return; } // Listen only to owner's objects. // if (MasterKey) { // Deal with the commands here... } else { MasterKey = id; llListenRemove(Handle); llListen(CHANNEL, "MasterName", MasterKey, ""); llRegionSayTo(MasterKey, CHANNEL, ""); // Chat to send own key. llOwnerSay("Ready"); // DEBUG } } } With this, the sub objects will wait for the first command from their master to narrow their listener. It is not possible to filter the master's listener the same way but the master can learn the keys of its subs. (If you are willing to give the same name to all the sub objects, you can filter on their name.) For now, I will assume we have 5 sub objects will different names. integer CHANNEL = -999666333; integer SUB_ALL = -1; list SubName = ["Sub0", "Sub1", "Sub2", "Sub3", "Sub4"]; list SubKey = [0, 0, 0, 0, 0, 0]; // One entry for each sub, plus one. uuCommand(integer sub, integer command) { key id = llList2Key(SubKey, sub); if (id) { llRegionSayTo(id, CHANNEL, (string)command); } else { llRegionSay(CHANNEL, (string)command); } } default { state_entry() { llListen(CHANNEL, "", "", ""); } touch_start(integer num) { integer sub; integer command; // Deal with the touches here... // // // At this point, we must know to whom we are talking. // It can be -1 to talk to all the subs at once. uuCommand(sub, command); } listen(integer channel, string name, key id, string msg) { if (llGetOwnerKey(id) != llGetOwner() { return; } // Listen only to owner's objects. // if (llistFindList(SubKey, [id]) == -1) // Unknown key talking { integer i = llListFindList(SubName, [name]); // Is it a sub? if (i != -1) // Yes! { SubKey = llListReplace(SubKey, [id], i, i); // Register it. llOwnerSay("Got key for " + name); // DEBUG } } } } (If you need to talk to all the subs at the same time all the time, a lot of that script is useless.) This is pure theoretical work but it I am not too out of my mind, you should be able to reset or edit and save the script of any sub or the master at any time. If you want more help, you will have to give more details, including unfinished or non-working scripts.
  21. You are really wasting a lot of time in here for somebody who thinks her time is always worth something. Seriously, if you have nothing else to say than "pay me if you want help", you should just refrain from posting. Forums are a free space in every sense of the expression. I program/script for money but I never hesitate to answer to questions which amuse me, puzzle me, inspire me or whatever reason, for the betterment of SL. Sometimes, people to whom I answered contact me in-world and I keep on helping if I have the time or to distract me from my daily work. We, so-called "experts", should always take the time to help the beginners... because we can and because it improves SL. Or maybe, just because scripting is fun. It looks like to me that you lost that feeling. Scripting time is always worth something but a warm "thank you" from another human being is priceless.
  22. I got an idea when I read your post. I was about to use a timer but Linda's idea to use the changed() event is much better. Here it comes: vector Color = <0.0, 1.0, 0.0>;list Changes = [ <0.01, 0.0, 0.0>, <0.0, -0.01, 0.0>, <0.0, 0.0, 0.01>, <-0.01, 0.0, 0.0>, <0.0, 0.01, 0.0>, <0.0, 0.0, -0.01>];integer Step = 0;integer MaxStep;integer isCYCLING = FALSE;default{ state_entry() { MaxStep = (Changes != []); // Faster llGetListLength() llSetColor(ZERO_VECTOR, ALL_SIDES); } touch_start(integer total_number) { if (!isCYCLING) { isCYCLING = TRUE; llSetColor(Color, ALL_SIDES); } else { isCYCLING = FALSE; llSetColor(ZERO_VECTOR, ALL_SIDES); llSetLinkPrimitiveParamsFast(LINK_THIS, [PRIM_POINT_LIGHT, FALSE, ZERO_VECTOR, 1.0, 10.0, 0.25]); } } changed(integer change) { if ((change & CHANGED_COLOR) && (isCYCLING)) { Color += llList2Vector(Changes, Step); integer next_step = FALSE; if (Color.x < 0.0) { Color.x = 0.0; next_step = TRUE; } // Red else if (Color.x > 1.0) { Color.x = 1.0; next_step = TRUE; } if (Color.y < 0.0) { Color.y = 0.0; next_step = TRUE; } // Green else if (Color.y > 1.0) { Color.y = 1.0; next_step = TRUE; } if (Color.z < 0.0) { Color.z = 0.0; next_step = TRUE; } // Blue else if (Color.z > 1.0) { Color.z = 1.0; next_step = TRUE; } llSetColor(Color, ALL_SIDES); llSetLinkPrimitiveParamsFast(LINK_THIS, [PRIM_POINT_LIGHT, TRUE, Color, 1.0, 10.0, 0.25]); if (next_step) { Step = (Step + 1) % MaxStep; } } }} Compiled and tested in-world. You talked about light so I added it already. Enjoy!
  23. In computer words: list Speech = ["punch_onetwo", "punch_3", "punch_4", "punch_5", "punch_6"];default{ touch_start(integer total_number) { llShout(0, llList2String(Speech, (integer)llFrand( (float)(Speech != []) ))); // (Speech != []) is just a faster way to say llGetListLength(Speech) } } I modified the list of strings to have different strings. Selecting a random item in a list of identical items always gives the same result: Random but identical.
  24. Just by looking at it, I can say that if you tried Helium's script, you get the error message twice. The error is on the line: llRemoveInventory((string)inventory); // Wrong You can do this... but only with one item. Beyond one item, the script takes the list of items, concatenate their names into a long string which it uses it as an item name that it will try to delete... as many times as the list length. Use this line instead: llRemoveInventory(llList2String(inventory, i)); // Better You cannot delete a list of items directly, you must delete each item in the list, one by one. Any way, since you delete the items after having given them, it is obvious that you do not need to keep their list in a global variable that will do nothing be eat your memory. Giving and deleting can go in the same function. GiveAndDeleteContents(){ string script = llGetScriptName(); list items; integer num = llGetInventoryNumber(INVENTORY_ALL); integer i = 0; for (; i < num; ++i) { string name = llGetInventoryName(INVENTORY_ALL, i); if (name != script) { if (llGetInventoryPermMask(name, MASK_OWNER) & PERM_COPY) { items += [name]; } } } num = (items != []); // Faster llGetListLength() if (num) { llGiveInventoryList(llDetectedKey(0), "Contents", items); for (i = 0; i < num; ++i) { llRemoveInventory(llList2String(items, i)); } llOwnerSay((string)num + " items given and deleted."); } else { llOwnerSay("Nothing to give, nothing to delete."); }} default{ touch_start(integer n) { GiveAndDeleteContents(); }} Never forget that scripts --and computers in general-- are docile slaves, not psychics. They will do exactly what you tell them to do, as many times as you want... But they never do what you want.
  25. 2 answers already while I was typing? I am getting old.. Well, at least, Ela's post made me think about a lock. integer TimeLeft; key Dropper; default { state_entry() { llSetText("Click to drop your object", <1.0, 1.0, 1.0>, 1.0); } touch_end(integer num) { if (Dropper) { return; } // Already busy. // llSetText("", <1.0, 1.0, 1.0>, 1.0); Dropper = llDetectedKey(0); llRegionSayTo(Dropper, 0, "/me -- You have 2 minutes to drop."); llAllowInventoryDrop(TRUE); TimeLeft = 90; // + 30 of timer = 120 llSetTimerEvent(30.0); // No stress... } timer() { if (TimeLeft > 0) { llRegionSayTo(Dropper, 0, "/me -- Time left: " + (string)TimeLeft + " sec."); if (TimeLeft > 30) { TimeLeft -= 30; } else { TimeLeft -= 10; llSetTimerEvent(10.0); // Now, you can stress! } } else { llSetTimerEvent(0.0); llAllowInventoryDrop(FALSE); llRegionSayTo(Dropper, 0, "/me -- Time out!"); Dropper = ""; llSetText("Click to drop your object", <1.0, 1.0, 1.0>, 1.0); } } changed(integer change) { if (change & CHANGED_INVENTORY) { if (Dropper) // is a valid key { llSetTimerEvent(0.0); llAllowInventoryDrop(FALSE); llRegionSayTo(Dropper, 0, "/me -- Thank you."); llSetText("Click to drop your object", <1.0, 1.0, 1.0>, 1.0); } } } } Compiled and tested in-world.
×
×
  • Create New...