// Wolf Air range board 1.0.0 - today's best bombing runs on this region's range, as floating text (wolf-air 1.7.0), 2026-11-02. // Copyright (C) 2026 IntelligentWolf Ltd. // // Put it in the score board prim of a bombing range (k-bombing-range/) or in any prim on a region with the wolf-air plugin. // Contract: a-research/DESIGN_BOMBERS.md s3.3: air.range ["scores"] -> ["scores", "|||||", ...] // (at most 20, the best of the day). Touch it: the board is asked again and you are told all of them in chat. // It asks every 60 s, and only while an avatar is within 30 m (one sensor sweep a minute: nothing runs for an empty range). // Floating text holds at most 254 bytes (SceneObjectPart.cs:4106 SetText: new osUTF8(text, 254)), so the board shows the top // runs that fit and the touch gives the full list. float EVERY = 60.0; // s3.3: the board script calls it every 60 s while someone is near float NEAR_M = 30.0; // s3.3 / the brief: only while an avatar is within 30 m integer TEXT_MAX = 254; // SceneObjectPart.cs:4106 vector COLOUR = <1.0, 0.85, 0.4>; list gRows; // the answer's lines string Clock(integer unix) { integer s = unix % 86400; string h = (string)(s / 3600); if (llStringLength(h) < 2) h = "0" + h; string m = (string)((s % 3600) / 60); if (llStringLength(m) < 2) m = "0" + m; return h + ":" + m; } string Row(integer i) { list f = llParseStringKeepNulls(llList2String(gRows, i), ["|"], []); return (string)(i + 1) + ". " + llList2String(f, 2) + " (" + llList2String(f, 1) + ") on " + llList2String(f, 0) + " - " + llList2String(f, 3) + " points, best " + llList2String(f, 4) + " m, " + Clock((integer)llList2String(f, 5)) + " UTC"; } string Short(integer i) { list f = llParseStringKeepNulls(llList2String(gRows, i), ["|"], []); return (string)(i + 1) + ". " + llList2String(f, 2) + " " + llList2String(f, 3) + " pts (" + llList2String(f, 4) + " m)"; } Ask() { list r = wolfCall("air.range", ["scores"]); if (r == []) { string e = wolfGetLastError(); if (llSubStringIndex(e, "no plugin function") != -1) e = "this region has no Wolf Air plugin (wolf-air)"; llSetText("BOMBING RANGE\n" + llGetSubString(e, 0, 200), COLOUR, 1.0); gRows = []; return; } gRows = llList2List(r, 1, -1); string t = "BOMBING RANGE - TODAY'S BEST"; if (gRows == []) t += "\nNo bombs on the range yet today."; integer i; for (i = 0; i < llGetListLength(gRows); ++i) { string add = "\n" + Short(i); if (llStringLength(t + add) > TEXT_MAX) i = 99; // UTF-8 names are rare; the server cuts at 254 bytes anyway else t += add; } llSetText(t, COLOUR, 1.0); } default { state_entry() { llSetText("BOMBING RANGE\nTouch for today's best runs.", COLOUR, 1.0); llSetTimerEvent(EVERY); } on_rez(integer p) { llResetScript(); } touch_start(integer n) { key a = llDetectedKey(0); Ask(); if (gRows == []) { llRegionSayTo(a, 0, "No bombing runs scored here today yet."); return; } integer i; llRegionSayTo(a, 0, "Today's best bombing runs on " + llGetRegionName() + ":"); for (i = 0; i < llGetListLength(gRows); ++i) llRegionSayTo(a, 0, Row(i)); } timer() { llSensor("", NULL_KEY, AGENT, NEAR_M, PI); } sensor(integer n) { Ask(); } no_sensor() { } }