mirror of
https://github.com/unanmed/HumanBreak.git
synced 2025-10-15 17:32:58 +08:00
chore: 怪物伤害计算与特殊属性调整为样板
This commit is contained in:
parent
fe46a7b397
commit
7c9847aa40
@ -53,7 +53,7 @@ export function toggleSkill1() {
|
|||||||
import { getSkill1Enabled } from '../machanism/skill'; // [!code ++]
|
import { getSkill1Enabled } from '../machanism/skill'; // [!code ++]
|
||||||
|
|
||||||
export function calDamageWith(
|
export function calDamageWith(
|
||||||
info: UserEnemyInfo,
|
info: EnemyInfo,
|
||||||
hero: Partial<HeroStatus>
|
hero: Partial<HeroStatus>
|
||||||
): number | null {
|
): number | null {
|
||||||
// ... 原有内容
|
// ... 原有内容
|
||||||
@ -241,7 +241,7 @@ export function getEnabledSkill() {
|
|||||||
import { getEnabledSkill, SkillType } from './skill';
|
import { getEnabledSkill, SkillType } from './skill';
|
||||||
|
|
||||||
export function calDamageWith(
|
export function calDamageWith(
|
||||||
info: UserEnemyInfo,
|
info: EnemyInfo,
|
||||||
hero: Partial<HeroStatus>
|
hero: Partial<HeroStatus>
|
||||||
): number | null {
|
): number | null {
|
||||||
// ... 原有内容
|
// ... 原有内容
|
||||||
@ -260,7 +260,7 @@ export function calDamageWith(
|
|||||||
import { getEnabledSkill, SkillType } from './skill';
|
import { getEnabledSkill, SkillType } from './skill';
|
||||||
|
|
||||||
export function calDamageWith(
|
export function calDamageWith(
|
||||||
info: UserEnemyInfo,
|
info: EnemyInfo,
|
||||||
hero: Partial<HeroStatus>
|
hero: Partial<HeroStatus>
|
||||||
): number | null {
|
): number | null {
|
||||||
// ... 原有内容
|
// ... 原有内容
|
||||||
|
@ -26,13 +26,13 @@ export const specials: SpecialDeclaration[] = [
|
|||||||
|
|
||||||
## 实现特殊属性
|
## 实现特殊属性
|
||||||
|
|
||||||
打开 `packages-user/data-state/src/enemy/damage.ts`,在文件最后的 `calDamageWith` 函数中编写:
|
打开 `packages-user/data-state/src/enemy/damage.ts`,在文件最后的 `calDamageWithTurn` 函数中编写:
|
||||||
|
|
||||||
```ts
|
```ts
|
||||||
export function calDamageWith(
|
export function calDamageWithTurn(
|
||||||
info: UserEnemyInfo,
|
info: EnemyInfo,
|
||||||
hero: Partial<HeroStatus>
|
hero: Partial<HeroStatus>
|
||||||
): number | null {
|
): DamageWithTurn {
|
||||||
// ... 原有内容
|
// ... 原有内容
|
||||||
|
|
||||||
// 在需要降低勇士伤害的地方将勇士伤害乘以 0.9 即可
|
// 在需要降低勇士伤害的地方将勇士伤害乘以 0.9 即可
|
||||||
@ -102,13 +102,13 @@ export const specials: SpecialDeclaration[] = [
|
|||||||
|
|
||||||
### 属性实现
|
### 属性实现
|
||||||
|
|
||||||
修改 `damage.ts` `calDamageWith` 中的实现:
|
修改 `damage.ts` `calDamageWithTurn` 中的实现:
|
||||||
|
|
||||||
```ts
|
```ts
|
||||||
export function calDamageWith(
|
export function calDamageWith(
|
||||||
info: UserEnemyInfo,
|
info: EnemyInfo,
|
||||||
hero: Partial<HeroStatus>
|
hero: Partial<HeroStatus>
|
||||||
): number | null {
|
): DamageWithTurn {
|
||||||
// ... 原有内容
|
// ... 原有内容
|
||||||
|
|
||||||
// 在乘以 1 - (myAttr / 100),除以 100 是因为 myAttr 是百分制
|
// 在乘以 1 - (myAttr / 100),除以 100 是因为 myAttr 是百分制
|
||||||
@ -210,10 +210,11 @@ class DamageEnemy {
|
|||||||
|
|
||||||
### 自定义形状
|
### 自定义形状
|
||||||
|
|
||||||
如果想要自定义光环形状,我们打开 `packages-user/data-utils/src/range.ts`,拉到最后可以看到形状定义,目前包含两个:
|
如果想要自定义光环形状,我们打开 `packages-user/data-utils/src/range.ts`,拉到最后可以看到形状定义,目前默认的包含这些:
|
||||||
|
|
||||||
- `square`: 中心点+边长的正方形
|
- `square`: 中心点+边长的正方形
|
||||||
- `rect`: 左上角坐标+宽高的矩形
|
- `rect`: 左上角坐标+宽高的矩形
|
||||||
|
- `manhattan`: 曼哈顿距离,坐标之和小于半径
|
||||||
|
|
||||||
我们以曼哈顿距离为例,展示如何自定义形状。
|
我们以曼哈顿距离为例,展示如何自定义形状。
|
||||||
|
|
||||||
@ -262,27 +263,3 @@ col.applyHalo(
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
```
|
```
|
||||||
|
|
||||||
## 拓展-输出回合数
|
|
||||||
|
|
||||||
样板默认的 `calDamageWith` 函数只允许输出伤害值,而有时候我们可能会需要战斗的回合数,这时候我们需要修改一下这部分内容,将伤害计算逻辑单独提出来,命名为 `calDamageWithTurn`,然后在 `calDamageWith` 中调用它。在需要回合数的时候,我们调用 `calDamageWithTurn` 函数即可,如下例所示:
|
|
||||||
|
|
||||||
```ts
|
|
||||||
/** 包含回合数的伤害计算 */
|
|
||||||
export function calDamageWithTurn(
|
|
||||||
info: UserEnemyInfo,
|
|
||||||
hero: Partial<HeroStatus>
|
|
||||||
) {
|
|
||||||
// ... 原本 calDamageWith 的计算逻辑,记得删除最后返回伤害的那一行返回值
|
|
||||||
|
|
||||||
// 返回回合数和伤害
|
|
||||||
return { turn, damage };
|
|
||||||
}
|
|
||||||
|
|
||||||
export function calDamageWith(info: UserEnemyInfo, hero: Partial<HeroStatus>) {
|
|
||||||
// 调用单独提出的函数计算伤害值
|
|
||||||
const damageInfo = calDamageWithTurn(info, hero);
|
|
||||||
// 如果伤害不存在,那么返回无穷大
|
|
||||||
return damageInfo?.damage ?? Infinity;
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
@ -210,7 +210,7 @@ const realStatus: (keyof HeroStatus)[] = [
|
|||||||
|
|
||||||
```ts
|
```ts
|
||||||
export function calDamageWith(
|
export function calDamageWith(
|
||||||
info: UserEnemyInfo,
|
info: EnemyInfo,
|
||||||
hero: Partial<HeroStatus>
|
hero: Partial<HeroStatus>
|
||||||
): number {
|
): number {
|
||||||
// ... 原有逻辑
|
// ... 原有逻辑
|
||||||
|
@ -969,10 +969,13 @@ export class TextContentParser {
|
|||||||
continue;
|
continue;
|
||||||
} else if (char === '$') {
|
} else if (char === '$') {
|
||||||
// 表达式
|
// 表达式
|
||||||
pointer++;
|
const next = text[pointer + 1];
|
||||||
inExpression = true;
|
if (next === '{') {
|
||||||
expStart = pointer + 1;
|
pointer++;
|
||||||
continue;
|
inExpression = true;
|
||||||
|
expStart = pointer + 1;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
} else if (char === '\n') {
|
} else if (char === '\n') {
|
||||||
// 在这里预先将换行处理为多个 node,会比在分行时再处理更方便
|
// 在这里预先将换行处理为多个 node,会比在分行时再处理更方便
|
||||||
this.addTextNode(pointer + 1, true);
|
this.addTextNode(pointer + 1, true);
|
||||||
|
@ -94,6 +94,8 @@ export function patchBattle() {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
patch2.add('battle', battle);
|
||||||
|
|
||||||
patch2.add('_sys_battle', function (data: Block, callback?: () => void) {
|
patch2.add('_sys_battle', function (data: Block, callback?: () => void) {
|
||||||
// 检查战前事件
|
// 检查战前事件
|
||||||
const floor = core.floors[core.status.floorId];
|
const floor = core.floors[core.status.floorId];
|
||||||
@ -156,8 +158,9 @@ export function patchBattle() {
|
|||||||
core.playSound('attack.opus');
|
core.playSound('attack.opus');
|
||||||
|
|
||||||
// 战斗伤害
|
// 战斗伤害
|
||||||
const info = enemy.calDamage(core.status.hero);
|
const info = enemy.getRealInfo();
|
||||||
const damage = info.damage;
|
const damageInfo = enemy.calDamage(core.status.hero);
|
||||||
|
const damage = damageInfo.damage;
|
||||||
// 判定是否致死
|
// 判定是否致死
|
||||||
if (damage >= core.status.hero.hp) {
|
if (damage >= core.status.hero.hp) {
|
||||||
core.status.hero.hp = 0;
|
core.status.hero.hp = 0;
|
||||||
@ -171,25 +174,41 @@ export function patchBattle() {
|
|||||||
core.status.hero.statistics.battleDamage += damage;
|
core.status.hero.statistics.battleDamage += damage;
|
||||||
core.status.hero.statistics.battle++;
|
core.status.hero.statistics.battle++;
|
||||||
|
|
||||||
// 获得金币
|
// 获得金币经验
|
||||||
const money = enemy.info.money!;
|
const money = core.hasFlag('curse') ? 0 : enemy.info.money!;
|
||||||
|
const exp = core.hasFlag('curse') ? 0 : enemy.info.exp!;
|
||||||
|
|
||||||
core.status.hero.money += money;
|
core.status.hero.money += money;
|
||||||
core.status.hero.statistics.money += money;
|
core.status.hero.statistics.money += money;
|
||||||
|
|
||||||
// 获得经验
|
|
||||||
const exp = enemy.info.exp!;
|
|
||||||
core.status.hero.exp += exp;
|
core.status.hero.exp += exp;
|
||||||
core.status.hero.statistics.exp += exp;
|
core.status.hero.statistics.exp += exp;
|
||||||
|
|
||||||
const hint =
|
const hint = `打败 ${enemy.enemy.name},金币+${money},经验+${exp}`;
|
||||||
'打败 ' +
|
|
||||||
enemy.enemy.name +
|
|
||||||
',金币+' +
|
|
||||||
money +
|
|
||||||
',经验+' +
|
|
||||||
exp;
|
|
||||||
core.drawTip(hint, enemy.id);
|
core.drawTip(hint, enemy.id);
|
||||||
|
|
||||||
|
// 毒衰咒
|
||||||
|
if (info.special.has(12)) core.setFlag('poison', true);
|
||||||
|
if (info.special.has(13)) core.setFlag('weak', true);
|
||||||
|
if (info.special.has(14)) core.setFlag('curse', true);
|
||||||
|
|
||||||
|
// 仇恨
|
||||||
|
if (info.special.has(17)) {
|
||||||
|
core.setFlag('hatred', core.getFlag('hatred', 0) / 2);
|
||||||
|
} else {
|
||||||
|
core.addFlag('hatred', core.values.hatred);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 自爆
|
||||||
|
if (info.special.has(19)) {
|
||||||
|
core.status.hero.hp = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 退化
|
||||||
|
if (info.special.has(21)) {
|
||||||
|
core.status.hero.atk -= info.atkValue ?? 0;
|
||||||
|
core.status.hero.def -= info.defValue ?? 0;
|
||||||
|
}
|
||||||
|
|
||||||
// 事件的处理
|
// 事件的处理
|
||||||
const todo: MotaEvent = [];
|
const todo: MotaEvent = [];
|
||||||
|
|
||||||
@ -231,7 +250,7 @@ declare global {
|
|||||||
interface Events {
|
interface Events {
|
||||||
battle(
|
battle(
|
||||||
enemy: DamageEnemy,
|
enemy: DamageEnemy,
|
||||||
_?: number,
|
y?: number,
|
||||||
force?: boolean,
|
force?: boolean,
|
||||||
callback?: () => void
|
callback?: () => void
|
||||||
): void;
|
): void;
|
||||||
|
@ -108,26 +108,10 @@ function renderThumbnailDamage(col: EnemyCollection) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// 电摇嘲讽
|
|
||||||
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 ? '↑' : '↓';
|
|
||||||
core.status.damage.extraData.push({
|
|
||||||
text: '嘲' + dir,
|
|
||||||
px: 32 * x + 16,
|
|
||||||
py: 32 * (y + 1) - 14,
|
|
||||||
color: '#fd4',
|
|
||||||
alpha: 1
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// 追猎
|
// 追猎
|
||||||
if (dam.hunt) {
|
if (dam.ambush) {
|
||||||
core.status.damage.extraData.push({
|
core.status.damage.extraData.push({
|
||||||
text: '猎',
|
text: '!',
|
||||||
px: 32 * x + 16,
|
px: 32 * x + 16,
|
||||||
py: 32 * (y + 1) - 14,
|
py: 32 * (y + 1) - 14,
|
||||||
color: '#fd4',
|
color: '#fd4',
|
||||||
|
@ -15,41 +15,6 @@ import {
|
|||||||
HaloType,
|
HaloType,
|
||||||
IEnemyCollectionEvent
|
IEnemyCollectionEvent
|
||||||
} from '@motajs/types';
|
} from '@motajs/types';
|
||||||
import { isNil } from 'lodash-es';
|
|
||||||
|
|
||||||
export interface UserEnemyInfo extends EnemyInfo {
|
|
||||||
togetherNum?: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** 光环属性 */
|
|
||||||
export const haloSpecials: Set<number> = new Set([
|
|
||||||
8, 21, 25, 26, 27, 29, 31, 32
|
|
||||||
]);
|
|
||||||
/** 不可被同化的属性 */
|
|
||||||
export const unassimilatable: Set<number> = new Set(haloSpecials);
|
|
||||||
unassimilatable.add(8).add(30).add(33);
|
|
||||||
/** 特殊属性对应 */
|
|
||||||
export const specialValue: Map<number, SelectKey<Enemy, number | undefined>[]> =
|
|
||||||
new Map();
|
|
||||||
specialValue
|
|
||||||
.set(1, ['crit'])
|
|
||||||
.set(6, ['n'])
|
|
||||||
.set(7, ['hungry'])
|
|
||||||
.set(8, ['together'])
|
|
||||||
.set(10, ['courage'])
|
|
||||||
.set(11, ['charge'])
|
|
||||||
.set(15, ['value'])
|
|
||||||
.set(18, ['value'])
|
|
||||||
.set(20, ['ice'])
|
|
||||||
.set(21, ['iceHalo'])
|
|
||||||
.set(22, ['night'])
|
|
||||||
.set(23, ['day'])
|
|
||||||
.set(25, ['melt'])
|
|
||||||
.set(26, ['iceCore'])
|
|
||||||
.set(27, ['fireCore'])
|
|
||||||
.set(28, ['paleShield'])
|
|
||||||
.set(31, ['hpHalo'])
|
|
||||||
.set(32, ['assimilateRange']);
|
|
||||||
|
|
||||||
export class EnemyCollection
|
export class EnemyCollection
|
||||||
extends EventEmitter<IEnemyCollectionEvent>
|
extends EventEmitter<IEnemyCollectionEvent>
|
||||||
@ -68,9 +33,6 @@ export class EnemyCollection
|
|||||||
/** 楼层高度 */
|
/** 楼层高度 */
|
||||||
height: number = 0;
|
height: number = 0;
|
||||||
|
|
||||||
/** 乾坤挪移属性 */
|
|
||||||
translation: [number, number] = [0, 0];
|
|
||||||
|
|
||||||
constructor(floorId: FloorIds) {
|
constructor(floorId: FloorIds) {
|
||||||
super();
|
super();
|
||||||
this.floorId = floorId;
|
this.floorId = floorId;
|
||||||
@ -111,7 +73,6 @@ export class EnemyCollection
|
|||||||
*/
|
*/
|
||||||
calRealAttribute() {
|
calRealAttribute() {
|
||||||
this.haloList = [];
|
this.haloList = [];
|
||||||
this.translation = [0, 0];
|
|
||||||
this.list.forEach(v => {
|
this.list.forEach(v => {
|
||||||
v.reset();
|
v.reset();
|
||||||
});
|
});
|
||||||
@ -204,7 +165,7 @@ export class DamageEnemy implements IDamageEnemy {
|
|||||||
* 属性计算流程:预平衡光环(即计算加光环的光环怪的光环) -> 计算怪物在没有光环下的属性
|
* 属性计算流程:预平衡光环(即计算加光环的光环怪的光环) -> 计算怪物在没有光环下的属性
|
||||||
* -> provide inject 光环 -> 计算怪物的光环加成 -> 计算完毕
|
* -> provide inject 光环 -> 计算怪物的光环加成 -> 计算完毕
|
||||||
*/
|
*/
|
||||||
info!: UserEnemyInfo;
|
info!: EnemyInfo;
|
||||||
|
|
||||||
/** 向其他怪提供过的光环 */
|
/** 向其他怪提供过的光环 */
|
||||||
providedHalo: Set<number> = new Set();
|
providedHalo: Set<number> = new Set();
|
||||||
@ -238,10 +199,10 @@ export class DamageEnemy implements IDamageEnemy {
|
|||||||
atk: enemy.atk,
|
atk: enemy.atk,
|
||||||
def: enemy.def,
|
def: enemy.def,
|
||||||
special: new Set(enemy.special),
|
special: new Set(enemy.special),
|
||||||
damageDecline: 0,
|
|
||||||
atkBuff_: 0,
|
atkBuff_: 0,
|
||||||
defBuff_: 0,
|
defBuff_: 0,
|
||||||
hpBuff_: 0,
|
hpBuff_: 0,
|
||||||
|
guard: [],
|
||||||
enemy: this.enemy,
|
enemy: this.enemy,
|
||||||
x: this.x,
|
x: this.x,
|
||||||
y: this.y,
|
y: this.y,
|
||||||
@ -256,12 +217,6 @@ export class DamageEnemy implements IDamageEnemy {
|
|||||||
}
|
}
|
||||||
this.progress = 0;
|
this.progress = 0;
|
||||||
this.providedHalo.clear();
|
this.providedHalo.clear();
|
||||||
|
|
||||||
// 在这里计算乾坤挪移
|
|
||||||
if (this.col && enemy.special.includes(30)) {
|
|
||||||
this.col.translation[0] += enemy.translation![0];
|
|
||||||
this.col.translation[1] += enemy.translation![1];
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -272,31 +227,18 @@ export class DamageEnemy implements IDamageEnemy {
|
|||||||
this.progress = 2;
|
this.progress = 2;
|
||||||
const special = this.info.special;
|
const special = this.info.special;
|
||||||
const info = this.info;
|
const info = this.info;
|
||||||
const floorId = this.floorId ?? core.status.floorId;
|
|
||||||
let [dx, dy] = [0, 0];
|
const { atk = 0, def = 0 } = getHeroStatusOn(realStatus);
|
||||||
const col = this.col ?? core.status.maps[this.floorId!]?.enemy;
|
|
||||||
if (col) {
|
// 坚固
|
||||||
[dx, dy] = col.translation;
|
if (special.has(3)) {
|
||||||
|
info.def = Math.max(info.def, atk - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 智慧之源
|
// 模仿
|
||||||
if (flags.hard === 2 && special.has(14)) {
|
if (special.has(10)) {
|
||||||
info.atk += flags[`inte_${floorId}`] ?? 0;
|
info.atk = atk;
|
||||||
}
|
info.def = def;
|
||||||
|
|
||||||
// 融化,融化不属于怪物光环,因此不能用provide和inject计算,需要在这里计算
|
|
||||||
const melt = flags[`melt_${floorId}`];
|
|
||||||
if (!isNil(melt) && !isNil(this.x) && !isNil(this.y)) {
|
|
||||||
for (const [loc, per] of Object.entries(melt)) {
|
|
||||||
const [mx, my] = loc.split(',').map(v => parseInt(v));
|
|
||||||
if (
|
|
||||||
Math.abs(mx + dx - this.x) <= 1 &&
|
|
||||||
Math.abs(my + dy - this.y) <= 1
|
|
||||||
) {
|
|
||||||
info.atkBuff_ += per as number;
|
|
||||||
info.defBuff_ += per as number;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -315,14 +257,6 @@ export class DamageEnemy implements IDamageEnemy {
|
|||||||
// 此时已经inject光环,因此直接计算真实属性
|
// 此时已经inject光环,因此直接计算真实属性
|
||||||
const info = this.info;
|
const info = this.info;
|
||||||
|
|
||||||
if (info.special.has(33)) {
|
|
||||||
const count = this.col?.list.size ?? 0;
|
|
||||||
const [hp, atk, def] = this.enemy.horn ?? [0, 0, 0];
|
|
||||||
info.hpBuff_ += hp * count;
|
|
||||||
info.atkBuff_ += atk * count;
|
|
||||||
info.defBuff_ += def * count;
|
|
||||||
}
|
|
||||||
|
|
||||||
info.atk = Math.floor(info.atk * (info.atkBuff_ / 100 + 1));
|
info.atk = Math.floor(info.atk * (info.atkBuff_ / 100 + 1));
|
||||||
info.def = Math.floor(info.def * (info.defBuff_ / 100 + 1));
|
info.def = Math.floor(info.def * (info.defBuff_ / 100 + 1));
|
||||||
info.hp = Math.floor(info.hp * (info.hpBuff_ / 100 + 1));
|
info.hp = Math.floor(info.hp * (info.hpBuff_ / 100 + 1));
|
||||||
@ -330,19 +264,6 @@ export class DamageEnemy implements IDamageEnemy {
|
|||||||
return this.info;
|
return this.info;
|
||||||
}
|
}
|
||||||
|
|
||||||
getHaloSpecials(): Set<number> {
|
|
||||||
if (!this.floorId) return new Set();
|
|
||||||
if (!has(this.x) || !has(this.y)) return new Set();
|
|
||||||
const special = this.info.special ?? this.enemy.special;
|
|
||||||
const res = new Set<number>();
|
|
||||||
special.forEach(v => {
|
|
||||||
if (haloSpecials.has(v) && !this.providedHalo.has(v)) {
|
|
||||||
res.add(v);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 光环预提供,用于平衡所有怪的光环属性,避免出现不同情况下光环效果不一致的现象
|
* 光环预提供,用于平衡所有怪的光环属性,避免出现不同情况下光环效果不一致的现象
|
||||||
*/
|
*/
|
||||||
@ -351,62 +272,10 @@ export class DamageEnemy implements IDamageEnemy {
|
|||||||
this.progress = 1;
|
this.progress = 1;
|
||||||
if (!this.floorId) return;
|
if (!this.floorId) return;
|
||||||
if (!has(this.x) || !has(this.y)) return;
|
if (!has(this.x) || !has(this.y)) return;
|
||||||
const special = this.getHaloSpecials();
|
|
||||||
const col = this.col ?? core.status.maps[this.floorId!].enemy;
|
// 这里可以做优先级更高的光环,比如加光环的光环怪等,写法与 provideHalo 类似
|
||||||
let [dx, dy] = [0, 0];
|
|
||||||
if (col) [dx, dy] = col.translation;
|
|
||||||
|
|
||||||
// e 是被加成怪的属性,enemy 是施加光环的怪
|
// e 是被加成怪的属性,enemy 是施加光环的怪
|
||||||
|
|
||||||
for (const halo of special) {
|
|
||||||
switch (halo) {
|
|
||||||
case 29: {
|
|
||||||
// 特殊光环
|
|
||||||
const e = this.enemy;
|
|
||||||
const type = 'square';
|
|
||||||
const r = Math.floor(e.haloRange!);
|
|
||||||
const d = r * 2 + 1;
|
|
||||||
const range = { x: this.x + dx, y: this.y + dy, d };
|
|
||||||
|
|
||||||
// 这一句必须放到applyHalo之前
|
|
||||||
this.providedHalo.add(29);
|
|
||||||
const halo = (e: UserEnemyInfo, enemy: UserEnemyInfo) => {
|
|
||||||
const s = enemy.specialHalo!;
|
|
||||||
|
|
||||||
for (const spe of s) {
|
|
||||||
e.special.add(spe);
|
|
||||||
}
|
|
||||||
// 如果是自身,就不进行特殊属性数值处理了
|
|
||||||
if (e === this.info) return;
|
|
||||||
// 然后计算特殊属性数值
|
|
||||||
for (const spec of s) {
|
|
||||||
// 如果目标怪物拥有杀戮光环,且光环会加成此属性,则忽略
|
|
||||||
if (e.specialHalo?.includes(spec)) continue;
|
|
||||||
const toChange = specialValue.get(spec);
|
|
||||||
if (!toChange) continue;
|
|
||||||
for (const key of toChange) {
|
|
||||||
// 这种光环应该获取怪物的原始数值,而不是真实数值
|
|
||||||
if (enemy.enemy.specialMultiply) {
|
|
||||||
e[key] ??= 1;
|
|
||||||
e[key] *= enemy[key] ?? 1;
|
|
||||||
} else {
|
|
||||||
e[key] ??= 0;
|
|
||||||
e[key] += enemy[key] ?? 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
col.applyHalo(type, range, this, halo, true);
|
|
||||||
col.haloList.push({
|
|
||||||
type: 'square',
|
|
||||||
data: { x: this.x + dx, y: this.y + dy, d },
|
|
||||||
special: 29,
|
|
||||||
from: this
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -419,159 +288,67 @@ export class DamageEnemy implements IDamageEnemy {
|
|||||||
if (!has(this.x) || !has(this.y)) return;
|
if (!has(this.x) || !has(this.y)) return;
|
||||||
const col = this.col ?? core.status.maps[this.floorId].enemy;
|
const col = this.col ?? core.status.maps[this.floorId].enemy;
|
||||||
if (!col) return;
|
if (!col) return;
|
||||||
const special = this.getHaloSpecials();
|
const special = this.info.special;
|
||||||
const [dx, dy] = col.translation;
|
|
||||||
|
|
||||||
const square7: HaloFn[] = [];
|
|
||||||
const square5: HaloFn[] = [];
|
|
||||||
|
|
||||||
// e 是被加成怪的属性,enemy 是施加光环的怪
|
// e 是被加成怪的属性,enemy 是施加光环的怪
|
||||||
|
|
||||||
// 抱团
|
// 普通光环
|
||||||
if (special.has(8)) {
|
if (special.has(25)) {
|
||||||
|
// 光环效果,这里直接增加 e 的 buff 属性
|
||||||
|
const halo = (e: EnemyInfo, enemy: EnemyInfo) => {
|
||||||
|
if (enemy.haloAdd) {
|
||||||
|
e.hpBuff_ += enemy.hpBuff ?? 0;
|
||||||
|
e.atkBuff_ += enemy.atkBuff ?? 0;
|
||||||
|
e.defBuff_ += enemy.defBuff ?? 0;
|
||||||
|
} else {
|
||||||
|
e.hpBuff_ = Math.max(e.hpBuff_, enemy.hpBuff ?? 0);
|
||||||
|
e.atkBuff_ = Math.max(e.atkBuff_, enemy.atkBuff ?? 0);
|
||||||
|
e.defBuff_ = Math.max(e.defBuff_, enemy.defBuff ?? 0);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
// 根据范围施加光环
|
||||||
|
const range = this.info.haloRange ?? 1;
|
||||||
|
if (this.info.haloSquare) {
|
||||||
|
col.applyHalo(
|
||||||
|
'square',
|
||||||
|
{ x: this.x, y: this.y, d: range * 2 + 1 },
|
||||||
|
this,
|
||||||
|
halo
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
col.applyHalo(
|
||||||
|
'manhattan',
|
||||||
|
{ x: this.x, y: this.y, d: range },
|
||||||
|
this,
|
||||||
|
halo
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 支援也是一类光环
|
||||||
|
if (special.has(26)) {
|
||||||
col.applyHalo(
|
col.applyHalo(
|
||||||
'square',
|
'square',
|
||||||
{ x: this.x, y: this.y, d: 5 },
|
{ x: this.x, y: this.y, d: 3 },
|
||||||
this,
|
this,
|
||||||
(e: UserEnemyInfo, enemy) => {
|
(e, enemy) => {
|
||||||
if (
|
e.guard.push(enemy);
|
||||||
e.special.has(8) &&
|
|
||||||
(e.x !== this.x || this.y !== e.y)
|
|
||||||
) {
|
|
||||||
e.atkBuff_ += enemy.together ?? 0;
|
|
||||||
e.defBuff_ += enemy.together ?? 0;
|
|
||||||
e.togetherNum ??= 0;
|
|
||||||
e.togetherNum++;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
this.providedHalo.add(8);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 冰封光环
|
|
||||||
if (special.has(21)) {
|
|
||||||
square7.push(e => {
|
|
||||||
e.damageDecline += this.info.iceHalo ?? 0;
|
|
||||||
});
|
|
||||||
this.providedHalo.add(21);
|
|
||||||
col.haloList.push({
|
|
||||||
type: 'square',
|
|
||||||
data: { x: this.x + dx, y: this.y + dy, d: 7 },
|
|
||||||
special: 21,
|
|
||||||
from: this
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// 冰封之核
|
|
||||||
if (special.has(26)) {
|
|
||||||
square5.push(e => {
|
|
||||||
e.defBuff_ += this.info.iceCore ?? 0;
|
|
||||||
});
|
|
||||||
this.providedHalo.add(26);
|
|
||||||
col.haloList.push({
|
|
||||||
type: 'square',
|
|
||||||
data: { x: this.x + dx, y: this.y + dy, d: 5 },
|
|
||||||
special: 26,
|
|
||||||
from: this
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// 火焰之核
|
|
||||||
if (special.has(27)) {
|
|
||||||
square5.push(e => {
|
|
||||||
e.atkBuff_ += this.info.fireCore ?? 0;
|
|
||||||
});
|
|
||||||
this.providedHalo.add(27);
|
|
||||||
col.haloList.push({
|
|
||||||
type: 'square',
|
|
||||||
data: { x: this.x + dx, y: this.y + dy, d: 5 },
|
|
||||||
special: 27,
|
|
||||||
from: this
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// 再生光环
|
|
||||||
if (special.has(31)) {
|
|
||||||
square7.push(e => {
|
|
||||||
e.hpBuff_ += this.info.hpHalo ?? 0;
|
|
||||||
});
|
|
||||||
this.providedHalo.add(31);
|
|
||||||
col.haloList.push({
|
|
||||||
type: 'square',
|
|
||||||
data: { x: this.x + dx, y: this.y + dy, d: 7 },
|
|
||||||
special: 31,
|
|
||||||
from: this
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// 同化,它不会被光环类属性影响,因此放到这
|
|
||||||
if (special.has(32)) {
|
|
||||||
const e = this.info;
|
|
||||||
const type = 'square';
|
|
||||||
const r = Math.floor(e.assimilateRange!);
|
|
||||||
const d = r * 2 + 1;
|
|
||||||
const range = { x: this.x, y: this.y, d };
|
|
||||||
|
|
||||||
col.applyHalo(type, range, this, (e, enemy) => {
|
|
||||||
// 如果是自身,就不进行特殊属性数值处理了
|
|
||||||
if (e === this.info) return;
|
|
||||||
const s = e.special;
|
|
||||||
|
|
||||||
for (const spe of s) {
|
|
||||||
if (unassimilatable.has(spe)) continue;
|
|
||||||
enemy.special.add(spe);
|
|
||||||
}
|
|
||||||
// 然后计算特殊属性数值
|
|
||||||
for (const spec of s) {
|
|
||||||
if (unassimilatable.has(spec)) continue;
|
|
||||||
const toChange = specialValue.get(spec);
|
|
||||||
if (!toChange) continue;
|
|
||||||
for (const key of toChange) {
|
|
||||||
// 这种光环应该获取怪物的原始数值,而不是真实数值
|
|
||||||
if (enemy.enemy.specialMultiply) {
|
|
||||||
enemy[key] ??= 1;
|
|
||||||
enemy[key] *= e[key] ?? 1;
|
|
||||||
} else {
|
|
||||||
enemy[key] ??= 0;
|
|
||||||
enemy[key] += e[key] ?? 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
col.haloList.push({
|
|
||||||
type: 'square',
|
|
||||||
data: range,
|
|
||||||
special: 32,
|
|
||||||
from: this
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
col.applyHalo(
|
|
||||||
'square',
|
|
||||||
{ x: this.x + dx, y: this.y + dy, d: 7 },
|
|
||||||
this,
|
|
||||||
square7
|
|
||||||
);
|
|
||||||
col.applyHalo(
|
|
||||||
'square',
|
|
||||||
{ x: this.x + dx, y: this.y + dy, d: 5 },
|
|
||||||
this,
|
|
||||||
square5
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 接受其他怪的光环
|
* 接受其他怪的光环
|
||||||
*/
|
*/
|
||||||
injectHalo(halo: HaloFn, enemy: UserEnemyInfo) {
|
injectHalo(halo: HaloFn, enemy: EnemyInfo) {
|
||||||
halo(this.info, enemy);
|
halo(this.info, enemy);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 计算怪物伤害
|
* 计算怪物伤害
|
||||||
*/
|
*/
|
||||||
calDamage(hero: Partial<HeroStatus> = core.status.hero) {
|
calDamage(hero: Partial<HeroStatus> = core.status.hero): DamageInfo {
|
||||||
const enemy = this.getRealInfo();
|
const enemy = this.getRealInfo();
|
||||||
return this.calEnemyDamageOf(hero, enemy);
|
return this.calEnemyDamageOf(hero, enemy);
|
||||||
}
|
}
|
||||||
@ -582,23 +359,23 @@ export class DamageEnemy implements IDamageEnemy {
|
|||||||
*/
|
*/
|
||||||
calMapDamage(
|
calMapDamage(
|
||||||
damage: Record<string, MapDamage> = {},
|
damage: Record<string, MapDamage> = {},
|
||||||
hero: Partial<HeroStatus> = getHeroStatusOn(realStatus)
|
_hero: Partial<HeroStatus> = getHeroStatusOn(realStatus)
|
||||||
) {
|
) {
|
||||||
if (!has(this.x) || !has(this.y) || !has(this.floorId)) return damage;
|
if (!has(this.x) || !has(this.y) || !has(this.floorId)) return damage;
|
||||||
const enemy = this.enemy;
|
const enemy = this.enemy;
|
||||||
const floor = core.status.maps[this.floorId];
|
const floor = core.status.maps[this.floorId];
|
||||||
const w = floor.width;
|
const w = floor.width;
|
||||||
const h = floor.height;
|
const h = floor.height;
|
||||||
|
const objs = core.getMapBlocksObj(this.floorId);
|
||||||
|
|
||||||
// 突刺
|
// 领域
|
||||||
if (this.info.special.has(15)) {
|
if (this.info.special.has(15)) {
|
||||||
const range = enemy.range ?? 1;
|
const range = enemy.range ?? 1;
|
||||||
const startX = Math.max(0, this.x - range);
|
const startX = Math.max(0, this.x - range);
|
||||||
const startY = Math.max(0, this.y - range);
|
const startY = Math.max(0, this.y - range);
|
||||||
const endX = Math.min(floor.width - 1, this.x + range);
|
const endX = Math.min(floor.width - 1, this.x + range);
|
||||||
const endY = Math.min(floor.height - 1, this.y + 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);
|
||||||
const objs = core.getMapBlocksObj(this.floorId);
|
|
||||||
|
|
||||||
for (let x = startX; x <= endX; x++) {
|
for (let x = startX; x <= endX; x++) {
|
||||||
for (let y = startY; y <= endY; y++) {
|
for (let y = startY; y <= endY; y++) {
|
||||||
@ -606,20 +383,20 @@ export class DamageEnemy implements IDamageEnemy {
|
|||||||
!enemy.zoneSquare &&
|
!enemy.zoneSquare &&
|
||||||
manhattan(x, y, this.x, this.y) > range
|
manhattan(x, y, this.x, this.y) > range
|
||||||
) {
|
) {
|
||||||
|
// 如果是十字范围而且曼哈顿距离大于范围,则跳过此格
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
const loc = `${x},${y}` as LocString;
|
const loc = `${x},${y}` as LocString;
|
||||||
if (objs[loc]?.event.noPass) continue;
|
if (objs[loc]?.event.noPass) continue;
|
||||||
this.setMapDamage(damage, loc, dam, '突刺');
|
this.setMapDamage(damage, loc, dam, '领域');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 射击
|
// 激光
|
||||||
if (this.info.special.has(24)) {
|
if (this.info.special.has(24)) {
|
||||||
const dirs: Dir[] = ['left', 'down', 'up', 'right'];
|
const dirs: Dir[] = ['left', 'down', 'up', 'right'];
|
||||||
const dam = Math.max((enemy.atk ?? 0) - hero.def!, 0);
|
const dam = Math.max(enemy.laser ?? 0, 0);
|
||||||
const objs = core.getMapBlocksObj(this.floorId);
|
|
||||||
|
|
||||||
for (const dir of dirs) {
|
for (const dir of dirs) {
|
||||||
let x = this.x;
|
let x = this.x;
|
||||||
@ -629,70 +406,67 @@ export class DamageEnemy implements IDamageEnemy {
|
|||||||
x += dx;
|
x += dx;
|
||||||
y += dy;
|
y += dy;
|
||||||
const loc = `${x},${y}` as LocString;
|
const loc = `${x},${y}` as LocString;
|
||||||
const block = objs[loc];
|
if (objs[loc]?.event.noPass) continue;
|
||||||
if (
|
this.setMapDamage(damage, loc, dam, '激光');
|
||||||
block &&
|
|
||||||
block.event.noPass &&
|
|
||||||
block.event.cls !== 'enemys'
|
|
||||||
) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
this.setMapDamage(damage, loc, dam, '射击');
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 电摇嘲讽
|
// 阻击
|
||||||
if (this.info.special.has(19)) {
|
if (this.info.special.has(18)) {
|
||||||
const objs = core.getMapBlocksObj(this.floorId);
|
const dirs: Dir[] = ['left', 'down', 'up', 'right'];
|
||||||
for (let nx = 0; nx < w; nx++) {
|
for (const dir of dirs) {
|
||||||
const loc = `${nx},${this.y}` as LocString;
|
const { x: dx, y: dy } = core.utils.scan[dir];
|
||||||
const block = objs[loc];
|
const x = this.x + dx;
|
||||||
if (!block?.event.noPass) {
|
const y = this.y + dy;
|
||||||
damage[loc] ??= { damage: 0, type: new Set() };
|
const loc = `${x},${y}` as LocString;
|
||||||
damage[loc].mockery ??= [];
|
if (objs[loc]?.event.noPass) continue;
|
||||||
damage[loc].mockery!.push([this.x, this.y]);
|
this.setMapDamage(damage, loc, this.info.repulse ?? 0, '阻击');
|
||||||
}
|
damage[loc].repulse ??= [];
|
||||||
}
|
damage[loc].repulse.push([this.x, this.y]);
|
||||||
for (let ny = 0; ny < h; ny++) {
|
|
||||||
const loc = `${this.x},${ny}` as LocString;
|
|
||||||
const block = objs[loc];
|
|
||||||
if (!block?.event.noPass) {
|
|
||||||
damage[loc] ??= { damage: 0, type: new Set() };
|
|
||||||
damage[loc].mockery ??= [];
|
|
||||||
damage[loc].mockery!.push([this.x, this.y]);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 追猎
|
// 捕捉
|
||||||
if (this.info.special.has(12)) {
|
if (this.info.special.has(27)) {
|
||||||
const objs = core.getMapBlocksObj(this.floorId);
|
const dirs: Dir[] = ['left', 'down', 'up', 'right'];
|
||||||
for (let nx = 0; nx < w; nx++) {
|
for (const dir of dirs) {
|
||||||
const loc = `${nx},${this.y}` as LocString;
|
const { x: dx, y: dy } = core.utils.scan[dir];
|
||||||
const block = objs[loc];
|
const x = this.x + dx;
|
||||||
if (!block?.event.noPass) {
|
const y = this.y + dy;
|
||||||
damage[loc] ??= { damage: 0, type: new Set() };
|
const loc = `${x},${y}` as LocString;
|
||||||
damage[loc].hunt ??= [];
|
if (objs[loc]?.event.noPass) continue;
|
||||||
damage[loc].hunt!.push([
|
damage[loc] ??= { damage: 0, type: new Set() };
|
||||||
this.x,
|
damage[loc].ambush ??= [];
|
||||||
this.y,
|
damage[loc].ambush.push([this.x, this.y]);
|
||||||
nx < this.x ? 'left' : 'right'
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
for (let ny = 0; ny < h; ny++) {
|
}
|
||||||
const loc = `${this.x},${ny}` as LocString;
|
|
||||||
const block = objs[loc];
|
// 夹击
|
||||||
if (!block?.event.noPass) {
|
if (this.info.special.has(16)) {
|
||||||
damage[loc] ??= { damage: 0, type: new Set() };
|
// 只计算右方和下方的怪物,这样就可以避免一个点被重复计算两次
|
||||||
damage[loc].hunt ??= [];
|
const dirs: Dir[] = ['down', 'right'];
|
||||||
damage[loc].hunt!.push([
|
for (const dir of dirs) {
|
||||||
this.x,
|
const { x: dx, y: dy } = core.utils.scan[dir];
|
||||||
this.y,
|
const x = this.x + dx * 2;
|
||||||
ny < this.y ? 'up' : 'down'
|
const y = this.y + dy * 2;
|
||||||
]);
|
const e = this.col?.get(x, y);
|
||||||
|
if (!e) continue;
|
||||||
|
const info = e.getRealInfo();
|
||||||
|
if (!info.special.has(16)) continue;
|
||||||
|
const cx = this.x + dx;
|
||||||
|
const cy = this.y + dy;
|
||||||
|
const loc = `${cx},${cy}` as LocString;
|
||||||
|
if (objs[loc]?.event.noPass) continue;
|
||||||
|
const half = getHeroStatusOn('hp') / 2;
|
||||||
|
let bt = half;
|
||||||
|
// 夹击不超伤害值
|
||||||
|
if (core.flags.betweenAttackMax) {
|
||||||
|
const aDamage = this.calDamage().damage;
|
||||||
|
const bDamage = e.calDamage().damage;
|
||||||
|
bt = Math.min(aDamage, bDamage, half);
|
||||||
}
|
}
|
||||||
|
this.setMapDamage(damage, loc, bt, '夹击');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -710,7 +484,10 @@ export class DamageEnemy implements IDamageEnemy {
|
|||||||
if (type) damage[loc].type.add(type);
|
if (type) damage[loc].type.add(type);
|
||||||
}
|
}
|
||||||
|
|
||||||
private calEnemyDamageOf(hero: Partial<HeroStatus>, enemy: UserEnemyInfo) {
|
private calEnemyDamageOf(
|
||||||
|
hero: Partial<HeroStatus>,
|
||||||
|
enemy: EnemyInfo
|
||||||
|
): DamageInfo {
|
||||||
const status = getHeroStatusOf(hero, realStatus, this.floorId);
|
const status = getHeroStatusOf(hero, realStatus, this.floorId);
|
||||||
const damage = calDamageWith(enemy, status) ?? Infinity;
|
const damage = calDamageWith(enemy, status) ?? Infinity;
|
||||||
|
|
||||||
@ -849,118 +626,75 @@ export class DamageEnemy implements IDamageEnemy {
|
|||||||
*/
|
*/
|
||||||
getSeckillAtk(): number {
|
getSeckillAtk(): number {
|
||||||
const info = this.getRealInfo();
|
const info = this.getRealInfo();
|
||||||
const add = info.def + info.hp - core.status.hero.mana;
|
|
||||||
|
|
||||||
// 坚固,不可能通过攻击秒杀
|
// 坚固,不可能通过攻击秒杀
|
||||||
if (info.special.has(3)) {
|
if (info.special.has(3)) {
|
||||||
return Infinity;
|
return Infinity;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 列方程求解,拿笔算一下就知道了
|
// 常规怪物秒杀攻击是怪物防御+怪物生命
|
||||||
// 饥渴,会偷取勇士攻击
|
return info.def + info.hp;
|
||||||
if (info.special.has(7)) {
|
|
||||||
if (info.damageDecline === 0) {
|
|
||||||
return add / (1 - this.enemy.hungry! / 100);
|
|
||||||
} else {
|
|
||||||
return (
|
|
||||||
(info.hp / (1 - info.damageDecline / 100) -
|
|
||||||
core.status.hero.mana +
|
|
||||||
info.def) /
|
|
||||||
(1 - this.enemy.hungry! / 100)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 霜冻
|
|
||||||
if (info.special.has(20)) {
|
|
||||||
return (
|
|
||||||
info.def +
|
|
||||||
info.hp / (1 - this.enemy.ice! / 100) -
|
|
||||||
core.status.hero.mana
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (info.damageDecline !== 0) {
|
|
||||||
return (
|
|
||||||
info.def +
|
|
||||||
info.hp / (1 - info.damageDecline / 100) -
|
|
||||||
core.status.hero.mana
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
return add;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface DamageWithTurn {
|
||||||
|
damage: number;
|
||||||
|
turn: number;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 计算伤害时会用到的勇士属性,攻击防御,其余的不会有buff加成,直接从core.status.hero取
|
* 计算伤害时会用到的勇士属性,攻击防御,其余的不会有buff加成,直接从core.status.hero取
|
||||||
|
* 如果有属性不会被 buff 加成请在这里去除,有助于提高性能表现
|
||||||
*/
|
*/
|
||||||
const realStatus: (keyof HeroStatus)[] = [
|
const realStatus: (keyof HeroStatus)[] = ['atk', 'def', 'mdef', 'hpmax'];
|
||||||
'atk',
|
|
||||||
'def',
|
/** 当前是否正在计算支援怪的伤害 */
|
||||||
'hpmax',
|
let inGuard = false;
|
||||||
'mana',
|
|
||||||
'magicDef'
|
|
||||||
];
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 计算怪物伤害
|
* 计算伤害,返回值包含伤害与回合数
|
||||||
* @param info 怪物信息
|
* @param info 怪物信息
|
||||||
* @param hero 勇士信息
|
* @param hero 勇士真实属性
|
||||||
*/
|
*/
|
||||||
export function calDamageWith(
|
export function calDamageWithTurn(
|
||||||
info: UserEnemyInfo,
|
info: EnemyInfo,
|
||||||
hero: Partial<HeroStatus>
|
hero: Partial<HeroStatus>
|
||||||
): number {
|
): DamageWithTurn {
|
||||||
const { mdef } = core.status.hero;
|
const { hp } = core.status.hero;
|
||||||
const { def, mana, magicDef } = hero as HeroStatus;
|
const { atk, def, mdef } = hero as HeroStatus;
|
||||||
const { hp: monHp, def: monDef, special, enemy } = info;
|
const { atk: monAtk, def: monDef, special } = info;
|
||||||
let { atk, hpmax } = hero as HeroStatus;
|
let { hp: monHp } = info;
|
||||||
let { atk: monAtk } = info;
|
|
||||||
|
|
||||||
// 赏金,优先级最高
|
// 无敌
|
||||||
if (special.has(34)) return 0;
|
if (special.has(20) && core.itemCount('cross') < 1) {
|
||||||
|
return { damage: Infinity, turn: 0 };
|
||||||
hpmax = Math.min(hpmax, def / 10);
|
}
|
||||||
|
|
||||||
|
/** 怪物会对勇士造成的总伤害 */
|
||||||
let damage = 0;
|
let damage = 0;
|
||||||
|
|
||||||
// 饥渴
|
/** 勇士每轮造成的伤害 */
|
||||||
if (special.has(7)) {
|
let heroPerDamage: number = 0;
|
||||||
const delta = Math.floor((atk * info.hungry!) / 100);
|
/** 怪物每轮造成的伤害 */
|
||||||
atk -= delta;
|
let enemyPerDamage: number = 0;
|
||||||
monAtk += delta;
|
|
||||||
|
// 勇士每轮伤害为勇士攻击减去怪物防御
|
||||||
|
heroPerDamage += atk - monDef;
|
||||||
|
|
||||||
|
// 吸血
|
||||||
|
if (special.has(11)) {
|
||||||
|
const vampire = info.vampire ?? 0;
|
||||||
|
const value = (vampire / 100) * hp;
|
||||||
|
damage += value;
|
||||||
|
// 如果吸血加到自身
|
||||||
|
if (info.add) {
|
||||||
|
monHp += value;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let heroPerDamage: number;
|
|
||||||
|
|
||||||
// 绝对防御
|
|
||||||
if (special.has(9)) {
|
|
||||||
heroPerDamage = atk + mana - monDef;
|
|
||||||
if (heroPerDamage <= 0) return Infinity;
|
|
||||||
} else if (special.has(3)) {
|
|
||||||
// 由于坚固的特性,只能放到这来计算了
|
|
||||||
if (atk > enemy.def) heroPerDamage = 1 + mana;
|
|
||||||
else return Infinity;
|
|
||||||
} else {
|
|
||||||
heroPerDamage = atk - monDef;
|
|
||||||
if (heroPerDamage > 0) heroPerDamage += mana;
|
|
||||||
else return Infinity;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 霜冻
|
|
||||||
if (special.has(20)) {
|
|
||||||
heroPerDamage *= 1 - info.ice! / 100;
|
|
||||||
}
|
|
||||||
|
|
||||||
heroPerDamage *= 1 - info.damageDecline / 100;
|
|
||||||
|
|
||||||
let enemyPerDamage: number;
|
|
||||||
|
|
||||||
// 魔攻
|
// 魔攻
|
||||||
if (special.has(2) || special.has(13)) {
|
if (special.has(2)) {
|
||||||
enemyPerDamage = monAtk;
|
enemyPerDamage = monAtk;
|
||||||
enemyPerDamage -= magicDef;
|
|
||||||
} else {
|
} else {
|
||||||
enemyPerDamage = monAtk - def;
|
enemyPerDamage = monAtk - def;
|
||||||
}
|
}
|
||||||
@ -972,50 +706,81 @@ export function calDamageWith(
|
|||||||
|
|
||||||
if (enemyPerDamage < 0) enemyPerDamage = 0;
|
if (enemyPerDamage < 0) enemyPerDamage = 0;
|
||||||
|
|
||||||
// 苍蓝刻
|
|
||||||
if (special.has(28)) {
|
|
||||||
heroPerDamage *= 1 - info.paleShield! / 100;
|
|
||||||
}
|
|
||||||
|
|
||||||
let turn = Math.ceil(monHp / heroPerDamage);
|
let turn = Math.ceil(monHp / heroPerDamage);
|
||||||
|
|
||||||
// 致命一击
|
// 支援,当怪物被支援且不包含支援标记时执行,因为支援怪不能再被支援了
|
||||||
if (special.has(1)) {
|
if (info.guard.length > 0 && !inGuard) {
|
||||||
const times = Math.floor(turn / 5);
|
inGuard = true;
|
||||||
damage += ((times * (info.crit! - 100)) / 100) * enemyPerDamage;
|
// 支援中魔防只会被计算一次,因此除了当前怪物,计算其他怪物伤害时魔防为 0
|
||||||
}
|
const status = { ...hero, mdef: 0 };
|
||||||
|
// 计算支援怪的伤害,同时把打支援怪花费的回合数加到当前怪物上,因为打支援怪的时候当前怪物也会打你
|
||||||
// 勇气之刃
|
// 因此回合数需要加上打支援怪的回合数
|
||||||
if (turn > 1 && special.has(10)) {
|
for (const enemy of info.guard) {
|
||||||
damage += (info.courage! / 100 - 1) * enemyPerDamage;
|
// 直接把 enemy 传过去,因此支援的 enemy 会吃到其原本所在位置的光环加成
|
||||||
}
|
const extraInfo = calDamageWithTurn(enemy, status);
|
||||||
|
turn += extraInfo.turn;
|
||||||
// 勇气冲锋
|
damage += extraInfo.damage;
|
||||||
if (special.has(11)) {
|
}
|
||||||
damage += (info.charge! / 100) * enemyPerDamage;
|
inGuard = false;
|
||||||
turn += 5;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 先攻
|
// 先攻
|
||||||
if (special.has(17)) {
|
if (special.has(1)) {
|
||||||
damage += enemyPerDamage;
|
damage += enemyPerDamage;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 破甲
|
||||||
|
if (special.has(7)) {
|
||||||
|
const value = info.breakArmor ?? core.values.breakArmor;
|
||||||
|
damage += (value / 100) * def;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 反击
|
||||||
|
if (special.has(8)) {
|
||||||
|
const value = info.counterAttack ?? core.values.counterAttack;
|
||||||
|
// 反击是每回合生效,因此加到 enemyPerDamage 上
|
||||||
|
enemyPerDamage += (value / 100) * atk;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 净化
|
||||||
|
if (special.has(9)) {
|
||||||
|
const value = info.purify ?? core.values.purify;
|
||||||
|
damage += mdef * value;
|
||||||
|
}
|
||||||
|
|
||||||
damage += (turn - 1) * enemyPerDamage;
|
damage += (turn - 1) * enemyPerDamage;
|
||||||
// 无上之盾
|
|
||||||
if (flags.superSheild) {
|
|
||||||
damage -= mdef / 10;
|
|
||||||
}
|
|
||||||
// 生命回复
|
|
||||||
damage -= hpmax * turn;
|
|
||||||
if (flags.hard === 1) damage *= 0.9;
|
|
||||||
|
|
||||||
if (flags.chapter > 1 && damage < 0) {
|
// 魔防
|
||||||
const dm = -info.hp * 0.25;
|
damage -= mdef;
|
||||||
if (damage < dm) damage = dm;
|
|
||||||
|
// 未开启负伤时,如果伤害为负,则设为 0
|
||||||
|
if (!core.flags.enableNegativeDamage && damage < 0) {
|
||||||
|
damage = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
return Math.floor(damage);
|
// 固伤,无法被魔防减伤
|
||||||
|
if (special.has(22)) {
|
||||||
|
damage += info.damage ?? 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 仇恨,无法被魔防减伤
|
||||||
|
if (special.has(17)) {
|
||||||
|
damage += core.getFlag('hatred', 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
return { damage: Math.floor(damage), turn };
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 计算怪物伤害
|
||||||
|
* @param info 怪物信息
|
||||||
|
* @param hero 勇士信息
|
||||||
|
*/
|
||||||
|
export function calDamageWith(
|
||||||
|
info: EnemyInfo,
|
||||||
|
hero: Partial<HeroStatus>
|
||||||
|
): number {
|
||||||
|
return calDamageWithTurn(info, hero).damage;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function ensureFloorDamage(floorId: FloorIds) {
|
export function ensureFloorDamage(floorId: FloorIds) {
|
||||||
|
@ -1,13 +1,26 @@
|
|||||||
|
import { EnemyInfo } from '@motajs/types';
|
||||||
import { getHeroStatusOn } from '../state/hero';
|
import { getHeroStatusOn } from '../state/hero';
|
||||||
import { UserEnemyInfo } from './damage';
|
|
||||||
|
|
||||||
export interface SpecialDeclaration {
|
export interface SpecialDeclaration {
|
||||||
code: number;
|
code: number;
|
||||||
name: string | ((enemy: UserEnemyInfo) => string);
|
name: string | ((enemy: EnemyInfo) => string);
|
||||||
desc: string | ((enemy: UserEnemyInfo) => string);
|
desc: string | ((enemy: EnemyInfo) => string);
|
||||||
color: string;
|
color: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 怪物特殊属性列表,当前版本中 code 最好与索引保持一致,不然可能会出现问题
|
||||||
|
* 属性实现位置一览('./'表示当前文件夹 '../'表示上一级文件夹):
|
||||||
|
* 1. 调参类属性 / 仅影响战斗过程的属性:./damage.ts calDamageWithTurn 函数
|
||||||
|
* 2. 地图伤害:./damage.ts DamageEnemy.calMapDamage 方法,搜索 calMapDamage 即可搜到
|
||||||
|
* 3. 光环属性:./damage.ts DamageEnemy.provideHalo 方法,搜索 provideHalo 即可搜到
|
||||||
|
* 4. 仇恨 / 退化 等战后效果:packages-user/data-fallback/src/battle.ts 中的 afterBattle
|
||||||
|
* 5. 中毒的每步效果:../state/move.ts HeroMover.onStepEnd 方法,在约 590 行
|
||||||
|
* 6. 中毒的瞬移效果:还在脚本编辑的 moveDirectly
|
||||||
|
* 7. 衰弱效果:../state/hero.ts getHeroStatusOf 方法
|
||||||
|
* 8. 重生属性:还在脚本编辑的 changingFloor
|
||||||
|
* 9. 阻击 / 捕捉 的每步效果:packages-user/legacy-plugin-data/src/enemy/checkblock.ts
|
||||||
|
*/
|
||||||
export const specials: SpecialDeclaration[] = [
|
export const specials: SpecialDeclaration[] = [
|
||||||
{
|
{
|
||||||
code: 0,
|
code: 0,
|
||||||
@ -48,7 +61,7 @@ export const specials: SpecialDeclaration[] = [
|
|||||||
{
|
{
|
||||||
code: 6,
|
code: 6,
|
||||||
name: enemy => `${enemy.n ?? 4}连击`,
|
name: enemy => `${enemy.n ?? 4}连击`,
|
||||||
desc: enemy => `怪物每回合攻击${enemy.n}次。`,
|
desc: enemy => `怪物每回合攻击${enemy.n ?? 4}次。`,
|
||||||
color: '#fe7'
|
color: '#fe7'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -82,7 +95,7 @@ export const specials: SpecialDeclaration[] = [
|
|||||||
code: 11,
|
code: 11,
|
||||||
name: '吸血',
|
name: '吸血',
|
||||||
desc: enemy => {
|
desc: enemy => {
|
||||||
const vampire = enemy.vampire ?? 10;
|
const vampire = enemy.vampire ?? 0;
|
||||||
return (
|
return (
|
||||||
`战斗前,怪物首先吸取角色的${vampire}%生命` +
|
`战斗前,怪物首先吸取角色的${vampire}%生命` +
|
||||||
`(约${Math.floor((vampire / 100) * getHeroStatusOn('hp'))}点)作为伤害` +
|
`(约${Math.floor((vampire / 100) * getHeroStatusOn('hp'))}点)作为伤害` +
|
||||||
@ -101,7 +114,14 @@ export const specials: SpecialDeclaration[] = [
|
|||||||
{
|
{
|
||||||
code: 13,
|
code: 13,
|
||||||
name: '衰弱',
|
name: '衰弱',
|
||||||
desc: '怪物攻击无视勇士的防御。',
|
desc: () => {
|
||||||
|
const weak = core.values.weakValue;
|
||||||
|
if (weak < 1) {
|
||||||
|
return `战斗后,角色陷入衰弱状态,攻防暂时下降${Math.floor(weak * 100)}%`;
|
||||||
|
} else {
|
||||||
|
return `战斗后,角色陷入衰弱状态,攻防暂时下降${weak}点`;
|
||||||
|
}
|
||||||
|
},
|
||||||
color: '#f0bbcc'
|
color: '#f0bbcc'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -114,7 +134,7 @@ export const specials: SpecialDeclaration[] = [
|
|||||||
code: 15,
|
code: 15,
|
||||||
name: '领域',
|
name: '领域',
|
||||||
desc: enemy =>
|
desc: enemy =>
|
||||||
`经过怪物周围${enemy.zoneSquare ? '九宫格' : '十字'}范围内${enemy.range}格时自动减生命${enemy.zone}点。`,
|
`经过怪物周围${enemy.zoneSquare ? '九宫格' : '十字'}范围内${enemy.range ?? 1}格时自动减生命${enemy.zone ?? 0}点。`,
|
||||||
color: '#c677dd'
|
color: '#c677dd'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -126,14 +146,15 @@ export const specials: SpecialDeclaration[] = [
|
|||||||
{
|
{
|
||||||
code: 17,
|
code: 17,
|
||||||
name: '仇恨',
|
name: '仇恨',
|
||||||
desc: `战斗前,怪物附加之前积累的仇恨值作为伤害;战斗后,释放一半的仇恨值。(每杀死一个怪物获得${core.values.hatred}点仇恨值)。`,
|
desc: () =>
|
||||||
|
`战斗前,怪物附加之前积累的仇恨值作为伤害;战斗后,释放一半的仇恨值。(每杀死一个怪物获得${core.values.hatred}点仇恨值)。`,
|
||||||
color: '#b0b666'
|
color: '#b0b666'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
code: 18,
|
code: 18,
|
||||||
name: '阻击',
|
name: '阻击',
|
||||||
desc: enemy =>
|
desc: enemy =>
|
||||||
`经过怪物十字范围内时怪物后退一格,同时对勇士造成${enemy.repulse}点伤害。`,
|
`经过怪物十字范围内时怪物后退一格,同时对勇士造成${enemy.repulse ?? 0}点伤害。`,
|
||||||
color: '#8888e6'
|
color: '#8888e6'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -193,7 +214,7 @@ export const specials: SpecialDeclaration[] = [
|
|||||||
str += `,生命提升${enemy.hpBuff}%`;
|
str += `,生命提升${enemy.hpBuff}%`;
|
||||||
}
|
}
|
||||||
if (enemy.atkBuff) {
|
if (enemy.atkBuff) {
|
||||||
str += `,攻击提升${enemy.hpBuff}%`;
|
str += `,攻击提升${enemy.atkBuff}%`;
|
||||||
}
|
}
|
||||||
if (enemy.defBuff) {
|
if (enemy.defBuff) {
|
||||||
str += `,防御提升${enemy.defBuff}%`;
|
str += `,防御提升${enemy.defBuff}%`;
|
||||||
|
@ -20,7 +20,7 @@ export function getHeroStatusOn(
|
|||||||
name: keyof HeroStatus | 'all' | (keyof HeroStatus)[],
|
name: keyof HeroStatus | 'all' | (keyof HeroStatus)[],
|
||||||
floorId?: FloorIds
|
floorId?: FloorIds
|
||||||
) {
|
) {
|
||||||
// @ts-ignore
|
// @ts-expect-error 暂时无法推导
|
||||||
return getHeroStatusOf(core.status.hero, name, floorId);
|
return getHeroStatusOf(core.status.hero, name, floorId);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -96,9 +96,22 @@ function getRealStatus(
|
|||||||
s *= core.status.hero.buff[name] ?? 1;
|
s *= core.status.hero.buff[name] ?? 1;
|
||||||
s = Math.floor(s);
|
s = Math.floor(s);
|
||||||
|
|
||||||
|
// 衰弱效果
|
||||||
|
if ((name === 'atk' || name === 'def') && flags.weak) {
|
||||||
|
const weak = core.values.weakValue;
|
||||||
|
if (weak < 1) {
|
||||||
|
// 百分比衰弱
|
||||||
|
s *= 1 - weak;
|
||||||
|
} else {
|
||||||
|
s -= weak;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 下面的内容暂时无用
|
||||||
|
|
||||||
export interface IHeroStatusDefault {
|
export interface IHeroStatusDefault {
|
||||||
atk: number;
|
atk: number;
|
||||||
def: number;
|
def: number;
|
||||||
@ -224,7 +237,7 @@ export class HeroState<
|
|||||||
refreshStatus(key?: keyof T): boolean {
|
refreshStatus(key?: keyof T): boolean {
|
||||||
if (key === void 0) {
|
if (key === void 0) {
|
||||||
for (const [key, value] of Object.entries(this.status)) {
|
for (const [key, value] of Object.entries(this.status)) {
|
||||||
// @ts-ignore
|
// @ts-expect-error 暂时无法推导
|
||||||
this.computedStatus[key] = HeroState.cal(this, key, value);
|
this.computedStatus[key] = HeroState.cal(this, key, value);
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
@ -257,7 +270,7 @@ export class HeroState<
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
interface IHeroItem {
|
interface _IHeroItem {
|
||||||
items: Map<AllIdsOf<'items'>, number>;
|
items: Map<AllIdsOf<'items'>, number>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -459,10 +459,11 @@ export class HeroMover extends ObjectMoverBase {
|
|||||||
const map = core.status.thisMap.enemy.mapDamage;
|
const map = core.status.thisMap.enemy.mapDamage;
|
||||||
const dam = map[index];
|
const dam = map[index];
|
||||||
const nextDam = map[nIndex];
|
const nextDam = map[nIndex];
|
||||||
if (nextDam?.mockery || (!dam?.hunt && nextDam?.hunt)) {
|
if (!dam || !nextDam) return;
|
||||||
core.autosave();
|
// 可以在这里判断地图伤害,并进行自动存档,例如在进入或离开地图伤害时存档
|
||||||
return true;
|
// if (dam.damage > 0 || nextDam.damage > 0) {
|
||||||
}
|
// core.autosave()
|
||||||
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
protected async onMoveStart(controller: IMoveController): Promise<void> {
|
protected async onMoveStart(controller: IMoveController): Promise<void> {
|
||||||
@ -586,6 +587,12 @@ export class HeroMover extends ObjectMoverBase {
|
|||||||
core.control._moveAction_popAutomaticRoute();
|
core.control._moveAction_popAutomaticRoute();
|
||||||
if (!this.noRoute) core.status.route.push(direction);
|
if (!this.noRoute) core.status.route.push(direction);
|
||||||
|
|
||||||
|
// 中毒处理
|
||||||
|
if (core.hasFlag('poison')) {
|
||||||
|
core.status.hero.hp -= core.values.poisonDamage;
|
||||||
|
core.updateStatusBar();
|
||||||
|
}
|
||||||
|
|
||||||
core.moveOneStep();
|
core.moveOneStep();
|
||||||
core.checkRouteFolding();
|
core.checkRouteFolding();
|
||||||
}
|
}
|
||||||
|
@ -3,6 +3,7 @@ import { isNil } from 'lodash-es';
|
|||||||
interface RangeTypeData {
|
interface RangeTypeData {
|
||||||
square: { x: number; y: number; d: number };
|
square: { x: number; y: number; d: number };
|
||||||
rect: { x: number; y: number; w: number; h: number };
|
rect: { x: number; y: number; w: number; h: number };
|
||||||
|
manhattan: { x: number; y: number; d: number };
|
||||||
}
|
}
|
||||||
|
|
||||||
type InRangeFn<E extends Partial<Loc>, T> = (item: E, data: T) => boolean;
|
type InRangeFn<E extends Partial<Loc>, T> = (item: E, data: T) => boolean;
|
||||||
@ -79,3 +80,7 @@ Range.register('rect', (item, { x, y, w, h }) => {
|
|||||||
const ey = y + h;
|
const ey = y + h;
|
||||||
return item.x >= x && item.y >= y && item.x < ex && item.y < ey;
|
return item.x >= x && item.y >= y && item.x < ex && item.y < ey;
|
||||||
});
|
});
|
||||||
|
Range.register('manhattan', (item, { x, y, d }) => {
|
||||||
|
if (isNil(item.x) || isNil(item.y)) return false;
|
||||||
|
return Math.abs(item.x - x) + Math.abs(item.y - y) < d;
|
||||||
|
});
|
||||||
|
@ -168,12 +168,12 @@ export function boundary(arr: any, key?: any) {
|
|||||||
* @param from 初始坐标
|
* @param from 初始坐标
|
||||||
* @param to 指向坐标
|
* @param to 指向坐标
|
||||||
*/
|
*/
|
||||||
export function findDir(from: Loc, to: Loc): Dir2 | 'none' {
|
export function findDir(from: Loc, to: Loc): Dir | 'none' {
|
||||||
const dx = to.x - from.x;
|
const dx = Math.sign(to.x - from.x);
|
||||||
const dy = to.y - from.y;
|
const dy = Math.sign(to.y - from.y);
|
||||||
return (
|
return (
|
||||||
(Object.entries(core.utils.scan2).find(v => {
|
(Object.entries(core.utils.scan).find(v => {
|
||||||
v[1].x === dx && v[1].y === dy;
|
return v[1].x === dx && v[1].y === dy;
|
||||||
})?.[0] as Dir2) ?? 'none'
|
})?.[0] as Dir) ?? 'none'
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -1,12 +1,18 @@
|
|||||||
|
import { DamageEnemy } from '@user/data-state';
|
||||||
|
import { findDir, ofDir } from '@user/data-utils';
|
||||||
|
|
||||||
export function createCheckBlock() {
|
export function createCheckBlock() {
|
||||||
// 伤害弹出
|
// 地图伤害在这实现。2.C 会修改实现方式
|
||||||
// 复写阻激夹域检测
|
|
||||||
control.prototype.checkBlock = function () {
|
control.prototype.checkBlock = function () {
|
||||||
const x = core.getHeroLoc('x'),
|
const heroLoc = core.status.hero.loc;
|
||||||
y = core.getHeroLoc('y'),
|
const { x, y } = heroLoc;
|
||||||
loc = x + ',' + y;
|
const loc = `${x},${y}`;
|
||||||
const info = core.status.thisMap.enemy.mapDamage[loc];
|
const col = core.status.thisMap.enemy;
|
||||||
const damage = info?.damage;
|
const info = col.mapDamage[loc];
|
||||||
|
if (!info) return;
|
||||||
|
const damage = info.damage;
|
||||||
|
|
||||||
|
// 阻击夹域伤害
|
||||||
if (damage) {
|
if (damage) {
|
||||||
core.status.hero.hp -= damage;
|
core.status.hero.hp -= damage;
|
||||||
const type = [...info.type];
|
const type = [...info.type];
|
||||||
@ -24,5 +30,62 @@ export function createCheckBlock() {
|
|||||||
core.updateStatusBar();
|
core.updateStatusBar();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const actions: MotaAction[] = [];
|
||||||
|
|
||||||
|
// 阻击效果
|
||||||
|
if (info.repulse) {
|
||||||
|
for (const [x, y] of info.repulse) {
|
||||||
|
const loc2 = { x, y };
|
||||||
|
const dir = findDir(heroLoc, loc2);
|
||||||
|
if (dir === 'none') continue;
|
||||||
|
const [nx, ny] = ofDir(x, y, dir);
|
||||||
|
if (core.noPass(nx, ny) || !core.canMoveHero(x, y, dir)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
actions.push({
|
||||||
|
type: 'move',
|
||||||
|
time: 250,
|
||||||
|
keep: true,
|
||||||
|
loc: [x, y],
|
||||||
|
steps: [`${dir}:1`],
|
||||||
|
async: true
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 存储要和哪些捕捉怪战斗 */
|
||||||
|
const ambushEnemies: DamageEnemy[] = [];
|
||||||
|
|
||||||
|
// 捕捉效果
|
||||||
|
if (info.ambush) {
|
||||||
|
for (const [x, y] of info.ambush) {
|
||||||
|
const loc2 = { x, y };
|
||||||
|
const dir = findDir(loc2, heroLoc);
|
||||||
|
if (dir === 'none') continue;
|
||||||
|
actions.push({
|
||||||
|
type: 'move',
|
||||||
|
time: 250,
|
||||||
|
keep: false,
|
||||||
|
loc: [x, y],
|
||||||
|
steps: [`${dir}:1`],
|
||||||
|
async: true
|
||||||
|
});
|
||||||
|
const enemy = col.get(x, y);
|
||||||
|
if (enemy) {
|
||||||
|
ambushEnemies.push(enemy);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (actions.length > 0) {
|
||||||
|
actions.push({ type: 'waitAsync' });
|
||||||
|
// 与捕捉怪战斗
|
||||||
|
core.insertAction(actions, void 0, void 0, () => {
|
||||||
|
ambushEnemies.forEach(v => {
|
||||||
|
core.battle(v, v.y, true);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -514,10 +514,19 @@ export function initFallback() {
|
|||||||
mover.insertMove(...[start, ...resolved]);
|
mover.insertMove(...[start, ...resolved]);
|
||||||
const controller = mover.startMove();
|
const controller = mover.startMove();
|
||||||
|
|
||||||
|
const id = fallbackIds++;
|
||||||
|
core.animateFrame.asyncId[id] = () => {
|
||||||
|
if (!keep) {
|
||||||
|
core.removeBlock(mover.x, mover.y);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
if (controller) {
|
if (controller) {
|
||||||
await controller.onEnd;
|
await controller.onEnd;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
delete core.animateFrame.asyncId[id];
|
||||||
|
|
||||||
if (!keep) {
|
if (!keep) {
|
||||||
core.removeBlock(mover.x, mover.y);
|
core.removeBlock(mover.x, mover.y);
|
||||||
}
|
}
|
||||||
@ -566,7 +575,18 @@ export function initFallback() {
|
|||||||
|
|
||||||
core.updateStatusBar();
|
core.updateStatusBar();
|
||||||
core.removeBlock(sx, sy);
|
core.removeBlock(sx, sy);
|
||||||
|
|
||||||
|
const id = fallbackIds++;
|
||||||
|
core.animateFrame.asyncId[id] = () => {
|
||||||
|
if (keep) {
|
||||||
|
core.setBlock(block.id, ex, ey);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
await promise;
|
await promise;
|
||||||
|
|
||||||
|
delete core.animateFrame.asyncId[id];
|
||||||
|
|
||||||
if (keep) {
|
if (keep) {
|
||||||
core.setBlock(block.id, ex, ey);
|
core.setBlock(block.id, ex, ey);
|
||||||
}
|
}
|
||||||
|
@ -5,11 +5,11 @@ export interface EnemyInfo extends Partial<Omit<Enemy, 'special'>> {
|
|||||||
def: number;
|
def: number;
|
||||||
hp: number;
|
hp: number;
|
||||||
special: Set<number>;
|
special: Set<number>;
|
||||||
damageDecline: number;
|
|
||||||
atkBuff_: number;
|
atkBuff_: number;
|
||||||
defBuff_: number;
|
defBuff_: number;
|
||||||
hpBuff_: number;
|
hpBuff_: number;
|
||||||
enemy: Enemy;
|
enemy: Enemy;
|
||||||
|
guard: EnemyInfo[];
|
||||||
x?: number;
|
x?: number;
|
||||||
y?: number;
|
y?: number;
|
||||||
floorId?: FloorIds;
|
floorId?: FloorIds;
|
||||||
@ -18,8 +18,8 @@ export interface EnemyInfo extends Partial<Omit<Enemy, 'special'>> {
|
|||||||
export interface MapDamage {
|
export interface MapDamage {
|
||||||
damage: number;
|
damage: number;
|
||||||
type: Set<string>;
|
type: Set<string>;
|
||||||
mockery?: LocArr[];
|
repulse?: LocArr[];
|
||||||
hunt?: [x: number, y: number, dir: Dir][];
|
ambush?: LocArr[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface DamageDelta {
|
export interface DamageDelta {
|
||||||
@ -93,11 +93,6 @@ export interface IDamageEnemy {
|
|||||||
*/
|
*/
|
||||||
getRealInfo(): EnemyInfo;
|
getRealInfo(): EnemyInfo;
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取这个怪物的所有光环属性
|
|
||||||
*/
|
|
||||||
getHaloSpecials(): Set<number>;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 计算怪物伤害
|
* 计算怪物伤害
|
||||||
*/
|
*/
|
||||||
|
@ -207,139 +207,125 @@ var comment_c456ea59_6018_45ef_8bcc_211a24c627dc = {
|
|||||||
},
|
},
|
||||||
"_data": "特殊属性"
|
"_data": "特殊属性"
|
||||||
},
|
},
|
||||||
"crit": {
|
"n": {
|
||||||
"_leaf": true,
|
"_leaf": true,
|
||||||
"_type": "textarea",
|
"_type": "textarea",
|
||||||
"_docs": "致命一击",
|
"_docs": "连击数",
|
||||||
"_data": "致命一击"
|
"_data": "连击数"
|
||||||
},
|
},
|
||||||
"charge": {
|
"breakArmor": {
|
||||||
"_leaf": true,
|
"_leaf": true,
|
||||||
"_type": "textarea",
|
"_type": "textarea",
|
||||||
"_docs": "勇气冲锋",
|
"_docs": "破甲百分比",
|
||||||
"_data": "勇气冲锋"
|
"_data": "破甲百分比"
|
||||||
},
|
},
|
||||||
"courage": {
|
"counterAttack": {
|
||||||
"_leaf": true,
|
"_leaf": true,
|
||||||
"_type": "textarea",
|
"_type": "textarea",
|
||||||
"_docs": "勇气之刃",
|
"_docs": "反击百分比",
|
||||||
"_data": "勇气之刃"
|
"_data": "反击百分比"
|
||||||
},
|
},
|
||||||
"together": {
|
"purify": {
|
||||||
"_leaf": true,
|
"_leaf": true,
|
||||||
"_type": "textarea",
|
"_type": "textarea",
|
||||||
"_docs": "抱团",
|
"_docs": "净化倍率",
|
||||||
"_data": "抱团"
|
"_data": "净化倍率"
|
||||||
},
|
},
|
||||||
"hungry": {
|
"vampire": {
|
||||||
"_leaf": true,
|
"_leaf": true,
|
||||||
"_type": "textarea",
|
"_type": "textarea",
|
||||||
"_docs": "饥渴",
|
"_docs": "吸血百分比",
|
||||||
"_data": "饥渴"
|
"_data": "吸血百分比"
|
||||||
},
|
},
|
||||||
"ice": {
|
"add": {
|
||||||
"_leaf": true,
|
"_leaf": true,
|
||||||
"_type": "textarea",
|
"_type": "textarea",
|
||||||
"_docs": "霜冻",
|
"_docs": "吸血加到自身",
|
||||||
"_data": "霜冻"
|
"_data": "吸血是否加到怪物自身血量上"
|
||||||
},
|
},
|
||||||
"iceHalo": {
|
"zoneSquare": {
|
||||||
"_leaf": true,
|
|
||||||
"_type": "textarea",
|
|
||||||
"_docs": "冰封光环",
|
|
||||||
"_data": "冰封光环"
|
|
||||||
},
|
|
||||||
"night": {
|
|
||||||
"_leaf": true,
|
|
||||||
"_type": "textarea",
|
|
||||||
"_docs": "永夜",
|
|
||||||
"_data": "永夜"
|
|
||||||
},
|
|
||||||
"day": {
|
|
||||||
"_leaf": true,
|
|
||||||
"_type": "textarea",
|
|
||||||
"_docs": "极昼",
|
|
||||||
"_data": "极昼"
|
|
||||||
},
|
|
||||||
"melt": {
|
|
||||||
"_leaf": true,
|
|
||||||
"_type": "textarea",
|
|
||||||
"_docs": "融化",
|
|
||||||
"_data": "融化"
|
|
||||||
},
|
|
||||||
"iceCore": {
|
|
||||||
"_leaf": true,
|
|
||||||
"_type": "textarea",
|
|
||||||
"_docs": "冰封之核",
|
|
||||||
"_data": "冰封之核"
|
|
||||||
},
|
|
||||||
"fireCore": {
|
|
||||||
"_leaf": true,
|
|
||||||
"_type": "textarea",
|
|
||||||
"_docs": "火焰之核",
|
|
||||||
"_data": "火焰之核"
|
|
||||||
},
|
|
||||||
"paleShield": {
|
|
||||||
"_leaf": true,
|
|
||||||
"_type": "textarea",
|
|
||||||
"_docs": "苍蓝刻",
|
|
||||||
"_data": "苍蓝刻"
|
|
||||||
},
|
|
||||||
"translation": {
|
|
||||||
"_leaf": true,
|
|
||||||
"_type": "textarea",
|
|
||||||
"_docs": "乾坤挪移",
|
|
||||||
"_data": "乾坤挪移"
|
|
||||||
},
|
|
||||||
"hpHalo": {
|
|
||||||
"_leaf": true,
|
|
||||||
"_type": "textarea",
|
|
||||||
"_docs": "再生光环",
|
|
||||||
"_data": "再生光环"
|
|
||||||
},
|
|
||||||
"assimilateRange": {
|
|
||||||
"_leaf": true,
|
|
||||||
"_type": "textarea",
|
|
||||||
"_docs": "同化范围",
|
|
||||||
"_data": "同化范围"
|
|
||||||
},
|
|
||||||
"horn": {
|
|
||||||
"_leaf": true,
|
|
||||||
"_type": "textarea",
|
|
||||||
"_docs": "战争号角",
|
|
||||||
"_data": "战争号角"
|
|
||||||
},
|
|
||||||
"specialHalo": {
|
|
||||||
"_leaf": true,
|
|
||||||
"_type": "popCheckboxSet",
|
|
||||||
"_checkboxSet": function () {
|
|
||||||
var array = Mota.require('@user/data-state').specials;
|
|
||||||
var b = [],
|
|
||||||
c = [];
|
|
||||||
for (var index = 0; index < array.length; index++) {
|
|
||||||
b.push(index);
|
|
||||||
var name = array[index].name;
|
|
||||||
if (name instanceof Function) name = name({});
|
|
||||||
c.push(name + "(" + index + ")");
|
|
||||||
}
|
|
||||||
return {
|
|
||||||
"prefix": c,
|
|
||||||
"key": b
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"_data": "杀戮光环"
|
|
||||||
},
|
|
||||||
"specialMultiply": {
|
|
||||||
"_leaf": true,
|
"_leaf": true,
|
||||||
"_type": "checkbox",
|
"_type": "checkbox",
|
||||||
"_docs": "光环叠加",
|
"_docs": "领域九宫格",
|
||||||
"_data": "光环叠加是否为乘算"
|
"_data": "领域九宫格"
|
||||||
|
},
|
||||||
|
"range": {
|
||||||
|
"_leaf": true,
|
||||||
|
"_type": "textarea",
|
||||||
|
"_docs": "范围",
|
||||||
|
"_data": "领域或光环范围"
|
||||||
|
},
|
||||||
|
"zone": {
|
||||||
|
"_leaf": true,
|
||||||
|
"_type": "textarea",
|
||||||
|
"_docs": "领域伤害",
|
||||||
|
"_data": "领域伤害"
|
||||||
|
},
|
||||||
|
"repulse": {
|
||||||
|
"_leaf": true,
|
||||||
|
"_type": "textarea",
|
||||||
|
"_docs": "阻击伤害",
|
||||||
|
"_data": "阻击伤害"
|
||||||
|
},
|
||||||
|
"atkValue": {
|
||||||
|
"_leaf": true,
|
||||||
|
"_type": "textarea",
|
||||||
|
"_docs": "退化攻击",
|
||||||
|
"_data": "退化攻击"
|
||||||
|
},
|
||||||
|
"defValue": {
|
||||||
|
"_leaf": true,
|
||||||
|
"_type": "textarea",
|
||||||
|
"_docs": "退化防御",
|
||||||
|
"_data": "退化防御"
|
||||||
|
},
|
||||||
|
"damage": {
|
||||||
|
"_leaf": true,
|
||||||
|
"_type": "textarea",
|
||||||
|
"_docs": "固伤伤害",
|
||||||
|
"_data": "固伤伤害"
|
||||||
|
},
|
||||||
|
"laser": {
|
||||||
|
"_leaf": true,
|
||||||
|
"_type": "textarea",
|
||||||
|
"_docs": "激光伤害",
|
||||||
|
"_data": "激光伤害"
|
||||||
},
|
},
|
||||||
"haloRange": {
|
"haloRange": {
|
||||||
"_leaf": true,
|
"_leaf": true,
|
||||||
"_type": "textarea",
|
"_type": "textarea",
|
||||||
"_docs": "光环范围",
|
"_docs": "光环范围",
|
||||||
"_data": "光环范围"
|
"_data": "光环范围,不填表示 1"
|
||||||
|
},
|
||||||
|
"haloSquare": {
|
||||||
|
"_leaf": true,
|
||||||
|
"_type": "checkbox",
|
||||||
|
"_docs": "光环九宫格",
|
||||||
|
"_data": "光环九宫格"
|
||||||
|
},
|
||||||
|
"hpBuff": {
|
||||||
|
"_leaf": true,
|
||||||
|
"_type": "textarea",
|
||||||
|
"_docs": "光环加血",
|
||||||
|
"_data": "光环加血百分比"
|
||||||
|
},
|
||||||
|
"atkBuff": {
|
||||||
|
"_leaf": true,
|
||||||
|
"_type": "textarea",
|
||||||
|
"_docs": "光环加攻",
|
||||||
|
"_data": "光环加攻百分比"
|
||||||
|
},
|
||||||
|
"defBuff": {
|
||||||
|
"_leaf": true,
|
||||||
|
"_type": "textarea",
|
||||||
|
"_docs": "光环加防",
|
||||||
|
"_data": "光环加防百分比"
|
||||||
|
},
|
||||||
|
"haloAdd": {
|
||||||
|
"_leaf": true,
|
||||||
|
"_type": "textarea",
|
||||||
|
"_docs": "光环叠加",
|
||||||
|
"_data": "光环是否叠加"
|
||||||
},
|
},
|
||||||
"value": {
|
"value": {
|
||||||
"_leaf": true,
|
"_leaf": true,
|
||||||
@ -347,66 +333,12 @@ var comment_c456ea59_6018_45ef_8bcc_211a24c627dc = {
|
|||||||
"_docs": "特殊属性数值",
|
"_docs": "特殊属性数值",
|
||||||
"_data": "特殊属性的数值\n如:领域/阻激/激光怪的伤害值;吸血怪的吸血比例;光环怪增加生命的比例"
|
"_data": "特殊属性的数值\n如:领域/阻激/激光怪的伤害值;吸血怪的吸血比例;光环怪增加生命的比例"
|
||||||
},
|
},
|
||||||
"zoneSquare": {
|
|
||||||
"_leaf": true,
|
|
||||||
"_type": "checkbox",
|
|
||||||
"_docs": "九宫格",
|
|
||||||
"_data": "领域、阻击、光环或捕捉怪是否九宫格"
|
|
||||||
},
|
|
||||||
"range": {
|
|
||||||
"_leaf": true,
|
|
||||||
"_type": "textarea",
|
|
||||||
"_range": "(thiseval==~~thiseval && thiseval>0)||thiseval==null",
|
|
||||||
"_docs": "领域范围",
|
|
||||||
"_data": "领域或光环的范围;领域不加默认为1,光环不加则为全图效果"
|
|
||||||
},
|
|
||||||
"notBomb": {
|
"notBomb": {
|
||||||
"_leaf": true,
|
"_leaf": true,
|
||||||
"_type": "checkbox",
|
"_type": "checkbox",
|
||||||
"_docs": "不可炸",
|
"_docs": "不可炸",
|
||||||
"_data": "该怪物不可被炸"
|
"_data": "该怪物不可被炸"
|
||||||
},
|
},
|
||||||
"n": {
|
|
||||||
"_leaf": true,
|
|
||||||
"_type": "textarea",
|
|
||||||
"_range": "(thiseval==~~thiseval && thiseval>0)||thiseval==null",
|
|
||||||
"_docs": "连击数",
|
|
||||||
"_data": "多连击的连击数,净化怪的净化倍率"
|
|
||||||
},
|
|
||||||
"add": {
|
|
||||||
"_leaf": true,
|
|
||||||
"_type": "checkbox",
|
|
||||||
"_docs": "吸血加到自身",
|
|
||||||
"_data": "吸血后是否加到自身;光环是否叠加"
|
|
||||||
},
|
|
||||||
"atkValue": {
|
|
||||||
"_leaf": true,
|
|
||||||
"_type": "textarea",
|
|
||||||
"_range": "thiseval==~~thiseval||thiseval==null",
|
|
||||||
"_docs": "退化扣攻",
|
|
||||||
"_data": "退化时勇士下降的攻击力点数;光环怪增加攻击的比例;反击的比例"
|
|
||||||
},
|
|
||||||
"defValue": {
|
|
||||||
"_leaf": true,
|
|
||||||
"_type": "textarea",
|
|
||||||
"_range": "thiseval==~~thiseval||thiseval==null",
|
|
||||||
"_docs": "退化扣防",
|
|
||||||
"_data": "退化时勇士下降的防御力点数;光环怪增加防御的比例;破甲的比例"
|
|
||||||
},
|
|
||||||
"damage": {
|
|
||||||
"_leaf": true,
|
|
||||||
"_type": "textarea",
|
|
||||||
"_range": "thiseval==~~thiseval||thiseval==null",
|
|
||||||
"_docs": "固伤",
|
|
||||||
"_data": "战前扣血的点数"
|
|
||||||
},
|
|
||||||
"beforeBattle": {
|
|
||||||
"_leaf": true,
|
|
||||||
"_type": "event",
|
|
||||||
"_event": "beforeBattle",
|
|
||||||
"_docs": "战前事件",
|
|
||||||
"_data": "和该怪物战斗前触发的事件列表"
|
|
||||||
},
|
|
||||||
"afterBattle": {
|
"afterBattle": {
|
||||||
"_leaf": true,
|
"_leaf": true,
|
||||||
"_type": "event",
|
"_type": "event",
|
||||||
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -4,7 +4,7 @@ var enemys_fcae963b_31c9_42b4_b48c_bb48d09f3f80 =
|
|||||||
"redSlime": {"name":"红头怪","hp":0,"atk":0,"def":0,"money":0,"exp":0,"point":0,"special":[16,18],"value":10},
|
"redSlime": {"name":"红头怪","hp":0,"atk":0,"def":0,"money":0,"exp":0,"point":0,"special":[16,18],"value":10},
|
||||||
"blackSlime": {"name":"青头怪","hp":0,"atk":0,"def":0,"money":0,"exp":0,"point":0,"special":[]},
|
"blackSlime": {"name":"青头怪","hp":0,"atk":0,"def":0,"money":0,"exp":0,"point":0,"special":[]},
|
||||||
"slimelord": {"name":"怪王","hp":100,"atk":120,"def":0,"money":10,"exp":0,"point":0,"special":[1,9]},
|
"slimelord": {"name":"怪王","hp":100,"atk":120,"def":0,"money":10,"exp":0,"point":0,"special":[1,9]},
|
||||||
"bat": {"name":"小蝙蝠","hp":100,"atk":120,"def":0,"money":2,"exp":0,"point":0,"special":[1]},
|
"bat": {"name":"小蝙蝠","hp":100,"atk":120,"def":0,"money":2,"exp":0,"point":0,"special":[1,27]},
|
||||||
"bigBat": {"name":"大蝙蝠","hp":0,"atk":0,"def":0,"money":0,"exp":0,"point":0,"special":[]},
|
"bigBat": {"name":"大蝙蝠","hp":0,"atk":0,"def":0,"money":0,"exp":0,"point":0,"special":[]},
|
||||||
"redBat": {"name":"红蝙蝠","hp":0,"atk":0,"def":0,"money":0,"exp":0,"point":0,"special":[]},
|
"redBat": {"name":"红蝙蝠","hp":0,"atk":0,"def":0,"money":0,"exp":0,"point":0,"special":[]},
|
||||||
"vampire": {"name":"冥灵魔王","hp":888,"atk":888,"def":888,"money":888,"exp":888,"point":0,"special":[6],"n":8},
|
"vampire": {"name":"冥灵魔王","hp":888,"atk":888,"def":888,"money":888,"exp":888,"point":0,"special":[6],"n":8},
|
||||||
|
@ -150,9 +150,6 @@ var functions_d6ad677b_427a_4623_b50f_a445a3b0ef8a = {
|
|||||||
// 根据分区信息自动砍层与恢复
|
// 根据分区信息自动砍层与恢复
|
||||||
Mota.require('@user/legacy-plugin-data')?.autoRemoveMaps?.(floorId);
|
Mota.require('@user/legacy-plugin-data')?.autoRemoveMaps?.(floorId);
|
||||||
|
|
||||||
// 重置画布尺寸
|
|
||||||
core.maps.resizeMap(floorId);
|
|
||||||
|
|
||||||
// ---------- 重绘新地图;这一步将会设置core.status.floorId ---------- //
|
// ---------- 重绘新地图;这一步将会设置core.status.floorId ---------- //
|
||||||
core.drawMap(floorId);
|
core.drawMap(floorId);
|
||||||
|
|
||||||
@ -192,6 +189,25 @@ var functions_d6ad677b_427a_4623_b50f_a445a3b0ef8a = {
|
|||||||
|
|
||||||
core.updateDamage();
|
core.updateDamage();
|
||||||
|
|
||||||
|
// 检查重生怪并重置
|
||||||
|
if (!fromLoad) {
|
||||||
|
core.extractBlocks(floorId);
|
||||||
|
const obj = core.getMapBlocksObj(floorId);
|
||||||
|
const floor = core.status.maps[floorId];
|
||||||
|
const col = floor.enemy;
|
||||||
|
col.list.forEach(v => {
|
||||||
|
const info = v.getRealInfo();
|
||||||
|
if (info.special.has(23)) {
|
||||||
|
const block = obj[`${v.x},${v.y}`];
|
||||||
|
if (block.disable) {
|
||||||
|
block.disable = false;
|
||||||
|
core.setMapBlockDisabled(floorId, v.x, v.y, false);
|
||||||
|
core.maps._updateMapArray(floorId, v.x, v.y);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
// ...可以新增一些其他内容,比如创建个画布在右上角显示什么内容等等
|
// ...可以新增一些其他内容,比如创建个画布在右上角显示什么内容等等
|
||||||
},
|
},
|
||||||
afterChangeFloor: function (floorId) {
|
afterChangeFloor: function (floorId) {
|
||||||
@ -347,6 +363,9 @@ var functions_d6ad677b_427a_4623_b50f_a445a3b0ef8a = {
|
|||||||
core.updateDamage();
|
core.updateDamage();
|
||||||
},
|
},
|
||||||
moveOneStep: function (callback) {
|
moveOneStep: function (callback) {
|
||||||
|
// 注意,此函数在 2.C 将会被弃用,并移动至 packages-user/data-state/src/state/move.ts 的 HeroMover 中
|
||||||
|
// 一些样板内置内容已经移动至上述函数,包括中毒行为等
|
||||||
|
|
||||||
// 勇士每走一步后执行的操作。callback为行走完毕后的回调
|
// 勇士每走一步后执行的操作。callback为行走完毕后的回调
|
||||||
// 这个函数执行在“刚走完”的时候,即还没有检查该点的事件和领域伤害等。
|
// 这个函数执行在“刚走完”的时候,即还没有检查该点的事件和领域伤害等。
|
||||||
// 请注意:瞬间移动不会执行该函数。如果要控制能否瞬间移动有三种方法:
|
// 请注意:瞬间移动不会执行该函数。如果要控制能否瞬间移动有三种方法:
|
||||||
@ -412,6 +431,13 @@ var functions_d6ad677b_427a_4623_b50f_a445a3b0ef8a = {
|
|||||||
// 判定能否瞬移到该点
|
// 判定能否瞬移到该点
|
||||||
if (ignoreSteps == null) ignoreSteps = core.canMoveDirectly(x, y);
|
if (ignoreSteps == null) ignoreSteps = core.canMoveDirectly(x, y);
|
||||||
if (ignoreSteps >= 0) {
|
if (ignoreSteps >= 0) {
|
||||||
|
// 中毒也允许瞬移
|
||||||
|
if (core.hasFlag('poison')) {
|
||||||
|
const damage = ignoreSteps * core.values.poisonDamage;
|
||||||
|
if (damage >= core.status.hero.hp) return false;
|
||||||
|
core.status.hero.statistics.poisonDamage += damage;
|
||||||
|
core.status.hero.hp -= damage;
|
||||||
|
}
|
||||||
core.clearMap('hero');
|
core.clearMap('hero');
|
||||||
// 获得勇士最后的朝向
|
// 获得勇士最后的朝向
|
||||||
var lastDirection =
|
var lastDirection =
|
||||||
|
@ -417,28 +417,28 @@ var items_296f5d02_12fd_4166_a7c1_b5e830c9ee3a =
|
|||||||
"cls": "tools",
|
"cls": "tools",
|
||||||
"name": "解毒药水",
|
"name": "解毒药水",
|
||||||
"text": "可以解除中毒状态",
|
"text": "可以解除中毒状态",
|
||||||
"useItemEffect": "core.triggerDebuff('remove', 'poison');",
|
"useItemEffect": "core.removeFlag('poison')",
|
||||||
"canUseItemEffect": "core.hasFlag('poison');"
|
"canUseItemEffect": "core.hasFlag('poison');"
|
||||||
},
|
},
|
||||||
"weakWine": {
|
"weakWine": {
|
||||||
"cls": "tools",
|
"cls": "tools",
|
||||||
"name": "解衰药水",
|
"name": "解衰药水",
|
||||||
"text": "可以解除衰弱状态",
|
"text": "可以解除衰弱状态",
|
||||||
"useItemEffect": "core.triggerDebuff('remove', 'weak');",
|
"useItemEffect": "core.removeFlag('weak');",
|
||||||
"canUseItemEffect": "core.hasFlag('weak');"
|
"canUseItemEffect": "core.hasFlag('weak');"
|
||||||
},
|
},
|
||||||
"curseWine": {
|
"curseWine": {
|
||||||
"cls": "tools",
|
"cls": "tools",
|
||||||
"name": "解咒药水",
|
"name": "解咒药水",
|
||||||
"text": "可以解除诅咒状态",
|
"text": "可以解除诅咒状态",
|
||||||
"useItemEffect": "core.triggerDebuff('remove', 'curse');",
|
"useItemEffect": "core.removeFlag('curse');",
|
||||||
"canUseItemEffect": "core.hasFlag('curse');"
|
"canUseItemEffect": "core.hasFlag('curse');"
|
||||||
},
|
},
|
||||||
"superWine": {
|
"superWine": {
|
||||||
"cls": "tools",
|
"cls": "tools",
|
||||||
"name": "万能药水",
|
"name": "万能药水",
|
||||||
"text": "可以解除所有不良状态",
|
"text": "可以解除所有不良状态",
|
||||||
"useItemEffect": "core.triggerDebuff('remove', ['poison', 'weak', 'curse']);",
|
"useItemEffect": "core.removeFlag('poison');\ncore.removeFlag('weak');\ncore.removeFlag('curse');",
|
||||||
"canUseItemEffect": "(function() {\n\treturn core.hasFlag('poison') || core.hasFlag('weak') || core.hasFlag('curse');\n})();"
|
"canUseItemEffect": "(function() {\n\treturn core.hasFlag('poison') || core.hasFlag('weak') || core.hasFlag('curse');\n})();"
|
||||||
},
|
},
|
||||||
"hammer": {
|
"hammer": {
|
||||||
|
@ -11,9 +11,9 @@ var maps_90f36752_8815_4be8_b32b_d7fad1d0542e =
|
|||||||
"9": {"cls":"terrains","id":"pinkShopLeft"},
|
"9": {"cls":"terrains","id":"pinkShopLeft"},
|
||||||
"10": {"cls":"terrains","id":"pinkShopRight"},
|
"10": {"cls":"terrains","id":"pinkShopRight"},
|
||||||
"11": {"cls":"animates","id":"lavaNet","canPass":true,"trigger":"null","script":"(function () {\n\t// 血网的伤害效果移动到 checkBlock 中处理\n\n\t// 如果要做一次性血网,可直接注释掉下面这句话:\n\t// core.removeBlock(core.getHeroLoc('x'), core.getHeroLoc('y'));\n})();","name":"血网"},
|
"11": {"cls":"animates","id":"lavaNet","canPass":true,"trigger":"null","script":"(function () {\n\t// 血网的伤害效果移动到 checkBlock 中处理\n\n\t// 如果要做一次性血网,可直接注释掉下面这句话:\n\t// core.removeBlock(core.getHeroLoc('x'), core.getHeroLoc('y'));\n})();","name":"血网"},
|
||||||
"12": {"cls":"animates","id":"poisonNet","canPass":true,"trigger":"null","script":"(function () {\n\tif (!core.hasItem('amulet')) {\n\t\tcore.triggerDebuff('get', 'poison');\n\t\tcore.updateStatusBar();\n\t}\n\n\t// 如果要做一次性毒网,可直接注释掉下面这句话:\n\t// core.removeBlock(core.getHeroLoc('x'), core.getHeroLoc('y'));\n})()","name":"毒网"},
|
"12": {"cls":"animates","id":"poisonNet","canPass":true,"trigger":"null","script":"(function () {\n\tif (!core.hasItem('amulet')) {\n\t\tcore.setFlag('poison', true);\n\t\tcore.updateStatusBar();\n\t}\n\n\t// 如果要做一次性毒网,可直接注释掉下面这句话:\n\t// core.removeBlock(core.getHeroLoc('x'), core.getHeroLoc('y'));\n})()","name":"毒网"},
|
||||||
"13": {"cls":"animates","id":"weakNet","canPass":true,"trigger":"null","script":"(function () {\n\tif (!core.hasItem('amulet')) {\n\t\tcore.triggerDebuff('get', 'weak');\n\t\tcore.updateStatusBar();\n\t}\n\n\t// 如果要做一次性衰网,可直接注释掉下面这句话:\n\t// core.removeBlock(core.getHeroLoc('x'), core.getHeroLoc('y'));\n})()","name":"衰网"},
|
"13": {"cls":"animates","id":"weakNet","canPass":true,"trigger":"null","script":"(function () {\n\tif (!core.hasItem('amulet')) {\n\t\tcore.setFlag('weak', true);\n\t\tcore.updateStatusBar();\n\t}\n\n\t// 如果要做一次性衰网,可直接注释掉下面这句话:\n\t// core.removeBlock(core.getHeroLoc('x'), core.getHeroLoc('y'));\n})()","name":"衰网"},
|
||||||
"14": {"cls":"animates","id":"curseNet","canPass":true,"trigger":"null","script":"(function () {\n\tif (!core.hasItem('amulet')) {\n\t\tcore.triggerDebuff('get', 'curse');\n\t\tcore.updateStatusBar();\n\t}\n\n\t// 如果要做一次性咒网,可直接注释掉下面这句话:\n\t// core.removeBlock(core.getHeroLoc('x'), core.getHeroLoc('y'));\n})()","name":"咒网"},
|
"14": {"cls":"animates","id":"curseNet","canPass":true,"trigger":"null","script":"(function () {\n\tif (!core.hasItem('amulet')) {\n\t\tcore.setFlag('curse', true);\n\t\tcore.updateStatusBar();\n\t}\n\n\t// 如果要做一次性咒网,可直接注释掉下面这句话:\n\t// core.removeBlock(core.getHeroLoc('x'), core.getHeroLoc('y'));\n})()","name":"咒网"},
|
||||||
"15": {"cls":"animates","id":"blueLava"},
|
"15": {"cls":"animates","id":"blueLava"},
|
||||||
"16": {"cls":"animates","id":"water"},
|
"16": {"cls":"animates","id":"water"},
|
||||||
"20": {"cls":"autotile","id":"autotile"},
|
"20": {"cls":"autotile","id":"autotile"},
|
||||||
|
2
src/types/declaration/core.d.ts
vendored
2
src/types/declaration/core.d.ts
vendored
@ -278,7 +278,7 @@ interface AnimateFrame {
|
|||||||
/**
|
/**
|
||||||
* 异步信息,想不到吧,这玩意是一个以number为索引的回调函数列表
|
* 异步信息,想不到吧,这玩意是一个以number为索引的回调函数列表
|
||||||
*/
|
*/
|
||||||
readonly asyncId: Record<number, () => void>;
|
readonly asyncId: Record<number | symbol, () => void>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 上一个异步事件的id
|
* 上一个异步事件的id
|
||||||
|
3
src/types/declaration/status.d.ts
vendored
3
src/types/declaration/status.d.ts
vendored
@ -802,9 +802,6 @@ interface HeroStatus {
|
|||||||
*/
|
*/
|
||||||
manamax: number;
|
manamax: number;
|
||||||
|
|
||||||
/** 魔法防御 */
|
|
||||||
magicDef: number;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 勇士的名称
|
* 勇士的名称
|
||||||
*/
|
*/
|
||||||
|
Loading…
Reference in New Issue
Block a user