From b9c1142d1404fbac5326916af114571c0a7a0848 Mon Sep 17 00:00:00 2001 From: unanmed <1319491857@qq.com> Date: Wed, 12 Jul 2023 18:34:55 +0800 Subject: [PATCH] =?UTF-8?q?=E5=BD=BB=E5=BA=95=E4=BF=AE=E6=AD=A3=E4=BC=A4?= =?UTF-8?q?=E5=AE=B3=E8=AE=A1=E7=AE=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/plugin/game/damage.ts | 169 +++++++++++++--------------------- src/plugin/game/itemDetail.ts | 1 + src/plugin/game/range.ts | 10 +- src/types/enemy.d.ts | 3 +- 4 files changed, 72 insertions(+), 111 deletions(-) diff --git a/src/plugin/game/damage.ts b/src/plugin/game/damage.ts index 93812f0..db4aa87 100644 --- a/src/plugin/game/damage.ts +++ b/src/plugin/game/damage.ts @@ -29,6 +29,9 @@ interface EnemyInfo { defBuff: number; hpBuff: number; enemy: Enemy; + x?: number; + y?: number; + floorId?: FloorIds; } interface DamageInfo { @@ -71,7 +74,7 @@ interface CriticalDamageDelta extends Omit { type HaloFn = (info: EnemyInfo, enemy: Enemy) => void; type DamageDir = Dir | 'none'; -export const haloSpecials: number[] = [21, 25, 26, 27]; +export const haloSpecials: number[] = [8, 21, 25, 26, 27]; export class EnemyCollection implements RangeCollection { floorId: FloorIds; @@ -105,9 +108,17 @@ export class EnemyCollection implements RangeCollection { * @param noCache 是否不使用缓存 */ calRealAttribute(noCache: boolean = false) { + if (!noCache) return; this.list.forEach(v => { - if (noCache) v.reset(); - v.calRealAttribute(); + v.reset(); + v.preProvideHalo(); + }); + this.list.forEach(v => { + v.calAttribute(); + v.provideHalo(); + }); + this.list.forEach(v => { + v.getRealInfo(); }); } @@ -116,11 +127,8 @@ export class EnemyCollection implements RangeCollection { * @param noCache 是否不使用缓存 */ calDamage(noCache: boolean = false, onMap: boolean = false) { + if (noCache) this.calRealAttribute(noCache); this.list.forEach(v => { - if (noCache || v.needCalculate) { - v.reset(); - v.calRealAttribute(); - } v.calDamage(void 0, onMap); }); } @@ -161,13 +169,13 @@ export class EnemyCollection implements RangeCollection { if (!recursion) { arr.forEach(v => { enemy.forEach(e => { - e.injectHalo(v); + e.injectHalo(v, e.enemy); }); }); } else { enemy.forEach(e => { arr.forEach(v => { - e.injectHalo(v); + e.injectHalo(v, e.enemy); e.preProvideHalo(); }); }); @@ -333,8 +341,6 @@ export class DamageEnemy { * -> provide inject 光环 -> 计算怪物的光环加成 -> 计算完毕 */ info!: EnemyInfo; - /** 是否需要计算属性 */ - needCalculate: boolean = true; /** 怪物伤害 */ damage?: DamageInfo[]; /** 是否需要计算伤害 */ @@ -376,38 +382,25 @@ export class DamageEnemy { atkBuff: 0, defBuff: 0, hpBuff: 0, - enemy: this.enemy + enemy: this.enemy, + x: this.x, + y: this.y, + floorId: this.floorId }; this.progress = 0; - this.needCalculate = true; this.needCalDamage = true; + this.providedHalo = []; } /** * 计算怪物在不计光环下的属性,在inject光环之前,预平衡光环之后执行 - * @param hero 勇士属性 - * @param getReal 是否获取勇士真实属性,默认获取 */ - calAttribute( - hero: Partial = core.status.hero, - getReal: boolean = true - ) { + calAttribute() { if (this.progress !== 1) return; this.progress = 2; const special = this.info.special; const info = this.info; - const enemy = this.enemy; const floorId = this.floorId ?? core.status.floorId; - const { atk } = getReal - ? getHeroStatusOf(hero, ['atk'], hero.x, hero.y, hero.floorId) - : hero; - - if (!has(atk)) return; - - // 饥渴 - if (special.includes(7)) { - info.atk += (atk * (enemy.hungry ?? 0)) / 100; - } // 智慧之源 if (flags.hard === 2 && special.includes(14)) { @@ -418,11 +411,6 @@ export class DamageEnemy { info.atk -= flags[`night_${floorId}`] ?? 0; info.def -= flags[`night_${floorId}`] ?? 0; - // 坚固 - if (special.includes(3) && enemy.def < atk - 1) { - info.def = atk - 1; - } - // 融化,融化不属于怪物光环,因此不能用provide和inject计算,需要在这里计算 if (has(flags[`melt_${floorId}`]) && has(this.x) && has(this.y)) { for (const [loc, per] of Object.entries(flags[`melt_${floorId}`])) { @@ -439,42 +427,24 @@ export class DamageEnemy { * 获取怪物的真实属性信息,在inject光环后执行 */ getRealInfo() { + if (this.progress < 3) { + throw new Error( + `Unexpected early real info calculating. Progress: ${this.progress}` + ); + } if (this.progress === 4) return this.info; - if (this.progress <= 3) this.ensureCaled(3); this.progress = 4; // 此时已经inject光环,因此直接计算真实属性 const info = this.info; + info.atk = Math.floor(info.atk * (info.atkBuff / 100 + 1)); info.def = Math.floor(info.def * (info.defBuff / 100 + 1)); info.hp = Math.floor(info.hp * (info.hpBuff / 100 + 1)); - this.needCalculate = false; - return this.info; } - /** - * 计算真实属性 - */ - calRealAttribute() { - this.preProvideHalo(); - this.calAttribute(); - this.provideHalo(); - this.getRealInfo(); - } - - /** - * 确保怪物属性计算已经到达某个进度 - * @param progress 期望进度 - */ - ensureCaled(progress: number) { - if (progress >= 1) this.preProvideHalo(); - if (progress >= 2) this.calAttribute(); - if (progress >= 3) this.provideHalo(); - if (progress >= 4) this.getRealInfo(); - } - getHaloSpecials(): number[] { if (!this.floorId) return []; if (!core.has(this.x) || !core.has(this.y)) return []; @@ -510,15 +480,17 @@ export class DamageEnemy { if (!core.has(this.x) || !core.has(this.y)) return; const col = this.col ?? core.status.maps[this.floorId].enemy; if (!col) return; - const speical = this.getHaloSpecials(); + const special = this.getHaloSpecials(); const square7: HaloFn[] = []; const square5: HaloFn[] = []; + // e 是被加成怪的属性,enemy 是施加光环的怪 + // 抱团 - if (speical.includes(8)) { + if (special.includes(8)) { square5.push((e, enemy) => { - if (e.special.includes(8)) { + if (e.special.includes(8) && e.x !== this.x && this.y !== e.y) { e.atkBuff += enemy.together ?? 0; e.defBuff += enemy.together ?? 0; } @@ -527,25 +499,25 @@ export class DamageEnemy { } // 冰封光环 - if (speical.includes(21)) { - square7.push((e, enemy) => { - e.damageDecline += enemy.iceDecline ?? 0; + if (special.includes(21)) { + square7.push(e => { + e.damageDecline += this.enemy.iceHalo ?? 0; }); this.providedHalo.push(21); } // 冰封之核 - if (speical.includes(26)) { - square5.push((e, enemy) => { - e.defBuff += enemy.iceCore ?? 0; + if (special.includes(26)) { + square5.push(e => { + e.defBuff += this.enemy.iceCore ?? 0; }); this.providedHalo.push(26); } // 火焰之核 - if (speical.includes(27)) { - square5.push((e, enemy) => { - e.atkBuff += enemy.fireCore ?? 0; + if (special.includes(27)) { + square5.push(e => { + e.atkBuff += this.enemy.fireCore ?? 0; }); this.providedHalo.push(27); } @@ -557,8 +529,8 @@ export class DamageEnemy { /** * 接受其他怪的光环 */ - injectHalo(halo: HaloFn) { - halo.call(this, this.info, this.enemy); + injectHalo(halo: HaloFn, enemy: Enemy) { + halo(this.info, enemy); } /** @@ -687,14 +659,10 @@ export class DamageEnemy { ): DamageInfo[] { const damageCache: Record = {}; const dirs = ensureArray(dir); + const enemy = this.getRealInfo(); return dirs.map(dir => { const status = getHeroStatusOf(hero, realStatus); - let enemy: EnemyInfo; - this.reset(); - this.preProvideHalo(); - this.calAttribute(status, false); - enemy = this.getRealInfo(); let damage = calDamageWith(enemy, status) ?? Infinity; let skill = -1; @@ -705,13 +673,6 @@ export class DamageEnemy { if (!flags[unlock]) continue; flags[condition] = true; const status = getHeroStatusOf(hero, realStatus); - // 这几个技能会导致怪物属性也改变,需要重新计算怪物属性 - if (needCalSpecial.some(v => enemy.special.includes(v))) { - this.reset(); - this.preProvideHalo(); - this.calAttribute(status, false); - enemy = this.getRealInfo(); - } const id = `${status.atk},${status.def}`; const d = @@ -727,12 +688,6 @@ export class DamageEnemy { damageCache[id] = d; } } - if (needCalSpecial.some(v => enemy.special.includes(v))) { - this.reset(); - this.preProvideHalo(); - this.calAttribute(status, false); - this.getRealInfo(); - } let x: number | undefined; let y: number | undefined; @@ -960,10 +915,6 @@ const skills: [unlock: string, condition: string][] = [ ['bladeOn', 'blade'], ['shieldOn', 'shield'] ]; -/** - * 需要在每次切换技能时都重新计算怪物属性的特殊属性 - */ -const needCalSpecial = [3, 7]; /** * 获取需要计算怪物伤害的方向 @@ -1017,13 +968,15 @@ export function calDamageWith( ): number | null { const { hp, hpmax, mana, mdef } = core.status.hero; let { atk, def } = hero as HeroStatus; - const { hp: monHp, atk: monAtk, def: monDef, special, enemy } = info; + let { hp: monHp, atk: monAtk, def: monDef, special, enemy } = info; let damage = 0; // 饥渴 if (special.includes(7)) { - atk *= 1 - enemy.hungry! / 100; + const delta = Math.floor((atk * enemy.hungry!) / 100); + atk -= delta; + monAtk += delta; } let heroPerDamage: number; @@ -1032,12 +985,23 @@ export function calDamageWith( if (special.includes(9)) { heroPerDamage = atk + mana - monDef; if (heroPerDamage <= 0) return null; + } else if (special.includes(3)) { + // 由于坚固的特性,只能放到这来计算了 + if (atk > enemy.def) heroPerDamage = 1 + mana; + else return null; } else { heroPerDamage = atk - monDef; if (heroPerDamage > 0) heroPerDamage += mana; else return null; } + // 霜冻 + if (special.includes(20) && !core.hasEquip('I589')) { + heroPerDamage *= 1 - enemy.ice! / 100; + } + + heroPerDamage *= 1 - info.damageDecline / 100; + let enemyPerDamage: number; // 魔攻 @@ -1048,17 +1012,16 @@ export function calDamageWith( if (enemyPerDamage < 0) enemyPerDamage = 0; } + // 先攻 + if (special.includes(17)) { + damage += enemyPerDamage; + } + // 连击 if (special.includes(4)) enemyPerDamage *= 2; if (special.includes(5)) enemyPerDamage *= 3; if (special.includes(6)) enemyPerDamage *= enemy.n!; - // 霜冻 - if (special.includes(20) && !core.hasEquip('I589')) { - heroPerDamage *= 1 - enemy.ice! / 100; - } - heroPerDamage *= 1 - info.damageDecline; - // 苍蓝刻 if (special.includes(28)) { heroPerDamage *= 1 - enemy.paleShield! / 100; diff --git a/src/plugin/game/itemDetail.ts b/src/plugin/game/itemDetail.ts index f75b272..6797c11 100644 --- a/src/plugin/game/itemDetail.ts +++ b/src/plugin/game/itemDetail.ts @@ -17,6 +17,7 @@ core.control.updateDamage = function (floorId = core.status.floorId, ctx) { } // 计算伤害 core.plugin.damage.ensureFloorDamage(floorId); + floor.enemy.calDamage(true, onMap); floor.enemy.calMapDamage(true); core.status.damage.data = []; diff --git a/src/plugin/game/range.ts b/src/plugin/game/range.ts index 8ef58fe..c858933 100644 --- a/src/plugin/game/range.ts +++ b/src/plugin/game/range.ts @@ -72,21 +72,17 @@ export class Range> { Range.registerRangeType( 'square', (col, { x, y, d }) => { - const cache = (col.cache.square ??= {}); - const index = `${x},${y},${d}`; - if (index in cache) return cache[index]; const list = col.collection.list; + const r = Math.floor(d / 2); - const r = Math.floor(d); - - return (cache[index] = list.filter(v => { + return list.filter(v => { return ( core.has(v.x) && core.has(v.y) && Math.abs(v.x - x) <= r && Math.abs(v.y - y) <= r ); - })); + }); }, (col, { x, y, d }, item) => { const r = Math.floor(d / 2); diff --git a/src/types/enemy.d.ts b/src/types/enemy.d.ts index ab970d0..a1887fe 100644 --- a/src/types/enemy.d.ts +++ b/src/types/enemy.d.ts @@ -25,7 +25,8 @@ type PartialNumbericEnemyProperty = | 'crit' | 'courage' | 'charge' - | 'paleShield'; + | 'paleShield' + | 'iceHalo'; type BooleanEnemyProperty = | 'zoneSquare'