mirror of
https://github.com/unanmed/HumanBreak.git
synced 2025-04-19 17:16:08 +08:00
feat: 战斗
This commit is contained in:
parent
c8e45f2a22
commit
6ce86501f1
@ -2933,6 +2933,11 @@ control.prototype.getBuff = function (name) {
|
||||
return core.getFlag('__' + name + '_buff__', 1);
|
||||
};
|
||||
|
||||
////// 获得或移除毒衰咒效果 //////
|
||||
control.prototype.triggerDebuff = function (action, type) {
|
||||
return this.controldata.triggerDebuff(action, type);
|
||||
};
|
||||
|
||||
////// 设置勇士的位置 //////
|
||||
control.prototype.setHeroLoc = function (name, value, noGather) {
|
||||
if (!core.status.hero) return;
|
||||
|
@ -16,7 +16,7 @@ var enemys_fcae963b_31c9_42b4_b48c_bb48d09f3f80 =
|
||||
"bluePriest": {"name":"初级法师","hp":100,"atk":120,"def":0,"money":3,"exp":0,"point":1,"special":[9]},
|
||||
"redPriest": {"name":"高级法师","hp":0,"atk":0,"def":0,"money":0,"exp":0,"point":0,"special":[]},
|
||||
"brownWizard": {"name":"初级巫师","hp":100,"atk":120,"def":0,"money":16,"exp":0,"point":0,"special":[15],"value":100,"range":2},
|
||||
"redWizard": {"name":"高级巫师","hp":1000,"atk":1200,"def":0,"money":160,"exp":0,"point":0,"special":[15,28],"value":200,"zoneSquare":true,"specialHalo":[6,16],"n":9,"haloRange":2,"haloSquare":true},
|
||||
"redWizard": {"name":"高级巫师","hp":1000,"atk":1200,"def":0,"money":160,"exp":0,"point":0,"special":[15,28],"value":200,"zoneSquare":true,"specialHalo":[6,16],"n":9,"haloRange":2,"haloSquare":true,"zone":200},
|
||||
"swordsman": {"name":"双手剑士","hp":100,"atk":120,"def":0,"money":6,"exp":0,"point":0,"special":[4]},
|
||||
"soldier": {"name":"冥战士","hp":0,"atk":0,"def":0,"money":0,"exp":0,"point":0,"special":[]},
|
||||
"yellowKnight": {"name":"金骑士","hp":0,"atk":0,"def":0,"money":0,"exp":0,"point":0,"special":[]},
|
||||
|
@ -365,6 +365,63 @@ var functions_d6ad677b_427a_4623_b50f_a445a3b0ef8a = {
|
||||
if (callback) callback();
|
||||
});
|
||||
},
|
||||
triggerDebuff: function (action, type) {
|
||||
// 毒衰咒效果的获得与解除
|
||||
// action:获得还是解除;'get'表示获得,'remove'表示解除
|
||||
// type:一个数组表示获得了哪些毒衰咒效果;poison, weak,curse
|
||||
if (!(type instanceof Array)) type = [type];
|
||||
|
||||
if (action == 'get') {
|
||||
if (core.inArray(type, 'poison') && !core.hasFlag('poison')) {
|
||||
// 获得毒效果
|
||||
core.setFlag('poison', true);
|
||||
}
|
||||
if (core.inArray(type, 'weak') && !core.hasFlag('weak')) {
|
||||
// 获得衰效果
|
||||
core.setFlag('weak', true);
|
||||
if (core.values.weakValue >= 1) {
|
||||
// >=1,直接扣数值
|
||||
core.addStatus('atk', -core.values.weakValue);
|
||||
core.addStatus('def', -core.values.weakValue);
|
||||
} else {
|
||||
// <1,扣比例
|
||||
core.addBuff('atk', -core.values.weakValue);
|
||||
core.addBuff('def', -core.values.weakValue);
|
||||
}
|
||||
}
|
||||
if (core.inArray(type, 'curse') && !core.hasFlag('curse')) {
|
||||
// 获得咒效果
|
||||
core.setFlag('curse', true);
|
||||
}
|
||||
} else if (action == 'remove') {
|
||||
var success = false;
|
||||
if (core.inArray(type, 'poison') && core.hasFlag('poison')) {
|
||||
success = true;
|
||||
// 移除毒效果
|
||||
core.setFlag('poison', false);
|
||||
}
|
||||
if (core.inArray(type, 'weak') && core.hasFlag('weak')) {
|
||||
success = true;
|
||||
// 移除衰效果
|
||||
core.setFlag('weak', false);
|
||||
if (core.values.weakValue >= 1) {
|
||||
// >=1,直接扣数值
|
||||
core.addStatus('atk', core.values.weakValue);
|
||||
core.addStatus('def', core.values.weakValue);
|
||||
} else {
|
||||
// <1,扣比例
|
||||
core.addBuff('atk', core.values.weakValue);
|
||||
core.addBuff('def', core.values.weakValue);
|
||||
}
|
||||
}
|
||||
if (core.inArray(type, 'curse') && core.hasFlag('curse')) {
|
||||
success = true;
|
||||
// 移除咒效果
|
||||
core.setFlag('curse', false);
|
||||
}
|
||||
if (success) core.playSound('回血');
|
||||
}
|
||||
},
|
||||
updateStatusBar: function () {
|
||||
// 更新状态栏
|
||||
|
||||
|
@ -361,7 +361,7 @@ var plugins_bb40132b_638b_4a9f_b028_d3fe47acc8d1 = {
|
||||
name: '破甲',
|
||||
desc: enemy =>
|
||||
`战斗前,怪物附加角色防御的${Math.floor(
|
||||
100 * (enemy.breakArmor || core.values.breakArmor)
|
||||
100 * (enemy.breakArmor ?? core.values.breakArmor)
|
||||
)}%作为伤害"`,
|
||||
color: '#b67'
|
||||
},
|
||||
@ -370,7 +370,7 @@ var plugins_bb40132b_638b_4a9f_b028_d3fe47acc8d1 = {
|
||||
name: '反击',
|
||||
desc: enemy =>
|
||||
`战斗时,怪物每回合附加角色攻击的${Math.floor(
|
||||
100 * (enemy.counterAttack || core.values.counterAttack)
|
||||
100 * (enemy.counterAttack ?? core.values.counterAttack)
|
||||
)}%作为伤害,无视角色防御`,
|
||||
color: '#fa4'
|
||||
},
|
||||
@ -379,7 +379,7 @@ var plugins_bb40132b_638b_4a9f_b028_d3fe47acc8d1 = {
|
||||
name: '净化',
|
||||
desc: enemy =>
|
||||
`战斗前,怪物附加角色护盾的${
|
||||
enemy.purify || core.values.purify
|
||||
enemy.purify ?? core.values.purify
|
||||
}倍作为伤害`,
|
||||
color: '#80eed6'
|
||||
},
|
||||
@ -578,6 +578,166 @@ var plugins_bb40132b_638b_4a9f_b028_d3fe47acc8d1 = {
|
||||
battle: function () {
|
||||
// 这个插件负责战斗相关内容
|
||||
|
||||
// --------------- 战后脚本
|
||||
// enemy: DamageEnemy实例,也就是怪物本身
|
||||
// x, y: 怪物坐标
|
||||
Mota.rewrite(core.events, 'afterBattle', 'full', (enemy, x, y) => {
|
||||
const { has } = Mota.Plugin.require('utils_g');
|
||||
|
||||
const floorId = core.status.floorId;
|
||||
const special = enemy.info.special;
|
||||
|
||||
// 播放战斗动画
|
||||
let animate = 'hand';
|
||||
// 检查当前装备是否存在攻击动画
|
||||
const equipId = core.getEquip(0);
|
||||
if (equipId && (core.material.items[equipId].equip || {}).animate)
|
||||
animate = core.material.items[equipId].equip.animate;
|
||||
|
||||
// 检查该动画是否存在SE,如果不存在则使用默认音效
|
||||
if (!core.material.animates[animate]?.se)
|
||||
core.playSound('attack.mp3');
|
||||
|
||||
// 战斗伤害
|
||||
const info = enemy.calDamage(core.status.hero);
|
||||
const damage = info.damage;
|
||||
// 判定是否致死
|
||||
if (damage >= core.status.hero.hp) {
|
||||
core.status.hero.hp = 0;
|
||||
core.updateStatusBar(false, true);
|
||||
core.events.lose('战斗失败');
|
||||
return;
|
||||
}
|
||||
|
||||
// 扣减体力值并记录统计数据
|
||||
core.status.hero.hp -= damage;
|
||||
core.status.hero.statistics.battleDamage += damage;
|
||||
core.status.hero.statistics.battle++;
|
||||
|
||||
// 获得金币
|
||||
let money = enemy.enemy.money;
|
||||
let exp = enemy.enemy.exp;
|
||||
if (enemy.info.guard) {
|
||||
enemy.info.guard.forEach(v => {
|
||||
money += v.enemy.money;
|
||||
exp += v.enemy.exp;
|
||||
});
|
||||
}
|
||||
core.status.hero.money += money;
|
||||
core.status.hero.statistics.money += money;
|
||||
|
||||
// 获得经验
|
||||
core.status.hero.exp += exp;
|
||||
core.status.hero.statistics.exp += exp;
|
||||
|
||||
const hint =
|
||||
'打败 ' +
|
||||
enemy.enemy.name +
|
||||
',金币+' +
|
||||
money +
|
||||
',经验+' +
|
||||
exp;
|
||||
core.drawTip(hint, enemy.id);
|
||||
|
||||
// 中毒
|
||||
if (special.includes(12)) {
|
||||
core.triggerDebuff('get', 'poison');
|
||||
}
|
||||
// 衰弱
|
||||
if (special.includes(13)) {
|
||||
core.triggerDebuff('get', 'weak');
|
||||
}
|
||||
// 诅咒
|
||||
if (special.includes(14)) {
|
||||
core.triggerDebuff('get', 'curse');
|
||||
}
|
||||
// 仇恨怪物将仇恨值减半
|
||||
if (special.includes(17)) {
|
||||
core.setFlag(
|
||||
'hatred',
|
||||
Math.floor(core.getFlag('hatred', 0) / 2)
|
||||
);
|
||||
}
|
||||
// 自爆
|
||||
if (special.includes(19)) {
|
||||
core.status.hero.statistics.battleDamage +=
|
||||
core.status.hero.hp - 1;
|
||||
core.status.hero.hp = 1;
|
||||
}
|
||||
// 退化
|
||||
if (special.includes(21)) {
|
||||
core.status.hero.atk -= enemy.atkValue || 0;
|
||||
core.status.hero.def -= enemy.defValue || 0;
|
||||
if (core.status.hero.atk < 0) core.status.hero.atk = 0;
|
||||
if (core.status.hero.def < 0) core.status.hero.def = 0;
|
||||
}
|
||||
// 增加仇恨值
|
||||
core.setFlag(
|
||||
'hatred',
|
||||
core.getFlag('hatred', 0) + core.values.hatred
|
||||
);
|
||||
|
||||
// 事件的处理
|
||||
const todo = [];
|
||||
|
||||
// 战后事件
|
||||
if (has(core.status.floorId)) {
|
||||
const loc = `${x},${y}`;
|
||||
todo.push(
|
||||
...(core.floors[core.status.floorId].afterBattle[loc] ?? [])
|
||||
);
|
||||
}
|
||||
todo.push(...(enemy.enemy.afterBattle ?? []));
|
||||
|
||||
// 如果事件不为空,将其插入
|
||||
if (todo.length > 0) core.insertAction(todo, x, y);
|
||||
|
||||
if (has(x) && has(y)) {
|
||||
core.drawAnimate(animate, x, y);
|
||||
if (special.includes(23)) core.hideBlock(x, y);
|
||||
else core.removeBlock(x, y);
|
||||
} else core.drawHeroAnimate(animate);
|
||||
|
||||
// 如果已有事件正在处理中
|
||||
if (core.status.event.id == null) core.continueAutomaticRoute();
|
||||
else core.clearContinueAutomaticRoute();
|
||||
|
||||
// 打怪特效
|
||||
Mota.r(() => {
|
||||
const setting = Mota.require('var', 'mainSetting');
|
||||
const { applyFragWith } = Mota.Plugin.require('frag_r');
|
||||
if (setting.getValue('fx.frag') && has(x) && has(y)) {
|
||||
const frame = core.status.globalAnimateStatus % 2;
|
||||
const canvas = document.createElement('canvas');
|
||||
canvas.width = 32;
|
||||
canvas.height = 32;
|
||||
core.drawIcon(canvas, enemy.id, 0, 0, 32, 32, frame);
|
||||
const manager = applyFragWith(canvas);
|
||||
const frag = manager.canvas;
|
||||
frag.style.imageRendering = 'pixelated';
|
||||
frag.style.width = `${frag.width * core.domStyle.scale}px`;
|
||||
frag.style.height = `${
|
||||
frag.height * core.domStyle.scale
|
||||
}px`;
|
||||
const left =
|
||||
(x * 32 + 16 - frag.width / 2 - core.bigmap.offsetX) *
|
||||
core.domStyle.scale;
|
||||
const top =
|
||||
(y * 32 + 16 - frag.height / 2 - core.bigmap.offsetY) *
|
||||
core.domStyle.scale;
|
||||
frag.style.left = `${left}px`;
|
||||
frag.style.top = `${top}px`;
|
||||
frag.style.zIndex = '45';
|
||||
frag.style.position = 'absolute';
|
||||
frag.style.filter = 'sepia(20%)brightness(120%)';
|
||||
core.dom.gameDraw.appendChild(frag);
|
||||
manager.onEnd.then(() => {
|
||||
frag.remove();
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// --------------- 战斗伤害
|
||||
|
||||
const Damage = Mota.require('module', 'Damage');
|
||||
@ -590,7 +750,7 @@ var plugins_bb40132b_638b_4a9f_b028_d3fe47acc8d1 = {
|
||||
// 返回null表示不能战斗,返回Infinity也可以
|
||||
Mota.rewrite(Damage, 'calDamageWith', 'full', (info, hero) => {
|
||||
// 获取勇士属性,这几个属性直接从core.status.hero获取
|
||||
const { hp, mana } = core.status.hero;
|
||||
const { hp, mana, manamax } = core.status.hero;
|
||||
// 获取勇士属性,这几个属性从勇士真实属性获取
|
||||
// 分开获取是因为获取勇士真实属性会对性能造成一定影响
|
||||
let { atk, def, mdef, hpmax } = hero;
|
||||
@ -601,21 +761,40 @@ var plugins_bb40132b_638b_4a9f_b028_d3fe47acc8d1 = {
|
||||
let damage = 0;
|
||||
/** 勇士单回合伤害 */
|
||||
let heroPerDamage;
|
||||
/** 战斗回合 */
|
||||
let turn = 0;
|
||||
|
||||
// 无敌
|
||||
if (special.includes(20) && !core.hasItem('cross')) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (special.includes(3)) {
|
||||
// 由于坚固的特性,只能放到这来计算了
|
||||
if (atk > enemy.def) heroPerDamage = 1;
|
||||
else return null;
|
||||
} else {
|
||||
// 模仿
|
||||
if (special.includes(10)) {
|
||||
monAtk = atk;
|
||||
monDef = def;
|
||||
}
|
||||
heroPerDamage = atk - monDef;
|
||||
if (heroPerDamage <= 0) return null;
|
||||
}
|
||||
|
||||
// 吸血
|
||||
if (special.includes(11)) {
|
||||
const vampire = hp * (info.vampire ?? 0);
|
||||
if (info.add) monHp += vampire;
|
||||
damage += vampire;
|
||||
}
|
||||
|
||||
/** 怪物单回合伤害 */
|
||||
let enemyPerDamage;
|
||||
|
||||
// 魔攻
|
||||
if (special.includes(2) || special.includes(13)) {
|
||||
if (special.includes(2)) {
|
||||
enemyPerDamage = monAtk;
|
||||
} else {
|
||||
enemyPerDamage = monAtk - def;
|
||||
@ -623,22 +802,69 @@ var plugins_bb40132b_638b_4a9f_b028_d3fe47acc8d1 = {
|
||||
}
|
||||
|
||||
// 先攻
|
||||
if (special.includes(17)) {
|
||||
if (special.includes(1)) {
|
||||
damage += enemyPerDamage;
|
||||
}
|
||||
|
||||
// 连击
|
||||
if (special.includes(4)) enemyPerDamage *= 2;
|
||||
if (special.includes(5)) enemyPerDamage *= 3;
|
||||
if (special.includes(6)) enemyPerDamage *= enemy.n;
|
||||
if (special.includes(6)) enemyPerDamage *= info.n;
|
||||
|
||||
/** 战斗回合 */
|
||||
let turn = Math.ceil(monHp / heroPerDamage);
|
||||
// 破甲
|
||||
if (special.includes(7)) {
|
||||
damage += def * (info.breakArmor ?? core.values.breakArmor);
|
||||
}
|
||||
|
||||
// 反击
|
||||
if (special.includes(8)) {
|
||||
enemyPerDamage +=
|
||||
atk * (info.counterAttack ?? core.values.counterAttack);
|
||||
}
|
||||
|
||||
// 净化
|
||||
if (special.includes(9)) {
|
||||
damage += mdef * (info.purify ?? core.values.purify);
|
||||
}
|
||||
|
||||
turn = Math.ceil(monHp / heroPerDamage);
|
||||
|
||||
// 支援,支援信息由光环计算而得,直接使用即可
|
||||
if (info.guard) {
|
||||
const guardFirst = false;
|
||||
const inGuard = core.getFlag('__inGuard__');
|
||||
if (!inGuard)
|
||||
core.setFlag('__extraTurn__', guardFirst ? 0 : turn);
|
||||
core.setFlag('__inGuard__', true);
|
||||
for (const enemy of info.guard) {
|
||||
const info = enemy.getRealInfo();
|
||||
damage +=
|
||||
Damage.calDamageWith(info, {
|
||||
...hero,
|
||||
mdef: 0
|
||||
}) ?? Infinity;
|
||||
if (!isFinite(damage)) return null;
|
||||
}
|
||||
if (!inGuard) core.removeFlag('__inGuard__');
|
||||
turn += core.getFlag('__extraTurn__', 0);
|
||||
core.removeFlag('__extraTurn__');
|
||||
}
|
||||
|
||||
// 计算最终伤害
|
||||
damage += (turn - 1) * enemyPerDamage;
|
||||
damage -= mdef;
|
||||
if (!core.flags.enableNegativeDamage) damage = Math.max(0, damage);
|
||||
|
||||
// 仇恨
|
||||
if (special.includes(17)) {
|
||||
damage += core.getFlag('hatred', 0);
|
||||
}
|
||||
|
||||
// 固伤
|
||||
if (special.includes(22)) {
|
||||
damage += info.damage;
|
||||
}
|
||||
|
||||
return damage;
|
||||
});
|
||||
|
||||
@ -660,13 +886,33 @@ var plugins_bb40132b_638b_4a9f_b028_d3fe47acc8d1 = {
|
||||
if (info.special.includes(3)) {
|
||||
return Infinity;
|
||||
}
|
||||
// 模仿,不计算临界
|
||||
if (info.special.includes(10)) {
|
||||
return Infinity;
|
||||
}
|
||||
|
||||
return add;
|
||||
}
|
||||
);
|
||||
|
||||
// --------------- 地图伤害
|
||||
// 全量复写地图伤害的计算函数,注意此处不能使用箭头函数,因为这是在原型上的函数,其this指向实例,也即怪物(DamageEnemy实例)
|
||||
const { getHeroStatusOn } = Mota.requireAll('fn');
|
||||
const caledBetween = new Set();
|
||||
// 全量复写地图伤害计算,这个计算会调用所有的 DamageEnemy 的地图伤害计算
|
||||
Mota.rewrite(
|
||||
Mota.require('class', 'EnemyCollection').prototype,
|
||||
'calMapDamage',
|
||||
'full',
|
||||
function () {
|
||||
this.mapDamage = {};
|
||||
caledBetween.clear();
|
||||
const hero = getHeroStatusOn(Damage.realStatus, this.floorId);
|
||||
this.list.forEach(v => {
|
||||
v.calMapDamage(this.mapDamage, hero);
|
||||
});
|
||||
}
|
||||
);
|
||||
// 全量复写单个怪物地图伤害的计算函数,注意此处不能使用箭头函数,因为这是在原型上的函数,其this指向实例,也即怪物(DamageEnemy实例)
|
||||
// 函数接收两个参数,damage和hero,前者表示要将结果存入的对象,后者是勇士真实属性
|
||||
// 直接将damage返回即可,返回其他值有可能会引起出错
|
||||
// 计算出伤害后直接调用this.setMapDamage即可将伤害传到对象中
|
||||
@ -678,21 +924,27 @@ var plugins_bb40132b_638b_4a9f_b028_d3fe47acc8d1 = {
|
||||
// 功能函数,计算曼哈顿距离,和判断一个值是否存在
|
||||
const { manhattan, has } = Mota.Plugin.require('utils_g');
|
||||
// 判断这个怪物是不是在地图上
|
||||
if (!has(this.x) || !has(this.y) || !has(this.floorId))
|
||||
if (
|
||||
!has(this.x) ||
|
||||
!has(this.y) ||
|
||||
!has(this.floorId) ||
|
||||
!has(this.col)
|
||||
) {
|
||||
return damage;
|
||||
const enemy = this.enemy;
|
||||
}
|
||||
const enemy = this.info;
|
||||
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);
|
||||
const dam = Math.max(enemy.zone ?? 0, 0);
|
||||
|
||||
for (let x = startX; x <= endX; x++) {
|
||||
for (let y = startY; y <= endY; y++) {
|
||||
@ -703,16 +955,15 @@ var plugins_bb40132b_638b_4a9f_b028_d3fe47acc8d1 = {
|
||||
continue;
|
||||
}
|
||||
const loc = `${x},${y}`;
|
||||
this.setMapDamage(damage, loc, dam, '突刺');
|
||||
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);
|
||||
const dam = Math.max(enemy.laser ?? 0, 0);
|
||||
|
||||
for (const dir of dirs) {
|
||||
let x = this.x;
|
||||
@ -722,22 +973,75 @@ var plugins_bb40132b_638b_4a9f_b028_d3fe47acc8d1 = {
|
||||
x += dx;
|
||||
y += dy;
|
||||
const loc = `${x},${y}`;
|
||||
const block = objs[loc];
|
||||
this.setMapDamage(damage, loc, dam, '激光');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 夹击
|
||||
if (this.info.special.includes(16)) {
|
||||
const dirs = ['left', 'down', 'up', 'right'];
|
||||
const dam = Math.floor(core.status.hero.hp / 2);
|
||||
|
||||
for (const dir of dirs) {
|
||||
let x = this.x;
|
||||
let y = this.y;
|
||||
const { x: dx, y: dy } = core.utils.scan[dir];
|
||||
if (caledBetween.has(`${x + dx},${y + dy}`)) continue;
|
||||
const e = this.col.list.find(v => {
|
||||
return v.x === x + dx * 2 && v.y === y + dy * 2;
|
||||
});
|
||||
if (e) {
|
||||
const loc = `${x + dx},${y + dy}`;
|
||||
this.setMapDamage(damage, loc, dam, '夹击');
|
||||
caledBetween.add(loc);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 阻击
|
||||
if (this.info.special.includes(18)) {
|
||||
const 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.repulse ?? 0, 0);
|
||||
|
||||
for (let x = startX; x <= endX; x++) {
|
||||
for (let y = startY; y <= endY; y++) {
|
||||
if (
|
||||
block &&
|
||||
block.event.noPass &&
|
||||
block.event.cls !== 'enemys' &&
|
||||
block.event.cls !== 'enemy48' &&
|
||||
block.id !== 141 &&
|
||||
block.id !== 151
|
||||
!enemy.zoneSquare &&
|
||||
manhattan(x, y, this.x, this.y) > range
|
||||
) {
|
||||
break;
|
||||
continue;
|
||||
}
|
||||
this.setMapDamage(damage, loc, dam, '射击');
|
||||
const loc = `${x},${y}`;
|
||||
this.setMapDamage(damage, loc, dam, '阻击');
|
||||
damage[loc].repulse = damage[loc].repulse ?? [];
|
||||
damage[loc].repulse.push([this.x, this.y]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 捕捉
|
||||
if (this.info.special.includes(27)) {
|
||||
const dirs = ['left', 'down', 'up', 'right'];
|
||||
for (const dir of dirs) {
|
||||
let x = this.x;
|
||||
let y = this.y;
|
||||
const { x: dx, y: dy } = core.utils.scan[dir];
|
||||
this.col.list.forEach(v => {
|
||||
if (v.x === x + dx * 2 && v.y === y + dy * 2) {
|
||||
const loc = `${x + dx},${y + dy}`;
|
||||
this.setMapDamage(damage, loc, 0);
|
||||
}
|
||||
damage[loc].ambush = damage[loc].ambush ?? [];
|
||||
damage[loc].ambush.push(this);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return damage;
|
||||
}
|
||||
);
|
||||
@ -750,7 +1054,7 @@ var plugins_bb40132b_638b_4a9f_b028_d3fe47acc8d1 = {
|
||||
|
||||
// 光环属性列表,是一个集合Set,你可以在这里配置会被视为光环的属性
|
||||
const haloSpecials = Mota.require('module', 'Damage').haloSpecials;
|
||||
haloSpecials.add(8).add(11);
|
||||
haloSpecials.add(25).add(26).add(28);
|
||||
|
||||
// ----- 计算第二类光环,即普通光环,这类光环更常见,因此放到前面了
|
||||
Mota.rewrite(
|
||||
@ -770,78 +1074,58 @@ var plugins_bb40132b_638b_4a9f_b028_d3fe47acc8d1 = {
|
||||
// 获取所有还没有计算的光环,注意这里不能直接获取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;
|
||||
// 普通光环
|
||||
case 25: {
|
||||
const e = this.enemy;
|
||||
const type = e.haloSquare ? 'square' : 'manhattan';
|
||||
const r = Math.floor(e.haloRange);
|
||||
const d = type === 'square' ? r * 2 + 1 : r;
|
||||
const range = { x: this.x, y: this.y, d };
|
||||
|
||||
// 施加光环
|
||||
col.applyHalo(type, range, this, (e, enemy) => {
|
||||
e.atkBuff += enemy.atkBuff ?? 0;
|
||||
e.defBuff += enemy.defBuff ?? 0;
|
||||
e.hpBuff += enemy.hpBuff ?? 0;
|
||||
});
|
||||
// 向已施加的光环列表中添加
|
||||
this.providedHalo.add(25);
|
||||
break;
|
||||
}
|
||||
});
|
||||
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
|
||||
case 26: {
|
||||
const range = { x: this.x, y: this.y, d: 1 };
|
||||
// 支援
|
||||
col.applyHalo('square', range, this, (e, enemy) => {
|
||||
e.guard = e.guard ?? [];
|
||||
e.guard.push(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
|
||||
);
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
// ----- 计算第一类光环
|
||||
const changeable = Mota.require('module', 'Damage').changeableHaloValue;
|
||||
changeable
|
||||
.set(21, ['atkValue', 'defValue'])
|
||||
.set(7, ['breakArmor'])
|
||||
.set(8, ['counterAttack'])
|
||||
.set(22, ['damage'])
|
||||
.set(25, ['haloRange'])
|
||||
.set(24, ['laser'])
|
||||
.set(6, ['n'])
|
||||
.set(9, ['purify'])
|
||||
.set(15, ['range'])
|
||||
.set(18, ['repulse'])
|
||||
.set(11, ['vampire'])
|
||||
.set(15, ['zone']);
|
||||
Mota.rewrite(
|
||||
Mota.require('class', 'DamageEnemy').prototype,
|
||||
'preProvideHalo',
|
||||
@ -850,11 +1134,47 @@ var plugins_bb40132b_638b_4a9f_b028_d3fe47acc8d1 = {
|
||||
if (this.progress !== 0) return;
|
||||
this.progress = 1;
|
||||
const special = this.getHaloSpecials();
|
||||
const col = this.col ?? core.status.maps[this.floorId].enemy;
|
||||
|
||||
for (const halo of special) {
|
||||
switch (halo) {
|
||||
default:
|
||||
break;
|
||||
case 28: {
|
||||
// 特殊光环
|
||||
const e = this.enemy;
|
||||
const type = e.haloSquare ? 'square' : 'manhattan';
|
||||
const r = Math.floor(e.haloRange);
|
||||
const d = type === 'square' ? r * 2 + 1 : r;
|
||||
const range = { x: this.x, y: this.y, d };
|
||||
|
||||
// 这一句必须放到applyHalo之前
|
||||
this.providedHalo.add(28);
|
||||
|
||||
col.applyHalo(
|
||||
type,
|
||||
range,
|
||||
this,
|
||||
(e, enemy) => {
|
||||
const s = enemy.specialHalo;
|
||||
e.special.push(...s);
|
||||
// 然后计算特殊属性数值
|
||||
for (const spec of s) {
|
||||
const toChange = changeable.get(spec);
|
||||
if (!toChange) continue;
|
||||
for (const key of toChange) {
|
||||
if (enemy.specialMultiply) {
|
||||
e[key] = s[key] ?? 1;
|
||||
e[key] *= enemy[key];
|
||||
} else {
|
||||
e[key] = s[key] ?? 0;
|
||||
e[key] += enemy[key];
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
// true表示递归计算,视为第一类光环
|
||||
true
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -870,5 +1190,96 @@ var plugins_bb40132b_638b_4a9f_b028_d3fe47acc8d1 = {
|
||||
halo(this.info, enemy);
|
||||
}
|
||||
);
|
||||
},
|
||||
checkBlock: function () {
|
||||
Mota.rewrite(core.control, 'checkBlock', 'full', function () {
|
||||
const x = core.getHeroLoc('x'),
|
||||
y = core.getHeroLoc('y'),
|
||||
loc = x + ',' + y;
|
||||
const info = core.status.thisMap.enemy.mapDamage[loc];
|
||||
const damage = info?.damage;
|
||||
const floor = core.status.thisMap;
|
||||
if (damage) {
|
||||
// 伤害弹出,在渲染进程中执行
|
||||
Mota.r(() => {
|
||||
Mota.Plugin.require('pop_r').addPop(
|
||||
(x - core.bigmap.offsetX / 32) * 32 + 12,
|
||||
(y - core.bigmap.offsetY / 32) * 32 + 20,
|
||||
(-damage).toString()
|
||||
);
|
||||
});
|
||||
core.status.hero.hp -= damage;
|
||||
const type = [...info.type];
|
||||
const text = type.join(',') || '伤害';
|
||||
core.drawTip('受到' + text + damage + '点');
|
||||
core.drawHeroAnimate('zone');
|
||||
this._checkBlock_disableQuickShop();
|
||||
core.status.hero.statistics.extraDamage += damage;
|
||||
if (core.status.hero.hp <= 0) {
|
||||
core.status.hero.hp = 0;
|
||||
core.updateStatusBar();
|
||||
core.events.lose();
|
||||
return;
|
||||
} else {
|
||||
core.updateStatusBar();
|
||||
}
|
||||
}
|
||||
const { findDir, ofDir } = Mota.Plugin.require('utils_g');
|
||||
|
||||
// 阻击处理
|
||||
if (info?.repulse) {
|
||||
const actions = [];
|
||||
for (const [ex, ey] of info.repulse) {
|
||||
const dir = findDir({ x, y }, { x: ex, y: ey });
|
||||
const [tx, ty] = ofDir(ex, ey, dir);
|
||||
if (
|
||||
tx < 0 ||
|
||||
ty < 0 ||
|
||||
tx >= floor.width ||
|
||||
ty >= floor.height ||
|
||||
core.getBlock(tx, ty)
|
||||
) {
|
||||
continue;
|
||||
}
|
||||
actions.push({
|
||||
type: 'move',
|
||||
loc: [ex, ey],
|
||||
steps: [findDir({ x, y }, { x: ex, y: ey })],
|
||||
time: 250,
|
||||
keep: true,
|
||||
async: true
|
||||
});
|
||||
}
|
||||
actions.push({ type: 'waitAsync' });
|
||||
core.insertAction(actions);
|
||||
}
|
||||
// 捕捉处理
|
||||
if (info?.ambush) {
|
||||
const actions = [];
|
||||
for (const enemy of info.ambush) {
|
||||
actions.push({
|
||||
type: 'move',
|
||||
loc: [enemy.x, enemy.y],
|
||||
steps: [findDir(enemy, { x, y })],
|
||||
time: 250,
|
||||
keep: false,
|
||||
async: true
|
||||
});
|
||||
}
|
||||
actions.push({ type: 'waitAsync' });
|
||||
// 强制战斗
|
||||
for (const enemy of info.ambush) {
|
||||
actions.push({
|
||||
type: 'function',
|
||||
function:
|
||||
'function() { ' +
|
||||
`core.battle(${enemy.x}, ${enemy.y}, true, core.doAction); ` +
|
||||
'}',
|
||||
async: true
|
||||
});
|
||||
}
|
||||
core.insertAction(actions);
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
@ -19,11 +19,14 @@
|
||||
class="special-text"
|
||||
v-if="has(enemy.special) && enemy.special.length > 0"
|
||||
>
|
||||
<template v-for="(text, i) in enemy.showSpecial">
|
||||
<span
|
||||
v-for="(text, i) in enemy.showSpecial"
|
||||
v-if="i < (isMobile ? 1 : 2)"
|
||||
:style="{ color: text[2] }"
|
||||
> {{ text[0] }} </span
|
||||
>
|
||||
<span v-if="i === (isMobile ? 1 : 2)">...</span>
|
||||
</template>
|
||||
</div>
|
||||
<div class="special-text" v-else>无属性</div>
|
||||
</div>
|
||||
|
@ -58,116 +58,6 @@ function init() {
|
||||
callback?.();
|
||||
};
|
||||
|
||||
core.events.afterBattle = function afterBattle(
|
||||
enemy: DamageEnemy,
|
||||
x?: number,
|
||||
y?: number
|
||||
) {
|
||||
const floorId = core.status.floorId;
|
||||
const special = enemy.info.special;
|
||||
|
||||
// 播放战斗动画
|
||||
let animate: AnimationIds = 'hand';
|
||||
// 检查当前装备是否存在攻击动画
|
||||
const equipId = core.getEquip(0);
|
||||
if (equipId && (core.material.items[equipId].equip || {}).animate)
|
||||
animate = core.material.items[equipId].equip.animate;
|
||||
|
||||
// 检查该动画是否存在SE,如果不存在则使用默认音效
|
||||
if (!core.material.animates[animate]?.se) core.playSound('attack.mp3');
|
||||
|
||||
// 战斗伤害
|
||||
const info = enemy.calDamage(core.status.hero);
|
||||
const damage = info.damage;
|
||||
// 判定是否致死
|
||||
if (damage >= core.status.hero.hp) {
|
||||
core.status.hero.hp = 0;
|
||||
core.updateStatusBar(false, true);
|
||||
core.events.lose('战斗失败');
|
||||
return;
|
||||
}
|
||||
|
||||
// 扣减体力值并记录统计数据
|
||||
core.status.hero.hp -= damage;
|
||||
core.status.hero.statistics.battleDamage += damage;
|
||||
core.status.hero.statistics.battle++;
|
||||
|
||||
// 智慧之源
|
||||
if (special.includes(14) && flags.hard === 2) {
|
||||
core.addFlag(
|
||||
'inte_' + floorId,
|
||||
Math.ceil((core.status.hero.mdef / 10) * 0.3) * 10
|
||||
);
|
||||
core.status.hero.mdef -=
|
||||
Math.ceil((core.status.hero.mdef / 10) * 0.3) * 10;
|
||||
}
|
||||
|
||||
// 极昼永夜
|
||||
if (special.includes(22)) {
|
||||
flags[`night_${floorId}`] ??= 0;
|
||||
flags[`night_${floorId}`] -= enemy.enemy.night!;
|
||||
}
|
||||
if (special.includes(23)) {
|
||||
flags[`night_${floorId}`] ??= 0;
|
||||
flags[`night_${floorId}`] += enemy.enemy.day;
|
||||
}
|
||||
|
||||
// if (core.plugin.skillTree.getSkillLevel(11) > 0) {
|
||||
// core.plugin.study.declineStudiedSkill();
|
||||
// }
|
||||
|
||||
// 如果是融化怪,需要特殊标记一下
|
||||
if (special.includes(25) && has(x) && has(y)) {
|
||||
flags[`melt_${floorId}`] ??= {};
|
||||
flags[`melt_${floorId}`][`${x},${y}`] = enemy.enemy.melt;
|
||||
}
|
||||
|
||||
// 获得金币
|
||||
const money = enemy.enemy.money;
|
||||
core.status.hero.money += money;
|
||||
core.status.hero.statistics.money += money;
|
||||
|
||||
// 获得经验
|
||||
const exp = enemy.enemy.exp;
|
||||
core.status.hero.exp += exp;
|
||||
core.status.hero.statistics.exp += exp;
|
||||
|
||||
const hint =
|
||||
'打败 ' + enemy.enemy.name + ',金币+' + money + ',经验+' + exp;
|
||||
core.drawTip(hint, enemy.id);
|
||||
|
||||
if (core.getFlag('bladeOn') && core.getFlag('blade')) {
|
||||
core.setFlag('blade', false);
|
||||
}
|
||||
if (core.getFlag('shieldOn') && core.getFlag('shield')) {
|
||||
core.setFlag('shield', false);
|
||||
}
|
||||
|
||||
// 事件的处理
|
||||
const todo: MotaEvent = [];
|
||||
|
||||
// 战后事件
|
||||
if (has(core.status.floorId)) {
|
||||
const loc = `${x},${y}` as LocString;
|
||||
todo.push(
|
||||
...(core.floors[core.status.floorId].afterBattle[loc] ?? [])
|
||||
);
|
||||
}
|
||||
todo.push(...(enemy.enemy.afterBattle ?? []));
|
||||
|
||||
// 如果事件不为空,将其插入
|
||||
if (todo.length > 0) core.insertAction(todo, x, y);
|
||||
|
||||
if (has(x) && has(y)) {
|
||||
core.drawAnimate(animate, x, y);
|
||||
core.removeBlock(x, y);
|
||||
} else core.drawHeroAnimate(animate);
|
||||
|
||||
// 如果已有事件正在处理中
|
||||
if (core.status.event.id == null) core.continueAutomaticRoute();
|
||||
else core.clearContinueAutomaticRoute();
|
||||
};
|
||||
|
||||
core.enemys.getCurrentEnemys = function getCurrentEnemys(
|
||||
floorId = core.status.floorId
|
||||
) {
|
||||
|
@ -14,9 +14,14 @@ interface HaloType {
|
||||
y: number;
|
||||
d: number;
|
||||
};
|
||||
manhattan: {
|
||||
x: number;
|
||||
y: number;
|
||||
d: number;
|
||||
};
|
||||
}
|
||||
|
||||
interface EnemyInfo {
|
||||
interface EnemyInfo extends Partial<SelectType<Enemy, number | undefined>> {
|
||||
atk: number;
|
||||
def: number;
|
||||
hp: number;
|
||||
@ -25,6 +30,7 @@ interface EnemyInfo {
|
||||
defBuff: number;
|
||||
hpBuff: number;
|
||||
enemy: Enemy;
|
||||
guard?: DamageEnemy[];
|
||||
x?: number;
|
||||
y?: number;
|
||||
floorId?: FloorIds;
|
||||
@ -39,7 +45,8 @@ interface DamageInfo {
|
||||
interface MapDamage {
|
||||
damage: number;
|
||||
type: Set<string>;
|
||||
mockery?: LocArr[];
|
||||
repulse?: LocArr[];
|
||||
ambush?: DamageEnemy[];
|
||||
}
|
||||
|
||||
interface HaloData<T extends keyof HaloType = keyof HaloType> {
|
||||
@ -103,6 +110,8 @@ export class EnemyCollection implements RangeCollection<DamageEnemy> {
|
||||
this.haloList = [];
|
||||
this.list.forEach(v => {
|
||||
v.reset();
|
||||
});
|
||||
this.list.forEach(v => {
|
||||
v.preProvideHalo();
|
||||
});
|
||||
this.list.forEach(v => {
|
||||
@ -146,21 +155,22 @@ export class EnemyCollection implements RangeCollection<DamageEnemy> {
|
||||
applyHalo<K extends keyof HaloType>(
|
||||
type: K,
|
||||
data: HaloType[K],
|
||||
enemy: DamageEnemy,
|
||||
halo: HaloFn | HaloFn[],
|
||||
recursion: boolean = false
|
||||
) {
|
||||
const arr = ensureArray(halo);
|
||||
const enemy = this.range.scan(type, data);
|
||||
const enemys = this.range.scan(type, data);
|
||||
if (!recursion) {
|
||||
arr.forEach(v => {
|
||||
enemy.forEach(e => {
|
||||
e.injectHalo(v, e.enemy);
|
||||
enemys.forEach(e => {
|
||||
e.injectHalo(v, enemy.enemy);
|
||||
});
|
||||
});
|
||||
} else {
|
||||
enemy.forEach(e => {
|
||||
enemys.forEach(e => {
|
||||
arr.forEach(v => {
|
||||
e.injectHalo(v, e.enemy);
|
||||
e.injectHalo(v, enemy.enemy);
|
||||
e.preProvideHalo();
|
||||
});
|
||||
});
|
||||
@ -260,6 +270,26 @@ export class EnemyCollection implements RangeCollection<DamageEnemy> {
|
||||
alpha: 1
|
||||
});
|
||||
}
|
||||
|
||||
if (dam.ambush) {
|
||||
core.status.damage.extraData.push({
|
||||
text: '!',
|
||||
px: 32 * x + 16,
|
||||
py: 32 * y + 16,
|
||||
color: '#fa3',
|
||||
alpha: 1
|
||||
});
|
||||
}
|
||||
|
||||
if (dam.repulse) {
|
||||
core.status.damage.extraData.push({
|
||||
text: '阻',
|
||||
px: 32 * x + 16,
|
||||
py: 32 * y + 16,
|
||||
color: '#fa3',
|
||||
alpha: 1
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -320,8 +350,15 @@ export class DamageEnemy<T extends EnemyIds = EnemyIds> {
|
||||
y: this.y,
|
||||
floorId: this.floorId
|
||||
};
|
||||
|
||||
for (const [key, value] of Object.entries(enemy)) {
|
||||
if (!(key in this.info) && has(value)) {
|
||||
// @ts-ignore
|
||||
this.info[key] = value;
|
||||
}
|
||||
}
|
||||
this.progress = 0;
|
||||
this.providedHalo = new Set();
|
||||
this.providedHalo.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -381,6 +418,7 @@ export class DamageEnemy<T extends EnemyIds = EnemyIds> {
|
||||
if (!this.floorId) return [];
|
||||
if (!has(this.x) || !has(this.y)) return [];
|
||||
const special = this.info.special ?? this.enemy.special;
|
||||
|
||||
const filter = special.filter(v => {
|
||||
return Damage.haloSpecials.has(v) && !this.providedHalo.has(v);
|
||||
});
|
||||
@ -397,92 +435,12 @@ export class DamageEnemy<T extends EnemyIds = EnemyIds> {
|
||||
/**
|
||||
* 光环预提供,用于平衡所有怪的光环属性,避免出现不同情况下光环效果不一致的现象
|
||||
*/
|
||||
preProvideHalo() {
|
||||
if (this.progress !== 0) return;
|
||||
this.progress = 1;
|
||||
const special = this.getHaloSpecials();
|
||||
|
||||
for (const halo of special) {
|
||||
switch (halo) {
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
preProvideHalo() {}
|
||||
|
||||
/**
|
||||
* 向其他怪提供光环
|
||||
*/
|
||||
provideHalo() {
|
||||
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;
|
||||
const special = this.getHaloSpecials();
|
||||
|
||||
const square7: HaloFn[] = [];
|
||||
const square5: HaloFn[] = [];
|
||||
|
||||
// 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);
|
||||
}
|
||||
provideHalo() {}
|
||||
|
||||
/**
|
||||
* 接受其他怪的光环
|
||||
@ -507,64 +465,6 @@ export class DamageEnemy<T extends EnemyIds = EnemyIds> {
|
||||
damage: Record<string, MapDamage> = {},
|
||||
hero: Partial<HeroStatus> = getHeroStatusOn(Damage.realStatus)
|
||||
) {
|
||||
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: Dir[] = ['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}` as LocString;
|
||||
// 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;
|
||||
}
|
||||
|
||||
@ -572,11 +472,11 @@ export class DamageEnemy<T extends EnemyIds = EnemyIds> {
|
||||
damage: Record<string, MapDamage>,
|
||||
loc: string,
|
||||
dam: number,
|
||||
type: string
|
||||
type?: string
|
||||
) {
|
||||
damage[loc] ??= { damage: 0, type: new Set() };
|
||||
damage[loc].damage += dam;
|
||||
damage[loc].type.add(type);
|
||||
if (type) damage[loc].type.add(type);
|
||||
}
|
||||
|
||||
private calEnemyDamageOf(hero: Partial<HeroStatus>, enemy: EnemyInfo) {
|
||||
@ -730,6 +630,12 @@ export namespace Damage {
|
||||
/** 光环属性 */
|
||||
export const haloSpecials: Set<number> = new Set();
|
||||
|
||||
/** 会被第一类光环修改的怪物特殊属性数值 */
|
||||
export const changeableHaloValue: Map<
|
||||
number,
|
||||
SelectKey<Enemy, number | undefined>[]
|
||||
> = new Map();
|
||||
|
||||
/**
|
||||
* 计算伤害时会用到的勇士属性,攻击防御,其余的不会有buff加成,直接从core.status.hero取
|
||||
*/
|
||||
@ -744,55 +650,7 @@ export namespace Damage {
|
||||
info: EnemyInfo,
|
||||
hero: Partial<HeroStatus>
|
||||
): number | null {
|
||||
const { hp, hpmax, mana, mdef } = core.status.hero;
|
||||
let { atk, def } = hero as HeroStatus;
|
||||
let { hp: monHp, atk: monAtk, def: monDef, special, enemy } = info;
|
||||
|
||||
let damage = 0;
|
||||
|
||||
// 饥渴
|
||||
if (special.includes(7)) {
|
||||
const delta = Math.floor((atk * enemy.hungry!) / 100);
|
||||
atk -= delta;
|
||||
monAtk += delta;
|
||||
}
|
||||
|
||||
let heroPerDamage: number;
|
||||
|
||||
// 绝对防御
|
||||
if (special.includes(3)) {
|
||||
// 由于坚固的特性,只能放到这来计算了
|
||||
if (atk > enemy.def) heroPerDamage = 1 + mana;
|
||||
else return null;
|
||||
} else {
|
||||
heroPerDamage = atk - monDef;
|
||||
if (heroPerDamage > 0) heroPerDamage += mana;
|
||||
else return null;
|
||||
}
|
||||
|
||||
let enemyPerDamage: number;
|
||||
|
||||
// 魔攻
|
||||
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);
|
||||
|
||||
return damage;
|
||||
return null;
|
||||
}
|
||||
|
||||
export function ensureFloorDamage(floorId: FloorIds) {
|
||||
|
@ -164,7 +164,6 @@ interface PluginInterface {
|
||||
heroFourFrames_g: typeof import('../plugin/game/fx/heroFourFrames');
|
||||
rewrite_g: typeof import('../plugin/game/fx/rewrite');
|
||||
itemDetail_g: typeof import('../plugin/game/fx/itemDetail');
|
||||
checkBlock_g: typeof import('../plugin/game/enemy/checkblock');
|
||||
}
|
||||
|
||||
interface PackageInterface {
|
||||
|
@ -24,40 +24,7 @@ const MAX_ROTATE = 0.5;
|
||||
/** 碎裂动画的速率曲线函数 */
|
||||
const FRAG_TIMING = linear();
|
||||
|
||||
export function init() {
|
||||
Mota.rewrite(core.events, 'afterBattle', 'add', (_, enemy, x, y) => {
|
||||
// 打怪特效
|
||||
const setting = Mota.require('var', 'mainSetting');
|
||||
|
||||
if (setting.getValue('fx.frag') && has(x) && has(y)) {
|
||||
const frame = core.status.globalAnimateStatus % 2;
|
||||
const canvas = document.createElement('canvas');
|
||||
canvas.width = 32;
|
||||
canvas.height = 32;
|
||||
core.drawIcon(canvas, enemy.id, 0, 0, 32, 32, frame);
|
||||
const manager = applyFragWith(canvas);
|
||||
const frag = manager.canvas;
|
||||
frag.style.imageRendering = 'pixelated';
|
||||
frag.style.width = `${frag.width * core.domStyle.scale}px`;
|
||||
frag.style.height = `${frag.height * core.domStyle.scale}px`;
|
||||
const left =
|
||||
(x * 32 + 16 - frag.width / 2 - core.bigmap.offsetX) *
|
||||
core.domStyle.scale;
|
||||
const top =
|
||||
(y * 32 + 16 - frag.height / 2 - core.bigmap.offsetY) *
|
||||
core.domStyle.scale;
|
||||
frag.style.left = `${left}px`;
|
||||
frag.style.top = `${top}px`;
|
||||
frag.style.zIndex = '45';
|
||||
frag.style.position = 'absolute';
|
||||
frag.style.filter = 'sepia(20%)brightness(120%)';
|
||||
core.dom.gameDraw.appendChild(frag);
|
||||
manager.onEnd.then(() => {
|
||||
frag.remove();
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
export function init() {}
|
||||
|
||||
export function applyFragWith(
|
||||
canvas: HTMLCanvasElement,
|
||||
|
@ -1,35 +0,0 @@
|
||||
export function init() {
|
||||
// 伤害弹出
|
||||
// 复写阻激夹域检测
|
||||
control.prototype.checkBlock = function (forceMockery: boolean = false) {
|
||||
const x = core.getHeroLoc('x'),
|
||||
y = core.getHeroLoc('y'),
|
||||
loc = x + ',' + y;
|
||||
const info = core.status.thisMap.enemy.mapDamage[loc];
|
||||
const damage = info?.damage;
|
||||
if (damage) {
|
||||
Mota.r(() => {
|
||||
Mota.Plugin.require('pop_r').addPop(
|
||||
(x - core.bigmap.offsetX / 32) * 32 + 12,
|
||||
(y - core.bigmap.offsetY / 32) * 32 + 20,
|
||||
(-damage).toString()
|
||||
);
|
||||
});
|
||||
core.status.hero.hp -= damage;
|
||||
const type = [...info.type];
|
||||
const text = type.join(',') || '伤害';
|
||||
core.drawTip('受到' + text + damage + '点');
|
||||
core.drawHeroAnimate('zone');
|
||||
this._checkBlock_disableQuickShop();
|
||||
core.status.hero.statistics.extraDamage += damage;
|
||||
if (core.status.hero.hp <= 0) {
|
||||
core.status.hero.hp = 0;
|
||||
core.updateStatusBar();
|
||||
core.events.lose();
|
||||
return;
|
||||
} else {
|
||||
core.updateStatusBar();
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
@ -6,7 +6,6 @@ import * as removeMap from './removeMap';
|
||||
import * as shop from './shop';
|
||||
import * as utils from './utils';
|
||||
import * as remainEnemy from './enemy/remainEnemy';
|
||||
import * as checkBlock from './enemy/checkblock';
|
||||
|
||||
Mota.Plugin.register('utils_g', utils);
|
||||
Mota.Plugin.register('shop_g', shop);
|
||||
@ -16,7 +15,6 @@ Mota.Plugin.register('heroFourFrames_g', heroFourFrames, heroFourFrames.init);
|
||||
Mota.Plugin.register('rewrite_g', rewrite, rewrite.init);
|
||||
Mota.Plugin.register('itemDetail_g', itemDetail, itemDetail.init);
|
||||
Mota.Plugin.register('remainEnemy_g', remainEnemy);
|
||||
Mota.Plugin.register('checkBlock_g', checkBlock, checkBlock.init);
|
||||
|
||||
// export {
|
||||
// halo,
|
||||
|
@ -96,3 +96,21 @@ Range.registerRangeType(
|
||||
);
|
||||
}
|
||||
);
|
||||
Range.registerRangeType(
|
||||
'manhattan',
|
||||
(col, { x, y, d }) => {
|
||||
const list = col.collection.list;
|
||||
return list.filter(v => {
|
||||
if (!has(v.x) || !has(v.y)) return;
|
||||
const dx = Math.abs(v.x - x);
|
||||
const dy = Math.abs(v.y - y);
|
||||
return dx + dy < d;
|
||||
});
|
||||
},
|
||||
(col, { x, y, d }, item) => {
|
||||
if (!has(item.x) || !has(item.y)) return false;
|
||||
const dx = Math.abs(item.x - x);
|
||||
const dy = Math.abs(item.y - y);
|
||||
return dx + dy < d;
|
||||
}
|
||||
);
|
||||
|
@ -160,9 +160,10 @@ export function boundary(arr: any, key?: any) {
|
||||
export function findDir(from: Loc, to: Loc): Dir2 | 'none' {
|
||||
const dx = to.x - from.x;
|
||||
const dy = to.y - from.y;
|
||||
|
||||
return (
|
||||
(Object.entries(core.utils.scan2).find(v => {
|
||||
v[1].x === dx && v[1].y === dy;
|
||||
return v[1].x === dx && v[1].y === dy;
|
||||
})?.[0] as Dir2) ?? 'none'
|
||||
);
|
||||
}
|
||||
|
@ -28,19 +28,17 @@ export function getDetailedEnemy(
|
||||
) => {
|
||||
return typeof func === 'string' ? func : func(enemy);
|
||||
};
|
||||
const special: [string, string, string][] = enemy.enemy.special.map(vv => {
|
||||
const special: [string, string, string][] = enemy.info.special.map(vv => {
|
||||
const s = Mota.require('var', 'enemySpecials')[vv];
|
||||
const info = { ...enemy.enemy, ...enemy.info };
|
||||
return [
|
||||
fromFunc(s.name, enemy.enemy),
|
||||
fromFunc(s.desc, enemy.enemy),
|
||||
fromFunc(s.name, info),
|
||||
fromFunc(s.desc, info),
|
||||
s.color as string
|
||||
];
|
||||
});
|
||||
const l = isMobile ? 1 : 2;
|
||||
const showSpecial =
|
||||
special.length > l
|
||||
? special.slice(0, l).concat([['...', '', '#fff']])
|
||||
: special.slice();
|
||||
const showSpecial = special;
|
||||
|
||||
const damageColor = getDamageColor(dam) as string;
|
||||
|
||||
|
16
src/types/enemy.d.ts
vendored
16
src/types/enemy.d.ts
vendored
@ -15,21 +15,7 @@ type PartialNumbericEnemyProperty =
|
||||
| 'purify'
|
||||
| 'atkValue'
|
||||
| 'defValue'
|
||||
| 'damage'
|
||||
| 'iceDecline'
|
||||
| 'iceCore'
|
||||
| 'fireCore'
|
||||
| 'together'
|
||||
| 'hungry'
|
||||
| 'ice'
|
||||
| 'crit'
|
||||
| 'courage'
|
||||
| 'charge'
|
||||
| 'paleShield'
|
||||
| 'iceHalo'
|
||||
| 'day'
|
||||
| 'night'
|
||||
| 'melt';
|
||||
| 'damage';
|
||||
|
||||
type BooleanEnemyProperty =
|
||||
| 'zoneSquare'
|
||||
|
Loading…
Reference in New Issue
Block a user