add battle to death

This commit is contained in:
bridge
2025-11-26 19:00:07 +08:00
parent 6227ebd0e8
commit 7980fc0705
3 changed files with 53 additions and 16 deletions

View File

@@ -5,6 +5,7 @@ from src.classes.event import Event
from src.classes.battle import decide_battle, get_effective_strength_pair
from src.classes.story_teller import StoryTeller
from src.classes.normalize import normalize_avatar_name
from src.classes.death import handle_death
class Battle(InstantAction):
@@ -45,7 +46,7 @@ class Battle(InstantAction):
if target is not None:
target.increase_weapon_proficiency(proficiency_gain)
self._last_result = (winner.name, loser.name, loser_damage, winner_damage)
self._last_result = (winner, loser, loser_damage, winner_damage)
def can_start(self, avatar_name: str | None = None) -> tuple[bool, str]:
if avatar_name is None:
@@ -77,21 +78,31 @@ class Battle(InstantAction):
return []
winner, loser = res[0], res[1]
loser_damage, winner_damage = res[2], res[3]
result_text = f"{winner} 战胜了 {loser}{loser} 受伤{loser_damage}点,{winner} 也受伤{winner_damage}"
# 判定是否致死
is_fatal = loser.hp <= 0
if is_fatal:
result_text = f"{winner.name} 战胜了 {loser.name},造成{loser_damage}点伤害。{loser.name} 遭受重创,当场陨落。"
else:
result_text = f"{winner.name} 战胜了 {loser.name}{loser.name} 受伤{loser_damage}点,{winner.name} 也受伤{winner_damage}"
rel_ids = [self.avatar.id]
target = self._get_target(avatar_name)
try:
t = self._get_target(avatar_name)
if t is not None:
rel_ids.append(t.id)
if target is not None:
rel_ids.append(target.id)
except Exception:
pass
result_event = Event(self.world.month_stamp, result_text, related_avatars=rel_ids, is_major=True)
# 生成战斗小故事
target = self._get_target(avatar_name)
start_text = self._start_event_content if hasattr(self, '_start_event_content') else result_event.content
# 战斗强制双人模式,允许改变关系
story = await StoryTeller.tell_story(start_text, result_event.content, self.avatar, target, prompt=self.STORY_PROMPT, allow_relation_changes=True)
story_event = Event(self.world.month_stamp, story, related_avatars=rel_ids, is_story=True)
# 如果死亡,执行死亡清理(在故事生成后,保证关系数据可用)
if is_fatal:
handle_death(self.world, loser)
return [result_event, story_event]

16
src/classes/death.py Normal file
View File

@@ -0,0 +1,16 @@
from __future__ import annotations
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from src.classes.world import World
from src.classes.avatar import Avatar
def handle_death(world: World, avatar: Avatar) -> None:
"""
处理角色死亡的统一入口。
负责将角色从世界管理器中移除,并处理相关的清理工作(如关系解除已在 remove_avatar 中实现)。
注意:本函数不负责生成死亡事件文本,调用者应在调用前生成相应的 Event。
"""
# 从管理器中移除角色remove_avatar 内部会自动清理双向关系)
world.avatar_manager.remove_avatar(avatar.id)

View File

@@ -15,6 +15,7 @@ from src.run.log import get_logger
from src.classes.fortune import try_trigger_fortune
from src.classes.celestial_phenomenon import get_random_celestial_phenomenon
from src.classes.long_term_objective import process_avatar_long_term_objective
from src.classes.death import handle_death
class Simulator:
def __init__(self, world: World):
@@ -76,21 +77,30 @@ class Simulator:
def _phase_resolve_death(self):
"""
结算战斗等导致的死亡以及寿终正寝,移除死亡角色,返回死亡事件集合。
结算死亡:
- 战斗死亡已在 Action 中结算,此处不再重复(因为已从 avatars 中移除)
- 此时剩下的 avatars 都是存活的,只需检查非战斗因素(如老死、被动掉血)
"""
events = []
death_avatar_ids = []
# 遍历时可能修改字典,使用 list() 复制
for avatar_id, avatar in list(self.world.avatar_manager.avatars.items()):
is_dead = False
reason = ""
# 优先判定重伤(可能是被动效果导致)
if avatar.hp <= 0:
death_avatar_ids.append(avatar_id)
event = Event(self.world.month_stamp, f"{avatar.name} 因重伤身亡", related_avatars=[avatar.id])
is_dead = True
reason = f"{avatar.name} 因重伤不治身亡"
# 其次判定寿元
elif avatar.death_by_old_age():
is_dead = True
reason = f"{avatar.name} 老死了,时年{avatar.age.get_age()}"
if is_dead:
event = Event(self.world.month_stamp, reason, related_avatars=[avatar.id])
events.append(event)
if avatar.death_by_old_age():
death_avatar_ids.append(avatar_id)
event = Event(self.world.month_stamp, f"{avatar.name} 老死了,时年{avatar.age.get_age()}", related_avatars=[avatar.id])
events.append(event)
if death_avatar_ids:
self.world.avatar_manager.remove_avatars(death_avatar_ids)
handle_death(self.world, avatar)
return events
def _phase_update_age_and_birth(self):