User:Tyken Hightower/GenericDoor
<lsl> // Generic Door // "N" was here
// Information // ---------------------------------------------------------------- // The door prim can be either a root or child (although a child will only rotate itself, not the linkset). // The script operates assuming that the 'front' of the door is its positive x-axis, the positive y-axis shoots from the hinges through the door, and the z-axis is up. // // To make a very simple one-prim door to use, give a box the following parameters and drop the script in: // Size X: 0.1 // Size Y: 3.0 // Size Z: 3.0 // Path Cut Begin: 0.375 // Path Cut End: 0.875 // // The door doesn't require any 'reset;' if you want to move it, go right ahead. Moving or rotating the door doesn't change its operation or open/closed status. // Changing and recompiling the script or resetting it makes the door assume it is in the 'closed' position. // ----------------------------------------------------------------
// User-customizable constants // ---------------------------------------------------------------- // Sets whether the door can be opened by touch integer touch_to_open = TRUE;
// Sets whether the door can be opened by collision integer collide_to_open = TRUE;
// Sets whether the door should use a sensor automatically open for nearby agents, the sensor range (in meters), and the sensor scan rate (in seconds) integer sensor_open = TRUE; float sensor_open_range = 3.0; float sensor_open_scanrate = 1.0;
// Seconds until an open door shuts itself automatically (set to 0.0 to let doors stay open forever) float door_timeout = 5.0;
// Which direction the door opens around the Z axis // Both can be set; the the direction will then depend on the position of the person opening it integer open_clockwise = TRUE; integer open_anticlockwise = TRUE; // Sets whether the door opens away (TRUE) from or toward (FALSE) the avatar opening it (only has an effect when both opening direction options above are TRUE) integer open_away = TRUE;
// Angle (in degrees) the door opens for each direction (use only positive values) float clockwise_angle = 90.0; float anticlockwise_angle = 90.0;
// Sound effect inventory names (or asset UUIDs) and volume levels (0.0 to 1.0) string open_sound = ""; float open_volume = 1.0; string close_sound = ""; float close_volume = 1.0; // ----------------------------------------------------------------
// Internal script variables - do not edit // ---------------------------------------------------------------- integer opened = FALSE; integer opened_clockwise = FALSE;
integer timeout_waiting = FALSE;
rotation clockwise_rot = <0.0, 0.0, 0.0, 1.0>; rotation inv_clockwise_rot = <0.0, 0.0, 0.0, 1.0>; rotation anticlockwise_rot = <0.0, 0.0, 0.0, 1.0>; rotation inv_anticlockwise_rot = <0.0, 0.0, 0.0, 1.0>; // ----------------------------------------------------------------
init() {
// Prepare internal rotation values to save calculations
clockwise_rot = llEuler2Rot(<0.0, 0.0, -clockwise_angle> * DEG_TO_RAD);
inv_clockwise_rot = ZERO_ROTATION / clockwise_rot;
anticlockwise_rot = llEuler2Rot(<0.0, 0.0, anticlockwise_angle> * DEG_TO_RAD);
inv_anticlockwise_rot = ZERO_ROTATION / anticlockwise_rot;
if (sensor_open) {
llSensorRepeat("", "", AGENT, sensor_open_range, PI, sensor_open_scanrate);
}
}
// Perform the actual opening, clockwise do_open_clockwise() {
if (open_sound != "") {
llTriggerSound(open_sound, open_volume);
}
llSetLocalRot(clockwise_rot * llGetLocalRot());
opened_clockwise = TRUE;
}
// Perform the actual opening, anticlockwise do_open_anticlockwise() {
if (open_sound != "") {
llTriggerSound(open_sound, open_volume);
}
llSetLocalRot(anticlockwise_rot * llGetLocalRot());
opened_clockwise = FALSE;
}
open(vector agent_pos) {
llSetTimerEvent(door_timeout);
// Don't try to open the door if it's already opened
if (opened) return;
// If necessary, determine whether to open clockwise or anticlockwise based on the agent's position
if (open_clockwise && open_anticlockwise) {
float agent_angle = llRot2Angle(llRotBetween(llRot2Fwd(llGetRot()), llVecNorm(agent_pos - llGetPos())));
if (agent_angle > PI_BY_TWO) { // Agent is 'behind' the door (negative on the door's x-axis)
if (open_away) { // Default behavior; agent behind door opens it 'away,' thus clockwise
do_open_clockwise();
} else { // Agent is behind door, but opens it toward themselves, thus anticlockwise
do_open_anticlockwise();
}
} else { // Agent is 'in front of' the door (positive on the door's x-axis)
if (open_away) { // Default behavior, agent in front of door opens it 'away,' thus anticlockwise
do_open_anticlockwise();
} else { // Agent is in front of door, but opens it toward themselves, thus clockwise
do_open_clockwise();
}
}
// Otherwise, open in a simple predetermined manner.
} else if (open_clockwise) {
do_open_clockwise();
} else {
do_open_anticlockwise();
}
opened = TRUE;
timeout_waiting = FALSE;
start_timeout();
}
close() {
llSetTimerEvent(0.0);
// Don't try to close the door if it's already closed
if (!opened) return;
if (close_sound != "") {
llTriggerSound(close_sound, close_volume);
}
if (opened_clockwise) {
llSetLocalRot(inv_clockwise_rot * llGetLocalRot());
} else {
llSetLocalRot(inv_anticlockwise_rot * llGetLocalRot());
}
opened = FALSE;
timeout_waiting = FALSE;
}
start_timeout() {
if (timeout_waiting) return; llSetTimerEvent(door_timeout); timeout_waiting = TRUE;
}
default {
state_entry() {
init();
}
on_rez(integer start) {
llResetScript();
}
// Touching can either open or close the door
touch_start(integer touches) {
if (touch_to_open) {
if (opened) {
close();
} else {
open(llDetectedPos(0));
}
}
}
// Collisions will open the door or keep it open by resetting the timer
collision_start(integer colliders) {
if (collide_to_open) {
open(llDetectedPos(0));
}
}
// Sensor matches will open the door or keep it open by resetting the timer
sensor(integer matches) {
open(llDetectedPos(0));
}
// Avatars have left door scan range, allowing timeout to begin
no_sensor() {
start_timeout();
}
// Timeout reached, close the door
timer() {
close();
}
} </lsl>