/* * [AV]LockGuard - Attach LockGuard V2 chains * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * Copyright © the AVsitter Contributors (http://avsitter.github.io) * AVsitter™ is a trademark. For trademark use policy see: * https://avsitter.github.io/TRADEMARK.mediawiki * * Please consider supporting continued development of AVsitter and * receive automatic updates and other benefits! All details and user * instructions can be found at http://avsitter.github.io */ // For use attaching particle chains to LockGuard V2 compatible cuffs such as Open Collar // This script should be placed inside the prim that contains your poses and props. // Inspiration and function (not code) from the Bright CISS system by Shan Bright & Innula Zenovka. // SITTER: // The AVsitter SITTER # the chain settings are for. // -> You can use -1 to mean all sitters, but that will mean that the very same // chain settings and pose list will be applied to all at the same time. If // you don't want that, then you need to add one script per sitter. integer SITTER = 0; // USES_PROPS: // - TRUE for ring prims within props // - FALSE for ring prims linked to furniture // - If you're using props, you must include the "[AV]LockGuard-object" script in your props // and ring prim names must contain the substring "ring". Each pose can only have 1 prop // for all the rings (e.g. the ring prop for each pose should be 1 linked object, not // separate props of individual rings). // NOTE: // - Most builds should use USES_PROPS = FALSE; // - USES_PROPS should only be used for specific cases. e.g. if the prop completely changes the // surrounding scene which the chains attach to. If you want the LockGuard rings rezzed all the // time then they should be permanently linked to the furniture and not approached with props. integer USES_PROPS = FALSE; // POSES list // - specifies which cuffs to chain to which prims for each POSE or SYNC (these correspond to // menu names of your poses, not animation file names!). // e.g: "Pose2", "leftwrist, ring1, rightwrist, ring2" // - When the POSE "Pose2" is played, this will chain the "leftwrist" cuff to the prim hook named // "ring1" and the "rightwrist" cuff to the prim hook named "ring2". The hook prims in the // furniture should be named (e.g. "ring1" and "ring2"). // - See http://www.lslwiki.net/lslwiki/wakka.php?wakka=exchangeLockGuardItem // for a list of LockGuard V2 Standard ID Tags and more information. The LockGuard package // (with full instructions for the protocol) can be obtained in-world from Lillani Lowell's // inworld location. // - A pose name of "*" provides a default for all poses, should that be necessary. list POSES = [ "cross", "rightwrist,ring1,leftwrist,ring2,rightankle,ring3,leftankle,ring4", "reverse", "rightwrist,ring2,leftwrist,ring1,rightankle,ring4,leftankle,ring3", "arms", "rightwrist,ring1,leftwrist,ring2", "upside", "rightwrist,ring2,leftwrist,ring1,leftankle,ring1,rightankle,ring2" ]; // CHAIN_PARAMETERS: // - For information on parameters see http://www.lslwiki.net/lslwiki/wakka.php?wakka=exchangeLockGuard // - Specifies any special LockGuard commands. If you do not specify any then the particle will // use the cuff default. Common used parameters are "gravity g", "life secs", // "color red green blue", "size x y", "texture uuid". // e.g. "color 1 0 0 texture 6808199d-e4c8-22f9-cf8a-2d9992ab630d" will bind with red ropes. string CHAIN_PARAMETERS = "size 0.12 0.12 life 1 gravity 0.3 texture d7277e78-06f4-58ae-9f7c-7499e50de18a"; // "size 0.12 0.12 life 1 gravity 0.3 texture 245ea72d-bc79-fee3-a802-8e73c0f09473" // "size 0.12 0.12 life 1.2 gravity 0 texture d7277e78-06f4-58ae-9f7c-7499e50de18a" integer LOCKGUARD_CHANNEL = -9119; integer COMM_CHANNEL = -57841689; integer comm_handle; key avatar; list links; list ring_prims; integer all_poses = -2; // cache the position of the "*" if it exists, for performance goChain(list new_links) { integer index; // unlink unused links for (; index < llGetListLength(links); index += 2) { if (llListFindList(new_links, [llList2String(links, index)]) == -1) { llWhisper(LOCKGUARD_CHANNEL, "lockguard " + (string)avatar + " " + llList2String(links, index) + " unlink"); } } index = 0; // link new links for (; index < llGetListLength(new_links); index += 2) { integer found = llListFindList(ring_prims, [llList2String(new_links, index + 1)]); if (~found) { llWhisper(LOCKGUARD_CHANNEL, "lockguard " + (string)avatar + " " + llList2String(new_links, index) + " link " + llList2String(ring_prims, found + 1) + " " + CHAIN_PARAMETERS); } } links = new_links; } list findPrimsWithSubstring(string name) { list found; integer index = llGetLinkNumber() != 0; integer number = llGetNumberOfPrims() + index; for (; index <= number; index++) { if (~llSubStringIndex(llToLower(llGetLinkName(index)), name)) { found += [llGetLinkName(index), llGetLinkKey(index)]; } } return found; } default { link_message(integer sender, integer num, string msg, key id) { if (sender != llGetLinkNumber()) return; if (num == 90500 && USES_PROPS) { list data = llParseStringKeepNulls(msg, ["|"], []); integer SITTER_NUMBER = (integer)llList2String(data, 1); if (SITTER_NUMBER == SITTER || !~SITTER) { avatar = id; string EVENT = llList2String(data, 0); // string PROP_NAME = llList2String(data, 2); string PROP_OBJECT = llList2String(data, 3); // string PROP_GROUP = llList2String(data, 4); string PROP_UUID = llList2String(data,5); // llOwnerSay(llList2CSV([EVENT, SITTER_NUMBER, PROP_NAME, PROP_OBJECT, PROP_GROUP, PROP_UUID, AVATAR_UUID])); if (EVENT == "REZ") { llListenRemove(comm_handle); comm_handle = llListen(COMM_CHANNEL, PROP_OBJECT, PROP_UUID, ""); llRegionSayTo((key)PROP_UUID, COMM_CHANNEL, "INFORM"); } } } else if (num == 90065) {//stands up if (id == avatar) { goChain([]); avatar = NULL_KEY; } } else if (num == 90045) {//animation played list data = llParseString2List(msg, ["|"], []); string SITTER_NUMBER = llList2String(data, 0); if ((integer)SITTER_NUMBER == SITTER || !~SITTER) { if (id != avatar) { goChain([]); } avatar = id; string POSE_NAME = llList2String(data, 1); list new_links; integer pose_index = llListFindList(POSES, [POSE_NAME]); if (!~pose_index) { if (all_poses == -2) all_poses = llListFindList(POSES, (list)"*"); pose_index = all_poses; } if (~pose_index) { new_links = llCSV2List(llList2String(POSES, pose_index + 1)); } if (USES_PROPS) { goChain(new_links); } else { ring_prims = findPrimsWithSubstring("ring"); } goChain(new_links); } else if (id == avatar) { goChain([]); avatar = NULL_KEY; } } } listen(integer listen_channel, string name, key id, string msg) { list data = llParseString2List(msg, ["|"], []); if (llList2String(data, 0) != "ATTACHPOINTS") return; ring_prims = llDeleteSubList(data, 0, 0); goChain(links); } }