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 tracks seven earnable badges that recognize player milestones — from making a first donation to witnessing a mythic hunt. Badges are stored once per user regardless of which Discord server they were earned in, they appear automatically on the /profile card, and they can never be lost or reset. This page documents every badge, its internal ID, the exact trigger that awards it, and implementation details for developers extending the system.

All Badges

Badge IDDisplay NameRequirementHow Awarded
donor💎 DonorMake a first successful donationAuto-awarded inside the OxaPay confirmation flow
hunter_10🏹 Hunter IReach 10 total huntsAuto-awarded during the hunt flow on the 10th hunt
hunter_50🏹 Hunter IIReach 50 total huntsAuto-awarded during the hunt flow on the 50th hunt
hunter_100🏹 Hunter IIIReach 100 total huntsAuto-awarded during the hunt flow on the 100th hunt
legendary🌟 Legendary FinderCatch any Legendary creatureAuto-awarded on first legendary rarity drop
mythic🌌 Mythic WitnessCatch any Mythic creatureAuto-awarded on first mythic rarity drop
streak_25🔥 Hot StreakMaintain a 25-hunt streakDefined and display-ready; award trigger reserved for future use

How Badges Are Stored

Badges live in the badges table in db/noxie.db (SQLite). The schema is:
CREATE TABLE IF NOT EXISTS badges (
    id          INTEGER PRIMARY KEY AUTOINCREMENT,
    user_id     TEXT    NOT NULL,
    badge_name  TEXT    NOT NULL,
    awarded_at  REAL    NOT NULL DEFAULT 0,
    UNIQUE(user_id, badge_name)
);
The UNIQUE(user_id, badge_name) constraint is what prevents duplicate awards — if award_badge() is called a second time for the same user and badge name, SQLite raises an IntegrityError that the function catches silently. Badges are stored by user_id only, with no guild_id column, making them cross-guild by design. A badge earned on one server is visible on /profile in every server.

The award_badge() Function

award_badge() in utils/economy.py is the single entry point for all badge grants:
def award_badge(conn: sqlite3.Connection, user_id: str, badge_name: str) -> bool:
    """Awards a badge. Returns True if it's new."""
    try:
        conn.execute(
            "INSERT INTO badges (user_id, badge_name, awarded_at) VALUES (?,?,?)",
            (user_id, badge_name, time.time())
        )
        conn.commit()
        return True
    except sqlite3.IntegrityError:
        return False
The boolean return value matters: the donation flow uses it to decide whether to show a “badge unlocked” notification to the user. When award_badge() returns True, the badge is freshly awarded and the flow surfaces a confirmation message. When it returns False, the badge was already held and the flow skips the notification silently.

How Badges Display on /profile

get_badges() returns a list of badge_name strings ordered by awarded_at ASC. The profile renderer maps each string through the BADGE_DISPLAY dictionary defined in utils/economy.py to produce the emoji + label shown on the card:
BADGE_DISPLAY: dict[str, str] = {
    "donor":       "💎 Donor",
    "hunter_10":   "🏹 Hunter I",
    "hunter_50":   "🏹 Hunter II",
    "hunter_100":  "🏹 Hunter III",
    "legendary":   "🌟 Legendary Finder",
    "mythic":      "🌌 Mythic Witness",
    "streak_25":   "🔥 Hot Streak",
}
Any badge_name not present in BADGE_DISPLAY is rendered as the raw ID string, so custom badges added to the database without a display entry will still appear — just without a friendly label.

Hunt Milestone Logic

The three Hunter badges share a single conditional block in do_hunt() inside cogs/hunt.py. After record_hunt() updates total_hunts, the block checks thresholds in descending order so a user who jumps straight to 100 hunts only triggers hunter_100, not all three at once:
total = bal["total_hunts"]
if total >= 100:
    if economy.award_badge(bot.db, user_id, "hunter_100"):
        logger.success(f"badge awarded: user={user_id} hunter_100")
elif total >= 50:
    if economy.award_badge(bot.db, user_id, "hunter_50"):
        logger.success(f"badge awarded: user={user_id} hunter_50")
elif total >= 10:
    if economy.award_badge(bot.db, user_id, "hunter_10"):
        logger.success(f"badge awarded: user={user_id} hunter_10")
Rarity badges (legendary, mythic) are checked in the same function immediately after, using the rolled rarity string as the condition.
The streak_25 badge (🔥 Hot Streak) is fully defined in BADGE_DISPLAY and the badges table schema supports it — but the automatic award trigger has not yet been wired into the hunt flow. To enable it, add a check for bal["hunt_streak"] >= 25 inside do_hunt() in cogs/hunt.py, following the same pattern as the Hunter milestone checks. The hunt_streak column already exists in the economy table and is incremented on every successful hunt.

Build docs developers (and LLMs) love