From c63a4368dc7e346ea3d841b4f30a09d9416ca94d Mon Sep 17 00:00:00 2001 From: daixiawu Date: Sat, 27 Jun 2026 00:11:05 +0800 Subject: [PATCH] Add dashboard hero upgrade estimates --- Tools/Dashboard/CHANGELOG.md | 6 + Tools/Dashboard/css/style.css | 106 +++++++ Tools/Dashboard/data/heroes.json | 511 ++++++++++++++++++++++++++++-- Tools/Dashboard/export_data.py | 35 ++ Tools/Dashboard/index.html | 37 +++ Tools/Dashboard/js/gamebalance.js | 441 ++++++++++++++++++++++++++ 6 files changed, 1101 insertions(+), 35 deletions(-) diff --git a/Tools/Dashboard/CHANGELOG.md b/Tools/Dashboard/CHANGELOG.md index 9ebdad836..55a1323b3 100644 --- a/Tools/Dashboard/CHANGELOG.md +++ b/Tools/Dashboard/CHANGELOG.md @@ -2,6 +2,12 @@ Dashboard 功能变更应在这里记录入口、数据源、接口和持久化位置,便于后续维护与迁移。 +## 2026-06-26 + +- `平衡性分析` 新增二级模块 `英雄升级`,读取当前 `HeroDataAssets` 英雄任务和 `UnitTypeDataAssets` 英雄基础数据,估算 Lv1->Lv2、Lv2->Lv3、Lv3->Lv4 所需回合数。 +- 新模块数据入口沿用 `GET /api/gamebalance/hero-data`,静态 fallback 使用 `data/units.json`、`data/skills.json`、`data/heroes.json`;估算逻辑在 `js/gamebalance.js` 内按任务类型与英雄特殊机制计算。 +- `export_data.py` 的 `heroes.json` 任务行追加 `skillParam`、`spType`、`skillList`、`unitFullTypes`、`targetBuff` 字段,供 Dashboard 分析模块识别更精确的任务目标。 + ## 2026-06-18 - 新增 `填表助手` 一级导航入口,当前包含 `Skill表` 二级栏。 diff --git a/Tools/Dashboard/css/style.css b/Tools/Dashboard/css/style.css index 2902bd85e..1f95aa051 100644 --- a/Tools/Dashboard/css/style.css +++ b/Tools/Dashboard/css/style.css @@ -5177,6 +5177,112 @@ body::after { color: var(--text-muted); } +/* Hero upgrade turn estimation */ +.gbhu-toolbar { + display: flex; + align-items: center; + justify-content: space-between; + gap: 12px; + margin-bottom: 10px; + flex-wrap: wrap; +} +.gbhu-model-note { + margin-bottom: 12px; + padding: 8px 10px; + border: 1px solid var(--border-color); + border-radius: 6px; + background: #f8fafc; + color: var(--text-secondary); + font-size: 12px; + line-height: 1.5; +} +.gbhu-table-shell { + display: flex; + flex-direction: column; +} +.gbhu-table-wrap { + overflow-x: auto; + border: 1px solid var(--border-color); + border-radius: 8px; +} +.gbhu-table { + min-width: 1180px; +} +.gbhu-table th, +.gbhu-table td { + vertical-align: top; +} +.gbhu-table thead th { + position: sticky; + top: 0; + z-index: 1; +} +.gbhu-force { + min-width: 120px; + font-size: 13px; + font-weight: 700; + color: var(--text-primary); +} +.gbhu-class { + margin-top: 2px; + color: var(--text-muted); + font-size: 11px; +} +.gbhu-est-cell { + width: 27%; + min-width: 260px; +} +.gbhu-est-head { + display: flex; + align-items: center; + justify-content: space-between; + gap: 8px; + margin-bottom: 4px; +} +.gbhu-turn { + color: #1f2937; + font-size: 15px; + font-weight: 800; + white-space: nowrap; +} +.gbhu-speed { + display: inline-flex; + align-items: center; + min-height: 20px; + padding: 1px 7px; + border-radius: 4px; + font-size: 11px; + font-weight: 750; + white-space: nowrap; +} +.gbhu-speed-fast { + background: rgba(16, 185, 129, 0.12); + color: #047857; +} +.gbhu-speed-normal { + background: rgba(59, 130, 246, 0.12); + color: #1d4ed8; +} +.gbhu-speed-slow { + background: rgba(245, 158, 11, 0.16); + color: #92400e; +} +.gbhu-speed-gated { + background: rgba(100, 116, 139, 0.14); + color: #475569; +} +.gbhu-task { + margin-bottom: 4px; + color: var(--text-primary); + font-size: 12px; + line-height: 1.45; +} +.gbhu-logic { + color: var(--text-secondary); + font-size: 12px; + line-height: 1.5; +} + /* Hero pricing model */ .gbhp-toolbar { display: flex; diff --git a/Tools/Dashboard/data/heroes.json b/Tools/Dashboard/data/heroes.json index 7d75e7364..db7c92c1b 100644 --- a/Tools/Dashboard/data/heroes.json +++ b/Tools/Dashboard/data/heroes.json @@ -7,18 +7,33 @@ { "taskContentType": 13, "param": 25, + "skillParam": 0, + "spType": 0, + "skillList": [], + "unitFullTypes": [], + "targetBuff": [], "skillName": "", "desc": "帝国累计获得**<{param}/{param}>**金币" }, { "taskContentType": 7, "param": 5, + "skillParam": 98, + "spType": 0, + "skillList": [], + "unitFullTypes": [], + "targetBuff": [], "skillName": "", "desc": "累计施加**<{param}/{param}>**次**<{param}>**" }, { "taskContentType": 7, "param": 20, + "skillParam": 98, + "spType": 0, + "skillList": [], + "unitFullTypes": [], + "targetBuff": [], "skillName": "", "desc": "累计施加**<{param}/{param}>**次**<{param}>**" } @@ -32,18 +47,33 @@ { "taskContentType": 22, "param": 2, + "skillParam": 0, + "spType": 0, + "skillList": [], + "unitFullTypes": [], + "targetBuff": [], "skillName": "", "desc": "我方占领2座村庄或1座敌方城市(**<{param}/{param}>**)" }, { "taskContentType": 8, "param": 5, + "skillParam": 103, + "spType": 0, + "skillList": [], + "unitFullTypes": [], + "targetBuff": [], "skillName": "", "desc": "累计创造**<{param}/{param}>**个月兔幻象" }, { "taskContentType": 7, "param": 40, + "skillParam": 82, + "spType": 0, + "skillList": [], + "unitFullTypes": [], + "targetBuff": [], "skillName": "", "desc": "累计施加**<{param}/{param}>**次**<{param}>**" } @@ -57,18 +87,33 @@ { "taskContentType": 21, "param": 2, + "skillParam": 0, + "spType": 0, + "skillList": [], + "unitFullTypes": [], + "targetBuff": [], "skillName": "", "desc": "帝国成员挖掘**<{param}/{param}>**处遗迹" }, { "taskContentType": 9, "param": 12, + "skillParam": 0, + "spType": 0, + "skillList": [], + "unitFullTypes": [], + "targetBuff": [], "skillName": "", "desc": "累计获得**<{param}/{param}>**点金币" }, { "taskContentType": 9, "param": 35, + "skillParam": 0, + "spType": 0, + "skillList": [], + "unitFullTypes": [], + "targetBuff": [], "skillName": "", "desc": "累计获得**<{param}/{param}>**点金币" } @@ -82,18 +127,33 @@ { "taskContentType": 5, "param": 50, + "skillParam": 0, + "spType": 0, + "skillList": [], + "unitFullTypes": [], + "targetBuff": [], "skillName": "", "desc": "累计探索**<{param}/{param}>**块迷雾区域" }, { "taskContentType": 3, "param": 20, + "skillParam": 103, + "spType": 0, + "skillList": [], + "unitFullTypes": [], + "targetBuff": [], "skillName": "", "desc": "累计提供**<{param}/{param}>**生命回复" }, { "taskContentType": 3, "param": 40, + "skillParam": 103, + "spType": 0, + "skillList": [], + "unitFullTypes": [], + "targetBuff": [], "skillName": "", "desc": "累计提供**<{param}/{param}>**生命回复" } @@ -107,18 +167,33 @@ { "taskContentType": 23, "param": 25, + "skillParam": 0, + "spType": 0, + "skillList": [], + "unitFullTypes": [], + "targetBuff": [], "skillName": "", "desc": "累计造成或承受**<{param}/{param}>**点伤害" }, { "taskContentType": 23, "param": 60, + "skillParam": 103, + "spType": 0, + "skillList": [], + "unitFullTypes": [], + "targetBuff": [], "skillName": "", "desc": "累计造成或承受**<{param}/{param}>**点伤害" }, { "taskContentType": 23, "param": 120, + "skillParam": 82, + "spType": 0, + "skillList": [], + "unitFullTypes": [], + "targetBuff": [], "skillName": "", "desc": "累计造成或承受**<{param}/{param}>**点伤害" } @@ -132,18 +207,33 @@ { "taskContentType": 13, "param": 25, + "skillParam": 0, + "spType": 0, + "skillList": [], + "unitFullTypes": [], + "targetBuff": [], "skillName": "", "desc": "帝国累计获得**<{param}/{param}>**金币" }, { "taskContentType": 12, "param": 10, + "skillParam": 0, + "spType": 1, + "skillList": [], + "unitFullTypes": [], + "targetBuff": [], "skillName": "", "desc": "累计创造**<{param}/{param}>**片红雾领地" }, { "taskContentType": 12, "param": 30, + "skillParam": 0, + "spType": 1, + "skillList": [], + "unitFullTypes": [], + "targetBuff": [], "skillName": "", "desc": "累计创造**<{param}/{param}>**片红雾领地" } @@ -157,18 +247,45 @@ { "taskContentType": 5, "param": 40, + "skillParam": 0, + "spType": 0, + "skillList": [], + "unitFullTypes": [], + "targetBuff": [], "skillName": "", "desc": "累计探索**<{param}/{param}>**块迷雾区域" }, { "taskContentType": 10, "param": 8, + "skillParam": 0, + "spType": 0, + "skillList": [ + 119, + 120, + 121, + 123, + 124 + ], + "unitFullTypes": [], + "targetBuff": [], "skillName": "", "desc": "累计消耗**<{param}/{param}>**颗魔力石" }, { "taskContentType": 10, "param": 24, + "skillParam": 0, + "spType": 0, + "skillList": [ + 119, + 120, + 121, + 123, + 124 + ], + "unitFullTypes": [], + "targetBuff": [], "skillName": "", "desc": "累计消耗**<{param}/{param}>**颗魔力石" } @@ -182,18 +299,33 @@ { "taskContentType": 5, "param": 50, + "skillParam": 0, + "spType": 0, + "skillList": [], + "unitFullTypes": [], + "targetBuff": [], "skillName": "", "desc": "累计探索**<{param}/{param}>**块迷雾区域" }, { "taskContentType": 0, "param": 25, + "skillParam": 0, + "spType": 0, + "skillList": [], + "unitFullTypes": [], + "targetBuff": [], "skillName": "", "desc": "累计承受**<{param}/{param}>**点伤害" }, { "taskContentType": 2, "param": 15, + "skillParam": 0, + "spType": 0, + "skillList": [], + "unitFullTypes": [], + "targetBuff": [], "skillName": "", "desc": "累计击杀**<{param}/{param}>**个敌方单位" } @@ -207,18 +339,33 @@ { "taskContentType": 22, "param": 2, + "skillParam": 0, + "spType": 0, + "skillList": [], + "unitFullTypes": [], + "targetBuff": [], "skillName": "", "desc": "我方占领2座村庄或1座敌方城市(**<{param}/{param}>**)" }, { "taskContentType": 2, "param": 10, + "skillParam": 0, + "spType": 0, + "skillList": [], + "unitFullTypes": [], + "targetBuff": [], "skillName": "", "desc": "累计击杀**<{param}/{param}>**个单位" }, { "taskContentType": 2, "param": 20, + "skillParam": 0, + "spType": 0, + "skillList": [], + "unitFullTypes": [], + "targetBuff": [], "skillName": "", "desc": "累计击杀**<{param}/{param}>**个单位" } @@ -232,18 +379,33 @@ { "taskContentType": 23, "param": 30, + "skillParam": 0, + "spType": 0, + "skillList": [], + "unitFullTypes": [], + "targetBuff": [], "skillName": "", "desc": "累计造成或承受**<{param}/{param}>**点伤害" }, { "taskContentType": 23, "param": 65, + "skillParam": 0, + "spType": 0, + "skillList": [], + "unitFullTypes": [], + "targetBuff": [], "skillName": "", "desc": "累计造成或承受**<{param}/{param}>**点伤害" }, { "taskContentType": 23, "param": 120, + "skillParam": 0, + "spType": 0, + "skillList": [], + "unitFullTypes": [], + "targetBuff": [], "skillName": "", "desc": "累计造成或承受**<{param}/{param}>**点伤害" } @@ -257,18 +419,33 @@ { "taskContentType": 14, "param": 5, + "skillParam": 0, + "spType": 0, + "skillList": [], + "unitFullTypes": [], + "targetBuff": [], "skillName": "", "desc": "已完成**<{param}/{param}>**科技的研发" }, { "taskContentType": 1, "param": 30, + "skillParam": 0, + "spType": 0, + "skillList": [], + "unitFullTypes": [], + "targetBuff": [], "skillName": "", "desc": "累计造成**<{param}/{param}>**点伤害" }, { "taskContentType": 1, "param": 70, + "skillParam": 0, + "spType": 0, + "skillList": [], + "unitFullTypes": [], + "targetBuff": [], "skillName": "", "desc": "累计造成**<{param}/{param}>**点伤害" } @@ -282,18 +459,76 @@ { "taskContentType": 20, "param": 40, + "skillParam": 0, + "spType": 0, + "skillList": [], + "unitFullTypes": [ + { + "unitType": 30, + "giantType": 0, + "unitLevel": 1 + }, + { + "unitType": 30, + "giantType": 0, + "unitLevel": 2 + }, + { + "unitType": 30, + "giantType": 0, + "unitLevel": 3 + }, + { + "unitType": 30, + "giantType": 0, + "unitLevel": 4 + }, + { + "unitType": 30, + "giantType": 0, + "unitLevel": 5 + }, + { + "unitType": 14, + "giantType": 12, + "unitLevel": 1 + } + ], + "targetBuff": [], "skillName": "", "desc": "累计探索**<{param}/{param}>**块迷雾区域" }, { "taskContentType": 15, "param": 1, + "skillParam": 0, + "spType": 0, + "skillList": [], + "unitFullTypes": [ + { + "unitType": 30, + "giantType": 0, + "unitLevel": 4 + } + ], + "targetBuff": [], "skillName": "", "desc": "拥有**<{param}/{param}>**御射宫司大人Lv.4" }, { "taskContentType": 16, "param": 15, + "skillParam": 0, + "spType": 0, + "skillList": [], + "unitFullTypes": [ + { + "unitType": 30, + "giantType": 0, + "unitLevel": 0 + } + ], + "targetBuff": [], "skillName": "", "desc": "御射宫司大人累积完成**<{param}/{param}>**击杀" } @@ -307,18 +542,38 @@ { "taskContentType": 5, "param": 50, + "skillParam": 0, + "spType": 0, + "skillList": [], + "unitFullTypes": [], + "targetBuff": [], "skillName": "", "desc": "累计探索**<{param}/{param}>**块迷雾区域" }, { "taskContentType": 7, "param": 30, + "skillParam": 162, + "spType": 0, + "skillList": [ + 162 + ], + "unitFullTypes": [], + "targetBuff": [], "skillName": "", "desc": "累计施加**<{param}/{param}>**次**<乘风>**" }, { "taskContentType": 17, "param": 3, + "skillParam": 0, + "spType": 0, + "skillList": [], + "unitFullTypes": [], + "targetBuff": [ + 0, + 3 + ], "skillName": "", "desc": "掷出**<大吉>**或**<大凶>**累计达**<{param}/{param}>**次" } @@ -332,18 +587,33 @@ { "taskContentType": 22, "param": 2, + "skillParam": 0, + "spType": 0, + "skillList": [], + "unitFullTypes": [], + "targetBuff": [], "skillName": "", "desc": "我方占领2座村庄或1座敌方城市(**<{param}/{param}>**)" }, { "taskContentType": 18, "param": 60, + "skillParam": 0, + "spType": 0, + "skillList": [], + "unitFullTypes": [], + "targetBuff": [], "skillName": "", "desc": "累计造成**<{param}/{param}>**点溅射伤害" }, { "taskContentType": 18, "param": 120, + "skillParam": 0, + "spType": 0, + "skillList": [], + "unitFullTypes": [], + "targetBuff": [], "skillName": "", "desc": "累计造成**<{param}/{param}>**点溅射伤害" } @@ -357,18 +627,33 @@ { "taskContentType": 23, "param": 25, + "skillParam": 0, + "spType": 0, + "skillList": [], + "unitFullTypes": [], + "targetBuff": [], "skillName": "", "desc": "累计造成或承受**<{param}/{param}>**点伤害" }, { "taskContentType": 23, "param": 60, + "skillParam": 0, + "spType": 0, + "skillList": [], + "unitFullTypes": [], + "targetBuff": [], "skillName": "", "desc": "累计造成或承受**<{param}/{param}>**点伤害" }, { "taskContentType": 23, "param": 120, + "skillParam": 0, + "spType": 0, + "skillList": [], + "unitFullTypes": [], + "targetBuff": [], "skillName": "", "desc": "累计造成或承受**<{param}/{param}>**点伤害" } @@ -382,18 +667,33 @@ { "taskContentType": 13, "param": 25, + "skillParam": 0, + "spType": 0, + "skillList": [], + "unitFullTypes": [], + "targetBuff": [], "skillName": "", "desc": "帝国累计获得**<{param}/{param}>**金币" }, { "taskContentType": 7, "param": 15, + "skillParam": 210, + "spType": 0, + "skillList": [], + "unitFullTypes": [], + "targetBuff": [], "skillName": "", "desc": "累计施加**<{param}/{param}>**次**<恐惧>**" }, { "taskContentType": 7, "param": 8, + "skillParam": 213, + "spType": 0, + "skillList": [], + "unitFullTypes": [], + "targetBuff": [], "skillName": "", "desc": "累计施加**<{param}/{param}>**次**<心理创伤>**" } @@ -407,18 +707,33 @@ { "taskContentType": 5, "param": 50, + "skillParam": 0, + "spType": 0, + "skillList": [], + "unitFullTypes": [], + "targetBuff": [], "skillName": "", "desc": "累计探索**<{param}/{param}>**块迷雾区域" }, { "taskContentType": 1, "param": 50, + "skillParam": 0, + "spType": 0, + "skillList": [], + "unitFullTypes": [], + "targetBuff": [], "skillName": "", "desc": "累计造成**<{param}/{param}>**点伤害" }, { "taskContentType": 1, "param": 100, + "skillParam": 0, + "spType": 0, + "skillList": [], + "unitFullTypes": [], + "targetBuff": [], "skillName": "", "desc": "累计造成**<{param}/{param}>**点伤害" } @@ -432,18 +747,33 @@ { "taskContentType": 22, "param": 2, + "skillParam": 0, + "spType": 0, + "skillList": [], + "unitFullTypes": [], + "targetBuff": [], "skillName": "", "desc": "我方占领2座村庄或1座敌方城市(**<{param}/{param}>**)" }, { "taskContentType": 23, "param": 50, + "skillParam": 0, + "spType": 0, + "skillList": [], + "unitFullTypes": [], + "targetBuff": [], "skillName": "", "desc": "累计造成或承受**<{param}/{param}>**点伤害" }, { "taskContentType": 23, "param": 100, + "skillParam": 0, + "spType": 0, + "skillList": [], + "unitFullTypes": [], + "targetBuff": [], "skillName": "", "desc": "累计造成或承受**<{param}/{param}>**点伤害" } @@ -457,18 +787,33 @@ { "taskContentType": 23, "param": 25, + "skillParam": 0, + "spType": 0, + "skillList": [], + "unitFullTypes": [], + "targetBuff": [], "skillName": "", "desc": "累计造成或承受**<{param}/{param}>**点伤害" }, { "taskContentType": 23, "param": 60, + "skillParam": 0, + "spType": 0, + "skillList": [], + "unitFullTypes": [], + "targetBuff": [], "skillName": "", "desc": "累计造成或承受**<{param}/{param}>**点伤害" }, { "taskContentType": 23, "param": 120, + "skillParam": 0, + "spType": 0, + "skillList": [], + "unitFullTypes": [], + "targetBuff": [], "skillName": "", "desc": "累计造成或承受**<{param}/{param}>**点伤害" } @@ -482,18 +827,39 @@ { "taskContentType": 5, "param": 50, + "skillParam": 0, + "spType": 0, + "skillList": [], + "unitFullTypes": [], + "targetBuff": [], "skillName": "", "desc": "累计探索**<{param}/{param}>**块迷雾区域" }, { "taskContentType": 7, "param": 12, + "skillParam": 217, + "spType": 0, + "skillList": [ + 217, + 252 + ], + "unitFullTypes": [], + "targetBuff": [], "skillName": "", "desc": "累计获得**<{param}/{param}>**层**<粗钝身>**或**<金刚身>**" }, { "taskContentType": 7, "param": 30, + "skillParam": 217, + "spType": 0, + "skillList": [ + 217, + 252 + ], + "unitFullTypes": [], + "targetBuff": [], "skillName": "", "desc": "累计获得**<{param}/{param}>**层**<粗钝身>**或**<金刚身>**" } @@ -505,22 +871,37 @@ "taskCount": 3, "tasks": [ { - "taskContentType": 23, + "taskContentType": 13, "param": 25, + "skillParam": 0, + "spType": 0, + "skillList": [], + "unitFullTypes": [], + "targetBuff": [], "skillName": "", - "desc": "累计造成或承受**<{param}/{param}>**点伤害" + "desc": "帝国累计获得**<{param}/{param}>**金币" }, { - "taskContentType": 23, - "param": 60, + "taskContentType": 1, + "param": 30, + "skillParam": 0, + "spType": 0, + "skillList": [], + "unitFullTypes": [], + "targetBuff": [], "skillName": "", - "desc": "累计造成或承受**<{param}/{param}>**点伤害" + "desc": "累计造成**<{param}/{param}>**点伤害" }, { - "taskContentType": 23, - "param": 120, + "taskContentType": 1, + "param": 70, + "skillParam": 0, + "spType": 0, + "skillList": [], + "unitFullTypes": [], + "targetBuff": [], "skillName": "", - "desc": "累计造成或承受**<{param}/{param}>**点伤害" + "desc": "累计造成**<{param}/{param}>**点伤害" } ] }, @@ -530,22 +911,37 @@ "taskCount": 3, "tasks": [ { - "taskContentType": 23, - "param": 25, + "taskContentType": 5, + "param": 40, + "skillParam": 0, + "spType": 0, + "skillList": [], + "unitFullTypes": [], + "targetBuff": [], "skillName": "", - "desc": "累计造成或承受**<{param}/{param}>**点伤害" + "desc": "探索**<{param}/{param}>**块迷雾" }, { - "taskContentType": 23, - "param": 60, + "taskContentType": 24, + "param": 4, + "skillParam": 0, + "spType": 0, + "skillList": [], + "unitFullTypes": [], + "targetBuff": [], "skillName": "", - "desc": "累计造成或承受**<{param}/{param}>**点伤害" + "desc": "设置**<{param}/{param}>**个灵异珠" }, { - "taskContentType": 23, - "param": 120, + "taskContentType": 24, + "param": 8, + "skillParam": 0, + "spType": 0, + "skillList": [], + "unitFullTypes": [], + "targetBuff": [], "skillName": "", - "desc": "累计造成或承受**<{param}/{param}>**点伤害" + "desc": "设置**<{param}/{param}>**个灵异珠" } ] }, @@ -555,22 +951,37 @@ "taskCount": 3, "tasks": [ { - "taskContentType": 23, - "param": 25, + "taskContentType": 5, + "param": 50, + "skillParam": 0, + "spType": 0, + "skillList": [], + "unitFullTypes": [], + "targetBuff": [], "skillName": "", - "desc": "累计造成或承受**<{param}/{param}>**点伤害" + "desc": "累计探索**<{param}/{param}>**块迷雾区域" }, { - "taskContentType": 23, - "param": 60, + "taskContentType": 8, + "param": 6, + "skillParam": 335, + "spType": 0, + "skillList": [], + "unitFullTypes": [], + "targetBuff": [], "skillName": "", - "desc": "累计造成或承受**<{param}/{param}>**点伤害" + "desc": "累计施加**<{param}/{param}>**次**<{param}>**" }, { - "taskContentType": 23, - "param": 120, + "taskContentType": 8, + "param": 12, + "skillParam": 335, + "spType": 0, + "skillList": [], + "unitFullTypes": [], + "targetBuff": [], "skillName": "", - "desc": "累计造成或承受**<{param}/{param}>**点伤害" + "desc": "累计施加**<{param}/{param}>**次**<{param}>**" } ] }, @@ -580,22 +991,37 @@ "taskCount": 3, "tasks": [ { - "taskContentType": 23, - "param": 25, + "taskContentType": 22, + "param": 2, + "skillParam": 0, + "spType": 0, + "skillList": [], + "unitFullTypes": [], + "targetBuff": [], "skillName": "", - "desc": "累计造成或承受**<{param}/{param}>**点伤害" + "desc": "我方占领2座村庄或1座敌方城市(**<{param}/{param}>**)" }, { - "taskContentType": 23, - "param": 60, + "taskContentType": 25, + "param": 10, + "skillParam": 330, + "spType": 0, + "skillList": [], + "unitFullTypes": [], + "targetBuff": [], "skillName": "", - "desc": "累计造成或承受**<{param}/{param}>**点伤害" + "desc": "在**<吽形石守>**状态下承受**<{param}/{param}>**次伤害" }, { - "taskContentType": 23, - "param": 120, + "taskContentType": 25, + "param": 20, + "skillParam": 330, + "spType": 0, + "skillList": [], + "unitFullTypes": [], + "targetBuff": [], "skillName": "", - "desc": "累计造成或承受**<{param}/{param}>**点伤害" + "desc": "在**<吽形石守>**状态下承受**<{param}/{param}>**次伤害" } ] }, @@ -607,18 +1033,33 @@ { "taskContentType": 23, "param": 25, + "skillParam": 0, + "spType": 0, + "skillList": [], + "unitFullTypes": [], + "targetBuff": [], "skillName": "", "desc": "累计造成或承受**<{param}/{param}>**点伤害" }, { "taskContentType": 23, "param": 60, + "skillParam": 0, + "spType": 0, + "skillList": [], + "unitFullTypes": [], + "targetBuff": [], "skillName": "", "desc": "累计造成或承受**<{param}/{param}>**点伤害" }, { "taskContentType": 23, "param": 120, + "skillParam": 0, + "spType": 0, + "skillList": [], + "unitFullTypes": [], + "targetBuff": [], "skillName": "", "desc": "累计造成或承受**<{param}/{param}>**点伤害" } diff --git a/Tools/Dashboard/export_data.py b/Tools/Dashboard/export_data.py index 54b1d29d5..b505f3d40 100644 --- a/Tools/Dashboard/export_data.py +++ b/Tools/Dashboard/export_data.py @@ -170,6 +170,36 @@ def parse_hex_int_list(hex_str): return result +def parse_int_list(value): + """Parse Unity int lists from either YAML arrays or packed hex strings.""" + if isinstance(value, list): + result = [] + for item in value: + if isinstance(item, dict): + continue + result.append(safe_int(item)) + return result + if isinstance(value, str): + return parse_hex_int_list(value) + return [] + + +def parse_unit_full_type_list(value): + """Normalize UnitFullType YAML list entries for dashboard consumers.""" + if not isinstance(value, list): + return [] + result = [] + for item in value: + if not isinstance(item, dict): + continue + result.append({ + "unitType": safe_int(item.get('UnitType')), + "giantType": safe_int(item.get('GiantType')), + "unitLevel": safe_int(item.get('UnitLevel')), + }) + return result + + def get_indent(line): """Get the indentation level of a line.""" return len(line) - len(line.lstrip(' ')) @@ -666,6 +696,11 @@ def export_heroes(): tasks.append({ "taskContentType": safe_int(task.get('taskContentType')), "param": safe_int(task.get('Param')), + "skillParam": safe_int(task.get('SkillParam')), + "spType": safe_int(task.get('SpType')), + "skillList": parse_int_list(task.get('SkillList')), + "unitFullTypes": parse_unit_full_type_list(task.get('UnitFullTypes', [])), + "targetBuff": parse_int_list(task.get('TargetBuff')), "skillName": skill_name, "desc": desc, }) diff --git a/Tools/Dashboard/index.html b/Tools/Dashboard/index.html index 123f2a13d..92f8c4ea0 100644 --- a/Tools/Dashboard/index.html +++ b/Tools/Dashboard/index.html @@ -1035,6 +1035,7 @@
+
@@ -1170,6 +1171,42 @@ + +
+
+
+ 英雄升级 + 未加载 +
+
+
+
+ 按当前 HeroDataAssets 任务配置估算每段升级大概需要的回合数,三段任务均按升级后从 0 重新累计处理。 +
+
+ + + +
+
+
+ 基础口径:金币 6/回合、探索 8格/回合、伤害 12点/回合、击杀 1.2个/回合、开遗迹约每2回合1处、主动/特殊技能约每回合1次;特殊任务按技能机制覆盖。 +
+
+
正在加载英雄升级估算...
+
+
+
+
+
diff --git a/Tools/Dashboard/js/gamebalance.js b/Tools/Dashboard/js/gamebalance.js index 25773fbeb..d6fe0b48f 100644 --- a/Tools/Dashboard/js/gamebalance.js +++ b/Tools/Dashboard/js/gamebalance.js @@ -141,6 +141,8 @@ let gbhpPricingData = null; // Latest balance modeling output let gbhpSort = 'finalDesc'; let gbhdData = null; // Static hero data from Dashboard export let gbhdRendered = false; +let gbhuData = null; // Hero upgrade turn estimation +let gbhuRendered = false; const GBHD_CLASS_ORDER = [1, 2, 3, 4, 5]; const GBHD_CLASS_NAMES = { @@ -162,6 +164,42 @@ const GBHD_ROW_SPECS = [ { key: 'skills', label: '技能', type: 'skills' }, ]; +const GBHU_TASK_TYPE_NAMES = { + 0: '累计承受伤害', + 1: '累计造成伤害', + 2: '累计击杀', + 3: '累计治疗', + 4: '开启遗迹', + 5: '探索迷雾', + 6: '占领城市', + 7: '增加技能层数', + 8: '技能生效', + 9: '帝金币收益', + 10: '技能掉层', + 11: '遇见玩家', + 12: '添加特殊地格', + 13: '帝国金币收益', + 14: '研发科技', + 15: '生产/拥有单位', + 16: '指定单位击杀', + 17: '御神签极端结果', + 18: '溅射伤害', + 19: '指定技能单位死亡', + 20: '指定单位探索', + 21: '帝国成员开遗迹', + 22: '占村/占城', + 23: '造成或承受伤害', + 24: '设置灵异珠', + 25: '阿吽石化承伤', +}; + +const GBHU_SPEED_LABELS = { + fast: '偏快', + normal: '常规', + slow: '偏慢', + gated: '门槛', +}; + // ── Init (lazy, called when panel activates) ── function gbInit() { @@ -183,6 +221,9 @@ function gbInit() { if (sub === 'gb-hero-data') { gbhdLoadData(); } + if (sub === 'gb-hero-upgrade') { + gbhuLoadData(); + } if (sub === 'gb-hero' && !gbhpPricingData) { gbhpLoadPricing(); } @@ -227,6 +268,9 @@ function gbInit() { if (document.getElementById('sub-gb-hero-data')?.classList.contains('active')) { gbhdLoadData(); } + if (document.getElementById('sub-gb-hero-upgrade')?.classList.contains('active')) { + gbhuLoadData(); + } } function wireFilterCheckbox(checkId, selectId) { @@ -1145,6 +1189,403 @@ function gbhdFormatNum(value) { return String(value).replace(/\.0$/, ''); } +// ════════════════════════════════════════════ +// Hero Upgrade Turn Estimation Sub-module +// ════════════════════════════════════════════ + +async function gbhuLoadData(forceReload = false) { + const table = document.getElementById('gbhu-upgrade-table'); + const badge = document.getElementById('gbhu-total-badge'); + if (!table) return; + + if (!forceReload && gbhuData) { + gbhuRender(); + return; + } + + table.innerHTML = '
正在读取英雄升级任务...
'; + if (badge) badge.textContent = '加载中'; + + try { + const payload = await gbhdFetchHeroPayload(); + const units = payload.units || []; + const skills = payload.skills || []; + const heroTasks = payload.heroes || []; + const baseData = gbhdBuildData(units, skills, heroTasks); + gbhuData = gbhuBuildData(baseData.heroes, skills); + gbhuInitFilters(); + gbhuRender(); + } catch (e) { + if (badge) badge.textContent = '读取失败'; + table.innerHTML = `
英雄升级估算读取失败: ${gbEscapeHtml(e.message)}
`; + } +} + +function gbhuBuildData(heroes, skills) { + const skillMap = new Map((skills || []).map(skill => [Number(skill.skillType), skill])); + const rows = []; + (heroes || []).forEach(hero => { + const estimates = [1, 2, 3].map((taskIndex, idx) => { + const fromLevel = idx + 1; + const task = hero.tasks?.[idx]; + return gbhuEstimateTask(hero, fromLevel, fromLevel + 1, task, skillMap); + }); + const searchText = [ + hero.heroName, + hero.giantName, + hero.forceName, + hero.forceNameLocal, + hero.civName, + hero.civNameLocal, + gbhdForceLabel(hero), + ...estimates.flatMap(est => [est.taskName, est.taskText, est.logic, est.turnText, est.speedLabel]), + ].filter(Boolean).join(' '); + rows.push({ ...hero, estimates, upgradeSearchText: searchText }); + }); + rows.sort((a, b) => { + const forceCmp = GBHD_FORCE_ORDER.indexOf(a.forceId) - GBHD_FORCE_ORDER.indexOf(b.forceId); + if (forceCmp !== 0) return forceCmp; + const classCmp = GBHD_CLASS_ORDER.indexOf(a.chessType) - GBHD_CLASS_ORDER.indexOf(b.chessType); + if (classCmp !== 0) return classCmp; + return (a.heroName || '').localeCompare(b.heroName || '', 'zh-Hans-CN'); + }); + return { heroes: rows }; +} + +function gbhuInitFilters() { + if (!gbhuData || gbhuRendered) return; + gbhuRendered = true; + + const forceSelect = document.getElementById('gbhu-force-filter'); + if (forceSelect) { + const forces = [...new Map(gbhuData.heroes.map(hero => [ + hero.forceName, + { forceName: hero.forceName, label: gbhdForceLabel(hero) }, + ])).values()] + .filter(force => force.forceName) + .sort((a, b) => a.label.localeCompare(b.label, 'zh-Hans-CN')); + forceSelect.insertAdjacentHTML('beforeend', forces + .map(force => ``) + .join('')); + forceSelect.addEventListener('change', gbhuRender); + } + + const speedSelect = document.getElementById('gbhu-speed-filter'); + if (speedSelect) speedSelect.addEventListener('change', gbhuRender); + + const search = document.getElementById('gbhu-search'); + if (search) search.addEventListener('input', gbhuRender); +} + +function gbhuRender() { + const table = document.getElementById('gbhu-upgrade-table'); + const badge = document.getElementById('gbhu-total-badge'); + if (!table || !gbhuData) return; + + const forceFilter = document.getElementById('gbhu-force-filter')?.value || ''; + const speedFilter = document.getElementById('gbhu-speed-filter')?.value || ''; + const query = (document.getElementById('gbhu-search')?.value || '').trim().toLowerCase(); + + const heroes = gbhuData.heroes.filter(hero => { + if (forceFilter && hero.forceName !== forceFilter) return false; + if (speedFilter && !hero.estimates.some(est => est.speed === speedFilter)) return false; + if (query && !hero.upgradeSearchText.toLowerCase().includes(query)) return false; + return true; + }); + + if (badge) badge.textContent = `${heroes.length}/${gbhuData.heroes.length} 英雄`; + if (heroes.length === 0) { + table.innerHTML = '
当前筛选条件下没有英雄升级估算
'; + return; + } + + table.innerHTML = `
+ + + + + + + + + + + + ${heroes.map(hero => gbhuRenderHeroRow(hero)).join('')} + +
帝国英雄Lv1 → Lv2Lv2 → Lv3Lv3 → Lv4
+
`; +} + +function gbhuRenderHeroRow(hero) { + return ` + +
${gbEscapeHtml(gbhdForceLabel(hero))}
+
${gbEscapeHtml(hero.className || '-')}
+ + +
+ ${gbEscapeHtml(hero.heroName || hero.giantName || '-')} + ${gbEscapeHtml(hero.giantName || '')} +
+ + ${hero.estimates.map(est => gbhuRenderEstimateCell(est)).join('')} + `; +} + +function gbhuRenderEstimateCell(est) { + return ` +
+ ${gbEscapeHtml(est.turnText)} + ${gbEscapeHtml(est.speedLabel)} +
+
${gbEscapeHtml(est.taskText)}
+
${gbEscapeHtml(est.logic)}
+ `; +} + +function gbhuEstimateTask(hero, fromLevel, toLevel, task, skillMap) { + if (!task) { + return gbhuEstimateResult(null, fromLevel, toLevel, 0, 0, 'gated', '没有配置任务,无法升级。', '无任务'); + } + + const taskType = Number(task.taskContentType); + const param = Number(task.param) || 0; + const taskName = GBHU_TASK_TYPE_NAMES[taskType] || `任务类型 ${taskType}`; + const taskText = gbhuTaskText(task, taskName, skillMap); + const special = gbhuSpecialEstimate(hero, fromLevel, toLevel, task, skillMap, taskName, taskText); + if (special) return special; + + const model = gbhuBaseModel(taskType, param); + return gbhuEstimateResult(task, fromLevel, toLevel, model.min, model.max, model.speed, model.logic, taskText, taskName); +} + +function gbhuSpecialEstimate(hero, fromLevel, toLevel, task, skillMap, taskName, taskText) { + const gt = Number(hero.giantType); + const taskType = Number(task.taskContentType); + const param = Number(task.param) || 0; + + if (gt === 6 && taskType === 7) { + const perTurn = fromLevel >= 3 ? 6 : 3; + const min = Math.ceil(param / perTurn); + const max = Math.ceil(param / Math.max(1, perTurn - 1)); + return gbhuEstimateResult(task, fromLevel, toLevel, min, max, 'normal', + `按辉夜每回合用永夜返给周围友军叠满月估算;Lv${fromLevel}常见每次影响${perTurn - 1}-${perTurn}个目标。`, + taskText, taskName); + } + + if (gt === 7 && taskType === 8) { + const min = Math.ceil(param / 1.5); + const max = Math.ceil(param / 1); + return gbhuEstimateResult(task, fromLevel, toLevel, min, max, 'normal', + '按铃仙每回合主动参战并靠幻视调率约1-1.5次有效创造幻象估算。', + taskText, taskName); + } + + if (gt === 7 && taskType === 7) { + const min = Math.ceil(param / 4); + const max = Math.ceil(param / 3); + return gbhuEstimateResult(task, fromLevel, toLevel, min, max, 'slow', + '按战地协同标的每回合约施加3-4层估算,需要持续围绕同一目标打配合。', + taskText, taskName); + } + + if (gt === 8 && taskType === 9) { + const min = Math.ceil(param / 4); + const max = Math.ceil(param / 3); + return gbhuEstimateResult(task, fromLevel, toLevel, min, max, 'normal', + '按帝每回合通过攻击、击杀或死亡收益约3-4金币估算;真实速度取决于能否持续找战斗。', + taskText, taskName); + } + + if (gt === 10 && taskType === 23) { + const min = Math.ceil(param / 16); + const max = Math.ceil(param / 12); + return gbhuEstimateResult(task, fromLevel, toLevel, min, max, 'normal', + '妹红既计造成也计承受伤害,按主动换血/自爆相关玩法每回合约12-16点累计估算。', + taskText, taskName); + } + + if (gt === 5 && taskType === 10) { + const perTurn = fromLevel >= 3 ? 6 : 4; + const min = Math.ceil(param / perTurn); + const max = Math.ceil(param / Math.max(1, perTurn - 1)); + return gbhuEstimateResult(task, fromLevel, toLevel, min, max, 'normal', + `按帕秋莉每回合消耗${perTurn - 1}-${perTurn}层魔力石估算,取决于能否连续攻击或治疗。`, + taskText, taskName); + } + + if (gt === 11 && taskType === 14) { + return gbhuEstimateResult(task, fromLevel, toLevel, 5, 7, 'gated', + '按前期完成5项科技估算:通常受科技节奏限制,约第5-7回合可达成。', + taskText, taskName); + } + + if (gt === 12 && taskType === 15) { + return gbhuEstimateResult(task, fromLevel, toLevel, 0, 1, 'gated', + '需要已有御射宫司大人Lv4。若神奈子已达Lv4基本可立即完成,否则完全受神奈子升级节奏锁定。', + taskText, taskName); + } + + if (gt === 12 && taskType === 16) { + const min = Math.ceil(param / 2); + const max = Math.ceil(param / 1); + return gbhuEstimateResult(task, fromLevel, toLevel, min, max, 'slow', + '按御射宫司大人每回合1-2次击杀估算;需要先有高等级蛇且持续参战。', + taskText, taskName); + } + + if (gt === 13 && taskType === 7) { + const perTurn = fromLevel >= 3 ? 6 : 4; + const min = Math.ceil(param / perTurn); + const max = Math.ceil(param / Math.max(1, perTurn - 2)); + return gbhuEstimateResult(task, fromLevel, toLevel, min, max, 'normal', + `按早苗每回合通过神风/治疗给友军施加乘风${perTurn - 2}-${perTurn}层估算。`, + taskText, taskName); + } + + if (gt === 13 && taskType === 17) { + const expectedActions = Math.ceil(param / 0.25); + return gbhuEstimateResult(task, fromLevel, toLevel, expectedActions, expectedActions + 3, 'slow', + '普通御神签大吉或大凶合计20%,且3次非极端后下次强制极端;按平均约4次行动出1次极端估算。', + taskText, taskName); + } + + if (gt === 14 && taskType === 18) { + const min = Math.ceil(param / 18); + const max = Math.ceil(param / 12); + return gbhuEstimateResult(task, fromLevel, toLevel, min, max, 'normal', + '按文的路径/踩踏溅射每回合约12-18点有效溅射伤害估算,敌方站位密集时偏快。', + taskText, taskName); + } + + if (gt === 16 && taskType === 7 && Number(task.skillParam) === 210) { + const min = Math.ceil(param / 5); + const max = Math.ceil(param / 3); + return gbhuEstimateResult(task, fromLevel, toLevel, min, max, 'normal', + '按觉每回合通过攻击/窥视等来源施加3-5层恐惧估算。', + taskText, taskName); + } + + if (gt === 16 && taskType === 7 && Number(task.skillParam) === 213) { + const min = Math.ceil(param / 2); + const max = Math.ceil(param / 1); + return gbhuEstimateResult(task, fromLevel, toLevel, min, max, 'slow', + '心理创伤来源更窄,按每回合1-2次有效施加估算。', + taskText, taskName); + } + + if (gt === 20 && taskType === 7) { + const min = Math.ceil(param / 5); + const max = Math.ceil(param / 3); + return gbhuEstimateResult(task, fromLevel, toLevel, min, max, 'normal', + '按燐通过收集尸骸并转化粗钝身/金刚身,每回合约3-5层估算。', + taskText, taskName); + } + + if (gt === 22 && taskType === 24) { + const min = Math.ceil(param / 1); + const max = Math.ceil(param / 0.8); + return gbhuEstimateResult(task, fromLevel, toLevel, min, max, 'normal', + '按堇子设置灵异珠每回合约1个估算;若需要走位找空地则取上限。', + taskText, taskName); + } + + if (gt === 24 && taskType === 25) { + const min = Math.ceil(param / 3); + const max = Math.ceil(param / 2); + return gbhuEstimateResult(task, fromLevel, toLevel, min, max, 'slow', + '按阿吽进入吽形石守后每回合承受2-3次有效伤害估算;需要主动让石化体吃火力。', + taskText, taskName); + } + + return null; +} + +function gbhuBaseModel(taskType, param) { + switch (Number(taskType)) { + case 0: + return gbhuModelFromRate(param, 10, 14, 'normal', '按英雄主动吃伤害,每回合约10-14点承伤估算。'); + case 1: + return gbhuModelFromRate(param, 10, 14, 'normal', '按英雄每回合一次有效攻击,约10-14点造成伤害估算。'); + case 2: + return gbhuModelFromRate(param, 1, 1.5, 'slow', '按英雄持续参战,每回合约1-1.5次击杀估算。'); + case 3: + return gbhuModelFromRate(param, 8, 12, 'normal', '按英雄每回合一次治疗或辅助治疗,约8-12点回复量估算。'); + case 4: + return gbhuModelFromRate(param, 0.4, 0.6, 'slow', '按英雄本人开遗迹,约每2回合1处估算。'); + case 5: + return gbhuModelFromRate(param, 7, 9, 'normal', '按探索型英雄每回合推进并揭开约7-9块迷雾估算。'); + case 7: + case 8: + return gbhuModelFromRate(param, 2, 4, 'normal', '按对应技能每回合约触发2-4层/次估算,实际取决于目标密度和行动点。'); + case 9: + case 13: + return gbhuModelFromRate(param, 5, 7, 'fast', '按帝国自然经济与战斗收益合计每回合约5-7金币估算。'); + case 10: + return gbhuModelFromRate(param, 3, 5, 'normal', '按每回合消耗或掉落3-5层目标技能估算。'); + case 12: + return gbhuModelFromRate(param, 1, 2, 'normal', '按每回合创建1-2个目标特殊地格估算。'); + case 14: + return gbhuModelFromRate(param, 0.8, 1.2, 'gated', '按科技节奏约每回合0.8-1.2项估算,受研究线限制。'); + case 15: + return gbhuModelFromRate(param, 0.8, 1.2, 'gated', '按目标单位生产/转化约每回合0.8-1.2个估算,受资源与前置单位限制。'); + case 16: + return gbhuModelFromRate(param, 1, 1.5, 'slow', '按指定单位每回合约1-1.5次击杀估算。'); + case 17: + return gbhuModelFromRate(param, 0.2, 0.25, 'slow', '按大吉/大凶约20%-25%出现率估算。'); + case 18: + return gbhuModelFromRate(param, 10, 14, 'normal', '按每回合约10-14点溅射伤害估算。'); + case 20: + return gbhuModelFromRate(param, 8, 10, 'normal', '按指定探索单位每回合揭开约8-10块迷雾估算。'); + case 21: + return gbhuModelFromRate(param, 0.5, 0.8, 'normal', '按帝国成员合计开遗迹,约每1-2回合1处估算。'); + case 22: + return gbhuModelFromRate(param, 0.6, 1, 'gated', '按占1城=2进度、占1村=1进度;前期通常约2-4回合完成。'); + case 23: + return gbhuModelFromRate(param, 12, 16, 'normal', '按英雄主动交战,造成或承受伤害合计每回合约12-16点估算。'); + case 24: + return gbhuModelFromRate(param, 0.8, 1, 'normal', '按每回合约设置0.8-1个目标物估算。'); + case 25: + return gbhuModelFromRate(param, 2, 3, 'slow', '按状态满足后每回合承受2-3次有效伤害估算。'); + default: + return gbhuModelFromRate(param, 1, 1, 'gated', '未知任务类型,暂按每回合1点进度粗估。'); + } +} + +function gbhuModelFromRate(param, lowRate, highRate, speed, logic) { + const min = Math.max(0, Math.ceil((Number(param) || 0) / Math.max(highRate, 0.01))); + const max = Math.max(min, Math.ceil((Number(param) || 0) / Math.max(lowRate, 0.01))); + return { min, max, speed, logic }; +} + +function gbhuEstimateResult(task, fromLevel, toLevel, min, max, speed, logic, taskText, taskName = '') { + const safeMin = Math.max(0, Math.ceil(min || 0)); + const safeMax = Math.max(safeMin, Math.ceil(max || safeMin)); + const turnText = safeMin === safeMax ? `${safeMin} 回合` : `${safeMin}-${safeMax} 回合`; + return { + fromLevel, + toLevel, + task, + taskName, + taskText, + minTurns: safeMin, + maxTurns: safeMax, + turnText, + speed, + speedLabel: GBHU_SPEED_LABELS[speed] || speed || '-', + logic, + }; +} + +function gbhuTaskText(task, taskName, skillMap) { + const desc = gbhdCleanMarkup(task?.desc || ''); + const param = Number(task?.param) || 0; + const skill = skillMap.get(Number(task?.skillParam)); + const suffix = skill?.name ? ` · ${skill.name}` : ''; + return `${taskName}${param ? ` ${param}` : ''}${suffix}${desc ? `|${desc}` : ''}`; +} + // ════════════════════════════════════════════ // Hero Pricing Model Sub-module // ════════════════════════════════════════════