mirror of
https://github.com/unanmed/HumanBreak.git
synced 2025-03-01 01:57:05 +08:00
删除不同位置攻击怪物伤害不同的机制
This commit is contained in:
parent
b14e4edcc7
commit
4999452cb6
@ -2822,6 +2822,7 @@ control.prototype.getRealStatus = function (name) {
|
|||||||
|
|
||||||
////// 从status中获得实际属性(增幅后的),如果不存在则从勇士属性中获取 //////
|
////// 从status中获得实际属性(增幅后的),如果不存在则从勇士属性中获取 //////
|
||||||
control.prototype.getRealStatusOrDefault = function (status, name) {
|
control.prototype.getRealStatusOrDefault = function (status, name) {
|
||||||
|
// todo: 删除
|
||||||
return core.plugin.hero.getHeroStatusOf(status, name);
|
return core.plugin.hero.getHeroStatusOf(status, name);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -331,6 +331,7 @@ var functions_d6ad677b_427a_4623_b50f_a445a3b0ef8a = {
|
|||||||
},
|
},
|
||||||
enemys: {
|
enemys: {
|
||||||
getSpecials: function () {
|
getSpecials: function () {
|
||||||
|
// todo: 重写
|
||||||
// 获得怪物的特殊属性,每一行定义一个特殊属性。
|
// 获得怪物的特殊属性,每一行定义一个特殊属性。
|
||||||
// 分为五项,第一项为该特殊属性的数字,第二项为特殊属性的名字,第三项为特殊属性的描述
|
// 分为五项,第一项为该特殊属性的数字,第二项为特殊属性的名字,第三项为特殊属性的描述
|
||||||
// 第四项为该特殊属性的颜色,可以写十六进制 #RRGGBB 或者 [r,g,b,a] 四元数组
|
// 第四项为该特殊属性的颜色,可以写十六进制 #RRGGBB 或者 [r,g,b,a] 四元数组
|
||||||
|
@ -1,10 +1,4 @@
|
|||||||
import {
|
import { DamageEnemy, ensureFloorDamage, getSingleEnemy } from './damage';
|
||||||
DamageDir,
|
|
||||||
DamageEnemy,
|
|
||||||
ensureFloorDamage,
|
|
||||||
getNeedCalDir,
|
|
||||||
getSingleEnemy
|
|
||||||
} from './damage';
|
|
||||||
import { findDir, has } from '../utils';
|
import { findDir, has } from '../utils';
|
||||||
|
|
||||||
export interface CurrentEnemy {
|
export interface CurrentEnemy {
|
||||||
@ -31,32 +25,23 @@ export function getEnemy(
|
|||||||
core.enemys.canBattle = function (
|
core.enemys.canBattle = function (
|
||||||
x: number,
|
x: number,
|
||||||
y: number,
|
y: number,
|
||||||
floorId: FloorIds = core.status.floorId,
|
floorId: FloorIds = core.status.floorId
|
||||||
dir: DamageDir | DamageDir[] = getNeedCalDir(x, y, floorId)
|
|
||||||
) {
|
) {
|
||||||
const enemy = getEnemy(x, y, floorId);
|
const enemy = getEnemy(x, y, floorId);
|
||||||
const damage = enemy.calEnemyDamage(core.status.hero, dir);
|
const { damage } = enemy.calDamage();
|
||||||
|
return damage < core.status.hero.hp;
|
||||||
return damage.some(v => {
|
|
||||||
return v.damage < core.status.hero.hp;
|
|
||||||
});
|
|
||||||
};
|
};
|
||||||
|
|
||||||
core.events.battle = function (
|
core.events.battle = function (
|
||||||
x: number,
|
x: number,
|
||||||
y: number,
|
y: number,
|
||||||
dir: DamageDir,
|
|
||||||
force: boolean = false,
|
force: boolean = false,
|
||||||
callback?: () => void
|
callback?: () => void
|
||||||
) {
|
) {
|
||||||
core.saveAndStopAutomaticRoute();
|
core.saveAndStopAutomaticRoute();
|
||||||
const enemy = getEnemy(x, y);
|
const enemy = getEnemy(x, y);
|
||||||
// 非强制战斗
|
// 非强制战斗
|
||||||
if (
|
if (!core.enemys.canBattle(x, y) && !force && !core.status.event.id) {
|
||||||
!core.enemys.canBattle(x, y, void 0, dir) &&
|
|
||||||
!force &&
|
|
||||||
!core.status.event.id
|
|
||||||
) {
|
|
||||||
core.stopSound();
|
core.stopSound();
|
||||||
core.playSound('操作失败');
|
core.playSound('操作失败');
|
||||||
core.drawTip('你打不过此怪物!', enemy.id);
|
core.drawTip('你打不过此怪物!', enemy.id);
|
||||||
@ -65,10 +50,10 @@ core.events.battle = function (
|
|||||||
// 自动存档
|
// 自动存档
|
||||||
if (!core.status.event.id) core.autosave(true);
|
if (!core.status.event.id) core.autosave(true);
|
||||||
// 战前事件
|
// 战前事件
|
||||||
if (!this.beforeBattle(enemy, x, y, dir))
|
if (!this.beforeBattle(enemy, x, y))
|
||||||
return core.clearContinueAutomaticRoute(callback);
|
return core.clearContinueAutomaticRoute(callback);
|
||||||
// 战后事件
|
// 战后事件
|
||||||
this.afterBattle(enemy, x, y, dir);
|
this.afterBattle(enemy, x, y);
|
||||||
callback?.();
|
callback?.();
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -79,8 +64,7 @@ core.events.beforeBattle = function () {
|
|||||||
core.events.afterBattle = function (
|
core.events.afterBattle = function (
|
||||||
enemy: DamageEnemy,
|
enemy: DamageEnemy,
|
||||||
x?: number,
|
x?: number,
|
||||||
y?: number,
|
y?: number
|
||||||
dir: DamageDir = 'none'
|
|
||||||
) {
|
) {
|
||||||
const floorId = core.status.floorId;
|
const floorId = core.status.floorId;
|
||||||
const special = enemy.info.special;
|
const special = enemy.info.special;
|
||||||
@ -96,7 +80,7 @@ core.events.afterBattle = function (
|
|||||||
if (!core.material.animates[animate]?.se) core.playSound('attack.mp3');
|
if (!core.material.animates[animate]?.se) core.playSound('attack.mp3');
|
||||||
|
|
||||||
// 战斗伤害
|
// 战斗伤害
|
||||||
const info = enemy.calEnemyDamage(core.status.hero, dir)[0];
|
const info = enemy.calDamage(core.status.hero);
|
||||||
const damage = info.damage;
|
const damage = info.damage;
|
||||||
// 判定是否致死
|
// 判定是否致死
|
||||||
if (damage >= core.status.hero.hp) {
|
if (damage >= core.status.hero.hp) {
|
||||||
@ -238,8 +222,7 @@ core.events._sys_battle = function (data: Block, callback?: () => void) {
|
|||||||
core.insertAction(beforeBattle, data.x, data.y, callback);
|
core.insertAction(beforeBattle, data.x, data.y, callback);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
const dir = findDir(data, core.status.hero.loc) as DamageDir;
|
this.battle(data.x, data.y, false, callback);
|
||||||
this.battle(data.x, data.y, dir, false, callback);
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -253,11 +236,7 @@ core.events._action_battle = function (data, x, y, prefix) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const [ex, ey] = this.__action_getLoc(data.loc, x, y, prefix) as LocArr;
|
const [ex, ey] = this.__action_getLoc(data.loc, x, y, prefix) as LocArr;
|
||||||
const dir = findDir(core.status.hero.loc, {
|
this.battle(ex, ey, true, core.doAction);
|
||||||
x: ex,
|
|
||||||
y: ey
|
|
||||||
}) as DamageDir;
|
|
||||||
this.battle(ex, ey, dir, true, core.doAction);
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -285,28 +264,16 @@ core.enemys.getCurrentEnemys = function (floorId = core.status.floorId) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
return enemys.sort((a, b) => {
|
return enemys.sort((a, b) => {
|
||||||
return (
|
const ad = a.enemy.calDamage().damage;
|
||||||
(a.enemy.damage?.[0]?.damage ?? Infinity) -
|
const bd = b.enemy.calDamage().damage;
|
||||||
(b.enemy.damage?.[0]?.damage ?? Infinity)
|
return ad - bd;
|
||||||
);
|
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
declare global {
|
declare global {
|
||||||
interface Events {
|
interface Events {
|
||||||
beforeBattle(
|
beforeBattle(enemy: DamageEnemy, x: number, y: number): boolean;
|
||||||
enemy: DamageEnemy,
|
afterBattle(enemy: DamageEnemy, x: number, y: number): void;
|
||||||
x: number,
|
|
||||||
y: number,
|
|
||||||
dir: DamageDir
|
|
||||||
): boolean;
|
|
||||||
|
|
||||||
afterBattle(
|
|
||||||
enemy: DamageEnemy,
|
|
||||||
x: number,
|
|
||||||
y: number,
|
|
||||||
dir: DamageDir
|
|
||||||
): void;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
interface Enemys {
|
interface Enemys {
|
||||||
|
@ -17,7 +17,7 @@ control.prototype.checkBlock = function (forceMockery: boolean = false) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
core.status.hero.hp -= damage;
|
core.status.hero.hp -= damage;
|
||||||
const type = Array.from(info.type.keys());
|
const type = [...info.type];
|
||||||
const text = type.join(',') || '伤害';
|
const text = type.join(',') || '伤害';
|
||||||
core.drawTip('受到' + text + damage + '点');
|
core.drawTip('受到' + text + damage + '点');
|
||||||
core.drawHeroAnimate('zone');
|
core.drawHeroAnimate('zone');
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
import { equal } from '../utils';
|
|
||||||
import { getHeroStatusOf, getHeroStatusOn } from '../hero';
|
import { getHeroStatusOf, getHeroStatusOn } from '../hero';
|
||||||
import { Range, RangeCollection } from '../range';
|
import { Range, RangeCollection } from '../range';
|
||||||
import {
|
import {
|
||||||
@ -36,10 +35,6 @@ interface EnemyInfo {
|
|||||||
|
|
||||||
interface DamageInfo {
|
interface DamageInfo {
|
||||||
damage: number;
|
damage: number;
|
||||||
/** 从怪物位置指向勇士的方向 */
|
|
||||||
dir: Dir | 'none';
|
|
||||||
x?: number;
|
|
||||||
y?: number;
|
|
||||||
/** 自动切换技能时使用的技能 */
|
/** 自动切换技能时使用的技能 */
|
||||||
skill?: number;
|
skill?: number;
|
||||||
}
|
}
|
||||||
@ -58,12 +53,9 @@ interface HaloData<T extends keyof HaloType = keyof HaloType> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
interface DamageDelta {
|
interface DamageDelta {
|
||||||
dir: DamageDir;
|
|
||||||
/** 跟最小伤害值的减伤 */
|
/** 跟最小伤害值的减伤 */
|
||||||
delta: number;
|
delta: number;
|
||||||
damage: number;
|
damage: number;
|
||||||
/** 跟当前方向的减伤 */
|
|
||||||
dirDelta: number;
|
|
||||||
info: DamageInfo;
|
info: DamageInfo;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -73,7 +65,6 @@ interface CriticalDamageDelta extends Omit<DamageDelta, 'info'> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type HaloFn = (info: EnemyInfo, enemy: Enemy) => void;
|
type HaloFn = (info: EnemyInfo, enemy: Enemy) => void;
|
||||||
export type DamageDir = Dir | 'none';
|
|
||||||
|
|
||||||
/** 光环属性 */
|
/** 光环属性 */
|
||||||
export const haloSpecials: number[] = [8, 21, 25, 26, 27];
|
export const haloSpecials: number[] = [8, 21, 25, 26, 27];
|
||||||
@ -129,10 +120,10 @@ export class EnemyCollection implements RangeCollection<DamageEnemy> {
|
|||||||
* 计算怪物伤害
|
* 计算怪物伤害
|
||||||
* @param noCache 是否不使用缓存
|
* @param noCache 是否不使用缓存
|
||||||
*/
|
*/
|
||||||
calDamage(noCache: boolean = false, onMap: boolean = false) {
|
calDamage(noCache: boolean = false) {
|
||||||
if (noCache) this.calRealAttribute();
|
if (noCache) this.calRealAttribute();
|
||||||
this.list.forEach(v => {
|
this.list.forEach(v => {
|
||||||
v.calDamage(void 0, onMap);
|
v.calDamage(void 0);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -141,12 +132,7 @@ export class EnemyCollection implements RangeCollection<DamageEnemy> {
|
|||||||
*/
|
*/
|
||||||
calMapDamage() {
|
calMapDamage() {
|
||||||
this.mapDamage = {};
|
this.mapDamage = {};
|
||||||
const hero = getHeroStatusOn(
|
const hero = getHeroStatusOn(realStatus, this.floorId);
|
||||||
realStatus,
|
|
||||||
core.status.hero.loc.x,
|
|
||||||
core.status.hero.loc.y,
|
|
||||||
this.floorId
|
|
||||||
);
|
|
||||||
this.list.forEach(v => {
|
this.list.forEach(v => {
|
||||||
v.calMapDamage(this.mapDamage, hero);
|
v.calMapDamage(this.mapDamage, hero);
|
||||||
});
|
});
|
||||||
@ -192,15 +178,8 @@ export class EnemyCollection implements RangeCollection<DamageEnemy> {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
render(onMap?: boolean): void;
|
render(onMap: boolean = false, cal: boolean = false) {
|
||||||
render(onMap: boolean, cal: boolean, noCache: boolean): void;
|
|
||||||
render(
|
|
||||||
onMap: boolean = false,
|
|
||||||
cal: boolean = false,
|
|
||||||
noCache: boolean = false
|
|
||||||
) {
|
|
||||||
if (cal) {
|
if (cal) {
|
||||||
this.calDamage(noCache, true);
|
|
||||||
this.calMapDamage();
|
this.calMapDamage();
|
||||||
}
|
}
|
||||||
core.status.damage.data = [];
|
core.status.damage.data = [];
|
||||||
@ -211,72 +190,23 @@ export class EnemyCollection implements RangeCollection<DamageEnemy> {
|
|||||||
this.list.forEach(v => {
|
this.list.forEach(v => {
|
||||||
if (onMap && !checkV2(v.x, v.y)) return;
|
if (onMap && !checkV2(v.x, v.y)) return;
|
||||||
|
|
||||||
if (!v.damage) {
|
const { damage } = v.calDamage();
|
||||||
throw new Error(
|
|
||||||
`Unexpected null of enemy's damage. Loc: '${v.x},${v.y}'. Floor: ${v.floorId}`
|
|
||||||
);
|
|
||||||
}
|
|
||||||
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 {
|
|
||||||
let min = v.damage[0].damage;
|
|
||||||
let max = min;
|
|
||||||
let minI = 0;
|
|
||||||
for (let i = 1; i < v.damage.length; i++) {
|
|
||||||
const dam = v.damage[i].damage;
|
|
||||||
if (dam < min) {
|
|
||||||
min = dam;
|
|
||||||
minI = i;
|
|
||||||
}
|
|
||||||
if (dam > max) {
|
|
||||||
max = dam;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
const delta = max - min;
|
|
||||||
const { damage, color } = formatDamage(min);
|
|
||||||
// 在怪物位置绘制最低的伤害
|
|
||||||
core.status.damage.data.push({
|
|
||||||
text: damage,
|
|
||||||
px: 32 * v.x! + 1,
|
|
||||||
py: 32 * (v.y! + 1) - 1,
|
|
||||||
color: color
|
|
||||||
});
|
|
||||||
// 绘制临界
|
|
||||||
const critical = v.calCritical(1, v.damage[minI].dir)[0]?.[0];
|
|
||||||
core.status.damage.data.push({
|
|
||||||
text: critical?.atkDelta.toString() ?? '?',
|
|
||||||
px: 32 * v.x! + 1,
|
|
||||||
py: 32 * (v.y! + 1) - 11,
|
|
||||||
color: '#fff'
|
|
||||||
});
|
|
||||||
// 然后根据位置依次绘制对应位置的伤害
|
|
||||||
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]);
|
|
||||||
|
|
||||||
core.status.damage.dir.push({
|
// 伤害全部相等,绘制在怪物本身所在位置
|
||||||
x: v.x!,
|
const { damage: dam, color } = formatDamage(damage);
|
||||||
y: v.y!,
|
const critical = v.calCritical(1)[0];
|
||||||
dir: dam.dir,
|
core.status.damage.data.push({
|
||||||
|
text: dam,
|
||||||
|
px: 32 * v.x! + 1,
|
||||||
|
py: 32 * (v.y! + 1) - 1,
|
||||||
color: color
|
color: color
|
||||||
});
|
});
|
||||||
}
|
core.status.damage.data.push({
|
||||||
}
|
text: critical?.atkDelta.toString() ?? '?',
|
||||||
|
px: 32 * v.x! + 1,
|
||||||
|
py: 32 * (v.y! + 1) - 11,
|
||||||
|
color: '#fff'
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
// 地图伤害
|
// 地图伤害
|
||||||
@ -362,10 +292,6 @@ export class DamageEnemy<T extends EnemyIds = EnemyIds> {
|
|||||||
* -> provide inject 光环 -> 计算怪物的光环加成 -> 计算完毕
|
* -> provide inject 光环 -> 计算怪物的光环加成 -> 计算完毕
|
||||||
*/
|
*/
|
||||||
info!: EnemyInfo;
|
info!: EnemyInfo;
|
||||||
/** 怪物伤害 */
|
|
||||||
damage?: DamageInfo[];
|
|
||||||
/** 是否需要计算伤害 */
|
|
||||||
needCalDamage: boolean = true;
|
|
||||||
|
|
||||||
/** 向其他怪提供过的光环 */
|
/** 向其他怪提供过的光环 */
|
||||||
providedHalo: number[] = [];
|
providedHalo: number[] = [];
|
||||||
@ -409,7 +335,6 @@ export class DamageEnemy<T extends EnemyIds = EnemyIds> {
|
|||||||
floorId: this.floorId
|
floorId: this.floorId
|
||||||
};
|
};
|
||||||
this.progress = 0;
|
this.progress = 0;
|
||||||
this.needCalDamage = true;
|
|
||||||
this.providedHalo = [];
|
this.providedHalo = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -578,17 +503,9 @@ export class DamageEnemy<T extends EnemyIds = EnemyIds> {
|
|||||||
/**
|
/**
|
||||||
* 计算怪物伤害
|
* 计算怪物伤害
|
||||||
*/
|
*/
|
||||||
calDamage(
|
calDamage(hero: Partial<HeroStatus> = core.status.hero) {
|
||||||
hero: Partial<HeroStatus> = core.status.hero,
|
const enemy = this.getRealInfo();
|
||||||
onMap: boolean = false
|
return this.calEnemyDamageOf(hero, enemy);
|
||||||
) {
|
|
||||||
if (onMap && !checkV2(this.x, this.y)) return this.damage!;
|
|
||||||
if (!this.needCalDamage) return this.damage!;
|
|
||||||
const dirs = getNeedCalDir(this.x, this.y, this.floorId, hero);
|
|
||||||
|
|
||||||
this.needCalDamage = false;
|
|
||||||
|
|
||||||
return (this.damage = this.calEnemyDamage(hero, dirs));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -695,44 +612,8 @@ export class DamageEnemy<T extends EnemyIds = EnemyIds> {
|
|||||||
damage[loc].type.add(type);
|
damage[loc].type.add(type);
|
||||||
}
|
}
|
||||||
|
|
||||||
calEnemyDamage(
|
private calEnemyDamageOf(hero: Partial<HeroStatus>, enemy: EnemyInfo) {
|
||||||
hero: Partial<HeroStatus> = core.status.hero,
|
const status = getHeroStatusOf(hero, realStatus, this.floorId);
|
||||||
dir: DamageDir | DamageDir[]
|
|
||||||
): DamageInfo[] {
|
|
||||||
const dirs = ensureArray(dir);
|
|
||||||
const enemy = this.getRealInfo();
|
|
||||||
|
|
||||||
return dirs.map(dir => {
|
|
||||||
let x: number | undefined;
|
|
||||||
let y: number | undefined;
|
|
||||||
if (has(this.x) && has(this.y)) {
|
|
||||||
if (dir !== 'none') {
|
|
||||||
[x, y] = ofDir(this.x, this.y, dir);
|
|
||||||
} else {
|
|
||||||
x = hero.x ?? this.x;
|
|
||||||
y = hero.y ?? this.y;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const { damage, skill } = this.calEnemyDamageOf(hero, enemy, x, y);
|
|
||||||
|
|
||||||
return {
|
|
||||||
damage,
|
|
||||||
dir,
|
|
||||||
skill,
|
|
||||||
x,
|
|
||||||
y
|
|
||||||
};
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
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 damage = calDamageWith(enemy, status) ?? Infinity;
|
||||||
let skill = -1;
|
let skill = -1;
|
||||||
|
|
||||||
@ -765,27 +646,11 @@ export class DamageEnemy<T extends EnemyIds = EnemyIds> {
|
|||||||
*/
|
*/
|
||||||
calCritical(
|
calCritical(
|
||||||
num: number = 1,
|
num: number = 1,
|
||||||
dir: DamageDir | DamageDir[] = 'none',
|
|
||||||
hero: Partial<HeroStatus> = core.status.hero
|
hero: Partial<HeroStatus> = core.status.hero
|
||||||
): CriticalDamageDelta[][] {
|
): CriticalDamageDelta[] {
|
||||||
const origin = this.calEnemyDamage(hero, dir);
|
const origin = this.calDamage(hero);
|
||||||
const min = Math.min(...origin.map(v => v.damage));
|
|
||||||
const seckill = this.getSeckillAtk();
|
const seckill = this.getSeckillAtk();
|
||||||
|
return this.calCriticalWith(num, seckill, origin, hero);
|
||||||
return origin.map(v => {
|
|
||||||
const dir = v.dir;
|
|
||||||
if (
|
|
||||||
dir === 'none' ||
|
|
||||||
!has(this.x) ||
|
|
||||||
!has(this.y) ||
|
|
||||||
!has(this.floorId)
|
|
||||||
) {
|
|
||||||
return this.calCriticalWith(num, min, seckill, v, hero);
|
|
||||||
} else {
|
|
||||||
const [x, y] = ofDir(this.x, this.y, dir);
|
|
||||||
return this.calCriticalWith(num, min, seckill, v, hero, x, y);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -797,12 +662,9 @@ export class DamageEnemy<T extends EnemyIds = EnemyIds> {
|
|||||||
*/
|
*/
|
||||||
private calCriticalWith(
|
private calCriticalWith(
|
||||||
num: number,
|
num: number,
|
||||||
min: number,
|
|
||||||
seckill: number,
|
seckill: number,
|
||||||
origin: DamageInfo,
|
origin: DamageInfo,
|
||||||
hero: Partial<HeroStatus>,
|
hero: Partial<HeroStatus>
|
||||||
x?: number,
|
|
||||||
y?: number
|
|
||||||
): CriticalDamageDelta[] {
|
): CriticalDamageDelta[] {
|
||||||
// todo: 可以优化,根据之前的计算可以直接确定下一个临界的范围
|
// todo: 可以优化,根据之前的计算可以直接确定下一个临界的范围
|
||||||
if (!isFinite(seckill)) return [];
|
if (!isFinite(seckill)) return [];
|
||||||
@ -819,8 +681,7 @@ export class DamageEnemy<T extends EnemyIds = EnemyIds> {
|
|||||||
let ori = origin.damage;
|
let ori = origin.damage;
|
||||||
|
|
||||||
const calDam = () => {
|
const calDam = () => {
|
||||||
return this.calEnemyDamageOf({ atk: curr, def }, enemy, x, y)
|
return this.calEnemyDamageOf({ atk: curr, def }, enemy).damage;
|
||||||
.damage;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let i = 0;
|
let i = 0;
|
||||||
@ -835,9 +696,7 @@ export class DamageEnemy<T extends EnemyIds = EnemyIds> {
|
|||||||
res.push({
|
res.push({
|
||||||
damage: dam,
|
damage: dam,
|
||||||
atkDelta: Math.ceil(v - hero.atk!),
|
atkDelta: Math.ceil(v - hero.atk!),
|
||||||
dir: origin.dir,
|
delta: dam - ori
|
||||||
delta: dam - min,
|
|
||||||
dirDelta: dam - origin.damage
|
|
||||||
});
|
});
|
||||||
|
|
||||||
start = v;
|
start = v;
|
||||||
@ -872,9 +731,7 @@ export class DamageEnemy<T extends EnemyIds = EnemyIds> {
|
|||||||
res.push({
|
res.push({
|
||||||
damage: dam,
|
damage: dam,
|
||||||
atkDelta: 0,
|
atkDelta: 0,
|
||||||
dir: origin.dir,
|
delta: 0
|
||||||
delta: dam - min,
|
|
||||||
dirDelta: 0
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -889,26 +746,19 @@ export class DamageEnemy<T extends EnemyIds = EnemyIds> {
|
|||||||
*/
|
*/
|
||||||
calDefDamage(
|
calDefDamage(
|
||||||
num: number = 1,
|
num: number = 1,
|
||||||
dir: DamageDir | DamageDir[] = 'none',
|
|
||||||
hero: Partial<HeroStatus> = core.status.hero
|
hero: Partial<HeroStatus> = core.status.hero
|
||||||
): DamageDelta[] {
|
): DamageDelta {
|
||||||
const damage = this.calEnemyDamage(
|
const damage = this.calDamage({
|
||||||
{ def: (hero.def ?? core.status.hero.def) + num },
|
def: (hero.def ?? core.status.hero.def) + num
|
||||||
dir
|
|
||||||
);
|
|
||||||
const origin = this.calEnemyDamage(hero, dir);
|
|
||||||
const min = Math.min(...origin.map(v => v.damage));
|
|
||||||
|
|
||||||
return damage.map((v, i) => {
|
|
||||||
const finite = isFinite(v.damage);
|
|
||||||
return {
|
|
||||||
dir: v.dir,
|
|
||||||
damage: v.damage,
|
|
||||||
info: v,
|
|
||||||
delta: finite ? v.damage - min : Infinity,
|
|
||||||
dirDelta: finite ? v.damage - origin[i].damage : Infinity
|
|
||||||
};
|
|
||||||
});
|
});
|
||||||
|
const origin = this.calDamage(hero);
|
||||||
|
const finite = isFinite(damage.damage);
|
||||||
|
|
||||||
|
return {
|
||||||
|
damage: damage.damage,
|
||||||
|
info: damage,
|
||||||
|
delta: finite ? damage.damage - origin.damage : Infinity
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -923,7 +773,7 @@ export class DamageEnemy<T extends EnemyIds = EnemyIds> {
|
|||||||
return Infinity;
|
return Infinity;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 列方程求解
|
// 列方程求解,拿笔算一下就知道了
|
||||||
// 饥渴,会偷取勇士攻击
|
// 饥渴,会偷取勇士攻击
|
||||||
if (info.special.includes(7)) {
|
if (info.special.includes(7)) {
|
||||||
if (info.damageDecline === 0) {
|
if (info.damageDecline === 0) {
|
||||||
@ -971,47 +821,6 @@ const skills: [unlock: string, condition: string][] = [
|
|||||||
['shieldOn', 'shield']
|
['shieldOn', 'shield']
|
||||||
];
|
];
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取需要计算怪物伤害的方向
|
|
||||||
* @param x 怪物横坐标
|
|
||||||
* @param y 怪物纵坐标
|
|
||||||
* @param floorId 怪物所在楼层
|
|
||||||
* @returns 由怪物方向指向勇士的方向
|
|
||||||
*/
|
|
||||||
export function getNeedCalDir(
|
|
||||||
x?: number,
|
|
||||||
y?: number,
|
|
||||||
floorId?: FloorIds,
|
|
||||||
hero: Partial<HeroStatus> = core.status.hero
|
|
||||||
): (Dir | 'none')[] {
|
|
||||||
// 第一章或序章,或者没有指定怪物位置,或者没开自动定位,用不到这个函数
|
|
||||||
if (flags.chapter < 2 || !has(x) || !has(y) || !floorId) {
|
|
||||||
return ['none'];
|
|
||||||
}
|
|
||||||
|
|
||||||
// 如果指定了勇士坐标
|
|
||||||
if (has(hero.x) && has(hero.y)) {
|
|
||||||
return ['none'];
|
|
||||||
}
|
|
||||||
|
|
||||||
const needMap: Dir[] = ['left', 'down', 'right', 'up'];
|
|
||||||
const { width, height } = core.status.maps[floorId];
|
|
||||||
const blocks = core.getMapBlocksObj(floorId);
|
|
||||||
|
|
||||||
const res = needMap.filter(v => {
|
|
||||||
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 || block.event.cls === 'items') return false;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
});
|
|
||||||
return res.length === 0 ? ['none'] : res;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 计算怪物伤害
|
* 计算怪物伤害
|
||||||
* @param info 怪物信息
|
* @param info 怪物信息
|
||||||
@ -1123,7 +932,7 @@ export function getSingleEnemy(id: EnemyIds) {
|
|||||||
const enemy = new DamageEnemy(e);
|
const enemy = new DamageEnemy(e);
|
||||||
enemy.calAttribute();
|
enemy.calAttribute();
|
||||||
enemy.getRealInfo();
|
enemy.getRealInfo();
|
||||||
enemy.calDamage(core.status.hero, false)[0];
|
enemy.calDamage(core.status.hero);
|
||||||
return enemy;
|
return enemy;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -19,7 +19,7 @@ core.control.updateDamage = function (floorId = core.status.floorId, ctx) {
|
|||||||
ensureFloorDamage(floorId);
|
ensureFloorDamage(floorId);
|
||||||
|
|
||||||
floor.enemy.extract();
|
floor.enemy.extract();
|
||||||
floor.enemy.calDamage(true, onMap);
|
floor.enemy.calDamage(true);
|
||||||
floor.enemy.calMapDamage();
|
floor.enemy.calMapDamage();
|
||||||
core.status.damage.data = [];
|
core.status.damage.data = [];
|
||||||
|
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
import { getEnemy } from '../enemy/battle';
|
import { getEnemy } from '../enemy/battle';
|
||||||
import { DamageDir, getNeedCalDir } from '../enemy/damage';
|
|
||||||
import { formatDamage } from '../utils';
|
import { formatDamage } from '../utils';
|
||||||
|
|
||||||
core.maps._initDetachedBlock = function (
|
core.maps._initDetachedBlock = function (
|
||||||
@ -37,16 +36,8 @@ core.maps._initDetachedBlock = function (
|
|||||||
displayDamage
|
displayDamage
|
||||||
) {
|
) {
|
||||||
const enemy = getEnemy(x, y);
|
const enemy = getEnemy(x, y);
|
||||||
const dam = enemy.calEnemyDamage(core.status.hero, getNeedCalDir(x, y));
|
const dam = enemy.calDamage();
|
||||||
let min = Infinity;
|
const { damage, color } = formatDamage(dam.damage);
|
||||||
let minDir: DamageDir = 'none';
|
|
||||||
for (const d of dam) {
|
|
||||||
if (d.damage < min) {
|
|
||||||
min = d.damage;
|
|
||||||
minDir = d.dir;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
const { damage, color } = formatDamage(min);
|
|
||||||
|
|
||||||
damageCanvas = '__damage_' + x + '_' + y;
|
damageCanvas = '__damage_' + x + '_' + y;
|
||||||
const ctx = core.createCanvas(damageCanvas, 0, 0, 32, 32, 65);
|
const ctx = core.createCanvas(damageCanvas, 0, 0, 32, 32, 65);
|
||||||
@ -54,8 +45,8 @@ core.maps._initDetachedBlock = function (
|
|||||||
ctx.font = '14px normal';
|
ctx.font = '14px normal';
|
||||||
core.fillBoldText(ctx, damage, 1, 31, color as string);
|
core.fillBoldText(ctx, damage, 1, 31, color as string);
|
||||||
if (core.flags.displayCritical) {
|
if (core.flags.displayCritical) {
|
||||||
const critical = enemy.calCritical(1, minDir)[0];
|
const critical = enemy.calCritical(1);
|
||||||
const atk = core.formatBigNumber(critical[0].dirDelta, true);
|
const atk = core.formatBigNumber(critical[0]?.delta, true);
|
||||||
const display = atk === '???' ? '?' : atk;
|
const display = atk === '???' ? '?' : atk;
|
||||||
core.fillBoldText(ctx, display, 1, 21, '#FFFFFF');
|
core.fillBoldText(ctx, display, 1, 21, '#FFFFFF');
|
||||||
}
|
}
|
||||||
|
@ -5,32 +5,21 @@
|
|||||||
* @param y 勇士所在纵坐标
|
* @param y 勇士所在纵坐标
|
||||||
* @param floorId 勇士所在楼层
|
* @param floorId 勇士所在楼层
|
||||||
*/
|
*/
|
||||||
export function getHeroStatusOn(
|
export function getHeroStatusOn(name: 'all', floorId?: FloorIds): HeroStatus;
|
||||||
name: 'all',
|
|
||||||
x?: number,
|
|
||||||
y?: number,
|
|
||||||
floorId?: FloorIds
|
|
||||||
): HeroStatus;
|
|
||||||
export function getHeroStatusOn(
|
export function getHeroStatusOn(
|
||||||
name: (keyof HeroStatus)[],
|
name: (keyof HeroStatus)[],
|
||||||
x?: number,
|
|
||||||
y?: number,
|
|
||||||
floorId?: FloorIds
|
floorId?: FloorIds
|
||||||
): Partial<HeroStatus>;
|
): Partial<HeroStatus>;
|
||||||
export function getHeroStatusOn<K extends keyof HeroStatus>(
|
export function getHeroStatusOn<K extends keyof HeroStatus>(
|
||||||
name: K,
|
name: K,
|
||||||
x?: number,
|
|
||||||
y?: number,
|
|
||||||
floorId?: FloorIds
|
floorId?: FloorIds
|
||||||
): HeroStatus[K];
|
): HeroStatus[K];
|
||||||
export function getHeroStatusOn(
|
export function getHeroStatusOn(
|
||||||
name: keyof HeroStatus | 'all' | (keyof HeroStatus)[],
|
name: keyof HeroStatus | 'all' | (keyof HeroStatus)[],
|
||||||
x?: number,
|
|
||||||
y?: number,
|
|
||||||
floorId?: FloorIds
|
floorId?: FloorIds
|
||||||
) {
|
) {
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
return getHeroStatusOf(core.status.hero, name, x, y, floorId);
|
return getHeroStatusOf(core.status.hero, name, floorId);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -44,44 +33,34 @@ export function getHeroStatusOn(
|
|||||||
export function getHeroStatusOf(
|
export function getHeroStatusOf(
|
||||||
status: Partial<HeroStatus>,
|
status: Partial<HeroStatus>,
|
||||||
name: 'all',
|
name: 'all',
|
||||||
x?: number,
|
|
||||||
y?: number,
|
|
||||||
floorId?: FloorIds
|
floorId?: FloorIds
|
||||||
): HeroStatus;
|
): HeroStatus;
|
||||||
export function getHeroStatusOf(
|
export function getHeroStatusOf(
|
||||||
status: Partial<HeroStatus>,
|
status: Partial<HeroStatus>,
|
||||||
name: (keyof HeroStatus)[],
|
name: (keyof HeroStatus)[],
|
||||||
x?: number,
|
|
||||||
y?: number,
|
|
||||||
floorId?: FloorIds
|
floorId?: FloorIds
|
||||||
): Partial<HeroStatus>;
|
): Partial<HeroStatus>;
|
||||||
export function getHeroStatusOf<K extends keyof HeroStatus>(
|
export function getHeroStatusOf<K extends keyof HeroStatus>(
|
||||||
status: Partial<HeroStatus>,
|
status: Partial<HeroStatus>,
|
||||||
name: K,
|
name: K,
|
||||||
x?: number,
|
|
||||||
y?: number,
|
|
||||||
floorId?: FloorIds
|
floorId?: FloorIds
|
||||||
): HeroStatus[K];
|
): HeroStatus[K];
|
||||||
export function getHeroStatusOf(
|
export function getHeroStatusOf(
|
||||||
status: DeepPartial<HeroStatus>,
|
status: DeepPartial<HeroStatus>,
|
||||||
name: keyof HeroStatus | 'all' | (keyof HeroStatus)[],
|
name: keyof HeroStatus | 'all' | (keyof HeroStatus)[],
|
||||||
x?: number,
|
|
||||||
y?: number,
|
|
||||||
floorId?: FloorIds
|
floorId?: FloorIds
|
||||||
) {
|
) {
|
||||||
return getRealStatus(status, name, x, y, floorId);
|
return getRealStatus(status, name, floorId);
|
||||||
}
|
}
|
||||||
|
|
||||||
function getRealStatus(
|
function getRealStatus(
|
||||||
status: DeepPartial<HeroStatus>,
|
status: DeepPartial<HeroStatus>,
|
||||||
name: keyof HeroStatus | 'all' | (keyof HeroStatus)[],
|
name: keyof HeroStatus | 'all' | (keyof HeroStatus)[],
|
||||||
x?: number,
|
floorId: FloorIds = core.status.floorId
|
||||||
y?: number,
|
|
||||||
floorId?: FloorIds
|
|
||||||
): any {
|
): any {
|
||||||
if (name instanceof Array) {
|
if (name instanceof Array) {
|
||||||
return Object.fromEntries(
|
return Object.fromEntries(
|
||||||
name.map(v => [v, getRealStatus(status, v, x, y, floorId)])
|
name.map(v => [v, getRealStatus(status, v, floorId)])
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -90,7 +69,7 @@ function getRealStatus(
|
|||||||
Object.keys(core.status.hero).map(v => [
|
Object.keys(core.status.hero).map(v => [
|
||||||
v,
|
v,
|
||||||
v !== 'all' &&
|
v !== 'all' &&
|
||||||
getRealStatus(status, v as keyof HeroStatus, x, y, floorId)
|
getRealStatus(status, v as keyof HeroStatus, floorId)
|
||||||
])
|
])
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -102,10 +81,6 @@ function getRealStatus(
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
x ??= core.status.hero.loc.x;
|
|
||||||
y ??= core.status.hero.loc.y;
|
|
||||||
floorId ??= core.status.floorId;
|
|
||||||
|
|
||||||
// 永夜、极昼
|
// 永夜、极昼
|
||||||
if (name === 'atk' || name === 'def') {
|
if (name === 'atk' || name === 'def') {
|
||||||
s += window.flags?.[`night_${floorId}`] ?? 0;
|
s += window.flags?.[`night_${floorId}`] ?? 0;
|
||||||
|
@ -65,13 +65,11 @@ export function getDetailedEnemy(
|
|||||||
|
|
||||||
const ratio = core.status.maps[floorId].ratio;
|
const ratio = core.status.maps[floorId].ratio;
|
||||||
|
|
||||||
const dam = enemy.calEnemyDamage(core.status.hero, 'none')[0].damage;
|
const dam = enemy.calDamage().damage;
|
||||||
const cri = enemy.calCritical(1, 'none')[0]?.[0];
|
const cri = enemy.calCritical(1)[0];
|
||||||
const critical = core.formatBigNumber(cri?.atkDelta);
|
const critical = core.formatBigNumber(cri?.atkDelta);
|
||||||
const criticalDam = core.formatBigNumber(cri?.delta);
|
const criticalDam = core.formatBigNumber(cri?.delta);
|
||||||
const defDam = core.formatBigNumber(
|
const defDam = core.formatBigNumber(enemy.calDefDamage(ratio).damage);
|
||||||
enemy.calDefDamage(ratio, 'none')[0].damage
|
|
||||||
);
|
|
||||||
const damage = core.formatBigNumber(dam);
|
const damage = core.formatBigNumber(dam);
|
||||||
|
|
||||||
const fromFunc = (
|
const fromFunc = (
|
||||||
|
1
src/types/event.d.ts
vendored
1
src/types/event.d.ts
vendored
@ -111,7 +111,6 @@ interface Events extends EventData {
|
|||||||
battle(
|
battle(
|
||||||
x: number,
|
x: number,
|
||||||
y: number,
|
y: number,
|
||||||
dir: Dir | 'none',
|
|
||||||
force: boolean = false,
|
force: boolean = false,
|
||||||
callback?: () => void
|
callback?: () => void
|
||||||
): void;
|
): void;
|
||||||
|
17
src/types/plugin.d.ts
vendored
17
src/types/plugin.d.ts
vendored
@ -363,22 +363,13 @@ interface GamePluginHeroRealStatus {
|
|||||||
* @param y 勇士所在纵坐标
|
* @param y 勇士所在纵坐标
|
||||||
* @param floorId 勇士所在楼层
|
* @param floorId 勇士所在楼层
|
||||||
*/
|
*/
|
||||||
getHeroStatusOn(
|
getHeroStatusOn(name: 'all', floorId?: FloorIds): HeroStatus;
|
||||||
name: 'all',
|
|
||||||
x?: number,
|
|
||||||
y?: number,
|
|
||||||
floorId?: FloorIds
|
|
||||||
): HeroStatus;
|
|
||||||
getHeroStatusOn(
|
getHeroStatusOn(
|
||||||
name: (keyof HeroStatus)[],
|
name: (keyof HeroStatus)[],
|
||||||
x?: number,
|
|
||||||
y?: number,
|
|
||||||
floorId?: FloorIds
|
floorId?: FloorIds
|
||||||
): Partial<HeroStatus>;
|
): Partial<HeroStatus>;
|
||||||
getHeroStatusOn<K extends keyof HeroStatus>(
|
getHeroStatusOn<K extends keyof HeroStatus>(
|
||||||
name: K,
|
name: K,
|
||||||
x?: number,
|
|
||||||
y?: number,
|
|
||||||
floorId?: FloorIds
|
floorId?: FloorIds
|
||||||
): HeroStatus[K];
|
): HeroStatus[K];
|
||||||
|
|
||||||
@ -393,22 +384,16 @@ interface GamePluginHeroRealStatus {
|
|||||||
getHeroStatusOf(
|
getHeroStatusOf(
|
||||||
status: Partial<HeroStatus>,
|
status: Partial<HeroStatus>,
|
||||||
name: 'all',
|
name: 'all',
|
||||||
x?: number,
|
|
||||||
y?: number,
|
|
||||||
floorId?: FloorIds
|
floorId?: FloorIds
|
||||||
): HeroStatus;
|
): HeroStatus;
|
||||||
getHeroStatusOf(
|
getHeroStatusOf(
|
||||||
status: Partial<HeroStatus>,
|
status: Partial<HeroStatus>,
|
||||||
name: (keyof HeroStatus)[],
|
name: (keyof HeroStatus)[],
|
||||||
x?: number,
|
|
||||||
y?: number,
|
|
||||||
floorId?: FloorIds
|
floorId?: FloorIds
|
||||||
): Partial<HeroStatus>;
|
): Partial<HeroStatus>;
|
||||||
getHeroStatusOf<K extends keyof HeroStatus>(
|
getHeroStatusOf<K extends keyof HeroStatus>(
|
||||||
status: Partial<HeroStatus>,
|
status: Partial<HeroStatus>,
|
||||||
name: K,
|
name: K,
|
||||||
x?: number,
|
|
||||||
y?: number,
|
|
||||||
floorId?: FloorIds
|
floorId?: FloorIds
|
||||||
): HeroStatus[K];
|
): HeroStatus[K];
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user