完成临界计算

This commit is contained in:
unanmed 2023-07-13 16:35:43 +08:00
parent b9c1142d14
commit 3aea023562

View File

@ -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 {