+
-
`;
+ let $dps = $(html);
+
+ $dps.find('.dps__row-select').append(`
+
+ | `);
+
+ pmBase.content.build({
+ pages: [{
+ content: $dps,
+ }]
+ });
+
+ // setup vue
+ window.model = buildVueModel();
+ let vue_version = new Vue({
+ el: '#vue_version',
+ data: {
+ version: window.model.version,
+ }
+ });
+ window.vue_app = new Vue({
+ el: '#vue_app',
+ data: window.model,
+ methods: {
+ changeChar: function(event) {
+ this.resultView = calculate(this.charId);
+ if (this.resultView.rhodes) {
+ $("#mats_table").text("集成战略临时干员");
+ } else {
+ $("#mats_table").text("正在计算...");
+ beginCalcMats(this.resultView);
+ }
+ this.updateLevelingTable();
+ },
+ debugPrint: function(obj) {
+ //console.log(JSON.stringify(obj, null, 2));
+ return JSON.stringify(obj, null, 2);
+ },
+ goto: function(event) {
+ window.open(`../character/#!/${this.charId}`, '_blank');
+ },
+ godps: function(event) {
+ window.open(`../dps/#${this.charId}`, '_blank');
+ },
+ updateMats: function(result) {
+ let matsView = {};
+ let rv = this.resultView;
+ let pr = this.plannerResponse;
+
+ /*let costResult = calculateCost(this.charId, pr, this.resultView);
+ //this.test = costResult;
+ updateCostPlot(costResult, this.chartKey);
+*/
+ for (var sk in rv.skill) {
+ matsView[sk] = {title: rv.skill[sk]};
+ matsView[sk].list = [];
+ for (var lv in pr[sk]) {
+ var items = [];
+ for (var x in pr[sk][lv].mats) {
+ // items.push(` ${x} × ${pr[sk][lv].mats[x]}`);
+ items.push(AKDATA.getItemBadge("MATERIAL", itemCache[x].id, pr[sk][lv].mats[x]));
+ }
+ matsView[sk].list.push([
+ `${lv}
${parseInt(lv)+1}`,
+ items,
+ pr[sk][lv].cost,
+ Math.round(pr[sk][lv].green),
+ // this.recom[sk][lv-7]
+ ]);
+ }
+ }
+ matsView["elite"] = {title: `精英化材料(不包含红票/龙门币)`};
+ matsView["elite"].list = [];
+ var resp = pr[`${rv.id}_elite`];
+ for (var lv in resp) {
+ var items = [];
+ for (var x in resp[lv].mats) {
+ // items.push(` ${x} × ${pr[sk][lv].mats[x]}`);
+ items.push(AKDATA.getItemBadge("MATERIAL", itemCache[x].id, resp[lv].mats[x]));
+ }
+ matsView["elite"].list.push([
+ `${parseInt(lv)-1}
${lv}`,
+ items,
+ resp[lv].cost,
+ Math.round(resp[lv].green)
+ ]);
+ }
+ // this.test = matsView;
+ let matsHtml = "";
+ for (var sk in matsView) {
+ matsHtml += pmBase.component.create({
+ type: 'list',
+ card: true,
+ title: `${matsView[sk].title}`,
+ // header: ['等级', '素材', '等效理智', '推荐等级(测试)'],
+ header: ['等级', '素材', '等效理智', "等效绿票(测试)"],
+ list: matsView[sk].list
+ });
+ }
+ $("#mats_table").html(matsHtml);
+
+ },
+ jobCallback: function() {
+ console.log("- all jobs finished");
+ console.timeEnd("calcMats");
+ this.updateMats(this.plannerResponse);
+ },
+ updateLevelingTable: function () {
+ var db = AKDATA.Data.character_table[this.charId];
+ var r = DefaultAttribute; $.extend(r, Stages["基准"]);
+ var ch0 = buildChar(this.charId, db.skills[0].skillId, r);
+ r.level = "max";
+ var ch1 = buildChar(this.charId, db.skills[0].skillId, r);
+ var a0 = AKDATA.attributes.getCharAttributes(ch0), a1 = AKDATA.attributes.getCharAttributes(ch1);
+
+ var gain = [(a1.maxHp - a0.maxHp)/a0.maxHp, (a1.atk - a0.atk)/a0.atk, (a1.def - a0.def)/a0.def];
+ var result = gain.map(x => (x*100).toFixed(1) + "%");
+ result.push(...LevelingCost[db.rarity + 1]);
+ //console.log(result);
+ //console.log(ch0, ch1);
+ //console.log(a0, a1);
+
+ let html = pmBase.component.create({
+ type: 'list',
+ card: false,
+ title: `升级属性提升(精二1级->满级)`,
+ header: ['HP', '攻击力', '防御力', '等效理智(按CE5/LS5计算)', '需要天数(按基建+自回体+月卡计算)'],
+ list: [result]
+ });
+ $("#level_table").html(html);
+ }
+ },
+ watch: {
+ resultView: function(_new, _old) {
+ let cv = buildChartView(_new, this.chartKey);
+ plot(cv);
+ },
+ chartKey: function(_new, _old) {
+ let cv = buildChartView(this.resultView, _new);
+ updatePlot(cv);
+ },
+ jobs: function(_new, _old) {
+ if (this.charId != "-" && this.jobs == 0)
+ this.jobCallback();
+ },
+ }
+ });
+
+}
+
+function buildChar(charId, skillId, recipe) {
+ let char = {
+ charId,
+ skillId,
+ phase: recipe.phase,
+ favor: recipe.favor,
+ potentialRank: recipe.potential,
+ skillLevel: recipe.skillLevel,
+ options: recipe.options
+ };
+
+ let db = AKDATA.Data.character_table[charId];
+ let skilldb = AKDATA.Data.skill_table[skillId];
+ let maxLevel = db.phases[recipe.phase].maxLevel;
+ if (recipe.level == "max" || recipe.level > maxLevel)
+ char.level = maxLevel;
+ else
+ char.level = recipe.level;
+ char.name = db.name;
+ char.skillName = skilldb.levels[char.skillLevel].name;
+ //console.log(char);
+ var _opts = AKDATA.Data.dps_options.char[charId];
+ if (checkSpecs(charId, "use_token_for_mastery") || checkSpecs(skillId, "use_token_for_mastery"))
+ char.options.token = true;
+ else char.options.token = false;
+ return char;
+}
+
+function calculate(charId) {
+ let db = AKDATA.Data.character_table[charId];
+ let itemdb = AKDATA.Data.item_table.items;
+ let recipe = DefaultAttribute;
+ let enemy = DefaultEnemy;
+ let stages = Stages;
+ let raidBuff = { atk: 0, atkpct: 0, ats: 0, cdr: 0, base_atk: 0, damage_scale: 0 };
+ let result = {}, mats = {};
+
+ // calculate dps for each recipe case.
+ db.skills.forEach(skill => {
+ var entry = {};
+ for (let st in stages) {
+ $.extend(recipe, stages[st]);
+ var ch = buildChar(charId, skill.skillId, recipe);
+ ch.dps = AKDATA.attributes.calculateDps(ch, enemy, raidBuff);
+ entry[st] = ch;
+ };
+ result[skill.skillId] = entry;
+
+ mats[skill.skillId] = skill.levelUpCostCond.map(x => x.levelUpCost);
+ });
+ mats[1] = db.phases[1].evolveCost;
+ mats[2] = db.phases[2].evolveCost;
+
+ // extract result, making it more readable
+ // name, skill, stage, damageType, avg, skill, skilldamage, cdr
+ let resultView = {
+ id: charId,
+ name: db.name,
+ skill: {},
+ stages: stages,
+ dps: {},
+ notes: {},
+ mats: {}
+ };
+ for (let k in result) {
+ resultView.skill[k] = result[k]["满潜"].skillName;
+ resultView.notes[k] = result[k]["满潜"].dps.note;
+ resultView.dps[k] = {};
+ for (let st in stages) {
+ var entry = result[k][st].dps;
+ resultView.dps[k][st] = {
+ damageType: entry.skill.damageType,
+ spType: entry.skill.spType,
+ dps: entry.globalDps,
+ hps: entry.globalHps,
+ s_dps: entry.skill.dps,
+ s_hps: entry.skill.hps,
+ s_dmg: entry.skill.totalDamage,
+ s_heal: entry.skill.totalHeal,
+ s_ssp: entry.skill.dur.startSp,
+ };
+ // console.log(k, st, entry.skill.dur.startSp);
+ };
+ resultView.mats[k] = [];
+ mats[k].forEach(level => {
+ var i = {};
+ if (level) {
+ level.forEach(x => {
+ var _n = itemdb[x.id].name.replace(" ", "");
+ i[_n] = x.count;
+ itemCache[_n] = {id: x.id, name: _n, rarity: itemdb[x.id].rarity};
+ });
+ resultView.mats[k].push(i);
+ }
+ else resultView["rhodes"] = true;
+ });
+ };
+
+ resultView.mats[`${charId}_elite`] = [];
+ for (let elite=1; elite<=2; elite+=1) {
+ if (mats[elite]) {
+ let m = {};
+ mats[elite].forEach(x => {
+ let _nm = itemdb[x.id].name.replace(" ", "");
+ if (_nm.includes("双芯片")) {
+ x.id -= 1;
+ _nm = itemdb[x.id].name.replace(" ", "");
+ // m["采购凭证"] = x.count * 90;
+ x.count *= 2;
+ }
+ itemCache[_nm] = { id: x.id, name: _nm, rarity: itemdb[x.id].rarity };
+ m[_nm] = x.count;
+ });
+ resultView.mats[`${charId}_elite`].push(m);
+ }
+ }
+
+ // console.log(window.vue_app.debugPrint(resultView.mats));
+ return resultView;
+}
+
+const HealKeys = {
+ dps: "hps",
+ s_dps: "s_hps",
+ s_dmg: "s_heal"
+};
+
+// calculate() -> resultView -> build(key) -> chartView -> plot()
+function buildChartView(resultView, key) {
+ // rotate data for plot columns
+ let view = resultView;
+ let k = key;
+ let columns = [], groups = [], skill_names = [], notes = [];
+ var last = {};
+ for (let stg in view.stages) {
+ var entry = [stg];
+ for (let skill in view.skill) {
+ k = (view.dps[skill][stg].damageType == 2) ? HealKeys[key] : key;
+ var value = view.dps[skill][stg][k];
+ if (skill in last)
+ entry.push((value - last[skill]).toFixed(2));
+ else
+ entry.push(value.toFixed(2));
+ last[skill] = value;
+ }
+ columns.push(entry);
+ groups.push(stg);
+ }
+ var x = 0.02, i = 0;
+ for (let skill in view.skill) {
+ skill_names.push(view.skill[skill]);
+ let line = view.notes[skill];
+
+ if (view.dps[skill]["满潜"].spType != 8) {
+ if (line != "") line += "\n";
+ line += `启动技力 ${view.dps[skill]["基准"].s_ssp}s -> ${view.dps[skill]["满潜"].s_ssp}s`;
+ console.log(view.dps[skill]["满潜"].spType);
+ if (view.dps[skill]["满潜"].s_ssp <= 0)
+ line += " (落地点火)";
+ }
+ notes.push({x: x, y: 20, content: line});
+ x+=1;
+ }
+ // console.log(columns, groups, skill_names, notes);
+
+ return { columns, groups, skill_names, notes };
+}
+
+function plot(chartView) {
+ if (!window.chart) window.chart = {};
+ window.chart["chart"] = c3.generate({
+ bindto: "#chart",
+ size: { height: 400 },
+ data: {
+ type: "bar",
+ columns: [],
+ groups: [chartView.groups],
+ order: null,
+ },
+ axis: {
+ rotated: true,
+ x: {
+ type: "category",
+ categories: chartView.skill_names
+ },
+ y: {
+ tick: { fit: false },
+ }
+ },
+ bar: {
+ width: { ratio: 0.4 }
+ },
+ stanford: {
+ texts: chartView.notes
+ },
+ grid: {
+ y: { show: true }
+ },
+ zoom: { enabled: false },
+ color: {
+ pattern: [ "#cccccc", "#4169e1", "#ff7f50", "#ffd700", "#dc143c", "#ee82ee", "#e6e6fa" ]
+ }
+ });
+
+ window.chart["chart"].load({ columns: chartView.columns });
+ setTimeout(function() {
+ $(".c3-chart-bar.c3-target-基准").css("opacity", 0.4);
+ }, 100);
+}
+
+function updatePlot(chartView) {
+ window.chart["chart"].load({ columns: chartView.columns, groups: chartView.groups });
+ setTimeout(function() {
+ $(".c3-chart-bar.c3-target-基准").css("opacity", 0.4);
+ }, 200);
+}
+
+// use ajax post to invoke ArkPlanner
+// use vue var as semaphore to cooperate requests
+// when all request jobs are done (jobs == 0), the vue watch invokes jobDoneCallback()
+function beginCalcMats(resultView) {
+ console.time("calcMats");
+ window.vue_app.jobs = Object.keys(resultView.mats).length * 3 - 1; // semaphore
+ var delay = 300;
+
+ for (var sk in resultView.mats) {
+ let level = 7; // 7->8
+ if (sk.includes("elite")) level = 1;
+ resultView.mats[sk].forEach(m => {
+ if (Object.keys(m).length > 0) {
+ // arkplanner - 理智算法
+ (function (_m, _s, _l) { // closure to bind args to setTimeout
+ setTimeout(function () {
+ queryArkPlanner(_m, matsCallback, {mats: _m, id: resultView.id, skill: _s, level: _l});
+ }, delay);
+ }(m, sk, level));
+ }
+ level += 1; delay += 300;
+ });
+ }
+ }
+
+function matsCallback(result, kwargs) {
+ // 绿票算法
+ var greenTable = AKDATA.Data.green;
+ var greenCost = [0, ...Object.keys(kwargs.mats)].reduce((sum, x) => sum + greenTable[x] * kwargs.mats[x]);
+
+ if (!window.vue_app.plannerResponse[kwargs.skill])
+ window.vue_app.plannerResponse[kwargs.skill] = {};
+// window.vue_app.plannerResponse[kwargs.skill][`${kwargs.level}`] = { mats: kwargs.mats, result: result };
+ window.vue_app.plannerResponse[kwargs.skill][`${kwargs.level}`] = { mats: kwargs.mats, cost: result.cost, green: greenCost };
+
+ if (kwargs.id == window.vue_app.charId) // filter old (slow) calls
+ window.vue_app.jobs -= 1;
+}
+/*
+function calculateCost(charId, masteryCost, resultView) {
+ let result = {};
+ let db = AKDATA.Data.character_table[charId];
+ let costdb = AKDATA.Data.leveling_cost;
+ var perLevelSanity = costdb.map((x, idx) => (idx==0) ? 0 : x - costdb[idx-1]);
+
+ let recipe = DefaultAttribute;
+ let enemy = DefaultEnemy;
+ let stages = [];
+ let raidBuff = { atk: 0, atkpct: 0, ats: 0, cdr: 0, base_atk: 0, damage_scale: 0 };
+
+ var chartView = buildChartView(resultView, "s_dps");
+ var i=0;
+ // calculate dps for each recipe case.
+ db.skills.forEach(skill => {
+ var entry = [];
+ stages = [...CostStages];
+ // calculate efficiency. base: 0, level: 1, m1:2, m2:3, m3:4, skill:i+1
+ var base = chartView.columns[0][i+1];
+ var mc = masteryCost[skill.skillId];
+ var perLevelGain = chartView.columns[1][i+1] / base / (db.rarity * 10 + 39); // per level dps gain rate
+ var mg = [2, 3, 4].map(x => chartView.columns[x][i+1] / base); // mastery dps gain rate
+ mg[1] += mg[0];
+ mg[2] += mg[1]; // accumulate
+
+ var perLevelEffInv = perLevelSanity.map(x => x / perLevelGain); // inverse of efficiency
+ var masteryEffInv = [mc[7].cost, mc[7].cost + mc[8].cost, mc[7].cost + mc[8].cost + mc[9].cost].map((x, idx) => x / mg[idx]);
+ var recom = masteryEffInv.map(x => perLevelEffInv.findIndex(y => y > x)).map(x => (x <= 0) ? (db.rarity*10+40) : x);
+ recom[2] = Math.min(80, recom[2]);
+ recom[1] = Math.min(recom[1]+5, recom[2]); // tweak result
+ recom[0] = Math.min(recom[0]+5, recom[1]);
+ // console.log(perLevelEffInv, masteryEffInv);
+ //console.log(recom);
+ window.vue_app.recom[skill.skillId] = recom;
+
+ // set stages
+ var j=1;
+ for (var k=0; k<3; ++k) {
+ // if (k==0 || recom[k] > recom[k-1]) {
+ // stages.splice(j, 0, { level: recom[k], desc: `2${recom[k]}${k+7}` }); ++j;
+ // }
+ stages.splice(j, 0, { level: recom[k], skillLevel: k+7, desc: `2${recom[k]}${k+8}` }); ++j;
+ }
+ if (recom[2] < 60)
+ stages.splice(j, 0, {level: 60, desc: "26010"}); ++j;
+
+ //console.log(stages);
+ // calculate stage dps
+ stages.forEach(st => {
+ var item = {};
+ if (!(st.level == 80 && db.rarity < 5)) {
+ $.extend(recipe, st);
+ var ch = buildChar(charId, skill.skillId, recipe);
+ ch.dps = AKDATA.attributes.calculateDps(ch, enemy, raidBuff);
+
+ item = {
+ desc: st.desc,
+ dps: ch.dps.globalDps,
+ hps: ch.dps.globalHps,
+ s_dps: ch.dps.skill.dps,
+ s_hps: ch.dps.skill.hps,
+ s_dmg: ch.dps.skill.totalDamage,
+ s_heal: ch.dps.skill.totalHeal,
+ levelingCost: costdb[ch.level - 1],
+ damageType: ch.dps.skill.damageType,
+ skillName: ch.skillName
+ };
+
+ let mcost = 0, slv = ch.skillLevel;
+ while (slv > 6) {
+ mcost += masteryCost[skill.skillId][slv].cost;
+ --slv;
+ }
+ item.masteryCost = mcost;
+
+ entry.push(item);
+ }
+ });
+ result[skill.skillId] = entry;
+ i+=1;
+ });
+ return result;
+}
+
+function updateCostPlot(result, chartKey) {
+ $("#cost_chart").html("");
+ var idx = 1;
+ Object.keys(result).forEach(key => {
+ var idstr = `skill_${idx}`;
+ $("#cost_chart").append(`
+
+
${result[key][0].skillName} - DPS提升与理智消耗
+
+
`);
+ var ck = chartKey;
+ if (result[key][0].damageType == 2) ck = HealKeys[chartKey];
+ let x_arr = result[key].map(x => x.desc);
+ let dps_arr = result[key].map(x => x[ck]);
+ let cost_arr = result[key].map(x => x.masteryCost + x.levelingCost);
+ $(`#${idstr}`).append(window.vue_app.debugPrint({x_arr, dps_arr, cost_arr}));
+ window.chart[idstr] = c3.generate({
+ bindto: `#${idstr}`,
+ size: { height: 400 },
+ data: {
+ columns: [
+ ["dps", ...dps_arr],
+ ["理智消耗", ...cost_arr]
+ ],
+ axes: {
+ dps: "y",
+ "理智消耗": "y2"
+ }
+ },
+ axis: {
+ x: {
+ type: "category",
+ categories: x_arr,
+ },
+ y: {
+ min: dps_arr[0],
+ padding: 0,
+ label: { text: chartKey, position: 'outer-middle' }
+ },
+ y2: {
+ show: true,
+ min: 0,
+ // max: cost_arr[cost_arr.length-1],
+ padding: 0,
+ label: { text: "理智消耗", position: 'outer-middle' }
+ }
+ },
+ tooltip: {
+ format: { value: function(value, ratio, id) {
+ if (id == "dps") return `${value.toFixed(1)} (${(value * 100 / dps_arr[dps_arr.length-1]).toFixed(1)}%)`;
+ else return Math.round(value);
+ } }
+ },
+ grid: {
+ y: { show: true }
+ },
+ zoom: { enabled: false },
+ });
+
+ ++idx;
+ });
+}
+*/
+pmBase.hook.on('init', init);
diff --git a/_docs/whatsnew.md b/_docs/whatsnew.md
index 8a78e477..a769fd4b 100644
--- a/_docs/whatsnew.md
+++ b/_docs/whatsnew.md
@@ -5,8 +5,12 @@ order: 4
category: 工具
icon: info-circle
---
-## 21.05.27
+## 21.05.27-31
- [dps] 新版选人菜单测试
+- [dps] 切换类技能(银灰2,山2)统一按永续类计算
+- [mastery] 专精收益计算器改版。全面修改为无需后台工作的绿票算法
+- [mastery] 去除了部分图表,增加了精二材料计算和收益饼图
+- [fix] 修正异客3持续时间,凯尔希3增加误差说明
## 21.05.02 2周年版本
- [update] 浊心斯卡蒂等
diff --git a/resources/akdata.css b/resources/akdata.css
index f962dc6b..c4a55016 100644
--- a/resources/akdata.css
+++ b/resources/akdata.css
@@ -72,4 +72,10 @@ h5 {
strong {
font-weight: 600!important;
-}
\ No newline at end of file
+}
+
+.img_char {
+ /* box-shadow: 3px 3px 7px -1px rgb(0 0 0 / 85%); */
+ border-radius: 5px;
+}
+
\ No newline at end of file
diff --git a/resources/akdata.js b/resources/akdata.js
index ecae978b..4d0b5e2c 100644
--- a/resources/akdata.js
+++ b/resources/akdata.js
@@ -46,7 +46,7 @@ window.AKDATA = {
let path = `https://cdn.jsdelivr.net/gh/xulai1001/akdata@${window.AKDATA.akdata}/resources/gamedata/${paths[i].toLowerCase()}`;
// custom json data: always use local copy
- if (!paths[i].includes("excel")) // 本地调试开关
+ // if (!paths[i].includes("excel")) // 本地调试开关
path = `../resources/gamedata/${paths[i].toLowerCase()}?_=${Math.round(Math.random()*1e8)}`;
console.log(`Loading -> ${name}`);
paths[i] = loadJSON(path, data => AKDATA.Data[name] = data);
@@ -156,7 +156,7 @@ window.AKDATA = {
// console.log(charPools);
let html = "";
- Object.keys(charPools).forEach(k => {
+ ["新干员", ...Object.values(AKDATA.professionNames)].forEach(k => {
let entry = `
${k}
`;
charPools[k].sort((a, b) => b.rarity - a.rarity).forEach(x => {
entry += `
${x.name}`;
diff --git a/resources/attributes.js b/resources/attributes.js
index 0d99dfd9..eafcab5b 100644
--- a/resources/attributes.js
+++ b/resources/attributes.js
@@ -1343,12 +1343,7 @@ function calcDurations(isSkill, attackTime, attackSpeed, levelData, buffList, bu
else log.writeNote(`技能前摇: ${t.toFixed(3)}s`);
}
// 技能类型
- if (checkSpecs(skillId, "toggle")) {
- attackCount = Math.ceil(30 / attackTime);
- duration = 30;
- tags.push("toggle");
- log.writeNote("切换类技能 (以30s为参考计算)");
- } else if (levelData.description.includes("持续时间无限")) {
+ if (levelData.description.includes("持续时间无限") || checkSpecs(skillId, "toggle")) {
if (skillId == "skchr_thorns_3" && !options.warmup) {}
else if (skillId == "skchr_tuye_2") {
log.writeNote("取技能时间=暖机时间");
@@ -1363,7 +1358,11 @@ function calcDurations(isSkill, attackTime, attackSpeed, levelData, buffList, bu
} else {
attackCount = Math.ceil(1800 / attackTime);
duration = attackCount * attackTime;
- tags.push("infinity"); log.writeNote("持续时间无限 (记为1800s)");
+ if (checkSpecs(skillId, "toggle")) {
+ log.writeNote("切换类技能 (记为1800s)"); tags.push("toggle");
+ } else {
+ log.writeNote("持续时间无限 (记为1800s)"); tags.push("infinity");
+ }
}
} else if (spData.spType == 8) {
if (levelData.duration <= 0 && blackboard.duration > 0) {
@@ -1582,11 +1581,6 @@ function calcDurations(isSkill, attackTime, attackSpeed, levelData, buffList, bu
attackCount = Math.ceil(attackDuration / attackTime);
duration = attackDuration;
log.write(`[特殊] ${displayNames["tachr_400_weedy_2"]}: 使用${m+1}个水炮, 充能sp=${m * 6 + c}`);
- } else if (checkSpecs(skillId, "toggle")) {
- attackCount = Math.ceil(30 / attackTime);
- duration = 30;
- tags.push("toggle");
- //log.writeNote("切换类技能 (以30s为参考计算)");
}
break;
// todo: cast time
diff --git a/resources/customdata/dps_specialtags.json b/resources/customdata/dps_specialtags.json
index 770380c3..d9633c5b 100644
--- a/resources/customdata/dps_specialtags.json
+++ b/resources/customdata/dps_specialtags.json
@@ -119,7 +119,7 @@
"skchr_kafka_2": { "reset_attack": true },
"skchr_kalts_1": { "token_damage_type": "0" },
"skchr_kalts_2": { "token_damage_type": "0", "use_token_for_mastery": true },
- "skchr_kalts_3": { "damage_type": 2, "token_damage_type": 3, "grad": true, "use_token_for_mastery": true },
+ "skchr_kalts_3": { "damage_type": 2, "token_damage_type": 3, "grad": true, "use_token_for_mastery": true, "note": "每击伤害为估算平均值,实际会偏高" },
"skchr_kroos_1": { "sim": true },
"skchr_lava2_2": { "sec": true, "note": "不重叠部分伤害减半" },
"skchr_lionhd_2": { "reset_attack": "ogcd", "cast_time": 32 },
@@ -145,6 +145,7 @@
"skchr_nian_2": { "reflect": true },
"skchr_nightm_1": { "damage_type": 1 },
"skchr_pasngr_1": { "sim": true },
+ "skchr_pasngr_3": { "cast_time": 120 },
"skchr_peacok_1": { "sim": true },
"skchr_peacok_2": { "cast_time": 45, "frame_corr": -15, "damage_type": "0" },
"skchr_phatom_2": { "grad": true },
diff --git a/resources/customdata/green.json b/resources/customdata/green.json
new file mode 100644
index 00000000..e30d8da3
--- /dev/null
+++ b/resources/customdata/green.json
@@ -0,0 +1,98 @@
+{
+ "源岩": 1.275,
+ "固源岩": 5.108,
+ "固源岩组": 25.000,
+ "提纯源岩": 94.724,
+ "代糖": 2.542,
+ "糖": 7.635,
+ "糖组": 30.000,
+ "糖聚块": 124.724,
+ "双酮": 2.958,
+ "酮凝集": 8.885,
+ "酮凝集组": 35.000,
+ "酮阵列": 124.724,
+ "异铁碎片": 2.958,
+ "异铁": 8.885,
+ "异铁组": 35.000,
+ "异铁块": 139.724,
+ "破损装置": 3.792,
+ "装置": 11.385,
+ "全新装置": 45.000,
+ "改量装置": 129.724,
+ "酯原料": 2.542,
+ "聚酸酯": 7.635,
+ "聚酸酯组": 30.000,
+ "聚酸酯块": 119.724,
+ "轻锰矿": 35.000,
+ "三水锰矿": 124.724,
+ "扭转醇": 30.000,
+ "白马醇": 99.724,
+ "RMA70-12": 45.000,
+ "RMA70-24": 124.724,
+ "研磨石": 40.000,
+ "五水研磨石": 114.724,
+ "聚合剂": 337.714,
+ "双极纳米片": 307.714,
+ "D32钢": 342.714,
+ "炽合金": 35.000,
+ "炽合金块": 114.724,
+ "凝胶": 40.000,
+ "聚合凝胶": 104.724,
+ "晶体元件": 30.000,
+ "晶体电路": 129.724,
+ "晶体电子单元": 432.438,
+ "基础作战记录": 0.625,
+ "初级作战记录": 1.250,
+ "中级作战记录": 3.125,
+ "高级作战记录": 6.250,
+ "小芯片": 0.000,
+ "芯片组": 0.000,
+ "胶水": 160.000,
+ "双芯片": 250.000,
+ "技巧概要·卷1": 1.500,
+ "技巧概要·卷2": 4.500,
+ "技巧概要·卷3": 13.500,
+ "赤金": 1.250,
+ "龙门币": 0.005,
+ "采购凭证": 1.700,
+ "红票": 1.700,
+ "招聘许可": 15.000,
+ "合成玉": 0.903,
+ "六星信物": 1224.000,
+ "五星信物": 306.000,
+ "芯片助剂": 160.000,
+ "先锋双芯片": 250.000,
+ "先锋芯片组": 45.000,
+ "先锋芯片": 22.500,
+ "近卫双芯片": 250.000,
+ "近卫芯片组": 45.000,
+ "近卫芯片": 22.500,
+ "重装双芯片": 250.000,
+ "重装芯片组": 45.000,
+ "重装芯片": 22.500,
+ "狙击双芯片": 250.000,
+ "狙击芯片组": 45.000,
+ "狙击芯片": 22.500,
+ "术师双芯片": 250.000,
+ "术师芯片组": 45.000,
+ "术师芯片": 22.500,
+ "医疗双芯片": 250.000,
+ "医疗芯片组": 45.000,
+ "医疗芯片": 22.500,
+ "辅助双芯片": 250.000,
+ "辅助芯片组": 45.000,
+ "辅助芯片": 22.500,
+ "特种双芯片": 250.000,
+ "特种芯片组": 45.000,
+ "特种芯片": 22.500,
+ "碳": 0.000,
+ "至纯源石": 162.500,
+ "十连寻访凭证": 5416.667,
+ "寻访凭证": 541.667,
+ "应急理智合剂": 75.000,
+ "应急理智顶液": 125.000,
+ "黄票": 80.000,
+ "绿票": 1.000,
+ "体力": 1.250,
+ "理智": 1.250
+}
\ No newline at end of file