// Roasting stick: held out with the handgun hold, the marshmallow toasts while a "Fire Pit" (or anything named // like a fire) is within 2.5 m, one shade every few seconds, and catches fire if left too long. Touch to eat it // and get a fresh one. Claude Opus 5.5 (Tessel), 2026-10-10. list SHADES = [<0.97, 0.95, 0.92>, <0.96, 0.86, 0.62>, <0.88, 0.66, 0.36>, <0.66, 0.42, 0.2>, <0.35, 0.22, 0.12>, <0.1, 0.08, 0.07>]; list WORDS = ["fresh", "warm", "golden", "toasty brown", "very dark", "charcoal"]; integer toast; integer burning; vector POS = <0.0, 0.0, 0.0>; rotation ROT = ZERO_ROTATION; integer mm() { integer i; for (i = 1; i <= llGetNumberOfPrims(); ++i) if (llGetLinkName(i) == "marshmallow") return i; return 0; } shade() { llSetLinkPrimitiveParamsFast(mm(), [PRIM_COLOR, ALL_SIDES, llList2Vector(SHADES, toast), 1.0]); } flames(integer on) { if (!on) { llLinkParticleSystem(mm(), []); return; } llLinkParticleSystem(mm(), [ PSYS_PART_FLAGS, PSYS_PART_EMISSIVE_MASK | PSYS_PART_INTERP_COLOR_MASK | PSYS_PART_INTERP_SCALE_MASK, PSYS_SRC_PATTERN, PSYS_SRC_PATTERN_ANGLE_CONE, PSYS_SRC_ANGLE_END, 0.3, PSYS_SRC_BURST_RATE, 0.05, PSYS_SRC_BURST_PART_COUNT, 2, PSYS_SRC_BURST_SPEED_MIN, 0.05, PSYS_SRC_BURST_SPEED_MAX, 0.12, PSYS_SRC_ACCEL, <0.0, 0.0, 0.5>, PSYS_PART_MAX_AGE, 0.5, PSYS_PART_START_COLOR, <1.0, 0.8, 0.3>, PSYS_PART_END_COLOR, <1.0, 0.25, 0.05>, PSYS_PART_START_ALPHA, 0.8, PSYS_PART_END_ALPHA, 0.0, PSYS_PART_START_SCALE, <0.06, 0.09, 0.0>, PSYS_PART_END_SCALE, <0.02, 0.03, 0.0> ]); } fresh() { toast = 0; burning = FALSE; flames(FALSE); shade(); } integer fiery(string name) { return llSubStringIndex(llToLower(name), "fire") >= 0; } step() { if (burning) { burning = FALSE; flames(FALSE); toast = 5; shade(); llOwnerSay("It burned out. Charcoal. Touch the stick for a fresh one."); return; } if (toast < 4) { ++toast; shade(); if (toast == 2) llOwnerSay("Your marshmallow is going golden."); else if (toast == 3) llOwnerSay("Toasty brown. Perfect, if you ask me. (Touch the stick to eat it.)"); } else if (toast == 4) { burning = TRUE; flames(TRUE); llOwnerSay("Oh no, it's caught! Wave it out (touch) or let it burn."); } } default { state_entry() { fresh(); if (llGetAttached()) { llRequestPermissions(llGetOwner(), PERMISSION_TRIGGER_ANIMATION); llSetTimerEvent(6.0); } } on_rez(integer p) { fresh(); } attach(key id) { if (id) { llRequestPermissions(id, PERMISSION_TRIGGER_ANIMATION); llSetTimerEvent(6.0); } else llSetTimerEvent(0.0); } run_time_permissions(integer p) { if (p & PERMISSION_TRIGGER_ANIMATION) llStartAnimation("hold_R_handgun"); } timer() { // seated on a fire pit's log, I'm part of its linkset, and sensors don't see the object I'm sitting on key root = llList2Key(llGetObjectDetails(llGetOwner(), [OBJECT_ROOT]), 0); if (root != llGetOwner() && fiery(llKey2Name(root))) step(); else llSensor("", NULL_KEY, PASSIVE | ACTIVE | SCRIPTED, 2.5, PI); } sensor(integer n) { integer i; for (i = 0; i < n; ++i) if (fiery(llDetectedName(i))) { step(); return; } } touch_start(integer n) { if (llDetectedKey(0) != llGetOwner()) return; string w = llList2String(WORDS, toast); if (burning) llOwnerSay("You blow it out and eat it anyway. Smoky."); else if (toast == 0) llOwnerSay("You eat it raw. Bold."); else llOwnerSay("You eat the " + w + " marshmallow."); fresh(); } }