From 068dca14f9c1225f596fdfa70db1e754541704f4 Mon Sep 17 00:00:00 2001
From: unanmed <1319491857@qq.com>
Date: Thu, 4 May 2023 16:03:23 +0800
Subject: [PATCH] =?UTF-8?q?=E8=8C=83=E5=9B=B4=E7=B1=BB?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
README.md | 11 +-
src/plugin/game/damage.ts | 147 ++++++++++++++++++++++++-
src/plugin/game/index.js | 38 +++----
src/plugin/game/range.ts | 100 +++++++++++++++++
src/plugin/game/{utils.js => utils.ts} | 21 ++--
src/types/plugin.d.ts | 11 +-
6 files changed, 287 insertions(+), 41 deletions(-)
create mode 100644 src/plugin/game/range.ts
rename src/plugin/game/{utils.js => utils.ts} (69%)
diff --git a/README.md b/README.md
index fd463c5..a9db5e5 100644
--- a/README.md
+++ b/README.md
@@ -4,7 +4,7 @@
## 项目结构
-`public`: mota-js 样板所在目录,该塔对样板的目录进行了一定的魔改,其中插件全部移动到`project/plugin`文件夹中,并使用了`es模块化`
+`public`: mota-js 样板所在目录,该塔对样板的目录进行了一定的魔改,其中插件全部移动到`src/plugin/game`文件夹中,并使用了`es模块化`
`src`: 与 ui、特效等与游戏进程无关的插件所在目录。其中包含以下内容:
@@ -45,7 +45,7 @@
1. 运行`vue-tsc`检查类型是否正确
2. 运行`vite`的构建工具,打包除`public`外的内容
-3. 运行`script/build.ts`,首先去除未使用的文件(即全塔属性中未注册的文件),然后压缩字体,再用`rollup`及`babel`压缩插件与`main.js`
+3. 运行`script/build.ts`,首先去除未使用的文件(即全塔属性中未注册的文件),然后压缩字体,再用`rollup` `terser`及`babel`压缩插件与`main.js`
## 热重载说明
@@ -53,10 +53,9 @@
1. `vite`热重载
2. 楼层热重载
-3. 插件热重载
-4. 脚本编辑热重载
-5. 道具、怪物、图块属性热重载
-6. styles.css
+3. 脚本编辑热重载
+4. 道具、怪物、图块属性热重载
+5. styles.css
以下内容修改后会自动刷新页面
diff --git a/src/plugin/game/damage.ts b/src/plugin/game/damage.ts
index 70ad5d3..1b458a8 100644
--- a/src/plugin/game/damage.ts
+++ b/src/plugin/game/damage.ts
@@ -1,9 +1,148 @@
-///
+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 = (enemy: Enemy) => Enemy;
+
+export const haloSpecials: number[] = [21, 25, 26, 27];
+
+export class EnemyCollection implements RangeCollection {
+ floorId: FloorIds;
+ list: DamageEnemy[] = [];
+
+ range: Range = 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(
+ type: K,
+ data: HaloType[K],
+ halo: HaloFn | HaloFn[],
+ recursion: boolean = false
+ ) {
+ const arr = ensureArray(halo);
+ }
+
+ /**
+ * 预平衡光环
+ */
+ preBalanceHalo() {}
+}
+
+export class DamageEnemy {
+ id: T;
+ x?: number;
+ y?: number;
+ floorId?: FloorIds;
+ enemy: Enemy;
+
+ /** 计算特殊属性但不计算光环的属性 */
+ noHaloInfo?: Enemy;
+ /** 既计算特殊属性又计算光环的属性 */
+ realInfo?: Enemy;
+ /** 向其他怪提供过的光环 */
+ providedHalo: number[] = [];
+
+ constructor(enemy: Enemy, 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) {}
+
+ calDamage() {}
+}
+
+declare global {
+ interface PluginDeclaration {
+ damage: {
+ Enemy: typeof DamageEnemy;
+ Collection: typeof EnemyCollection;
+ };
+ }
+
+ interface Floor {
+ enemy: EnemyCollection;
+ }
+}
core.plugin.damage = {
- Enemy
+ Enemy: DamageEnemy,
+ Collection: EnemyCollection
};
diff --git a/src/plugin/game/index.js b/src/plugin/game/index.js
index 85507c6..b30632e 100644
--- a/src/plugin/game/index.js
+++ b/src/plugin/game/index.js
@@ -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 {
diff --git a/src/plugin/game/range.ts b/src/plugin/game/range.ts
new file mode 100644
index 0000000..8ef58fe
--- /dev/null
+++ b/src/plugin/game/range.ts
@@ -0,0 +1,100 @@
+type RangeScanFn> = (
+ collection: Range,
+ data: any
+) => C[];
+type InRangeFn> = (
+ collection: Range,
+ data: any,
+ item: Partial
+) => boolean;
+
+interface RangeType> {
+ scan: RangeScanFn;
+ inRange: InRangeFn;
+}
+
+export interface RangeCollection> {
+ list: I[];
+ range: Range;
+}
+
+export class Range> {
+ collection: RangeCollection;
+ cache: Record = {};
+
+ static rangeType: Record>> = {};
+
+ constructor(collection: RangeCollection) {
+ 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) {
+ 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>,
+ inRange: InRangeFn>
+ ) {
+ 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
+ );
+ }
+);
diff --git a/src/plugin/game/utils.js b/src/plugin/game/utils.ts
similarity index 69%
rename from src/plugin/game/utils.js
rename to src/plugin/game/utils.ts
index 5d813f7..b9e8b52 100644
--- a/src/plugin/game/utils.js
+++ b/src/plugin/game/utils.ts
@@ -2,10 +2,10 @@
/**
* 滑动数组
- * @param {any[]} arr
- * @param {number} delta
+ * @param arr
+ * @param delta
*/
-export function slide(arr, delta) {
+export function slide(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(v: T): v is NonNullable {
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(arr: T): T extends any[] ? T : T[] {
+ // @ts-ignore
+ return arr instanceof Array ? arr : [arr];
+}
+
core.plugin.utils = {
slide,
backDir,
diff --git a/src/types/plugin.d.ts b/src/types/plugin.d.ts
index e81ca88..37d3d11 100644
--- a/src/types/plugin.d.ts
+++ b/src/types/plugin.d.ts
@@ -30,7 +30,6 @@ interface PluginDeclaration
hero: GamePluginHeroRealStatus;
replay: PluginReplay;
chase: PluginChase;
- damage: PluginDamage;
skills: Record;
skillEffects: SkillEffects;
@@ -94,6 +93,12 @@ interface PluginDeclaration
* 重置变量的设置信息
*/
resetFlagSettings(): void;
+
+ /**
+ * 判定一个值是否不是undefined或null
+ * @param value 要判断的值
+ */
+ has(value: T): value is NonNullable;
}
interface GamePluginUtils {
@@ -457,10 +462,6 @@ interface Skill {
effect: string[];
}
-interface PluginDamage {
- Enemy: new () => DamageEnemy;
-}
-
interface DamageEnemy {}
type Forward = {