add alignment

This commit is contained in:
bridge
2025-10-02 21:24:50 +08:00
parent f4ef5a00de
commit 939b1102eb
10 changed files with 167 additions and 9 deletions

View File

@@ -6,6 +6,7 @@ import random
from src.classes.root import Root, get_essence_types_for_root, extra_breakthrough_success_rate
from src.classes.region import Region, CultivateRegion, NormalRegion, CityRegion
from src.classes.alignment import Alignment
from src.classes.event import Event, NULL_EVENT
from src.classes.item import Item, items_by_name
from src.classes.prices import prices
@@ -689,3 +690,77 @@ class Battle(DefineAction, ActualActionMixin):
winner, loser = res
return [Event(self.world.month_stamp, f"{winner} 战胜了 {loser}")]
return []
@long_action(step_month=3)
class PlunderMortals(DefineAction, ActualActionMixin):
"""
在城镇对凡人进行搜刮,获取少量灵石。
仅邪阵营可执行。
"""
COMMENT = "在城镇搜刮凡人,获取少量灵石"
DOABLES_REQUIREMENTS = "仅限城市区域,且角色阵营为‘邪’"
PARAMS = {}
GAIN = 20
def _execute(self) -> None:
region = self.avatar.tile.region
if not isinstance(region, CityRegion):
return
gain = self.GAIN
self.avatar.magic_stone = self.avatar.magic_stone + gain
def can_start(self) -> bool:
region = self.avatar.tile.region
if not isinstance(region, CityRegion):
return False
return self.avatar.alignment == Alignment.EVIL
def start(self) -> Event:
return Event(self.world.month_stamp, f"{self.avatar.name} 在城镇开始搜刮凡人")
def step(self) -> tuple[StepStatus, list[Event]]:
self.execute()
return (StepStatus.COMPLETED if getattr(self, "is_finished")() else StepStatus.RUNNING), []
def finish(self) -> list[Event]:
return []
@long_action(step_month=3)
class HelpMortals(DefineAction, ActualActionMixin):
"""
在城镇帮助凡人,消耗少量灵石。
仅正阵营可执行。
"""
COMMENT = "在城镇帮助凡人,消耗少量灵石"
DOABLES_REQUIREMENTS = "仅限城市区域,且角色阵营为‘正’,并且灵石足够"
PARAMS = {}
COST = 10
def _execute(self) -> None:
region = self.avatar.tile.region
if not isinstance(region, CityRegion):
return
cost = self.COST
if getattr(self.avatar.magic_stone, "value", 0) >= cost:
self.avatar.magic_stone = self.avatar.magic_stone - cost
def can_start(self) -> bool:
region = self.avatar.tile.region
if not isinstance(region, CityRegion):
return False
if self.avatar.alignment != Alignment.RIGHTEOUS:
return False
cost = self.COST
return getattr(self.avatar.magic_stone, "value", 0) >= cost
def start(self) -> Event:
return Event(self.world.month_stamp, f"{self.avatar.name} 在城镇开始帮助凡人")
def step(self) -> tuple[StepStatus, list[Event]]:
self.execute()
return (StepStatus.COMPLETED if getattr(self, "is_finished")() else StepStatus.RUNNING), []
def finish(self) -> list[Event]:
return []

View File

@@ -13,6 +13,8 @@ from src.classes.action import (
Harvest,
Sold,
Battle,
PlunderMortals,
HelpMortals,
)
from src.classes.mutual_action import (
DriveAway,
@@ -33,6 +35,8 @@ ALL_ACTION_CLASSES = [
Hunt,
Harvest,
Sold,
PlunderMortals,
HelpMortals,
# 互动相关动作(实际执行的反馈动作也纳入)
DriveAway,
Attack,
@@ -49,6 +53,8 @@ ALL_ACTUAL_ACTION_CLASSES = [
Hunt,
Harvest,
Sold,
PlunderMortals,
HelpMortals,
DriveAway,
Attack,
]

21
src/classes/alignment.py Normal file
View File

@@ -0,0 +1,21 @@
from enum import Enum
class Alignment(Enum):
"""
阵营:正/邪。
值使用英文,便于与代码/保存兼容__str__ 返回中文。
"""
RIGHTEOUS = "righteous" # 正
EVIL = "evil" # 邪
def __str__(self) -> str:
return alignment_strs.get(self, self.value)
alignment_strs = {
Alignment.RIGHTEOUS: "",
Alignment.EVIL: "",
}

View File

@@ -25,6 +25,7 @@ from src.utils.id_generator import get_avatar_id
from src.utils.config import CONFIG
from src.classes.relation import Relation
from src.run.log import get_logger
from src.classes.alignment import Alignment
persona_num = CONFIG.avatar.persona_num
@@ -73,6 +74,7 @@ class Avatar:
hp: HP = field(default_factory=lambda: HP(0, 0)) # 将在__post_init__中初始化
mp: MP = field(default_factory=lambda: MP(0, 0)) # 将在__post_init__中初始化
relations: dict["Avatar", Relation] = field(default_factory=dict)
alignment: Alignment = field(default_factory=lambda: random.choice(list(Alignment)))
def __post_init__(self):
"""
@@ -101,7 +103,7 @@ class Avatar:
尽量多打一些因为会用来给LLM进行决策
"""
personas_str = ", ".join([persona.name for persona in self.personas])
return f"Avatar(id={self.id}, 性别={self.gender}, 年龄={self.age}, name={self.name}, 区域={self.tile.region.name}, 灵根={str(self.root)}, 境界={self.cultivation_progress}, HP={self.hp}, MP={self.mp}, 个性={personas_str})"
return f"Avatar(id={self.id}, 性别={self.gender}, 年龄={self.age}, name={self.name}, 阵营={self.alignment}, 区域={self.tile.region.name}, 灵根={str(self.root)}, 境界={self.cultivation_progress}, HP={self.hp}, MP={self.mp}, 个性={personas_str})"
def __str__(self) -> str:
return self.get_info()
@@ -437,11 +439,11 @@ class Avatar:
def get_other_avatar_info(self, other_avatar: "Avatar") -> str:
"""
仅显示个字段:名字、境界、关系。
仅显示4个字段:名字、境界、关系、阵营
"""
relation = self.get_relation(other_avatar)
relation_str = str(relation)
return f"{other_avatar.name},境界:{other_avatar.cultivation_progress.get_simple_info()},关系:{relation_str}"
return f"{other_avatar.name},境界:{other_avatar.cultivation_progress.get_simple_info()},关系:{relation_str},阵营:{other_avatar.alignment}"
@property
def move_step_length(self) -> int:

View File

@@ -25,4 +25,31 @@ class AvatarManager:
same_region.append(other)
return same_region
def remove_avatar(self, avatar_id: str) -> None:
"""
从管理器中删除一个 avatar并清理所有与其相关的双向关系。
"""
avatar = self.avatars.get(avatar_id)
if avatar is None:
return
# 先清理与其直接记录的关系(会保持对称)
related = list(getattr(avatar, "relations", {}).keys())
for other in related:
avatar.clear_relation(other)
# 再次扫一遍所有 avatar确保不存在残留引用
for other in list(self.avatars.values()):
if other is avatar:
continue
if getattr(other, "relations", None) is not None and avatar in other.relations:
other.clear_relation(avatar)
# 最后移除自身
self.avatars.pop(avatar_id, None)
def remove_avatars(self, avatar_ids: List[str]) -> None:
"""
批量删除 avatars并清理所有关系。
"""
for aid in list(avatar_ids):
self.remove_avatar(aid)