// ===================================================================== // Home Position // skimi3d script library // https://grid.skimi3d.com/scripts/home-position // // Remembers where a thing belongs and puts it back there. // // For anything visitors are allowed to pick up and push about: the // chairs round a table, the ball in a garden, the props in a photo // studio, the cups on a bar. Somebody always leaves them in the sea. // // Plain LSL. // ===================================================================== // --------------------------------------------------------------------- // Settings // --------------------------------------------------------------------- // Touching it sends it home. Owner or group only, set below. integer GO_HOME_ON_TOUCH = TRUE; // Put it back by itself. Seconds between checks; 0.0 never checks and // leaves it to the touch. // // A number here is a script that wakes up for ever, so make it a large // one. Sixty seconds is a busy prop; three hundred is plenty for the // furniture in a garden. float CHECK_EVERY = 0.0; // How far it has to have wandered before that counts as moved, in // metres. Small numbers make it fight the person editing it. float DRIFT = 0.5; // Put its rotation back as well, not only its place. integer KEEP_ROTATION = TRUE; // Who may send it home by touch. 0 = everyone, 1 = only the owner, // 2 = anyone wearing the same group tag. integer WHO_MAY_SEND_HOME = 1; // --------------------------------------------------------------------- // Everything below here is the machinery // --------------------------------------------------------------------- vector gHome; rotation gHomeRot; goHome() { // llSetRegionPos reaches anywhere in the region, unlike llSetPos, // which only moves a thing ten metres at a time. It answers with // zero rather than complaining, and the three reasons it refuses // are worth saying out loud. integer ok = llSetRegionPos(gHome); if (!ok) { llOwnerSay("I could not go home. Either I am physical, or I am being worn, or home is outside this region."); return; } if (KEEP_ROTATION) llSetRot(gHomeRot); } integer maySend(key who) { if (WHO_MAY_SEND_HOME == 1) return who == llGetOwner(); if (WHO_MAY_SEND_HOME == 2) return llSameGroup(who); return TRUE; } default { state_entry() { // WHEREVER IT IS NOW IS HOME. Put the thing exactly where it // belongs before you drop the script in, and reset the script // whenever you move it somewhere it should stay. gHome = llGetPos(); gHomeRot = llGetRot(); if (CHECK_EVERY > 0.0) llSetTimerEvent(CHECK_EVERY); if (CHECK_EVERY <= 0.0) llSetTimerEvent(0.0); llOwnerSay("Home is set to " + (string)gHome + ". Reset me if I should live somewhere else."); } touch_start(integer total) { if (!GO_HOME_ON_TOUCH) return; key who = llDetectedKey(0); if (!maySend(who)) { llRegionSayTo(who, 0, "This one is not yours to move."); return; } goHome(); } timer() { // Only when it has really wandered. Comparing against a // distance rather than against the exact spot is what stops it // wrestling with somebody who is nudging it into place. if (llVecDist(llGetPos(), gHome) < DRIFT) return; goHome(); } on_rez(integer start) { // A rezzed copy belongs where it was rezzed, not where the // original lived. llResetScript(); } }