Jump to content

Give Package Contents for No Copy items


EnCore Mayne
 Share

You are about to reply to a thread that has been inactive for 2933 days.

Please take a moment to consider if this thread is worth bumping.

Recommended Posts

i have a package script that won't provide the no copy content to the owner.

is this a defect of the script or a permissions function i have to overcome wih the proper type script?

=====

default
{
    state_entry()
    {
    }       
   
    touch_start(integer numberofagentstouching)
    {
        list items = [];
        integer numberofitemsincontents = llGetInventoryNumber(INVENTORY_ALL);
        do
        {
            string name = llGetInventoryName(INVENTORY_ALL, numberofitemsincontents);
            if (name != llGetScriptName()) items = (items = []) + items + [name];
        }
        while (--numberofitemsincontents >= 0);
        llGiveInventoryList(llDetectedKey(0), llGetObjectName(), items);
    }
}

=====

Link to comment
Share on other sites

There's a bigger problem with the script ... typing proper answer offline.  I'll edit this post when it's done.

Edit:

default{// If it's empty there's no point in having this here at all    state_entry()    {    }// So just delete it    touch_start(integer numberofagentstouching)    {        list items = [];        integer numberofitemsincontents = llGetInventoryNumber(INVENTORY_ALL);        // NB: This will tell you, for instance, that there is ONE thing in inventory...        do        {        	// ... but the FIRST thing is index ZERO, not ONE            string name = llGetInventoryName(INVENTORY_ALL, numberofitemsincontents);            // So the line above will start at one more than it should and return an empty string            if (name != llGetScriptName()) items = (items = []) + items + [name];        }        while (--numberofitemsincontents >= 0);        // The empty string will cause a run-time error when this line tries to find it in inventory        llGiveInventoryList(llDetectedKey(0), llGetObjectName(), items);        // (Apart from your no-copy issue)       // To cure it I'd use an ordinary while() loop instead of do...while()       // First check if there is an(other) item and decrement the counter       // while(numberofitems--){ ... }    }}

 

Link to comment
Share on other sites

The problem is that llGiveInventoryList does not let you include any no copy items in the list.  See caveats in the LSL wiki HERE:

If inventory permissions do not allow copy, the transfer fails and an error is shouted on DEBUG_CHANNEL.

You didn't ask for anything else, but while I'm here .... :smileytongue:

You can simplify your list-building statement by writing

if (name != llGetScriptName()) {items += [name];}

The extra step of clearing the list before adding new items doesn't make any difference, and it makes your code clunkier. At the same time, although not strictly necessary, you should get in the habit of always inserting curly bracketsaround the scope of an if test, even if it's only one line. It's a good habit, because soone or later you'll forget the brackets and add a line that gives you a logic error.


Link to comment
Share on other sites


Caer Balogh wrote:

See
You can't give no-copy items in a list, you need to use LlGiveInventory. There is an example script on that page that does what you want.

duly noted that no copy items can't be given with the llGiveInventoryList function/(thingy). yes, i'm an amateur scripter. can you tell?

the example you point to in the wiki scatters the contents of the package throughout the inventory (landmarks in Landmarks folder, notecards in the Notecards folder, scripts in the Scripts folder and object in the Objects folder. i'd prefer restricting it to providing all the contents within one single folder. oh, and the script has to stay put and not be given out. this may prove to be a gargantuan task with my limited skills.

Link to comment
Share on other sites

Unfortunately llGiveInventory() doesn't let you specify a destination folder, so each item goes wherever SL feels like putting things of that type :-(

(set click-action to 'open' and let the new owner click 'copy to inventory', that works even for no-copy.  You don't need a script at all for that, even if it is less fun)

Link to comment
Share on other sites

thank you everyone for your help. my head is spinning trying to translate your advise into my soft and mushy brain. having hacked the script into its present form (without fully understanding just what it's doing) serves its purposes for my copy item goods.  i'll have to labour long on another one so i can get no copies over. right now, my head hurts, time for some air.

Link to comment
Share on other sites

Hehehe  .. I had time on my hands, and this is a nice short problem. Try this......

 

list gItems;list gNocopy;list gList_types = [iNVENTORY_TEXTURE, INVENTORY_SOUND, INVENTORY_LANDMARK,INVENTORY_CLOTHING, INVENTORY_OBJECT, INVENTORY_NOTECARD, INVENTORY_SCRIPT,INVENTORY_BODYPART, INVENTORY_ANIMATION, INVENTORY_GESTURE];list gList_names = ["Texture", "Sound", "Landmark", "Clothing", "Object", "Notecard",    "Script", "Body Part", "Animation", "Gesture"];default{    // Put this stuff in state_entry because you only need to do it once    state_entry()    {        integer numberofitemsincontents = llGetInventoryNumber(INVENTORY_ALL);        while (numberofitemsincontents)        {            string name = llGetInventoryName(INVENTORY_ALL, numberofitemsincontents - 1);            if (name != llGetScriptName())            {                if(llGetInventoryPermMask(name, MASK_OWNER) & PERM_COPY)                {                    gItems += [name]; //Copy perm items                }                else                {                    gNocopy += [name];  //No-copy perm items                }            }            --numberofitemsincontents;        }    }    touch_start(integer numberofagentstouching)    {        llOwnerSay("Look for unpacked items in a folder named " + llGetObjectName() + " in your inventory.");        llGiveInventoryList(llDetectedKey(0), llGetObjectName(), gItems);        integer len = llGetListLength(gNocopy);        if (len) // That is, if len > 0        {            llOwnerSay("Also, look for the following one-of-a-kind items:");            while (len) 
{ llGiveInventory(llDetectedKey(0),llList2String(gNocopy,len-1)); // Determine what kind of inventory this is, and find that type in the gList_types list integer idx = llListFindList(gList_types,[llGetInventoryType(llList2String(gNocopy,len-1))]); // Then use idx to find the name of that type in the gList_names list and say it llOwnerSay(llList2String(gNocopy,len-1) + " will be in your " + llList2String(gList_names,idx) + " folder."); --len; } } }}

 I haven't field-tested this script, so it's not guaranteed to be free of a loop index error, but it compiles and looks OK.  If nothing else, it shows one way to hand out the copy-perm things in a single folder and the no-copy things individually, along with a friendly note that tells the owner where to find them.  Play with it. :smileyhappy:

ETA:  Well, I did catch a loop index error, and fixed it.  With luck, that's it.

 

Link to comment
Share on other sites


Rolig Loon wrote:

Hehehe  .. I had time on my hands, and this is a nice short problem. Try this......

 

thanks for your time and effort on this little (omg/me faints) problem Rolig. as far as i know (that won't take you too far) after extensive and rigorous testing the script has fallen short of providing me with exactly what it was i thought it might do. of course, if the capability of the language fails me, my world is not crushed beyond salvation. my understanding is enhanced far more than i could have imagined were i not given access to a plethora, yea a virtual cornucopia, of admirably able coders help.

i won't fool you in believing i'm anywhere near as capable with this new toy but i seem to have an inordinate amount of time to observe scripted phenomenon. upon first run through (after clearing the website's somewhat corrupted copy, harumph) i recall the primary function to get the NoCopy item over to the intended customer's inventory was not forthcoming. as a matter of fact i don't believe any Objects came out of the package! i made sure i test filled the package with a No Copy item as well as a Copy one.

upon inspection of the code (i've only gotten into the while statement at this point) it seems that the gNocopy list never gets populated and the gItems doesn't recognize either of the Objects. if i knew why, honestly, i'd tell ya. all's i could discover was that the llList2String(gItems, numberofitemsincontents) read out had two blank lines along with the properly named landmark and notecard objects. oh god, i just replaced the landmark (which was listed as being in the gItems list and now the Copy object is showing but not the landmark.

i think i'll go play with some blocks now.

Link to comment
Share on other sites

Hmmmm... Well, I warned you that I hadn't had time to test it in world.  :smileysurprised:  It's probably something small. I'll take a look at it again this evening.  Meantime, though, do keep poking at it.  I always learn a lot by trying to figure out how someone else's script is supposed to work.  Maybe you will too.  (This is my way of trying to pass of my scripting error as a "learning experience." )

Link to comment
Share on other sites


Rolig Loon wrote:

... I always learn a lot by trying to figure out how someone else's script is supposed to work.  Maybe you will too.  (This is my way of trying to pass of my scripting error as a "learning experience." )

this is how i've learned too Rolig. now if i could only remember what i just learned....

Link to comment
Share on other sites

Well, there was only one small error and one oversight on my part.  The error was in the end of the touch_start event. I used llGiveInventory to give a no-copy item and then tried to get its inventory type. That won't work, because the item is no longer in inventory at that point :smileytongue:, so I simply changed the order of the statements to make it work as advertised. 

The oversight --- the thing that made it not work for you -- is that I should have included a changed event that would reset the script if the inventory in the box changes.  The script didn't work for you because you put the script in the box first, then added items and didn't reset the script. As a result, the setup sequence in the state_entry event never saw those items.  The script thought the box was still empty.  So, I fixed things by adding a changed event. 

Here's the repaired script, field tested.  It works.  :smileyhappy:

 

list gItems;list gNocopy;list gList_types = [iNVENTORY_NONE,INVENTORY_TEXTURE, INVENTORY_SOUND, INVENTORY_LANDMARK,INVENTORY_CLOTHING, INVENTORY_OBJECT, INVENTORY_NOTECARD, INVENTORY_SCRIPT,INVENTORY_BODYPART, INVENTORY_ANIMATION, INVENTORY_GESTURE];list gList_names = ["None", "Texture", "Sound", "Landmark", "Clothing", "Object", "Notecard", "Script", "Body Part", "Animation", "Gesture"];default{    // Put this stuff in state_entry because you only need to do it once    state_entry()    {        integer numberofitemsincontents = llGetInventoryNumber(INVENTORY_ALL);        while (numberofitemsincontents)        {            string name = llGetInventoryName(INVENTORY_ALL, numberofitemsincontents - 1);            if (name != llGetScriptName())            {                if(llGetInventoryPermMask(name, MASK_OWNER) & PERM_COPY)                {                    gItems += [name]; //Copy perm items                }                else                {                    gNocopy += [name];  //No-copy perm items                }            }            --numberofitemsincontents;        }    }        changed (integer change)    {        if ((change & CHANGED_INVENTORY) || (change & CHANGED_OWNER))        {            llResetScript();        }    }    touch_start(integer numberofagentstouching)    {        llOwnerSay("Look for unpacked items in a folder named " + llGetObjectName() + " in your inventory.");        llGiveInventoryList(llDetectedKey(0), llGetObjectName(), gItems);        integer len = llGetListLength(gNocopy);        if (len) // That is, if len > 0        {            llOwnerSay("Also, look for the following one-of-a-kind items:");            while (len)             {                // Determine what kind of inventory this is, and find that type in the gList_types list                integer idx = llListFindList(gList_types,[llGetInventoryType(llList2String(gNocopy,len-1))]);                // Then use idx to find the name of that type in the gList_names list and say it                llOwnerSay(llList2String(gNocopy,len-1) + " will be in your " + llList2String(gList_names,idx) + " folder.");                llGiveInventory(llDetectedKey(0),llList2String(gNocopy,len-1));                --len;            }        }    }}

 

 

  • Like 1
Link to comment
Share on other sites


Rolig Loon wrote:

Well, there was only one small error and one oversight on my part.  The error was in the end of the
touch_start
event. I used
llGiveInventory
to give a no-copy item and then tried to get its inventory type. That won't work, because the item is no longer in inventory at that point :smileytongue:, so I simply changed the order of the statements to make it work as advertised. 

The oversight --- the thing that made it not work for you -- is that I should have included a
changed
event that would reset the script if the inventory in the box changes.  The script didn't work for you because you put the script in the box first, then added items and didn't reset the script. As a result, the setup sequence in the
state_entry
event never saw those items.  The script thought the box was still empty.  So, I fixed things by adding a changed event. 

Here's the repaired script, field tested.  It works.  :smileyhappy: 

 

well for heaven's sake! it works like a charm. i am forever indebted to your magnificence. i haven't at this point studied the changes you made, i'm just so exited that it works. i'm so fortunate that your laser focus is here to help we muddled minded with the keys to the nuclear engineering schematics. please accept what small gifts i may offer to you.

Link to comment
Share on other sites

I don't generally like discussions of coding style because they tend to come down to personal preference and what you're used to.  I think I have to point out again though that using the post-decrement (--) operator in your loop conditions can make things a lot simpler. 

With everything but the relevant instructions removed Rolig has this:

        while (numberofitemsincontents)        {            string name = ...(..., numberofitemsincontents - 1);	    ...            --numberofitemsincontents;        }    }...            while (len)            {		...                integer idx = ...(...,[...(...(...,len-1))]);		...                llOwnerSay(...(...,len-1) + ...;                llGiveInventory(...,...(...,len-1));                --len;            }

Now, whatever works is good and I personally think it's more important to write clear code for maintainability than get the last ounce of performance out of everything.  Specifically, though, I think it's easy to miss one of those '-1's that are needed if you're keeping the loop condiition variable as is.  My recommendation is to decrement it straight away, then you don't need to keep adjusting it later:

 

        while (numberofitemsincontents--)        {            string name = ...(..., numberofitemsincontents); // <- Simplified	    ...            // --numberofitemsincontents; <- No longer required        }    }...            while (len--)            {		...                integer idx = ...(...,[...(...(...,len))]); // <- Simplified		...                llOwnerSay(...(...,len) + ...; // <- Simplified                llGiveInventory(...,...(...,len)); // <- Simplified                // --len; <- No longer required            }

 Everything's a trade-off, of course so there may be times when your loops are using the original value so you can't use this technique.  You may also believe it is harder to read so just don't like it.  That's fine, getting a script to work in the first place is the important thing!

Link to comment
Share on other sites


PeterCanessa Oh wrote:

With everything but the relevant instructions removed Rolig has this:

for what it's worth, from someone who comes from a world foreign to the means, indeed even the logic sometimes, of constructing scripts i find most attempts at describing code extraordinarily confusing. i've taken a few formal classroom courses many years ago but most of my learning for the sl code is based on an unfulfilled need of the moment.

trying to research functions, events, or whatchamacallits in the secondlife wiki is, for me, a minefield of opportunities to reduce my level of comprehension dramatically instead of enhancing it. i just can't understand, from my newbishness point of view, just who the authors are trying to educate. i realize the task of bringing a curious newbie up through the geek ranks can be quite arduous. i also realize that the wiki contains far more than any geek wannabee could digest in one sitting. but really, there has got to be a simpler way of producing the desired effect on the reader than what exists presently.

i'll use the snippets of code you used to illustrate my "omg what's he trying to say, he's trying to help but all i see is a wall of indistinct meaningless characters all jumbled together like some sort of wild and tangled mess" reaction. now, quite normally, i would not give your help a second glance. however, for as long as it lasts, i'd like to be able to contribute in some small measure to what i believe may be helpful to the wider audience of individuals who may have the same response and intents as myself. i really want to be able to give your code its due. i do understand how much time is spent on responses and i appreciate it and want to give something back (without offense should my perspective be totally rejected).

it's hard enough reading code with all the proper terms and placements. believe me. it really is a gruelling sludge getting any sense to travel over whatever synaptical paths that might be sparked with some gloriously elucidated flow of nuanced genius. i like code. i like language. i think the two can be combined in such a manner as to produce a poetic geeky rush. sparing us the full complimentary code with numerous dot dot dots only serves to further generate a confused  furrowed huh? brow from the likes of moi.

i don't mean to change your world. i don't expect you to change the synaptical structures you've laid down over whatever time you've spent delineating your point. i do know, from where i am in the long process of learning, that i'd far more appreciate your embedded comments should the full code you copy be exactly as the earlier quoted style. just so ya know. i don't want to drop you off from the numerous individuals whose help i take away from this forum. now if i only knew what "post decrementing" was i could enter some intelligent response. :-)

Link to comment
Share on other sites

@ EnCore - don't worry, my comments were mainly aimed at the other people who use the forum, not you and other neophytes.  The main problem is that I can't point at Rolig's code and say, "See this bit?  I think it would be better like this".  If I'd (re)posted) the code from Rolig's post you wouldn't be able to tell which lines I was talking about, especially as the highlighting options I have seem to be extremely limited [read 'non-existent'] or at least it looks that way on my screen.  Lol, not that you can tell what I'm talking about now apparently.

Ah well, at least I can help you with post decrementing :-)

  • 'Decrement' means "To decrease a value" (according to the dictionary - the opposite is "increment")
  • "X = X - 1;" subtracts one from a value (decrements it by one)
  • So does "X -= 1;", it's just a shorthand-notation way of doing the same thing
  • "--X;" also decrements X by one - it is pre-decrement (see below)
  • And finally: "X--;" is yet another way of taking-away one from a value.  It is 'post decrementing'

The big difference between those last two and the others is that they are 'meant' to be used in conditions, loops, etc. (although there's nothing stopping you using them on their own or using the other notations in their place, it's just shorthand gibberish).

"--X;" means "Take away one and use the result" (hence decrementing pre/before the operation)

"X--;" means "Use the value as it is then take away one" (hence decrementing post/after the operation)

Soooo ... in a while loop with a counter initialised to, say, 10 you could have:

while(numberofbottles){   llOwnerSay("There were " + (string) numberofbottles + " green bottles, standing on the wall");   numberofbottles = numberofbottles - 1;}

 to count from 10 down to 1 inclusive.  It will stop BEFORE printing 0 because that's the same as FALSE and fails the while test.

You can get rid of the line that decrements the counter in a few ways.  I'm just going to show the difference between pre- and post-decrementing (numberofbottles still starts at 10):

while(--numberofbottles){   llOwnerSay("There were " + (string) numberofbottles + " green bottles, standing on the wall");}

 This pre-decrementing "takes away one and uses the result".  Because of that the first time the while-condition is tested numberofbottles is 9.  The test still fails for 0, so this loop only prints from 9 down to 1 inclusive.

For the loops that you've been using to go through inventory you need to go through all (10) things in inventory but their numbers should be 0 - 9, not 1 - 10.  So, finally, post-decrementing:

while(numberofbottles--){   llOwnerSay("There were " + (string) numberofbottles + " green bottles, standing on the wall");}

 "Use the value then take away one" - the test first 'sees' 10, but the line inside always uses one lower.  On the final successful loop the test has 1 and makes that 0.  Which means that this is a simpler way to print 9 down to 0 inclusive even though your original counter (such as number of things in inventory) runs 10 to 1.  This is just what you need to access everything in inventory using llGetInventoryNumber() or in a list using llGetListLength().

Good luck.  Hope that didn't hurt too much.  Don't worry about it too much, we all started the same way,  (Most) confusion is caused by the fact that different posts in the forums addess different audiences.

Link to comment
Share on other sites

Thanks, Peter.

I've had this debate with myself many times over the years, and I usually come down on the side of pre-decrement, not for any rational reason but because it seems to be the way that my mind works. It just seems natural to me, so I seem to make fewer logical errors when I go that route. That's the essence of personal style, I suppose. (It also shows, perhaps, that I am a self-taught amateur instead of a properly-trained professional.) It does help to have the debate in the open occasionally, though, especially for the benefit of those who haven't made up their minds yet.  :smileywink:

Link to comment
Share on other sites


Rolig Loon wrote:

It does help to have the debate in the open occasionally, though, especially for the benefit of those who haven't made up their minds yet.

You are allowed to use both at different times you know, lol.  Yes, pre- and post-decrementing and the whole loop-counter/conditional testing stuff is where we have to start applying the 'logic' of programming but, "bleh", I don't go much for "properly-trained profesionals".  Too many I've met have taken that to mean "these are the rules and you have to stick to them, or else".  I'm too pragmatic for that which is why I tend to avoid questions of style.  Make it work, make it readable, make it efficient - in that order and stop when you've had enough. [Of course, even that is arguable but I'm not dogmatic about it].

I should, perhaps, explain why all this stuff relates to the OPs original script and why I pointed out the indexing error in the first place -

    touch_start(integer numberofagentstouching)    {        list items = [];        integer numberofitemsincontents = llGetInventoryNumber(INVENTORY_ALL);        do        {            string name = llGetInventoryName(INVENTORY_ALL, numberofitemsincontents);            if (name != llGetScriptName()) items = (items = []) + items + [name];        }        while (--numberofitemsincontents >= 0);        llGiveInventoryList(llDetectedKey(0), llGetObjectName(), items);    }

 (Assume 'Object' and 'This Script' are the only thing in the prim's inventory):

  • llGetInventoryNumber(INVENTORY_ALL) gives the answer 2
  • First time through the loop llGetInventoryName(INVENTORY_ALL, 2) gives an empty string and no error (http://wiki.secondlife.com/wiki/LlGetInventoryName) because the indices are only 0 and 1, there is no 2.
  • As the empty string is not the same as this script's name it is added to the list of items.
  • Second time through the loop llGetInventoryName(INVENTORY_ALL, 1) gives 'This Script', which is not added to the list
  • Third (last) time through the loop 'Object' is returned and added to the list.
  • So the list is now ["", "Object"]
  • As "" (the empty string) is missing from the prim's inventory then llGiveInventoryList() shouts an error on the DEBUG_CHANNEL (http://wiki.secondlife.com/wiki/LlGiveInventoryList)

Now since most people don't see or hear script errors and neither of the errors with these indices stops the script it doesn't really matter if we ignore them.  :-) I didn't think that was the case for people reading this forum though :-)

Link to comment
Share on other sites

  • 5 years later...

Not meaning to resurrect a dead topic, but the scripts from Rolig and Peter on post 12 & 14 work pretty well.

At first when I tried Peter suggestion, it just gave errors and wouldn't work at all. That is until i noticed that he forgot to comment part of what he added/changed. Both scripts are good, though still have minor issues.

Link to comment
Share on other sites

   As a side note, only one fix i would give to Rolig script. In the

touch_start

   after the

if(){} 

   I would add a

llResetScript();

   so that copyable items afterwards wouldn't be sent a +1 increment with each successive touch/click.

   I did a few of my own updates to it so i wouldn't get a error message if there is no item within the Unpacker.

   Plus a few other minor useful addins. Yet all in all, Rolig script is a pretty good solid starting base.

 

Link to comment
Share on other sites

You are about to reply to a thread that has been inactive for 2933 days.

Please take a moment to consider if this thread is worth bumping.

Please sign in to comment

You will be able to leave a comment after signing in



Sign In Now
 Share

×
×
  • Create New...