| from __future__ import annotations |
| from typing import TYPE_CHECKING |
|
|
| if TYPE_CHECKING: |
| from ..environment.environment import Environment |
|
|
|
|
| class MoveTool: |
| name = "move" |
| schema = { |
| "type": "function", |
| "function": { |
| "name": "move", |
| "description": "Move to an adjacent tile. Auto-loots any items on the destination tile.", |
| "parameters": { |
| "type": "object", |
| "properties": { |
| "dx": {"type": "integer", "description": "Change in x (-1, 0, or 1)"}, |
| "dy": {"type": "integer", "description": "Change in y (-1, 0, or 1)"}, |
| }, |
| "required": ["dx", "dy"], |
| }, |
| }, |
| } |
|
|
| @staticmethod |
| def run(env: Environment, aid: str, args: dict) -> str: |
| agent = env.agents[aid] |
| x, y = agent.pos |
| dx, dy = args.get("dx", 0), args.get("dy", 0) |
|
|
| if abs(dx) > 1 or abs(dy) > 1: |
| return "Invalid move: can only move to adjacent tiles (±1 in x or y)" |
|
|
| nx, ny = x + dx, y + dy |
|
|
| if not env.is_in_bounds(nx, ny): |
| return "Invalid move: out of bounds" |
|
|
| if not env.is_empty(nx, ny): |
| return "Invalid move: tile is occupied" |
|
|
| agent.pos = [nx, ny] |
| tile = env.get_tile(nx, ny) |
|
|
| loot_results = [] |
| if tile.loot: |
| for item in tile.loot: |
| if item.type == "ability": |
| from ..agent.state import AbilityInstance |
| from ..environment.ability_registry import ABILITY_REGISTRY |
| ab_def = ABILITY_REGISTRY.get(item.ability_name) |
| max_uses = ab_def.max_uses if ab_def else None |
| agent.abilities.append( |
| AbilityInstance(name=item.ability_name, uses_remaining=max_uses) |
| ) |
| desc = env.get_ability_description(item.ability_name) |
| cd = env.get_ability_cooldown(item.ability_name) |
| ab_def = ABILITY_REGISTRY.get(item.ability_name) |
| uses_str = "unlimited" if ab_def and ab_def.max_uses is None else (f"{ab_def.max_uses} use(s)" if ab_def else "?") |
| loot_results.append( |
| f"picked up ability '{item.ability_name}': {desc} " |
| f"(cooldown {cd} turn(s), {uses_str})" |
| ) |
| elif item.type == "points": |
| agent.score += item.points or 0 |
| loot_results.append(f"picked up {item.points} points") |
| tile.loot = None |
|
|
| msg = f"Moved to ({nx}, {ny})" |
| if loot_results: |
| msg += ". Loot: " + ", ".join(loot_results) |
| return msg |
|
|