Jump to content

Drawer Script by Racer Plisskin


Prokofy Neva
 Share

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

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

Recommended Posts

So I know doors are a special hell in SL and I have been all over them for years and solve them in different ways or don't -- but my question today is very specific.

Why can't things you link to a drawer stay put when the drawer moves?

There is an old script and old forums discussion on this and it seems the solution is to put the script into all the parts of the drawer, say the bottom and the sides, and then each thing you put in that drawer, say, shirts or lavender sprigs.

integer drawer_num = 1;  // this is the top drawer - all componenets
                         // of a drawer should use the same number.
                         // EG: change to 2 for all 2nd drawer prims
float slide_dist = 0.5;  // distance in meters drawer should open
integer is_open = FALSE; // assume drawer starts out closed
string close_message = "CLOSE DRAWER"; // Close message to send to other prims
string open_message = "OPEN DRAWER";   // Open message to send to other prims

default
{

    state_entry()
    {
    }   // end of state_entry state

    touch_start(integer nullvar)
    {
        if ( is_open )
        {   // it's open, so close it
            is_open = FALSE;
            llMessageLinked(LINK_ALL_OTHERS, drawer_num, close_message, NULL_KEY);
            llSetPos(<-slide_dist, 0.0, 0.0> + llGetLocalPos());
        }
        else
        {   // it's closed so open it
            is_open = TRUE;
            llMessageLinked(LINK_ALL_OTHERS, drawer_num, open_message, NULL_KEY);
            llSetPos(<slide_dist, 0.0, 0.0> + llGetLocalPos());
        }
    }   // end of touch_start state

    link_message(integer sender_num, integer num, string str, key id)
    {
        if ( num == drawer_num )
        {
            if ( str == open_message )
            {   // we are bing asked to open
                if ( ! is_open )
                {   // if closed, then open.  Otherwise do nothing
                    llSetPos(<slide_dist, 0.0, 0.0> + llGetLocalPos());
                    is_open = TRUE;
                }
            }

            if ( str == close_message )
            {   // we are bing asked to close
                if ( is_open )
                {   // if open then close.  Otherwise do nothing
                    llSetPos(<-slide_dist, 0.0, 0.0> + llGetLocalPos());
                    is_open = FALSE;
                }
            }
        }
    }   // end of link_message state
}

But is there a limit? Can it only handle 2? or 3? 

I thought at first the issue was the root prim, which is another bane of SL. But no.

There's also the issue if you have more than one drawer, each script has to be labelled 1 or 2.

But...it doesn't work. One piece out of a set of 3 or a set of 5 lags and won't move with the rest. Maybe this is an optical illusion. But it seems not to move, really.

I'm not even talking about linking the drawer to the cabinet, so that it would work in any direction -- I figure it's a given that a set of prims like this supposedly talking to each other are not going to work if further linked to another set.

But what's the deal? How can I get it to work?

 

Edited by Prokofy Neva
Link to comment
Share on other sites

The answer is to put one script in the root prim of the drawer and then use llSetLinkPrimitiveParamsFast or your favorite function to move the root.  The child prims will follow. 

integer iMove = 1;

default
{
    touch_start(integer total_number)
    {
        llSetLinkPrimitiveParamsFast(LINK_THIS,[PRIM_POSITION, llGetPos() + <0.5*(iMove *= -1),0.0,0.0>*llGetRot()]);
    }
}

 

0db9db1e55402cae4f3eff6328cb5fcc.gif

Link to comment
Share on other sites

That one tiny script moves all parts of the drawer.  Just drop it in the root.  No Magic.  One click opens the drawer, the next one closes it (or vice versa).  Depending on the way your drawer is built, you might have to trade X for Y, but that's easy enough.  Don't link the drawer to anything else (like the dresser).  If you do, all is not lost, but this particular script won't work.  You'll just need to work harder to write one that does.

Link to comment
Share on other sites

If a drawer and everything "inside" is linked as one object, then you only have to move the root.  The entire link-set moves as one unit, so need need to use llMessageLinked() to control every individual prim separately.  Even though Rolig uses llSetLinkPrimitiveParamsFast(), "LINK_THIS" means it's only "talking" to the root prim.

Your old llMessageLinked() ascript is designed to work with multiple drawers all linked together as a single object.  In that case, the script would need to control every linked prim individually, only only move the prims defined as part of a specific drawer.  For llMessageLinked(), there would be another script in all the child prims that makes the child prim move when their number is called.

On a side-note.. it be nice if we had a llSetSomePrimitiveParamsFast() function where we could define a start linknum and end linknum (or [] list of links) rather run through a loop with individual sends.

Edited by DoteDote Edison
Link to comment
Share on other sites

28 minutes ago, DoteDote Edison said:

it be nice if we had a llSetSomePrimitiveParamsFast() function where we could define a start linknum and end linknum rather run through a loop with individual sends.

I suppose so, but then you'd have to be careful to link all the components consecutively.  You can do the job almost as easily by giving all components of each drawer the same name and then building a separate list of link numbers for each drawer in state_entry (list lDrawer1, list lDrawer2, etc.).  Then, when you click on any part of the linkset, check to see if you touched a component of one of the drawers.  If so, apply the set of movement commands to every link in the list for that drawer.  It is mildly fiddly to set up, but you can still manage the entire thing with a single script in the root prim of the linkset.  [EDIT:  The "linkset" I'm talking about is the linkset for the entire dresser, including all of the drawers, in the sense that Rachel is discussing in her post, below this one.]

Edited by Rolig Loon
Link to comment
Share on other sites

In theory you could make a cabinet with 255 drawers and handle this multi drawer cabinet easy with one single script in the root as @Rolig Loon showed.

Now, if you designed the drawer by your self, be sure to enumerate the drawers from 1 to say 4, if we have four drawers.

To handle which drawer to open, we use llDetectedLinkNumber() and use the returned link number in a global variable.

Now, if you did not make the drawer your self, we need to examine the link number of each drawer and store the result in a list.  Again we use what drawer we touched, look up the link number in our list and the uses this to handle the open/close of the drawer.

Now it is a good idea to store the state of the drawer in a separate list, so we know if it is open or closed, so we can handle it correct.

All this a good little exercise in making a simple LSL script.

Edited by Rachel1206
  • Like 1
Link to comment
Share on other sites

1 hour ago, Prokofy Neva said:

Hmm well I could try that, does it also move everything linked to the drawer?

Also, what is this "one script" I am putting into the root?

And then what you have pasted here is sufficient for the others?

With Rolig's script, your drawer will have to be made up of multiple, separate linksets.

Each usable drawer (and its contents) will be its own linkset, where Rolig's script will be in the root prim and no scripts are needed in any other part. Here's a short video: https://gfycat.com/illfixedafricanhornbill The "main body" of the drawer is unscripted.

Edited by Wulfie Reanimator
  • Like 1
Link to comment
Share on other sites

2 hours ago, Prokofy Neva said:

There is an old script ...

Yes, that's an old script, and although the approach should work, it's really not the way modern products are scripted because we now try very hard to minimize script count within a linkset.

But for all practical purposes, a script can only affect stuff within its linkset, so that ends up dictating how many scripts you need: if the drawer(s) and the rest of the cabinet should be one linkset, then the item will want a single script no matter how many drawers (and contents) are part of the cabinet. That one script to rule them all is a little trickier, but it may be worthwhile, so the whole cabinet, drawers, contents, and all can be moved around as a single selected item.

The alternative, with each drawer a separate linkset, requires each drawer to have its own script, but those identical scripts can be pretty simple, as Wulfie's video shows.

In case some new-ish scripter stumbles on this thread: As Rolig and Rachel mentioned, it's a bit fiddly to wade through all the links in a full-cabinet linkset, figuring out which bits are contents of which drawer, probably using some convention for names or descriptions of all the related links. But while at the same time the script is figuring that out, it may as well construct the full llSetLinkPrimitiveParamsFast() parameter lists, one for opening and another for closing each drawerful of primitives, using PRIM_LINK_TARGET to address each item in the individual drawer and its contents. You can start out storing each of those pre-calculated parameter lists in a separate variable, one per drawer, or take it further to a single long list containing all the parameter lists, and separately list the start and end indices of parameters in that list addressing the individual drawer assemblies.

Or you might want to calculate all that stuff at runtime, in response to a touch, but still use PRIM_LINK_TARGET to try to make it all happen as simultaneously as possible. And if you want to make the motion appear realistically "smooth" you may want to check out Nexii Malthus' wonderful wiki articles of interpolation scripts.

Link to comment
Share on other sites

1 hour ago, Qie Niangao said:

Yes, that's an old script, and although the approach should work, it's really not the way modern products are scripted because we now try very hard to minimize script count within a linkset.

...

 

it's a bit fiddly to wade through all the links in a full-cabinet linkset, figuring out which bits are contents of which drawer, probably using some convention for names or descriptions of all the related links.

So, I do grasp that ideally you don't want to put a script inside every single piece as it adds to lag. I couldn't see that this script ate very much script time, but every little bit hurts. (In fact, I couldn't see it show up on a script monitor at all but maybe the sim wasn't reporting instantly or it shows only when it use).

And the other reason why you don't want to do this is the fiddly part, for sure.

I did discover why this script "didn't work" on the way to finally "making it work". And that is that of course, you have to be scrupulous about labeling the script inside every single part with the number for that set the same. So if there is a 3-prim drawer with bottom, sides, and a handle, and inside are shirts, a cap, a knife, a cloth -- 8 distinct items each with a script in it -- then each piece has to have the script inside labelled "Drawer 1" (on the line where that number goes) or it messes up. If even a single part was left "Drawer 1" on the "Drawer 2" set, it doesn't move.  The script is labelled 1, so if you have 2 drawers, the second set has to have each piece with "2" (as Racer explains in his original posts about this ages ago).

Also, some of the pieces lag, so you get a jittery effect, not unlike real life. This script won't work right if linked to the main cabinet, so you have to soft link.

Meanwhile, Rolig's little script is, indeed magic. Link up the whole set with nothing in any piece (unless you had a door creaking sound or something), then drop this little script into the root. Then the whole thing moves smoothly and with presumably less lag. Thank you so much, Rolig!

PS The point of Racer's script is to have multiple drawer sets. But if they aren't linked to the cabinet, two drawer sets, both with Rolig's script, still work.

Link to comment
Share on other sites

19 hours ago, Rolig Loon said:

I suppose so, but then you'd have to be careful to link all the components consecutively.  You can do the job almost as easily by giving all components of each drawer the same name and then building a separate list of link numbers for each drawer in state_entry (list lDrawer1, list lDrawer2, etc.).  Then, when you click on any part of the linkset, check to see if you touched a component of one of the drawers.  If so, apply the set of movement commands to every link in the list for that drawer.  It is mildly fiddly to set up, but you can still manage the entire thing with a single script in the root prim of the linkset.  [EDIT:  The "linkset" I'm talking about is the linkset for the entire dresser, including all of the drawers, in the sense that Rachel is discussing in her post, below this one.]

Ohh, how we could save a ton of work with 3 additional LSL commands:

llGetDescPrimitiveParams(), llSetDescPrimitiveParamsFast() and llDetectedDesc(). Also the flag "NEXT_DESC_TARGET"

Same format as LLSLPPF, except instead of a link number, you would supply a link description string to match:

llSetDescPrimitiveParamsFast("Drawer1",  [PRIM_POS_LOCAL, ...... ] );

You could target 1 or more links in a set just by using the description you assigned to the link. Link order wouldn't matter at all. No viewer changes needed.

Edited by Phate Shepherd
  • Like 2
Link to comment
Share on other sites

You are about to reply to a thread that has been inactive for 1401 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...