重构怪物属性定义

This commit is contained in:
AncTe committed 2023-08-07 17:57:51 +08:00
1 parent 93fad2f637
commit 9bab089a14
18 files changed
+250 -610

No files matched your search

+4
View File
@@ -326,6 +326,8 @@ function handleScreenSetting<T extends number | boolean>(
// 字体大小
core.setLocalStorage('fontSize', n);
root.style.fontSize = root2.style.fontSize = `${n}px`;
} else if (key === 'smoothView') {
core.setLocalStorage('smoothView', n);
}
}
@@ -370,6 +372,7 @@ mainSetting
.register('antiAlias', '抗锯齿', false)
.register('autoScale', '自动放缩', true)
.register('fontSize', '字体大小', 16, [8, 28, 1])
.register('smoothView', '平滑镜头', true)
)
.register(
'action',
@@ -397,6 +400,7 @@ loading.once('coreInit', () => {
'screen.antiAlias': !!core.getLocalStorage('antiAlias', false),
'screen.autoScale': !!core.getLocalStorage('autoScale', true),
'screen.fontSize': core.getLocalStorage('fontSize', 16),
'screen.smoothView': !!core.getLocalStorage('smoothView', true),
'action.fixed': !!core.getLocalStorage('fixed', true),
'utils.betterLoad': !!core.getLocalStorage('betterLoad', true)
});
+1 -1
View File
@@ -75,7 +75,7 @@ export {};
const fns = before[mod];
for (const id in fns) {
const fn = fns[id];
if (typeof fn !== 'function' || id === 'hasSpecial') continue;
if (typeof fn !== 'function') continue;
const now = after[mod][id];
if (fn.toString() !== now.toString()) {
try {
+4 -4
View File
@@ -96,7 +96,7 @@ core.events.afterBattle = function (
core.status.hero.statistics.battle++;
// 智慧之源
if (core.hasSpecial(special, 14) && flags.hard === 2) {
if (special.includes(14) && flags.hard === 2) {
core.addFlag(
'inte_' + floorId,
Math.ceil((core.status.hero.mdef / 10) * 0.3) * 10
@@ -106,11 +106,11 @@ core.events.afterBattle = function (
}
// 极昼永夜
if (core.hasSpecial(special, 22)) {
if (special.includes(22)) {
flags[`night_${floorId}`] ??= 0;
flags[`night_${floorId}`] -= enemy.enemy.night!;
}
if (core.hasSpecial(special, 23)) {
if (special.includes(23)) {
flags[`night_${floorId}`] ??= 0;
flags[`night_${floorId}`] += enemy.enemy.day;
}
@@ -120,7 +120,7 @@ core.events.afterBattle = function (
// }
// 如果是融化怪,需要特殊标记一下
if (core.hasSpecial(special, 25) && core.has(x) && core.has(y)) {
if (special.includes(25) && core.has(x) && core.has(y)) {
flags[`melt_${floorId}`] ??= {};
flags[`melt_${floorId}`][`${x},${y}`] = enemy.enemy.melt;
}
+2
View File
@@ -1,5 +1,7 @@
///<reference path="../../../../src/types/core.d.ts" />
// todo: 优化,直接调用 floor.enemy.list 进行计算
/**
* 检查漏怪
* @param {FloorIds[]} floorIds
+212
View File
@@ -0,0 +1,212 @@
import { getHeroStatusOn } from '../hero';
export interface SpecialDeclaration {
code: number;
name: string | ((enemy: Enemy) => string);
desc: string | ((enemy: Enemy) => string);
color: string;
}
export const enemySpecials: SpecialDeclaration[] = [
{
code: 0,
name: '空',
desc: '空',
color: '#fff'
},
{
code: 1,
name: '致命一击',
desc: enemy => `怪物每5回合触发一次强力攻击,造成${enemy.crit}%的伤害`,
color: '#fc3'
},
{
code: 2,
name: '恶毒',
desc: '怪物攻击无视勇士的防御',
color: '#bbb0ff'
},
{
code: 3,
name: '坚固',
desc: '怪物防御不小于勇士攻击-1',
color: '#c0b088'
},
{
code: 4,
name: '2连击',
desc: '怪物每回合攻击2次',
color: '#fe7'
},
{
code: 5,
name: '3连击',
desc: '怪物每回合攻击3次',
color: '#fe7'
},
{
code: 6,
name: enemy => `${enemy.n}连击`,
desc: enemy => `怪物每回合攻击${enemy.n}次`,
color: '#fe7'
},
{
code: 7,
name: '饥渴',
desc: enemy =>
`战斗前,怪物降低勇士${enemy.hungry}%的攻击,并加在自己身上`,
color: '#b67'
},
{
code: 8,
name: '抱团',
desc: enemy =>
`怪物周围5×5范围内每有一个拥有该属性的怪物,自身攻防就增加${enemy.together}%(线性叠加)`,
color: '#fa4'
},
{
code: 9,
name: '绝对防御',
desc: '怪物的奇特护甲可以让勇士的额外攻击失效,攻击变为基础攻击+额外攻击',
color: '#80eed6'
},
{
code: 10,
name: '勇气之刃',
desc: enemy => `怪物第一回合造成${enemy.courage}%的伤害`,
color: '#b0c0dd'
},
{
code: 11,
name: '勇气冲锋',
desc: enemy =>
`怪物首先攻击,造成${enemy.charge}%的伤害,并眩晕勇士5回合`,
color: '#ff00d2'
},
{
code: 12,
name: '追猎',
desc: '当勇士移动到该怪物的水平或竖直方向上时,怪物向勇士移动一格',
color: '#9e8'
},
{
code: 13,
name: '魔攻',
desc: '怪物攻击无视勇士的防御',
color: '#bbb0ff'
},
{
code: 14,
name: '智慧之源',
desc: '困难难度下(简单难度没有效果),战斗后,怪物会吸取勇士30%的智慧(勇士智慧向下取整至整十)加在本层的拥有该属性的怪物攻击上',
color: '#bbeef0'
},
{
code: 15,
name: '突刺',
desc: enemy =>
`勇士走到怪物怪物周围四格时,怪物对勇士造成${core.formatBigNumber(
Math.max((enemy.value || 0) - getHeroStatusOn('def'))
)}点伤害`,
color: '#c677dd'
},
{
code: 16,
name: '空',
desc: '空',
color: '#fff'
},
{
code: 17,
name: '先攻',
desc: '战斗时,怪物首先攻击',
color: '#b0b666'
},
{
code: 18,
name: '阻击',
desc: enemy =>
`经过怪物十字范围内时怪物后退一格,同时对勇士造成${enemy.value}点伤害`,
color: '#8888e6'
},
{
code: 19,
name: '电摇嘲讽',
desc:
'当勇士移动到怪物同行或同列时,勇士会直接冲向怪物,撞碎路上的所有地形和门,拾取路上的道具,与路上的怪物战斗' +
',最后与该怪物战斗',
color: '#ff6666'
},
{
code: 20,
name: '霜冻',
desc: enemy =>
`怪物寒冷的攻击使勇士动作变慢,勇士每回合对怪物造成的伤害减少${enemy.ice}%。装备杰克的衣服后可以免疫。`,
color: 'cyan'
},
{
code: 21,
name: '冰封光环',
desc: enemy =>
`寒气逼人,使勇士对该怪物周围7*7范围内的怪物伤害减少${enemy.iceHalo}%(线性叠加)`,
color: 'cyan'
},
{
code: 22,
name: '永夜',
desc: enemy =>
`战斗后,减少勇士${enemy.night}点攻防,增加本层所有怪物${enemy.night}点攻防,仅在本层有效`,
color: '#d8a'
},
{
code: 23,
name: '极昼',
desc: enemy =>
`战斗后,减少本层所有怪物${enemy.day}点攻防,增加勇士${enemy.day}点攻防,仅在本层有效`,
color: '#ffd'
},
{
code: 24,
name: '射击',
desc: function () {
return '经过怪物同行或同列的可视范围内时受到一次普通攻击的伤害';
},
color: '#dda0dd'
},
{
code: 25,
name: '融化',
desc: enemy =>
`战斗后该怪物会融化,在怪物位置产生一个3*3的范围光环,光环内怪物的攻防增加${enemy.melt}%`,
color: '#e6e099'
},
{
code: 26,
name: '冰封之核',
desc: enemy =>
`怪物拥有逼人的寒气,使周围5*5范围内的怪物防御增加${enemy.iceCore}%`,
color: '#70ffd1'
},
{
code: 27,
name: '火焰之核',
desc: enemy =>
`怪物拥有灼热的火焰,使周围5*5范围内的怪物攻击增加${enemy.fireCore}%`,
color: '#ff6f0a'
},
{
code: 28,
name: '苍蓝刻',
desc: enemy =>
`怪物使用苍蓝之灵的力量,使自身受到的伤害减少${enemy.paleShield}%`,
color: '#ff6f0a'
}
];
declare global {
interface PluginDeclaration {
special: SpecialDeclaration[];
}
}
core.plugin.special = enemySpecials;
-15
View File
@@ -22,21 +22,6 @@ export function canStudySkill(number: number) {
export function studySkill(enemy: any, number: number) {
core.status.hero.special ??= { num: [], last: [] };
const s = core.status.hero.special;
const specials = core.getSpecials();
let special = specials[number - 1][1];
if (special instanceof Function) special = special(enemy);
if (!canStudySkill(number)) {
if (!main.replayChecking) {
ancTe.plugin.utils.tip('error', `无法学习${special}`);
}
return;
}
s.num.push(number);
s.last.push(core.plugin.skillTree.getSkillLevel(11) * 3 + 2);
const value = values[number] ?? [];
for (const key of value) {
s[key] = enemy[key];
}
}
export function forgetStudiedSkill(num: number, i: number) {
+4 -13
View File
@@ -56,15 +56,6 @@ export function getDetailedEnemy(
enemy: DamageEnemy,
floorId: FloorIds = core.status.floorId
): ToShowEnemy {
const specials = Object.fromEntries(
core.getSpecials().map(v => {
return [v[0], v.slice(1)];
})
) as Record<
string,
EnemySpecialDeclaration extends [number, ...infer F] ? F : never
>;
const ratio = core.status.maps[floorId].ratio;
const dam = enemy.calDamage().damage;
@@ -81,11 +72,11 @@ export function getDetailedEnemy(
return typeof func === 'string' ? func : func(enemy);
};
const special: [string, string, string][] = enemy.enemy.special.map(vv => {
const s = specials[vv];
const s = core.plugin.special[vv];
return [
fromFunc(s[0], enemy.enemy),
fromFunc(s[1], enemy.enemy),
s[2] as string
fromFunc(s.name, enemy.enemy),
fromFunc(s.desc, enemy.enemy),
s.color as string
];
});
const l = isMobile ? 1 : 2;
+1 -79
View File
@@ -242,7 +242,7 @@ interface BookEnemyInfo extends Enemy, EnemyInfo {
/**
* 怪物模块
*/
interface Enemys extends EnemyData {
interface Enemys {
/**
* 所有的怪物信息
*/
@@ -250,11 +250,6 @@ interface Enemys extends EnemyData {
[P in EnemyIds]: Enemy<P>;
};
/**
* 脚本编辑的怪物相关
*/
readonly enemydata: EnemyData;
/**
* 获得所有怪物原始数据的一个副本
*/
@@ -262,51 +257,6 @@ interface Enemys extends EnemyData {
[P in EnemyIds]: Enemy<P>;
};
/**
* 获得某种敌人的全部特殊属性名称
* @example core.getSpecialText('greenSlime') // ['先攻', '3连击', '破甲', '反击']
* @param enemy 敌人id或敌人对象,如core.material.enemys.greenSlime
* @returns 字符串数组
*/
getSpecialText(enemy: EnemyIds | Enemy): string[];
/**
* 获得所有特殊属性的颜色
* @param enemy 敌人id或敌人对象,如core.material.enemys.greenSlime
*/
getSpecialColor(enemy: EnemyIds | Enemy): Color[];
/**
* 获得所有特殊属性的额外标记
* @param enemy 敌人id或敌人对象,如core.material.enemys.greenSlime
*/
getSpecialFlag(enemy: EnemyIds | Enemy): number[];
/**
* 获得某种敌人的某种特殊属性的介绍
* @example core.getSpecialHint('bat', 1) // '先攻:怪物首先攻击'
* @param enemy 敌人id或敌人对象,用于确定属性的具体数值
* @param special 属性编号,可以是该敌人没有的属性
* @returns 属性的介绍,以属性名加中文冒号开头
*/
getSpecialHint(enemy: EnemyIds | Enemy, special: number): string;
/**
* 获得某个敌人的某项属性值
* @param enemy 敌人id或敌人对象
* @param name 获取的敌人属性
* @param x 敌人的横坐标
* @param y 敌人的纵坐标
* @param floorId 敌人所在楼层
*/
getEnemyValue<K extends keyof Enemy>(
enemy: EnemyIds | Enemy,
name: K,
x?: number,
y?: number,
floorId?: FloorIds
): Enemy[K];
/**
* 判定主角当前能否打败某只敌人
* @example core.canBattle('greenSlime',0,0,'MT0') // 能否打败主塔0层左上角的绿头怪(假设有)
@@ -322,34 +272,6 @@ interface Enemys extends EnemyData {
floorId?: FloorIds,
dir?: Dir | 'none' | (Dir | 'none')[]
): boolean;
/**
* 获得某只敌人对主角的总伤害
* @example core.getDamage('greenSlime',0,0,'MT0') // 绿头怪的总伤害
* @param enemy 敌人id或敌人对象
* @param x 敌人的横坐标
* @param y 敌人的纵坐标
* @param floorId 敌人所在的地图
* @returns 总伤害,如果因为没有破防或无敌怪等其他原因无法战斗,则返回null
*/
getDamage(
enemy: EnemyIds | Enemy,
x?: number,
y?: number,
floorId?: FloorIds
): number;
/**
* 检查某些楼层是否还有漏打的(某种)敌人
* @example core.hasEnemyLeft('greenSlime', ['sample0', 'sample1']) // 样板0层和1层是否有漏打的绿头怪
* @param enemyId 敌人id,可选,默认为任意敌人
* @param floorId 地图id或其数组,可选,默认为当前地图
* @returns true表示有敌人被漏打,false表示敌人已死光
*/
hasEnemyLeft(
enemyId?: EnemyIds | EnemyIds[],
floorId?: FloorIds | FloorIds[]
): boolean;
}
declare const enemys: new () => Enemys;
-24
View File
@@ -52,25 +52,6 @@ interface ControlData {
parallelDo(time: number): void;
}
interface EnemyData {
/**
* 获得所有特殊属性定义
*/
getSpecials(): EnemySpecialDeclaration[];
/**
* 判定某种特殊属性的有无
* @example core.hasSpecial('greenSlime', 1) // 判定绿头怪有无先攻属性
* @param special 敌人id或敌人对象或正整数数组或自然数
* @param test 待检查的属性编号
* @returns 若special为数组或数且含有test或相等、或special为敌人id或对象且具有此属性,则返回true
*/
hasSpecial(
special: number | number[] | EnemyIds | Enemy,
test: number
): boolean;
}
interface UiData {
/**
* 数据统计界面统计的道具数量
@@ -184,11 +165,6 @@ interface FunctionsData {
*/
control: ControlData;
/**
* 怪物信息
*/
enemys: EnemyData;
/**
* ui信息
*/
-10
View File
@@ -48,22 +48,12 @@ import { LeftOutlined } from '@ant-design/icons-vue';
import { KeyCode } from '../plugin/keyCodes';
import { noClosePanel } from '../plugin/uiController';
import { ToShowEnemy, detailInfo } from '../plugin/ui/book';
import { isMobile } from '../plugin/use';
import { getDetailedEnemy } from '../plugin/ui/fixed';
const floorId =
// @ts-ignore
core.floorIds[core.status.event?.ui?.index] ?? core.status.floorId;
const specials = Object.fromEntries(
core.getSpecials().map(v => {
return [v[0], v.slice(1)];
})
) as Record<
string,
EnemySpecialDeclaration extends [number, ...infer F] ? F : never
>;
const enemy = core.getCurrentEnemys(floorId);
const toShow: ToShowEnemy[] = enemy.map(v =>
getDetailedEnemy(v.enemy, floorId)
+1
View File
@@ -154,6 +154,7 @@ async function clickStartButton(id: string) {
}
function onmove(e: MouseEvent) {
if (!window.core) return;
const { offsetX, offsetY } = e;
const ele = e.target as HTMLDivElement;
const style = getComputedStyle(ele);
+5 -38
View File
@@ -10,26 +10,11 @@
>
<Scroll :no-scroll="true" style="height: 100%">
<div id="studied-main">
<div v-for="(num, i) of studied" :key="i">
<div id="studied-rough">
<right-outlined
:class="folded[i] ? 'folded' : ''"
@click="folded[i] = !folded[i]"
id="studied-fold"
/>
<span
>{{ i }}. {{ skills[i] }},剩余{{
last[i]
}}场战斗</span
>
</div>
<div id="studied-detail" v-if="!folded[i]">
{{ hint(num) }}
</div>
</div>
</div></Scroll
></Box
>
<div
v-for="(num, i) of studied"
:key="i"
></div></div></Scroll
></Box>
</div>
</template>
@@ -61,24 +46,6 @@ const last = computed(() => {
return core.status.hero.special?.last ?? [];
});
const skills = computed(() => {
const specials = core.getSpecials();
return studied.value.map(v => {
const s = specials[v - 1][1];
// @ts-ignore
if (s instanceof Function) return s(core.status.hero.special);
else return s;
});
});
function hint(number: number) {
const specials = core.getSpecials();
const s = specials[number - 1][2];
// @ts-ignore
if (s instanceof Function) return s(core.status.hero.special);
else return s;
}
async function calHeight() {
await new Promise<void>(resolve => {
requestAnimationFrame(() => {