add wanhunfan

This commit is contained in:
bridge
2025-10-19 01:54:05 +08:00
parent a002d1bd70
commit 840046080c
7 changed files with 99 additions and 76 deletions

View File

@@ -3,18 +3,18 @@ from __future__ import annotations
from src.classes.action import TimedAction
from src.classes.event import Event
from src.classes.region import CityRegion
from src.classes.alignment import Alignment
from src.classes.technique import TechniqueAttribute
from src.classes.event import Event
import random
class DevourMortals(TimedAction):
"""
吞噬凡人:仅邪阵营可在城市区域执行,获得大量修炼经验
吞噬凡人:在城市区域执行,需持有万魂幡,吞噬魂魄可增加战力
与普通修炼相比,经验获取显著更高。
"""
COMMENT = "在城镇吞噬凡人,获得大量修行经验(邪功法)"
DOABLES_REQUIREMENTS = "仅限城市区域,且当前功法为‘邪’,且未处于瓶颈"
DOABLES_REQUIREMENTS = "仅限城市区域;持有万魂幡"
PARAMS = {}
duration_months = 2
@@ -24,18 +24,22 @@ class DevourMortals(TimedAction):
region = self.avatar.tile.region
if not isinstance(region, CityRegion):
return
if self.avatar.cultivation_progress.is_in_bottleneck():
return
self.avatar.cultivation_progress.add_exp(self.EXP_GAIN)
# 若持有万魂幡累积吞噬魂魄10~100上限10000
tr = getattr(self.avatar, "treasure", None)
if tr is not None and tr.name == "万魂幡":
gain = random.randint(10, 100)
tr.devoured_souls = min(10000, int(tr.devoured_souls) + gain)
def can_start(self) -> bool:
region = self.avatar.tile.region
if not isinstance(region, CityRegion):
return False
tech = self.avatar.technique
if tech.attribute != TechniqueAttribute.EVIL:
# 需持有万魂幡且行为被允许
tr = getattr(self.avatar, "treasure", None)
if tr is None or tr.name != "万魂幡":
return False
return not self.avatar.cultivation_progress.is_in_bottleneck()
legal = self.avatar.effects.get("legal_actions", [])
return "DevourMortals" in legal
def start(self) -> Event:
return Event(self.world.month_stamp, f"{self.avatar.name} 在城镇开始吞噬凡人")

View File

@@ -133,7 +133,7 @@ class Avatar:
def effects(self) -> dict[str, object]:
merged: dict[str, object] = defaultdict(str)
# 来自宗门
if self.sect is not None and getattr(self.sect, "effects", None):
if self.sect is not None:
merged = _merge_effects(merged, self.sect.effects)
# 来自功法
merged = _merge_effects(merged, self.technique.effects)
@@ -142,7 +142,17 @@ class Avatar:
# 来自法宝
if self.treasure is not None:
merged = _merge_effects(merged, self.treasure.effects)
return merged
# 评估动态效果表达式:值以 "eval(...)" 形式给出
evaluated: dict[str, object] = {}
for k, v in merged.items():
if isinstance(v, str):
s = v.strip()
if s.startswith("eval(") and s.endswith(")"):
expr = s[5:-1]
evaluated[k] = eval(expr, {"__builtins__": {}}, {"avatar": self})
continue
evaluated[k] = v
return evaluated
def __hash__(self) -> int:
@@ -157,6 +167,7 @@ class Avatar:
magic_stone_info = str(self.magic_stone)
if detailed:
treasure_info = self.treasure.get_detailed_info() if self.treasure is not None else ""
sect_info = self.sect.get_detailed_info() if self.sect is not None else "散修"
alignment_info = self.alignment.get_detailed_info() if self.alignment is not None else "未知"
region_info = region.get_detailed_info() if region is not None else ""
@@ -167,6 +178,7 @@ class Avatar:
items_info = "".join([f"{item.get_detailed_info()}x{quantity}" for item, quantity in self.items.items()]) if self.items else ""
appearance_info = self.appearance.get_detailed_info(self.gender)
else:
treasure_info = self.treasure.get_info() if self.treasure is not None else ""
# personas和sect一致返回detailed因为这俩太重要了
sect_info = self.sect.get_detailed_info() if self.sect is not None else "散修"
region_info = region.get_info() if region is not None else ""
@@ -178,12 +190,6 @@ class Avatar:
items_info = "".join([f"{item.get_info()}x{quantity}" for item, quantity in self.items.items()]) if self.items else ""
appearance_info = self.appearance.get_info()
# 法宝信息detailed 使用 get_detailed_info简略使用 get_info
if self.treasure is not None:
treasures_info = self.treasure.get_detailed_info() if detailed else self.treasure.get_info()
else:
treasures_info = ""
return {
"id": self.id,
"名字": self.name,
@@ -202,7 +208,7 @@ class Avatar:
"个性": personas_info,
"物品": items_info,
"外貌": appearance_info,
"法宝": treasures_info,
"法宝": treasure_info,
}
def __str__(self) -> str:
@@ -485,55 +491,70 @@ class Avatar:
"""
返回用于前端悬浮提示的多行信息。
"""
lines: list[str] = [
f"{self.name}",
f"性别: {self.gender}",
f"年龄: {self.age}",
f"外貌: {self.appearance.get_info()}",
f"阵营: {self.alignment}",
f"境界: {str(self.cultivation_progress)}",
f"HP: {self.hp}",
f"MP: {self.mp}",
f"战斗力: {int(get_base_strength(self))}",
]
lines.append(f"宗门: {self.get_sect_str()}")
from src.classes.root import format_root_cn
lines.append(f"灵根: {format_root_cn(self.root)}")
if self.technique is not None:
lines.append(f"功法: {self.technique.name}{self.technique.attribute}·{self.technique.grade.value}")
else:
lines.append("功法: 无")
if self.personas:
lines.append(f"个性: {', '.join([persona.name for persona in self.personas])}")
lines.append(f"位置: ({self.pos_x}, {self.pos_y})")
lines.append(f"灵石: {str(self.magic_stone)}")
if self.items:
lines.append("物品:")
for item, quantity in self.items.items():
lines.append(f" {item.name} x{quantity}")
else:
lines.append("")
lines.append("物品: 无")
if self.thinking:
lines.append("")
lines.append("思考:")
from src.utils.text_wrap import wrap_text
lines.extend(wrap_text(self.thinking, 28))
if getattr(self, "objective", None):
lines.append("")
lines.append("目标:")
from src.utils.text_wrap import wrap_text
lines.extend(wrap_text(self.objective, 28))
def add_kv(lines: list[str], key: str, value: object) -> None:
lines.append(f"{key}: {value}")
# 关系信息
lines.append("")
def add_section(lines: list[str], title: str, body: list[str]) -> None:
lines.append("")
lines.append(f"{title}:")
lines.extend(body)
lines: list[str] = []
# 基础信息
lines.append(f"{self.name}")
add_kv(lines, "性别", self.gender)
add_kv(lines, "年龄", self.age)
add_kv(lines, "外貌", self.appearance.get_info())
add_kv(lines, "阵营", self.alignment)
add_kv(lines, "境界", str(self.cultivation_progress))
add_kv(lines, "HP", self.hp)
add_kv(lines, "MP", self.mp)
add_kv(lines, "战斗力", int(get_base_strength(self)))
add_kv(lines, "宗门", self.get_sect_str())
from src.classes.root import format_root_cn
add_kv(lines, "灵根", format_root_cn(self.root))
if self.technique is not None:
tech_str = f"{self.technique.name}{self.technique.attribute}·{self.technique.grade.value}"
else:
tech_str = ""
add_kv(lines, "功法", tech_str)
if self.personas:
add_kv(lines, "个性", ", ".join([p.name for p in self.personas]))
add_kv(lines, "位置", f"({self.pos_x}, {self.pos_y})")
add_kv(lines, "灵石", str(self.magic_stone))
# 物品
if self.items:
items_lines = [f" {item.name} x{quantity}" for item, quantity in self.items.items()]
add_section(lines, "物品", items_lines)
else:
add_kv(lines, "物品", "")
# 思考与目标
if self.thinking:
from src.utils.text_wrap import wrap_text
add_section(lines, "思考", wrap_text(self.thinking, 28))
if getattr(self, "objective", None):
from src.utils.text_wrap import wrap_text
add_section(lines, "目标", wrap_text(self.objective, 28))
# 法宝(仅名字)
if self.treasure is not None:
add_section(lines, "法宝", [self.treasure.get_info()])
else:
add_kv(lines, "法宝", "")
# 关系
relations_list = [f"{other.name}({str(relation)})" for other, relation in getattr(self, "relations", {}).items()]
if relations_list:
lines.append("关系:")
for s in relations_list[:6]:
lines.append(f" {s}")
add_section(lines, "关系", [f" {s}" for s in relations_list[:6]])
else:
lines.append("关系: ")
add_kv(lines, "关系", "")
return lines
def get_sect_str(self) -> str:

View File

@@ -45,7 +45,6 @@ class Sect:
# 影响角色或系统的效果
effects: dict[str, object] = field(default_factory=dict)
# 功法在technique.csv中配置
# TODO法宝
# TODO宗内等级和称谓
def get_info(self) -> str:

View File

@@ -22,13 +22,16 @@ class Treasure:
desc: str
effects: dict[str, object] = field(default_factory=dict)
sect: Optional[Sect] = None
# 万魂幡专用吞噬魂魄计数0~10000
devoured_souls: int = 0
def get_info(self) -> str:
return self.name
suffix = f"(吞噬魂魄:{self.devoured_souls}" if self.name == "万魂幡" and self.devoured_souls > 0 else ""
return f"{self.name}{suffix}"
def get_detailed_info(self) -> str:
sect_name = self.sect.name if self.sect is not None else "散修可用"
return f"{self.name}宗门:{sect_name}{self.desc}"
souls = f" 吞噬魂魄:{self.devoured_souls}" if self.name == "万魂幡" and self.devoured_souls > 0 else ""
return f"{self.name}{self.desc}{souls}"
def _load_treasures() -> tuple[Dict[int, Treasure], Dict[str, Treasure], Dict[int, Treasure]]:
@@ -71,8 +74,4 @@ def _load_treasures() -> tuple[Dict[int, Treasure], Dict[str, Treasure], Dict[in
return treasures_by_id, treasures_by_name, treasures_by_sect_id
treasures_by_id, treasures_by_name, treasures_by_sect_id = _load_treasures()
for name, treasure in treasures_by_name.items():
print(name, treasure.sect.name)
treasures_by_id, treasures_by_name, treasures_by_sect_id = _load_treasures()