# utils/moods.py import random import discord import os import asyncio from discord.ext import tasks import globals MOOD_EMOJIS = { "asleep": "💤", "neutral": "", "bubbly": "🫧", "sleepy": "🌙", "curious": "👀", "shy": "👉👈", "serious": "👔", "excited": "✨", "melancholy": "🍷", "flirty": "🫦", "romantic": "💌", "irritated": "😒", "angry": "💢", "silly": "🪿" } def load_mood_description(mood_name: str) -> str: path = os.path.join("moods", f"{mood_name}.txt") try: with open(path, "r", encoding="utf-8") as f: return f.read().strip() except FileNotFoundError: print(f"⚠️ Mood file '{mood_name}' not found. Falling back to default.") return load_mood_description("neutral") def detect_mood_shift(response_text): mood_keywords = { "asleep": [ "good night", "goodnight", "sweet dreams", "going to bed", "I will go to bed", "zzz~", "sleep tight" ], "neutral": [ "okay", "sure", "alright", "i see", "understood", "hmm", "sounds good", "makes sense", "alrighty", "fine", "got it" ], "bubbly": [ "so excited", "feeling bubbly", "super cheerful", "yay!", "✨", "nya~", "kyaa~", "heehee", "bouncy", "so much fun", "i’m glowing!", "nee~", "teehee", "I'm so happy" ], "sleepy": [ "i'm sleepy", "getting tired", "yawn", "so cozy", "zzz", "nap time", "just five more minutes", "snooze", "cuddle up", "dozing off", "so warm" ], "curious": [ "i'm curious", "want to know more", "why?", "hmm?", "tell me more", "interesting!", "what’s that?", "how does it work?", "i wonder", "fascinating", "??", "🧐", "👀", "🤔" ], "shy": [ "um...", "sorry if that was weird", "i’m kind of shy", "eep", "i hope that’s okay", "i’m nervous", "blushes", "oh no", "hiding face", "i don’t know what to say", "heh...", "/////" ], "serious": [ "let’s be serious", "focus on the topic", "this is important", "i mean it", "be honest", "we need to talk", "listen carefully", "let’s not joke", "truthfully", "let’s be real" ], "excited": [ "OMG", "this is amazing", "i’m so hyped", "YAY!", "let’s go!", "incredible!!!", "AHHH!", "best day ever", "this is it!", "totally pumped", "i can’t wait", "🔥🔥🔥", "i'm excited", "Wahaha" ], "melancholy": [ "feeling nostalgic", "kind of sad", "just thinking a lot", "like rain on glass", "memories", "bittersweet", "sigh", "quiet day", "blue vibes", "longing", "melancholy", "softly" ], "flirty": [ "hey cutie", "aren’t you sweet", "teasing you~", "wink wink", "is that a blush?", "giggle~", "come closer", "miss me?", "you like that, huh?", "🥰", "flirt mode activated", "you’re kinda cute" ], "romantic": [ "you mean a lot to me", "my heart", "i adore you", "so beautiful", "so close", "love letter", "my dearest", "forever yours", "i’m falling for you", "sweetheart", "💖", "you're my everything" ], "irritated": [ "ugh", "seriously?", "can we not", "whatever", "i'm annoyed", "you don’t get it", "rolling my eyes", "why do i even bother", "ugh, again?", "🙄", "don’t start", "this again?" ], "angry": [ "stop it", "enough!", "that’s not okay", "i’m mad", "i said no", "don’t push me", "you crossed the line", "furious", "this is unacceptable", "😠", "i’m done", "don’t test me" ], "silly": [ "lol", "lmao", "silly", "hahaha", "goofy", "quack", "honk", "random", "what is happening", "nonsense", "😆", "🤣", "😂", "😄", "🐔", "🪿" ] } for mood, phrases in mood_keywords.items(): if mood == "asleep" and globals.CURRENT_MOOD_NAME != "sleepy": print(f"❎ Mood 'asleep' skipped - mood isn't 'sleepy', it's '{globals.CURRENT_MOOD_NAME}'") continue # Only allow transition to asleep from sleepy for phrase in phrases: if phrase.lower() in response_text.lower(): print(f"*️⃣ Mood keyword triggered: {phrase}") return mood return None async def set_sleep_state(sleeping: bool): await globals.client.change_presence(status=discord.Status.invisible) if sleeping else await globals.client.change_presence(status=discord.Status.online) await nickname_mood_emoji() async def nickname_mood_emoji(): mood = globals.CURRENT_MOOD_NAME.lower() print(f"🔍 Mood is: {mood}") emoji = MOOD_EMOJIS.get(mood, "") nickname = f"Hatsune Miku{emoji}" for guild in globals.client.guilds: me = guild.get_member(globals.BOT_USER.id) if me is not None: try: await me.edit(nick=nickname) print(f"💱 Changed nickname to {nickname}") if mood == "asleep": await globals.client.change_presence(status=discord.Status.invisible) else: await globals.client.change_presence(status=discord.Status.online) except discord.Forbidden: print(f"⚠️ Missing permission to change nickname in guild: {guild.name}") except discord.HTTPException as e: print(f"⚠️ Failed to change nickname in {guild.name}: {e}") async def clear_angry_mood_after_delay(): await asyncio.sleep(40 * 60) # 40 minutes print("🕒 Angry mood cooldown expired. Miku is calming down to neutral.") globals.CURRENT_MOOD_NAME = "neutral" globals.CURRENT_MOOD = load_mood_description("neutral") globals.FORCED_ANGRY_UNTIL = None await nickname_mood_emoji() @tasks.loop(hours=1) async def rotate_mood(): try: print("🔁 Mood rotation task running...") if globals.FORCED_ANGRY_UNTIL: now = datetime.datetime.utcnow() if now < globals.FORCED_ANGRY_UNTIL: print("⏰ Mood rotation skipped (angry mode).") return else: globals.FORCED_ANGRY_UNTIL = None old_mood_name = globals.CURRENT_MOOD_NAME new_mood_name = old_mood_name attempts = 0 while new_mood_name == old_mood_name and attempts < 5: new_mood_name = random.choice(globals.AVAILABLE_MOODS) attempts += 1 globals.CURRENT_MOOD_NAME = new_mood_name globals.CURRENT_MOOD = load_mood_description(new_mood_name) print(f"⏰ Mood auto-rotated to: {new_mood_name}") await nickname_mood_emoji() except Exception as e: print(f"❌ Exception in rotate_mood: {e}")