Files
ai-town/engine-python/app/factions.py
empty 28976d9672 feat(engine): 实现阵营博弈机制
- FactionData 新增 threshold 和 skill 字段
- 修改能量累积逻辑:power 跨 tick 累积
- 阈值改为 10,达到后触发阵营技能
- festival 提升情绪,panic 降低情绪

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-30 12:10:28 +08:00

141 lines
4.6 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""派系系统 - 基于立场分类角色并影响世界"""
from typing import Dict, Tuple
from .models import (
WorldState, AgentState, Factions, FactionData,
FactionEventResult, WorldEffect, Emotion
)
# 派系分类阈值
OPTIMIST_THRESHOLD = 0.6
FEARFUL_THRESHOLD = 0.6
# 阵营技能触发阈值
FACTION_POWER_THRESHOLD = 10
# 阵营事件对情绪的影响
FACTION_EVENT_EFFECTS = {
"festival": 0.2, # 乐观派事件提升情绪
"panic": -0.3, # 恐惧派事件降低情绪
}
def classify_faction(agent: AgentState) -> str:
"""根据 emotion 分类角色所属派系
规则:
- emotion 偏正 (happy) → optimists
- emotion 偏负 (anxious) → fearful
- 其它 (calm) → neutral
"""
if agent.emotion == Emotion.HAPPY:
return "optimists"
elif agent.emotion == Emotion.ANXIOUS:
return "fearful"
else:
return "neutral"
def update_factions(state: WorldState) -> None:
"""统计各派系并更新 world_state
流程:
1. 清空 factions.members但保留 power
2. 遍历所有 agents根据 emotion 分类
3. 更新 agent.faction 字段
4. 将 agent 加入对应 faction.members
5. 每个 agent 为 faction 增加 power += 1累积
"""
# 保留现有 power只清空 members
current_optimist_power = state.factions.optimists.power
current_fearful_power = state.factions.fearful.power
state.factions.optimists.members = []
state.factions.fearful.members = []
for agent_id, agent in state.agents.items():
faction = classify_faction(agent)
agent.faction = faction
if faction == "optimists":
state.factions.optimists.members.append(agent_id)
state.factions.optimists.power = current_optimist_power + 1
current_optimist_power = state.factions.optimists.power
elif faction == "fearful":
state.factions.fearful.members.append(agent_id)
state.factions.fearful.power = current_fearful_power + 1
current_fearful_power = state.factions.fearful.power
def apply_faction_influence(state: WorldState) -> None:
"""派系分布影响世界情绪(保留原有逻辑)"""
optimists = state.factions.optimists.power
fearful = state.factions.fearful.power
if optimists > fearful:
state.town_mood = min(10, state.town_mood + 1)
elif fearful > optimists:
state.town_mood = max(-10, state.town_mood - 1)
def check_and_trigger_faction_event(state: WorldState) -> FactionEventResult:
"""检查并触发阵营事件
规则:
- 当 faction.power >= faction.threshold 时,触发对应技能
- optimists → festival提升情绪
- fearful → panic降低情绪
- 触发后该 faction.power 归零
"""
result = FactionEventResult(type=None, source_faction=None)
# 检查乐观派
if state.factions.optimists.power >= state.factions.optimists.threshold:
result = FactionEventResult(type="festival", source_faction="optimists")
_apply_faction_event(state, "festival")
state.factions.optimists.power = 0
# 检查恐惧派
elif state.factions.fearful.power >= state.factions.fearful.threshold:
result = FactionEventResult(type="panic", source_faction="fearful")
_apply_faction_event(state, "panic")
state.factions.fearful.power = 0
return result
def _apply_faction_event(state: WorldState, event_type: str) -> None:
"""应用阵营事件效果
1. 创建 WorldEffect 写入 world_state.world_effects
2. 影响所有 agent 的 emotion
"""
# 创建持续影响效果
if event_type == "festival":
effect = WorldEffect(
type="faction_event",
name="节日庆典",
intensity=1,
remaining_ticks=3,
mood_modifier=1
)
else: # panic
effect = WorldEffect(
type="faction_event",
name="恐慌蔓延",
intensity=1,
remaining_ticks=3,
mood_modifier=-1
)
state.world_effects.append(effect)
# 影响所有 agent 的 stance间接影响下一轮 emotion
emotion_delta = FACTION_EVENT_EFFECTS.get(event_type, 0)
for agent in state.agents.values():
if emotion_delta > 0:
agent.stance.optimism = min(1.0, agent.stance.optimism + emotion_delta)
agent.stance.fear = max(0.0, agent.stance.fear - emotion_delta * 0.5)
else:
agent.stance.fear = min(1.0, agent.stance.fear + abs(emotion_delta))
agent.stance.optimism = max(0.0, agent.stance.optimism - abs(emotion_delta) * 0.5)