mirror of
https://github.com/unanmed/HumanBreak.git
synced 2026-11-02 17:44:31 +08:00
范围类
This commit is contained in:
1 parent
2e7e64b399
commit
068dca14f9
6 files changed
+287
-41
No files matched your search
+143
-4
@@ -1,9 +1,148 @@
|
||||
///<reference path="../../../src/types/core.d.ts" />
|
||||
import { Range, RangeCollection } from './range';
|
||||
import { ensureArray } from './utils';
|
||||
|
||||
export class EnemyCollection {}
|
||||
interface HaloType {
|
||||
square: {
|
||||
x: number;
|
||||
y: number;
|
||||
d: number;
|
||||
};
|
||||
}
|
||||
|
||||
export class Enemy {}
|
||||
type HaloFn<T extends EnemyIds = EnemyIds> = (enemy: Enemy<T>) => Enemy<T>;
|
||||
|
||||
export const haloSpecials: number[] = [21, 25, 26, 27];
|
||||
|
||||
export class EnemyCollection implements RangeCollection<DamageEnemy> {
|
||||
floorId: FloorIds;
|
||||
list: DamageEnemy[] = [];
|
||||
|
||||
range: Range<DamageEnemy> = new Range(this);
|
||||
|
||||
constructor(floorId: FloorIds) {
|
||||
this.floorId = floorId;
|
||||
}
|
||||
|
||||
extract() {
|
||||
core.extractBlocks(this.floorId);
|
||||
core.status.maps[this.floorId].blocks.forEach(v => {
|
||||
if (v.event.cls !== 'enemy48' && v.event.cls !== 'enemys') return;
|
||||
const enemy = core.material.enemys[v.event.id as EnemyIds];
|
||||
this.list.push(new DamageEnemy(enemy));
|
||||
});
|
||||
}
|
||||
|
||||
calAttribute(noCache: boolean = false) {}
|
||||
|
||||
calDamage(noCache: boolean = false) {}
|
||||
|
||||
/**
|
||||
* 向怪物施加光环
|
||||
* @param type 光环的范围类型
|
||||
* @param data 光环范围信息
|
||||
* @param halo 光环效果函数
|
||||
* @param recursion 是否递归施加,一般只有在光环预平衡阶段会使用到
|
||||
*/
|
||||
applyHalo<K extends keyof HaloType>(
|
||||
type: K,
|
||||
data: HaloType[K],
|
||||
halo: HaloFn | HaloFn[],
|
||||
recursion: boolean = false
|
||||
) {
|
||||
const arr = ensureArray(halo);
|
||||
}
|
||||
|
||||
/**
|
||||
* 预平衡光环
|
||||
*/
|
||||
preBalanceHalo() {}
|
||||
}
|
||||
|
||||
export class DamageEnemy<T extends EnemyIds = EnemyIds> {
|
||||
id: T;
|
||||
x?: number;
|
||||
y?: number;
|
||||
floorId?: FloorIds;
|
||||
enemy: Enemy<T>;
|
||||
|
||||
/** 计算特殊属性但不计算光环的属性 */
|
||||
noHaloInfo?: Enemy<T>;
|
||||
/** 既计算特殊属性又计算光环的属性 */
|
||||
realInfo?: Enemy<T>;
|
||||
/** 向其他怪提供过的光环 */
|
||||
providedHalo: number[] = [];
|
||||
|
||||
constructor(enemy: Enemy<T>, x?: number, y?: number, floorId?: FloorIds) {
|
||||
this.id = enemy.id;
|
||||
this.enemy = enemy;
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
this.floorId = floorId;
|
||||
}
|
||||
|
||||
reset() {
|
||||
delete this.noHaloInfo;
|
||||
delete this.realInfo;
|
||||
}
|
||||
|
||||
calAttribute() {}
|
||||
|
||||
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 filter = special.filter(v => {
|
||||
return haloSpecials.includes(v) && !this.providedHalo.includes(v);
|
||||
});
|
||||
if (filter.length === 0) return [];
|
||||
const collection = core.status.maps[this.floorId].enemy;
|
||||
if (!collection) {
|
||||
throw new Error(
|
||||
`Unexpected undefined of enemy collection in floor ${this.floorId}.`
|
||||
);
|
||||
}
|
||||
return filter;
|
||||
}
|
||||
|
||||
/**
|
||||
* 光环预提供,用于平衡所有怪的光环属性,避免出现不同情况下光环效果不一致的现象
|
||||
*/
|
||||
preProvideHalo() {}
|
||||
|
||||
/**
|
||||
* 向其他怪提供光环
|
||||
*/
|
||||
provideHalo() {
|
||||
const speical = this.getHaloSpecials();
|
||||
|
||||
const square7: HaloFn[] = [];
|
||||
|
||||
if (speical.includes(21)) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 接受其他怪的光环
|
||||
*/
|
||||
injectHalo(halo: HaloFn<T>) {}
|
||||
|
||||
calDamage() {}
|
||||
}
|
||||
|
||||
declare global {
|
||||
interface PluginDeclaration {
|
||||
damage: {
|
||||
Enemy: typeof DamageEnemy;
|
||||
Collection: typeof EnemyCollection;
|
||||
};
|
||||
}
|
||||
|
||||
interface Floor {
|
||||
enemy: EnemyCollection;
|
||||
}
|
||||
}
|
||||
|
||||
core.plugin.damage = {
|
||||
Enemy
|
||||
Enemy: DamageEnemy,
|
||||
Collection: EnemyCollection
|
||||
};
|
||||
+19
-19
@@ -1,22 +1,22 @@
|
||||
import './fiveLayer.js';
|
||||
import './heroFourFrames.js';
|
||||
import './hotReload.js';
|
||||
import './itemDetail.js';
|
||||
import './popup.js';
|
||||
import './replay.js';
|
||||
import './ui.js';
|
||||
import * as halo from './halo.js';
|
||||
import * as hero from './hero.js';
|
||||
import * as loopMap from './loopMap.js';
|
||||
import * as remainEnemy from './remainEnemy.js';
|
||||
import * as removeMap from './removeMap.js';
|
||||
import * as shop from './shop.js';
|
||||
import * as skill from './skills.js';
|
||||
import * as skillTree from './skillTree.js';
|
||||
import * as study from './study.js';
|
||||
import * as towerBoss from './towerBoss.js';
|
||||
import * as utils from './utils.js';
|
||||
import * as chase from './chase.js';
|
||||
import './fiveLayer';
|
||||
import './heroFourFrames';
|
||||
import './hotReload';
|
||||
import './itemDetail';
|
||||
import './popup';
|
||||
import './replay';
|
||||
import './ui';
|
||||
import * as halo from './halo';
|
||||
import * as hero from './hero';
|
||||
import * as loopMap from './loopMap';
|
||||
import * as remainEnemy from './remainEnemy';
|
||||
import * as removeMap from './removeMap';
|
||||
import * as shop from './shop';
|
||||
import * as skill from './skills';
|
||||
import * as skillTree from './skillTree';
|
||||
import * as study from './study';
|
||||
import * as towerBoss from './towerBoss';
|
||||
import * as utils from './utils';
|
||||
import * as chase from './chase';
|
||||
import * as damage from './damage';
|
||||
|
||||
export {
|
||||
|
||||
@@ -0,0 +1,100 @@
|
||||
type RangeScanFn<C extends Partial<Loc>> = (
|
||||
collection: Range<C>,
|
||||
data: any
|
||||
) => C[];
|
||||
type InRangeFn<C extends Partial<Loc>> = (
|
||||
collection: Range<C>,
|
||||
data: any,
|
||||
item: Partial<Loc>
|
||||
) => boolean;
|
||||
|
||||
interface RangeType<C extends Partial<Loc>> {
|
||||
scan: RangeScanFn<C>;
|
||||
inRange: InRangeFn<C>;
|
||||
}
|
||||
|
||||
export interface RangeCollection<I extends Partial<Loc>> {
|
||||
list: I[];
|
||||
range: Range<I>;
|
||||
}
|
||||
|
||||
export class Range<C extends Partial<Loc>> {
|
||||
collection: RangeCollection<C>;
|
||||
cache: Record<string, any> = {};
|
||||
|
||||
static rangeType: Record<string, RangeType<Partial<Loc>>> = {};
|
||||
|
||||
constructor(collection: RangeCollection<C>) {
|
||||
this.collection = collection;
|
||||
}
|
||||
|
||||
/**
|
||||
* 扫描 collection 中在范围内的物品
|
||||
* @param type 范围类型
|
||||
* @param data 范围数据
|
||||
* @returns 在范围内的物品列表
|
||||
*/
|
||||
scan(type: string, data: any): C[] {
|
||||
const t = Range.rangeType[type];
|
||||
if (!t) {
|
||||
throw new Error(`Unknown range type: ${type}.`);
|
||||
}
|
||||
return t.scan(this, data) as C[];
|
||||
}
|
||||
|
||||
inRange(type: string, data: any, item: Partial<Loc>) {
|
||||
const t = Range.rangeType[type];
|
||||
if (!t) {
|
||||
throw new Error(`Unknown range type: ${type}.`);
|
||||
}
|
||||
return t.inRange(this, data, item);
|
||||
}
|
||||
|
||||
clearCache() {
|
||||
this.cache = {};
|
||||
}
|
||||
|
||||
static registerRangeType(
|
||||
type: string,
|
||||
scan: RangeScanFn<Partial<Loc>>,
|
||||
inRange: InRangeFn<Partial<Loc>>
|
||||
) {
|
||||
Range.rangeType[type] = {
|
||||
scan,
|
||||
inRange
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
// ----- 默认的范围类型
|
||||
|
||||
// 方形区域
|
||||
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);
|
||||
|
||||
return (cache[index] = 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);
|
||||
return (
|
||||
core.has(item.x) &&
|
||||
core.has(item.y) &&
|
||||
Math.abs(item.x - x) <= r &&
|
||||
Math.abs(item.y - y) <= r
|
||||
);
|
||||
}
|
||||
);
|
||||
@@ -2,10 +2,10 @@
|
||||
|
||||
/**
|
||||
* 滑动数组
|
||||
* @param {any[]} arr
|
||||
* @param {number} delta
|
||||
* @param arr
|
||||
* @param delta
|
||||
*/
|
||||
export function slide(arr, delta) {
|
||||
export function slide<T>(arr: T[], delta: number): T[] {
|
||||
if (delta === 0) return arr;
|
||||
delta %= arr.length;
|
||||
if (delta > 0) {
|
||||
@@ -16,27 +16,29 @@ export function slide(arr, delta) {
|
||||
arr.push(...arr.splice(0, -delta));
|
||||
return arr;
|
||||
}
|
||||
return arr;
|
||||
}
|
||||
|
||||
export function backDir(dir) {
|
||||
export function backDir(dir: Dir): Dir {
|
||||
return {
|
||||
up: 'down',
|
||||
down: 'up',
|
||||
left: 'right',
|
||||
right: 'left'
|
||||
}[dir];
|
||||
}[dir] as Dir;
|
||||
}
|
||||
|
||||
export function has(v) {
|
||||
export function has<T>(v: T): v is NonNullable<T> {
|
||||
return v !== null && v !== void 0;
|
||||
}
|
||||
|
||||
export function maxGameScale(n = 0) {
|
||||
export function maxGameScale(n: number = 0) {
|
||||
const index = core.domStyle.availableScale.indexOf(core.domStyle.scale);
|
||||
core.control.setDisplayScale(
|
||||
core.domStyle.availableScale.length - 1 - index - n
|
||||
);
|
||||
if (!core.isPlaying() && core.flags.enableHDCanvas) {
|
||||
// @ts-ignore
|
||||
core.domStyle.ratio = Math.max(
|
||||
window.devicePixelRatio || 1,
|
||||
core.domStyle.scale
|
||||
@@ -45,6 +47,11 @@ export function maxGameScale(n = 0) {
|
||||
}
|
||||
}
|
||||
|
||||
export function ensureArray<T>(arr: T): T extends any[] ? T : T[] {
|
||||
// @ts-ignore
|
||||
return arr instanceof Array ? arr : [arr];
|
||||
}
|
||||
|
||||
core.plugin.utils = {
|
||||
slide,
|
||||
backDir,
|
||||
Reference in new issue
Block a user