diff --git a/public/libs/control.js b/public/libs/control.js index b64cbfb..aaf6793 100644 --- a/public/libs/control.js +++ b/public/libs/control.js @@ -3056,14 +3056,7 @@ control.prototype.getStatus = function (name) { if (main.mode == 'editor' && !core.hasFlag('__statistics__')) { return data_a1e2fb4a_e986_4524_b0da_9b7ba7c0874d.firstData.hero[name]; } - if (name === 'atk' || name === 'def') { - return ( - core.status.hero[name] + - (window.flags?.[`night_${core.status.floorId}`] ?? 0) - ); - } else { - return core.status.hero[name]; - } + return core.status.hero[name]; }; ////// 从status中获得属性,如果不存在则从勇士属性中获取 ////// @@ -3079,9 +3072,7 @@ control.prototype.getRealStatus = function (name) { ////// 从status中获得实际属性(增幅后的),如果不存在则从勇士属性中获取 ////// control.prototype.getRealStatusOrDefault = function (status, name) { - return Math.floor( - this.getStatusOrDefault(status, name) * this.getBuff(name) - ); + return core.getHeroStatusOf(status, name); }; ////// 获得勇士原始属性(无装备和衰弱影响) ////// diff --git a/public/libs/enemys.js b/public/libs/enemys.js index 493f541..24737c9 100644 --- a/public/libs/enemys.js +++ b/public/libs/enemys.js @@ -517,6 +517,7 @@ enemys.prototype._getDamage = function (enemy, hero, x, y, floorId) { if (typeof enemy == 'string') enemy = core.material.enemys[enemy]; if (enemy == null) return null; + if (x === 9 && y === 3) debugger; var info = this.getDamageInfo(enemy, hero, x, y, floorId); if (info == null) return null; if (typeof info == 'number') return info; diff --git a/public/project/data.js b/public/project/data.js index f42e2d3..3e907cc 100644 --- a/public/project/data.js +++ b/public/project/data.js @@ -282,7 +282,7 @@ var data_a1e2fb4a_e986_4524_b0da_9b7ba7c0874d = "statusLeftBackground": "url(project/images/cave1.jpg)", "statusTopBackground": "url(project/images/cave2.jpg) no-repeat", "toolsBackground": "url(project/images/cave2.jpg) no-repeat", - "floorChangingStyle": "background-color: #000000;color:#000000", + "floorChangingStyle": " ", "statusBarColor": [ 255, 255, diff --git a/public/project/functions.js b/public/project/functions.js index 8e7d143..3f07167 100644 --- a/public/project/functions.js +++ b/public/project/functions.js @@ -61,7 +61,6 @@ var functions_d6ad677b_427a_4623_b50f_a445a3b0ef8a = { // 游戏获胜事件 // 请注意,成绩统计时是按照hp进行上传并排名 // 可以先在这里对最终分数进行计算,比如将2倍攻击和5倍黄钥匙数量加到分数上 - // core.status.hero.hp += 2 * core.getRealStatus('atk') + 5 * core.itemCount('yellowKey'); // 如果不退出,则临时存储数据 if (noexit) { @@ -648,11 +647,7 @@ var functions_d6ad677b_427a_4623_b50f_a445a3b0ef8a = { core.formatBigNumber( Math.max( (enemy.value || 0) - - core.getRealStatusOrDefault( - null, - 'def' - ), - 0 + core.getHeroStatusOn('def') ) ) + '点伤害' @@ -762,10 +757,19 @@ var functions_d6ad677b_427a_4623_b50f_a445a3b0ef8a = { // floorId:该怪物所在的楼层 // 后面三个参数主要是可以在光环等效果上可以适用(也可以按需制作部分范围光环效果) floorId = floorId || core.status.floorId; - var hero_hp = core.getRealStatusOrDefault(hero, 'hp'), - hero_atk = core.getRealStatusOrDefault(hero, 'atk'), - hero_def = core.getRealStatusOrDefault(hero, 'def'), - hero_mdef = core.getRealStatusOrDefault(hero, 'mdef'); + + let { + atk: hero_atk, + def: hero_def, + mdef: hero_mdef, + hp: hero_hp + } = core.getHeroStatusOf( + hero, + ['atk', 'def', 'mdef', 'hp'], + hero?.x, + hero?.y, + floorId + ); var mon_hp = core.getEnemyValue(enemy, 'hp', x, y, floorId), mon_atk = core.getEnemyValue(enemy, 'atk', x, y, floorId), @@ -793,7 +797,7 @@ var functions_d6ad677b_427a_4623_b50f_a445a3b0ef8a = { } // 智慧之源 - if (core.hasSpecial(mon_special, 14) && flags.hard == 2) { + if (core.hasSpecial(mon_special, 14) && flags.hard === 2) { mon_atk += core.getFlag('inte_' + floorId, 0); } @@ -906,13 +910,6 @@ var functions_d6ad677b_427a_4623_b50f_a445a3b0ef8a = { mon_def *= 1 + def_buff / 100; } - // TODO:可以在这里新增其他的怪物数据变化 - // 比如仿攻(怪物攻击不低于勇士攻击): - // if (core.hasSpecial(mon_special, 27) && mon_atk < hero_atk) { - // mon_atk = hero_atk; - // } - // 也可以按需增加各种自定义内容 - return { hp: Math.floor(mon_hp), atk: Math.floor(mon_atk), @@ -936,19 +933,62 @@ var functions_d6ad677b_427a_4623_b50f_a445a3b0ef8a = { // 后面三个参数主要是可以在光环等效果上可以适用 floorId = floorId || core.status.floorId; - function getDamage() { - let hero_hp = core.getRealStatusOrDefault(hero, 'hp'), - hero_atk = core.getRealStatusOrDefault(hero, 'atk'), - hero_def = core.getRealStatusOrDefault(hero, 'def'), - hero_IQ = core.getRealStatusOrDefault(hero, 'mdef'), - hero_recovery = core.getRealStatusOrDefault(hero, 'hpmax'), - hero_extraAtk = core.getRealStatusOrDefault(hero, 'mana'), - origin_hero_hp = core.getStatusOrDefault(hero, 'hp'), - origin_hero_atk = core.getStatusOrDefault(hero, 'atk'), - origin_hero_def = core.getStatusOrDefault(hero, 'def'); + // 勇士位置应该在这里进行计算,四个位置依次遍历,去重 + let toMap = []; + if ( + x !== null && + x !== void 0 && + y !== null && + y !== void 0 && + floorId !== null && + floorId !== void 0 && + flags.autoLocate && + flags.chapter >= 2 + ) { + const floor = core.status.maps[floorId]; + // 存在坐标,进行遍历 + for (const [dir, { x: dx, y: dy }] of Object.entries( + core.utils.scan + )) { + // 只有攻击和防御和特殊光环需要注意,其他的一般都不会随楼层与坐标变化 + const nx = x + dx; + const ny = y + dy; + if ( + nx < 0 || + nx >= floor.width || + ny < 0 || + ny >= floor.height + ) { + continue; + } + if ( + core.noPass(nx, ny) || + !core.canMoveHero(nx, ny, core.backDir(dir), floorId) + ) { + continue; + } + const toGet = ['atk', 'def']; + const status = core.getHeroStatusOf( + hero, + toGet, + x, + y, + floorId + ); + if ( + toMap.some(v => + toGet.every(vv => v[1][vv] === status[vv]) + ) + ) { + continue; + } + toMap.push([dir, Object.assign({}, status, { x, y })]); + } + } else { + toMap = [['none', core.getHeroStatusOf(hero, ['atk', 'def'])]]; + } - // 怪物的各项数据 - // 对坚固模仿等处理扔到了脚本编辑-getEnemyInfo之中 + function getDamage(h) { const enemyInfo = core.enemys.getEnemyInfo( enemy, hero, @@ -957,10 +997,18 @@ var functions_d6ad677b_427a_4623_b50f_a445a3b0ef8a = { floorId ); - let mon_hp = enemyInfo.hp, - mon_atk = enemyInfo.atk, - mon_def = enemyInfo.def, - mon_special = enemyInfo.special; + let { + hp: mon_hp, + atk: mon_atk, + def: mon_def, + special: mon_special + } = enemyInfo; + let { atk: hero_atk, def: hero_def } = h; + + let hero_hp = core.getRealStatusOrDefault(hero, 'hp'), + hero_IQ = core.getRealStatusOrDefault(hero, 'mdef'), + hero_recovery = core.getRealStatusOrDefault(hero, 'hpmax'), + hero_extraAtk = core.getRealStatusOrDefault(hero, 'mana'); let damage = 0; @@ -1045,52 +1093,6 @@ var functions_d6ad677b_427a_4623_b50f_a445a3b0ef8a = { turn += 5; } - // ------ 支援 ----- // - // 这个递归最好想明白为什么,flag:__extraTurn__是怎么用的 - const guards = core.getFlag( - '__guards__' + x + '_' + y, - enemyInfo.guards - ); - const guard_before_current_enemy = true; // ------ 支援怪是先打(true)还是后打(false)? - turn += core.getFlag('__extraTurn__', 0); - if (guards.length > 0) { - if (!guard_before_current_enemy) { - // --- 先打当前怪物,记录当前回合数 - core.setFlag('__extraTurn__', turn); - } - // 获得那些怪物组成小队战斗 - for (var i = 0; i < guards.length; i++) { - var gx = guards[i][0], - gy = guards[i][1], - gid = guards[i][2]; - // 递归计算支援怪伤害信息,这里不传x,y保证不会重复调用 - // 这里的mdef传0,因为护盾应该只会被计算一次 - var info = core.enemys.getDamageInfo( - core.material.enemys[gid], - { - hp: origin_hero_hp, - atk: origin_hero_atk, - def: origin_hero_def, - mdef: 0 - } - ); - if (info == null) { - // 小队中任何一个怪物不可战斗,直接返回null - core.removeFlag('__extraTurn__'); - return null; - } - // 已经进行的回合数 - core.setFlag('__extraTurn__', info.turn); - init_damage += info.damage; - } - if (guard_before_current_enemy) { - // --- 先打支援怪物,增加当前回合数 - turn += core.getFlag('__extraTurn__', 0); - } - } - core.removeFlag('__extraTurn__'); - // ------ 支援END ------ // - // 最终伤害:初始伤害 + 怪物对勇士造成的伤害 + 反击伤害 damage += init_damage + (turn - 1) * per_damage; // 无上之盾 @@ -1113,34 +1115,55 @@ var functions_d6ad677b_427a_4623_b50f_a445a3b0ef8a = { }; } - let damageInfo = null; - let damage = Infinity; - const skills = [ ['bladeOn', 'blade'], ['shieldOn', 'shield'] ]; - damageInfo = getDamage(); - if (damageInfo) damage = damageInfo.damage; - if (flags.autoSkill) { - for (const [unlock, condition] of skills) { - if (flags[unlock]) { - flags[condition] = true; - const info = getDamage(); - const d = info?.damage; - if (d !== null && d !== void 0) { - if (d < damage) { - damage = d; - damageInfo = info; + function autoSkillOf(h) { + if (flags.autoSkill) { + for (const [unlock, condition] of skills) { + if (flags[unlock]) { + flags[condition] = true; + const info = getDamage(h); + const d = info?.damage; + if (d !== null && d !== void 0) { + if (d < damage) { + damage = d; + damageInfo = info; + } } + flags[condition] = false; } - flags[condition] = false; } + } else { + damageInfo = getDamage(h); + if (damageInfo) damage = damageInfo.damage; } + } + + let damageInfo = null; + let damage = Infinity; + + if (!flags.autoLocate) { + autoSkillOf(toMap[0][1]); return damageInfo; + } + + if (toMap.length === 1) { + // 单个与多个分开计算,有助于提高性能表现 + const h = toMap[0][1]; + autoSkillOf(h); + if (damageInfo) { + return Object.assign(damageInfo, { dir: toMap[0][0] }); + } else return null; } else { - return getDamage(); + for (const [dir, h] of toMap) { + autoSkillOf(h); + if (damageInfo) { + return Object.assign(damageInfo, { dir }); + } else return null; + } } } }, diff --git a/public/project/plugins.js b/public/project/plugins.js index 150b4c1..902db9a 100644 --- a/public/project/plugins.js +++ b/public/project/plugins.js @@ -1416,7 +1416,7 @@ var plugins_bb40132b_638b_4a9f_b028_d3fe47acc8d1 = { // 获取宝石信息 并绘制 this.getItemDetail = function (floorId) { if (!core.getFlag('itemDetail')) return; - floorId = floorId ?? core.status.thisMap.floorId; + floorId ??= core.status.thisMap.floorId; let diff = {}; const before = core.status.hero; const hero = core.clone(core.status.hero); @@ -4306,24 +4306,6 @@ var plugins_bb40132b_638b_4a9f_b028_d3fe47acc8d1 = { } }; - /** - * 滑动数组 - * @param {any[]} arr - * @param {number} delta - */ - this.slide = function (arr, delta) { - if (delta === 0) return arr; - delta %= arr.length; - if (delta > 0) { - arr.unshift(...arr.splice(arr.length - delta, delta)); - return arr; - } - if (delta < 0) { - arr.push(...arr.splice(0, -delta)); - return arr; - } - }; - /** * 移动地图 * @param {number} delta @@ -4642,5 +4624,92 @@ var plugins_bb40132b_638b_4a9f_b028_d3fe47acc8d1 = { } ctx.restore(); }; + }, + hero: function () { + /** + * 获取勇士在某一点的属性 + * @param {keyof HeroStatus | 'all'} name + * @param {number} x + * @param {number} y + * @param {FloorIds} floorId + */ + this.getHeroStatusOn = function (name, x, y, floorId) { + return this.getRealStatusOf(core.status.hero, name, x, y, floorId); + }; + + this.getHeroStatusOf = function (status, name, x, y, floorId) { + return getRealStatus(status, name, x, y, floorId); + }; + + function getRealStatus(status, name, x, y, floorId) { + if (name instanceof Array) { + return Object.fromEntries( + name.map(v => [ + v, + v !== 'all' && getRealStatus(status, v, x, y, floorId) + ]) + ); + } + + if (name === 'all') { + return Object.fromEntries( + Object.keys(core.status.hero).map(v => [ + v, + v !== 'all' && getRealStatus(status, v, x, y, floorId) + ]) + ); + } + + let s = status?.[name] ?? core.status.hero[name]; + if (s === null || s === void 0) { + throw new ReferenceError( + `Wrong hero status property name is delivered: ${name}` + ); + } + + x ??= core.status.hero.loc.x; + y ??= core.status.hero.loc.y; + floorId ??= core.status.floorId; + + // 永夜、极昼 + if (name === 'atk' || name === 'def') { + s += window.flags?.[`night_${floorId}`] ?? 0; + } + + // buff + if (typeof s === 'number') s *= core.getBuff(name); + + // 取整 + if (typeof s === 'number') s = Math.floor(s); + return s; + } + }, + pluginUtils: function () { + /** + * 滑动数组 + * @param {any[]} arr + * @param {number} delta + */ + this.slide = function (arr, delta) { + if (delta === 0) return arr; + delta %= arr.length; + if (delta > 0) { + arr.unshift(...arr.splice(arr.length - delta, delta)); + return arr; + } + if (delta < 0) { + arr.push(...arr.splice(0, -delta)); + return arr; + } + }; + + this.backDir = function (dir) { + return { + up: 'down', + down: 'up', + left: 'right', + right: 'left' + }[dir]; + }; } }; diff --git a/public/styles.css b/public/styles.css index ff97b3e..36a4f79 100644 --- a/public/styles.css +++ b/public/styles.css @@ -261,7 +261,7 @@ span#hard { position: absolute; text-align: center; display: none; - color: #fff; + color: transparent; background-color: #000; z-index: 230; user-select: none; diff --git a/src/data/settings.json b/src/data/settings.json index 5498f32..e5e9625 100644 --- a/src/data/settings.json +++ b/src/data/settings.json @@ -43,6 +43,13 @@ "注:当鼠标移动到怪物上时,经过200毫秒才会显示信息,防止误操作。" ] }, + "autoLocate": { + "text": "自动勇士定位", + "desc": [ + "此项会在进入第二章后会起作用。开启后,当勇士处于不同位置打同一个怪物伤害不同时,在地图上使用绿色箭头标出伤害最低的位置,", + "使用红色箭头标出伤害较高的位置,在自动寻路中选择伤害最低的位置。" + ] + }, "showStudied": { "text": "展示已学习技能", "desc": [ diff --git a/src/plugin/settings.ts b/src/plugin/settings.ts index 71dd2b6..0dba7ec 100644 --- a/src/plugin/settings.ts +++ b/src/plugin/settings.ts @@ -35,6 +35,11 @@ export const showStudied = ref(true); */ export const useFixed = ref(true); +/** + * 是否使用勇士自动定位功能 + */ +export const autoLocate = ref(true); + watch(transition, n => { core.plugin.transition.value = n; core.setLocalStorage('transition', n); @@ -67,6 +72,12 @@ watch(useFixed, n => { core.setLocalStorage('useFixed', n); }); +watch(autoSkill, n => { + flags.autoLocate = n; + core.updateStatusBar(); + core.status.route.push(`set:autoLocate:${n}`); +}); + /** * 重置设置信息,从localStorage读取即可 */ @@ -82,9 +93,11 @@ function reset() { function resetFlag() { flags.autoSkill ??= true; flags.itemDetail ??= true; + flags.autoLocate ??= true; itemDetail.value = flags.itemDetail ? true : false; autoSkill.value = flags.autoSkill ? true : false; + autoLocate.value = flags.autoLocate ? true : false; } export default function init() { diff --git a/src/plugin/uiController.ts b/src/plugin/uiController.ts index df79740..9884bfe 100644 --- a/src/plugin/uiController.ts +++ b/src/plugin/uiController.ts @@ -1,5 +1,5 @@ import { sleep } from 'mutate-animate'; -import { Component, markRaw, ref, Ref, watch } from 'vue'; +import { Component, markRaw, ref, Ref, shallowReactive, watch } from 'vue'; import Book from '../ui/book.vue'; import Toolbox from '../ui/toolbox.vue'; import Equipbox from '../ui/equipbox.vue'; @@ -41,21 +41,22 @@ const UI_LIST: [Ref, Component][] = [ ]; /** ui栈 */ -export const uiStack = ref([]); +export const uiStack = shallowReactive([]); export default function init() { app = document.getElementById('root') as HTMLDivElement; UI_LIST.forEach(([ref, com]) => { watch(ref, n => { if (n === true) { - uiStack.value.push(markRaw(com)); + uiStack.push(markRaw(com)); showApp(); } else { - const index = uiStack.value.findIndex(v => v === com); - if (uiStack.value.length === 1) { + const index = uiStack.findIndex(v => v === com); + if (index === -1) return; + if (uiStack.length === 1) { hideApp(index); } else { - uiStack.value.splice(index, 1); + uiStack.splice(index, 1); } } }); @@ -98,7 +99,7 @@ async function hideApp(index: number) { app.style.transition = ''; app.style.opacity = '0'; } - uiStack.value.splice(index, 1); + uiStack.splice(index, 1); app.style.display = 'none'; if (!noClosePanel.value) core.closePanel(); noClosePanel.value = false; diff --git a/src/types/plugin.d.ts b/src/types/plugin.d.ts index 203d563..05ade6c 100644 --- a/src/types/plugin.d.ts +++ b/src/types/plugin.d.ts @@ -19,7 +19,8 @@ interface PluginDeclaration PluginUis, PluginUse, SkillTree, - MiniMap { + MiniMap, + HeroRealStatus { /** * 添加函数 例:添加弹出文字,像这个就可以使用core.addPop或core.plugin.addPop调用 * @param px 弹出的横坐标 @@ -127,6 +128,12 @@ interface PluginUtils { * @param delta 偏移量,正数表示向右滑动,负数表示向左滑动 */ slide(arr: T[], delta: number): T[]; + + /** + * 获取方向的反方向 + * @param dir 方向 + */ + backDir(dir: Dir): Dir; } interface PluginUis { @@ -300,6 +307,64 @@ interface Study { studySkill(enemy: Enemy, num: number): void; } +interface HeroRealStatus { + /** + * 获取勇士在某一点的属性 + * @param name 要获取的勇士属性 + * @param x 勇士所在横坐标 + * @param y 勇士所在纵坐标 + * @param floorId 勇士所在楼层 + */ + getHeroStatusOn( + name: 'all', + x?: number, + y?: number, + floorId?: FloorIds + ): HeroStatus; + getHeroStatusOn( + name: (keyof HeroStatus)[], + x?: number, + y?: number, + floorId?: FloorIds + ): Partial; + getHeroStatusOn( + name: K, + x?: number, + y?: number, + floorId?: FloorIds + ): HeroStatus[K]; + + /** + * 获取一定状态下的勇士在某一点的属性 + * @param status 勇士的状态 + * @param name 要获取的勇士属性 + * @param x 勇士所在横坐标 + * @param y 勇士所在纵坐标 + * @param floorId 勇士所在楼层 + */ + getHeroStatusOf( + status: Partial, + name: 'all', + x?: number, + y?: number, + floorId?: FloorIds + ): HeroStatus; + getHeroStatusOf( + status: Partial, + name: (keyof HeroStatus)[], + x?: number, + y?: number, + floorId?: FloorIds + ): Partial; + getHeroStatusOf( + status: Partial, + name: K, + x?: number, + y?: number, + floorId?: FloorIds + ): HeroStatus[K]; +} + type Chapter = 'chapter1' | 'chapter2'; interface Skill { diff --git a/src/ui/settings.vue b/src/ui/settings.vue index 46aff66..19a2ac5 100644 --- a/src/ui/settings.vue +++ b/src/ui/settings.vue @@ -50,6 +50,14 @@ useFixed ? 'ON' : 'OFF' }} + 勇士自动定位:   {{ + autoLocate ? 'ON' : 'OFF' + }}