add elixir
This commit is contained in:
@@ -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:
|
||||
"""加入宗门"""
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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()
|
||||
|
||||
|
||||
@@ -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
|
||||
],
|
||||
}
|
||||
|
||||
|
||||
17
static/game_configs/elixir.csv
Normal file
17
static/game_configs/elixir.csv
Normal 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}"
|
||||
|
@@ -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。
|
||||
}}
|
||||
}}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user