diff --git "a/zsim/data/APLData/\346\237\232\345\217\266-\351\233\205-\350\226\207\350\226\207\345\256\211.toml" "b/zsim/data/APLData/\346\237\232\345\217\266-\351\233\205-\350\226\207\350\226\207\345\256\211.toml" index 45bf2da2..02b10236 100644 --- "a/zsim/data/APLData/\346\237\232\345\217\266-\351\233\205-\350\226\207\350\226\207\345\256\211.toml" +++ "b/zsim/data/APLData/\346\237\232\345\217\266-\351\233\205-\350\226\207\350\226\207\345\256\211.toml" @@ -3,7 +3,7 @@ title = "柚叶-雅-薇薇安" comment = "开发组为 柚叶、雅、薇薇安 提供的默认APL" author = "虎皮" create_time = "2025-07-15T14:06:38.457+08:00" -latest_change_time = "2025-07-26T09:39:24.292+08:00" +latest_change_time = "2025-07-27T03:23:03.891+08:00" [characters] required = [ "柚叶", "薇薇安", "雅",] diff --git a/zsim/data/buff_effect.csv b/zsim/data/buff_effect.csv index 190bb7d8..a0fa4b2f 100644 --- a/zsim/data/buff_effect.csv +++ b/zsim/data/buff_effect.csv @@ -466,7 +466,7 @@ Buff-角色-薇薇安-核心被动触发器,,,,,,,, Buff-角色-薇薇安-预言触发器,,,,,,,, Buff-角色-薇薇安-额外能力-协同攻击触发器,,,,,,,, Buff-角色-薇薇安-额外能力-全队侵蚀伤害增加,侵蚀额外伤害增幅,0.12,,,,,, -Buff-角色-薇薇安-额外能力-侵蚀紊乱伤害提升,侵蚀紊乱伤害提升,0.12,,,,,, +Buff-角色-薇薇安-额外能力-侵蚀紊乱伤害提升,紊乱额外伤害增幅,0.12,,,,,, Buff-角色-薇薇安-1画-全属性异常和紊乱伤害提升,全属性异常额外伤害增幅,0.16,紊乱额外伤害增幅,0.16,,,, Buff-角色-薇薇安-2画-以太积蓄效率提升,以太积蓄效率增加,0.25,,,,,, Buff-角色-薇薇安-2画-异放全属性抗性穿透,全属性抗性穿透,0.15,,,,,, diff --git a/zsim/data/character_config_example.toml b/zsim/data/character_config_example.toml index d686013f..2cdbb2a0 100644 --- a/zsim/data/character_config_example.toml +++ b/zsim/data/character_config_example.toml @@ -169,7 +169,7 @@ equip_set2_a = "激素朋克" name = "薇薇安" weapon = "飞鸟星梦" weapon_level = 1 -cinema = 6 +cinema = 0 crit_balancing = true scATK_percent = 5 scATK = 0 diff --git a/zsim/data/skill.csv b/zsim/data/skill.csv index 318b895d..bd2059da 100644 --- a/zsim/data/skill.csv +++ b/zsim/data/skill.csv @@ -863,4 +863,4 @@ 1411,柚叶,普攻,1411_CoAttack_C,协同攻击(狸猫),普通攻击:狸之助,,狸猫阿釜自主攻击,1.1,0.1,2.2,2.4,2.6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,85,8,FALSE,TRUE,0,0,,,,0,0,"[15, 20, 24, 33, 41, 60, 63, 68]",,FALSE,1,FALSE, 1411,柚叶,支援突击,1411_Assault_Aid_A,突击支援(开伞格挡后),支援突击:夹心硬糖射击,,,4.636,0.422,9.278,10.122,10.966,4.087,0.186,6.133,6.505,6.877,0,0,0,0,0,0,0,129.635,221.64,0,0,39642,6,9,0,1,0,137,6,TRUE,TRUE,0,0,,,,0,0,"[28, 35, 42, 51, 98, 113]",,TRUE,1,FALSE, 1411,柚叶,附加伤害,1411_Cinema_6,6画炮弹,强力炮弹,,,0.3,0,0.3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,1,FALSE,FALSE,0,0,"{'additional_damage':1,'sugar_points':-1}",,,0,0,,,FALSE,1,FALSE, -1411,柚叶,支援突击,1411_Assault_Aid_B,突击支援(6画专属),支援突击:夹心硬糖射击,,6画专属蓄力版支援突击,4.636,0.422,9.278,10.122,10.966,4.087,0.186,6.133,6.505,6.877,0,0,0,0,0,0,0,129.635,221.64,0,0,39642,6,9,0,1,0,185,6,TRUE,TRUE,0,0,,,,0,0,"[28, 35, 42, 51, 146, 161]",,TRUE,1,FALSE, +1411,柚叶,支援突击,1411_Assault_Aid_B,突击支援(6画专属),支援突击:夹心硬糖射击,,6画专属蓄力版支援突击,4.636,0.422,9.278,10.122,10.966,4.087,0.186,6.133,6.505,6.877,0,0,0,0,0,0,0,129.635,221.64,0,0,39642,6,9,0,1,0,137,6,TRUE,TRUE,0,0,,,,0,0,"[28, 35, 42, 51, 122, 136]",,TRUE,1,FALSE, diff --git "a/zsim/data/\346\277\200\346\264\273\345\210\244\346\226\255.csv" "b/zsim/data/\346\277\200\346\264\273\345\210\244\346\226\255.csv" index efa59531..100a2b0d 100644 --- "a/zsim/data/\346\277\200\346\264\273\345\210\244\346\226\255.csv" +++ "b/zsim/data/\346\277\200\346\264\273\345\210\244\346\226\255.csv" @@ -466,7 +466,7 @@ Buff-角色-薇薇安-核心被动触发器,FALSE,FALSE,FALSE,FALSE,薇薇安,FA Buff-角色-薇薇安-预言触发器,FALSE,FALSE,FALSE,FALSE,薇薇安,FALSE,添加核心被动Dot的触发器,FALSE,0,1,1,FALSE,FALSE,TRUE,FALSE,TRUE,0,TRUE,FALSE,TRUE,TRUE,FALSE,TRUE,TRUE,0,1000,FALSE,FALSE,TRUE,,, Buff-角色-薇薇安-额外能力-协同攻击触发器,FALSE,FALSE,TRUE,FALSE,薇薇安,FALSE,队友触发属性异常时,协同释放一次落雨生花,FALSE,0,1,1,FALSE,FALSE,TRUE,FALSE,TRUE,0,TRUE,FALSE,TRUE,TRUE,TRUE,FALSE,TRUE,0,1000,TRUE,FALSE,TRUE,,, Buff-角色-薇薇安-额外能力-全队侵蚀伤害增加,FALSE,TRUE,TRUE,FALSE,薇薇安,FALSE,全队造成的侵蚀伤害提高12%,FALSE,0,1,1,FALSE,FALSE,TRUE,TRUE,FALSE,0,TRUE,TRUE,TRUE,TRUE,TRUE,TRUE,TRUE,0,1,FALSE,FALSE,FALSE,,, -Buff-角色-薇薇安-额外能力-侵蚀紊乱伤害提升,FALSE,TRUE,TRUE,FALSE,薇薇安,FALSE,侵蚀状态被结算的紊乱伤害提升12%,FALSE,0,1,1,FALSE,FALSE,TRUE,TRUE,FALSE,0,TRUE,TRUE,TRUE,TRUE,TRUE,TRUE,TRUE,0,1,FALSE,FALSE,FALSE,,, +Buff-角色-薇薇安-额外能力-侵蚀紊乱伤害提升,FALSE,TRUE,TRUE,FALSE,薇薇安,FALSE,侵蚀状态被结算的紊乱伤害提升12%,FALSE,0,1,1,FALSE,FALSE,TRUE,TRUE,FALSE,0,TRUE,TRUE,TRUE,TRUE,TRUE,TRUE,TRUE,0,1,FALSE,FALSE,FALSE,"{""specified_disorder_element_type"":[4,6]}",, Buff-角色-薇薇安-1画-全属性异常和紊乱伤害提升,FALSE,TRUE,FALSE,TRUE,薇薇安,FALSE,处于薇薇安预言下的目标受到的所有属性异常伤害和紊乱伤害提高16%,FALSE,999999,1,1,FALSE,FALSE,TRUE,FALSE,TRUE,0,TRUE,FALSE,TRUE,TRUE,TRUE,TRUE,TRUE,1,1,FALSE,FALSE,TRUE,,, Buff-角色-薇薇安-2画-以太积蓄效率提升,FALSE,FALSE,FALSE,TRUE,薇薇安,FALSE,以太异常积蓄效率提升25%,FALSE,0,1,1,FALSE,FALSE,TRUE,TRUE,FALSE,0,TRUE,TRUE,TRUE,TRUE,TRUE,TRUE,TRUE,2,1000,FALSE,FALSE,FALSE,,, Buff-角色-薇薇安-2画-异放全属性抗性穿透,FALSE,TRUE,FALSE,TRUE,薇薇安,FALSE,专属于异放的15%全属性伤害抗性穿透,FALSE,0,1,1,FALSE,FALSE,TRUE,TRUE,FALSE,0,TRUE,TRUE,TRUE,TRUE,TRUE,TRUE,TRUE,2,1,FALSE,FALSE,TRUE,"{""only_anomaly"":[""Abloom""]}",, diff --git a/zsim/define.py b/zsim/define.py index 7a6ac75d..a8c7bd1e 100644 --- a/zsim/define.py +++ b/zsim/define.py @@ -104,7 +104,14 @@ def update_json_config(template: dict, user: dict) -> bool: PARRY_BASE_PARAMETERS: dict[str, int | float] = { "ChainParryActionTimeCost": 10, # 连续招架动作的时间消耗 } -CHAR_PARRY_STRATEGY_MAP: dict = {1411: "1411_Assault_Aid_A"} + +# 招架策略,有些角色的拥有不同的突击支援(比如柚叶),所以在这里用字典进行映射。 +# 该字典的key为CID,value为招架动作的skill_tag +# 注意,不同的招架策略有时候存在着影画或是其他的限制条件, +# 所以若是在不满足这些条件的情况下强行使用这些招架策略,那么character中的审查函数会报错而中断程序运行。 +CHAR_PARRY_STRATEGY_MAP: dict = { + 1411: "1411_Assault_Aid_A" +} # debug参数,用于检查APL在窗口期间的想法 APL_THOUGHT_CHECK: bool = _config["apl_mode"].get("apl_thought_check", False) diff --git a/zsim/script/draw_anomaly_timeline.py b/zsim/script/draw_anomaly_timeline.py new file mode 100644 index 00000000..5fd3c89a --- /dev/null +++ b/zsim/script/draw_anomaly_timeline.py @@ -0,0 +1,225 @@ +#!/usr/bin/env python3 +""" +绘制异常轴图的脚本。 +该脚本读取本地results目录下的damage.csv文件,并根据其中的信息绘制一个透明背景的异常轴图。 + + +启动命令:python zsim/script/draw_anomaly_timeline.py results/359 + +""" + +import os +import sys +import argparse +try: + import pandas as pd + import plotly.express as px + import plotly.graph_objects as go + PLOTLY_AVAILABLE = True +except ImportError: + PLOTLY_AVAILABLE = False + print("错误: 缺少必要的依赖包。请安装 pandas 和 plotly:") + print(" pip install pandas plotly") + sys.exit(1) + + +def find_consecutive_true_ranges(df, column): + """查找DataFrame列中连续为True的范围。 + + Args: + df (pd.DataFrame): 输入的DataFrame,需要包含 'tick' 列。 + column (str): 要查找的布尔列名。 + + Returns: + list[tuple[int, int]]: 一个包含 (开始tick, 结束tick) 元组的列表。 + """ + ranges = [] + start = None + + # 获取tick列和指定列的值 + ticks = df["tick"].tolist() + values = df[column].tolist() + + for i, (tick, value) in enumerate(zip(ticks, values)): + if value: + if start is None: + start = tick + else: + if start is not None: + # 结束tick应该是上一个为True的tick + prev_tick = ticks[i - 1] if i > 0 else start + ranges.append((start, prev_tick)) + start = None + # 处理最后一个区间(如果存在) + if start is not None: + ranges.append((start, ticks[-1])) + return ranges + + +def prepare_timeline_data(df): + """准备用于绘制异常状态时间线的数据。 + + Args: + df (pd.DataFrame): 原始伤害数据。 + + Returns: + tuple: (用于绘制Gantt图的DataFrame, 每种异常状态的平均持续时间字典) + """ + required_columns = [ + "冻结", + "霜寒", + "畏缩", + "感电", + "灼烧", + "侵蚀", + "烈霜霜寒", + "tick", + ] + missing_cols = [col for col in required_columns if col not in df.columns] + if missing_cols: + raise ValueError(f"输入数据缺少必要的列: {missing_cols}") + + columns_to_check = ["冻结", "霜寒", "畏缩", "感电", "灼烧", "侵蚀", "烈霜霜寒"] + gantt_data = [] + duration_stats = {} + + for col in columns_to_check: + if col in df.columns: + ranges = find_consecutive_true_ranges(df, col) + durations = [end - start + 1 for start, end in ranges] # 持续时间包含首尾 + duration_stats[col] = durations + + for start, end in ranges: + gantt_data.append({"Task": col, "Start": start, "Finish": end}) + + if not gantt_data: + return pd.DataFrame(), {} + + gantt_df = pd.DataFrame(gantt_data) + gantt_df["Duration"] = gantt_df["Finish"] - gantt_df["Start"] + 1 # 持续时间包含首尾 + + # 计算每种异常状态的平均持续时间 + avg_durations = {} + for col, durations in duration_stats.items(): + if durations: + avg_durations[col] = sum(durations) / len(durations) + else: + avg_durations[col] = 0 + + return gantt_df, avg_durations + + +def draw_anomaly_timeline(gantt_df, output_path=None): + """绘制异常状态时间线(Gantt图)。 + + Args: + gantt_df (pd.DataFrame): 用于绘制Gantt图的数据。 + output_path (str, optional): 输出图片文件路径(例如 output.png)。 + """ + if gantt_df is not None and len(gantt_df) > 0: + fig = px.bar( + gantt_df, + x="Duration", + y="Task", + base="Start", + orientation="h", + labels={ + "Start": "开始时间(帧)", + "Duration": "持续时间(帧)", + "Task": "状态类型", + }, + height=350, + ) + + # 设置透明背景 + fig.update_layout( + plot_bgcolor='rgba(0,0,0,0)', + paper_bgcolor='rgba(0,0,0,0)', + ) + + # 设置网格线颜色 + fig.update_xaxes(showgrid=True, gridwidth=3, gridcolor='rgba(128,128,128,0.2)') + fig.update_yaxes(showgrid=True, gridwidth=3, gridcolor='rgba(128,128,128,0.2)') + + if output_path: + # 保存为PNG图片 + try: + fig.write_image(output_path, width=1200, height=300) + print(f"异常轴图已保存至: {output_path}") + except ValueError as e: + if "kaleido" in str(e).lower(): + print("错误: 缺少kaleido包,无法保存图片。请安装kaleido:") + print(" pip install kaleido") + print("或者只在浏览器中查看图表,不使用 -o 参数") + sys.exit(1) + else: + raise e + else: + # 在浏览器中显示 + fig.show() + else: + print("没有找到任何连续的状态数据") + + +def main(): + parser = argparse.ArgumentParser(description="绘制异常轴图") + parser.add_argument("result_dir", help="战斗日志所在的结果目录,例如 results/123") + parser.add_argument("-o", "--output", help="输出图片文件路径(例如 output.png)") + + args = parser.parse_args() + + # 如果指定了输出路径,检查kaleido是否可用 + if args.output: + try: + import plotly.io as pio + # 尝试导入kaleido + pio.kaleido.scope + except ImportError: + print("警告: 如果要保存图片,请安装kaleido:") + print(" pip install kaleido") + print("否则请只在浏览器中查看图表,不使用 -o 参数") + + # 构建damage.csv文件路径 + damage_csv_path = os.path.join(args.result_dir, "damage.csv") + + # 检查文件是否存在 + if not os.path.exists(damage_csv_path): + print(f"错误: 文件 {damage_csv_path} 不存在") + sys.exit(1) + + # 读取damage.csv文件 + try: + df = pd.read_csv(damage_csv_path) + print(f"成功读取文件: {damage_csv_path}") + except Exception as e: + print(f"读取文件时出错: {e}") + sys.exit(1) + + # 准备数据 + try: + gantt_df, avg_durations = prepare_timeline_data(df) + print("数据准备完成") + except Exception as e: + print(f"准备数据时出错: {e}") + sys.exit(1) + + # 输出每种异常状态的平均持续时间 + print("\n各异常状态的平均持续时间:") + print("-" * 30) + for anomaly, avg_duration in avg_durations.items(): + if avg_duration == 0: + continue + print(f"{anomaly}: {avg_duration/60:.2f} 秒") + print("-" * 30) + + # 绘制图表 + try: + draw_anomaly_timeline(gantt_df, args.output) + print("异常轴图绘制完成") + except Exception as e: + print(f"绘制图表时出错: {e}") + sys.exit(1) + + +if __name__ == "__main__": + main() diff --git a/zsim/sim_progress/Buff/BuffXLogic/YuzuhaCinema6SheelTrigger.py b/zsim/sim_progress/Buff/BuffXLogic/YuzuhaCinema6SheelTrigger.py index a11484ed..ecf09299 100644 --- a/zsim/sim_progress/Buff/BuffXLogic/YuzuhaCinema6SheelTrigger.py +++ b/zsim/sim_progress/Buff/BuffXLogic/YuzuhaCinema6SheelTrigger.py @@ -50,7 +50,7 @@ def special_judge_logic(self, **kwargs): return False tick = self.buff_instance.sim_instance.tick lasting_tick = tick - skill_node.preload_tick - if 0 <= lasting_tick < 51: + if 0 <= lasting_tick < 24: return False else: self.record.charging_start = True diff --git a/zsim/sim_progress/ScheduledEvent/CalAnomaly.py b/zsim/sim_progress/ScheduledEvent/CalAnomaly.py index f4d44c66..4449940d 100644 --- a/zsim/sim_progress/ScheduledEvent/CalAnomaly.py +++ b/zsim/sim_progress/ScheduledEvent/CalAnomaly.py @@ -6,11 +6,10 @@ from zsim.sim_progress.anomaly_bar import AnomalyBar from zsim.sim_progress.anomaly_bar.CopyAnomalyForOutput import ( DirgeOfDestinyAnomaly as Abloom, -) -from zsim.sim_progress.anomaly_bar.CopyAnomalyForOutput import ( Disorder, PolarityDisorder, ) +from zsim.sim_progress.Character.character import Character from zsim.sim_progress.Character.Yanagi import Yanagi from zsim.sim_progress.Enemy import Enemy from zsim.sim_progress.Report import report_to_log @@ -105,7 +104,7 @@ def __init__( stun_vulnerability, special_mul, imp_mul, - stun_mul, + stun_mul ) @staticmethod @@ -150,7 +149,9 @@ def cal_def_mul(self, data: MulData, v_char_level) -> np.float64: # 计算属性/类型的穿透 if self.element_type == 0: # 穿透率 - addon_pen_ratio = float(self.dmg_sp[0, 6]) + self.data.dynamic.strike_ignore_defense + addon_pen_ratio = ( + float(self.dmg_sp[0, 6]) + self.data.dynamic.strike_ignore_defense + ) # 受击方有效防御 else: addon_pen_ratio = float(self.dmg_sp[0, 6]) @@ -208,9 +209,7 @@ def set_final_multipliers( def cal_anomaly_dmg(self) -> np.float64: """计算异常伤害期望""" - return np.float64( - np.prod(self.final_multipliers) / (self.dmg_sp[0, 9] * self.dmg_sp[0, 10]) - ) + return np.float64(np.prod(self.final_multipliers)/(self.dmg_sp[0,9] * self.dmg_sp[0,10])) class CalDisorder(CalAnomaly): @@ -225,7 +224,9 @@ def __init__( 异常伤害快照以 array 形式储存,顺序为: [基础伤害区、增伤区、异常精通区、等级、异常增伤区、异常暴击区、穿透率、穿透值、抗性穿透] """ - super().__init__(disorder_obj, enemy_obj, dynamic_buff, sim_instance=sim_instance) + super().__init__( + disorder_obj, enemy_obj, dynamic_buff, sim_instance=sim_instance + ) self.final_multipliers[0] = self.cal_disorder_base_dmg( np.float64(self.final_multipliers[0]) ) @@ -239,38 +240,45 @@ def cal_disorder_base_dmg(self, base_mul: np.float64) -> np.float64: """ t_s = np.float64(self.anomaly_obj.remaining_tick() / 60) disorder_base_dmg: np.float64 + # 计算紊乱基础倍率增幅 + disorder_basic_mul_map = self.data.dynamic.disorder_basic_mul_map + disorder_base_ratio_increase = disorder_basic_mul_map[self.element_type] + disorder_basic_mul_map["all"] # 计算紊乱基础伤害 match self.element_type: case 0: # 强击紊乱 - disorder_base_dmg = (base_mul / 7.13) * (np.floor(t_s) * 0.075 + 4.5) + _atk = base_mul / 7.13 + _ratio = np.floor(t_s) * 0.075 + 4.5 + disorder_base_ratio_increase case 1: # 灼烧紊乱 - disorder_base_dmg = (base_mul / 0.5) * (np.floor(t_s / 0.5) * 0.5 + 4.5) + _atk = base_mul / 0.5 + _ratio = np.floor(t_s / 0.5) * 0.5 + 4.5 + disorder_base_ratio_increase case 2: # 霜寒紊乱 - disorder_base_dmg = (base_mul / 5) * (np.floor(t_s) * 0.075 + 4.5) + _atk = base_mul / 5 + _ratio = np.floor(t_s) * 0.075 + 4.5 + disorder_base_ratio_increase case 3: # 感电紊乱 - disorder_base_dmg = (base_mul / 1.25) * (np.floor(t_s) * 1.25 + 4.5) + _atk = base_mul / 1.25 + _ratio = np.floor(t_s) * 1.25 + 4.5 + disorder_base_ratio_increase case 4: # 侵蚀紊乱 - disorder_base_dmg = (base_mul / 0.625) * (np.floor(t_s / 0.5) * 0.625 + 4.5) + _atk = base_mul / 0.625 + _ratio = np.floor(t_s / 0.5) * 0.625 + 4.5 + disorder_base_ratio_increase case 5: # 烈霜紊乱 - disorder_base_dmg = (base_mul / 5) * (np.floor(t_s) * 0.75 + 6) + _atk = base_mul / 5 + _ratio = np.floor(t_s) * 0.75 + 6 + disorder_base_ratio_increase case 6: # 玄墨侵蚀紊乱 - disorder_base_dmg = (base_mul / 0.625) * (np.floor(t_s / 0.5) * 0.625 + 4.5) + _atk = base_mul / 0.625 + _ratio = np.floor(t_s / 0.5) * 0.625 + 4.5 + disorder_base_ratio_increase case _: assert False, f"Invalid Element Type {self.element_type}" - # 计算紊乱基础倍率增幅 - disorder_basic_mul_map: dict[ElementType | Literal["all"], float] = ( - self.data.dynamic.disorder_basic_mul_map - ) - disorder_base_dmg *= 1 + ( - disorder_basic_mul_map[self.element_type] + disorder_basic_mul_map["all"] - ) - # print(f"111111,计算紊乱!{disorder_basic_mul_map}") + disorder_base_dmg = _atk * _ratio + # from zsim.define import ELEMENT_TYPE_MAPPING as ETM + # print(f"111111,计算紊乱!{ETM[self.element_type]}属性的紊乱,攻击力为:{_atk:.2f},倍率为:{_ratio:.2f}, 紊乱倍率加成为:{disorder_base_ratio_increase}") return np.float64(disorder_base_dmg) def cal_disorder_extra_mul(self) -> np.float64: - """计算紊乱的异常额外增伤区 - + """ + 计算紊乱的异常额外增伤区,即紊乱的异常增伤区。 异常额外增伤区 = 1 + 对应属性异常额外增伤 + 紊乱的额外增伤本身只有一个词条:紊乱额外伤害增幅(disorder_dmg_mul),该词条本身是对所有紊乱通用的, + 所以若是要实现“X属性紊乱伤害增幅”,则必须通过buff label的"specified_disorder_element_type"加以限制。 """ map: dict[ElementType | Literal["all", -1], float] = self.data.dynamic.ano_extra_bonus return np.float64(1 + map[-1]) diff --git a/zsim/sim_progress/ScheduledEvent/buff_effect_trans.json b/zsim/sim_progress/ScheduledEvent/buff_effect_trans.json index 249d8e85..2af1e273 100644 --- a/zsim/sim_progress/ScheduledEvent/buff_effect_trans.json +++ b/zsim/sim_progress/ScheduledEvent/buff_effect_trans.json @@ -171,11 +171,11 @@ "紊乱倍率增加": "all_disorder_basic_mul", - "强击紊乱伤害提升": "strike_disorder_basic_mul", - "灼烧紊乱伤害提升": "burn_disorder_basic_mul", - "霜寒紊乱伤害提升": "frostbite_disorder_basic_mul", - "感电紊乱伤害提升": "shock_disorder_basic_mul", - "侵蚀紊乱伤害提升": "chaos_disorder_basic_mul", + "强击紊乱倍率增加": "strike_disorder_basic_mul", + "灼烧紊乱倍率增加": "burn_disorder_basic_mul", + "霜寒紊乱倍率增加": "frostbite_disorder_basic_mul", + "感电紊乱倍率增加": "shock_disorder_basic_mul", + "侵蚀紊乱倍率增加": "chaos_disorder_basic_mul", "贯穿伤害增加": "sheer_dmg_bonus" } diff --git a/zsim/sim_progress/Update/Update_Buff.py b/zsim/sim_progress/Update/Update_Buff.py index e4a52d7c..99a1b5a1 100644 --- a/zsim/sim_progress/Update/Update_Buff.py +++ b/zsim/sim_progress/Update/Update_Buff.py @@ -32,8 +32,8 @@ def update_dynamic_bufflist(DYNAMIC_BUFF_DICT: dict, timetick, exist_buff_dict: report_buff_to_queue(charname, timetick, _.ft.index, _.dy.count, True, level=4) continue if _.ft.individual_settled: - if len(_.dy.built_in_buff_box) <= 0 or timetick >= _.dy.endticks: - # 层数为0或是到点了,都会导致buff结束, + if len(_.dy.built_in_buff_box) <= 0: + # 层数为0时候结束 remove_buff_list.append(_) continue else: @@ -72,10 +72,14 @@ def process_individual_buff(_, timetick): """ 针对层数独立结算的buff的tuple的独立结算。去除过期的tuple """ - for tuples in _.dy.built_in_buff_box[:]: - if tuples[1] <= timetick: - _.dy.built_in_buff_box.remove(tuples) - _.dy.count = len(_.dy.built_in_buff_box) + end_tuples_list = [] + for tuples in _.dy.built_in_buff_box: + if tuples[1] < timetick: + end_tuples_list.append(tuples) + else: + for _end_tuples in end_tuples_list: + _.dy.built_in_buff_box.remove(_end_tuples) + _.dy.count = len(_.dy.built_in_buff_box) def KickOutBuff( diff --git a/zsim/sim_progress/data_struct/data_analyzer.py b/zsim/sim_progress/data_struct/data_analyzer.py index 20d23dfd..74264955 100644 --- a/zsim/sim_progress/data_struct/data_analyzer.py +++ b/zsim/sim_progress/data_struct/data_analyzer.py @@ -21,7 +21,7 @@ def cal_buff_total_bonus( enabled_buff: Sequence["Buff"], judge_obj: "SkillNode | AnomalyBar | None" = None, sim_instance: "Simulator" = None, - char_name: str | None = None, + char_name: str | None = None ) -> dict[str, float]: """过滤并计算buff总加成。 @@ -43,7 +43,6 @@ def cal_buff_total_bonus( from zsim.sim_progress.anomaly_bar import AnomalyBar from zsim.sim_progress.Buff import Buff from zsim.sim_progress.Preload.SkillsQueue import SkillNode - # FIXME: # 已知bug:武器【时流贤者】的“对佩戴者造成的紊乱伤害增幅”的效果在部分紊乱、极性紊乱上会失效,原因未知,等待继续排查。 buff_obj: Buff @@ -54,7 +53,9 @@ def cal_buff_total_bonus( else: # 检查buff是否激活 if not buff_obj.dy.active: - report_to_log(f"[Warning] 动态buff列表中混入了未激活buff: {str(buff_obj)},已跳过") + report_to_log( + f"[Warning] 动态buff列表中混入了未激活buff: {str(buff_obj)},已跳过" + ) continue # 检查buff的标签是否与技能节点匹配 if judge_obj is not None: @@ -65,14 +66,11 @@ def cal_buff_total_bonus( 这些buff只有在特定条件被满足的情况下才会对当前技能生效——__check_skill_node() 和 __check_special_anomlay()这几个函数就是用来检查这个的。 总之,被continue跳过的Buff一定自带label或是其他的特殊判定条件,并且和当前的检查对象——judge_obj不相符,导致它对当前检测对象无法生效。 """ - if not __check_activation_origin( - buff_obj=buff_obj, - judge_obj=judge_obj, - sim_instance=sim_instance, - char_name=char_name, - ): + if not __check_activation_origin(buff_obj=buff_obj, judge_obj=judge_obj, sim_instance=sim_instance, char_name=char_name): continue - if isinstance(judge_obj, SkillNode) and not __check_skill_node(buff_obj, judge_obj): + if isinstance(judge_obj, SkillNode) and not __check_skill_node( + buff_obj, judge_obj + ): continue if isinstance(judge_obj, AnomalyBar) and not __check_special_anomly( buff_obj, judge_obj @@ -89,7 +87,9 @@ def cal_buff_total_bonus( for key, value in buff_obj.effect_dct.items(): # 如果键值对在动态语句字典中,则累加值,否则初始化并赋值 try: - dynamic_statement[key] = dynamic_statement.get(key, 0) + value * count + dynamic_statement[key] = ( + dynamic_statement.get(key, 0) + value * count + ) except TypeError: continue # effect_buff_list.append(buff_obj) @@ -171,25 +171,36 @@ def __check_skill_node(buff: "Buff", skill_node: "SkillNode") -> bool: # return True # else: # print(skill_node.skill_tag, skill_labels, _sub_label, label_value) - elif __check_label_key(label_key=label_key, target_label_key="only_trigger_buff_level"): + elif __check_label_key( + label_key=label_key, target_label_key="only_trigger_buff_level" + ): if skill_node.skill.trigger_buff_level in label_value: # print(f"{buff.ft.index}对技能{skill_tag}成功生效!") return True - elif __check_label_key(label_key=label_key, target_label_key="only_back_attack"): + elif __check_label_key( + label_key=label_key, target_label_key="only_back_attack" + ): from zsim.sim_progress.RandomNumberGenerator import RNG rng: RNG = buff.sim_instance.rng_instance normalized_value = rng.random_float() if normalized_value <= BACK_ATTACK_RATE: return True - elif __check_label_key(label_key=label_key, target_label_key="only_element"): + elif __check_label_key( + label_key=label_key, target_label_key="only_element" + ): from zsim.define import ELEMENT_EQUIVALENCE_MAP for _ele_type in label_value: - if skill_node.element_type in ELEMENT_EQUIVALENCE_MAP[_ele_type]: + if ( + skill_node.element_type + in ELEMENT_EQUIVALENCE_MAP[_ele_type] + ): # 只要找到一种符合要求的元素,就返回True return True - elif __check_label_key(label_key=label_key, target_label_key="only_skill_type"): + elif __check_label_key( + label_key=label_key, target_label_key="only_skill_type" + ): if skill_node.skill.skill_type in label_value: return True else: @@ -243,11 +254,10 @@ def __check_special_anomly(buff: "Buff", anomaly_node: "AnomalyBar") -> bool: FrostAnomaly, EtherAnomaly, ElectricAnomaly, - AuricInkAnomaly, - ) + AuricInkAnomaly) # 定义允许的标签类型 - ALLOW_LABELS = ["only_anomaly"] + ALLOW_LABELS = ["only_anomaly", "specified_disorder_element_type"] # 定义异常状态类型映射字典 SELECT_ANOMALY_MAP = { "Disorder": [Disorder], @@ -261,8 +271,7 @@ def __check_special_anomly(buff: "Buff", anomaly_node: "AnomalyBar") -> bool: EtherAnomaly, ElectricAnomaly, AuricInkAnomaly, - NewAnomaly, - ], + NewAnomaly] } # 获取buff的标签列表 buff_labels: dict[str, list[str] | str] = buff.ft.label @@ -277,30 +286,48 @@ def __check_special_anomly(buff: "Buff", anomaly_node: "AnomalyBar") -> bool: continue # 检查是否为允许的标签类型 if label_key in ALLOW_LABELS: - # 输入为单个字符串 - if isinstance(label_value, str): - if label_value in SELECT_ANOMALY_MAP.keys(): - for sig_value in SELECT_ANOMALY_MAP[label_value]: - if isinstance(anomaly_node, sig_value): - # buff.sim_instance.schedule_data.change_process_state() - # print(f"{ELEMENT_TYPE_MAPPING[anomaly_node.element_type]}属性的{type(anomaly_node).__name__}对象成功与{buff.ft.index}匹配") - return True - - # 输入为列表 - if isinstance(label_value, list): - for checked_value in label_value: - if checked_value in SELECT_ANOMALY_MAP.keys(): - for sig_value in SELECT_ANOMALY_MAP[checked_value]: + if label_key == "only_anomaly": # 特定异常类型的判断 + # 输入为单个字符串 + if isinstance(label_value, str): + if label_value in SELECT_ANOMALY_MAP.keys(): + for sig_value in SELECT_ANOMALY_MAP[label_value]: if isinstance(anomaly_node, sig_value): # buff.sim_instance.schedule_data.change_process_state() # print(f"{ELEMENT_TYPE_MAPPING[anomaly_node.element_type]}属性的{type(anomaly_node).__name__}对象成功与{buff.ft.index}匹配") return True + + # 输入为列表 + if isinstance(label_value, list): + for checked_value in label_value: + if checked_value in SELECT_ANOMALY_MAP.keys(): + for sig_value in SELECT_ANOMALY_MAP[checked_value]: + if isinstance(anomaly_node, sig_value): + # buff.sim_instance.schedule_data.change_process_state() + # print(f"{ELEMENT_TYPE_MAPPING[anomaly_node.element_type]}属性的{type(anomaly_node).__name__}对象成功与{buff.ft.index}匹配") + return True + elif label_key == "specified_disorder_element_type": # 制定元素类型的紊乱判断 + # 首先,它得是个紊乱或是极性紊乱 + if not isinstance(anomaly_node, Disorder | PolarityDisorder): + continue + if isinstance(label_value, int): + if anomaly_node.element_type == label_value: + # buff.sim_instance.schedule_data.change_process_state() + # print(f"【测试】{ELEMENT_TYPE_MAPPING[anomaly_node.element_type]}属性的{type(anomaly_node).__name__}对象成功与{buff.ft.index}匹配") + return True + if isinstance(label_value, list): + for checked_value in label_value: + if checked_value == anomaly_node.element_type: + # buff.sim_instance.schedule_data.change_process_state() + # print(f"【测试】{ELEMENT_TYPE_MAPPING[anomaly_node.element_type]}属性的{type(anomaly_node).__name__}对象成功与{buff.ft.index}匹配") + return True + else: + buff.sim_instance.schedule_data.change_process_state() + print(f"【data_analyzer警告】识别到暂无处理逻辑的标签类型:{label_key},故当前buff{buff.ft.index}无法对对象{type(anomaly_node).__name__}生效") + return False return False -def __check_activation_origin( - buff_obj: "Buff", judge_obj: "SkillNode | AnomalyBar", sim_instance: "Simulator", char_name: str -): +def __check_activation_origin(buff_obj: "Buff", judge_obj: "SkillNode | AnomalyBar", sim_instance: "Simulator", char_name: str): """检查buff的label是否存在“only_active_by”,然后再检查当前被检项目与源头是否匹配。 - buff_obj: 被检查的buff - judge_obj: 被检查的对象,可能是SkillNode或者异常""" @@ -310,7 +337,6 @@ def __check_activation_origin( return True from zsim.sim_progress.Preload import SkillNode from zsim.sim_progress.anomaly_bar import AnomalyBar - CID_list = buff_obj.ft.label.get("only_active_by") # FIXME: 当队伍中同时存在两把“时流贤者”时,Buff源检验可能会出错,暂不确定。 if CID_list[0] == "self": @@ -321,7 +347,7 @@ def __check_activation_origin( 举例:如果某把武器会给三名队友上一个“自己触发的属性异常的伤害提升”的Buff,那么这里对比的就是触发源的角色以及当前buff的受益者。 所以这里的self指的是beneficiary """ - beneficiary = buff_obj.ft.beneficiary # Buff的实际受益者 + beneficiary = buff_obj.ft.beneficiary # Buff的实际受益者 if isinstance(judge_obj, SkillNode): skill_result = beneficiary == judge_obj.char_name return skill_result