Fix craft parsing, sustained combat, combat cooldown
- Craft regex now captures only 1-2 words (not entire sentence) - Mine regex same fix - Combat is now sustained: bridge keeps attacking every 500ms until target dies, leaves range, or 10s timeout - Combat has 12-second cooldown to prevent spam - Bot chases target if too far for melee during combat Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
3832094a5c
commit
9c7ae89dd2
3 changed files with 56 additions and 8 deletions
|
|
@ -583,8 +583,50 @@ async function handleAction(action, params = {}) {
|
||||||
if (hostiles.length === 0) return { attacked: false, reason: 'no_hostiles' };
|
if (hostiles.length === 0) return { attacked: false, reason: 'no_hostiles' };
|
||||||
hostiles.sort((a, b) => a.dist - b.dist);
|
hostiles.sort((a, b) => a.dist - b.dist);
|
||||||
const target = hostiles[0].entity;
|
const target = hostiles[0].entity;
|
||||||
bot.attack(target);
|
|
||||||
return { attacked: true, target: target.name || target.type, distance: hostiles[0].dist };
|
// Sustained combat: keep attacking until target is dead or out of range
|
||||||
|
let hits = 0;
|
||||||
|
const maxHits = 20;
|
||||||
|
const combatPromise = new Promise((resolve) => {
|
||||||
|
const attackInterval = setInterval(() => {
|
||||||
|
// Check if target is still alive and in range
|
||||||
|
const ent = bot.entities[target.id];
|
||||||
|
if (!ent || !ent.position) {
|
||||||
|
clearInterval(attackInterval);
|
||||||
|
resolve({ attacked: true, hits, result: 'target_gone' });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const d = ent.position.distanceTo(bot.entity.position);
|
||||||
|
if (d > range + 2) {
|
||||||
|
clearInterval(attackInterval);
|
||||||
|
resolve({ attacked: true, hits, result: 'out_of_range' });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (hits >= maxHits) {
|
||||||
|
clearInterval(attackInterval);
|
||||||
|
resolve({ attacked: true, hits, result: 'max_hits' });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Look at target and attack
|
||||||
|
bot.lookAt(ent.position.offset(0, ent.height * 0.8, 0)).then(() => {
|
||||||
|
try { bot.attack(ent); hits++; } catch (e) {}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Move toward target if too far for melee
|
||||||
|
if (d > 3) {
|
||||||
|
bot.pathfinder.setGoal(new GoalNear(ent.position.x, ent.position.y, ent.position.z, 2));
|
||||||
|
}
|
||||||
|
}, 500); // Attack every 500ms
|
||||||
|
|
||||||
|
// Safety timeout
|
||||||
|
setTimeout(() => {
|
||||||
|
clearInterval(attackInterval);
|
||||||
|
resolve({ attacked: true, hits, result: 'timeout' });
|
||||||
|
}, 10000);
|
||||||
|
});
|
||||||
|
|
||||||
|
return await combatPromise;
|
||||||
}
|
}
|
||||||
|
|
||||||
// --- Crafting ---
|
// --- Crafting ---
|
||||||
|
|
|
||||||
|
|
@ -41,6 +41,7 @@ class BehaviorEngine:
|
||||||
self._last_scan_time = 0.0
|
self._last_scan_time = 0.0
|
||||||
self._last_chat_time = 0.0
|
self._last_chat_time = 0.0
|
||||||
self._last_wander_time = 0.0
|
self._last_wander_time = 0.0
|
||||||
|
self._last_combat_time = 0.0
|
||||||
self._explored_positions: list[dict] = [] # Places we've been
|
self._explored_positions: list[dict] = [] # Places we've been
|
||||||
self._known_containers: list[dict] = [] # Containers we've found
|
self._known_containers: list[dict] = [] # Containers we've found
|
||||||
self._relationships: dict[str, float] = {} # Player name → fondness (-1 to 1)
|
self._relationships: dict[str, float] = {} # Player name → fondness (-1 to 1)
|
||||||
|
|
@ -215,19 +216,24 @@ class BehaviorEngine:
|
||||||
if bravery < 30:
|
if bravery < 30:
|
||||||
return None # Too scared to fight
|
return None # Too scared to fight
|
||||||
|
|
||||||
|
# Cooldown — don't spam combat tasks
|
||||||
|
if time.time() - self._last_combat_time < 12:
|
||||||
|
return None
|
||||||
|
|
||||||
# Find attackable hostile within melee range
|
# Find attackable hostile within melee range
|
||||||
for hostile in self.nearby_hostiles:
|
for hostile in self.nearby_hostiles:
|
||||||
dist = hostile.get("distance", 99)
|
dist = hostile.get("distance", 99)
|
||||||
if dist < 4 and self.health > 8:
|
if dist < 5 and self.health > 8:
|
||||||
# Brave Dougs attack, others might not
|
# Brave Dougs attack, others might not
|
||||||
if bravery > 60 or (bravery > 40 and self.health > 14):
|
if bravery > 60 or (bravery > 40 and self.health > 14):
|
||||||
|
self._last_combat_time = time.time()
|
||||||
return Task(
|
return Task(
|
||||||
name=f"attack_{hostile['type']}",
|
name="combat",
|
||||||
priority=Priority.HIGH,
|
priority=Priority.HIGH,
|
||||||
action="attack_nearest_hostile",
|
action="attack_nearest_hostile",
|
||||||
params={"range": 5},
|
params={"range": 6},
|
||||||
description=f"Fighting a {hostile['type']}!",
|
description=f"Fighting a {hostile['type']}!",
|
||||||
timeout=10,
|
timeout=15,
|
||||||
)
|
)
|
||||||
|
|
||||||
return None
|
return None
|
||||||
|
|
|
||||||
|
|
@ -57,11 +57,11 @@ class CommandParser:
|
||||||
]
|
]
|
||||||
|
|
||||||
CRAFT_PATTERNS = [
|
CRAFT_PATTERNS = [
|
||||||
r"(?:craft|make|build|create)\s+(?:a\s+|an\s+|some\s+)?(.+)",
|
r"(?:craft|make|build|create)\s+(?:a\s+|an\s+|some\s+|me\s+)?(\w+(?:\s+\w+)?)",
|
||||||
]
|
]
|
||||||
|
|
||||||
MINE_PATTERNS = [
|
MINE_PATTERNS = [
|
||||||
r"(?:mine|dig|break|destroy)\s+(?:that|this|the)?\s*(.+)",
|
r"(?:mine|dig|break|destroy)\s+(?:that|this|the|some)?\s*(\w+(?:\s+\w+)?)",
|
||||||
]
|
]
|
||||||
|
|
||||||
GIVE_PATTERNS = [
|
GIVE_PATTERNS = [
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue