refactor: 特殊属性改成集合

This commit is contained in:
unanmed 2024-09-30 10:35:25 +08:00
parent f97e7c1bff
commit 39f38cd703
6 changed files with 51 additions and 87 deletions
src
core/render/preset
game/enemy
plugin
ui

View File

@ -340,7 +340,7 @@ export class Damage extends Sprite<EDamageEvent> {
}; };
block.add(dam1).add(dam2); block.add(dam1).add(dam2);
if (real.special.includes(8) && real.togetherNum) { if (real.special.has(8) && real.togetherNum) {
const dam3: DamageRenderable = { const dam3: DamageRenderable = {
align: 'right', align: 'right',
baseline: 'top', baseline: 'top',
@ -352,7 +352,7 @@ export class Damage extends Sprite<EDamageEvent> {
}; };
block.add(dam3); block.add(dam3);
} }
if (real.special.includes(30)) { if (real.special.has(30)) {
const dam4: DamageRenderable = { const dam4: DamageRenderable = {
align: 'left', align: 'left',
baseline: 'top', baseline: 'top',

View File

@ -192,7 +192,7 @@ function init() {
core.status.hero.statistics.battle++; core.status.hero.statistics.battle++;
// 智慧之源 // 智慧之源
if (special.includes(14) && flags.hard === 2) { if (special.has(14) && flags.hard === 2) {
core.addFlag( core.addFlag(
'inte_' + floorId, 'inte_' + floorId,
Math.ceil((core.status.hero.mdef / 10) * 0.3) * 10 Math.ceil((core.status.hero.mdef / 10) * 0.3) * 10
@ -202,11 +202,11 @@ function init() {
} }
// 极昼永夜 // 极昼永夜
if (special.includes(22)) { if (special.has(22)) {
flags[`night_${floorId}`] ??= 0; flags[`night_${floorId}`] ??= 0;
flags[`night_${floorId}`] -= enemy.info.night!; flags[`night_${floorId}`] -= enemy.info.night!;
} }
if (special.includes(23)) { if (special.has(23)) {
flags[`night_${floorId}`] ??= 0; flags[`night_${floorId}`] ??= 0;
flags[`night_${floorId}`] += enemy.info.day; flags[`night_${floorId}`] += enemy.info.day;
} }
@ -216,7 +216,7 @@ function init() {
// } // }
// 如果是融化怪,需要特殊标记一下 // 如果是融化怪,需要特殊标记一下
if (special.includes(25) && has(x) && has(y)) { if (special.has(25) && has(x) && has(y)) {
flags[`melt_${floorId}`] ??= {}; flags[`melt_${floorId}`] ??= {};
flags[`melt_${floorId}`][`${x},${y}`] = enemy.info.melt; flags[`melt_${floorId}`][`${x},${y}`] = enemy.info.melt;
} }

View File

@ -1,12 +1,6 @@
import { getHeroStatusOf, getHeroStatusOn } from '@/game/state/hero'; import { getHeroStatusOf, getHeroStatusOn } from '@/game/state/hero';
import { Range, RangeCollection } from '@/plugin/game/range'; import { Range, RangeCollection } from '@/plugin/game/range';
import { import { ensureArray, has, manhattan } from '@/plugin/game/utils';
checkV2,
ensureArray,
formatDamage,
has,
manhattan
} from '@/plugin/game/utils';
import EventEmitter from 'eventemitter3'; import EventEmitter from 'eventemitter3';
// todo: 光环划分优先级,从而可以实现光环的多级运算 // todo: 光环划分优先级,从而可以实现光环的多级运算
@ -24,11 +18,11 @@ interface HaloType {
}; };
} }
export interface EnemyInfo extends Partial<Enemy> { export interface EnemyInfo extends Partial<Omit<Enemy, 'special'>> {
atk: number; atk: number;
def: number; def: number;
hp: number; hp: number;
special: number[]; special: Set<number>;
damageDecline: number; damageDecline: number;
atkBuff_: number; atkBuff_: number;
defBuff_: number; defBuff_: number;
@ -280,7 +274,7 @@ export class DamageEnemy<T extends EnemyIds = EnemyIds> {
hp: enemy.hp, hp: enemy.hp,
atk: enemy.atk, atk: enemy.atk,
def: enemy.def, def: enemy.def,
special: enemy.special.slice(), special: new Set(enemy.special),
damageDecline: 0, damageDecline: 0,
atkBuff_: 0, atkBuff_: 0,
defBuff_: 0, defBuff_: 0,
@ -323,7 +317,7 @@ export class DamageEnemy<T extends EnemyIds = EnemyIds> {
} }
// 智慧之源 // 智慧之源
if (flags.hard === 2 && special.includes(14)) { if (flags.hard === 2 && special.has(14)) {
info.atk += flags[`inte_${floorId}`] ?? 0; info.atk += flags[`inte_${floorId}`] ?? 0;
} }
@ -368,21 +362,17 @@ export class DamageEnemy<T extends EnemyIds = EnemyIds> {
return this.info; return this.info;
} }
getHaloSpecials(): number[] { getHaloSpecials(): Set<number> {
if (!this.floorId) return []; if (!this.floorId) return new Set();
if (!has(this.x) || !has(this.y)) return []; if (!has(this.x) || !has(this.y)) return new Set();
const special = this.info.special ?? this.enemy.special; const special = this.info.special ?? this.enemy.special;
const filter = special.filter(v => { const res = new Set<number>();
return haloSpecials.has(v) && !this.providedHalo.has(v); special.forEach(v => {
if (haloSpecials.has(v) && !this.providedHalo.has(v)) {
res.add(v);
}
}); });
if (filter.length === 0) return []; return res;
const collection = this.col ?? core.status.maps[this.floorId].enemy;
if (!collection) {
throw new Error(
`Unexpected undefined of enemy collection in floor ${this.floorId}.`
);
}
return filter;
} }
/** /**
@ -421,9 +411,7 @@ export class DamageEnemy<T extends EnemyIds = EnemyIds> {
const s = enemy.specialHalo!; const s = enemy.specialHalo!;
for (const spe of s) { for (const spe of s) {
// 防止重复 e.special.add(spe);
if (!e.special.includes(spe))
e.special.push(spe);
} }
// 如果是自身,就不进行特殊属性数值处理了 // 如果是自身,就不进行特殊属性数值处理了
if (e === this.info) return; if (e === this.info) return;
@ -476,14 +464,14 @@ export class DamageEnemy<T extends EnemyIds = EnemyIds> {
// e 是被加成怪的属性enemy 是施加光环的怪 // e 是被加成怪的属性enemy 是施加光环的怪
// 抱团 // 抱团
if (special.includes(8)) { if (special.has(8)) {
col.applyHalo( col.applyHalo(
'square', 'square',
{ x: this.x, y: this.y, d: 5 }, { x: this.x, y: this.y, d: 5 },
this, this,
(e, enemy) => { (e, enemy) => {
if ( if (
e.special.includes(8) && e.special.has(8) &&
(e.x !== this.x || this.y !== e.y) (e.x !== this.x || this.y !== e.y)
) { ) {
e.atkBuff_ += enemy.together ?? 0; e.atkBuff_ += enemy.together ?? 0;
@ -497,7 +485,7 @@ export class DamageEnemy<T extends EnemyIds = EnemyIds> {
} }
// 冰封光环 // 冰封光环
if (special.includes(21)) { if (special.has(21)) {
square7.push(e => { square7.push(e => {
e.damageDecline += this.info.iceHalo ?? 0; e.damageDecline += this.info.iceHalo ?? 0;
}); });
@ -511,7 +499,7 @@ export class DamageEnemy<T extends EnemyIds = EnemyIds> {
} }
// 冰封之核 // 冰封之核
if (special.includes(26)) { if (special.has(26)) {
square5.push(e => { square5.push(e => {
e.defBuff_ += this.info.iceCore ?? 0; e.defBuff_ += this.info.iceCore ?? 0;
}); });
@ -525,7 +513,7 @@ export class DamageEnemy<T extends EnemyIds = EnemyIds> {
} }
// 火焰之核 // 火焰之核
if (special.includes(27)) { if (special.has(27)) {
square5.push(e => { square5.push(e => {
e.atkBuff_ += this.info.fireCore ?? 0; e.atkBuff_ += this.info.fireCore ?? 0;
}); });
@ -539,7 +527,7 @@ export class DamageEnemy<T extends EnemyIds = EnemyIds> {
} }
// 再生光环 // 再生光环
if (special.includes(31)) { if (special.has(31)) {
square7.push(e => { square7.push(e => {
e.hpBuff_ += this.info.hpHalo ?? 0; e.hpBuff_ += this.info.hpHalo ?? 0;
}); });
@ -553,7 +541,7 @@ export class DamageEnemy<T extends EnemyIds = EnemyIds> {
} }
// 同化,它不会被光环类属性影响,因此放到这 // 同化,它不会被光环类属性影响,因此放到这
if (special.includes(32)) { if (special.has(32)) {
const e = this.info; const e = this.info;
const type = 'square'; const type = 'square';
const r = Math.floor(e.assimilateRange!); const r = Math.floor(e.assimilateRange!);
@ -567,10 +555,7 @@ export class DamageEnemy<T extends EnemyIds = EnemyIds> {
for (const spe of s) { for (const spe of s) {
if (unassimilatable.has(spe)) continue; if (unassimilatable.has(spe)) continue;
// 防止重复 enemy.special.add(spe);
if (!enemy.special.includes(spe)) {
enemy.special.push(spe);
}
} }
// 然后计算特殊属性数值 // 然后计算特殊属性数值
for (const spec of s) { for (const spec of s) {
@ -643,7 +628,7 @@ export class DamageEnemy<T extends EnemyIds = EnemyIds> {
const h = floor.height; const h = floor.height;
// 突刺 // 突刺
if (this.info.special.includes(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);
@ -666,7 +651,7 @@ export class DamageEnemy<T extends EnemyIds = EnemyIds> {
} }
// 射击 // 射击
if (this.info.special.includes(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.atk ?? 0) - hero.def!, 0);
const objs = core.getMapBlocksObj(this.floorId); const objs = core.getMapBlocksObj(this.floorId);
@ -683,8 +668,6 @@ export class DamageEnemy<T extends EnemyIds = EnemyIds> {
if ( if (
block && block &&
block.event.noPass && block.event.noPass &&
block.event.cls !== 'enemys' &&
block.event.cls !== 'enemy48' &&
block.id !== 141 && block.id !== 141 &&
block.id !== 151 block.id !== 151
) { ) {
@ -696,7 +679,7 @@ export class DamageEnemy<T extends EnemyIds = EnemyIds> {
} }
// 电摇嘲讽 // 电摇嘲讽
if (this.info.special.includes(19)) { if (this.info.special.has(19)) {
const objs = core.getMapBlocksObj(this.floorId); const objs = core.getMapBlocksObj(this.floorId);
for (let nx = 0; nx < w; nx++) { for (let nx = 0; nx < w; nx++) {
const loc = `${nx},${this.y}` as LocString; const loc = `${nx},${this.y}` as LocString;
@ -719,7 +702,7 @@ export class DamageEnemy<T extends EnemyIds = EnemyIds> {
} }
// 追猎 // 追猎
if (this.info.special.includes(12)) { if (this.info.special.has(12)) {
const objs = core.getMapBlocksObj(this.floorId); const objs = core.getMapBlocksObj(this.floorId);
for (let nx = 0; nx < w; nx++) { for (let nx = 0; nx < w; nx++) {
const loc = `${nx},${this.y}` as LocString; const loc = `${nx},${this.y}` as LocString;
@ -922,13 +905,13 @@ export class DamageEnemy<T extends EnemyIds = EnemyIds> {
const add = info.def + info.hp - core.status.hero.mana; const add = info.def + info.hp - core.status.hero.mana;
// 坚固,不可能通过攻击秒杀 // 坚固,不可能通过攻击秒杀
if (info.special.includes(3)) { if (info.special.has(3)) {
return Infinity; return Infinity;
} }
// 列方程求解,拿笔算一下就知道了 // 列方程求解,拿笔算一下就知道了
// 饥渴,会偷取勇士攻击 // 饥渴,会偷取勇士攻击
if (info.special.includes(7)) { if (info.special.has(7)) {
if (info.damageDecline === 0) { if (info.damageDecline === 0) {
return add / (1 - this.enemy.hungry! / 100); return add / (1 - this.enemy.hungry! / 100);
} else { } else {
@ -942,7 +925,7 @@ export class DamageEnemy<T extends EnemyIds = EnemyIds> {
} }
// 霜冻 // 霜冻
if (info.special.includes(20) && !core.hasEquip('I589')) { if (info.special.has(20) && !core.hasEquip('I589')) {
return ( return (
info.def + info.def +
info.hp / (1 - this.enemy.ice! / 100) - info.hp / (1 - this.enemy.ice! / 100) -
@ -998,7 +981,7 @@ export function calDamageWith(
let damage = 0; let damage = 0;
// 饥渴 // 饥渴
if (special.includes(7)) { if (special.has(7)) {
const delta = Math.floor((atk * info.hungry!) / 100); const delta = Math.floor((atk * info.hungry!) / 100);
atk -= delta; atk -= delta;
monAtk += delta; monAtk += delta;
@ -1007,10 +990,10 @@ export function calDamageWith(
let heroPerDamage: number; let heroPerDamage: number;
// 绝对防御 // 绝对防御
if (special.includes(9)) { if (special.has(9)) {
heroPerDamage = atk + mana - monDef; heroPerDamage = atk + mana - monDef;
if (heroPerDamage <= 0) return null; if (heroPerDamage <= 0) return null;
} else if (special.includes(3)) { } else if (special.has(3)) {
// 由于坚固的特性,只能放到这来计算了 // 由于坚固的特性,只能放到这来计算了
if (atk > enemy.def) heroPerDamage = 1 + mana; if (atk > enemy.def) heroPerDamage = 1 + mana;
else return null; else return null;
@ -1021,7 +1004,7 @@ export function calDamageWith(
} }
// 霜冻 // 霜冻
if (special.includes(20) && !core.hasEquip('I589')) { if (special.has(20) && !core.hasEquip('I589')) {
heroPerDamage *= 1 - info.ice! / 100; heroPerDamage *= 1 - info.ice! / 100;
} }
@ -1030,7 +1013,7 @@ export function calDamageWith(
let enemyPerDamage: number; let enemyPerDamage: number;
// 魔攻 // 魔攻
if (special.includes(2) || special.includes(13)) { if (special.has(2) || special.has(13)) {
enemyPerDamage = monAtk; enemyPerDamage = monAtk;
enemyPerDamage -= magicDef; enemyPerDamage -= magicDef;
} else { } else {
@ -1038,38 +1021,38 @@ export function calDamageWith(
} }
// 连击 // 连击
if (special.includes(4)) enemyPerDamage *= 2; if (special.has(4)) enemyPerDamage *= 2;
if (special.includes(5)) enemyPerDamage *= 3; if (special.has(5)) enemyPerDamage *= 3;
if (special.includes(6)) enemyPerDamage *= info.n!; if (special.has(6)) enemyPerDamage *= info.n!;
if (enemyPerDamage < 0) enemyPerDamage = 0; if (enemyPerDamage < 0) enemyPerDamage = 0;
// 苍蓝刻 // 苍蓝刻
if (special.includes(28)) { if (special.has(28)) {
heroPerDamage *= 1 - info.paleShield! / 100; heroPerDamage *= 1 - info.paleShield! / 100;
} }
let turn = Math.ceil(monHp / heroPerDamage); let turn = Math.ceil(monHp / heroPerDamage);
// 致命一击 // 致命一击
if (special.includes(1)) { if (special.has(1)) {
const times = Math.floor(turn / 5); const times = Math.floor(turn / 5);
damage += ((times * (info.crit! - 100)) / 100) * enemyPerDamage; damage += ((times * (info.crit! - 100)) / 100) * enemyPerDamage;
} }
// 勇气之刃 // 勇气之刃
if (turn > 1 && special.includes(10)) { if (turn > 1 && special.has(10)) {
damage += (info.courage! / 100 - 1) * enemyPerDamage; damage += (info.courage! / 100 - 1) * enemyPerDamage;
} }
// 勇气冲锋 // 勇气冲锋
if (special.includes(11)) { if (special.has(11)) {
damage += (info.charge! / 100) * enemyPerDamage; damage += (info.charge! / 100) * enemyPerDamage;
turn += 5; turn += 5;
} }
// 先攻 // 先攻
if (special.includes(17)) { if (special.has(17)) {
damage += enemyPerDamage; damage += enemyPerDamage;
} }

View File

@ -45,25 +45,6 @@ export function init() {
return true; return true;
}); });
core.registerReplayAction('study', name => {
if (!name.startsWith('study:')) return false;
const [num, x, y] = name
.slice(6)
.split(',')
.map(v => parseInt(v));
if (!canStudySkill(num)) return false;
const id = core.getBlockId(x, y);
ensureFloorDamage(core.status.floorId);
const col = core.status.thisMap.enemy;
col.calRealAttribute();
const enemy = col.list.find(v => v.x === x && v.y === y)!.info;
if (!enemy.special.includes(num)) return false;
studySkill(enemy, num);
core.status.route.push(name);
core.replay();
return true;
});
// 商店 // 商店
let shopOpened = false; let shopOpened = false;
let openedShopId = ''; let openedShopId = '';

View File

@ -28,7 +28,7 @@ export function getDetailedEnemy(
) => { ) => {
return typeof func === 'string' ? func : func(enemy); return typeof func === 'string' ? func : func(enemy);
}; };
const special: [string, string, string][] = enemy.info.special const special: [string, string, string][] = [...enemy.info.special]
.filter(v => !enemy.info.specialHalo?.includes(v)) .filter(v => !enemy.info.specialHalo?.includes(v))
.map(vv => { .map(vv => {
const s = Mota.require('var', 'enemySpecials')[vv]; const s = Mota.require('var', 'enemySpecials')[vv];

View File

@ -73,7 +73,7 @@ const detail = ((): [number, string, string][] => {
]; ];
})(); })();
const special = (() => { const special = (() => {
const s = enemy.info.special; const s = [...enemy.info.special];
const fromFunc = ( const fromFunc = (
func: string | ((enemy: EnemyInfo) => string), func: string | ((enemy: EnemyInfo) => string),