add elixir

This commit is contained in:
bridge
2026-01-05 22:26:16 +08:00
parent 96c43c7cf5
commit 2a68f352bc
7 changed files with 206 additions and 2 deletions

View File

@@ -39,6 +39,7 @@ from src.classes.long_term_objective import LongTermObjective
from src.classes.nickname_data import Nickname
from src.classes.emotions import EmotionType
from src.utils.config import CONFIG
from src.classes.elixir import ConsumedElixir, Elixir
# Mixin 导入
from src.classes.effect import EffectsMixin
@@ -110,6 +111,8 @@ class Avatar(
emotion: EmotionType = EmotionType.CALM
custom_pic_id: Optional[int] = None
elixirs: List[ConsumedElixir] = field(default_factory=list)
is_dead: bool = False
death_info: Optional[dict] = None
@@ -122,6 +125,23 @@ class Avatar(
relation_interaction_states: dict[str, dict[str, int]] = field(default_factory=lambda: defaultdict(lambda: {"count": 0, "checked_times": 0}))
# ========== 宗门相关 ==========
def consume_elixir(self, elixir: Elixir) -> bool:
"""
服用丹药
:return: 是否成功服用
"""
# 1. 境界校验:只能服用境界等于或者小于当前境界的丹药
if elixir.realm > self.cultivation_progress.realm:
return False
# 2. 记录服用状态
self.elixirs.append(ConsumedElixir(elixir, int(self.world.month_stamp)))
# 3. 立即触发属性重算因为可能有立即生效的数值变化或者MaxHP/Lifespan改变
self.recalc_effects()
return True
def join_sect(self, sect: Sect, rank: "SectRank") -> None:
"""加入宗门"""

View File

@@ -60,7 +60,7 @@ class EffectsMixin:
@property
def effects(self: "Avatar") -> dict[str, object]:
"""
合并所有来源的效果:宗门、功法、灵根、特质、兵器、辅助装备、灵兽、天地灵机
合并所有来源的效果:宗门、功法、灵根、特质、兵器、辅助装备、灵兽、天地灵机、丹药
"""
merged: dict[str, object] = {}
@@ -107,6 +107,11 @@ class EffectsMixin:
if self.world.current_phenomenon is not None:
_process_source(self.world.current_phenomenon)
# 来自已服用的丹药
# 简化逻辑:直接 merge 所有丹药的效果
for consumed in self.elixirs:
_process_source(consumed.elixir)
return merged
def get_effect_breakdown(self: "Avatar") -> list[tuple[str, dict[str, Any]]]:
@@ -152,6 +157,9 @@ class EffectsMixin:
if self.world.current_phenomenon:
_collect("天地灵机", self.world.current_phenomenon)
for consumed in self.elixirs:
_collect(f"丹药【{consumed.elixir.name}", consumed.elixir)
return breakdown
def recalc_effects(self: "Avatar") -> None:

View File

@@ -0,0 +1,139 @@
from __future__ import annotations
from dataclasses import dataclass, field
from enum import Enum
from typing import Dict, List
from src.utils.df import game_configs, get_str, get_int
from src.classes.effect import load_effect_from_str, format_effects_to_text
from src.classes.cultivation import Realm
class ElixirType(Enum):
"""丹药类型"""
Breakthrough = "Breakthrough" # 破境
Lifespan = "Lifespan" # 延寿
BurnBlood = "BurnBlood" # 燃血
Heal = "Heal" # 疗伤
Unknown = "Unknown"
@dataclass
class Elixir:
"""
丹药类
字段与 static/game_configs/elixir.csv 对应
"""
id: int
name: str
realm: Realm
type: ElixirType
desc: str
price: int
effects: dict[str, object] = field(default_factory=dict)
effect_desc: str = ""
def get_info(self, detailed: bool = False) -> str:
"""获取信息"""
if detailed:
return self.get_detailed_info()
return f"{self.name}"
def get_detailed_info(self) -> str:
"""获取详细信息"""
effect_part = f" 效果:{self.effect_desc}" if self.effect_desc else ""
return f"{self.name}{self.realm.value}·{self._get_type_name()}{self.desc}{effect_part}"
def _get_type_name(self) -> str:
type_names = {
ElixirType.Breakthrough: "破境",
ElixirType.Lifespan: "延寿",
ElixirType.BurnBlood: "燃血",
ElixirType.Heal: "疗伤",
}
return type_names.get(self.type, "未知")
def get_colored_info(self) -> str:
"""获取带颜色标记的信息,供前端渲染使用"""
# 使用对应境界的颜色
r, g, b = self.realm.color_rgb
return f"<color:{r},{g},{b}>{self.get_info()}</color>"
def get_structured_info(self) -> dict:
return {
"name": self.name,
"desc": self.desc,
"grade": self.realm.value,
"type": self.type.value,
"type_name": self._get_type_name(),
"price": self.price,
"color": self.realm.color_rgb,
"effect_desc": self.effect_desc,
}
@dataclass
class ConsumedElixir:
"""
已服用的丹药记录
"""
elixir: Elixir
consume_time: int # 服用时的 MonthStamp
def _load_elixirs() -> tuple[Dict[int, Elixir], Dict[str, List[Elixir]]]:
"""
加载丹药配置
:return: (id索引字典, name索引字典(值为list))
"""
elixirs_by_id: Dict[int, Elixir] = {}
elixirs_by_name: Dict[str, List[Elixir]] = {}
if "elixir" not in game_configs:
return elixirs_by_id, elixirs_by_name
df = game_configs["elixir"]
for row in df:
elixir_id = get_int(row, "id")
name = get_str(row, "name")
desc = get_str(row, "desc")
price = get_int(row, "price")
# 解析境界
realm_str = get_str(row, "realm")
# 尝试匹配 Realm 枚举
realm = Realm.Qi_Refinement # 默认
for r in Realm:
if r.value == realm_str or r.name == realm_str:
realm = r
break
# 解析类型
elixir_type = ElixirType(get_str(row, "type"))
# 解析 effects
effects = load_effect_from_str(get_str(row, "effects"))
effect_desc = format_effects_to_text(effects)
elixir = Elixir(
id=elixir_id,
name=name,
realm=realm,
type=elixir_type,
desc=desc,
price=price,
effects=effects,
effect_desc=effect_desc
)
elixirs_by_id[elixir_id] = elixir
if name not in elixirs_by_name:
elixirs_by_name[name] = []
elixirs_by_name[name].append(elixir)
return elixirs_by_id, elixirs_by_name
# 导出全局变量
elixirs_by_id, elixirs_by_name = _load_elixirs()

View File

@@ -52,6 +52,7 @@ class AvatarLoadMixin:
from src.classes.appearance import get_appearance_by_level
from src.classes.magic_stone import MagicStone
from src.classes.action_runtime import ActionPlan
from src.classes.elixir import elixirs_by_id, ConsumedElixir
# 重建基本对象
gender = Gender(data["gender"])
@@ -212,6 +213,16 @@ class AvatarLoadMixin:
# relations需要在外部单独重建因为需要所有avatar都加载完成
avatar.relations = {}
# 恢复丹药记录
elixir_list_data = data.get("elixirs", [])
avatar.elixirs = []
for elixir_data in elixir_list_data:
elixir_id = elixir_data["id"]
if elixir_id in elixirs_by_id:
elixir_obj = elixirs_by_id[elixir_id]
consume_time = elixir_data["time"]
avatar.elixirs.append(ConsumedElixir(elixir_obj, consume_time))
# 加载完成后重新计算effects确保数值正确
avatar.recalc_effects()

View File

@@ -107,5 +107,14 @@ class AvatarSaveMixin:
} if self.long_term_objective else None,
"_action_cd_last_months": self._action_cd_last_months,
"known_regions": list(self.known_regions),
# 丹药
"elixirs": [
{
"id": consumed.elixir.id,
"time": consumed.consume_time
}
for consumed in self.elixirs
],
}

View File

@@ -0,0 +1,17 @@
id,name,realm,type,desc,price,effects
,名称,境界(练气/筑基/金丹/元婴),类型(Breakthrough/Lifespan/BurnBlood/Heal),描述,价格,JSON形式Effects
1,破境丹,练气,Breakthrough,凝聚灵气辅助练气期修士突破瓶颈的丹药药效5年,50,"{duration_month: 60, extra_breakthrough_success_rate: 0.1}"
2,破境丹,筑基,Breakthrough,蕴含筑基真意辅助筑基期修士突破瓶颈的灵丹药效5年,200,"{duration_month: 60, extra_breakthrough_success_rate: 0.1}"
3,破境丹,金丹,Breakthrough,凝结金丹之气辅助金丹期修士碎丹成婴药效5年,500,"{duration_month: 60, extra_breakthrough_success_rate: 0.1}"
5,长生丹,练气,Lifespan,采用凡间珍草炼制略微延缓衰老药效50年,100,"{duration_month: 600, extra_max_lifespan: 5}"
6,长生丹,筑基,Lifespan,取天地灵草炼制可延寿十载药效50年,500,"{duration_month: 1200, extra_max_lifespan: 10}"
7,长生丹,金丹,Lifespan,夺天地造化凡人服之立毙金丹修士服之延寿半甲子药效50年,200,"{duration_month: 2400, extra_max_lifespan: 30}"
8,长生丹,元婴,Lifespan,蕴含一丝长生之气元婴老怪以此续命药效50年,5000,"{duration_month: 6000, extra_max_lifespan: 100}"
9,燃血丹,练气,BurnBlood,燃烧精血换取短暂爆发。3年内战力提升但10年内经脉受损战力下降。,50,"[{duration_month: 36, extra_battle_strength_points: 3}, {duration_month: 120, extra_battle_strength_points: -1}]"
10,燃血丹,筑基,BurnBlood,激发潜能的猛药。3年内战力大增但10年内虚弱。,100,"[{duration_month: 36, extra_battle_strength_points: 5}, {duration_month: 120, extra_battle_strength_points: -2}]"
11,燃血丹,金丹,BurnBlood,金丹修士拼命时的选择。3年内战力暴涨但10年内重伤。,200,"[{duration_month: 36, extra_battle_strength_points: 7}, {duration_month: 120, extra_battle_strength_points: -3}]"
12,燃血丹,元婴,BurnBlood,燃烧元婴本源。3年内获得毁天灭地的力量但10年内几乎废人。,300,"[{duration_month: 36, extra_battle_strength_points: 10}, {duration_month: 120, extra_battle_strength_points: -5}]"
13,回春丹,练气,Heal,普通的疗伤丹药可恢复练气期修士的伤势持续5年,20,"{duration_month: 60, extra_hp_recovery_rate: 0.5}"
14,回春丹,筑基,Heal,药力温和醇厚能快速愈合筑基期修士的肉身损伤持续5年,50,"{duration_month: 60, extra_hp_recovery_rate: 1.0}"
15,回春丹,金丹,Heal,蕴含生机之力疗伤圣药持续5年,100,"{duration_month: 60, extra_hp_recovery_rate: 2.0}"
16,回春丹,元婴,Heal,蕴含造化生机肉身修复极快持续5年,200,"{duration_month: 60, extra_hp_recovery_rate: 5.0}"
1 id name realm type desc price effects
2 名称 境界(练气/筑基/金丹/元婴) 类型(Breakthrough/Lifespan/BurnBlood/Heal) 描述 价格 JSON形式Effects
3 1 破境丹 练气 Breakthrough 凝聚灵气,辅助练气期修士突破瓶颈的丹药(药效5年)。 50 {duration_month: 60, extra_breakthrough_success_rate: 0.1}
4 2 破境丹 筑基 Breakthrough 蕴含筑基真意,辅助筑基期修士突破瓶颈的灵丹(药效5年)。 200 {duration_month: 60, extra_breakthrough_success_rate: 0.1}
5 3 破境丹 金丹 Breakthrough 凝结金丹之气,辅助金丹期修士碎丹成婴(药效5年)。 500 {duration_month: 60, extra_breakthrough_success_rate: 0.1}
6 5 长生丹 练气 Lifespan 采用凡间珍草炼制,略微延缓衰老(药效50年)。 100 {duration_month: 600, extra_max_lifespan: 5}
7 6 长生丹 筑基 Lifespan 取天地灵草炼制,可延寿十载(药效50年)。 500 {duration_month: 1200, extra_max_lifespan: 10}
8 7 长生丹 金丹 Lifespan 夺天地造化,凡人服之立毙,金丹修士服之延寿半甲子(药效50年)。 200 {duration_month: 2400, extra_max_lifespan: 30}
9 8 长生丹 元婴 Lifespan 蕴含一丝长生之气,元婴老怪以此续命(药效50年)。 5000 {duration_month: 6000, extra_max_lifespan: 100}
10 9 燃血丹 练气 BurnBlood 燃烧精血换取短暂爆发。3年内战力提升,但10年内经脉受损战力下降。 50 [{duration_month: 36, extra_battle_strength_points: 3}, {duration_month: 120, extra_battle_strength_points: -1}]
11 10 燃血丹 筑基 BurnBlood 激发潜能的猛药。3年内战力大增,但10年内虚弱。 100 [{duration_month: 36, extra_battle_strength_points: 5}, {duration_month: 120, extra_battle_strength_points: -2}]
12 11 燃血丹 金丹 BurnBlood 金丹修士拼命时的选择。3年内战力暴涨,但10年内重伤。 200 [{duration_month: 36, extra_battle_strength_points: 7}, {duration_month: 120, extra_battle_strength_points: -3}]
13 12 燃血丹 元婴 BurnBlood 燃烧元婴本源。3年内获得毁天灭地的力量,但10年内几乎废人。 300 [{duration_month: 36, extra_battle_strength_points: 10}, {duration_month: 120, extra_battle_strength_points: -5}]
14 13 回春丹 练气 Heal 普通的疗伤丹药,可恢复练气期修士的伤势(持续5年)。 20 {duration_month: 60, extra_hp_recovery_rate: 0.5}
15 14 回春丹 筑基 Heal 药力温和醇厚,能快速愈合筑基期修士的肉身损伤(持续5年)。 50 {duration_month: 60, extra_hp_recovery_rate: 1.0}
16 15 回春丹 金丹 Heal 蕴含生机之力,疗伤圣药(持续5年)。 100 {duration_month: 60, extra_hp_recovery_rate: 2.0}
17 16 回春丹 元婴 Heal 蕴含造化生机,肉身修复极快(持续5年)。 200 {duration_month: 60, extra_hp_recovery_rate: 5.0}

View File

@@ -14,7 +14,7 @@
"avatar_thinking": ... // 从角色角度,以第一人称视角,简单清晰的描述想法
"current_emotion": ... // 从以下列表中选择一个最符合当前心情的词:平静、开心、愤怒、悲伤、恐惧、惊讶、期待、厌恶、疑惑、疲惫
"short_term_objective": ..., // 角色接下来一段时间的短期目标
"action_name_params_pairs": list[Tuple[action_name, action_params]] // 一次性决定未来的5~10个动作按顺序执行。action_params 必须是字典 {{}},不能null。
"action_name_params_pairs": list[Tuple[action_name, action_params]] // 一次性决定未来的5~10个动作按顺序执行。action_params 必须是字典 {{}}。如果为空则返回空字典,不能返回null。
}}
}}