refactor: 技能系统

This commit is contained in:
unanmed 2024-11-07 23:43:08 +08:00
parent eca62f5dd0
commit d137068f4f
17 changed files with 235 additions and 86 deletions

View File

@ -38,9 +38,8 @@ main.floors.MT12=
"去南方那个之前过不去的地方推进游戏剧情",
"手机端可以点击右下角的难度来切换下方工具栏至数字键",
{
"type": "setValue",
"name": "flag:skill2",
"value": "true"
"type": "function",
"function": "function(){\nconst HeroSkill = Mota.require('module', 'Mechanism').HeroSkill;\nHeroSkill.learnSkill(HeroSkill.Jump);\n}"
},
{
"type": "hide",

View File

@ -261,6 +261,11 @@ var functions_d6ad677b_427a_4623_b50f_a445a3b0ef8a = {
values[key] = core.clone(core.values[key]);
}
const { NightSpecial, HeroSkill } = Mota.require(
'module',
'Mechanism'
);
// 要存档的内容
var data = {
floorId: core.status.floorId,
@ -273,12 +278,8 @@ var functions_d6ad677b_427a_4623_b50f_a445a3b0ef8a = {
guid: core.getGuid(),
time: new Date().getTime(),
skills: Mota.Plugin.require('skillTree_g').saveSkillTree(),
night: [
...Mota.require(
'module',
'Mechanism'
).NightSpecial.saveNight()
]
night: [...NightSpecial.saveNight()],
skill: HeroSkill.saveSkill()
};
return data;
@ -323,20 +324,49 @@ var functions_d6ad677b_427a_4623_b50f_a445a3b0ef8a = {
core.setFlag('__fromLoad__', true);
Mota.Plugin.require('skillTree_g').loadSkillTree(data.skills);
const Night = Mota.require('module', 'Mechanism').NightSpecial;
const { NightSpecial, HeroSkill } = Mota.require(
'module',
'Mechanism'
);
if (!data.night) {
// 兼容旧版
Night.loadNight([]);
NightSpecial.loadNight([]);
for (const [key, value] of Object.entries(data.hero.flags)) {
if (key.startsWith('night_')) {
const [, floorId] = key.split('_');
Night.addNight(floorId, value);
NightSpecial.addNight(floorId, value);
delete data.hero.flags[key];
}
}
}
if (!data.skill) {
HeroSkill.loadSkill({ autoSkill: true, learned: [] });
if (flags.bladeOn) {
HeroSkill.learnSkill(HeroSkill.Blade);
if (flags.blade) {
HeroSkill.enableSkill(HeroSkill.Blade);
}
delete flags.bladeOn;
delete flags.blade;
}
if (flags.shieldOn) {
HeroSkill.learnSkill(HeroSkill.Shield);
if (flags.shield) {
HeroSkill.enableSkill(HeroSkill.Shield);
}
delete flags.shieldOn;
delete flags.shield;
}
if (flags.skill2) {
HeroSkill.learnSkill(HeroSkill.Jump);
delete flags.skill2;
}
HeroSkill.setAutoSkill(!!flags.autoSkill);
delete flags.autoSkill;
}
// 切换到对应的楼层
core.changeFloor(data.floorId, null, data.hero.loc, 0, function () {
if (core.hasFlag('__bgm__')) {

View File

@ -527,25 +527,26 @@ gameKey
core.actions._clickGameInfo_openComments();
})
.realize('skill1', () => {
if (!flags.bladeOn) return;
if (flags.autoSkill) {
const HeroSkill = Mota.require('module', 'Mechanism').HeroSkill;
if (!HeroSkill.learnedSkill(HeroSkill.Blade)) return;
if (HeroSkill.getAutoSkill()) {
tip('error', '已开启自动切换技能!');
return;
}
core.playSound('光标移动');
if (flags.blade) flags.blade = false;
else flags.blade = true;
core.status.route.push('skill:1');
HeroSkill.toggleSkill(HeroSkill.Blade);
core.status.route.push('skill:Blade');
core.updateStatusBar();
})
.realize('skill2', () => {
const HeroSkill = Mota.require('module', 'Mechanism').HeroSkill;
if (
!flags.chase &&
!flags.onChase &&
!core.status.floorId.startsWith('tower') &&
flags.skill2
HeroSkill.learnedSkill(HeroSkill.Jump)
) {
Mota.Plugin.require('skill_g').jumpSkill();
core.status.route.push('skill:2');
core.status.route.push('skill:Jump');
} else {
if (core.hasItem('pickaxe')) {
core.useItem('pickaxe');
@ -553,15 +554,15 @@ gameKey
}
})
.realize('skill3', () => {
if (!flags.shieldOn) return;
if (flags.autoSkill) {
const HeroSkill = Mota.require('module', 'Mechanism').HeroSkill;
if (!HeroSkill.learnedSkill(HeroSkill.Shield)) return;
if (HeroSkill.getAutoSkill()) {
tip('error', '已开启自动切换技能!');
return;
}
core.playSound('光标移动');
if (flags.shield) flags.shield = false;
else flags.shield = true;
core.status.route.push('skill:3');
HeroSkill.toggleSkill(HeroSkill.Shield);
core.status.route.push('skill:Shield');
core.updateStatusBar();
})
.realize('debug', () => {

View File

@ -383,7 +383,8 @@ function handleActionSetting<T extends number | boolean>(
) {
if (key === 'autoSkill') {
// 自动切换技能
flags.autoSkill = n;
const HeroSkill = Mota.require('module', 'Mechanism').HeroSkill;
HeroSkill.setAutoSkill(n as boolean);
core.status.route.push(`set:autoSkill:${n}`)
}
}
@ -535,8 +536,9 @@ loading.once('coreInit', () => {
const { hook } = Mota.requireAll('var');
hook.on('reset', () => {
const HeroSkill = Mota.require('module', 'Mechanism').HeroSkill;
mainSetting.reset({
'action.autoSkill': flags.autoSkill ?? true
'action.autoSkill': HeroSkill.getAutoSkill()
});
});

View File

@ -8,7 +8,7 @@
},
"blade": {
"text": "1断灭之刃",
"opened": "Mota.Plugin.require('skillTree_g').getSkillLevel(2) > 0",
"opened": "true",
"desc": [
"<span style=\"color: gold\">快捷键1</span>,开启后勇士攻击增加${level:2 * 10}%",
"同时防御减少${level:2 * 10}%。",
@ -19,7 +19,7 @@
},
"jump": {
"text": "2跳跃",
"opened": "flags.skill2 === true",
"opened": "true",
"desc": [
"<span style=\"color: gold\">快捷键2</span>消耗200点生命值困难消耗400点一个地图只能使用3次",
"如果前方为可通行的地面,则不能使用该技能,如果前方为怪物,则将怪物移至勇士视线上第一个不能通行的方块后",
@ -31,7 +31,7 @@
},
"shield": {
"text": "3铸剑为盾",
"opened": "Mota.Plugin.require('skillTree_g').getSkillLevel(10) > 0",
"opened": "true",
"desc": [
"<span style=\"color: gold\">快捷键3</span>,开启后勇士防御增加${level:10 * 10}%",
"同时攻击减少${level:10 * 10}%。",

View File

@ -1,7 +1,7 @@
import { DamageEnemy, ensureFloorDamage, getSingleEnemy } from './damage';
import { findDir, has } from '../../plugin/game/utils';
import { hook, loading } from '../game';
import { NightSpecial } from '../mechanism/misc';
import { HeroSkill, NightSpecial } from '../mechanism/misc';
export interface CurrentEnemy {
enemy: DamageEnemy;
@ -225,12 +225,7 @@ function init() {
'打败 ' + enemy.enemy.name + ',金币+' + money + ',经验+' + exp;
core.drawTip(hint, enemy.id);
if (core.getFlag('bladeOn') && core.getFlag('blade')) {
core.setFlag('blade', false);
}
if (core.getFlag('shieldOn') && core.getFlag('shield')) {
core.setFlag('shield', false);
}
HeroSkill.disableSkill();
// 事件的处理
const todo: MotaEvent = [];

View File

@ -3,7 +3,7 @@ import { Range } from '../util/range';
import { ensureArray, has, manhattan } from '@/plugin/game/utils';
import EventEmitter from 'eventemitter3';
import { hook } from '../game';
import { NightSpecial } from '../mechanism/misc';
import { HeroSkill, NightSpecial } from '../mechanism/misc';
// todo: 光环划分优先级,从而可以实现光环的多级运算
@ -772,27 +772,26 @@ export class DamageEnemy<T extends EnemyIds = EnemyIds> {
private calEnemyDamageOf(hero: Partial<HeroStatus>, enemy: EnemyInfo) {
const status = getHeroStatusOf(hero, realStatus, this.floorId);
let damage = calDamageWith(enemy, status) ?? Infinity;
let skill = -1;
let bestSkill = -1;
// 自动切换技能
if (flags.autoSkill) {
for (let i = 0; i < skills.length; i++) {
const [unlock, condition] = skills[i];
if (!flags[unlock]) continue;
flags[condition] = true;
if (HeroSkill.getAutoSkill()) {
for (const skill of skills) {
if (!HeroSkill.learnedSkill(skill)) continue;
HeroSkill.enableSkill(skill);
const status = getHeroStatusOf(hero, realStatus);
const d = calDamageWith(enemy, status) ?? Infinity;
if (d < damage) {
damage = d;
skill = i;
bestSkill = skill;
}
flags[condition] = false;
HeroSkill.disableSkill();
}
}
return { damage, skill };
return { damage, skill: bestSkill };
}
/**
@ -838,8 +837,11 @@ export class DamageEnemy<T extends EnemyIds = EnemyIds> {
let end = seckill;
let ori = origin.damage;
const status = { atk: curr, def };
const calDam = () => {
return this.calEnemyDamageOf({ atk: curr, def }, enemy).damage;
status.atk = curr;
return this.calEnemyDamageOf(status, enemy).damage;
};
let i = 0;
@ -981,10 +983,7 @@ const realStatus: (keyof HeroStatus)[] = [
/**
*
*/
const skills: [unlock: string, condition: string][] = [
['bladeOn', 'blade'],
['shieldOn', 'shield']
];
const skills: HeroSkill.Skill[] = [HeroSkill.Blade, HeroSkill.Shield];
/**
*

View File

@ -35,7 +35,8 @@ Mota.register('var', 'loading', loading);
Mota.register('module', 'Mechanism', {
BluePalace: miscMechanism.BluePalace,
NightSpecial: miscMechanism.NightSpecial,
MiscData: miscMechanism.MiscData
MiscData: miscMechanism.MiscData,
HeroSkill: miscMechanism.HeroSkill
});
Mota.register('module', 'State', {
ItemState,

View File

@ -14,7 +14,7 @@ export namespace MiscData {
* /
*/
export namespace NightSpecial {
let nightMap = new Map<FloorIds, number>();
const nightMap = new Map<FloorIds, number>();
export function getNight(floor: FloorIds) {
return nightMap.get(floor) ?? 0;
@ -25,12 +25,21 @@ export namespace NightSpecial {
nightMap.set(floor, num + value);
}
export function clearNight(floors: Iterable<FloorIds>) {
for (const floor of floors) {
nightMap.delete(floor);
}
}
export function saveNight() {
return nightMap.entries();
}
export function loadNight(night: IterableIterator<[FloorIds, number]>) {
nightMap = new Map(night);
export function loadNight(night: Iterable<[FloorIds, number]>) {
nightMap.clear();
for (const [floor, num] of night) {
nightMap.set(floor, num);
}
}
export function getAll() {
@ -38,6 +47,86 @@ export namespace NightSpecial {
}
}
export namespace HeroSkill {
export const enum Skill {
None,
/** 断灭之刃 */
Blade,
/** 铸剑为盾 */
Shield,
/** 跳跃 */
Jump
}
export const Blade = Skill.Blade;
export const Shield = Skill.Shield;
export const Jump = Skill.Jump;
interface SkillSave {
autoSkill: boolean;
learned: Skill[];
}
const learned = new Set<Skill>();
let autoSkill = true;
let enabled: Skill = Skill.None;
export function setAutoSkill(auto: boolean) {
autoSkill = auto;
}
export function getAutoSkill() {
return autoSkill;
}
export function learnedSkill(skill: Skill) {
return learned.has(skill);
}
export function learnSkill(skill: Skill) {
learned.add(skill);
}
export function forgetSkill(skill: Skill) {
learned.delete(skill);
}
export function saveSkill(): SkillSave {
return { autoSkill, learned: [...learned] };
}
export function loadSkill(skills: SkillSave) {
learned.clear();
for (const skill of skills.learned) {
learned.add(skill);
}
autoSkill = skills.autoSkill;
}
export function getAll() {
return learned;
}
export function toggleSkill(skill: Skill) {
if (!learned.has(skill)) return;
if (enabled !== skill) enabled = skill;
else enabled = Skill.None;
}
export function enableSkill(skill: Skill) {
if (!learned.has(skill)) return;
enabled = skill;
}
export function disableSkill() {
enabled = Skill.None;
}
export function getEnabled() {
return enabled;
}
}
export namespace BluePalace {
type DoorConvertInfo = [id: AllIds, x: number, y: number];

View File

@ -2,7 +2,7 @@ import { logger } from '@/core/common/logger';
import { EventEmitter } from 'eventemitter3';
import { cloneDeep, isNil } from 'lodash-es';
import { ItemState } from './item';
import { NightSpecial } from '../mechanism/misc';
import { HeroSkill, NightSpecial } from '../mechanism/misc';
/**
*
@ -100,16 +100,16 @@ function getRealStatus(
s += NightSpecial.getNight(floorId);
}
const enabled = HeroSkill.getEnabled();
// 技能
if (flags.bladeOn && flags.blade) {
if (enabled === HeroSkill.Blade) {
const level = getSkillLevel(2);
if (name === 'atk') {
s *= 1 + 0.1 * level;
} else if (name === 'def') {
s *= 1 - 0.1 * level;
}
}
if (flags.shield && flags.shieldOn) {
} else if (enabled === HeroSkill.Shield) {
const level = getSkillLevel(10);
if (name === 'atk') {
s *= 1 - 0.1 * level;

View File

@ -107,6 +107,7 @@ interface ModuleInterface {
BluePalace: typeof misc.BluePalace;
NightSpecial: typeof misc.NightSpecial;
MiscData: typeof misc.MiscData;
HeroSkill: typeof misc.HeroSkill;
};
Effect: {
Portal: typeof portal;

View File

@ -1,3 +1,4 @@
import { HeroSkill } from '@/game/mechanism/misc';
import { upgradeSkill } from './skillTree';
const replayableSettings = ['autoSkill'];
@ -99,15 +100,22 @@ export function init() {
});
function skillAction(skill: string) {
let toEmit = skill;
// 兼容性处理
if (skill === '1') {
if (flags.autoSkill || !flags.bladeOn) return true;
if (flags.blade) flags.blade = false;
else flags.blade = true;
toEmit = 'Blade';
} else if (skill === '2') {
toEmit = 'Jump';
} else if (skill === '3') {
toEmit = 'Shield';
}
if (toEmit === 'Jump') {
if (
!flags.chase &&
!flags.onChase &&
!core.status.floorId.startsWith('tower') &&
flags.skill2
HeroSkill.learnedSkill(HeroSkill.Jump)
) {
Mota.Plugin.require('skill_g').jumpSkill();
} else {
@ -115,10 +123,22 @@ export function init() {
core.useItem('pickaxe');
}
}
} else if (skill === '3') {
if (flags.autoSkill || !flags.shieldOn) return true;
if (flags.shield) flags.shield = false;
else flags.shield = true;
} else {
if (HeroSkill.getAutoSkill()) {
core.replay();
core.updateStatusBar();
return true;
}
let num = HeroSkill.Skill.None;
switch (toEmit) {
case 'Blade':
num = HeroSkill.Blade;
break;
case 'Shield':
num = HeroSkill.Shield;
break;
}
HeroSkill.toggleSkill(num);
}
core.updateStatusBar();
core.replay();

View File

@ -1,5 +1,7 @@
// @ts-nocheck
import { HeroSkill } from '@/game/mechanism/misc';
// 所有的主动技能效果
var ignoreInJump = {
event: ['X20007', 'X20001', 'X20006', 'X20014', 'X20010', 'X20007'],
@ -56,7 +58,7 @@ export function jumpSkill() {
if (jumpIgnoreFloor.has(core.status.floorId) || flags.onChase) {
return core.drawTip('当前楼层无法使用该技能');
}
if (!flags.skill2) return;
if (!HeroSkill.learnedSkill(HeroSkill.Jump)) return;
if (!flags['jump_' + core.status.floorId])
flags['jump_' + core.status.floorId] = 0;
if (core.status.floorId == 'MT14') {

View File

@ -1,3 +1,5 @@
import { HeroSkill } from '@/game/mechanism/misc';
let levels: number[] = [];
export type Chapter = 'chapter1' | 'chapter2';
@ -263,7 +265,7 @@ export function upgradeSkill(skill: number) {
core.status.hero.mana += 5;
break;
case 2: // 断灭之刃
core.setFlag('bladeOn', true);
HeroSkill.learnSkill(HeroSkill.Blade);
break;
case 3: // 坚韧 +2防御
core.status.hero.def += 2;
@ -287,7 +289,7 @@ export function upgradeSkill(skill: number) {
core.addBuff('def', 0.01);
break;
case 10: // 铸剑为盾
core.setFlag('shieldOn', true);
HeroSkill.learnSkill(HeroSkill.Shield);
break;
case 11: // 学习
core.status.hero.magicDef += 100;

2
src/types/core.d.ts vendored
View File

@ -1424,6 +1424,7 @@ declare const main: Main;
declare const core: CoreMixin;
/**
* @deprecated
*
*/
declare let flags: Flags;
@ -1483,6 +1484,7 @@ declare const plugins_bb40132b_638b_4a9f_b028_d3fe47acc8d1: PluginDeclaration;
interface Window {
core: CoreMixin;
/** @deprecated */
flags: Flags;
hero: HeroStatus;
}

View File

@ -962,9 +962,5 @@ interface HeroStatus {
[k: string]: any;
};
x?: number;
y?: number;
floorId?: FloorIds;
buff: Partial<Record<keyof NumbericHeroStatus, number>>;
}

View File

@ -138,11 +138,13 @@ watch(width, n => (updateStatus.value = !updateStatus.value));
watch(height, n => (updateStatus.value = !updateStatus.value));
watch(fontSize, n => (main.style.fontSize = `${isMobile ? n * 1.5 : n}%`));
const HeroSkill = Mota.require('module', 'Mechanism').HeroSkill;
const hero = shallowReactive<Partial<HeroStatus>>({});
const keys = shallowReactive<number[]>([]);
const floor = ref<string>();
const lvName = ref<string>();
const skill = ref<string>(flags.autoSkill ? '自动切换' : '无');
const skill = ref<string>(HeroSkill.getAutoSkill() ? '自动切换' : '无');
const up = ref(0);
const spring = ref<number>();
const skillOpened = ref(core.getFlag('chapter', 0) > 0);
@ -150,7 +152,7 @@ const jumpCnt = ref<number>();
/**
* 要展示的勇士属性
*/
const toShow: (keyof NumbericHeroStatus)[] = [
const toShow: (keyof HeroStatus)[] = [
'hp', //
'atk', //
'def', //
@ -177,17 +179,24 @@ function update() {
keys[2] = core.itemCount('redKey');
floor.value = core.status.thisMap?.title;
lvName.value = core.getLvName(hero.lv);
if (flags.autoSkill) {
if (HeroSkill.getAutoSkill()) {
skill.value = '自动切换';
} else {
if (flags.blade && flags.bladeOn) {
skill.value = '断灭之刃';
} else if (flags.shield && flags.shieldOn) {
skill.value = '铸剑为盾';
} else {
skill.value = '无';
const enabled = HeroSkill.getEnabled();
switch (enabled) {
case HeroSkill.Blade:
skill.value = '断灭之刃';
break;
case HeroSkill.Shield:
skill.value = '铸剑为盾';
break;
default:
skill.value = '无';
break;
}
}
up.value = core.getNextLvUpNeed() ?? 0;
if (core.hasFlag('spring')) {
spring.value = 50 - (flags.springCount ?? 0);
@ -195,8 +204,9 @@ function update() {
spring.value = void 0;
}
skillOpened.value = core.getFlag('chapter', 0) > 0;
jumpCnt.value =
flags.skill2 &&
HeroSkill.learnedSkill(HeroSkill.Jump) &&
!Mota.Plugin.require('skill_g').jumpIgnoreFloor.has(core.status.floorId)
? 3 - (flags[`jump_${core.status.floorId}`] ?? 0)
: void 0;