+
+ # --- NEW: THE ASTERISK SCRUBBER ---
+ if not ALLOW_TEXT_EMOTES:
+ # This deletes anything wrapped in asterisks (e.g. "*smiles* Hello" becomes " Hello")
+ message = re.sub(r'\*.*?\*', '', message).strip()
+
+ # Extract the dynamic variables sent from the Aurora Toolset/Engine
+ player_race = data.get('player_race', 'Unknown')
+ player_alignment = data.get('player_alignment', 'Unknown')
+ nearby_players = data.get('nearby_players', '')
+
+ # Extract the decoupled NPC attributes
+ npc_persona = data.get('persona', 'You are a generic citizen.')
+ npc_profession = data.get('profession', 'Commoner')
+ npc_mood = data.get('mood', 'Neutral')
+ npc_secret = data.get('secret', '')
+
+ # Extract Character Traits & Native Engine Data
+ npc_alignment = data.get('npc_alignment', 'True Neutral')
+ npc_gender = data.get('npc_gender', 'Unknown')
+ npc_race = data.get('npc_race', 'Creature')
+ npc_routine = data.get('npc_routine', '')
+
+ # Build the context strings
+ group_context = ""
+ if nearby_players:
+ group_context = f"Be aware that these other players are listening nearby: {nearby_players}."
+
+ secret_context = ""
+ if npc_secret:
+ secret_context = f"YOUR SECRET (Reveal only if players are persuasive): {npc_secret}"
+
+ routine_context = ""
+ if npc_routine:
+ routine_context = f"YOUR REQUIRED ROUTINE: {npc_routine}"
+
+ # =====================================================================
+ # THE PROMPT COMPILER
+ # =====================================================================
+ dynamic_system_prompt = f"""
+
+ {WORLD_LORE}
+
+ {npc_persona}
+
+ CURRENT STATUS & TRAITS:
+ - Race & Gender: {npc_gender} {npc_race}
+ - Profession: {npc_profession}
+ - Alignment: {npc_alignment}
+ - Conversational Charisma: Low/Gruff unless otherwise specified.
+ - Current Mood: {npc_mood}
+ {secret_context}
+
+ {routine_context}
+
+ CURRENT TARGET: You are speaking to {player_name}, who is a {player_alignment} {player_race}.
+ {group_context}
+ React appropriately based on your personality, alignment, and mood.
+
+ CRITICAL ENGINE RULES:
+ Respond ONLY in valid JSON. You MUST use exactly these FIVE keys: "thought", "speech", "emotion", "action", and "action_target".
+
+ ACTION RULE:
+ Your "action" key MUST be exactly one of the following words:
+ [WANDER, PATROL, FOLLOW, GUARD, GO_TO, INTERACT, USE_OBJECT, RETURN_TO_POST, ATTACK, REST, STEALTH, SEARCH, UNSTEALTH]
+
+ - Use REST if you are severely injured, out of spells, or exhausted. This will heal you.
+ - Use STEALTH if you need to hide from enemies, sneak past someone, or if you are a rogue preparing an ambush.
+ - Use SEARCH if you suspect traps, are looking for clues, or are trying to find hidden enemies.
+ - Use UNSTEALTH to return to normal walking/visibility.
+
+ EMOTION RULE:
+ Your "emotion" key MUST be exactly one of the following words:
+ [NEUTRAL, LAUGHING, ANGRY, PLEADING, BOW, TAUNT, CHEER]. Do not invent new emotions. Do not perform writen emotions in text with **.
+
+ YOUR RESPONSE MUST BE A SINGLE, VALID JSON OBJECT. YOU MUST USE THIS EXACT TEMPLATE:
+ {{
+ "thought": "Your internal reasoning here.",
+ "speech": "You MUST say something out loud. If you don't want to talk, output something your character would do.",
+ "emotion": "MACRO WORD",
+ "action": "MACRO WORD",
+ "action_target": "Target name"
+ }}
+ """