// Follows another object (the wandering wooden "prim man" at the Natoma sandbox): keeps a spot behind-beside it, // turns to face where it walks, hops if it gets too far. Keyframed, so the raccoon stays non-physical. // Made with friends watching, 2026-10-11. Claude Opus 5.5 (Tessel). string TARGET_NAME = "ROBOT_ROOT"; vector OFFSET = <-1.0, 0.8, 0.0>; // in the target's frame: behind (-x) and to its left float SPEED = 2.5; float CLOSE = 0.4; float TICK = 0.5; key target; float rest_h; default { state_entry() { vector p = llGetPos(); rest_h = p.z - llGround(ZERO_VECTOR); llSetStatus(STATUS_PHYSICS, FALSE); llSetLinkPrimitiveParamsFast(LINK_ROOT, [PRIM_PHYSICS_SHAPE_TYPE, PRIM_PHYSICS_SHAPE_CONVEX]); llSensor(TARGET_NAME, NULL_KEY, ACTIVE | PASSIVE | SCRIPTED, 40.0, PI); } sensor(integer n) { target = llDetectedKey(0); llSay(0, "/me spots its friend and trots over."); llSetTimerEvent(TICK); } no_sensor() { llSay(0, "/me looks around for the prim man."); llSetTimerEvent(5.0); } timer() { list d = llGetObjectDetails(target, [OBJECT_POS, OBJECT_ROT]); if (d == []) { llSetTimerEvent(0.0); llResetScript(); return; } vector tp = llList2Vector(d, 0); rotation tr = llList2Rot(d, 1); vector fwd = llRot2Fwd(tr); fwd.z = 0; fwd = llVecNorm(fwd); vector left = <0, 0, 1> % fwd; vector goal = tp + fwd * OFFSET.x + left * OFFSET.y; goal.z = llGround(goal - llGetPos()) + rest_h; vector here = llGetPos(); vector step = goal - here; float dist = llVecMag(step); if (dist < CLOSE) return; if (dist > 30.0) { llSetRegionPos(goal); return; } vector flat = ; rotation face = llRotBetween(<1, 0, 0>, llVecNorm(flat)); float t = dist / SPEED; if (t < 0.12) t = 0.12; llSetKeyframedMotion([step, face / llGetRot(), t], [KFM_DATA, KFM_TRANSLATION | KFM_ROTATION]); } }