Fix: fight vs flee (bravery), goal cooldowns, stop AI lying
Combat: - Brain now decides fight vs flee based on bravery trait - Bravery > 30 + health > 8 + mob within 6 blocks = FIGHT - Otherwise flee. Combat tasks are non-interruptible. Goals: - 30-second cooldown after completing a goal before it can respawn - Prevents "check out something interesting" loop AI Prompt: - STRICT rules against inventing items/builds/contraptions - "You have NOTHING unless told otherwise" - Must use ONLY the context provided for current activity Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
48d968a9d7
commit
5a42c2b881
3 changed files with 37 additions and 8 deletions
|
|
@ -123,9 +123,12 @@ def build_system_prompt(
|
||||||
custom,
|
custom,
|
||||||
context_line,
|
context_line,
|
||||||
"",
|
"",
|
||||||
"Rules: Reply in ONE short sentence. Under 15 words. Talk like a normal person.",
|
"STRICT RULES:",
|
||||||
"If asked what you are doing, answer based on your current activity above.",
|
"- ONE short sentence. Under 15 words.",
|
||||||
"Plain text only. Do not start with your name.",
|
"- NEVER invent things you have or did. You have NOTHING unless told otherwise.",
|
||||||
|
"- NEVER mention items, builds, or contraptions unless the context says you have them.",
|
||||||
|
"- If asked what you are doing, use ONLY the 'Right now' context above. If no context, say not much.",
|
||||||
|
"- Plain text only. No name prefix.",
|
||||||
]
|
]
|
||||||
|
|
||||||
return "\n".join(p for p in parts if p)
|
return "\n".join(p for p in parts if p)
|
||||||
|
|
|
||||||
|
|
@ -214,6 +214,7 @@ class GoalManager:
|
||||||
self._age = age
|
self._age = age
|
||||||
self._goals: list[dict] = []
|
self._goals: list[dict] = []
|
||||||
self._completed_goals: list[str] = [] # names of recently completed goals
|
self._completed_goals: list[str] = [] # names of recently completed goals
|
||||||
|
self._goal_cooldowns: dict[str, float] = {} # name → last completion time
|
||||||
self._max_goals = 5 # Don't pile up too many goals
|
self._max_goals = 5 # Don't pile up too many goals
|
||||||
|
|
||||||
def has_any_goals(self) -> bool:
|
def has_any_goals(self) -> bool:
|
||||||
|
|
@ -227,6 +228,10 @@ class GoalManager:
|
||||||
"""Add a goal from templates."""
|
"""Add a goal from templates."""
|
||||||
if self.has_goal(name):
|
if self.has_goal(name):
|
||||||
return
|
return
|
||||||
|
# Cooldown: don't re-add same goal within 30 seconds
|
||||||
|
last_done = self._goal_cooldowns.get(name, 0)
|
||||||
|
if time.time() - last_done < 30:
|
||||||
|
return
|
||||||
if len([g for g in self._goals if g["status"] == "active"]) >= self._max_goals:
|
if len([g for g in self._goals if g["status"] == "active"]) >= self._max_goals:
|
||||||
# Remove lowest priority active goal
|
# Remove lowest priority active goal
|
||||||
active = [g for g in self._goals if g["status"] == "active"]
|
active = [g for g in self._goals if g["status"] == "active"]
|
||||||
|
|
@ -311,6 +316,7 @@ class GoalManager:
|
||||||
if g["name"] == name and g["status"] == "active":
|
if g["name"] == name and g["status"] == "active":
|
||||||
g["status"] = "complete"
|
g["status"] = "complete"
|
||||||
self._completed_goals.append(name)
|
self._completed_goals.append(name)
|
||||||
|
self._goal_cooldowns[name] = time.time()
|
||||||
if len(self._completed_goals) > 20:
|
if len(self._completed_goals) > 20:
|
||||||
self._completed_goals.pop(0)
|
self._completed_goals.pop(0)
|
||||||
log.info(f"Goal complete: {g['description']}")
|
log.info(f"Goal complete: {g['description']}")
|
||||||
|
|
|
||||||
|
|
@ -297,15 +297,35 @@ class DougBrain(QObject):
|
||||||
# ── Need-driven tasks ──
|
# ── Need-driven tasks ──
|
||||||
|
|
||||||
def _survival_task(self) -> Task | None:
|
def _survival_task(self) -> Task | None:
|
||||||
"""Handle immediate survival threats."""
|
"""Handle immediate survival threats — fight or flee based on bravery."""
|
||||||
b = self._behaviors
|
b = self._behaviors
|
||||||
|
bravery = b._traits.get("bravery", 50)
|
||||||
|
|
||||||
# Flee from nearby hostiles
|
hostile = self._nearest_hostile(10)
|
||||||
hostile = self._nearest_hostile(12)
|
|
||||||
if hostile:
|
if hostile:
|
||||||
|
dist = hostile.get("distance", 99)
|
||||||
|
|
||||||
|
# FIGHT if: brave enough AND health is ok AND mob is close
|
||||||
|
should_fight = (
|
||||||
|
bravery > 30
|
||||||
|
and b.health > 8
|
||||||
|
and dist < 6
|
||||||
|
)
|
||||||
|
|
||||||
|
if should_fight:
|
||||||
|
return Task(
|
||||||
|
name="combat",
|
||||||
|
priority=Priority.CRITICAL,
|
||||||
|
action="attack_nearest_hostile",
|
||||||
|
params={"range": 6},
|
||||||
|
description=f"Fighting {hostile.get('type', 'mob')}!",
|
||||||
|
timeout=12,
|
||||||
|
interruptible=False,
|
||||||
|
)
|
||||||
|
else:
|
||||||
return self._flee_task(hostile)
|
return self._flee_task(hostile)
|
||||||
|
|
||||||
# Critical health with no hostiles — stay still and eat if possible
|
# Critical health with no hostiles — eat if possible
|
||||||
if b.health <= 6:
|
if b.health <= 6:
|
||||||
food = self._find_food()
|
food = self._find_food()
|
||||||
if food:
|
if food:
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue