// Stargate Lights Controller v4 Minimal Test // // Purpose: // - Minimal diagnostic lights controller for isolating mesh face behavior. // - No notecard config. // - No texture writes. // - Defaults to face 0 only. // - Supports chevron discovery by prim name or description: 1..9, CHEV1..9, CHEVRON1..9. // // Recommended test flow with stargate_gate_av_tester_v1.lsl: // 1) Remove or disable other light controller scripts. // 2) Drop this script into the same linked gate object as the tester. // 3) Set chevron prim descriptions to CHEV1..CHEV9 or leave prim names as CHEV1..CHEV9. // 4) Run /779907 rescan // 5) Run /779907 toggle 1 // // Supported commands: // llMessageLinked(LINK_SET, 0, "SG_LIGHT", "SCAN"); // llMessageLinked(LINK_SET, 1, "SG_LIGHT", "OFF"); // llMessageLinked(LINK_SET, 1, "SG_LIGHT", "LOCK"); // llMessageLinked(LINK_SET, 1, "SG_LIGHT", "CHARGE"); // llMessageLinked(LINK_SET, 1, "SG_LIGHT", "FAIL"); // llMessageLinked(LINK_SET, 1, "SG_LIGHT", "ACTIVE"); integer debug = TRUE; integer defaultFace = 0; vector COLOR_OFF = <1.000, 1.000, 1.000>; vector COLOR_CHARGE = <0.050, 0.350, 1.000>; vector COLOR_LOCK = <0.000, 0.500, 0.850>; vector COLOR_FAIL = <1.000, 0.120, 0.120>; vector COLOR_ACTIVE = <0.000, 0.750, 1.000>; vector COLOR_ON = <0.000, 0.400, 0.600>; float GLOW_OFF = 0.0; float GLOW_ON = 0.03; list gChevrons; // [index, link, index, link, ...] string normalize_name(string n) { return llToUpper(llStringTrim(n, STRING_TRIM)); } integer is_chevron_name_for_index(string value, integer idx) { string n = normalize_name(value); string s = (string)idx; if (n == s) return TRUE; if (n == ("CHEV" + s)) return TRUE; if (n == ("CHEVRON" + s)) return TRUE; return FALSE; } integer is_integer_string(string value) { string trimmed = llStringTrim(value, STRING_TRIM); if (trimmed == "") return FALSE; integer i = 0; integer len = llStringLength(trimmed); for (; i < len; ++i) { string c = llGetSubString(trimmed, i, i); if (c < "0" || c > "9") return FALSE; } return TRUE; } string desc_chevron_label(string desc) { integer pipePos = llSubStringIndex(desc, "|"); if (pipePos == -1) return llStringTrim(desc, STRING_TRIM); return llStringTrim(llGetSubString(desc, 0, pipePos - 1), STRING_TRIM); } string desc_face_spec(string desc) { integer pipePos = llSubStringIndex(desc, "|"); if (pipePos == -1) return ""; return llStringTrim(llGetSubString(desc, pipePos + 1, -1), STRING_TRIM); } integer desc_declares_chevron(string desc, integer idx) { string trimmed = desc_chevron_label(desc); if (trimmed == "") return FALSE; list parts = llParseString2List(trimmed, [";", ",", " "], []); integer i = 0; integer n = llGetListLength(parts); for (; i < n; ++i) { if (is_chevron_name_for_index(llList2String(parts, i), idx)) return TRUE; } return FALSE; } list get_faces_for_link(integer link) { string desc = llList2String(llGetLinkPrimitiveParams(link, [PRIM_DESC]), 0); string spec = desc_face_spec(desc); if (!is_integer_string(spec)) { return [defaultFace, defaultFace]; } integer face = (integer)spec; return [face, face]; } scan_chevrons() { gChevrons = []; integer max = llGetNumberOfPrims(); integer link = 1; for (; link <= max; ++link) { string primName = llList2String(llGetLinkPrimitiveParams(link, [PRIM_NAME]), 0); string primDesc = llList2String(llGetLinkPrimitiveParams(link, [PRIM_DESC]), 0); integer idx = 1; for (; idx <= 9; ++idx) { if (is_chevron_name_for_index(primName, idx) || desc_declares_chevron(primDesc, idx)) { gChevrons += [idx, link]; if (debug) llOwnerSay("[LIGHTS_V4] mapped chevron " + (string)idx + " to link " + (string)link); idx = 10; } } } if (debug) llOwnerSay("[LIGHTS_V4] mappings=" + llList2CSV(gChevrons)); } list get_target_links(integer idx) { list result = []; integer i = 0; integer n = llGetListLength(gChevrons); for (; i < n; i += 2) { integer mappedIndex = llList2Integer(gChevrons, i); integer mappedLink = llList2Integer(gChevrons, i + 1); if (idx == 0 || mappedIndex == idx) { result += [mappedLink]; } } return result; } apply_to_link(integer link, vector color, integer isOn, float glowVal) { list faces = get_faces_for_link(link); integer face = llList2Integer(faces, 0); // Clear historical whole-prim writes first. llSetLinkPrimitiveParamsFast(link, [ PRIM_COLOR, ALL_SIDES, <1.000, 1.000, 1.000>, 1.0, PRIM_FULLBRIGHT, ALL_SIDES, FALSE, PRIM_GLOW, ALL_SIDES, 0.0, PRIM_POINT_LIGHT, FALSE, <1.0, 1.0, 1.0>, 0.0, 0.0, 0.0 ]); llSetLinkPrimitiveParamsFast(link, [ PRIM_COLOR, face, color, 1.0, PRIM_FULLBRIGHT, face, isOn, PRIM_GLOW, face, glowVal, PRIM_POINT_LIGHT, FALSE, <1.0, 1.0, 1.0>, 0.0, 0.0, 0.0 ]); if (debug) llOwnerSay("[LIGHTS_V4] link=" + (string)link + " face=" + (string)face + " on=" + (string)isOn + " color=" + (string)color); } set_lights(integer chevIndex, string mode) { list targets = get_target_links(chevIndex); integer i = 0; integer n = llGetListLength(targets); vector color = COLOR_ON; integer isOn = TRUE; float glowVal = GLOW_ON; string m = llToUpper(llStringTrim(mode, STRING_TRIM)); if (m == "OFF") { color = COLOR_OFF; isOn = FALSE; glowVal = GLOW_OFF; } else if (m == "CHARGE") { color = COLOR_CHARGE; } else if (m == "LOCK") { color = COLOR_LOCK; } else if (m == "FAIL") { color = COLOR_FAIL; } else if (m == "ACTIVE") { color = COLOR_ACTIVE; } for (; i < n; ++i) { apply_to_link(llList2Integer(targets, i), color, isOn, glowVal); } } default { state_entry() { scan_chevrons(); set_lights(0, "OFF"); } changed(integer c) { if (c & CHANGED_LINK) llResetScript(); if (c & CHANGED_OWNER) llResetScript(); } link_message(integer sender, integer num, string str, key id) { list rawParts = llParseStringKeepNulls(str, ["|"], []); string command = llToUpper(llStringTrim(llList2String(rawParts, 0), STRING_TRIM)); string payload = ""; // Prefer SG_LIGHT|MODE payload in the string channel. if (llGetListLength(rawParts) >= 2) { payload = llStringTrim(llList2String(rawParts, 1), STRING_TRIM); } // Backward compatibility: accept legacy key payload only when not NULL_KEY. if (payload == "") { string keyPayload = llStringTrim((string)id, STRING_TRIM); if (keyPayload != "" && keyPayload != (string)NULL_KEY) { payload = keyPayload; } } if (command != "LIGHT" && command != "SG_LIGHT") return; if (debug) llOwnerSay("[LIGHTS_V4] command=" + command + " chev=" + (string)num + " payload=" + payload); if (llToUpper(payload) == "SCAN") { scan_chevrons(); return; } if (num < 0 || num > 9) { if (debug) llOwnerSay("[LIGHTS_V4] invalid chevron index " + (string)num); return; } if (payload == "") payload = "ON"; set_lights(num, payload); } }