src/commands/npc_state_applier.py
Rama main · réplica de lectura del repositorio original.
"""NPC 状态更新:NPC 注册、默认战斗属性推断、数量告警。
从 state_update_applier 拆出的 NPC 字段应用逻辑。
"""
from __future__ import annotations
from src.engine.modules import game_config
import logging
from src.engine.game_instance import GameInstance
from src.engine.modules import progression_state
from src.engine import module_hooks
logger = logging.getLogger("trpg")
class NpcStateApplier:
"""将 LLM 输出的 state_update.npcs 部分应用到 NPC 状态。"""
def apply_npcs(self, instance: GameInstance, npcs_update: dict) -> None:
for npc_name, nud in npcs_update.items():
if not module_hooks.ask(module_hooks.NPC_ADMISSION, instance, npc_name, default=True):
logger.warning('Story policy rejected unadopted NPC: %s', npc_name)
continue
if npc_name in instance.npcs:
instance.npcs[npc_name].update(nud)
else:
# D10: NPC 默认战斗属性(按 tier 和难度推断,避免一击必杀)
tier = nud.get("tier", nud.get("relation", "neutral"))
diff = game_config.difficulty(instance)
base_hp = {"friendly": 15, "neutral": 20, "hostile": 30, "boss": 60}.get(tier, 20)
if diff == "硬核":
base_hp = int(base_hp * 1.3)
elif diff == "轻松":
base_hp = int(base_hp * 0.7)
base_armor = {"friendly": 0, "neutral": 1, "hostile": 2, "boss": 5}.get(tier, 1)
instance.npcs[npc_name] = {
"name": npc_name,
"character_name": npc_name,
"first_seen_round": progression_state.round_value(instance),
"hp": base_hp,
"max_hp": base_hp,
"armor": base_armor,
}
instance.npcs[npc_name].update(nud)
logger.info("新 NPC 已注册: %s (hp=%d armor=%d)", npc_name, base_hp, base_armor)
if len(instance.npcs) >= 500:
logger.warning(
"NPC 数量已达 %d,建议 DM 手动清理不再需要的 NPC 数据,"
"或使用 WebUI 角色管理页面删除无用 NPC",
len(instance.npcs),
)