diff --git a/src/classes/action/devour_mortals.py b/src/classes/action/devour_mortals.py index 785745a..e3306d4 100644 --- a/src/classes/action/devour_mortals.py +++ b/src/classes/action/devour_mortals.py @@ -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} 在城镇开始吞噬凡人") diff --git a/src/classes/avatar.py b/src/classes/avatar.py index b7dc271..6f6599a 100644 --- a/src/classes/avatar.py +++ b/src/classes/avatar.py @@ -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: diff --git a/src/classes/sect.py b/src/classes/sect.py index aa87880..18a44c7 100644 --- a/src/classes/sect.py +++ b/src/classes/sect.py @@ -45,7 +45,6 @@ class Sect: # 影响角色或系统的效果 effects: dict[str, object] = field(default_factory=dict) # 功法:在technique.csv中配置 - # TODO:法宝 # TODO:宗内等级和称谓 def get_info(self) -> str: diff --git a/src/classes/treasure.py b/src/classes/treasure.py index 5d15776..ecfc03b 100644 --- a/src/classes/treasure.py +++ b/src/classes/treasure.py @@ -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) \ No newline at end of file +treasures_by_id, treasures_by_name, treasures_by_sect_id = _load_treasures() \ No newline at end of file diff --git a/static/config.yml b/static/config.yml index 9f7b3ca..a66c322 100644 --- a/static/config.yml +++ b/static/config.yml @@ -15,7 +15,7 @@ ai: max_decide_num: 4 game: - init_npc_num: 8 + init_npc_num: 6 sect_num: 2 # init_npc_num大于sect_num时,会随机选择sect_num个宗门 npc_birth_rate_per_month: 0.001 diff --git a/static/game_configs/sect.csv b/static/game_configs/sect.csv index 9c15c4d..ca3c84a 100644 --- a/static/game_configs/sect.csv +++ b/static/game_configs/sect.csv @@ -3,7 +3,7 @@ id,name,desc,member_act_style,alignment,sect_surnames,male_sect_given_names,fema 1,明心剑宗,通玄界东方第一宗,以无上剑道称雄于世。云纹禁制为不传心法。,清明克己,行止如一。重剑与心法并重,讲究明心见性。,正,明;心;剑;霄;玄;霁;衡;孤;徽;肃,澄川;宏石;磐岳;霆岱;寂岚;久安;宸秋;烁离;沧岳;砺锋;炎洲;远歌,采微;霏岚;韶华;绮澜;珠影;远岫;若水;凝香;雪瑶;南絮;轻萝;宛竹,1, 2,百兽宗,以驯养灵兽闻名,豢养各种妖兽灵怪为战力。,你言语直接,重视力量与血性,崇尚狩猎与搏斗。,邪,,驼王;飞熊;虎魄;狼行;熊罡;白猿;石坚;山岚;青鬃;玄爪;金瞳;裂爪;破角;狂鬃;赤鬣;苍隼;啸风;裂岩,狐绮;白貂;青翎;雪牙;赤羽;玄狸;灵爪;月狐;银鳞;霜蹄;云貉;绒尾;锦狐;轻蹄,1, 3,水镜宗,正道十宗之一,实则严守中立。拥有仙界异宝"彻天水镜"可预知未来。,你处事冷静圆融,喜以柔克刚,擅借力与反制。,中,水;镜;寒;霜;冰;清;沐;澜;渊;泉,涟光;沧浪;泽远;浩川;泊舟;涓石;溪原;涵舟;泠曜;漪岑;淞岳;涔雨,漫霖;洛漪;潋月;涵烟;沁波;翠波;漫葭;汀兰;潭歌;涓玥;澧宁;潇然,1, -4,冥王宗,行走幽冥之道,术法阴冷狠厉。,你言辞冷厉少情,敬畏因果而不惧杀伐,偏向效率与结果。,邪,冥;王;玄;幽;夜;白;冷;狱;魇;阴,血燎;焚魄;灰燼;殁川;绝尘;厌离;朔寒;邪风;归墟;朽骨;朔月;止戈,寒绫;霜瑶;凄歌;素鸢;祭宁;黛魂;夙梦;绫雪;凛珑;霁月;旷音;凝岚,1, +4,冥王宗,行走幽冥之道,术法阴冷狠厉。,你言辞冷厉少情,敬畏因果而不惧杀伐,偏向效率与结果。,邪,冥;王;玄;幽;夜;白;冷;狱;魇;阴,血燎;焚魄;灰燼;殁川;绝尘;厌离;朔寒;邪风;归墟;朽骨;朔月;止戈,寒绫;霜瑶;凄歌;素鸢;祭宁;黛魂;夙梦;绫雪;凛珑;霁月;旷音;凝岚,1000, 5,朱勾宗,邪宗大派。以炼器、机关、暗杀闻名于世,素来阴毒冷僻。,你直面欲望与代价,不惧黑暗,以攻伐见长。,邪,朱;绯;刃;戮;蚀;渊;钧;鸦;墨;殷,暗阑;机括;鬼匣;夜禁;幻锁;残锋;暗弦;影栅;幽钩;断线;潜匿;迷踪,玄簪;霜绡;纤罗;碎玉;影裳;轻弦;凝黛;凝烟;冷珥;素纱;凛钗;寒袖,1, 6,合欢宗,以情入道,靠双修增进修为,善驭人心,长于权变。,你辞令婉转,善于拿捏人欲与局势,以柔制刚。,中,合;欢;苏;陆;柳;花;月;楚;顾;白,流烟;迟夜;长陌;归舟;暮成;远辞;行止;轻寒;沉香;野鹤;乘风,婉心;轻柔;疏影;如梦;绮念;惜香;慕雪;倾城;绯烟;晚晴;素袖;霁眉;绸缪;静妍,1000,'legal_actions': ['DualCultivation'] 7,镇魂宗,铁血风格,擅安魂、封邪、渡厄,兼有刚烈镇压之术。,你肃穆沉稳,重安魂镇邪,少言而果决。,正,厉;卢;镇;魂;钟;青;凌;白;楚;顾,安魄;靖川;霁阳;季衡;砺甲;烁锋;昊戈;祁光;漠石;启封;殷策;定魄,清宁;素铃;靖霜;澄心;霁雪;安祈;净月;宁枝;祷绫;明槐;采霁;定寒,1, diff --git a/static/game_configs/treasure.csv b/static/game_configs/treasure.csv index 18d8ae7..81a9478 100644 --- a/static/game_configs/treasure.csv +++ b/static/game_configs/treasure.csv @@ -5,7 +5,7 @@ id,name,sect_id,desc,effects 3,千里镜,3,澄澈如镜,观千里之外,洞察先机.,"extra_observation_radius": 2 4,镇魂钟,7,钟鸣摄魄,定魂镇邪,护心安魂.,"extra_battle_strength_points": 3; "extra_observation_radius": 1 5,聚灵阵盘,5,刻阵成盘,聚纳灵机,修行事半功倍.,"extra_cultivate_exp": 50 -6,万魂幡,4,幡起万魂啾啾,阴风过境。(效果留空,后续配置), +6,万魂幡,4,幡起万魂啾啾,阴风过境.,"legal_actions": ["DevourMortals"]; "extra_battle_strength_points": eval(avatar.treasure.devoured_souls // 100 * 0.1) 7,万欲同心结,6,情意同心,双修之道相互映照,修为更精进.,"extra_dual_cultivation_exp": 100 8,影遁披风,8,融身影界,来去无踪,伏击出其不意.,"extra_move_step": 1; "extra_observation_radius": 1