refactor world regions
This commit is contained in:
@@ -35,6 +35,7 @@ from .catch import Catch
|
||||
from .nurture_weapon import NurtureWeapon
|
||||
from .switch_weapon import SwitchWeapon
|
||||
from .assassinate import Assassinate
|
||||
from .move_to_direction import MoveToDirection
|
||||
|
||||
# 注册到 ActionRegistry(标注是否为实际可执行动作)
|
||||
register_action(actual=False)(Action)
|
||||
@@ -66,6 +67,7 @@ register_action(actual=True)(Catch)
|
||||
register_action(actual=True)(NurtureWeapon)
|
||||
register_action(actual=True)(SwitchWeapon)
|
||||
register_action(actual=True)(Assassinate)
|
||||
register_action(actual=True)(MoveToDirection)
|
||||
# Talk 已移动到 mutual_action 模块,在那里注册
|
||||
|
||||
__all__ = [
|
||||
@@ -100,6 +102,7 @@ __all__ = [
|
||||
"NurtureWeapon",
|
||||
"SwitchWeapon",
|
||||
"Assassinate",
|
||||
"MoveToDirection",
|
||||
# Talk 已移动到 mutual_action 模块
|
||||
]
|
||||
|
||||
|
||||
@@ -1 +1,81 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import random
|
||||
from src.classes.action import DefineAction, ActualActionMixin, Move
|
||||
from src.classes.event import Event
|
||||
from src.classes.action_runtime import ActionResult, ActionStatus
|
||||
from src.utils.distance import manhattan_distance
|
||||
from src.classes.region import Region
|
||||
|
||||
class MoveToDirection(DefineAction, ActualActionMixin):
|
||||
"""
|
||||
向某个方向移动探索(固定时长6个月)
|
||||
"""
|
||||
|
||||
COMMENT = "向某个方向探索未知区域"
|
||||
DOABLES_REQUIREMENTS = "任何时候都可以执行"
|
||||
PARAMS = {"direction": "direction (North/South/East/West)"}
|
||||
IS_MAJOR = False
|
||||
|
||||
# 固定持续时间
|
||||
DURATION = 6
|
||||
|
||||
def __init__(self, avatar, world):
|
||||
super().__init__(avatar, world)
|
||||
# 记录本次动作的开始状态
|
||||
self.start_monthstamp = None
|
||||
self.direction = None
|
||||
|
||||
# 方向向量映射 (假设 (0,0) 在左上角)
|
||||
# North: y减小
|
||||
# South: y增加
|
||||
# West: x减小
|
||||
# East: x增加
|
||||
self.DIR_VECTORS = {
|
||||
"North": (0, -1),
|
||||
"South": (0, 1),
|
||||
"West": (-1, 0),
|
||||
"East": (1, 0),
|
||||
"北": (0, -1),
|
||||
"南": (0, 1),
|
||||
"西": (-1, 0),
|
||||
"东": (1, 0)
|
||||
}
|
||||
|
||||
def can_start(self, direction: str | None = None) -> tuple[bool, str]:
|
||||
if not direction:
|
||||
return False, "缺少方向参数"
|
||||
if direction not in self.DIR_VECTORS:
|
||||
return False, f"无效的方向: {direction}"
|
||||
return True, ""
|
||||
|
||||
def start(self, direction: str) -> Event:
|
||||
self.start_monthstamp = self.world.month_stamp
|
||||
self.direction = direction
|
||||
return Event(self.world.month_stamp, f"{self.avatar.name} 开始向{direction}方探索未知区域", related_avatars=[self.avatar.id])
|
||||
|
||||
def step(self, direction: str) -> ActionResult:
|
||||
# 确保方向已设置
|
||||
self.direction = direction
|
||||
dx_dir, dy_dir = self.DIR_VECTORS[direction]
|
||||
|
||||
# 计算本次移动步长
|
||||
step_len = getattr(self.avatar, "move_step_length", 1)
|
||||
|
||||
# 计算实际位移
|
||||
dx = dx_dir * step_len
|
||||
dy = dy_dir * step_len
|
||||
|
||||
# 执行移动
|
||||
Move(self.avatar, self.world).execute(dx, dy)
|
||||
|
||||
# 检查是否完成(固定时长)
|
||||
# 修正:(current - start) >= duration - 1,即第1个月执行后,差值为0,如果duration=1则完成
|
||||
elapsed = self.world.month_stamp - self.start_monthstamp
|
||||
is_done = elapsed >= (self.DURATION - 1)
|
||||
|
||||
return ActionResult(status=(ActionStatus.COMPLETED if is_done else ActionStatus.RUNNING), events=[])
|
||||
|
||||
async def finish(self, direction: str) -> list[Event]:
|
||||
return [Event(self.world.month_stamp, f"{self.avatar.name} 结束了向{direction}方的探索", related_avatars=[self.avatar.id])]
|
||||
|
||||
|
||||
@@ -71,7 +71,7 @@ class LLMAI(AI):
|
||||
general_action_infos = ACTION_INFOS_STR
|
||||
async def decide_one(avatar: Avatar):
|
||||
# 获取基于该角色已知区域的世界信息(包含距离计算)
|
||||
world_info = world.get_info(avatar=avatar)
|
||||
world_info = world.get_info(avatar=avatar, detailed=True)
|
||||
|
||||
# 在提示中包含处于角色观测范围内的其他角色
|
||||
observed = world.get_observable_avatars(avatar)
|
||||
|
||||
@@ -91,7 +91,6 @@ class Map():
|
||||
from src.classes.avatar import Avatar
|
||||
|
||||
from src.classes.region import NormalRegion, CultivateRegion, CityRegion
|
||||
from src.utils.distance import chebyshev_distance
|
||||
|
||||
known_region_ids = avatar.known_regions if avatar else None
|
||||
current_loc = (avatar.pos_x, avatar.pos_y) if avatar else None
|
||||
@@ -99,23 +98,14 @@ class Map():
|
||||
def filter_regions(cls):
|
||||
return {
|
||||
rid: r for rid, r in self.regions.items()
|
||||
if known_region_ids is None or rid in known_region_ids
|
||||
if isinstance(r, cls) and (known_region_ids is None or rid in known_region_ids)
|
||||
}
|
||||
|
||||
def build_regions_info(regions_dict) -> list[str]:
|
||||
infos = []
|
||||
step_len = avatar.move_step_length if avatar else 1
|
||||
for r in regions_dict.values():
|
||||
base_info = r.get_detailed_info() if detailed else r.get_info()
|
||||
|
||||
# 如果有当前位置,追加距离信息
|
||||
dist = chebyshev_distance(current_loc, r.center_loc)
|
||||
# 估算到达时间:距离 / 步长 (向上取整)
|
||||
step_len = avatar.move_step_length
|
||||
months = (dist + step_len - 1) // step_len
|
||||
# 避免显示 0 个月
|
||||
months = max(1, months)
|
||||
base_info += f"(距离:{months}月)"
|
||||
|
||||
base_info = r.get_detailed_info(current_loc, step_len) if detailed else r.get_info(current_loc, step_len)
|
||||
infos.append(base_info)
|
||||
return infos
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@ from abc import ABC, abstractmethod
|
||||
|
||||
from src.utils.df import game_configs, get_str, get_int, get_list_int
|
||||
from src.utils.config import CONFIG
|
||||
from src.utils.distance import chebyshev_distance
|
||||
from src.classes.essence import EssenceType, Essence
|
||||
from src.classes.animal import Animal, animals_by_id
|
||||
from src.classes.plant import Plant, plants_by_id
|
||||
@@ -65,11 +66,26 @@ class Region(ABC):
|
||||
f"描述: {self.desc}",
|
||||
]
|
||||
|
||||
def get_info(self) -> str:
|
||||
return self.name
|
||||
@abstractmethod
|
||||
def _get_desc(self) -> str:
|
||||
"""返回紧跟在名字后的描述,通常包含括号,例如 '(金行灵气:5)'"""
|
||||
pass
|
||||
|
||||
def get_detailed_info(self) -> str:
|
||||
return f"{self.name} - {self.desc}"
|
||||
def _get_distance_desc(self, current_loc: tuple[int, int] = None, step_len: int = 1) -> str:
|
||||
if current_loc is None:
|
||||
return ""
|
||||
dist = chebyshev_distance(current_loc, self.center_loc)
|
||||
# 估算到达时间:距离 / 步长 (向上取整)
|
||||
months = (dist + step_len - 1) // step_len
|
||||
# 避免显示 0 个月
|
||||
months = max(1, months)
|
||||
return f"(距离:{months}月)"
|
||||
|
||||
def get_info(self, current_loc: tuple[int, int] = None, step_len: int = 1) -> str:
|
||||
return f"{self.name}{self._get_distance_desc(current_loc, step_len)}"
|
||||
|
||||
def get_detailed_info(self, current_loc: tuple[int, int] = None, step_len: int = 1) -> str:
|
||||
return f"{self.name}{self._get_desc()} - {self.desc}{self._get_distance_desc(current_loc, step_len)}"
|
||||
|
||||
def get_structured_info(self) -> dict:
|
||||
return {
|
||||
@@ -108,32 +124,16 @@ class NormalRegion(Region):
|
||||
info_parts.extend([a.get_info() for a in self.animals])
|
||||
if self.plants:
|
||||
info_parts.extend([p.get_info() for p in self.plants])
|
||||
return "; ".join(info_parts) if info_parts else "暂无特色物种"
|
||||
return "; ".join(info_parts) if info_parts else "无特色物种"
|
||||
|
||||
def _get_species_brief(self) -> str:
|
||||
briefs: list[str] = []
|
||||
if self.animals:
|
||||
briefs.extend([f"{a.name}({a.realm.value})" for a in self.animals])
|
||||
if self.plants:
|
||||
briefs.extend([f"{p.name}({p.realm.value})" for p in self.plants])
|
||||
return "、".join(briefs)
|
||||
def _get_desc(self) -> str:
|
||||
species_info = self.get_species_info()
|
||||
return f"(物种分布:{species_info})"
|
||||
|
||||
def __str__(self) -> str:
|
||||
species_info = self.get_species_info()
|
||||
return f"普通区域:{self.name} - {self.desc} | 物种分布:{species_info}"
|
||||
|
||||
def get_info(self) -> str:
|
||||
brief = self._get_species_brief()
|
||||
return f"{self.name}({brief})" if brief else self.name
|
||||
|
||||
def get_detailed_info(self) -> str:
|
||||
brief = self._get_species_brief()
|
||||
name_with_brief = f"{self.name}({brief})" if brief else self.name
|
||||
species_info = self.get_species_info()
|
||||
if not species_info or species_info == "暂无特色物种":
|
||||
return f"{name_with_brief} - {self.desc}"
|
||||
return f"{name_with_brief} - {self.desc} | 物种分布:{species_info}"
|
||||
|
||||
def get_hover_info(self) -> list[str]:
|
||||
lines = super().get_hover_info()
|
||||
species_info = self.get_species_info()
|
||||
@@ -183,15 +183,12 @@ class CultivateRegion(Region):
|
||||
def get_region_type(self) -> str:
|
||||
return "cultivate"
|
||||
|
||||
def _get_desc(self) -> str:
|
||||
return f"({self.essence_type}行灵气:{self.essence_density})"
|
||||
|
||||
def __str__(self) -> str:
|
||||
return f"修炼区域:{self.name}({self.essence_type}行灵气:{self.essence_density})- {self.desc}"
|
||||
|
||||
def get_info(self) -> str:
|
||||
return f"{self.name}({self.essence_type}行灵气:{self.essence_density})"
|
||||
|
||||
def get_detailed_info(self) -> str:
|
||||
return f"{self.name}({self.essence_type}行灵气:{self.essence_density})- {self.desc}"
|
||||
|
||||
def get_hover_info(self) -> list[str]:
|
||||
lines = super().get_hover_info()
|
||||
stars = "★" * self.essence_density + "☆" * (10 - self.essence_density)
|
||||
@@ -217,12 +214,6 @@ class CityRegion(Region):
|
||||
def __str__(self) -> str:
|
||||
return f"城市区域:{self.name} - {self.desc}"
|
||||
|
||||
def get_info(self) -> str:
|
||||
return self.name
|
||||
|
||||
def get_detailed_info(self) -> str:
|
||||
return f"{self.name} - {self.desc}"
|
||||
|
||||
def get_structured_info(self) -> dict:
|
||||
info = super().get_structured_info()
|
||||
info["type_name"] = "城市区域"
|
||||
|
||||
@@ -22,4 +22,5 @@
|
||||
- 长期目标是非常重要的一个参数,其权重最高
|
||||
- 执行动作只能从给定的全部动作中选,且需满足对应条件,见动作的requirements文本
|
||||
- 一些动作需要先移动满足某些条件才可执行,可以适当规划。
|
||||
- 和另一个角色交互的动作,必须在对应角色附近。执行前可以先MoveToAvatar
|
||||
- 和另一个角色交互的动作,必须在对应角色附近。执行前可以先MoveToAvatar
|
||||
- 如果对世界了解太少,可以先通过MoveToDirection探索世界
|
||||
Reference in New Issue
Block a user