// ===================================================================== // Sit Here // skimi3d script library ยท https://grid.skimi3d.com/scripts/sit-here // // Turns any prim into a proper seat: the avatar lands where you say // rather than wherever the region guesses, the menu says something // better than "Sit Here", and a pose from the prim's own contents // replaces the default hunch. // // Without a script, sitting on a prim puts the avatar somewhere near // the top of it in a default pose, facing whichever way it feels like. // Four lines below fix all of that. // // Plain LSL. Works on a lone prim and on any prim in a linkset. // ===================================================================== // --------------------------------------------------------------------- // Settings // --------------------------------------------------------------------- // Where the avatar sits, measured from the middle of this prim and in // this prim's own body. Up is Z. Expect to nudge this by a few // centimetres once you can see somebody sitting in it. // // IT MUST NOT BE EXACTLY <0.0, 0.0, 0.0>. That is not "the middle", it // is the way of saying "no seat at all", and the whole script goes // quiet. If you really want the middle, use <0.0, 0.0, 0.01>. vector SIT_POSITION = <0.0, 0.0, 0.4>; // Which way the sitter faces, in degrees, as pitch, roll and yaw. // <0.0, 0.0, 0.0> faces the same way as the prim. vector SIT_ROTATION = <0.0, 0.0, 0.0>; // What the menu says instead of "Sit Here". Keep it short, the viewer // gives it little room. string MENU_TEXT = "Sit down"; // Left click sits the visitor down straight away, with no menu at all. integer CLICK_TO_SIT = TRUE; // The pose to play, by name. Leave it empty and the seat uses the first // animation it finds in its own Contents, which is usually what you // want: drop a pose in, and it is used. string ANIMATION = ""; // Something said quietly to whoever sits down. Empty says nothing. string GREETING = ""; // Who may sit. 0 = everyone, 1 = only the owner, 2 = only people // wearing the same group tag. integer WHO_MAY_SIT = 0; // --------------------------------------------------------------------- // Everything below here is the machinery // --------------------------------------------------------------------- key gSitter = NULL_KEY; string gPose = ""; // The pose this seat should play, or an empty string for none. string findPose() { if (ANIMATION != "") return ANIMATION; // Nothing named, so take the first animation lying in Contents. // This is what makes the seat re-usable: drop a different pose in // and reset, and the seat is a different seat. if (llGetInventoryNumber(INVENTORY_ANIMATION) > 0) { return llGetInventoryName(INVENTORY_ANIMATION, 0); } return ""; } integer maySit(key who) { if (WHO_MAY_SIT == 1) return who == llGetOwner(); if (WHO_MAY_SIT == 2) return llSameGroup(who); return TRUE; } seat() { llSitTarget(SIT_POSITION, llEuler2Rot(SIT_ROTATION * DEG_TO_RAD)); llSetSitText(MENU_TEXT); if (CLICK_TO_SIT) llSetClickAction(CLICK_ACTION_SIT); if (!CLICK_TO_SIT) llSetClickAction(CLICK_ACTION_TOUCH); } default { state_entry() { seat(); gPose = findPose(); gSitter = NULL_KEY; } changed(integer what) { // Somebody sitting down or standing up both arrive as a change // of links, which is why this one event has to sort out which // of the two just happened. if (what & CHANGED_LINK) { key who = llAvatarOnSitTarget(); if (who) { // Somebody sat down. if (!maySit(who)) { llRegionSayTo(who, 0, "This seat is not for you."); llUnSit(who); return; } gSitter = who; // Sitting on an object grants this by itself, with no // dialog for the visitor to dismiss. Asking is still // required; it is the asking that is free, not the // permission. llRequestPermissions(who, PERMISSION_TRIGGER_ANIMATION); if (GREETING != "") llRegionSayTo(who, 0, GREETING); return; } // Nobody on the target any more, so whoever it was stood up. if (gSitter) { if (gPose != "") llStopAnimation(gPose); gSitter = NULL_KEY; } } // A pose dropped in after the seat was built should be picked // up without anyone having to remember to reset the script. if (what & CHANGED_INVENTORY) gPose = findPose(); } run_time_permissions(integer granted) { if (!(granted & PERMISSION_TRIGGER_ANIMATION)) return; if (gPose == "") return; // The default sit has to be stopped by name, and it has to be // stopped AFTER the avatar is seated, which is why this lives // here and not next to llSitTarget. llStopAnimation("sit"); llStartAnimation(gPose); } on_rez(integer start) { llResetScript(); } }