mirror of
https://github.com/ZZZure/ZZZ-Plugin.git
synced 2025-12-16 05:07:46 +00:00
重构更改面板评分规则
This commit is contained in:
parent
d594caaeb1
commit
b46537ea3d
15 changed files with 474 additions and 445 deletions
|
|
@ -368,25 +368,25 @@ export class ZZZAvatarInfo {
|
|||
|
||||
/** @type {'C'|'B'|'A'|'S'|'SS'|'SSS'|'ACE'|false} */
|
||||
get equip_comment() {
|
||||
if (this.equip_score < 45) {
|
||||
if (this.equip_score < 90) {
|
||||
return 'C';
|
||||
}
|
||||
if (this.equip_score <= 80) {
|
||||
if (this.equip_score < 120) {
|
||||
return 'B';
|
||||
}
|
||||
if (this.equip_score <= 115) {
|
||||
if (this.equip_score < 150) {
|
||||
return 'A';
|
||||
}
|
||||
if (this.equip_score <= 150) {
|
||||
if (this.equip_score < 170) {
|
||||
return 'S';
|
||||
}
|
||||
if (this.equip_score <= 185) {
|
||||
if (this.equip_score < 190) {
|
||||
return 'SS';
|
||||
}
|
||||
if (this.equip_score <= 220) {
|
||||
if (this.equip_score < 210) {
|
||||
return 'SSS';
|
||||
}
|
||||
if (this.equip_score > 220) {
|
||||
if (this.equip_score >= 210) {
|
||||
return 'ACE';
|
||||
}
|
||||
return false;
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
import _ from 'lodash';
|
||||
export var elementEnum;
|
||||
(function (elementEnum) {
|
||||
// 物理、火、冰、电、以太
|
||||
elementEnum[elementEnum["Physical"] = 0] = "Physical";
|
||||
elementEnum[elementEnum["Fire"] = 1] = "Fire";
|
||||
elementEnum[elementEnum["Ice"] = 2] = "Ice";
|
||||
|
|
@ -10,20 +9,17 @@ export var elementEnum;
|
|||
})(elementEnum || (elementEnum = {}));
|
||||
export var anomalyEnum;
|
||||
(function (anomalyEnum) {
|
||||
// 伤害异常
|
||||
anomalyEnum[anomalyEnum["\u5F3A\u51FB"] = 0] = "\u5F3A\u51FB";
|
||||
anomalyEnum[anomalyEnum["\u707C\u70E7"] = 1] = "\u707C\u70E7";
|
||||
anomalyEnum[anomalyEnum["\u788E\u51B0"] = 2] = "\u788E\u51B0";
|
||||
anomalyEnum[anomalyEnum["\u611F\u7535"] = 3] = "\u611F\u7535";
|
||||
anomalyEnum[anomalyEnum["\u4FB5\u8680"] = 4] = "\u4FB5\u8680";
|
||||
anomalyEnum[anomalyEnum["\u7D0A\u4E71"] = 5] = "\u7D0A\u4E71";
|
||||
// 状态异常(异常持续时间buff应作用于对应的状态异常)
|
||||
anomalyEnum[anomalyEnum["\u754F\u7F29"] = 6] = "\u754F\u7F29";
|
||||
anomalyEnum[anomalyEnum["\u971C\u5BD2"] = 7] = "\u971C\u5BD2";
|
||||
})(anomalyEnum || (anomalyEnum = {}));
|
||||
export var buffTypeEnum;
|
||||
(function (buffTypeEnum) {
|
||||
// 通用乘区
|
||||
buffTypeEnum[buffTypeEnum["\u653B\u51FB\u529B"] = 0] = "\u653B\u51FB\u529B";
|
||||
buffTypeEnum[buffTypeEnum["\u500D\u7387"] = 1] = "\u500D\u7387";
|
||||
buffTypeEnum[buffTypeEnum["\u589E\u4F24"] = 2] = "\u589E\u4F24";
|
||||
|
|
@ -32,30 +28,22 @@ export var buffTypeEnum;
|
|||
buffTypeEnum[buffTypeEnum["\u65E0\u89C6\u9632\u5FA1"] = 5] = "\u65E0\u89C6\u9632\u5FA1";
|
||||
buffTypeEnum[buffTypeEnum["\u7A7F\u900F\u503C"] = 6] = "\u7A7F\u900F\u503C";
|
||||
buffTypeEnum[buffTypeEnum["\u7A7F\u900F\u7387"] = 7] = "\u7A7F\u900F\u7387";
|
||||
// 直伤乘区
|
||||
buffTypeEnum[buffTypeEnum["\u66B4\u51FB\u7387"] = 8] = "\u66B4\u51FB\u7387";
|
||||
buffTypeEnum[buffTypeEnum["\u66B4\u51FB\u4F24\u5BB3"] = 9] = "\u66B4\u51FB\u4F24\u5BB3";
|
||||
// 异常乘区
|
||||
buffTypeEnum[buffTypeEnum["\u5F02\u5E38\u7CBE\u901A"] = 10] = "\u5F02\u5E38\u7CBE\u901A";
|
||||
buffTypeEnum[buffTypeEnum["\u5F02\u5E38\u589E\u4F24"] = 11] = "\u5F02\u5E38\u589E\u4F24";
|
||||
buffTypeEnum[buffTypeEnum["\u5F02\u5E38\u66B4\u51FB\u7387"] = 12] = "\u5F02\u5E38\u66B4\u51FB\u7387";
|
||||
buffTypeEnum[buffTypeEnum["\u5F02\u5E38\u66B4\u51FB\u4F24\u5BB3"] = 13] = "\u5F02\u5E38\u66B4\u51FB\u4F24\u5BB3";
|
||||
buffTypeEnum[buffTypeEnum["\u5F02\u5E38\u6301\u7EED\u65F6\u95F4"] = 14] = "\u5F02\u5E38\u6301\u7EED\u65F6\u95F4";
|
||||
// 其他属性,一般不直接影响伤害,但可能用于buff是否生效判断/转模
|
||||
buffTypeEnum[buffTypeEnum["\u751F\u547D\u503C"] = 15] = "\u751F\u547D\u503C";
|
||||
buffTypeEnum[buffTypeEnum["\u9632\u5FA1\u529B"] = 16] = "\u9632\u5FA1\u529B";
|
||||
buffTypeEnum[buffTypeEnum["\u51B2\u51FB\u529B"] = 17] = "\u51B2\u51FB\u529B";
|
||||
buffTypeEnum[buffTypeEnum["\u5F02\u5E38\u638C\u63A7"] = 18] = "\u5F02\u5E38\u638C\u63A7";
|
||||
})(buffTypeEnum || (buffTypeEnum = {}));
|
||||
let depth = 0, weakMapCheck = new WeakMap();
|
||||
/**
|
||||
* Buff管理器
|
||||
* 用于管理角色局内Buff
|
||||
*/
|
||||
export class BuffManager {
|
||||
avatar;
|
||||
buffs = [];
|
||||
/** 套装计数 */
|
||||
setCount = {};
|
||||
defaultBuff = {};
|
||||
constructor(avatar) {
|
||||
|
|
@ -66,7 +54,6 @@ export class BuffManager {
|
|||
buff.forEach(b => this.new(b));
|
||||
return this.buffs;
|
||||
}
|
||||
// 简化参数
|
||||
if (!buff.name && (buff.source || this.defaultBuff.source) === 'Set' && this.defaultBuff.name && typeof buff.check === 'number')
|
||||
buff.name = this.defaultBuff.name + buff.check;
|
||||
buff = _.merge({
|
||||
|
|
@ -91,7 +78,6 @@ export class BuffManager {
|
|||
}
|
||||
if (!buff.name || !buff.value || !buff.source || !buffTypeEnum[buffTypeEnum[buff.type]])
|
||||
return logger.warn('无效buff:', buff);
|
||||
// 武器buff职业检查
|
||||
if (buff.source === 'Weapon') {
|
||||
const professionCheck = (avatar) => {
|
||||
const weapon_profession = avatar.weapon?.profession;
|
||||
|
|
@ -119,27 +105,19 @@ export class BuffManager {
|
|||
if (buff.status === false)
|
||||
return false;
|
||||
const judge = (() => {
|
||||
// 未传入calc时不判断range、include、exclude
|
||||
if (typeof valueOcalc !== 'object' || Array.isArray(valueOcalc))
|
||||
return true;
|
||||
// buff指定排除该技能
|
||||
if (buff.exclude && buff.exclude.includes(valueOcalc.skill.type))
|
||||
return false;
|
||||
// 11 10 01
|
||||
if (buff.range || buff.include) {
|
||||
// 11 01 存在include且满足时则直接返回true
|
||||
if (buff.include && buff.include.includes(valueOcalc.skill.type))
|
||||
return true;
|
||||
// 01 没有range则代表只有include,直接返回false
|
||||
if (!buff.range)
|
||||
return false;
|
||||
// 11 10 直接返回range的结果即可
|
||||
const buffRange = buff.range;
|
||||
const skillRange = param.range?.filter(r => typeof r === 'string');
|
||||
if (!skillRange?.length)
|
||||
return true; // 对任意类型生效
|
||||
// buff作用范围向后覆盖
|
||||
// 存在重定向时,range须全匹配,redirect向后覆盖
|
||||
return true;
|
||||
else if (param.redirect) {
|
||||
if (skillRange.some(ST => buffRange.some(BT => BT === ST)))
|
||||
return true;
|
||||
|
|
@ -148,10 +126,8 @@ export class BuffManager {
|
|||
return true;
|
||||
return false;
|
||||
}
|
||||
// 不存在重定向时,range向后覆盖
|
||||
return skillRange.some(ST => buffRange.some(BT => ST.startsWith(BT)));
|
||||
}
|
||||
// 00
|
||||
return true;
|
||||
})();
|
||||
if (!judge)
|
||||
|
|
@ -161,14 +137,13 @@ export class BuffManager {
|
|||
continue;
|
||||
if (key === 'element') {
|
||||
if (!buff.element || !param.element)
|
||||
continue; // 对任意属性生效
|
||||
continue;
|
||||
if (Array.isArray(buff.element)) {
|
||||
if (buff.element.includes(param.element))
|
||||
continue;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
// @ts-ignore
|
||||
if (buff[key] !== param[key])
|
||||
return false;
|
||||
}
|
||||
|
|
@ -181,7 +156,6 @@ export class BuffManager {
|
|||
}
|
||||
else if (valueOcalc) {
|
||||
if (weakMapCheck.has(buff)) {
|
||||
// console.log(`depth:${depth} ${buff.name}:${weakMapCheck.get(buff)}`)
|
||||
if (!weakMapCheck.get(buff))
|
||||
return false;
|
||||
}
|
||||
|
|
@ -212,20 +186,16 @@ export class BuffManager {
|
|||
logger.error(e);
|
||||
}
|
||||
if (--depth === 0) {
|
||||
// console.log('重置weakMapCheck')
|
||||
weakMapCheck = new WeakMap();
|
||||
}
|
||||
return buffs;
|
||||
}
|
||||
filter(param, valueOcalc) {
|
||||
// @ts-ignore
|
||||
return this._filter(this.buffs, param, valueOcalc);
|
||||
}
|
||||
/** 遍历buff列表 */
|
||||
forEach(fnc) {
|
||||
return this.buffs.forEach(fnc);
|
||||
}
|
||||
/** 查找指定buff */
|
||||
find(type, value) {
|
||||
return this.buffs.find(buff => buff[type] === value);
|
||||
}
|
||||
|
|
@ -236,15 +206,9 @@ export class BuffManager {
|
|||
}
|
||||
});
|
||||
}
|
||||
/**
|
||||
* 关闭符合条件的所有buff
|
||||
*/
|
||||
close(type, value) {
|
||||
this.operator(type, value, buff => buff.status = false);
|
||||
}
|
||||
/**
|
||||
* 开启符合条件的所有buff
|
||||
*/
|
||||
open(type, value) {
|
||||
this.operator(type, value, buff => buff.status = true);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,7 +10,6 @@ export class Calculator {
|
|||
skills = [];
|
||||
cache = {};
|
||||
props = {};
|
||||
/** 当前正在计算的技能 */
|
||||
skill;
|
||||
defaultSkill = {};
|
||||
enemy;
|
||||
|
|
@ -72,7 +71,6 @@ export class Calculator {
|
|||
return dmg;
|
||||
}
|
||||
const props = this.props = skill.props || {};
|
||||
/** 缩小筛选范围 */
|
||||
const usefulBuffs = this.buffM.filter({
|
||||
element: skill.element,
|
||||
range: [skill.type],
|
||||
|
|
@ -163,7 +161,6 @@ export class Calculator {
|
|||
logger.debug('最终伤害:', result);
|
||||
if (!skill.banCache)
|
||||
this.cache[skill.type] = damage;
|
||||
// console.log(damage)
|
||||
return damage;
|
||||
}
|
||||
calc() {
|
||||
|
|
@ -188,20 +185,12 @@ export class Calculator {
|
|||
this.defaultSkill[param] = value;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* 获取技能等级
|
||||
* @param baseType 技能基类 'A', 'E', 'C', 'R', 'T', 'L'
|
||||
*/
|
||||
get_SkillLevel(baseType) {
|
||||
const id = ['A', 'E', 'C', 'R', , 'T', 'L'].indexOf(baseType);
|
||||
if (id === -1)
|
||||
return 1;
|
||||
return Number(this.avatar.skills.find(({ skill_type }) => skill_type === id)?.level || 1);
|
||||
}
|
||||
/**
|
||||
* 获取技能倍率
|
||||
* @param type 参见技能命名标准
|
||||
*/
|
||||
get_SkillMultiplier(type) {
|
||||
const SkillLevel = this.get_SkillLevel(type[0]);
|
||||
logger.debug(`${type[0]}等级:${SkillLevel}`);
|
||||
|
|
@ -220,7 +209,6 @@ export class Calculator {
|
|||
a = a.filter(({ sub_element_type }) => sub_element_type === this.avatar.sub_element_type);
|
||||
return a[0];
|
||||
}
|
||||
/** 获取属性异常倍率 */
|
||||
get_AnomalyMultiplier(skill, usefulBuffs, times = 0) {
|
||||
const anomalyData = this.get_AnomalyData(skill.type);
|
||||
if (!anomalyData)
|
||||
|
|
@ -234,7 +222,6 @@ export class Calculator {
|
|||
logger.debug(`倍率:${Multiplier}`);
|
||||
return Multiplier;
|
||||
}
|
||||
/** 获取紊乱倍率 */
|
||||
get_DiscoverMultiplier(skill) {
|
||||
const anomalyData = this.get_AnomalyData(skill.type);
|
||||
if (!anomalyData)
|
||||
|
|
@ -274,10 +261,6 @@ export class Calculator {
|
|||
default: return 0;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* 获取局内属性原始值
|
||||
* @param isRatio 是否支持buff.value为数值/字符串/数组类型且<1时按初始数值百分比提高处理
|
||||
*/
|
||||
get(type, initial, skill, usefulBuffs = this.buffM.buffs, isRatio = false) {
|
||||
return this.props[type] ??= this.buffM._filter(usefulBuffs, {
|
||||
element: skill?.element,
|
||||
|
|
@ -287,7 +270,7 @@ export class Calculator {
|
|||
}, this).reduce((previousValue, buff) => {
|
||||
const { value } = buff;
|
||||
let add = 0;
|
||||
if (isRatio && typeof value === 'number' && value < 1) { // 值小于1时,认为是百分比
|
||||
if (isRatio && typeof value === 'number' && value < 1) {
|
||||
add = value * initial;
|
||||
}
|
||||
else {
|
||||
|
|
@ -299,157 +282,131 @@ export class Calculator {
|
|||
return previousValue + add;
|
||||
}, initial);
|
||||
}
|
||||
/** 攻击力 */
|
||||
get_ATK(skill, usefulBuffs) {
|
||||
let ATK = this.get('攻击力', this.initial_properties.ATK, skill, usefulBuffs, true);
|
||||
ATK = Math.max(0, Math.min(ATK, 10000));
|
||||
logger.debug(`攻击力:${ATK}`);
|
||||
return ATK;
|
||||
}
|
||||
/** 额外倍率 */
|
||||
get_ExtraMultiplier(skill, usefulBuffs) {
|
||||
const ExtraMultiplier = this.get('倍率', 0, skill, usefulBuffs);
|
||||
ExtraMultiplier && logger.debug(`额外倍率:${ExtraMultiplier}`);
|
||||
return ExtraMultiplier;
|
||||
}
|
||||
/** 暴击率 */
|
||||
get_CRITRate(skill, usefulBuffs) {
|
||||
let CRITRate = this.get('暴击率', this.initial_properties.CRITRate, skill, usefulBuffs);
|
||||
CRITRate = Math.max(0, Math.min(CRITRate, 1));
|
||||
logger.debug(`暴击率:${CRITRate}`);
|
||||
return CRITRate;
|
||||
}
|
||||
/** 暴击伤害 */
|
||||
get_CRITDMG(skill, usefulBuffs) {
|
||||
let CRITDMG = this.get('暴击伤害', this.initial_properties.CRITDMG + 1, skill, usefulBuffs);
|
||||
CRITDMG = Math.max(0, Math.min(CRITDMG, 5));
|
||||
logger.debug(`暴击伤害:${CRITDMG}`);
|
||||
return CRITDMG;
|
||||
}
|
||||
/** 增伤区 */
|
||||
get_BoostArea(skill, usefulBuffs) {
|
||||
const BoostArea = this.get('增伤', 1, skill, usefulBuffs);
|
||||
logger.debug(`增伤区:${BoostArea}`);
|
||||
return BoostArea;
|
||||
}
|
||||
/** 易伤区 */
|
||||
get_VulnerabilityArea(skill, usefulBuffs) {
|
||||
const VulnerabilityArea = this.get('易伤', 1, skill, usefulBuffs);
|
||||
logger.debug(`易伤区:${VulnerabilityArea}`);
|
||||
return VulnerabilityArea;
|
||||
}
|
||||
/** 抗性区 */
|
||||
get_ResistanceArea(skill, usefulBuffs) {
|
||||
const ResistanceArea = this.get('无视抗性', 1 + this.enemy.resistance, skill, usefulBuffs);
|
||||
logger.debug(`抗性区:${ResistanceArea}`);
|
||||
return ResistanceArea;
|
||||
}
|
||||
/** 无视防御 */
|
||||
get_IgnoreDEF(skill, usefulBuffs) {
|
||||
const IgnoreDEF = this.get('无视防御', 0, skill, usefulBuffs);
|
||||
IgnoreDEF && logger.debug(`无视防御:${IgnoreDEF}`);
|
||||
return IgnoreDEF;
|
||||
}
|
||||
/** 穿透值 */
|
||||
get_Pen(skill, usefulBuffs) {
|
||||
let Pen = this.get('穿透值', this.initial_properties.Pen, skill, usefulBuffs);
|
||||
Pen = Math.max(0, Math.min(Pen, 1000));
|
||||
Pen && logger.debug(`穿透值:${Pen}`);
|
||||
return Pen;
|
||||
}
|
||||
/** 穿透率 */
|
||||
get_PenRatio(skill, usefulBuffs) {
|
||||
let PenRatio = this.get('穿透率', this.initial_properties.PenRatio, skill, usefulBuffs);
|
||||
PenRatio = Math.max(0, Math.min(PenRatio, 2));
|
||||
PenRatio && logger.debug(`穿透率:${PenRatio}`);
|
||||
return PenRatio;
|
||||
}
|
||||
/** 防御区 */
|
||||
get_DefenceArea(skill, usefulBuffs) {
|
||||
const get_base = (level) => Math.floor(0.1551 * Math.min(60, level) ** 2 + 3.141 * Math.min(60, level) + 47.2039);
|
||||
/** 等级基数 */
|
||||
const base = get_base(this.avatar.level);
|
||||
/** 基础防御 */
|
||||
const DEF = this.enemy.basicDEF / 50 * get_base(this.enemy.level);
|
||||
const IgnoreDEF = this.get_IgnoreDEF(skill, usefulBuffs);
|
||||
const Pen = this.get_Pen(skill, usefulBuffs);
|
||||
const PenRatio = this.get_PenRatio(skill, usefulBuffs);
|
||||
/** 防御 */
|
||||
const defence = DEF * (1 - IgnoreDEF);
|
||||
/** 有效防御 */
|
||||
const effective_defence = Math.max(0, defence * (1 - PenRatio) - Pen);
|
||||
const DefenceArea = base / (effective_defence + base);
|
||||
logger.debug(`防御区:${DefenceArea}`);
|
||||
return DefenceArea;
|
||||
}
|
||||
/** 等级区 */
|
||||
get_LevelArea(level = this.avatar.level) {
|
||||
const LevelArea = +(1 + 1 / 59 * (level - 1)).toFixed(4);
|
||||
logger.debug(`等级区:${LevelArea}`);
|
||||
return LevelArea;
|
||||
}
|
||||
/** 异常精通 */
|
||||
get_AnomalyProficiency(skill, usefulBuffs) {
|
||||
let AnomalyProficiency = this.get('异常精通', this.initial_properties.AnomalyProficiency, skill, usefulBuffs);
|
||||
AnomalyProficiency = Math.max(0, Math.min(AnomalyProficiency, 1000));
|
||||
logger.debug(`异常精通:${AnomalyProficiency}`);
|
||||
return AnomalyProficiency;
|
||||
}
|
||||
/** 异常精通区 */
|
||||
get_AnomalyProficiencyArea(skill, usefulBuffs) {
|
||||
const AnomalyProficiency = this.get_AnomalyProficiency(skill, usefulBuffs);
|
||||
const AnomalyProficiencyArea = AnomalyProficiency / 100;
|
||||
logger.debug(`异常精通区:${AnomalyProficiencyArea}`);
|
||||
return AnomalyProficiencyArea;
|
||||
}
|
||||
/** 异常增伤区 */
|
||||
get_AnomalyBoostArea(skill, usefulBuffs) {
|
||||
const AnomalyBoostArea = this.get('异常增伤', 1, skill, usefulBuffs);
|
||||
AnomalyBoostArea && logger.debug(`异常增伤区:${AnomalyBoostArea}`);
|
||||
return AnomalyBoostArea;
|
||||
}
|
||||
/** 异常暴击率 */
|
||||
get_AnomalyCRITRate(skill, usefulBuffs) {
|
||||
let AnomalyCRITRate = this.get('异常暴击率', 0, skill, usefulBuffs);
|
||||
AnomalyCRITRate = Math.max(0, Math.min(AnomalyCRITRate, 1));
|
||||
AnomalyCRITRate && logger.debug(`异常暴击率:${AnomalyCRITRate}`);
|
||||
return AnomalyCRITRate;
|
||||
}
|
||||
/** 异常暴击伤害 */
|
||||
get_AnomalyCRITDMG(skill, usefulBuffs) {
|
||||
let AnomalyCRITDMG = this.get('异常暴击伤害', 1, skill, usefulBuffs);
|
||||
AnomalyCRITDMG = Math.max(0, Math.min(AnomalyCRITDMG, 5));
|
||||
AnomalyCRITDMG && logger.debug(`异常暴击伤害:${AnomalyCRITDMG}`);
|
||||
return AnomalyCRITDMG;
|
||||
}
|
||||
/** 异常持续时间 */
|
||||
get_AnomalyDuration(skill, usefulBuffs, duration = 0) {
|
||||
const AnomalyDuration = +this.get('异常持续时间', duration, skill, usefulBuffs).toFixed(1);
|
||||
logger.debug(`异常持续时间:${AnomalyDuration}`);
|
||||
return AnomalyDuration;
|
||||
}
|
||||
/** 生命值 */
|
||||
get_HP(skill, usefulBuffs) {
|
||||
let HP = this.get('生命值', this.initial_properties.HP, skill, usefulBuffs, true);
|
||||
HP = Math.max(0, Math.min(HP, 100000));
|
||||
logger.debug(`生命值:${HP}`);
|
||||
return HP;
|
||||
}
|
||||
/** 防御力 */
|
||||
get_DEF(skill, usefulBuffs) {
|
||||
let DEF = this.get('防御力', this.initial_properties.DEF, skill, usefulBuffs, true);
|
||||
DEF = Math.max(0, Math.min(DEF, 1000));
|
||||
logger.debug(`防御力:${DEF}`);
|
||||
return DEF;
|
||||
}
|
||||
/** 冲击力 */
|
||||
get_Impact(skill, usefulBuffs) {
|
||||
let Impact = this.get('冲击力', this.initial_properties.Impact, skill, usefulBuffs, true);
|
||||
Impact = Math.max(0, Math.min(Impact, 1000));
|
||||
logger.debug(`冲击力:${Impact}`);
|
||||
return Impact;
|
||||
}
|
||||
/** 异常掌控 */
|
||||
get_AnomalyMastery(skill, usefulBuffs) {
|
||||
let AnomalyMastery = this.get('异常掌控', this.initial_properties.AnomalyMastery, skill, usefulBuffs, true);
|
||||
AnomalyMastery = Math.max(0, Math.min(AnomalyMastery, 1000));
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@ export interface skill {
|
|||
*
|
||||
* 当为数组类型时(多类型共存),满足数组内其一类型即可,判断规则同上
|
||||
*/
|
||||
redirect?: string | string[]
|
||||
redirect?: string | string[] | anomaly[] | "追加攻击"[]
|
||||
/** 角色面板伤害统计中是否隐藏显示 */
|
||||
isHide?: boolean
|
||||
/** 禁用伤害计算cache */
|
||||
|
|
|
|||
95
model/damage/Score.js
Normal file
95
model/damage/Score.js
Normal file
|
|
@ -0,0 +1,95 @@
|
|||
import { baseValueData, scoreData } from '../../lib/score.js';
|
||||
import { idToName } from '../../lib/convert/property.js';
|
||||
import { getMapData } from '../../utils/file.js';
|
||||
var rarity;
|
||||
(function (rarity) {
|
||||
rarity[rarity["S"] = 0] = "S";
|
||||
rarity[rarity["A"] = 1] = "A";
|
||||
rarity[rarity["B"] = 2] = "B";
|
||||
})(rarity || (rarity = {}));
|
||||
const mainStats = getMapData('EquipMainStats');
|
||||
const subStats = Object.keys(baseValueData).map(Number);
|
||||
export default class Score {
|
||||
scoreData;
|
||||
equip;
|
||||
partition;
|
||||
userMainStat;
|
||||
constructor(charID, equip) {
|
||||
this.scoreData = scoreData[charID];
|
||||
this.equip = equip;
|
||||
this.partition = this.equip.equipment_type;
|
||||
this.userMainStat = this.equip.main_properties[0].property_id;
|
||||
}
|
||||
get_level_multiplier() {
|
||||
return (0.25 + +this.equip.level * 0.05) || 1;
|
||||
}
|
||||
get_rarity_multiplier() {
|
||||
switch (rarity[this.equip.rarity]) {
|
||||
case rarity.S:
|
||||
return 1;
|
||||
case rarity.A:
|
||||
return 2 / 3;
|
||||
case rarity.B:
|
||||
return 1 / 3;
|
||||
default:
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
get_max_count() {
|
||||
const subMaxStats = subStats
|
||||
.filter(p => p !== this.userMainStat && this.scoreData[p])
|
||||
.sort((a, b) => this.scoreData[b] - this.scoreData[a]).slice(0, 4);
|
||||
if (!subMaxStats.length)
|
||||
return 0;
|
||||
logger.debug(`[${this.partition}号位]理论副词条:` + subMaxStats.map(idToName).reduce((a, p, i) => a + `${p}*${this.scoreData[subMaxStats[i]].toFixed(2)} `, ''));
|
||||
let count = this.scoreData[subMaxStats[0]] * 6;
|
||||
subMaxStats.slice(1).forEach(p => count += this.scoreData[p] || 0);
|
||||
logger.debug(`[${this.partition}号位]理论词条数:${logger.blue(count)}`);
|
||||
return count;
|
||||
}
|
||||
get_actual_count() {
|
||||
let count = 0;
|
||||
for (const prop of this.equip.properties) {
|
||||
const propID = prop.property_id;
|
||||
const weight = this.scoreData[propID];
|
||||
if (weight) {
|
||||
logger.debug(`[${this.partition}号位]实际副词条:${idToName(propID)} ${logger.green(prop.count + 1)}*${weight}`);
|
||||
count += weight * (prop.count + 1);
|
||||
}
|
||||
}
|
||||
logger.debug(`[${this.partition}号位]实际词条数:${logger.blue(count)}`);
|
||||
return count;
|
||||
}
|
||||
get_score() {
|
||||
const rarity_multiplier = this.get_rarity_multiplier();
|
||||
const actual_count = this.get_actual_count();
|
||||
if (actual_count === 0 && this.partition <= 3) {
|
||||
return 12 * this.get_level_multiplier();
|
||||
}
|
||||
const max_count = this.get_max_count();
|
||||
if (max_count === 0)
|
||||
return 0;
|
||||
if (this.partition <= 3) {
|
||||
const score = actual_count / max_count * rarity_multiplier * 55;
|
||||
logger.debug(`[${this.partition}号位] ${logger.magenta(`${actual_count} / ${max_count} * ${rarity_multiplier} * 55 = ${score}`)}`);
|
||||
return score;
|
||||
}
|
||||
const mainMaxStat = mainStats[this.partition]
|
||||
.filter(p => this.scoreData[p])
|
||||
.sort((a, b) => this.scoreData[b] - this.scoreData[a])[0];
|
||||
const mainScore = (mainMaxStat ? 12 * (this.scoreData[this.userMainStat] || 0) / this.scoreData[mainMaxStat] : 12) * this.get_level_multiplier();
|
||||
const subScore = actual_count / max_count * 43;
|
||||
const score = (mainScore + subScore) * rarity_multiplier;
|
||||
logger.debug(`[${this.partition}号位] ${logger.magenta(`(${mainScore} + ${subScore}) * ${rarity_multiplier} = ${score}`)}`);
|
||||
return score;
|
||||
}
|
||||
static main(charID, equip) {
|
||||
try {
|
||||
return new Score(charID, equip).get_score();
|
||||
}
|
||||
catch (err) {
|
||||
logger.error('角色驱动盘评分计算错误:', err);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
111
model/damage/Score.ts
Normal file
111
model/damage/Score.ts
Normal file
|
|
@ -0,0 +1,111 @@
|
|||
import type { Equip } from '../equip.js'
|
||||
import { baseValueData, scoreData } from '../../lib/score.js'
|
||||
import { idToName } from '../../lib/convert/property.js'
|
||||
import { getMapData } from '../../utils/file.js'
|
||||
|
||||
enum rarity { S, A, B }
|
||||
|
||||
/** 主词条可能属性 */
|
||||
const mainStats = getMapData('EquipMainStats') as { [partition: string]: number[] }
|
||||
/** 副词条可能属性 */
|
||||
const subStats = Object.keys(baseValueData).map(Number)
|
||||
|
||||
export default class Score {
|
||||
protected scoreData: typeof scoreData[string]
|
||||
protected equip: Equip
|
||||
/** 驱动盘n号位 */
|
||||
protected partition: number
|
||||
/** 用户主词条 */
|
||||
protected userMainStat: number
|
||||
constructor(charID: string, equip: Equip) {
|
||||
this.scoreData = scoreData[charID]
|
||||
this.equip = equip
|
||||
this.partition = this.equip.equipment_type
|
||||
this.userMainStat = this.equip.main_properties[0].property_id
|
||||
}
|
||||
|
||||
/** 等级倍率 */
|
||||
get_level_multiplier() {
|
||||
return (0.25 + +this.equip.level * 0.05) || 1
|
||||
}
|
||||
|
||||
/** 品质倍率 */
|
||||
get_rarity_multiplier() {
|
||||
switch (rarity[this.equip.rarity]) {
|
||||
case rarity.S:
|
||||
return 1
|
||||
case rarity.A:
|
||||
return 2 / 3
|
||||
case rarity.B:
|
||||
return 1 / 3
|
||||
default:
|
||||
return 1
|
||||
}
|
||||
}
|
||||
|
||||
/** 理论最大词条数 */
|
||||
get_max_count() {
|
||||
/** 权重最大的4个副词条 */
|
||||
const subMaxStats = subStats
|
||||
.filter(p => p !== this.userMainStat && this.scoreData[p])
|
||||
.sort((a, b) => this.scoreData[b] - this.scoreData[a]).slice(0, 4)
|
||||
if (!subMaxStats.length) return 0
|
||||
logger.debug(`[${this.partition}号位]理论副词条:` + subMaxStats.map(idToName).reduce((a, p, i) => a + `${p}*${this.scoreData[subMaxStats[i]].toFixed(2)} `, ''))
|
||||
let count = this.scoreData[subMaxStats[0]] * 6 // 权重最大副词条强化五次
|
||||
subMaxStats.slice(1).forEach(p => count += this.scoreData[p] || 0) // 其他词条各计入一次
|
||||
logger.debug(`[${this.partition}号位]理论词条数:${logger.blue(count)}`)
|
||||
return count
|
||||
}
|
||||
|
||||
/** 实际词条数 */
|
||||
get_actual_count() {
|
||||
let count = 0
|
||||
for (const prop of this.equip.properties) {
|
||||
const propID = prop.property_id
|
||||
const weight = this.scoreData[propID]
|
||||
if (weight) {
|
||||
logger.debug(`[${this.partition}号位]实际副词条:${idToName(propID)} ${logger.green(prop.count + 1)}*${weight}`)
|
||||
count += weight * (prop.count + 1)
|
||||
}
|
||||
}
|
||||
logger.debug(`[${this.partition}号位]实际词条数:${logger.blue(count)}`)
|
||||
return count
|
||||
}
|
||||
|
||||
/** 计算驱动盘得分 */
|
||||
get_score() {
|
||||
const rarity_multiplier = this.get_rarity_multiplier()
|
||||
const actual_count = this.get_actual_count()
|
||||
if (actual_count === 0 && this.partition <= 3) {
|
||||
// 1…1个有效副词条都没有吗?真是拿你没办法呢~给点主词条的分吧~❤️杂鱼~❤️杂鱼~❤️
|
||||
return 12 * this.get_level_multiplier()
|
||||
}
|
||||
const max_count = this.get_max_count()
|
||||
if (max_count === 0) return 0
|
||||
// 123号位
|
||||
if (this.partition <= 3) {
|
||||
const score = actual_count / max_count * rarity_multiplier * 55
|
||||
logger.debug(`[${this.partition}号位] ${logger.magenta(`${actual_count} / ${max_count} * ${rarity_multiplier} * 55 = ${score}`)}`)
|
||||
return score
|
||||
}
|
||||
// 456号位
|
||||
const mainMaxStat = mainStats[this.partition]
|
||||
.filter(p => this.scoreData[p])
|
||||
.sort((a, b) => this.scoreData[b] - this.scoreData[a])[0]
|
||||
const mainScore = (mainMaxStat ? 12 * (this.scoreData[this.userMainStat] || 0) / this.scoreData[mainMaxStat] : 12) * this.get_level_multiplier()
|
||||
const subScore = actual_count / max_count * 43
|
||||
const score = (mainScore + subScore) * rarity_multiplier
|
||||
logger.debug(`[${this.partition}号位] ${logger.magenta(`(${mainScore} + ${subScore}) * ${rarity_multiplier} = ${score}`)}`)
|
||||
return score
|
||||
}
|
||||
|
||||
static main(charID: string, equip: Equip) {
|
||||
try {
|
||||
return new Score(charID, equip).get_score()
|
||||
} catch (err) {
|
||||
logger.error('角色驱动盘评分计算错误:', err)
|
||||
return 0
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -14,7 +14,6 @@ const calcFnc = {
|
|||
set: {}
|
||||
};
|
||||
async function init() {
|
||||
// debug模式下监听文件变化
|
||||
const isWatch = await (async () => {
|
||||
try {
|
||||
return (await import('../../../../lib/config/config.js')).default.bot.log_level === 'debug';
|
||||
|
|
@ -86,7 +85,6 @@ async function importFile(type, name, isWatch = false) {
|
|||
}
|
||||
}
|
||||
await init();
|
||||
/** 角色计算 */
|
||||
export function avatar_ability(avatar) {
|
||||
const m = calcFnc.character[avatar.id];
|
||||
if (!m)
|
||||
|
|
@ -105,7 +103,6 @@ export function avatar_ability(avatar) {
|
|||
logger.debug(`Buff*${buffM.buffs.length}:`, buffM.buffs);
|
||||
return calc.calc();
|
||||
}
|
||||
/** 武器加成 */
|
||||
export function weapon_buff(weapon, buffM) {
|
||||
const name = weapon?.name;
|
||||
if (!name)
|
||||
|
|
@ -121,16 +118,13 @@ export function weapon_buff(weapon, buffM) {
|
|||
m.calc(buffM, weapon.star);
|
||||
buffM.default({});
|
||||
}
|
||||
/** 套装加成 */
|
||||
export function set_buff(equips, buffM) {
|
||||
buffM.default({ name: '', source: 'Set' });
|
||||
const setCount = {};
|
||||
for (const equip of equips) {
|
||||
if (equip.equipment_type == 5) {
|
||||
// 属伤加成
|
||||
const index = [31503, 31603, 31703, 31803, 31903].indexOf(equip.main_properties[0].property_id);
|
||||
if (index > -1 && elementEnum[index]) {
|
||||
// @ts-ignore
|
||||
buffM.new({
|
||||
name: '驱动盘5号位',
|
||||
type: '增伤',
|
||||
|
|
|
|||
|
|
@ -1,11 +1,11 @@
|
|||
import { property } from '../lib/convert.js';
|
||||
import { getSuitImage, getWeaponImage } from '../lib/download.js';
|
||||
import {
|
||||
getEquipPropertyBaseScore,
|
||||
getEquipPropertyEnhanceCount,
|
||||
getEquipPropertyScore,
|
||||
scoreData,
|
||||
hasScoreData,
|
||||
getEquipPropertyEnhanceCount
|
||||
} from '../lib/score.js';
|
||||
import Score from './damage/Score.js';
|
||||
|
||||
/**
|
||||
* @class
|
||||
|
|
@ -33,26 +33,10 @@ export class EquipProperty {
|
|||
this.property_name = property_name;
|
||||
this.property_id = property_id;
|
||||
this.base = base;
|
||||
/** @type {number | false} */
|
||||
this.score = false;
|
||||
|
||||
this.base_score = 0
|
||||
this.classname = property.idToClassName(property_id);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取属性分数
|
||||
* @param {string} charID
|
||||
* @returns {number}
|
||||
*/
|
||||
get_score(charID) {
|
||||
if (hasScoreData(charID)) {
|
||||
this.score = getEquipPropertyScore(charID, this.property_id, this.base);
|
||||
/** @type {number} */
|
||||
this.base_score = getEquipPropertyBaseScore(charID, this.property_id);
|
||||
}
|
||||
return this.score;
|
||||
}
|
||||
|
||||
/** @type {number} */
|
||||
get count() {
|
||||
return getEquipPropertyEnhanceCount(this.property_id, this.base);
|
||||
|
|
@ -87,25 +71,6 @@ export class EquipMainProperty {
|
|||
this.base = base;
|
||||
|
||||
this.classname = property.idToClassName(property_id);
|
||||
this.score = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取属性分数
|
||||
* @param {string} charID
|
||||
* @returns {number}
|
||||
*/
|
||||
get_score(charID) {
|
||||
/** @type {number} */
|
||||
const _score = getEquipPropertyBaseScore(
|
||||
charID,
|
||||
this.property_id,
|
||||
this.base
|
||||
);
|
||||
if (_score > 0) {
|
||||
this.score = 1;
|
||||
}
|
||||
return this.score;
|
||||
}
|
||||
|
||||
/** @type {string} */
|
||||
|
|
@ -167,7 +132,7 @@ export class Equip {
|
|||
this.name;
|
||||
/** @type {string} */
|
||||
this.icon;
|
||||
/** @type {string} */
|
||||
/** @type {'S'|'A'|'B'} */
|
||||
this.rarity;
|
||||
/** @type {EquipProperty[]} */
|
||||
this.properties;
|
||||
|
|
@ -226,46 +191,33 @@ export class Equip {
|
|||
*/
|
||||
get_score(charID) {
|
||||
if (hasScoreData(charID)) {
|
||||
this.score = this.properties.reduce(
|
||||
(acc, item) => acc + item.get_score(charID),
|
||||
0
|
||||
);
|
||||
const additional = this.main_properties.reduce(
|
||||
(acc, item) => acc + item.get_score(charID),
|
||||
0
|
||||
);
|
||||
if (this.equipment_type === 4) {
|
||||
this.score += 4.8 * additional;
|
||||
} else if (this.equipment_type === 5) {
|
||||
this.score += 9.6 * additional;
|
||||
} else if (this.equipment_type === 6) {
|
||||
this.score += 4.8 * additional;
|
||||
}
|
||||
this.properties.forEach(item => item.base_score = scoreData[charID][item.property_id] || 0);
|
||||
this.score = Score.main(charID, this);
|
||||
}
|
||||
return this.score;
|
||||
}
|
||||
|
||||
/** @type {'C'|'B'|'A'|'S'|'SS'|'SSS'|'ACE'|false} */
|
||||
get comment() {
|
||||
if (this.score < 10) {
|
||||
if (this.score <= 12) {
|
||||
return 'C';
|
||||
}
|
||||
if (this.score <= 15) {
|
||||
if (this.score < 20) {
|
||||
return 'B';
|
||||
}
|
||||
if (this.score <= 20) {
|
||||
if (this.score < 28) {
|
||||
return 'A';
|
||||
}
|
||||
if (this.score <= 25) {
|
||||
if (this.score < 32) {
|
||||
return 'S';
|
||||
}
|
||||
if (this.score <= 30) {
|
||||
if (this.score < 36) {
|
||||
return 'SS';
|
||||
}
|
||||
if (this.score <= 35) {
|
||||
if (this.score < 40) {
|
||||
return 'SSS';
|
||||
}
|
||||
if (this.score > 35) {
|
||||
if (this.score >= 40) {
|
||||
return 'ACE';
|
||||
}
|
||||
return false;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue