HumanBreak/public/project/plugins.js
2024-02-05 12:41:32 +08:00

802 lines
32 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

///<reference path="../../src/types/core.d.ts"/>
var plugins_bb40132b_638b_4a9f_b028_d3fe47acc8d1 = {
fiveLayer: function () {
// 注册插件
Mota.Plugin.register('fiveLayer_g', { init }, init);
// 创建新图层
function createCanvas(name, zIndex) {
if (!name) return;
var canvas = document.createElement('canvas');
canvas.id = name;
canvas.className = 'gameCanvas no-anti-aliasing';
// 编辑器模式下设置zIndex会导致加入的图层覆盖优先级过高
if (main.mode != 'editor') canvas.style.zIndex = zIndex || 0;
// 将图层插入进游戏内容
document.getElementById('gameDraw').appendChild(canvas);
var ctx = canvas.getContext('2d');
core.canvas[name] = ctx;
return canvas;
}
function init() {
var bg2Canvas = createCanvas('bg2', 20);
var fg2Canvas = createCanvas('fg2', 63);
// 大地图适配
core.bigmap.canvas = [
'bg2',
'fg2',
'bg',
'event',
'event2',
'fg',
'damage'
];
core.initStatus.bg2maps = {};
core.initStatus.fg2maps = {};
if (main.mode == 'editor') {
/*插入编辑器的图层 不做此步新增图层无法在编辑器显示*/
// 编辑器图层覆盖优先级 eui > efg > fg(前景层) > event2(48*32图块的事件层) > event(事件层) > bg(背景层)
// 背景层2(bg2) 插入事件层(event)之前(即bg与event之间)
document
.getElementById('mapEdit')
.insertBefore(bg2Canvas, document.getElementById('event'));
// 前景层2(fg2) 插入编辑器前景(efg)之前(即fg之后)
document
.getElementById('mapEdit')
.insertBefore(fg2Canvas, document.getElementById('ebm'));
// 原本有三个图层 从4开始添加
var num = 4;
// 新增图层存入editor.dom中
editor.dom.bg2c = core.canvas.bg2.canvas;
editor.dom.bg2Ctx = core.canvas.bg2;
editor.dom.fg2c = core.canvas.fg2.canvas;
editor.dom.fg2Ctx = core.canvas.fg2;
editor.dom.maps.push('bg2map', 'fg2map');
editor.dom.canvas.push('bg2', 'fg2');
// 创建编辑器上的按钮
var createCanvasBtn = name => {
// 电脑端创建按钮
var input = document.createElement('input');
// layerMod4/layerMod5
var id = 'layerMod' + num++;
// bg2map/fg2map
var value = name + 'map';
input.type = 'radio';
input.name = 'layerMod';
input.id = id;
input.value = value;
editor.dom[id] = input;
input.onchange = () => {
editor.uifunctions.setLayerMod(value);
};
return input;
};
var createCanvasBtn_mobile = name => {
// 手机端往选择列表中添加子选项
var input = document.createElement('option');
var id = 'layerMod' + num++;
var value = name + 'map';
input.name = 'layerMod';
input.value = value;
editor.dom[id] = input;
return input;
};
if (!editor.isMobile) {
var input = createCanvasBtn('bg2');
var input2 = createCanvasBtn('fg2');
// 获取事件层及其父节点
var child = document.getElementById('layerMod'),
parent = child.parentNode;
// 背景层2插入事件层前
parent.insertBefore(input, child);
// 不能直接更改背景层2的innerText 所以创建文本节点
var txt = document.createTextNode('背2');
// 插入事件层前(即新插入的背景层2前)
parent.insertBefore(txt, child);
// 向最后插入前景层2(即插入前景层后)
parent.appendChild(input2);
var txt2 = document.createTextNode('前2');
parent.appendChild(txt2);
} else {
var input = createCanvasBtn_mobile('bg2');
var input2 = createCanvasBtn_mobile('fg2');
// 手机端因为是选项 所以可以直接改innerText
input.innerText = '背景2';
input2.innerText = '前景2';
var parent = document.getElementById('layerMod');
parent.insertBefore(input, parent.children[1]);
parent.appendChild(input2);
}
}
maps.prototype._loadFloor_doNotCopy = function () {
return [
'firstArrive',
'eachArrive',
'blocks',
'parallelDo',
'map',
'bgmap',
'fgmap',
'bg2map',
'fg2map',
'events',
'changeFloor',
'afterBattle',
'afterGetItem',
'afterOpenDoor',
'cannotMove',
'enemy'
];
};
////// 绘制背景和前景层 //////
maps.prototype._drawBg_draw = function (
floorId,
toDrawCtx,
cacheCtx,
config
) {
config.ctx = cacheCtx;
core.maps._drawBg_drawBackground(floorId, config);
// ------ 调整这两行的顺序来控制是先绘制贴图还是先绘制背景图块;后绘制的覆盖先绘制的。
core.maps._drawFloorImages(
floorId,
config.ctx,
'bg',
null,
null,
config.onMap
);
core.maps._drawBgFgMap(floorId, 'bg', config);
if (config.onMap) {
core.drawImage(
toDrawCtx,
cacheCtx.canvas,
core.bigmap.v2 ? -32 : 0,
core.bigmap.v2 ? -32 : 0
);
core.clearMap('bg2');
core.clearMap(cacheCtx);
}
core.maps._drawBgFgMap(floorId, 'bg2', config);
if (config.onMap)
core.drawImage(
'bg2',
cacheCtx.canvas,
core.bigmap.v2 ? -32 : 0,
core.bigmap.v2 ? -32 : 0
);
config.ctx = toDrawCtx;
};
maps.prototype._drawFg_draw = function (
floorId,
toDrawCtx,
cacheCtx,
config
) {
config.ctx = cacheCtx;
// ------ 调整这两行的顺序来控制是先绘制贴图还是先绘制前景图块;后绘制的覆盖先绘制的。
core.maps._drawFloorImages(
floorId,
config.ctx,
'fg',
null,
null,
config.onMap
);
core.maps._drawBgFgMap(floorId, 'fg', config);
if (config.onMap) {
core.drawImage(
toDrawCtx,
cacheCtx.canvas,
core.bigmap.v2 ? -32 : 0,
core.bigmap.v2 ? -32 : 0
);
core.clearMap('fg2');
core.clearMap(cacheCtx);
}
core.maps._drawBgFgMap(floorId, 'fg2', config);
if (config.onMap)
core.drawImage(
'fg2',
cacheCtx.canvas,
core.bigmap.v2 ? -32 : 0,
core.bigmap.v2 ? -32 : 0
);
config.ctx = toDrawCtx;
};
////// 移动判定 //////
maps.prototype._generateMovableArray_arrays = function (floorId) {
return {
bgArray: this.getBgMapArray(floorId),
fgArray: this.getFgMapArray(floorId),
eventArray: this.getMapArray(floorId),
bg2Array: this._getBgFgMapArray('bg2', floorId),
fg2Array: this._getBgFgMapArray('fg2', floorId)
};
};
}
},
uiRewrite: function () {
Mota.Plugin.register('ui_g', { init }, init);
function init() {
const { mainUi, fixedUi } = Mota.requireAll('var');
ui.prototype.drawBook = function () {
if (!core.isReplaying()) return mainUi.open('book');
};
ui.prototype._drawToolbox = function () {
if (!core.isReplaying()) return mainUi.open('toolbox');
};
ui.prototype._drawEquipbox = function () {
if (!core.isReplaying()) return mainUi.open('equipbox');
};
ui.prototype.drawFly = function () {
if (!core.isReplaying()) return mainUi.open('fly');
};
control.prototype.updateStatusBar_update = function () {
core.control.updateNextFrame = false;
if (!core.isPlaying() || core.hasFlag('__statistics__')) return;
core.control.controldata.updateStatusBar();
if (!core.control.noAutoEvents) core.checkAutoEvents();
core.control._updateStatusBar_setToolboxIcon();
core.clearRouteFolding();
core.control.noAutoEvents = true;
// 更新vue状态栏
updateVueStatusBar();
Mota.require('var', 'hook').emit('statusBarUpdate');
};
// todo: 多个状态栏分离与控制
control.prototype.showStatusBar = function () {
if (main.mode == 'editor') return;
core.removeFlag('hideStatusBar');
if (!fixedUi.hasName('statusBar')) {
fixedUi.open('statusBar');
}
core.dom.tools.hard.style.display = 'block';
core.dom.toolBar.style.display = 'block';
};
control.prototype.hideStatusBar = function (showToolbox) {
if (main.mode == 'editor') return;
// 如果原本就是隐藏的,则先显示
if (!core.domStyle.showStatusBar) this.showStatusBar();
if (core.isReplaying()) showToolbox = true;
fixedUi.closeByName('statusBar');
var toolItems = core.dom.tools;
core.setFlag('hideStatusBar', true);
core.setFlag('showToolbox', showToolbox || null);
if (
(!core.domStyle.isVertical && !core.flags.extendToolbar) ||
!showToolbox
) {
for (var i = 0; i < toolItems.length; ++i)
toolItems[i].style.display = 'none';
}
if (!core.domStyle.isVertical && !core.flags.extendToolbar) {
core.dom.toolBar.style.display = 'none';
}
};
}
function updateVueStatusBar() {
Mota.r(() => {
const status = Mota.require('var', 'status');
status.value = !status.value;
});
}
},
special: function () {
// 这个插件负责定义怪物属性
const specials = Mota.require('var', 'enemySpecials');
// 怪物特殊属性包含四个信息
// code: 索引,必须与该属性在数组内的索引一致
// name: 特殊属性名称,可以是一个函数,接受 enemy 作为参数,返回字符串
// desc: 特殊属性说明,也可以是一个函数,接受 enemy 作为参数,返回字符串
// color: 特殊属性颜色,会在怪物手册中显示出来
specials.push(
{
code: 0,
name: '空',
desc: '空',
color: '#fff'
},
{
code: 1,
name: '致命一击',
desc: enemy =>
`怪物每5回合触发一次强力攻击造成${enemy.crit}%的伤害`,
color: '#fc3'
},
{
code: 2,
name: '恶毒',
desc: '怪物攻击无视勇士的防御',
color: '#bbb0ff'
},
{
code: 3,
name: '坚固',
desc: '怪物防御不小于勇士攻击-1',
color: '#c0b088'
},
{
code: 4,
name: '2连击',
desc: '怪物每回合攻击2次',
color: '#fe7'
},
{
code: 5,
name: '3连击',
desc: '怪物每回合攻击3次',
color: '#fe7'
},
{
code: 6,
name: enemy => `${enemy.n}连击`,
desc: enemy => `怪物每回合攻击${enemy.n}`,
color: '#fe7'
},
{
code: 7,
name: '饥渴',
desc: enemy =>
`战斗前,怪物降低勇士${enemy.hungry}%的攻击,并加在自己身上`,
color: '#b67'
},
{
code: 8,
name: '抱团',
desc: enemy =>
`怪物周围5×5范围内每有一个拥有该属性的怪物自身攻防就增加${enemy.together}%(线性叠加)`,
color: '#fa4'
},
{
code: 9,
name: '绝对防御',
desc: '怪物的奇特护甲可以让勇士的额外攻击失效,攻击变为基础攻击+额外攻击',
color: '#80eed6'
},
{
code: 10,
name: '勇气之刃',
desc: enemy => `怪物第一回合造成${enemy.courage}%的伤害`,
color: '#b0c0dd'
},
{
code: 11,
name: '勇气冲锋',
desc: enemy =>
`怪物首先攻击,造成${enemy.charge}%的伤害并眩晕勇士5回合`,
color: '#ff00d2'
},
{
code: 12,
name: '追猎',
desc: '当勇士移动到该怪物的水平或竖直方向上时,怪物向勇士移动一格',
color: '#9e8'
},
{
code: 13,
name: '魔攻',
desc: '怪物攻击无视勇士的防御',
color: '#bbb0ff'
},
{
code: 14,
name: '智慧之源',
desc: '困难难度下简单难度没有效果战斗后怪物会吸取勇士30%的智慧(勇士智慧向下取整至整十)加在本层的拥有该属性的怪物攻击上',
color: '#bbeef0'
},
{
code: 15,
name: '突刺',
desc: enemy =>
`勇士走到怪物怪物周围四格时,怪物对勇士造成${core.formatBigNumber(
Math.max((enemy.value || 0) - getHeroStatusOn('def'))
)}点伤害`,
color: '#c677dd'
},
{
code: 16,
name: '空',
desc: '空',
color: '#fff'
},
{
code: 17,
name: '先攻',
desc: '战斗时,怪物首先攻击',
color: '#b0b666'
},
{
code: 18,
name: '阻击',
desc: enemy =>
`经过怪物十字范围内时怪物后退一格,同时对勇士造成${enemy.value}点伤害`,
color: '#8888e6'
},
{
code: 19,
name: '电摇嘲讽',
desc:
'当勇士移动到怪物同行或同列时,勇士会直接冲向怪物,撞碎路上的所有地形和门,拾取路上的道具,与路上的怪物战斗' +
',最后与该怪物战斗',
color: '#ff6666'
},
{
code: 20,
name: '霜冻',
desc: enemy =>
`怪物寒冷的攻击使勇士动作变慢,勇士每回合对怪物造成的伤害减少${enemy.ice}%。装备杰克的衣服后可以免疫。`,
color: 'cyan'
},
{
code: 21,
name: '冰封光环',
desc: enemy =>
`寒气逼人使勇士对该怪物周围7*7范围内的怪物伤害减少${enemy.iceHalo}%(线性叠加)`,
color: 'cyan'
},
{
code: 22,
name: '永夜',
desc: enemy =>
`战斗后,减少勇士${enemy.night}点攻防,增加本层所有怪物${enemy.night}点攻防,仅在本层有效`,
color: '#d8a'
},
{
code: 23,
name: '极昼',
desc: enemy =>
`战斗后,减少本层所有怪物${enemy.day}点攻防,增加勇士${enemy.day}点攻防,仅在本层有效`,
color: '#ffd'
},
{
code: 24,
name: '射击',
desc: function () {
return '经过怪物同行或同列的可视范围内时受到一次普通攻击的伤害';
},
color: '#dda0dd'
},
{
code: 25,
name: '融化',
desc: enemy =>
`战斗后该怪物会融化在怪物位置产生一个3*3的范围光环光环内怪物的攻防增加${enemy.melt}%`,
color: '#e6e099'
},
{
code: 26,
name: '冰封之核',
desc: enemy =>
`怪物拥有逼人的寒气使周围5*5范围内的怪物防御增加${enemy.iceCore}%`,
color: '#70ffd1'
},
{
code: 27,
name: '火焰之核',
desc: enemy =>
`怪物拥有灼热的火焰使周围5*5范围内的怪物攻击增加${enemy.fireCore}%`,
color: '#ff6f0a'
},
{
code: 28,
name: '苍蓝刻',
desc: enemy =>
`怪物使用苍蓝之灵的力量,使自身受到的伤害减少${enemy.paleShield}%`,
color: '#ff6f0a'
}
);
},
battle: function () {
// 这个插件负责战斗相关内容
// --------------- 战斗伤害
const Damage = Mota.require('module', 'Damage');
// 这个数组常量控制着在战斗时哪些属性计算真实属性也就是经过buff加成的属性
// 如果有属性不会经过buff加成等请将其去除可以提高性能表现
Damage.realStatus = ['atk', 'def', 'mdef', 'hpmax'];
// 复写系统的伤害计算函数即可,全量复写
// 函数接受两个参数,分别是怪物信息和勇士信息,返回一个数字作为伤害
// 返回null表示不能战斗返回Infinity也可以
Mota.rewrite(Damage, 'calDamageWith', 'full', (info, hero) => {
// 获取勇士属性这几个属性直接从core.status.hero获取
const { hp, mana } = core.status.hero;
// 获取勇士属性,这几个属性从勇士真实属性获取
// 分开获取是因为获取勇士真实属性会对性能造成一定影响
let { atk, def, mdef, hpmax } = hero;
// 获取怪物信息,是在某点的信息
let { hp: monHp, atk: monAtk, def: monDef, special, enemy } = info;
/** 总伤害 */
let damage = 0;
/** 勇士单回合伤害 */
let heroPerDamage;
if (special.includes(3)) {
// 由于坚固的特性,只能放到这来计算了
if (atk > enemy.def) heroPerDamage = 1;
else return null;
} else {
heroPerDamage = atk - monDef;
if (heroPerDamage <= 0) return null;
}
/** 怪物单回合伤害 */
let enemyPerDamage;
// 魔攻
if (special.includes(2) || special.includes(13)) {
enemyPerDamage = monAtk;
} else {
enemyPerDamage = monAtk - def;
if (enemyPerDamage < 0) enemyPerDamage = 0;
}
// 先攻
if (special.includes(17)) {
damage += enemyPerDamage;
}
// 连击
if (special.includes(4)) enemyPerDamage *= 2;
if (special.includes(5)) enemyPerDamage *= 3;
if (special.includes(6)) enemyPerDamage *= enemy.n;
/** 战斗回合 */
let turn = Math.ceil(monHp / heroPerDamage);
damage += (turn - 1) * enemyPerDamage;
damage -= mdef;
if (!core.flags.enableNegativeDamage) damage = Math.max(0, damage);
return damage;
});
// --------------- 秒杀伤害计算
// 用于计算一些特殊属性怪物在一回合内秒杀所需的攻击,依此计算临界的上界
// 函数没有参数返回一个数字表示临界上界Infinity表示没有上界不计算临界
// 不能返回数字型外的量
Mota.rewrite(
Mota.require('class', 'DamageEnemy').prototype,
'getSeckillAtk',
'full',
function () {
// 获取怪物的属性
const info = this.getRealInfo();
// 对于一般的怪物,应该是怪物防御加上怪物血量
const add = info.def + info.hp;
// 坚固,不可能通过攻击秒杀
if (info.special.includes(3)) {
return Infinity;
}
return add;
}
);
// --------------- 地图伤害
// 全量复写地图伤害的计算函数注意此处不能使用箭头函数因为这是在原型上的函数其this指向实例也即怪物(DamageEnemy实例)
// 函数接收两个参数damage和hero前者表示要将结果存入的对象后者是勇士真实属性
// 直接将damage返回即可返回其他值有可能会引起出错
// 计算出伤害后直接调用this.setMapDamage即可将伤害传到对象中
Mota.rewrite(
Mota.require('class', 'DamageEnemy').prototype,
'calMapDamage',
'full',
function (damage = {}, hero = getHeroStatusOn(Damage.realStatus)) {
// 功能函数,计算曼哈顿距离,和判断一个值是否存在
const { manhattan, has } = Mota.Plugin.require('utils_g');
// 判断这个怪物是不是在地图上
if (!has(this.x) || !has(this.y) || !has(this.floorId))
return damage;
const enemy = this.enemy;
const floor = core.status.maps[this.floorId];
const w = floor.width;
const h = floor.height;
// 突刺
if (this.info.special.includes(15)) {
const range = enemy.range ?? 1;
const startX = Math.max(0, this.x - range);
const startY = Math.max(0, this.y - range);
const endX = Math.min(floor.width - 1, this.x + range);
const endY = Math.min(floor.height - 1, this.y + range);
const dam = Math.max((enemy.value ?? 0) - hero.def, 0);
for (let x = startX; x <= endX; x++) {
for (let y = startY; y <= endY; y++) {
if (
!enemy.zoneSquare &&
manhattan(x, y, this.x, this.y) > range
) {
continue;
}
const loc = `${x},${y}`;
this.setMapDamage(damage, loc, dam, '突刺');
}
}
}
// 射击
if (this.info.special.includes(24)) {
const dirs = ['left', 'down', 'up', 'right'];
const dam = Math.max((enemy.atk ?? 0) - hero.def, 0);
const objs = core.getMapBlocksObj(this.floorId);
for (const dir of dirs) {
let x = this.x;
let y = this.y;
const { x: dx, y: dy } = core.utils.scan[dir];
while (x >= 0 && y >= 0 && x < w && y < h) {
x += dx;
y += dy;
const loc = `${x},${y}`;
const block = objs[loc];
if (
block &&
block.event.noPass &&
block.event.cls !== 'enemys' &&
block.event.cls !== 'enemy48' &&
block.id !== 141 &&
block.id !== 151
) {
break;
}
this.setMapDamage(damage, loc, dam, '射击');
}
}
}
return damage;
}
);
// --------------- 光环处理
// 光环分为两类,一类是会增强光环或者给怪物加光环的光环,另一类就是普通光环,这两种光环处理方式不同
// 对于前者,光环将会优先递归计算,同时每个光环将会确保只计算一次,直到没有光环需要计算
// 对于后者,不进行递归计算,只进行单次遍历计算。
// 光环使用 provideHalo 和 injectHalo 作为api表示提供光环和接受光环
// 光环属性列表是一个集合Set你可以在这里配置会被视为光环的属性
const haloSpecials = Mota.require('module', 'Damage').haloSpecials;
haloSpecials.add(8).add(11);
// ----- 计算第二类光环,即普通光环,这类光环更常见,因此放到前面了
Mota.rewrite(
Mota.require('class', 'DamageEnemy').prototype,
'provideHalo',
'full',
function () {
// 这部分用于判断当前是否应该计算光环,即计算光环的函数是否在不应该被调用的时刻调用了
// 一般不需要改动
if (this.progress !== 2) return;
this.progress = 3;
if (!this.floorId) return;
if (!has(this.x) || !has(this.y)) return;
const col = this.col ?? core.status.maps[this.floorId].enemy;
if (!col) return;
// 获取所有还没有计算的光环注意这里不能直接获取haloSpecial
const special = this.getHaloSpecials();
const square7 = [];
const square5 = [];
// e 是被加成怪的属性enemy 是施加光环的怪
for (const halo of special) {
switch (halo) {
case 8:
square5.push((e, enemy) => {
if (
e.special.includes(8) &&
(e.x !== this.x || this.y !== e.y)
) {
e.atkBuff += enemy.together ?? 0;
e.defBuff += enemy.together ?? 0;
}
});
this.providedHalo.add(8);
break;
case 21:
square7.push(e => {
// e.damageDecline += this.enemy.iceHalo ?? 0;
});
col.haloList.push({
type: 'square',
data: { x: this.x, y: this.y, d: 7 },
special: 21,
from: this
});
this.providedHalo.add(21);
break;
case 26:
square5.push(e => {
e.defBuff += this.enemy.iceCore ?? 0;
});
col.haloList.push({
type: 'square',
data: { x: this.x, y: this.y, d: 5 },
special: 26,
from: this
});
this.providedHalo.add(26);
break;
case 27:
square5.push(e => {
e.atkBuff += this.enemy.fireCore ?? 0;
});
col.haloList.push({
type: 'square',
data: { x: this.x, y: this.y, d: 5 },
special: 27,
from: this
});
this.providedHalo.add(27);
break;
}
}
col.applyHalo(
'square',
{ x: this.x, y: this.y, d: 7 },
square7
);
col.applyHalo(
'square',
{ x: this.x, y: this.y, d: 5 },
square5
);
}
);
// ----- 计算第一类光环
Mota.rewrite(
Mota.require('class', 'DamageEnemy').prototype,
'preProvideHalo',
'full',
function () {
if (this.progress !== 0) return;
this.progress = 1;
const special = this.getHaloSpecials();
for (const halo of special) {
switch (halo) {
default:
break;
}
}
}
);
// ----- 接受光环处理
Mota.rewrite(
Mota.require('class', 'DamageEnemy').prototype,
'injectHalo',
'full',
function (halo, enemy) {
// 这里的 halo 是光环函数enemy 是施加光环的怪物this.info 是当前怪物信息
halo(this.info, enemy);
}
);
}
};