mirror of
https://github.com/unanmed/HumanBreak.git
synced 2025-01-19 20:59:37 +08:00
完成临界计算
This commit is contained in:
parent
b9c1142d14
commit
3aea023562
@ -490,7 +490,10 @@ export class DamageEnemy<T extends EnemyIds = EnemyIds> {
|
|||||||
// 抱团
|
// 抱团
|
||||||
if (special.includes(8)) {
|
if (special.includes(8)) {
|
||||||
square5.push((e, enemy) => {
|
square5.push((e, enemy) => {
|
||||||
if (e.special.includes(8) && e.x !== this.x && this.y !== e.y) {
|
if (
|
||||||
|
e.special.includes(8) &&
|
||||||
|
(e.x !== this.x || this.y !== e.y)
|
||||||
|
) {
|
||||||
e.atkBuff += enemy.together ?? 0;
|
e.atkBuff += enemy.together ?? 0;
|
||||||
e.defBuff += enemy.together ?? 0;
|
e.defBuff += enemy.together ?? 0;
|
||||||
}
|
}
|
||||||
@ -657,38 +660,10 @@ export class DamageEnemy<T extends EnemyIds = EnemyIds> {
|
|||||||
hero: Partial<HeroStatus> = core.status.hero,
|
hero: Partial<HeroStatus> = core.status.hero,
|
||||||
dir: DamageDir | DamageDir[]
|
dir: DamageDir | DamageDir[]
|
||||||
): DamageInfo[] {
|
): DamageInfo[] {
|
||||||
const damageCache: Record<string, number> = {};
|
|
||||||
const dirs = ensureArray(dir);
|
const dirs = ensureArray(dir);
|
||||||
const enemy = this.getRealInfo();
|
const enemy = this.getRealInfo();
|
||||||
|
|
||||||
return dirs.map(dir => {
|
return dirs.map(dir => {
|
||||||
const status = getHeroStatusOf(hero, realStatus);
|
|
||||||
let damage = calDamageWith(enemy, status) ?? Infinity;
|
|
||||||
let skill = -1;
|
|
||||||
|
|
||||||
// 自动切换技能
|
|
||||||
if (flags.autoSkill) {
|
|
||||||
for (let i = 0; i < skills.length; i++) {
|
|
||||||
const [unlock, condition] = skills[i];
|
|
||||||
if (!flags[unlock]) continue;
|
|
||||||
flags[condition] = true;
|
|
||||||
const status = getHeroStatusOf(hero, realStatus);
|
|
||||||
|
|
||||||
const id = `${status.atk},${status.def}`;
|
|
||||||
const d =
|
|
||||||
id in damageCache
|
|
||||||
? damageCache[id]
|
|
||||||
: calDamageWith(enemy, status) ?? Infinity;
|
|
||||||
|
|
||||||
if (d < damage) {
|
|
||||||
damage = d;
|
|
||||||
skill = i;
|
|
||||||
}
|
|
||||||
flags[condition] = false;
|
|
||||||
damageCache[id] = d;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let x: number | undefined;
|
let x: number | undefined;
|
||||||
let y: number | undefined;
|
let y: number | undefined;
|
||||||
if (has(this.x) && has(this.y)) {
|
if (has(this.x) && has(this.y)) {
|
||||||
@ -700,6 +675,8 @@ export class DamageEnemy<T extends EnemyIds = EnemyIds> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const { damage, skill } = this.calEnemyDamageOf(hero, enemy, x, y);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
damage,
|
damage,
|
||||||
dir,
|
dir,
|
||||||
@ -710,6 +687,37 @@ export class DamageEnemy<T extends EnemyIds = EnemyIds> {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private calEnemyDamageOf(
|
||||||
|
hero: Partial<HeroStatus>,
|
||||||
|
enemy: EnemyInfo,
|
||||||
|
x?: number,
|
||||||
|
y?: number
|
||||||
|
) {
|
||||||
|
const status = getHeroStatusOf(hero, realStatus, x, y, this.floorId);
|
||||||
|
let damage = calDamageWith(enemy, status) ?? Infinity;
|
||||||
|
let skill = -1;
|
||||||
|
|
||||||
|
// 自动切换技能
|
||||||
|
if (flags.autoSkill) {
|
||||||
|
for (let i = 0; i < skills.length; i++) {
|
||||||
|
const [unlock, condition] = skills[i];
|
||||||
|
if (!flags[unlock]) continue;
|
||||||
|
flags[condition] = true;
|
||||||
|
const status = getHeroStatusOf(hero, realStatus);
|
||||||
|
|
||||||
|
const d = calDamageWith(enemy, status) ?? Infinity;
|
||||||
|
|
||||||
|
if (d < damage) {
|
||||||
|
damage = d;
|
||||||
|
skill = i;
|
||||||
|
}
|
||||||
|
flags[condition] = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return { damage, skill };
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 计算怪物临界,计算临界时,根据当前方向计算临界,但也会输出与当前最少伤害的伤害差值
|
* 计算怪物临界,计算临界时,根据当前方向计算临界,但也会输出与当前最少伤害的伤害差值
|
||||||
* @param num 要计算多少个临界
|
* @param num 要计算多少个临界
|
||||||
@ -733,18 +741,10 @@ export class DamageEnemy<T extends EnemyIds = EnemyIds> {
|
|||||||
!has(this.y) ||
|
!has(this.y) ||
|
||||||
!has(this.floorId)
|
!has(this.floorId)
|
||||||
) {
|
) {
|
||||||
const status = getHeroStatusOf(hero, realStatus);
|
return this.calCriticalWith(num, min, seckill, v, hero);
|
||||||
return this.calCriticalWith(num, min, seckill, v, status);
|
|
||||||
} else {
|
} else {
|
||||||
const [x, y] = ofDir(this.x, this.y, dir);
|
const [x, y] = ofDir(this.x, this.y, dir);
|
||||||
const status = getHeroStatusOf(
|
return this.calCriticalWith(num, min, seckill, v, hero, x, y);
|
||||||
hero,
|
|
||||||
realStatus,
|
|
||||||
x,
|
|
||||||
y,
|
|
||||||
this.floorId
|
|
||||||
);
|
|
||||||
return this.calCriticalWith(num, min, seckill, v, status);
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -761,65 +761,58 @@ export class DamageEnemy<T extends EnemyIds = EnemyIds> {
|
|||||||
min: number,
|
min: number,
|
||||||
seckill: number,
|
seckill: number,
|
||||||
origin: DamageInfo,
|
origin: DamageInfo,
|
||||||
hero: Partial<HeroStatus>
|
hero: Partial<HeroStatus>,
|
||||||
|
x?: number,
|
||||||
|
y?: number
|
||||||
): CriticalDamageDelta[] {
|
): CriticalDamageDelta[] {
|
||||||
if (!isFinite(seckill)) return [];
|
if (!isFinite(seckill)) return [];
|
||||||
const damageCache: Record<number, number> = {};
|
|
||||||
const res: CriticalDamageDelta[] = [];
|
const res: CriticalDamageDelta[] = [];
|
||||||
const def = hero.def!;
|
const def = hero.def!;
|
||||||
const precision =
|
const precision =
|
||||||
seckill < Number.MAX_SAFE_INTEGER ? 1 : seckill / 1e15;
|
(seckill < Number.MAX_SAFE_INTEGER ? 1 : seckill / 1e15) * 2;
|
||||||
|
const enemy = this.getRealInfo();
|
||||||
|
|
||||||
let curr = hero.atk!;
|
let curr = hero.atk!;
|
||||||
let start = curr;
|
let start = curr;
|
||||||
let end = seckill;
|
let end = seckill;
|
||||||
let ori = origin.damage;
|
let ori = origin.damage;
|
||||||
|
if (start >= end) return [];
|
||||||
|
|
||||||
|
const calDam = () => {
|
||||||
|
return this.calEnemyDamageOf({ atk: curr, def }, enemy, x, y)
|
||||||
|
.damage;
|
||||||
|
};
|
||||||
|
|
||||||
let i = 0;
|
let i = 0;
|
||||||
while (1) {
|
while (res.length < num) {
|
||||||
if (res.length >= num) break;
|
if (end - start <= precision) {
|
||||||
if (end - start <= 2 * precision) {
|
|
||||||
// 到达二分所需精度,计算临界准确值
|
// 到达二分所需精度,计算临界准确值
|
||||||
const damages: number[] = [];
|
|
||||||
let cal = false;
|
let cal = false;
|
||||||
[start, (start + end) / 2, end].forEach((v, i) => {
|
for (const v of [(start + end) / 2, end]) {
|
||||||
const damage = (damages[i] =
|
curr = v;
|
||||||
calDamageWith(this.info, { atk: v, def }) ?? Infinity);
|
const dam = calDam();
|
||||||
if (i !== 0 && damages[i] < damages[i - 1]) {
|
if (dam < ori) {
|
||||||
res.push({
|
res.push({
|
||||||
damage: damages[i],
|
damage: dam,
|
||||||
atkDelta: Math.ceil(v - hero.atk!),
|
atkDelta: Math.ceil(v - hero.atk!),
|
||||||
dir: origin.dir,
|
dir: origin.dir,
|
||||||
delta: damages[i] - min,
|
delta: dam - min,
|
||||||
dirDelta: damages[i] - origin.damage
|
dirDelta: dam - origin.damage
|
||||||
});
|
});
|
||||||
|
|
||||||
// 计算下一个临界,借助于之前的计算,可以直接知道下一个临界在哪个范围内
|
start = v;
|
||||||
const d = Object.entries(damageCache)
|
end = seckill;
|
||||||
.filter(v => {
|
cal = true;
|
||||||
return parseFloat(v[0]) < damage;
|
ori = dam;
|
||||||
})
|
break;
|
||||||
.map(v => [parseFloat(v[0]), v[1]])
|
|
||||||
.sort((a, b) => a[0] - b[0]);
|
|
||||||
|
|
||||||
for (let i = 0; i < d.length - 1; i++) {
|
|
||||||
const [na, ndam] = d[i + 1];
|
|
||||||
if (ndam < damage) {
|
|
||||||
start = v;
|
|
||||||
end = na;
|
|
||||||
cal = true;
|
|
||||||
}
|
|
||||||
ori = damage;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
if (!cal) break;
|
if (!cal) break;
|
||||||
}
|
}
|
||||||
curr = Math.floor((start + end) / 2);
|
curr = Math.floor((start + end) / 2);
|
||||||
|
|
||||||
const damage =
|
const damage = calDam();
|
||||||
calDamageWith(this.info, { atk: curr, def }) ?? Infinity;
|
|
||||||
damageCache[curr] = damage;
|
|
||||||
if (damage < ori) {
|
if (damage < ori) {
|
||||||
end = curr;
|
end = curr;
|
||||||
} else {
|
} else {
|
||||||
@ -878,16 +871,26 @@ export class DamageEnemy<T extends EnemyIds = EnemyIds> {
|
|||||||
return Infinity;
|
return Infinity;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 列方程求解
|
||||||
// 饥渴,会偷取勇士攻击
|
// 饥渴,会偷取勇士攻击
|
||||||
if (info.special.includes(7)) {
|
if (info.special.includes(7)) {
|
||||||
return add / (1 - this.enemy.hungry! / 100);
|
if (info.damageDecline === 0) {
|
||||||
|
return add / (1 - this.enemy.hungry! / 100);
|
||||||
|
} else {
|
||||||
|
return (
|
||||||
|
(info.hp / (1 - info.damageDecline / 100) -
|
||||||
|
core.status.hero.mana +
|
||||||
|
info.def) /
|
||||||
|
(1 - this.enemy.hungry! / 100)
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 霜冻
|
// 霜冻
|
||||||
if (info.special.includes(20) && !core.hasEquip('I589')) {
|
if (info.special.includes(20) && !core.hasEquip('I589')) {
|
||||||
return (
|
return (
|
||||||
info.def +
|
info.def +
|
||||||
info.hp / (1 - this.enemy.ice!) -
|
info.hp / (1 - this.enemy.ice! / 100) -
|
||||||
core.status.hero.mana
|
core.status.hero.mana
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -895,7 +898,7 @@ export class DamageEnemy<T extends EnemyIds = EnemyIds> {
|
|||||||
if (info.damageDecline !== 0) {
|
if (info.damageDecline !== 0) {
|
||||||
return (
|
return (
|
||||||
info.def +
|
info.def +
|
||||||
info.hp / (1 - info.damageDecline) -
|
info.hp / (1 - info.damageDecline / 100) -
|
||||||
core.status.hero.mana
|
core.status.hero.mana
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
|
Loading…
Reference in New Issue
Block a user