From 061e25e8d196498db9000d54a927bf7dc564893d Mon Sep 17 00:00:00 2001 From: unanmed <1319491857@qq.com> Date: Wed, 12 Jul 2023 17:38:23 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E6=AD=A3=E4=BC=A4=E5=AE=B3=E8=AE=A1?= =?UTF-8?q?=E7=AE=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/plugin/game/damage.ts | 98 ++++++++++++++++++++---------------- src/plugin/game/popup.js | 102 ++++++++++++++++++++++++++++++++++++++ src/plugin/game/utils.ts | 18 +++++++ src/types/status.d.ts | 12 +++++ 4 files changed, 188 insertions(+), 42 deletions(-) diff --git a/src/plugin/game/damage.ts b/src/plugin/game/damage.ts index c8e367c..93812f0 100644 --- a/src/plugin/game/damage.ts +++ b/src/plugin/game/damage.ts @@ -194,6 +194,9 @@ export class EnemyCollection implements RangeCollection { this.calDamage(noCache, true); this.calMapDamage(noCache); } + core.status.damage.data = []; + core.status.damage.extraData = []; + core.status.damage.dir = []; // 怪物伤害 this.list.forEach(v => { @@ -207,12 +210,19 @@ export class EnemyCollection implements RangeCollection { if (equal(v.damage, 'damage')) { // 伤害全部相等,绘制在怪物本身所在位置 const { damage, color } = formatDamage(v.damage[0].damage); + const critical = v.calCritical(1)[0]?.[0]; core.status.damage.data.push({ text: damage, px: 32 * v.x! + 1, py: 32 * (v.y! + 1) - 1, color: color }); + core.status.damage.data.push({ + text: critical?.atkDelta.toString() ?? '?', + px: 32 * v.x! + 1, + py: 32 * (v.y! + 1) - 11, + color: '#fff' + }); } else { const [min, max] = boundary(v.damage, 'damage'); const delta = max - min; @@ -226,33 +236,16 @@ export class EnemyCollection implements RangeCollection { }); // 然后根据位置依次绘制对应位置的伤害 for (const dam of v.damage) { + if (dam.dir === 'none') continue; const d = ((dam.damage - min) / delta) * 255; const color = core.arrayToRGB([d, 255 - d, 0]); - if (dam.dir === 'down' || dam.dir === 'up') { - const dir = dam.dir === 'down' ? '↑' : '↓'; - core.status.damage.extraData.push({ - text: dir, - px: 32 * v.x! + 16, - py: - 32 * v.y! + - 16 + - core.utils.scan[dam.dir].y * 16, - color: color, - alpha: 1 - }); - } else if (dam.dir === 'left' || dam.dir === 'right') { - const dir = dam.dir === 'left' ? '→' : '←'; - core.status.damage.extraData.push({ - text: dir, - px: - 32 * v.x! + - 16 + - core.utils.scan[dam.dir].x * 16, - py: 32 * v.y! + 16, - color: color, - alpha: 1 - }); - } + + core.status.damage.dir.push({ + x: v.x!, + y: v.y!, + dir: dam.dir, + color: color + }); } } }); @@ -385,6 +378,7 @@ export class DamageEnemy { hpBuff: 0, enemy: this.enemy }; + this.progress = 0; this.needCalculate = true; this.needCalDamage = true; } @@ -398,7 +392,7 @@ export class DamageEnemy { hero: Partial = core.status.hero, getReal: boolean = true ) { - if (this.progress !== 1) return this.info; + if (this.progress !== 1) return; this.progress = 2; const special = this.info.special; const info = this.info; @@ -451,9 +445,9 @@ export class DamageEnemy { // 此时已经inject光环,因此直接计算真实属性 const info = this.info; - info.atk *= info.atkBuff / 100 + 1; - info.def *= info.defBuff / 100 + 1; - info.hp *= info.hpBuff / 100 + 1; + 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; @@ -576,12 +570,11 @@ export class DamageEnemy { ) { if (onMap && !checkV2(this.x, this.y)) return this.damage!; if (!this.needCalDamage) return this.damage!; - const info = this.getRealInfo(); const dirs = getNeedCalDir(this.x, this.y, this.floorId, hero); this.needCalDamage = false; - return (this.damage = this.calEnemyDamage(info, hero, dirs)); + return (this.damage = this.calEnemyDamage(hero, dirs)); } /** @@ -689,7 +682,6 @@ export class DamageEnemy { } private calEnemyDamage( - enemy: EnemyInfo = this.getRealInfo(), hero: Partial = core.status.hero, dir: DamageDir | DamageDir[] ): DamageInfo[] { @@ -698,6 +690,11 @@ export class DamageEnemy { 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; @@ -708,11 +705,20 @@ 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 = id in damageCache ? damageCache[id] : calDamageWith(enemy, status) ?? Infinity; + if (d < damage) { damage = d; skill = i; @@ -721,6 +727,12 @@ 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; @@ -754,7 +766,7 @@ export class DamageEnemy { dir: DamageDir | DamageDir[] = 'none', hero: Partial = core.status.hero ): CriticalDamageDelta[][] { - const origin = this.calEnemyDamage(void 0, hero, dir); + const origin = this.calEnemyDamage(hero, dir); const min = Math.min(...origin.map(v => v.damage)); const seckill = this.getSeckillAtk(); @@ -821,7 +833,7 @@ export class DamageEnemy { if (i !== 0 && damages[i] < damages[i - 1]) { res.push({ damage: damages[i], - atkDelta: v - hero.atk!, + atkDelta: Math.ceil(v - hero.atk!), dir: origin.dir, delta: damages[i] - min, dirDelta: damages[i] - origin.damage @@ -830,20 +842,19 @@ export class DamageEnemy { // 计算下一个临界,借助于之前的计算,可以直接知道下一个临界在哪个范围内 const d = Object.entries(damageCache) .filter(v => { - return parseFloat(v[0]) <= damage; + return parseFloat(v[0]) < damage; }) .map(v => [parseFloat(v[0]), v[1]]) .sort((a, b) => a[0] - b[0]); for (let i = 0; i < d.length - 1; i++) { - const [a, dam] = d[i]; const [na, ndam] = d[i + 1]; if (ndam < damage) { - start = a; + start = v; end = na; cal = true; } - ori = dam; + ori = damage; } } }); @@ -882,11 +893,10 @@ export class DamageEnemy { hero: Partial = core.status.hero ): DamageDelta[] { const damage = this.calEnemyDamage( - void 0, { def: (hero.def ?? core.status.hero.def) + num }, dir ); - const origin = this.calEnemyDamage(void 0, hero, dir); + const origin = this.calEnemyDamage(hero, dir); const min = Math.min(...origin.map(v => v.damage)); return damage.map((v, i) => { @@ -950,6 +960,10 @@ const skills: [unlock: string, condition: string][] = [ ['bladeOn', 'blade'], ['shieldOn', 'shield'] ]; +/** + * 需要在每次切换技能时都重新计算怪物属性的特殊属性 + */ +const needCalSpecial = [3, 7]; /** * 获取需要计算怪物伤害的方向 @@ -982,10 +996,10 @@ export function getNeedCalDir( const [tx, ty] = ofDir(x, y, v); if (tx < 0 || ty < 0 || tx >= width || ty >= height) return false; const index = `${tx},${ty}` as LocString; + if (!core.canMoveHero(tx, ty, backDir(v), floorId)) return false; const block = blocks[index]; if (!block) return true; - if (block.event.noPass) return false; - if (!core.canMoveHero(tx, ty, backDir(v), floorId)) return false; + if (block.event.noPass || block.event.cls === 'items') return false; return true; }); diff --git a/src/plugin/game/popup.js b/src/plugin/game/popup.js index 5a0ff77..7a69ea7 100644 --- a/src/plugin/game/popup.js +++ b/src/plugin/game/popup.js @@ -37,6 +37,108 @@ control.prototype.checkBlock = function (forceMockery) { checkMockery(loc, forceMockery); }; +/** + * @param {CanvasRenderingContext2D} ctx + */ +control.prototype._drawDamage_draw = function (ctx, onMap) { + if (!core.hasItem('book')) return; + core.plugin.halo.drawHalo(ctx, onMap); + + core.setFont(ctx, "14px 'normal'"); + core.setTextAlign(ctx, 'center'); + core.setTextBaseline(ctx, 'middle'); + core.status.damage.extraData.forEach(function (one) { + var px = one.px, + py = one.py; + if (onMap && core.bigmap.v2) { + px -= core.bigmap.posX * 32; + py -= core.bigmap.posY * 32; + if ( + px < -32 || + px > core._PX_ + 32 || + py < -32 || + py > core._PY_ + 32 + ) + return; + } + var alpha = core.setAlpha(ctx, one.alpha); + core.fillBoldText(ctx, one.text, px, py, one.color); + core.setAlpha(ctx, alpha); + }); + + core.setTextAlign(ctx, 'left'); + core.setTextBaseline(ctx, 'alphabetic'); + core.status.damage.data.forEach(function (one) { + var px = one.px, + py = one.py; + if (onMap && core.bigmap.v2) { + px -= core.bigmap.posX * 32; + py -= core.bigmap.posY * 32; + if ( + px < -32 * 2 || + px > core._PX_ + 32 || + py < -32 || + py > core._PY_ + 32 + ) + return; + } + core.fillBoldText(ctx, one.text, px, py, one.color); + }); + + ctx.save(); + ctx.lineCap = 'round'; + ctx.lineJoin = 'round'; + ctx.lineWidth = 2; + core.status.damage.dir.forEach(v => { + let x = v.x; + let y = v.y; + if (onMap && core.bigmap.v2) { + x -= core.bigmap.posX; + y -= core.bigmap.posY; + } + if (x < -1 || x > 15 || y < 0 || y > 15) return; + let px = x * 32; + let py = y * 32; + ctx.beginPath(); + if (v.dir === 'down') { + py -= 32; + ctx.moveTo(px + 16, py + 18); + ctx.lineTo(px + 16, py + 32); + ctx.moveTo(px + 10, py + 26); + ctx.lineTo(px + 16, py + 32); + ctx.lineTo(px + 22, py + 26); + } else if (v.dir === 'left') { + px += 32; + ctx.moveTo(px + 14, py + 16); + ctx.lineTo(px, py + 16); + ctx.moveTo(px + 6, py + 10); + ctx.lineTo(px, py + 16); + ctx.lineTo(px + 6, py + 22); + } else if (v.dir === 'up') { + py += 32; + ctx.moveTo(px + 16, py + 14); + ctx.lineTo(px + 16, py); + ctx.moveTo(px + 10, py + 6); + ctx.lineTo(px + 16, py); + ctx.lineTo(px + 22, py + 6); + } else { + px -= 32; + ctx.moveTo(px + 18, py + 16); + ctx.lineTo(px + 32, py + 16); + ctx.moveTo(px + 26, py + 10); + ctx.lineTo(px + 32, py + 16); + ctx.lineTo(px + 26, py + 22); + } + ctx.strokeStyle = 'black'; + ctx.lineWidth = 2.5; + ctx.stroke(); + ctx.strokeStyle = v.color; + ctx.lineWidth = 1; + ctx.stroke(); + }); + ctx.restore(); +}; + control.prototype.moveHero = function (direction, callback) { // todo: 不使用 core.status.checkBlock // 如果正在移动,直接return diff --git a/src/plugin/game/utils.ts b/src/plugin/game/utils.ts index 3fb7f24..46785fb 100644 --- a/src/plugin/game/utils.ts +++ b/src/plugin/game/utils.ts @@ -97,7 +97,16 @@ export function formatDamage(damage: number): DamageString { return { damage: dam, color: color as Color }; } +/** + * 判断一个数组的数值是否全部相等 + * @param arr 要判断的数组 + */ export function equal(arr: number[]): boolean; +/** + * 判断一个数组的元素的某个属性的数值是否全部相等 + * @param arr 要判断的数组 + * @param key 要判断的属性名 + */ export function equal(arr: T[], key: keyof T): boolean; export function equal(arr: any, key?: any) { if (has(key)) { @@ -113,7 +122,16 @@ export function equal(arr: any, key?: any) { } } +/** + * 获得一个数组的数值的最大值和最小值 + * @param arr 要获得的数组 + */ export function boundary(arr: number[]): [number, number]; +/** + * 获得一个数组的元素的某个属性的数值的最大值和最小值 + * @param arr 要获得的数组 + * @param key 要获得的属性名 + */ export function boundary(arr: T[], key: keyof T): [number, number]; export function boundary(arr: any, key?: any) { if (has(key)) { diff --git a/src/types/status.d.ts b/src/types/status.d.ts index b22fd5a..434c082 100644 --- a/src/types/status.d.ts +++ b/src/types/status.d.ts @@ -80,6 +80,11 @@ interface DamageStatus { * 地图伤害或其它在地图上显示的文字 */ extraData: DamageStatusExtraData[]; + + /** + * 不同方向伤害不同的信息 + */ + dir: DamageDirData[]; } interface DamageStatusData { @@ -111,6 +116,13 @@ interface DamageStatusExtraData extends DamageStatusData { alpha: number; } +interface DamageDirData { + x: number; + y: number; + dir: Dir; + color: Color; +} + interface AutomaticRouteStatus { /** * 勇士是否正在移动