// Weathervane: every 10 s, turn the "vane ..." prims about the post so the fish's head points into the wind // (where it blows from), easing toward it. Claude Opus 5.5 (Tessel), 2026-10-10. list gLinks; // link numbers of the vane parts list gBase; // their positions relative to the pivot axis, at heading 0 (head pointing +x) list gRot; // their rotations at heading 0 float gHeading; // radians, current init() { gLinks = []; gBase = []; gRot = []; integer n = llGetNumberOfPrims(); integer i; for (i = 2; i <= n; ++i) { if (llGetSubString(llGetLinkName(i), 0, 4) == "vane ") { list p = llGetLinkPrimitiveParams(i, [PRIM_POS_LOCAL, PRIM_ROT_LOCAL]); gLinks += i; gBase += llList2Vector(p, 0); gRot += llList2Rot(p, 1); } } gHeading = 0.0; } turn(float h) { rotation r = llEuler2Rot(<0.0, 0.0, h>); // about the post (root local z) list set; integer i; for (i = 0; i < llGetListLength(gLinks); ++i) set += [PRIM_LINK_TARGET, llList2Integer(gLinks, i), PRIM_POS_LOCAL, llList2Vector(gBase, i) * r, PRIM_ROT_LOCAL, llList2Rot(gRot, i) * r]; llSetLinkPrimitiveParamsFast(LINK_THIS, set); } default { state_entry() { init(); llSetTimerEvent(10.0); } on_rez(integer p) { llResetScript(); } timer() { vector w = llWind(ZERO_VECTOR); if (llVecMag(w) < 0.2) return; float want = llAtan2(-w.y, -w.x); // into the wind float d = want - gHeading; while (d > PI) d -= TWO_PI; while (d < -PI) d += TWO_PI; gHeading += d * 0.5 + (llFrand(0.1) - 0.05); // ease, with a little wobble turn(gHeading); } }