Jump to content

Tattooshop

Resident
  • Posts

    365
  • Joined

  • Last visited

Posts posted by Tattooshop

  1. 8 minutes ago, Jenna Huntsman said:

    You may find it useful to add in some failover modes with some helpful messages to see where code goes wrong.

    For example, this version of your script will check the contents of msg and verify that the key is valid, and the HUD will warn the user if objKey is not populated.

    HUD:

    integer iOBJChannel = 10;
    integer iHUDChannel = 20;
    key objKey; // or string....
    
    default
    {
        state_entry()
        {
            llListen(iHUDChannel, "", "", "");
        }
        
        listen(integer channel, string name, key id, string msg)
        {
            if((key)msg)
            { //if the contents of msg is a valid key (not NULL_KEY or a random string).
                objKey = (key)msg;
            }
            else
            { //msg wasn't a valid key.
                llSay(0, "That's not a valid key!");
            }
        }
    
        touch_start(integer total_number)
        {
            if(objKey) //if objKey is set and a valid key.
            {
                llRegionSayTo(objKey, iOBJChannel, "TEXTURE");
            }
            else
            {
                llSay(0, "I don't know who to send this to!"); //Triggered if objKey isn't set
            }
        }
    }

    Object:

    integer iOBJChannel = 10;
    integer iHUDChannel = 20;
    
    default
    {
        state_entry()
        {
            llListen(iOBJChannel, "", "", "");
        }
        
        listen(integer channel, string name, key id, string msg)
        {
            if (msg == "TEXTURE")
            llSay(0, "Done!");
        }
    
        touch_start(integer total_number)
        {        
            llRegionSayTo(llDetectedKey(0), iHUDChannel, llGetKey()); //Sending to llDetectedKey(0) will send the message to the avatar who touched this ONLY.
        }
    }

     

    Perfect! Thank you very much! :)

  2. 16 hours ago, Rolig Loon said:

    Sure.  As long as you have permission to modify any object that you are going to texture , you can drop a script into it that will communicate with your HUD when you click on it. Just include code that does something like

    touch_start(integer num)
    {
        llRegionSayTo( llDetectedKey(0), iHUDChannel, "whatever message you want to send");
    }

    The message is sent to the person who clicks on the object, and any attachment that is listening on iHUDChannel will hear it.  The message from the touched object might include, for example, the link number and face that you clicked on, or anything else that might be useful.  The listen event in the HUD's script will see the sending object's name and UUID, so you can then send any texture information back to it with a llRegionSayTo statement in that script.

     

    13 hours ago, Jenna Huntsman said:

    Use a typecast, for example

    listen(integer channel, string name, key id, string msg)
        {
            objKey = (key)msg; //Use a typecast (key) to convert msg, a string, back into a key.
        }

     

    Thanks again! Please tell me what I'm doing wrong, why doesn't it work? Here are both draft scripts. :)

    OBJECT Script:

    integer iOBJChannel = 10;
    integer iHUDChannel = 20;
    
    default
    {
        state_entry()
        {
            llListen(iOBJChannel, "", "", "");
        }
        
        listen(integer channel, string name, key id, string msg)
        {
            if (msg == "TEXTURE")
            llSay(0, "Done!");
        }
    
        touch_start(integer total_number)
        {        
            llRegionSayTo(llDetectedKey(0), iHUDChannel, llGetKey());
        }
    }

    HUD Script:

    integer iOBJChannel = 10;
    integer iHUDChannel = 20;
    key objKey; // or string....
    
    default
    {
        state_entry()
        {
            llListen(iHUDChannel, "", "", "");
        }
        
        listen(integer channel, string name, key id, string msg)
        {
            objKey = (key)msg;
        }
    
        touch_start(integer total_number)
        {
            llRegionSayTo(objKey, iOBJChannel, "TEXTURE");
        }
    }

     

  3. 2 hours ago, Rolig Loon said:

    Sure.  As long as you have permission to modify any object that you are going to texture , you can drop a script into it that will communicate with your HUD when you click on it. Just include code that does something like

    touch_start(integer num)
    {
        llRegionSayTo( llDetectedKey(0), iHUDChannel, "whatever message you want to send");
    }

    The message is sent to the person who clicks on the object, and any attachment that is listening on iHUDChannel will hear it.  The message from the touched object might include, for example, the link number and face that you clicked on, or anything else that might be useful.  The listen event in the HUD's script will see the sending object's name and UUID, so you can then send any texture information back to it with a llRegionSayTo statement in that script.

    Thanks! :D

    Almost, but the HUD script seems gets the message with the object key as text, how can I convert it back to a key so that it can be sent to that specific object?

        listen(integer channel, string name, key id, string msg)
        {
            msg == objKey; // how to string to key?
        }
    
        touch_start(integer total_number)
        {
            llRegionSayTo(objKey, iOBJChannel, "TEXTURE");
        }

     

  4. Hello! :D


    I have a question for you. Texture on object changed with HUD. And when there is one object, then everything is fine, if there are several objects, everything is fine if you need to change textures in the same way on all objects. But if you need to change the texture on only one of them without affecting the rest, you will have to either stop the scripts or do everything manually.


    Is it possible to somehow restrict the action, for example, to click on an object, it sends some kind of signal to HUD and the texture changes only on it? If it makes sense...

    Thanks for any help! :)

  5. 4 hours ago, Ariu Arai said:

    This will do the trick. llGiveInventoryList doesn't support no-copy items, which is kind of annoying. Instead, a separate list will need to be build for the no-copy items and they will need to be given to the owner individually using llGiveInventory.

    I removed the for loop for the touch event as it's not needed.

    default
    {
        touch_start(integer num)
        {
            if(llDetectedKey(0) == llGetOwner())
            {
                integer InvenNumber = llGetInventoryNumber(INVENTORY_ALL);
    
                list copy_list = [];
                list no_copy_list = [];
    
                integer count = llGetInventoryNumber(INVENTORY_ALL);
    
                while(~--count)
                {
                    string name = llGetInventoryName(INVENTORY_ALL, count);
    
                    if(name != llGetScriptName())
                    {
                        integer perms = llGetInventoryPermMask(name, MASK_OWNER);
    
                        if(perms & PERM_COPY)
                        {
                            copy_list += name;
                        }
                        else
                        {
                            no_copy_list += name;
                        }
                    }
                }
    
                if(copy_list != [])
                {
                    llGiveInventoryList(llGetOwner(), llGetObjectName(), copy_list);
                }
    
                count = llGetListLength(no_copy_list);
    
                while(~--count)
                {
                    llGiveInventory(llGetOwner(), llList2String(no_copy_list, count));
                }
                
            }
        }
    }

     

    Thank you so much! You are genius! 👍:)

     

  6. Hello! :)🤚

    I have an unpacker script, but all the items it gives must have copy permission, and if it encounters no copy item, it throws an error.

    How to add such a filter so that if, among other things, a no copy item was found, it would be placed in the "Objects" folder, and all copy items — in the usual way — into the newly created folder?

    Added: or it is still unpacked as a regular item, but is moved from the package to the folder with all the items, if it makes sense.

    Thanks for any help! :)

    default {
        touch_start(integer total_number) {
            integer x;
            for (x = 0; x < total_number; x++) {
                if (llDetectedKey(x) == llGetOwner()) {
                    string InvenName;
                    integer InvenNumber = llGetInventoryNumber(INVENTORY_ALL);
                    list InvenList = [];
                    integer y;
                    for (y = 0; y < InvenNumber; y++) {
                        InvenName = llGetInventoryName(INVENTORY_ALL, y);
                        if (InvenName != llGetScriptName()) InvenList += [InvenName];
                    }
                    llGiveInventoryList(llGetOwner(), llGetObjectName(), InvenList);
                }
            }
        }
    }

     

  7. On 9/29/2021 at 6:56 AM, Gayngel said:

    Reading a notecard every time someone clicks is slow and inefficient. You should read the notecard in state_entry and pass each piece of data into a strided list as [site_name, weblink, site_name, web_link]. Then when the user touches the button for the link you can search the list with llListFindList.

    Each line of the notecard should be comma seperated values:

    Facebook, https://facebook.com

    Youtube, https://youtube.com

    Marketplace, https://marketplace.secondlife.com/

    Then your code should look like this:

    key notecardQueryId;
    integer line;
    string link_name;
    list websites;
    integer allow = FALSE; // only allow touches if the notecard has been read completely;
    
    getURL(key id, string site)
    {
       site = llToLower(site);	
       integer idx = llListFindList(websites,[site]); // searches the list for the name of the site and gets its index number. 
       
       llRegionSayTo(id,0,"Visit our [ "+llList2String(websites,idx)+": "+llList2String(websites,idx+1)+"]!");
    }
    
    default
    {
    	state_entry()
    	{
          line = 0;
    	  notecardQueryId = llGetNotecardLine("config", line);
    	}
    
    	changed(integer change)  // editing the notecard triggers an inventory change so let's re-read the notecard.
    	{
    		
    		if(change & CHANGED_INVENTORY)
    		llResetScript();
    
    	}
        
        
        dataserver(key what, string data)
        {
            if (notecardQueryId == what)
            {
                if (data != EOF)
                {
    				if(data !="") //if the line is not blank
    				{
    				list tmp = llPareStringToList(data,[","],[])
                    string link_name = llStringTrim(llToLower(llList2String(tmp, 0)),STRING_TRIM); // make all website names lower case so it's easier to search for in the list.
    				string link = llStringTrim(llList2String(tmp, 1),STRING_TRIM);
                   websites += [link_name] + [link];
    				}
    			  ++line;
    			  notecardQueryId = llGetNotecardLine("config", line);
                }
    			
    		  else
    		 {
    			llSay(0,"Reading of notecard complete");
    			allow = TRUE;
    		 }
            }
        }
    
    
    	 touch_start(integer total_number)
        {
    		if(allow == TRUE)
           {
            string button = llGetLinkName(llDetectedLinkNumber(0));
    		key id = llDetectedKey(0);
          
            if (button == "marketplace") // Button's name
            {
                getUrl(id,"Marketplace");
            }
            else if (button == "facebook")
            {
                getUrl(id,"Facebook");
            }
            else if (button == "youtube")
            {
                getUrl(id,"Youtube");
            }
            }
    		
        }
    	
    	
    
    }

     

     

    I'm not really sure why you need a notecard in the first place though. Since you have to hard code the button names in the touch event you can just hard code the web links in it too.

     

    getURL(key id, string site, string url)
    {
    
      llRegionSayTo(id,0,"Visit our [ "+site+": "+url+"]!");
    }
    
    default
    {
        
        touch_start(integer total_number)
        {
            string button = llGetLinkName(llDetectedLinkNumber(0));
            key id = llDetectedKey(0);
            
            if (button == "marketplace") // Button's name
            {
                getURL(id, "Marketplace", "https://marketplace.secondlife.com/");
            }
            else if (button == "facebook")
            {
                 getURL(id, "Facebook", "https://facebook.com");
            }
            else if (button == "youtube")
            {
                 getURL(id, "Youtube", "https://youtube.com");
            }
          
        }
        
       
    }

     

     

     

    On 9/29/2021 at 8:40 AM, Quistess Alpha said:

    You can improve further by eliminating the string of if-else clauses, and expect the buttons to be named according to the string you are searching for:

    list gUrls = 
    [  "Marketplace", "https://marketplace.secondlife.com/",
       "Facebook", "https://facebook.com",
       "Youtube", "https://youtube.com"
    ];
    getURL(key id, string site, string url)
    {
      llRegionSayTo(id,0,"Visit our [ "+site+": "+url+"]!");
    }
    
    default
    {
        touch_start(integer total_number)
        {
            string button = llGetLinkName(llDetectedLinkNumber(0));
            key id = llDetectedKey(0);
            
            integer index = llListFindList(gUrls,[button]);
            if(index!=-1)
            {  getURL(id,button,llList2String(gUrls,index+1));
            }else
            {  llOwnerSay("Debug: Bad button-name.");
            }
        }
    }

    this might be slightly less efficient for small numbers of links, but it's a lot easier to extend by adding to the list than adding more if-else statements IMO. You do have to be careful the name of the button and the item in the list have the same capitalization though.

    Thank you very much!

    I was very interested in trying your versions, but for some reason first script gives an error in line 62. What am I doing wrong? I understand that these names are not defined in the script. How to do it right? :)

    And the script stubbornly refuses to send a link by RegionSayTo / llInstantMessage, so I had to use llSay. Is this completely impossible or can I somehow fix it?

    f964a31692c54421d130e805d3888e41.png

  8. 12 hours ago, Rolig Loon said:

    Oh, I see your point.  Well, you could simply rewrite that routine in state_entry ....

    list lWhatToDo;
    integer LIGHT_FACE = ALL_SIDES;
    
    default
    {
        state_entry()
        {
             list Params = [PRIM_COLOR, LIGHT_FACE, < 1, 1, 1 > , 1.0, PRIM_GLOW, LIGHT_FACE, 0.3,
                 PRIM_FULLBRIGHT, LIGHT_FACE, TRUE, PRIM_POINT_LIGHT, TRUE, < 1, 1, 1 > , 1.0, 10.0, 0.2];
             integer i;
             while ( i < llGetNumberOfPrims() )
             {
                 ++i;
                 string name = llToLower( llGetLinkName(i) );
                 if ( ~llSubStringIndex(name,"lamp") )
                 {
                    lWhatToDo += [34,i] + Params;
                 }
             }
        }
    
        touch_start(integer num)
        {
            llSetLinkPrimitiveParamsFast(LINK_SET,lWhatToDo);
        }
    }

    So, instead of creating a list of lamp links, you create a list that is the full string of SLPPF commands you'll need.

    Thanks a lot! Now everything works! It's like a magic spell! :D👍

    • Like 2
  9. I mean, yes, of course, you can pre-specify, for example, ten links and limit the script to that, which is very reasonable. But how to make the script "automatically" determine how many lamps and apply parameters unlimited in their number to all? :)

  10. 41 minutes ago, Rolig Loon said:

    That's why you created that list lLampLinks in state_entry.  If you've done that, you know exactly which links are lamps.  Any link that's not in that list won't be addressed by your massive SLPPF function call. If you expect to have changes, of course, you can always use a changed event to rebuild the list:

    changed (integer change)
    {
        if (change & CHANGED_LINK)
        {
            lLampLinks = [];
             integer i;
             while ( i < llGetNumberOfPrims() )
             {
                 ++i;
                 string name = llToLower( llGetLinkName(i) );
                 if ( ~llSubStringIndex(name,"lamp") )
                 {
                    lLampLinks += [i];
                 }
             }
        }

     

    But... but what if I specify parameters for five lamps in the script, and in the linkset there are 6 or 16? :D

  11. 40 minutes ago, Rolig Loon said:

    That's not quite the right syntax.  You want to address the entire linkset, so the instruction should begin with 

    llSetLinkPrimitiveParamsFast(LINK_SET,

    Then, you want to express the actions that you want to apply to the first link in the lLampLinks list.  To do that, you use PRIM_LINK_TARGET to signal that you are talking about a specific link and you identify that first link, with llList2Integer(lLampLinks,0), followed by the list of params that you want to adjust....

    llSetLinkPrimitiveParamsFast(LINK_SET, [ PRIM_LINK_TARGET, llList2Integer(lLampLinks,0), PRIM_COLOR, LIGHT_FACE, < 1, 1, 1 > , 1.0, PRIM_GLOW, LIGHT_FACE, 0.3, PRIM_FULLBRIGHT, LIGHT_FACE, TRUE, PRIM_POINT_LIGHT, TRUE, < 1, 1, 1 > , 1.0, 10.0, 0.2,    ........

    and then you repeat that for the next link in lLampLinks, so the instruction now becomes ...

    llSetLinkPrimitiveParamsFast(LINK_SET, [ PRIM_LINK_TARGET, llList2Integer(lLampLinks,0), PRIM_COLOR, LIGHT_FACE, < 1, 1, 1 > , 1.0, PRIM_GLOW, LIGHT_FACE, 0.3, PRIM_FULLBRIGHT, LIGHT_FACE, TRUE, PRIM_POINT_LIGHT, TRUE, < 1, 1, 1 > , 1.0, 10.0, 0.2, PRIM_LINK_TARGET, llList2Integer(lLampLinks,1), PRIM_COLOR, LIGHT_FACE, < 1, 1, 1 > , 1.0, PRIM_GLOW, LIGHT_FACE, 0.3, PRIM_FULLBRIGHT, LIGHT_FACE, TRUE, PRIM_POINT_LIGHT, TRUE, < 1, 1, 1 > , 1.0, 10.0, 0.2,     .......

    and so on, until you have finished specifying the actions for each of the links that you want to adjust.  As you see, this can become tedious, so it's wise to use some shortcuts and make use of sensible formatting so that your work is human-readable:

    list Params = [PRIM_COLOR, LIGHT_FACE, < 1, 1, 1 > , 1.0, PRIM_GLOW, LIGHT_FACE, 0.3, PRIM_FULLBRIGHT, LIGHT_FACE, TRUE, PRIM_POINT_LIGHT, TRUE, < 1, 1, 1 > , 1.0, 10.0, 0.2];

    llSetLinkPrimitiveParamsFast( LINK_SET, [34, llList2Integer(lLampLinks,0)] + Params + 

              [34, llList2Integer(lLampLinks,1)] + Params + 

              [34, llList2Integer(lLampLinks,2)] + Params + 

              [34, llList2Integer(lLampLinks,3)] + Params + 

              [34, llList2Integer(lLampLinks,4)] + Params + 

              [34, llList2Integer(lLampLinks,5)] + Params ); 

    until you run out of links to add to the growing SLPPF instruction.  (34 is the integer code for PRIM_LINK_TARGET )

    Wow! Thank you very much for showing everything in such detail! Now it is clear even to me! :D


    But what if the script doesn't know in advance how many lamps there will be and must apply the parameters to all, no matter how many there are? 

  12. 1 hour ago, Rolig Loon said:

    D'uh.. Sorry.. That's what I get for typing fast.   Thanks for the save, Qie.

    2 hours ago, Qie Niangao said:

    (probably meant llGetNumberOfPrims() which would be better named llGetNumberOfLinks)

    Thanks! I added lLampLinks to the line when the light is on but there is an error. I'm doing something wrong. What should be used instead of links numbers in this case? Also what if there is an indefinite number of objects with the same name - 2, 8, and so on? :)

    llSetLinkPrimitiveParamsFast(lLampLinks, [PRIM_COLOR, LIGHT_FACE, < 1, 1, 1 > , 1.0, PRIM_GLOW, LIGHT_FACE, 0.3, PRIM_FULLBRIGHT, LIGHT_FACE, TRUE, PRIM_POINT_LIGHT, TRUE, < 1, 1, 1 > , 1.0, 10.0, 0.2]);

     

  13. 2 hours ago, Rolig Loon said:
    list lLampLinks;
    
    default
    {
        state_entry()
        {
             integer i;
             while ( i < llGetNumberOfLinks() )
             {
                 ++i;
                 string name = llToLower( llGetLinkName(i) );
                 if ( ~llSubStringIndex(name,"lamp") )
                 {
                    lLampLinks += [i];
                 }
             }
        }
    }

    That will give you a list of all link numbers that have the substring "lamp" in them.  Now all you have to do is use the PRIM_LINK_TARGET (34) param in SLPPF and string a mess of instructions for all of those links together in one long command.

    Thank you! May I ask what is llGetNumberOfLinks()? My script doesn't seem to recognize this.

  14. Hey! :)🤚

    Here I have a light toggle script and it uses primitive numbers for the lights, but how can I get the script to define primitive names and apply light parameters, for example, only to objects named "lamp"?

    (And one more sub-question, is it possible to somehow shorten llSetLinkPrimitiveParamsFast in the script? For example, PRIM_COLOR can be shortened to 18, and so on.)

    Thanks for any help!

    integer LIGHT_PRIM_1 = 2; // Light prim number 1
    integer LIGHT_PRIM_2 = 3; // Light prim number 2
    integer LIGHT_FACE = ALL_SIDES; // Light face number
    
    integer tog;
    default
    {
        touch_start(integer total_number)
        {
            if (tog)
            {
                tog = FALSE;
                llSetLinkPrimitiveParamsFast(LINK_SET, [PRIM_COLOR, LIGHT_FACE, < 1, 1, 1 > , 1.0, PRIM_GLOW, LIGHT_FACE, FALSE, PRIM_FULLBRIGHT, LIGHT_FACE, FALSE, PRIM_POINT_LIGHT, FALSE, < 1, 1, 1 > , 1.0, 10.0, 0.2]);
            }
            else
            {
                tog = TRUE;
                llSetLinkPrimitiveParamsFast(LIGHT_PRIM_1, [PRIM_COLOR, LIGHT_FACE, < 1, 1, 1 > , 1.0, PRIM_GLOW, LIGHT_FACE, 0.3, PRIM_FULLBRIGHT, LIGHT_FACE, TRUE, PRIM_POINT_LIGHT, TRUE, < 1, 1, 1 > , 1.0, 10.0, 0.2]);
                llSetLinkPrimitiveParamsFast(LIGHT_PRIM_2, [PRIM_COLOR, LIGHT_FACE, < 1, 1, 1 > , 1.0, PRIM_GLOW, LIGHT_FACE, 0.3, PRIM_FULLBRIGHT, LIGHT_FACE, TRUE, PRIM_POINT_LIGHT, TRUE, < 1, 1, 1 > , 1.0, 10.0, 0.2]);
            }
        }
    }

     

  15. On 9/25/2021 at 6:08 PM, Rolig Loon said:

    You have defined new local string variables called link_name in each of the if tests in your touch_start event.  You are never loading any value into the global variable called link_name.

    And come back to this topic again. :D


    I found that when trying to use llInstantMessage or llRegionSayTo in the dataserver, of course, the message does not come out. I added a detector to the touch_start event

    key id = llDetectedKey(0);

    but how can I pass this data to the dataserver so that in this case, only send a message to the one who touched the object?

    llRegionSayTo(???, 0, "Message"); or llInstantMessage( ???, "Message" );

×
×
  • Create New...