fix: 迁移过程中产生的所有报错

This commit is contained in:
AncTe committed 2025-03-09 17:38:29 +08:00
1 parent 0679bbb1a5
commit 4fda246a9a
72 files changed
+225 -189

No files matched your search

@@ -0,0 +1,599 @@
import {
ERenderItemEvent,
RenderItem,
MotaOffscreenCanvas2D,
Transform,
transformCanvas
} from '@motajs/render-core';
import { logger } from '@motajs/common';
import EventEmitter from 'eventemitter3';
import { isNil } from 'lodash-es';
import {
BlockCacher,
CanvasCacheItem,
ICanvasCacheItem,
calNeedRenderOf,
ILayerGroupRenderExtends,
Layer,
LayerGroup,
LayerGroupFloorBinder,
tagMap
} from '@motajs/render';
import { IDamageEnemy, IEnemyCollection, MapDamage } from '@motajs/types';
import { UserEnemyInfo } from '@user/data-state';
const { ensureFloorDamage } = Mota.require('@user/data-state');
/**
* 根据伤害大小获取颜色
* @param damage 伤害大小
*/
export function getDamageColor(damage: number): string {
if (typeof damage !== 'number') return '#f00';
if (damage === 0) return '#2f2';
if (damage < 0) return '#7f7';
if (damage < core.status.hero.hp / 3) return '#fff';
if (damage < (core.status.hero.hp * 2) / 3) return '#ff4';
if (damage < core.status.hero.hp) return '#f93';
return '#f22';
}
interface EFloorDamageEvent {
update: [floor: FloorIds];
}
export class FloorDamageExtends
extends EventEmitter<EFloorDamageEvent>
implements ILayerGroupRenderExtends
{
id: string = 'floor-damage';
floorBinder!: LayerGroupFloorBinder;
group!: LayerGroup;
sprite!: Damage;
/**
* 立刻刷新伤害渲染
*/
update(floor: FloorIds) {
if (!this.sprite || !floor) return;
const map = core.status.maps[floor];
this.sprite.setMapSize(map.width, map.height);
ensureFloorDamage(floor);
const enemy = core.status.maps[floor].enemy;
this.sprite.updateCollection(enemy);
this.emit('update', floor);
}
/**
* 创建显伤层
*/
private create() {
if (this.sprite) return;
const sprite = new Damage();
sprite.setZIndex(80);
this.group.appendChild(sprite);
this.sprite = sprite;
}
private onUpdate = (floor: FloorIds) => {
if (!this.floorBinder.bindThisFloor) {
ensureFloorDamage(floor);
core.status.maps[floor].enemy.calRealAttribute();
}
this.update(floor);
};
// private onSetBlock = (x: number, y: number, floor: FloorIds) => {
// this.sprite.enemy?.once('extract', () => {
// if (floor !== this.sprite.enemy?.floorId) return;
// this.sprite.updateBlocks();
// });
// if (!this.floorBinder.bindThisFloor) {
// this.sprite.enemy?.extract();
// }
// };
/**
* 进行楼层更新监听
*/
private listen() {
this.floorBinder.on('update', this.onUpdate);
// this.floorBinder.on('setBlock', this.onSetBlock);
}
awake(group: LayerGroup): void {
const ex = group.getExtends('floor-binder');
if (ex instanceof LayerGroupFloorBinder) {
this.floorBinder = ex;
this.group = group;
this.create();
this.listen();
} else {
logger.warn(17);
group.removeExtends('floor-damage');
}
}
onDestroy(_group: LayerGroup): void {
this.floorBinder.off('update', this.onUpdate);
// this.floorBinder.off('setBlock', this.onSetBlock);
}
}
export interface DamageRenderable {
x: number;
y: number;
align: CanvasTextAlign;
baseline: CanvasTextBaseline;
text: string;
color: CanvasStyle;
font?: string;
stroke?: CanvasStyle;
strokeWidth?: number;
}
export interface EDamageEvent extends ERenderItemEvent {
setMapSize: [width: number, height: number];
beforeDamageRender: [need: Set<number>, transform: Transform];
updateBlocks: [blocks: Set<number>];
dirtyUpdate: [block: number];
}
export class Damage extends RenderItem<EDamageEvent> {
mapWidth: number = 0;
mapHeight: number = 0;
block: BlockCacher<ICanvasCacheItem>;
/** 键表示分块索引,值表示在这个分块上的渲染信息(当然实际渲染位置可以不在这个分块上) */
renderable: Map<number, Set<DamageRenderable>> = new Map();
/** 当前渲染怪物列表 */
enemy?: IEnemyCollection;
/** 每个分块中包含的怪物集合 */
blockData: Map<number, Map<number, IDamageEnemy>> = new Map();
/** 单元格大小 */
cellSize: number = 32;
/** 默认伤害字体 */
font: string = '300 9px Verdana';
/** 默认描边样式,当伤害文字不存在描边属性时会使用此属性 */
strokeStyle: CanvasStyle = '#000';
/** 默认描边宽度 */
strokeWidth: number = 2;
/** 要懒更新的所有分块 */
private dirtyBlocks: Set<number> = new Set();
constructor() {
super('absolute', false, true);
this.block = new BlockCacher(0, 0, core._WIDTH_, 1);
this.type = 'absolute';
this.size(core._PX_, core._PY_);
this.setHD(true);
this.setAntiAliasing(true);
}
protected render(
canvas: MotaOffscreenCanvas2D,
transform: Transform
): void {
this.renderDamage(canvas, transform);
}
private onExtract = () => {
if (this.enemy) this.updateCollection(this.enemy);
};
/**
* 设置地图大小,后面应紧跟更新怪物列表
*/
setMapSize(width: number, height: number) {
this.mapWidth = width;
this.mapHeight = height;
this.enemy = void 0;
this.blockData.clear();
this.renderable.clear();
this.block.size(width, height);
// 预留blockData
const w = this.block.blockData.width;
const h = this.block.blockData.height;
const num = w * h;
for (let i = 0; i < num; i++) {
this.blockData.set(i, new Map());
this.renderable.set(i, new Set());
this.dirtyBlocks.add(i);
}
this.emit('setMapSize', width, height);
}
/**
* 设置每个图块的大小
*/
setCellSize(size: number) {
this.cellSize = size;
this.update();
}
/**
* 更新怪物列表。更新后,{@link Damage.enemy} 会丢失原来的怪物列表引用,换为传入的列表引用
* @param enemy 怪物列表
*/
updateCollection(enemy: IEnemyCollection) {
if (this.enemy !== enemy) {
this.enemy?.off('calculated', this.onExtract);
enemy.on('calculated', this.onExtract);
}
this.enemy = enemy;
this.blockData.forEach(v => v.clear());
this.renderable.forEach(v => v.clear());
this.block.clearAllCache();
const w = this.block.blockData.width;
const h = this.block.blockData.height;
const num = w * h;
for (let i = 0; i < num; i++) {
this.dirtyBlocks.add(i);
}
enemy.list.forEach(v => {
if (isNil(v.x) || isNil(v.y)) return;
const index = this.block.getIndexByLoc(v.x, v.y);
this.blockData.get(index)?.set(v.y * this.mapWidth + v.x, v);
});
// this.updateBlocks();
this.update(this);
}
/**
* 更新指定矩形区域内的渲染信息
* @param x 左上角横坐标
* @param y 左上角纵坐标
* @param width 宽度
* @param height 高度
*/
updateRenderable(x: number, y: number, width: number, height: number) {
this.updateBlocks(this.block.updateElementArea(x, y, width, height));
}
/**
* 更新指定分块
* @param blocks 要更新的分块集合
* @param map 是否更新地图伤害
*/
updateBlocks(blocks?: Set<number>) {
if (blocks) {
blocks.forEach(v => this.dirtyBlocks.add(v));
this.emit('updateBlocks', blocks);
} else {
this.blockData.forEach((_v, i) => {
this.dirtyBlocks.add(i);
});
this.emit('updateBlocks', new Set(this.blockData.keys()));
}
this.update(this);
}
/**
* 更新指定位置的怪物信息
*/
updateEnemyOn(x: number, y: number) {
const enemy = this.enemy?.get(x, y);
const block = this.block.getIndexByLoc(x, y);
const data = this.blockData.get(block);
const index = x + y * this.mapWidth;
if (!data) return;
if (!enemy) {
data.delete(index);
} else {
data.set(index, enemy);
}
this.update(this);
// 渲染懒更新,优化性能表现
this.dirtyBlocks.add(block);
}
/**
* 更新单个分块
* @param block 更新的分块
* @param map 是否更新地图伤害
*/
private updateBlock(block: number, map: boolean = true) {
const data = this.blockData.get(block);
if (!data) return;
this.block.clearCache(block, 1);
const renderable = this.renderable.get(block)!;
renderable.clear();
data.forEach(v => this.extract(v, renderable));
if (map) this.extractMapDamage(block, renderable);
}
/**
* 将怪物解析为renderable的伤害
* @param enemy 怪物
* @param block 怪物所属分块
*/
private extract(enemy: IDamageEnemy, block: Set<DamageRenderable>) {
if (enemy.progress !== 4) return;
const x = enemy.x!;
const y = enemy.y!;
const { damage } = enemy.calDamage();
const cri = enemy.calCritical(1)[0]?.atkDelta ?? Infinity;
const real = enemy.getRealInfo() as UserEnemyInfo;
const dam1: DamageRenderable = {
align: 'left',
baseline: 'alphabetic',
text: isFinite(damage) ? core.formatBigNumber(damage, true) : '???',
color: getDamageColor(damage),
x: x * this.cellSize + 1,
y: y * this.cellSize + this.cellSize - 1
};
const dam2: DamageRenderable = {
align: 'left',
baseline: 'alphabetic',
text: isFinite(cri) ? core.formatBigNumber(cri, true) : '?',
color: '#fff',
x: x * this.cellSize + 1,
y: y * this.cellSize + this.cellSize - 11
};
block.add(dam1).add(dam2);
const hasHorn = real.special.has(33);
if (real.special.has(8) && real.togetherNum && !hasHorn) {
const dam3: DamageRenderable = {
align: 'right',
baseline: 'top',
text: real.togetherNum.toString(),
color: '#09FF5B',
x: x * this.cellSize + this.cellSize - 1,
y: y * this.cellSize + 2,
strokeWidth: 3
};
block.add(dam3);
}
if (real.special.has(30)) {
const dam4: DamageRenderable = {
align: 'left',
baseline: 'top',
text: '乾',
color: '#FDCD0B',
x: x * this.cellSize + 1,
y: y * this.cellSize + 2,
strokeWidth: 2,
font: '500 10px Verdana'
};
block.add(dam4);
}
if (enemy.col && hasHorn) {
const dam5: DamageRenderable = {
align: 'right',
baseline: 'top',
text: enemy.col.list.size.toString(),
color: '#fff866',
x: x * this.cellSize + this.cellSize - 1,
y: y * this.cellSize + 2,
strokeWidth: 3
};
block.add(dam5);
}
}
/**
* 解析指定分块的地图伤害
* @param block 分块索引
*/
private extractMapDamage(block: number, renderable: Set<DamageRenderable>) {
if (!this.enemy) return;
const damage = this.enemy.mapDamage;
const [sx, sy, ex, ey] = this.block.getRectOfIndex(block);
for (let x = sx; x < ex; x++) {
for (let y = sy; y < ey; y++) {
const loc = `${x},${y}`;
const dam = damage[loc];
if (!dam) continue;
this.pushMapDamage(x, y, renderable, dam);
}
}
}
/**
* 解析所有地图伤害
*/
private extractAllMapDamage() {
// todo: 测试性能,这样真的会更快吗?或许能更好的优化?或者是根本不需要这个函数?
if (!this.enemy) return;
for (const [loc, enemy] of Object.entries(this.enemy.mapDamage)) {
const [sx, sy] = loc.split(',');
const x = Number(sx);
const y = Number(sy);
const block = this.renderable.get(this.block.getIndexByLoc(x, y))!;
this.pushMapDamage(x, y, block, enemy);
}
}
private pushMapDamage(
x: number,
y: number,
block: Set<DamageRenderable>,
dam: MapDamage
) {
// todo: 这个应当可以自定义,通过地图伤害注册实现
let text = '';
let color = '#fa3';
let font = '300 9px Verdana';
if (dam.damage > 0) {
text = core.formatBigNumber(dam.damage, true);
} else if (dam.mockery) {
dam.mockery.sort((a, b) =>
a[0] === b[0] ? a[1] - b[1] : a[0] - b[0]
);
const [tx, ty] = dam.mockery[0];
const dir = x > tx ? '←' : x < tx ? '→' : y > ty ? '↑' : '↓';
text = '嘲' + dir;
color = '#fd4';
font = '500 11px Verdana';
} else if (dam.hunt) {
text = '猎';
color = '#fd4';
font = '500 11px Verdana';
} else {
return;
}
const mapDam: DamageRenderable = {
align: 'center',
baseline: 'middle',
text,
color,
font,
x: x * this.cellSize + this.cellSize / 2,
y: y * this.cellSize + this.cellSize / 2
};
block.add(mapDam);
}
/**
* 计算需要渲染哪些块
*/
calNeedRender(transform: Transform) {
if (this.parent instanceof LayerGroup) {
// 如果处于地图组中,每个地图的渲染区域应该是一样的,因此可以缓存优化
return this.parent.cacheNeedRender(transform, this.block);
} else if (this.parent instanceof Layer) {
// 如果是地图的子元素,直接调用Layer的计算函数
return this.parent.calNeedRender(transform);
} else {
return calNeedRenderOf(transform, this.cellSize, this.block);
}
}
/**
* 渲染伤害层
* @param transform 变换矩阵
*/
renderDamage(canvas: MotaOffscreenCanvas2D, transform: Transform) {
// console.time('damage');
const { ctx } = canvas;
transformCanvas(canvas, transform);
const render = this.calNeedRender(transform);
const block = this.block;
const cell = this.cellSize;
const size = cell * block.blockSize;
this.emit('beforeDamageRender', render, transform);
render.forEach(v => {
const [x, y] = block.getBlockXYByIndex(v);
const bx = x * block.blockSize;
const by = y * block.blockSize;
const px = bx * cell;
const py = by * cell;
// todo: 是否真的需要缓存
// 检查有没有缓存
const cache = block.cache.get(v);
if (cache && cache.symbol === cache.canvas.symbol) {
ctx.drawImage(cache.canvas.canvas, px, py, size, size);
return;
}
if (this.dirtyBlocks.has(v)) {
this.updateBlock(v, true);
}
this.emit('dirtyUpdate', v);
// 否则依次渲染并写入缓存
const temp = block.cache.get(v)?.canvas ?? this.requireCanvas();
temp.clear();
temp.setHD(true);
temp.setAntiAliasing(true);
temp.withGameScale(true);
temp.size(size, size);
const { ctx: ct } = temp;
ct.translate(-px, -py);
const render = this.renderable.get(v);
render?.forEach(v => {
if (!v) return;
ct.fillStyle = v.color;
ct.textAlign = v.align;
ct.textBaseline = v.baseline;
ct.font = v.font ?? this.font;
ct.strokeStyle = v.stroke ?? this.strokeStyle;
ct.lineWidth = v.strokeWidth ?? this.strokeWidth;
ct.strokeText(v.text, v.x, v.y);
ct.fillText(v.text, v.x, v.y);
});
ctx.drawImage(temp.canvas, px, py, size, size);
block.cache.set(v, new CanvasCacheItem(temp, temp.symbol));
});
ctx.restore();
// console.timeEnd('damage');
}
protected handleProps(
key: string,
_prevValue: any,
nextValue: any
): boolean {
switch (key) {
case 'mapWidth':
if (!this.assertType(nextValue, 'number', key)) return false;
this.setMapSize(nextValue, this.mapHeight);
return true;
case 'mapHeight':
if (!this.assertType(nextValue, 'number', key)) return false;
this.setMapSize(this.mapWidth, nextValue);
return true;
case 'cellSize':
if (!this.assertType(nextValue, 'number', key)) return false;
this.setCellSize(nextValue);
return true;
case 'enemy':
if (!this.assertType(nextValue, 'object', key)) return false;
this.updateCollection(nextValue);
return true;
case 'font':
if (!this.assertType(nextValue, 'string', key)) return false;
this.font = nextValue;
this.update();
return true;
case 'strokeStyle':
this.strokeStyle = nextValue;
this.update();
return true;
case 'strokeWidth':
if (!this.assertType(nextValue, 'number', key)) return false;
this.strokeWidth = nextValue;
this.update();
return true;
}
return false;
}
destroy(): void {
super.destroy();
this.block.destroy();
this.enemy?.off('extract', this.onExtract);
}
}
// 注册为内部元素
tagMap.register<EDamageEvent, Damage>('damage', (_0, _1, _props) => {
return new Damage();
});
// const adapter = new RenderAdapter<Damage>('damage');
@@ -3,7 +3,7 @@ import { defineComponent } from 'vue';
import { UIController } from '@motajs/system-ui';
import { mainSceneUI } from './ui/main';
import { MAIN_HEIGHT, MAIN_WIDTH } from './shared';
import { TextboxStore } from './components';
import { hook } from '@user/data-base';
export function create() {
const main = new MotaRenderer();
@@ -23,21 +23,17 @@ export function create() {
main.hide();
createApp(App).mount(main);
Mota.require('var', 'hook').on('reset', () => {
hook.on('reset', () => {
main.show();
});
Mota.require('var', 'hook').on('restart', () => {
hook.on('restart', () => {
main.hide();
});
console.log(main);
}
Mota.register('module', 'MainUI', {
TextboxStore
});
export * from './components';
export * from './ui';
export * from './use';
@@ -0,0 +1,267 @@
import { logger } from '@motajs/common';
import { mainSetting } from '@motajs/legacy-ui';
import {
LayerGroupFloorBinder,
ILayerGroupRenderExtends,
LayerGroup
} from '@motajs/render';
import { hook } from '@user/data-base';
import { ItemState } from '@user/data-state';
import { Damage, DamageRenderable, FloorDamageExtends } from './damage';
interface ItemDetailData {
x: number;
y: number;
diff: Record<string | symbol, number | undefined>;
}
interface ItemData {
id: AllIdsOf<'items'>;
x: number;
y: number;
}
hook.on('setBlock', (x, y, floorId, block) => {
FloorItemDetail.listened.forEach(v => {
v.setBlock(block, x, y);
});
});
export class FloorItemDetail implements ILayerGroupRenderExtends {
id: string = 'item-detail';
group!: LayerGroup;
floorBinder!: LayerGroupFloorBinder;
damage!: FloorDamageExtends;
sprite!: Damage;
/** 每个分块中包含的物品信息 */
blockData: Map<number, Map<number, ItemData>> = new Map();
/** 需要更新的分块 */
private dirtyBlock: Set<number> = new Set();
/** 道具详细信息 */
private detailData: Map<number, Map<number, ItemDetailData>> = new Map();
static detailColor: Record<string, CanvasStyle> = {
atk: '#FF7A7A',
atkper: '#FF7A7A',
def: '#00E6F1',
defper: '#00E6F1',
mdef: '#6EFF83',
mdefper: '#6EFF83',
hp: '#A4FF00',
hpmax: '#F9FF00',
hpmaxper: '#F9FF00',
mana: '#c66',
manaper: '#c66'
};
static listened: Set<FloorItemDetail> = new Set();
private onBeforeDamageRender = (block: number) => {
if (!mainSetting.getValue('screen.itemDetail')) return;
if (this.dirtyBlock.has(block)) {
this.sprite.block.clearCache(block, 1);
}
this.render(block);
};
private onUpdateMapSize = (width: number, height: number) => {
this.updateMapSize(width, height);
};
private onUpdate = () => {
this.updateItems();
};
private onUpdateBlocks = (blocks: Set<number>) => {
blocks.forEach(v => {
this.dirtyBlock.add(v);
});
};
private listen() {
this.sprite.on('dirtyUpdate', this.onBeforeDamageRender);
this.sprite.on('setMapSize', this.onUpdateMapSize);
this.sprite.on('updateBlocks', this.onUpdateBlocks);
this.damage.on('update', this.onUpdate);
}
/**
* 更新地图大小
*/
updateMapSize(width: number, height: number) {
this.blockData.clear();
// 预留blockData
this.sprite.block.size(width, height);
const data = this.sprite.block.blockData;
const num = data.width * data.height;
for (let i = 0; i <= num; i++) {
this.blockData.set(i, new Map());
this.detailData.set(i, new Map());
this.dirtyBlock.add(i);
}
}
/**
* 更新全地图的物品,并进行分块存储
*/
updateItems() {
const floor = this.floorBinder.getFloor();
if (!floor) return;
core.extractBlocks(floor);
core.status.maps[floor].blocks.forEach(v => {
if (v.event.cls !== 'items' || v.disable) return;
const id = v.event.id as AllIdsOf<'items'>;
const item = core.material.items[id];
if (item.cls === 'constants' || item.cls === 'tools') return;
const x = v.x;
const y = v.y;
const block = this.sprite.block.getIndexByLoc(x, y);
const index = x + y * this.sprite.mapWidth;
const blockData = this.blockData.get(block);
blockData?.set(index, { x, y, id });
});
}
/**
* 设置图块
* @param block 图块数字
* @param x 横坐标
* @param y 纵坐标
*/
setBlock(block: AllNumbers, x: number, y: number) {
const map = maps_90f36752_8815_4be8_b32b_d7fad1d0542e;
const index = this.sprite.block.getIndexByLoc(x, y);
const itemIndex = x + y * this.sprite.mapWidth;
const blockData = this.blockData.get(index);
this.dirtyBlock.add(index);
if (block === 0) {
blockData?.delete(itemIndex);
return;
}
const cls = map[block].cls;
if (cls !== 'items') {
blockData?.delete(itemIndex);
return;
}
const id = map[block].id;
blockData?.set(itemIndex, { x, y, id });
}
/**
* 计算指定分块中的物品信息
* @param block 要计算的分块
*/
calAllItems(block: Set<number>) {
if (!core.status.thisMap) return;
if (this.dirtyBlock.size === 0 || block.size === 0) return;
let diff: Record<string | symbol, number | undefined> = {};
const before = core.status.hero;
const hero = structuredClone(core.status.hero);
const handler: ProxyHandler<any> = {
set(target, key, v) {
diff[key] = v - (target[key] || 0);
if (!diff[key]) diff[key] = void 0;
return true;
}
};
core.status.hero = new Proxy(hero, handler);
core.setFlag('__statistics__', true);
block.forEach(v => {
if (!this.dirtyBlock.has(v)) return;
const data = this.blockData.get(v);
const detail = this.detailData.get(v);
detail?.clear();
if (!data) return;
data.forEach(v => {
const { id, x, y } = v;
const index = x + y * this.sprite.mapWidth;
diff = {};
const item = core.material.items[id];
if (item.cls === 'equips') {
// 装备也显示
const diff: Record<string, any> = {
...(item.equip.value ?? {})
};
const per = item.equip.percentage ?? {};
for (const name of Object.keys(per)) {
const n = name as SelectKey<HeroStatus, number>;
diff[name + 'per'] = per[n].toString() + '%';
}
detail?.set(index, { x, y, diff });
return;
}
ItemState.item(id)?.itemEffectFn?.();
detail?.set(index, { x, y, diff });
});
});
core.status.hero = before;
window.hero = before;
window.flags = before.flags;
}
/**
* 计算并渲染指定格子里面的物品
* @param block 需要渲染的格子
*/
render(block: number) {
if (this.dirtyBlock.has(block)) {
this.calAllItems(new Set([block]));
}
const data = this.detailData;
this.dirtyBlock.delete(block);
const info = data.get(block);
if (!info) return;
info.forEach(({ x, y, diff }) => {
let n = 0;
for (const [key, value] of Object.entries(diff)) {
if (!value) continue;
const color = FloorItemDetail.detailColor[key] ?? '#fff';
const text = core.formatBigNumber(value, 4);
const renderable: DamageRenderable = {
x: x * this.sprite.cellSize + 2,
y: y * this.sprite.cellSize + 31 - n * 10,
text,
color,
align: 'left',
baseline: 'alphabetic'
};
this.sprite.renderable.get(block)?.add(renderable);
n++;
}
});
}
awake(group: LayerGroup): void {
this.group = group;
const binder = group.getExtends('floor-binder');
const damage = group.getExtends('floor-damage');
if (
binder instanceof LayerGroupFloorBinder &&
damage instanceof FloorDamageExtends
) {
this.floorBinder = binder;
this.damage = damage;
this.sprite = damage.sprite;
this.listen();
FloorItemDetail.listened.add(this);
} else {
logger.warn(1001);
group.removeExtends('item-detail');
}
}
onDestroy(group: LayerGroup): void {
this.sprite.off('beforeDamageRender', this.onBeforeDamageRender);
this.sprite.off('setMapSize', this.onUpdateMapSize);
FloorItemDetail.listened.delete(this);
}
}
@@ -0,0 +1,106 @@
import {
Container,
LayerGroupFloorBinder,
FloorLayer,
LayerGroup,
FloorViewport,
MotaRenderer
} from '@motajs/render';
import { hook } from '@user/data-base';
import { MiscData } from '@user/data-state';
import { FloorDamageExtends } from './damage';
import { FloorItemDetail } from './itemDetail';
const loopMaps = MiscData.loopMaps;
let loopLayer: LayerGroup;
let show: boolean = false;
/** 循环式地图中,更新视角的委托ticker */
let delegation: number = -1;
hook.on('changingFloor', (floorId, heroLoc) => {
enableLoopMapElement(floorId);
});
function createLayer() {
const group = new LayerGroup();
['bg', 'bg2', 'event', 'fg', 'fg2'].forEach(v => {
group.addLayer(v as FloorLayer);
});
const damage = new FloorDamageExtends();
const detail = new FloorItemDetail();
group.id = 'layer-loop';
group.extends(damage);
group.extends(detail);
loopLayer = group;
group.setZIndex(20);
}
function enableLoopMapElement(floorId: FloorIds) {
if (!loopMaps.has(floorId)) {
disableLoopMapElement();
return;
}
if (!loopLayer) createLayer();
const render = MotaRenderer.get('render-main');
const draw = render?.getElementById('map-draw') as Container;
const group = render?.getElementById('layer-main') as LayerGroup;
if (!draw || !group) return;
const ex = loopLayer.getExtends('floor-binder') as LayerGroupFloorBinder;
const viewport = group.getExtends('viewport') as FloorViewport;
if (!ex || !viewport) return;
ex.bindFloor(floorId);
draw.appendChild(loopLayer);
show = true;
const floor = core.status.maps[floorId];
viewport.setAutoBound(false);
const transform = group.camera;
const width = floor.width;
const testPos = width * loopLayer.cellSize;
loopLayer.removeTicker(delegation);
delegation = loopLayer.delegateTicker(() => {
const [x1] = transform.transformed(0, 0);
const camera = loopLayer.camera;
if (x1 > 0) {
// 这个是计算循环地图应该显示在哪
const [, y2] = transform.transformed(x1 - testPos, 0);
camera.reset();
camera.translate(core._PX_ - testPos, y2);
loopLayer.pos(transform.x - core._PX_, 0);
loopLayer.show();
loopLayer.update(loopLayer);
} else {
const [x2, y2] = transform.transformed(testPos, 0);
if (x2 < core._PX_) {
// 这个不用做其他运算,可以直接显示
camera.reset();
camera.translate(0, y2);
loopLayer.pos(x2, 0);
loopLayer.show();
loopLayer.update(loopLayer);
} else {
loopLayer.hide();
}
}
});
}
function disableLoopMapElement() {
if (!show) return;
show = false;
loopLayer.remove();
const render = MotaRenderer.get('render-main');
const group = render?.getElementById('layer-main') as LayerGroup;
if (!group) return;
const viewport = group.getExtends('viewport') as FloorViewport;
if (!viewport) return;
viewport.setAutoBound(true);
loopLayer.removeTicker(delegation);
}
@@ -1,7 +1,6 @@
import { LayerShadowExtends } from '@/core/fx/shadow';
import { LayerShadowExtends } from '@motajs/legacy-ui';
import {
ILayerGroupRenderExtends,
FloorDamageExtends,
LayerGroupAnimate,
FloorViewport,
ILayerRenderExtends,
@@ -11,13 +10,14 @@ import {
LayerGroup,
Font
} from '@motajs/render';
import { WeatherController } from '@/module/weather';
import { FloorChange } from '@/plugin/fallback';
import { LayerGroupFilter } from '@/plugin/fx/gameCanvas';
import { LayerGroupHalo } from '@/plugin/fx/halo';
import { FloorItemDetail } from '@/plugin/fx/itemDetail';
import { PopText } from '@/plugin/fx/pop';
import { LayerGroupPortal } from '@/plugin/fx/portal';
import { WeatherController } from '../../weather';
import {
FloorChange,
LayerGroupFilter,
LayerGroupHalo,
LayerGroupPortal,
PopText
} from '@user/legacy-plugin-client';
import { defineComponent, onMounted, reactive, ref } from 'vue';
import { Textbox, Tip } from '../components';
import { GameUI, UIController } from '@motajs/system-ui';
@@ -35,6 +35,11 @@ import {
} from './statusBar';
import { onLoaded } from '../use';
import { ReplayingStatus } from './toolbar';
import { getHeroStatusOn, HeroSkill, NightSpecial } from '@user/data-state';
import { jumpIgnoreFloor } from '@user/legacy-plugin-data';
import { hook } from '@user/data-base';
import { FloorDamageExtends } from '../damage';
import { FloorItemDetail } from '../itemDetail';
const MainScene = defineComponent(() => {
const layerGroupExtends: ILayerGroupRenderExtends[] = [
@@ -112,8 +117,6 @@ const MainScene = defineComponent(() => {
night: 0
});
const { getHeroStatusOn } = Mota.requireAll('fn');
const updateStatus = () => {
if (!core.status || !core.status.hero || !core.status.floorId) return;
hideStatus.value = core.getFlag('hideStatusBar', false);
@@ -135,7 +138,6 @@ const MainScene = defineComponent(() => {
leftStatus.exAtk = getHeroStatusOn('mana');
leftStatus.magicDef = getHeroStatusOn('magicDef');
const { HeroSkill, NightSpecial } = Mota.require('module', 'Mechanism');
rightStatus.autoSkill = HeroSkill.getAutoSkill();
rightStatus.skillName = HeroSkill.getSkillName();
rightStatus.skillDesc = HeroSkill.getSkillDesc();
@@ -148,7 +150,7 @@ const MainScene = defineComponent(() => {
replayStatus.played = totalList.length - toReplay.length;
replayStatus.total = totalList.length;
if (HeroSkill.learnedSkill(HeroSkill.Jump)) {
if (Mota.Plugin.require('skill_g').jumpIgnoreFloor.has(floor)) {
if (jumpIgnoreFloor.has(floor)) {
rightStatus.jumpCount = -2;
} else {
rightStatus.jumpCount = 3 - (flags[`jump_${floor}`] ?? 0);
@@ -168,7 +170,7 @@ const MainScene = defineComponent(() => {
loaded.value = true;
});
Mota.require('var', 'hook').on('statusBarUpdate', updateStatus);
hook.on('statusBarUpdate', updateStatus);
return () => (
<container id="main-scene" width={MAIN_WIDTH} height={MAIN_HEIGHT}>
@@ -14,7 +14,7 @@ import { mainUi } from '@motajs/legacy-ui';
import { gameKey } from '@motajs/system-action';
import { generateKeyboardEvent } from '@motajs/system-action';
import { getVitualKeyOnce } from '@motajs/legacy-ui';
import { getAllSavesData, getSaveData } from '@/module/utils';
import { getAllSavesData, getSaveData } from '../../utils';
export interface SettingsProps extends Partial<ChoicesProps>, UIComponentProps {
loc: ElementLocator;
@@ -410,7 +410,9 @@ export const DownloadSaveSelect = defineComponent<SettingsProps>(props => {
{ text: '请等待处理完毕' }
);
core.download(
`${core.firstData.name}_${core.formatDate2(new Date())}.h5save`,
`${core.firstData.name}_${core.formatDate2(
new Date()
)}.h5save`,
data
);
}
@@ -426,7 +428,9 @@ export const DownloadSaveSelect = defineComponent<SettingsProps>(props => {
if (confirm) {
const data = await getSaveData(core.saves.saveIndex);
core.download(
`${core.firstData.name}_${core.formatDate2(new Date())}.h5save`,
`${core.firstData.name}_${core.formatDate2(
new Date()
)}.h5save`,
data
);
}
@@ -18,6 +18,7 @@ import {
ReplayingStatus,
ReplayingToolbar
} from './toolbar';
import { HeroSkill } from '@user/data-state';
export interface ILeftHeroStatus {
hp: number;
@@ -275,7 +276,6 @@ export const RightStatusBar = defineComponent<StatusBarProps<IRightHeroStatus>>(
};
const changeAutoSkill = () => {
const { HeroSkill } = Mota.require('module', 'Mechanism');
const auto = !s.autoSkill;
HeroSkill.setAutoSkill(auto);
core.status.route.push(`set:autoSkill:${auto}`);
@@ -1,3 +1,4 @@
import { loading } from '@user/data-base';
import { TimingFn, Transition } from 'mutate-animate';
import {
ComponentInternalInstance,
@@ -59,7 +60,6 @@ export function onOrientationChange(hook: OrientationHook) {
* @param hook 当游戏加载完成时执行的函数
*/
export function onLoaded(hook: () => void) {
const loading = Mota.require('var', 'loading');
if (!loading.loaded) {
loading.once('loaded', hook);
} else {