Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/developer51709/Noxie/llms.txt

Use this file to discover all available pages before exploring further.

Noxie is not a neutral bot. Every response — hunt results, cooldown messages, donation confirmations, errors — passes through a personality engine that picks a tone based on the current context. The system lives in utils/personality.py and exposes three public functions: active_tone(), get_line(), and vibe_status(). Tone shifts are entirely stateless and derived at call time from two numeric inputs: the user’s hunt streak and a floating-point luck value.

The Four Tones

ToneTriggersCharacter
DeadpanDefault state, low streakDry, flat delivery. Acknowledges events without emotion.
CozyHigh luck rolls, warm eventsWarm and gentle. Uses exclamation marks, heart emojis, and soft reassurances.
ChaoticLong streaks (15+), rare findsWild and unhinged. All-caps outbursts, rhetorical questions, barely contained energy.
SarcasticLow luck, empty inventorySardonic and dismissive. Technically responds but makes you feel slightly judged.

How Tone Is Determined

Tone is derived by active_tone(streak, luck) in utils/personality.py:
def active_tone(streak: int = 0, luck: float = 0.5) -> Tone:
    """Derive Noxie's current dominant tone from context."""
    if streak >= 15:
        return "chaotic"
    if luck > 0.85:
        return "cozy"
    if luck < 0.15:
        return "sarcastic"
    return "deadpan"
The luck value used in the hunt flow is computed directly from the streak:
luck = min(1.0, streak / 20.0)
This means luck and streak are tightly coupled during hunts. A streak of 20 or higher caps luck at 1.0, which is well above the 0.85 cozy threshold — but the streak >= 15 chaotic check fires first, so a long streak always resolves to chaotic regardless. The rarity of the caught creature provides an independent luck signal:
RARITY_LUCK = {
    "common": 0.3, "uncommon": 0.5, "rare": 0.65,
    "epic": 0.8, "legendary": 0.93, "mythic": 1.0,
}
When get_line() is called after a hunt, the rarity luck value is passed in directly, letting a mythic catch push toward cozy even when the streak is low.

Getting Personality Lines

get_line(event, streak, luck) returns one context-appropriate string from a pre-written bank of lines in the LINES dict:
def get_line(event: str, streak: int = 0, luck: float = 0.5) -> str:
    pool = LINES.get(event, ["..."])

    if streak >= 10 or luck > 0.8:
        filtered = [l for l in pool if any(k in l for k in ["!!", "?", "WAIT", "hii", "OH", "oh"])]
        if filtered:
            return random.choice(filtered)
    elif luck < 0.2 or streak == 0:
        filtered = [l for l in pool if not any(k in l for k in ["!!", "WAIT", "OH"])]
        if filtered:
            return random.choice(filtered)

    return random.choice(pool)
High streak or high luck biases the selection toward lines containing excited markers (!!, ?, OH). Low luck or a fresh start biases away from them. If neither filter produces results, the function falls back to a fully random pick from the pool, so every event always returns something.

Event Keys

Event KeyWhen It Fires
hunt_successSuccessful hunt (common, uncommon, rare)
hunt_rareSuccessful hunt (epic, legendary, mythic)
hunt_failHunt failure; also used for the empty-inventory banner
cooldownHunt attempted while on cooldown
errorUnhandled exception in a command
inventory_empty/inventory called with no caught creatures
donate_thanksDonation confirmed via OxaPay webhook
greetingBot joins a new server
profile_low_level/profile on a user with very few hunts
To add new event keys, append an entry to the LINES dict in utils/personality.py and call personality.get_line("your_event_key") wherever you want the line to appear. No other changes are needed.

Vibe Status

vibe_status(streak, luck) wraps active_tone() and returns a human-readable status string displayed on the /vibe and /profile commands:
def vibe_status(streak: int, luck: float) -> str:
    tone = active_tone(streak, luck)
    statuses = {
        "chaotic":   "⚡ full chaos mode",
        "cozy":      "🌿 cozy and soft",
        "sarcastic": "🌑 deeply unimpressed",
        "deadpan":   "👁️ existing. barely.",
    }
    return statuses.get(tone, "🫧 undefined vibe")
This string is embedded directly in the vibe card container alongside the streak count.

How Personality Affects CV2 Containers

The personality line is the last piece assembled before a CV2 container is sent. In cogs/hunt.py the call chain is:
event = "hunt_rare" if rarity in ("legendary", "mythic", "epic") else "hunt_success"
line = personality.get_line(event, streak=bal["hunt_streak"], luck=luck)
The resulting line string is rendered in italics at the bottom of the hunt card, just above the mood banner:
*{personality_line}*
The same pattern is used across all CV2 container types:
ContainerLine event used
Hunt resulthunt_success or hunt_rare
Cooldown responsecooldown
Error responseerror
Empty inventoryinventory_empty
Vibe cardhunt_success (with live streak/luck)
Donation confirmationdonate_thanks
Guild joingreeting
Mood banner selection is also tone-aware at the event level — the same streak and luck context that shapes the line also drives which face image the face_manager picks for the container.
Build a hunt streak of 15 or more consecutive hunts to trigger chaotic personality. Noxie’s responses will become progressively more unhinged the longer the streak runs.

Build docs developers (and LLMs) love