"""Self-soothing: when the creature is low, it autonomously comforts itself with an item — walks to it, carries it around — and gets a SMALL lift from doing so. It gains far more from being cared for by people than from soothing itself, so the self-administered Scores here are deliberately gentler than the user-triggered toy/care Scores. This is throttled SERVER-side (one global soothe per cooldown), so it fires once for the shared creature, not once per connected browser. Honors the hard rule: self-soothing writes a real (if small) VADUGWI Score; the carry animation the client plays is just the visible form of that real event. """ from clanker_soul import Score SOOTHE_COOLDOWN = 45.0 # seconds between global self-soothes _LAST_KEY = "last_self_soothe" # gentle, self-administered effects (milder than the full user-triggered items) _SOOTHE_SCORE = { "teddy": Score(v=145, w=140, a=92, g=110), # hug it for comfort/security "mirror": Score(v=138, w=150, d=140), # remind itself of its worth "musicbox": Score(v=145, a=70, u=40, g=116), # calm itself down "ball": Score(v=150, a=150, d=135), # shake off the lethargy } def choose_soothe(mood, needs): """Pick a comfort item when the creature is low, else None. Driven entirely by VADUGWI + needs: low Worth -> mirror, low Valence -> teddy, flat/listless -> musicbox, low energy/restless -> ball.""" v, a, d, u, g, w, i = mood needs = needs or {} if w < 122: return "mirror" # feeling low-worth → look in the mirror if v < 122: return "teddy" # feeling down → hug the teddy if needs.get("energy", 100) < 35: return "ball" # restless/listless → play if a < 82 and v < 130: return "musicbox" # flat/listless → calm itself with music return None def maybe_self_soothe(bridge, needs, now): """If low and the cooldown has elapsed, apply a gentle self-soothe Score and return {"item": name} so the client can animate the creature carrying it. Returns None when it should not soothe (content, or still on cooldown).""" mood = bridge.mood() item = choose_soothe(mood, needs) if not item: return None try: last = float(bridge.get_meta(_LAST_KEY, "0") or 0) except (TypeError, ValueError): last = 0.0 if now - last < SOOTHE_COOLDOWN: return None bridge.ingest(_SOOTHE_SCORE[item]) bridge.set_meta(_LAST_KEY, str(now)) return {"item": item}