Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion zsim/data/APLData/柚叶-雅-薇薇安.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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 = [ "柚叶", "薇薇安", "雅",]
Expand Down
2 changes: 1 addition & 1 deletion zsim/data/buff_effect.csv
Original file line number Diff line number Diff line change
Expand Up @@ -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,,,,,,
Expand Down
2 changes: 1 addition & 1 deletion zsim/data/character_config_example.toml
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,7 @@ equip_set2_a = "激素朋克"
name = "薇薇安"
weapon = "飞鸟星梦"
weapon_level = 1
cinema = 6
cinema = 0
crit_balancing = true
scATK_percent = 5
scATK = 0
Expand Down
2 changes: 1 addition & 1 deletion zsim/data/skill.csv
Original file line number Diff line number Diff line change
Expand Up @@ -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,
2 changes: 1 addition & 1 deletion zsim/data/激活判断.csv
Original file line number Diff line number Diff line change
Expand Up @@ -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""]}",,
Expand Down
9 changes: 8 additions & 1 deletion zsim/define.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
225 changes: 225 additions & 0 deletions zsim/script/draw_anomaly_timeline.py
Original file line number Diff line number Diff line change
@@ -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()
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Loading
Loading