Sit Here
Turns any prim into a proper seat: the sitter lands where you say, faces the way you meant, and plays a pose from the prim's own Contents.
What it does
Without a script, sitting on a prim drops the avatar somewhere near the top of it, in the default hunch, facing whichever way the region felt like. This script sets the seat position and facing yourself, renames the menu entry, turns a left click straight into sitting down, and swaps the default pose for whatever animation is lying in the prim's Contents. When the sitter stands up it puts the pose away again.
What you can build with it
Chairs, benches, bar stools, a window seat, a hammock, the driver's seat of a vehicle, a pose stand for a photo booth. Drop a different animation into the Contents and the same seat becomes a different seat, without touching a line of the script.
How to use it
Settings you can change
7Edit these at the top of the script. Everything works on the defaults · change them only when you need to.
// =====================================================================
// 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();
}
}
Copy it, make a new script inworld, paste over what is there and save. Nothing here phones home.