update effects

This commit is contained in:
bridge
2025-11-13 11:28:09 +08:00
parent f8c4f84c7a
commit 7af6757e64
8 changed files with 188 additions and 68 deletions

View File

@@ -9,7 +9,15 @@ if TYPE_CHECKING:
def load_effect_from_str(value: object) -> dict[str, Any] | list[dict[str, Any]]:
"""
将 effects 字段解析为 dict 或 list支持标准 JSON 字符串)。
将 effects 字段解析为 dict 或 list支持宽松JSON格式)。
支持的格式:
1. 标准JSON: {"extra_battle_strength_points": 3}
2. 单引号: {'extra_battle_strength_points': 3}
3. 无引号key: {extra_battle_strength_points: 3}
4. 混合格式: {extra_battle_strength_points: 3, 'legal_actions': ['DevourMortals']}
5. 条件数组: [{when: 'condition', effect1: value1}, ...]
- value 为 None/空字符串/'nan' 时返回 {}
- 解析失败时返回 {}
- 支持返回 dict单个effect或 list[dict]多个条件effect
@@ -21,11 +29,59 @@ def load_effect_from_str(value: object) -> dict[str, Any] | list[dict[str, Any]]
s = str(value).strip()
if not s or s == "nan":
return {}
# 先尝试标准 JSON 解析
try:
obj = json.loads(s)
if isinstance(obj, (dict, list)):
return obj
return {}
except Exception:
pass
# 尝试宽松解析:单引号转双引号 + 无引号key处理
try:
import re
# 1. 先保护所有引号内的内容(包括单引号和双引号字符串)
strings = []
def save_string(match):
strings.append(match.group(0))
return f"__STRING_{len(strings)-1}__"
relaxed = s
# 保护双引号字符串
relaxed = re.sub(r'"(?:[^"\\]|\\.)*"', save_string, relaxed)
# 保护单引号字符串
relaxed = re.sub(r"'(?:[^'\\]|\\.)*'", save_string, relaxed)
# 2. 给无引号的key添加引号此时所有字符串都已被保护
# 匹配: 开始位置后的标识符 + 冒号
relaxed = re.sub(r'([{\[,]\s*)([a-zA-Z_][a-zA-Z0-9_]*)(\s*):', r'\1"__KEY_\2__"\3:', relaxed)
# 3. 恢复字符串,并将单引号转为双引号
for i, s_val in enumerate(strings):
# 如果是单引号字符串,转为双引号
if s_val.startswith("'"):
# 需要转义内部的双引号但要先恢复其中的__STRING_占位符
content = s_val[1:-1] # 去掉单引号
# 恢复内部的字符串占位符
for j, inner_str in enumerate(strings):
if f"__STRING_{j}__" in content and j != i:
content = content.replace(f"__STRING_{j}__", inner_str)
# 转义处理
content = content.replace('\\', '\\\\').replace('"', '\\"')
s_val = f'"{content}"'
relaxed = relaxed.replace(f"__STRING_{i}__", s_val)
# 4. 恢复key去掉__KEY_标记
relaxed = relaxed.replace('"__KEY_', '"').replace('__"', '"')
# 5. 尝试解析
obj = json.loads(relaxed)
if isinstance(obj, (dict, list)):
return obj
return {}
except Exception:
return {}

View File

@@ -150,6 +150,70 @@ LEGAL_ACTIONS = "legal_actions"
- "DevourMortals": 吞噬凡人(邪道法宝)
"""
# =============================================================================
# CSV 配置格式规范
# =============================================================================
"""
## CSV 中 effects 列的写法支持宽松JSON格式
### 基础格式(推荐)
```
{extra_battle_strength_points: 3}
{extra_battle_strength_points: 2, extra_max_hp: 50}
{legal_actions: ['DevourMortals'], extra_battle_strength_points: 2}
```
### 格式规则
1. ✅ 无引号key推荐: {extra_battle_strength_points: 3}
2. ✅ 单引号: {'extra_battle_strength_points': 3}
3. ✅ 双引号: {"extra_battle_strength_points": 3}
4. ✅ 混合使用: {key1: 1, 'key2': 2, "key3": 3}
### 条件effectwhen 子句)
当 effect 需要根据条件生效时,使用 when 字段:
```
# 单条件
[{when: 'avatar.weapon.type == WeaponType.SWORD', extra_battle_strength_points: 3}]
# 多条件满足任一条件即生效effects会累加
[
{when: 'avatar.weapon.type == WeaponType.SWORD', extra_weapon_proficiency_gain: 1.0, extra_battle_strength_points: 3},
{when: 'avatar.alignment == Alignment.EVIL', extra_cultivate_exp: 20}
]
```
### 动态表达式eval
对于需要运行时计算的值,使用字符串形式的表达式:
```
{extra_battle_strength_points: 'avatar.weapon.special_data.get("devoured_souls", 0) // 100 * 0.1'}
```
注意:
- eval 表达式在 Avatar.effects property 中动态计算
- 可访问的变量avatar, WeaponType, EquipmentGrade, Alignment
- 表达式失败时默认为 0
### 实际示例
```csv
# weapon.csv
id,name,effects
1,本命剑匣,{extra_battle_strength_points: 3}
4,镇魂钟,{extra_battle_strength_points: 2, extra_observation_radius: 1}
6,万魂幡,{legal_actions: ['DevourMortals'], extra_battle_strength_points: 'avatar.weapon.special_data.get("devoured_souls", 0) // 100 * 0.1'}
# persona.csv - 条件effect
32,剑痴,[{when: 'avatar.weapon.type == WeaponType.SWORD', extra_weapon_proficiency_gain: 1.0, extra_battle_strength_points: 3}]
46,音律大师,[{when: 'avatar.weapon.type == WeaponType.ZITHER or avatar.weapon.type == WeaponType.FLUTE', extra_weapon_proficiency_gain: 1.0, extra_battle_strength_points: 3}]
# technique.csv - 负面effect
28,血神噬魂大法,{extra_breakthrough_success_rate: -0.1, extra_cultivate_exp: 50}
```
"""
# =============================================================================
# Effect 合并规则
# =============================================================================
@@ -161,7 +225,7 @@ Effects 通过 src/classes/effect.py 中的 _merge_effects() 函数合并。
1. 列表类型 (如 legal_actions): 取并集(去重)
2. 数值类型 (如 extra_*): 累加
3. 其他类型: 后者覆盖前者
4. 动态表达式 ("eval(...)"): 在 Avatar.effects property 中 eval 计算
4. 动态表达式 (字符串形式): 在 Avatar.effects property 中 eval 计算
合并顺序(从低到高优先级):
1. 宗门 (sect)