// init flow -> init() -> populate_link_nums() -> dataserver -> finalize_init() //-------------------------------------------------------------------------- // BEGIN config // use flags //#define USE_BOLTS //#define USE_VERBOSE #define DEVICE_VERSION "0.1" #define DEVICE_NAME "indicators" // lights #define MAX_GLOW 0.3 #define FULLBRIGHT_ON_GLOW #define OFF_DAMP_FACTOR 0.4 #define MASKED_TINT_FACTOR 0.5 #define INDICATOR_LINK_NAME "icon" #define TOUCHABLE_LINK_NAME "glass" #define TEXTURE_TILES 8 // END config //-------------------------------------------------------------------------- // BEGIN macros #define color_parse(_argv) <(float)gets(_argv, 1), (float)gets(argv, 2), (float)gets(argv, 3)> #define add_device(_id, _ch) tell(_id, _ch, "add " + DEVICE_NAME) // END macros //-------------------------------------------------------------------------- // BEGIN includes #include #include // END includes //-------------------------------------------------------------------------- // BEGIN globals key config_query = NULL_KEY; integer config_cur_line = 0; string config_nc_name = "config"; key config_nc_key = NULL_KEY; list system_names = []; list system_flags = []; list system_texcoords = []; list ind_links = []; list touch_links = []; integer L_CAPS = 0; integer L_LIGHTS = 0; #define C_CAPS 411 integer C_LIGHTS = 0; integer power_on = 1; integer broken = 0; float gap = 0; vector color = <1, 1, 1>; vector color2 = <1, 1, 1>; vector color3 = <1, 1, 1>; vector color4 = <1, 1, 1>; integer sys_state = 0xFFFFFFFF; integer masked_state = 0; integer forbidden_state = 0; key avatar = NULL_KEY; key controller = NULL_KEY; // END globals //-------------------------------------------------------------------------- // BEGIN functions set_tint(integer link, integer side, vector tint, vector repeats, vector offsets, float glow) { #ifdef FULLBRIGHT_ON_GLOW integer fullbright = 0; if (glow > 0) { fullbright = 1; } #endif setp(link, [ PRIM_COLOR, side, tint, 1, PRIM_GLOW, side, glow, #ifdef FULLBRIGHT_ON_GLOW PRIM_FULLBRIGHT, side, fullbright, #endif PRIM_GLTF_BASE_COLOR, side, "", repeats, offsets, 0, llsRGB2Linear(tint), 1, PRIM_GLTF_ALPHA_MODE_OPAQUE, 0.5, 0, PRIM_GLTF_NORMAL, side, "", repeats, offsets, 0, PRIM_GLTF_METALLIC_ROUGHNESS, side, "", repeats, offsets, 0, 1, 1, PRIM_GLTF_EMISSIVE, side, "", repeats, offsets, 0, llsRGB2Linear(tint) ]); } update_colors(float level) { if (level < 0) { level = 0; } if (level > 1) { level = 1; } integer sysi = count(system_names); float tex_scale = 1.0 / TEXTURE_TILES; vector repeats = ; while (sysi--) { integer l = geti(ind_links, sysi); string name = gets(system_names, sysi); integer flag = geti(system_flags, sysi); vector texcoord = getv(system_texcoords, sysi); #ifdef USE_VERBOSE echo("Updating sysi " + (string)sysi + ": link " + (string)l + ", system " + name + ", flag " + (string)flag + ", with offset " + (string)texcoord); #endif if (!l || !strlen(name) || !flag || texcoord == ZERO_VECTOR) { #ifdef USE_VERBOSE echo("Invalid, skipping " + (string)sysi + "..."); #endif jump sysicontinue; } if (power_on) { if (forbidden_state & flag) { // System forbidden set_tint(l, ALL_SIDES, color * OFF_DAMP_FACTOR, repeats, texcoord * tex_scale, 0); } else if (masked_state & flag) { // System requirements unmet set_tint(l, ALL_SIDES, color3 * level * MASKED_TINT_FACTOR, repeats, texcoord * tex_scale, level * MAX_GLOW); } else if (sys_state & flag) { // System enabled set_tint(l, ALL_SIDES, color * level, repeats, texcoord * tex_scale, level * MAX_GLOW); } else { // System disabled explicitly set_tint(l, ALL_SIDES, color3 * level, repeats, texcoord * tex_scale, level * MAX_GLOW); } } else { set_tint(l, ALL_SIDES, color * OFF_DAMP_FACTOR, repeats, texcoord * tex_scale, 0); } @sysicontinue; } } integer get_prim_count() { if (llGetAttached()) { return llGetNumberOfPrims(); } return llGetObjectPrimCount(llGetKey()); } // get_prim_count() populate_link_nums() { ind_links = []; touch_links = []; integer i = get_prim_count(); string link_name; for (; i > 0; i--) { link_name = llGetLinkName(i); if (strpos(link_name, INDICATOR_LINK_NAME) != -1) { ind_links += i; } if (strpos(link_name, TOUCHABLE_LINK_NAME) != -1) { touch_links += i; } } // for (...) #ifdef USE_VERBOSE echo("Found " + (string)count(ind_links) + " icons, with " + (string)count(touch_links) + " touchable links"); #endif } // populate_link_nums() init() { avatar = llGetOwner(); controller = NULL_KEY; populate_link_nums(); power_on = 1; key nc = llGetInventoryKey(config_nc_name); if (nc == config_nc_key && nc != NULL_KEY) { // No config change. finalize_init(); return; } system_names = []; system_flags = []; system_texcoords = []; config_nc_key = nc; config_cur_line = 0; if (config_nc_key == NULL_KEY) { echo("No config found, cannot start"); return; } config_query = llGetNotecardLine(config_nc_name, config_cur_line); } finalize_init() { #ifdef USE_VERBOSE echo("Found " + (string)count(system_names) + " configured systems to track, finalizing"); #endif update_colors(1); // Called from dataserver once config is read. C_LIGHTS = 105 - (integer)("0x" + substr(avatar, 29, 35)); llListenRemove(L_LIGHTS); L_LIGHTS = llListen(C_LIGHTS, "", NULL_KEY, ""); llListenRemove(L_CAPS); L_CAPS = llListen(C_CAPS, "", NULL_KEY, ""); add_device(avatar, C_LIGHTS); } // END functions //-------------------------------------------------------------------------- // BEGIN main default { state_entry() { init(); } // state_entry() on_rez(integer n) { init(); } // on_rez(...) changed(integer chg) { if (chg & CHANGED_INVENTORY) { init(); } if (chg & CHANGED_OWNER) { init(); } if (chg & CHANGED_LINK) { init(); } } dataserver(key qid, string data) { if (qid == config_query) { if (data == EOF) { echo("Config reloaded."); finalize_init(); } else { // line if (substr(data, 0, 0) == "#") { #ifdef USE_VERBOSE echo("Skipping comment in config: " + data); #endif jump confignextline; } list cl = split(data, " "); if (count(cl) != 4) { echo("Invalid line in config: " + data); jump confignextline; } system_names += gets(cl, 0); system_flags += geti(cl, 1); system_texcoords += ; #ifdef USE_VERBOSE echo("Registered system " + concat(cl, " ")); #endif @confignextline; config_query = llGetNotecardLine(config_nc_name, ++config_cur_line); } } } listen(integer cc, string src, key id, string msg) { if (cc == C_CAPS) { if (substr(msg, 0, 4) == "info ") { integer rc = (integer)delstring(msg, 0, 4); tell(id, rc, "hwc " + jsobject([ "vendor", "Cat Conspiracy", "version", DEVICE_VERSION, "purpose", "info", "channel", jsobject(["caps", C_CAPS, "lights", C_LIGHTS]), "private", 0, "busy", 0, "usable", power_on, "health", 1.0, "info", "http://localhost:8080/" ])); } // if (cmd == "info") } // if (cc == C_CAPS) else if (cc == C_LIGHTS) { list argv = split(msg, " "); string cmd = gets(argv, 0); switch (cmd) { case "off": power_on = 0; gap = 0; update_colors(1); break; case "on": power_on = 1; if (broken) { gap = 0.05; } else { gap = 0; } update_colors(1); break; #ifdef USE_BOLTS case "bolts": if (gets(argv, 1) == "on") { echo("@detach=n"); } else if (gets(argv, 1) == "off") { echo("@detach=y"); } break; #endif case "broken": gap = 0.05; broken = 1; break; case "fixed": gap = 0; broken = 0; update_colors(1); break; case "color": color = color_parse(argv); update_colors(1); break; case "color-2": color2 = color_parse(argv); update_colors(1); break; case "color-3": color3 = color_parse(argv); update_colors(1); break; case "color-4": color4 = color_parse(argv); update_colors(1); break; case "name": llSetObjectName(concat(delrange(argv, 0, 0), " ") + " (" + DEVICE_NAME + ")"); case "probe": add_device(id, C_LIGHTS); break; case "add-confirm": controller = id; tell(id, C_LIGHTS, "color-q"); tell(id, C_LIGHTS, "command " + (string)avatar + " " + (string)avatar + " subsys query"); break; case "subsys": #ifdef USE_VERBOSE echo("Received " + msg); #endif sys_state = geti(argv, 1); masked_state = geti(argv, 2); forbidden_state = geti(argv, 3); update_colors(1); break; case "power": break; case "rate": break; default: #ifdef USE_VERBOSE echo("Unhandled light bus (" + src + "): " + msg); #endif break; } // switch (cmd) llSetTimerEvent(gap); } // if (cc == C_LIGHTS) } // listen(...) timer() { if (!broken) { return; } float t = 1; if (llFrand(1.0) < 0.1) { t = llFrand(0.2); } update_colors(t); } // timer() } // state default // END main //--------------------------------------------------------------------------