获取怪物属性与光环加成

This commit is contained in:
unanmed 2023-05-04 22:06:25 +08:00
parent 068dca14f9
commit 19b2256efb
5 changed files with 343 additions and 100 deletions

View File

@ -1,5 +1,6 @@
import { getHeroStatusOf, getHeroStatusOn } from './hero';
import { Range, RangeCollection } from './range';
import { ensureArray } from './utils';
import { ensureArray, has } from './utils';
interface HaloType {
square: {
@ -9,7 +10,23 @@ interface HaloType {
};
}
type HaloFn<T extends EnemyIds = EnemyIds> = (enemy: Enemy<T>) => Enemy<T>;
interface EnemyInfo {
atk: number;
def: number;
hp: number;
special: number[];
damageDecline: number;
atkBuff: number;
defBuff: number;
hpBuff: number;
together: number;
}
interface DamageInfo {
damage: number;
}
type HaloFn = (info: EnemyInfo, enemy: Enemy) => void;
export const haloSpecials: number[] = [21, 25, 26, 27];
@ -41,7 +58,7 @@ export class EnemyCollection implements RangeCollection<DamageEnemy> {
* @param type
* @param data
* @param halo
* @param recursion 使
* @param recursion 使
*/
applyHalo<K extends keyof HaloType>(
type: K,
@ -50,12 +67,31 @@ export class EnemyCollection implements RangeCollection<DamageEnemy> {
recursion: boolean = false
) {
const arr = ensureArray(halo);
const enemy = this.range.scan(type, data);
if (!recursion) {
arr.forEach(v => {
enemy.forEach(e => {
e.injectHalo(v);
});
});
} else {
enemy.forEach(e => {
arr.forEach(v => {
e.injectHalo(v);
e.preProvideHalo();
});
});
}
}
/**
*
*/
preBalanceHalo() {}
preBalanceHalo() {
this.list.forEach(v => {
v.preProvideHalo();
});
}
}
export class DamageEnemy<T extends EnemyIds = EnemyIds> {
@ -65,10 +101,15 @@ export class DamageEnemy<T extends EnemyIds = EnemyIds> {
floorId?: FloorIds;
enemy: Enemy<T>;
/** 计算特殊属性但不计算光环的属性 */
noHaloInfo?: Enemy<T>;
/** 既计算特殊属性又计算光环的属性 */
realInfo?: Enemy<T>;
/** 怪物属性 */
info!: EnemyInfo;
/** 是否需要计算属性 */
needCalculate: boolean = true;
/** 怪物伤害 */
damage?: DamageInfo;
/** 是否需要计算伤害 */
needCalDamage: boolean = true;
/** 向其他怪提供过的光环 */
providedHalo: number[] = [];
@ -78,19 +119,99 @@ export class DamageEnemy<T extends EnemyIds = EnemyIds> {
this.x = x;
this.y = y;
this.floorId = floorId;
this.reset();
}
reset() {
delete this.noHaloInfo;
delete this.realInfo;
const enemy = this.enemy;
this.info = {
hp: enemy.hp,
atk: enemy.atk,
def: enemy.def,
special: enemy.special.slice(),
damageDecline: 0,
atkBuff: 0,
defBuff: 0,
hpBuff: 0,
together: 0
};
this.needCalculate = true;
this.needCalDamage = true;
}
calAttribute() {}
/**
* inject光环之前
* @param hero
* @param getReal
* @returns
*/
calAttribute(
hero: Partial<HeroStatus> = core.status.hero,
getReal: boolean = true
) {
if (!this.needCalculate) return;
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)) {
info.atk += flags[`inte_${floorId}`] ?? 0;
}
// 极昼永夜
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}`])) {
const [mx, my] = loc.split(',').map(v => parseInt(v));
if (Math.abs(mx - this.x) <= 1 && Math.abs(my - this.y) <= 1) {
info.atkBuff += per as number;
info.defBuff += per as number;
}
}
}
}
/**
* inject光环后执行
*/
getRealInfo() {
if (!this.needCalculate) return this.info;
// 此时已经inject光环因此直接计算真实属性
const info = this.info;
info.atk *= info.atkBuff / 100 + 1;
info.def *= info.defBuff / 100 + 1;
info.hp *= info.hpBuff / 100 + 1;
this.needCalculate = false;
return this.info;
}
getHaloSpecials(): number[] {
if (!this.floorId) return [];
if (!core.has(this.x) || !core.has(this.y)) return [];
const special = this.realInfo?.special ?? this.enemy.special;
const special = this.info.special ?? this.enemy.special;
const filter = special.filter(v => {
return haloSpecials.includes(v) && !this.providedHalo.includes(v);
});
@ -113,22 +234,73 @@ export class DamageEnemy<T extends EnemyIds = EnemyIds> {
*
*/
provideHalo() {
if (!this.floorId) return;
if (!core.has(this.x) || !core.has(this.y)) return;
const collection = core.status.maps[this.floorId].enemy;
const speical = this.getHaloSpecials();
const square7: HaloFn[] = [];
const square5: HaloFn[] = [];
if (speical.includes(21)) {
if (speical.includes(8)) {
square5.push((e, enemy) => {
if (e === this.info) e.together += enemy.together ?? 0;
});
this.providedHalo.push(8);
}
// 冰封光环
if (speical.includes(21)) {
square7.push((e, enemy) => {
e.damageDecline += enemy.iceDecline ?? 0;
});
this.providedHalo.push(21);
}
// 冰封之核
if (speical.includes(26)) {
square5.push((e, enemy) => {
e.defBuff += enemy.iceCore ?? 0;
});
this.providedHalo.push(26);
}
// 火焰之核
if (speical.includes(27)) {
square5.push((e, enemy) => {
e.atkBuff += enemy.fireCore ?? 0;
});
this.providedHalo.push(27);
}
collection.applyHalo('square', { x: this.x, y: this.y, d: 7 }, square7);
collection.applyHalo('square', { x: this.x, y: this.y, d: 5 }, square5);
}
/**
*
*/
injectHalo(halo: HaloFn<T>) {}
injectHalo(halo: HaloFn) {
halo.call(this, this.info, this.enemy);
}
calDamage() {}
/**
*
*/
calDamage() {
if (!this.needCalDamage) return this.damage!;
const info = this.getRealInfo();
}
}
/**
*
* @param x
* @param y
* @param floorId
*/
export function getNeedCalDir(x: number, y: number, floorId: FloorIds) {}
declare global {
interface PluginDeclaration {
damage: {

View File

@ -1,84 +0,0 @@
///<reference path="../../../src/types/core.d.ts" />
/**
* 获取勇士在某一点的属性
* @param {keyof HeroStatus | 'all'} name
* @param {number} x
* @param {number} y
* @param {FloorIds} floorId
*/
export function getHeroStatusOn(name, x, y, floorId) {
return getHeroStatusOf(core.status.hero, name, x, y, floorId);
}
export function getHeroStatusOf(status, name, x, y, floorId) {
return getRealStatus(status, name, x, y, floorId);
}
function getRealStatus(status, name, x, y, floorId) {
if (name instanceof Array) {
return Object.fromEntries(
name.map(v => [
v,
v !== 'all' && getRealStatus(status, v, x, y, floorId)
])
);
}
if (name === 'all') {
return Object.fromEntries(
Object.keys(core.status.hero).map(v => [
v,
v !== 'all' && getRealStatus(status, v, x, y, floorId)
])
);
}
let s = status?.[name] ?? core.status.hero[name];
if (s === null || s === void 0) {
throw new ReferenceError(
`Wrong hero status property name is delivered: ${name}`
);
}
x ??= core.status.hero.loc.x;
y ??= core.status.hero.loc.y;
floorId ??= core.status.floorId;
// 永夜、极昼
if (name === 'atk' || name === 'def') {
s += window.flags?.[`night_${floorId}`] ?? 0;
}
// 技能
if (flags.bladeOn && flags.blade) {
const level = core.plugin.skillTree.getSkillLevel(2);
if (name === 'atk') {
s *= 1 + 0.1 * level;
}
if (name === 'def') {
s *= 1 - 0.1 * level;
}
}
if (flags.shield && flags.shieldOn) {
const level = core.plugin.skillTree.getSkillLevel(10);
if (name === 'atk') {
s *= 1 - 0.1 * level;
}
if (name === 'def') {
s *= 1 + 0.1 * level;
}
}
// buff
if (typeof s === 'number') s *= core.getBuff(name);
// 取整
if (typeof s === 'number') s = Math.floor(s);
return s;
}
core.plugin.hero = {
getHeroStatusOf,
getHeroStatusOn
};

146
src/plugin/game/hero.ts Normal file
View File

@ -0,0 +1,146 @@
/**
*
* @param name
* @param x
* @param y
* @param floorId
*/
export function getHeroStatusOn(
name: 'all',
x?: number,
y?: number,
floorId?: FloorIds
): HeroStatus;
export function getHeroStatusOn(
name: (keyof HeroStatus)[],
x?: number,
y?: number,
floorId?: FloorIds
): Partial<HeroStatus>;
export function getHeroStatusOn<K extends keyof HeroStatus>(
name: K,
x?: number,
y?: number,
floorId?: FloorIds
): HeroStatus[K];
export function getHeroStatusOn(
name: keyof HeroStatus | 'all' | (keyof HeroStatus)[],
x?: number,
y?: number,
floorId?: FloorIds
) {
// @ts-ignore
return getHeroStatusOf(core.status.hero, name, x, y, floorId);
}
/**
*
* @param status
* @param name
* @param x
* @param y
* @param floorId
*/
export function getHeroStatusOf(
status: Partial<HeroStatus>,
name: 'all',
x?: number,
y?: number,
floorId?: FloorIds
): HeroStatus;
export function getHeroStatusOf(
status: Partial<HeroStatus>,
name: (keyof HeroStatus)[],
x?: number,
y?: number,
floorId?: FloorIds
): Partial<HeroStatus>;
export function getHeroStatusOf<K extends keyof HeroStatus>(
status: Partial<HeroStatus>,
name: K,
x?: number,
y?: number,
floorId?: FloorIds
): HeroStatus[K];
export function getHeroStatusOf(
status: DeepPartial<HeroStatus>,
name: keyof HeroStatus | 'all' | (keyof HeroStatus)[],
x?: number,
y?: number,
floorId?: FloorIds
) {
return getRealStatus(status, name, x, y, floorId);
}
function getRealStatus(
status: DeepPartial<HeroStatus>,
name: keyof HeroStatus | 'all' | (keyof HeroStatus)[],
x?: number,
y?: number,
floorId?: FloorIds
): any {
if (name instanceof Array) {
return Object.fromEntries(
name.map(v => [v, getRealStatus(status, v, x, y, floorId)])
);
}
if (name === 'all') {
return Object.fromEntries(
Object.keys(core.status.hero).map(v => [
v,
v !== 'all' &&
getRealStatus(status, v as keyof HeroStatus, x, y, floorId)
])
);
}
let s = (status?.[name] ?? core.status.hero[name]) as number;
if (s === null || s === void 0) {
throw new ReferenceError(
`Wrong hero status property name is delivered: ${name}`
);
}
x ??= core.status.hero.loc.x;
y ??= core.status.hero.loc.y;
floorId ??= core.status.floorId;
// 永夜、极昼
if (name === 'atk' || name === 'def') {
s += window.flags?.[`night_${floorId}`] ?? 0;
}
// 技能
if (flags.bladeOn && flags.blade) {
const level = core.plugin.skillTree.getSkillLevel(2);
if (name === 'atk') {
s *= 1 + 0.1 * level;
}
if (name === 'def') {
s *= 1 - 0.1 * level;
}
}
if (flags.shield && flags.shieldOn) {
const level = core.plugin.skillTree.getSkillLevel(10);
if (name === 'atk') {
s *= 1 - 0.1 * level;
}
if (name === 'def') {
s *= 1 + 0.1 * level;
}
}
// buff
if (typeof s === 'number')
s *= core.getBuff(name as keyof NumbericHeroStatus);
// 取整
if (typeof s === 'number') s = Math.floor(s);
return s;
}
core.plugin.hero = {
getHeroStatusOf,
getHeroStatusOn
};

View File

@ -15,7 +15,12 @@ type PartialNumbericEnemyProperty =
| 'purify'
| 'atkValue'
| 'defValue'
| 'damage';
| 'damage'
| 'iceDecline'
| 'iceCore'
| 'fireCore'
| 'together'
| 'hungry';
type BooleanEnemyProperty =
| 'zoneSquare'

View File

@ -968,4 +968,8 @@ interface HeroStatus {
last: [];
[k: string]: any;
};
x?: number;
y?: number;
floorId?: FloorIds;
}