From 351e136775eb76a7b839250ea85930acc55e67bb Mon Sep 17 00:00:00 2001 From: unanmed <1319491857@qq.com> Date: Sun, 30 Jul 2023 16:46:34 +0800 Subject: [PATCH] =?UTF-8?q?=E9=87=8D=E5=86=99=E6=88=98=E6=96=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- idea.md | 37 ++-- public/_server/table/functions.comment.js | 6 - public/libs/enemys.js | 22 +- public/libs/events.js | 36 +--- public/libs/maps.js | 2 +- public/project/functions.js | 133 ------------- src/plugin/game/battle.ts | 232 ++++++++++++++++++++++ src/plugin/game/damage.ts | 4 +- src/plugin/game/index.js | 4 +- src/plugin/game/replay.js | 2 +- src/plugin/game/{study.js => study.ts} | 22 +- src/plugin/game/utils.ts | 15 ++ src/types/enemy.d.ts | 13 +- src/types/event.d.ts | 10 +- src/types/function.d.ts | 12 -- src/types/plugin.d.ts | 2 - src/types/status.d.ts | 4 +- 17 files changed, 311 insertions(+), 245 deletions(-) create mode 100644 src/plugin/game/battle.ts rename src/plugin/game/{study.js => study.ts} (80%) diff --git a/idea.md b/idea.md index 6251004..7146384 100644 --- a/idea.md +++ b/idea.md @@ -24,27 +24,12 @@ #### 技能 +分成多条线,可以单独点一条线,也可以混搭 + 闪避:每 M 回合闪避一次,减少 N% 的伤害 ## 机制 -### 通用 - -- 实时天气 -- 成就系统(完成) -- 装备合成、装备(孔)强化 -- 宝石目标设定 -- 自动宝物规划,选中两个或更多宝物后自动在本地图中规划出最优拾取路线,原则是尽量减少其余宝物的捡拾,自动切换主动技能,怪物造成的伤害最低的路线 -- 临界显示方式,宝石数还是数值 -- 怪物目标设定(完成) -- 木牌查看系统(完成) -- 宝物目标设定 -- 每个怪物加一个怪物说明 -- 歌词展示系统 -- 小地图显示框,可以选择是否显示剩余怪物数量等 -- 怪物死亡特效 -- 区域名称显示特效,3D 粒子 - ### 第二章 智慧 - 苍蓝之殿 1: 利用点光源,照到的位置与没照到的位置内容不同,玩家可以选择是否装备手电筒 @@ -65,3 +50,21 @@ dam1.png ---- 存档 404 dam2.png ---- 存档 285 dam3.png ---- 存档 243 dam4.png ---- 存档 59 + +## TODO + +[] 实时天气 +[x] 成就系统 +[] 装备合成、装备(孔)强化 +[] 宝石目标设定 +[] 自动宝物规划,选中两个或更多宝物后自动在本地图中规划出最优拾取路线,原则是尽量减少其余宝物的捡拾,自动切换主动技能,怪物造成的伤害最低的路线 +[] 临界显示方式,宝石数还是数值 +[x] 怪物目标设定 +[x] 木牌查看系统(百科全书) +[] 宝物目标设定 +[] 每个怪物加一个怪物说明 +[] 歌词展示系统 +[] 小地图显示框,可以选择是否显示剩余怪物数量等 +[] 怪物死亡特效 +[] 区域名称显示特效,3D 粒子 +[] 单独的工具栏 diff --git a/public/_server/table/functions.comment.js b/public/_server/table/functions.comment.js index 318a832..adb3444 100644 --- a/public/_server/table/functions.comment.js +++ b/public/_server/table/functions.comment.js @@ -47,12 +47,6 @@ var functions_comment_c456ea59_6018_45ef_8bcc_211a24c627dc = { _lint: true, _data: '楼层飞行' }, - beforeBattle: { - _leaf: true, - _type: 'textarea', - _lint: true, - _data: '战前判定' - }, afterBattle: { _leaf: true, _type: 'textarea', diff --git a/public/libs/enemys.js b/public/libs/enemys.js index 1d47fa4..c20e3a8 100644 --- a/public/libs/enemys.js +++ b/public/libs/enemys.js @@ -203,14 +203,11 @@ enemys.prototype.getEnemyValue = function (enemy, name, x, y, floorId) { ////// 能否获胜 ////// enemys.prototype.canBattle = function (enemy, x, y, floorId) { - // todo: 重写这个函数 - if (typeof enemy == 'string') enemy = core.material.enemys[enemy]; - var damage = this.getDamage(enemy, x, y, floorId); - return damage != null && damage < core.status.hero.hp; + // Deprecated. See src/plugin/game/battle.ts }; enemys.prototype.getDamageString = function (enemy, x, y, floorId, hero) { - // todo: 重写这个函数 + // todo: 删除 if (typeof enemy == 'string') enemy = core.material.enemys[enemy]; var damage = this.getDamage(enemy, x, y, floorId, hero); @@ -237,7 +234,7 @@ enemys.prototype.getDamageString = function (enemy, x, y, floorId, hero) { ////// 接下来N个临界值和临界减伤计算 ////// enemys.prototype.nextCriticals = function (enemy, number, x, y, floorId, hero) { - // todo: 删除 getDamageInfo + // todo: 删除这个函数 if (typeof enemy == 'string') enemy = core.material.enemys[enemy]; number = number || 1; @@ -284,7 +281,7 @@ enemys.prototype._nextCriticals_overAtk = function ( floorId, hero ) { - // todo: 删除 getDamageInfo + // todo: 删除这个函数 var calNext = function (currAtk, maxAtk) { var start = currAtk, end = maxAtk; @@ -342,7 +339,7 @@ enemys.prototype._nextCriticals_useBinarySearch = function ( floorId, hero ) { - // todo: 删除 getDamageInfo + // todo: 删除这个函数 var mon_hp = info.mon_hp, hero_atk = core.getStatusOrDefault(hero, 'atk'), mon_def = info.mon_def, @@ -417,7 +414,7 @@ enemys.prototype.getDefDamage = function (enemy, k, x, y, floorId, hero) { }; enemys.prototype.getEnemyInfo = function (enemy, hero, x, y, floorId) { - // throw new Error(`This function has been deprecated.`); + // todo: 删除这个函数 if (enemy == null) return null; if (typeof enemy == 'string') enemy = core.material.enemys[enemy]; return this.enemydata.getEnemyInfo(enemy, hero, x, y, floorId); @@ -425,7 +422,7 @@ enemys.prototype.getEnemyInfo = function (enemy, hero, x, y, floorId) { ////// 获得战斗伤害信息(实际伤害计算函数) ////// enemys.prototype.getDamageInfo = function (enemy, hero, x, y, floorId) { - // throw new Error(`This function has been deprecated.`); + // todo: 删除这个函数 if (enemy == null) return null; // 移动到了脚本编辑 - getDamageInfo中 if (typeof enemy == 'string') enemy = core.material.enemys[enemy]; @@ -434,11 +431,12 @@ enemys.prototype.getDamageInfo = function (enemy, hero, x, y, floorId) { ////// 获得在某个勇士属性下怪物伤害 ////// enemys.prototype.getDamage = function (enemy, x, y, floorId, hero) { + // todo: 修改这个函数的参数 return this._getDamage(enemy, hero, x, y, floorId); }; enemys.prototype._getDamage = function (enemy, hero, x, y, floorId) { - // todo: 删除 getDamageInfo + // todo: 重写这个函数 if (enemy == null) enemy = core.getBlockId(x, y, floorId); if (typeof enemy == 'string') enemy = core.material.enemys[enemy]; if (enemy == null) return null; @@ -451,7 +449,7 @@ enemys.prototype._getDamage = function (enemy, hero, x, y, floorId) { ////// 获得当前楼层的怪物列表 ////// enemys.prototype.getCurrentEnemys = function (floorId) { - // todo: 删除 getEnemyInfo - _getCurrentEnemys_addEnemy + // todo: 重写这个函数 floorId = floorId || core.status.floorId; var enemys = [], used = {}; diff --git a/public/libs/events.js b/public/libs/events.js index e8e11b3..ad50f18 100644 --- a/public/libs/events.js +++ b/public/libs/events.js @@ -430,16 +430,7 @@ events.prototype._trigger_ignoreChangeFloor = function (block) { }; events.prototype._sys_battle = function (data, callback) { - // 检查是否需要改变朝向 - /* if (data.x == core.nextX() && data.y == core.nextY()) { - var dir = core.turnDirection(":back"); - var id = data.event.id, toId = (data.event.faceIds || {})[dir]; - if (toId && id != toId) { - var number = core.getNumberById(toId); - if (number > 0) - core.setBlock(number, data.x, data.y); - } - } */ + // todo: 重写这个函数的一部分 // 检查战前事件 var beforeBattle = []; @@ -471,35 +462,17 @@ events.prototype._sys_battle = function (data, callback) { ////// 战斗 ////// events.prototype.battle = function (id, x, y, force, callback) { - // todo: 重写这个函数的一部分,修改参数 - core.saveAndStopAutomaticRoute(); - id = id || core.getBlockId(x, y); - if (!id) return core.clearContinueAutomaticRoute(callback); - // 非强制战斗 - if (!core.enemys.canBattle(id, x, y) && !force && !core.status.event.id) { - core.stopSound(); - core.playSound('操作失败'); - core.drawTip('你打不过此怪物!', id); - return core.clearContinueAutomaticRoute(callback); - } - // 自动存档 - if (!core.status.event.id) core.autosave(true); - // 战前事件 - if (!this.beforeBattle(id, x, y)) - return core.clearContinueAutomaticRoute(callback); - // 战后事件 - this.afterBattle(id, x, y); - if (callback) callback(); + // Deprecated. See src/plugin/game/battle.ts }; ////// 战斗前触发的事件 ////// events.prototype.beforeBattle = function (enemyId, x, y) { - return this.eventdata.beforeBattle(enemyId, x, y); + // Deprecated. See src/plugin/game/battle.ts }; ////// 战斗结束后触发的事件 ////// events.prototype.afterBattle = function (enemyId, x, y) { - return this.eventdata.afterBattle(enemyId, x, y); + // Deprecated. See src/plugin/game/battle.ts }; events.prototype._sys_openDoor = function (data, callback) { @@ -2140,6 +2113,7 @@ events.prototype._action_disableShop = function (data, x, y, prefix) { }; events.prototype._action_battle = function (data, x, y, prefix) { + // todo: 修改battle的参数 if (data.id) { this.battle(data.id, null, null, true, core.doAction); } else { diff --git a/public/libs/maps.js b/public/libs/maps.js index 5c6a1ca..8b2d490 100644 --- a/public/libs/maps.js +++ b/public/libs/maps.js @@ -3531,7 +3531,7 @@ maps.prototype.resetMap = function (floorId) { ////// 初始化独立的block canvas ////// maps.prototype._initDetachedBlock = function (blockInfo, x, y, displayDamage) { - // todo: 不使用 nextCriticals + // todo: 不使用 nextCriticals 和 getDamageString var headCanvas = null, bodyCanvas = '__body_' + x + '_' + y, damageCanvas = null; diff --git a/public/project/functions.js b/public/project/functions.js index d4a4ff1..489127a 100644 --- a/public/project/functions.js +++ b/public/project/functions.js @@ -262,139 +262,6 @@ var functions_d6ad677b_427a_4623_b50f_a445a3b0ef8a = { return true; }, - beforeBattle: function (enemyId, x, y) { - // 战斗前触发的事件,可以加上一些战前特效(详见下面支援的例子) - // 此函数在“检测能否战斗和自动存档”【之后】执行。如果需要更早的战前事件,请在插件中覆重写 core.events.doSystemEvent 函数。 - // 返回true则将继续战斗,返回false将不再战斗。 - // todo: 重写 - - return true; - }, - afterBattle: function (enemyId, x, y) { - // todo: 重写 - // 战斗结束后触发的事件 - const floorId = core.status.floorId; - - var enemy = core.material.enemys[enemyId]; - var special = enemy.special; - - // 播放战斗音效和动画 - // 默认播放的动画;你也可以使用 - var animate = 'hand'; // 默认动画 - // 检查当前装备是否存在攻击动画 - var equipId = core.getEquip(0); - if (equipId && (core.material.items[equipId].equip || {}).animate) - animate = core.material.items[equipId].equip.animate; - - // 检查该动画是否存在SE,如果不存在则使用默认音效 - if (!(core.material.animates[animate] || {}).se) - core.playSound('attack.mp3'); - - // 播放动画;如果不存在坐标(强制战斗)则播放到勇士自身 - if (x != null && y != null) core.drawAnimate(animate, x, y); - else core.drawHeroAnimate(animate); - - // 获得战斗伤害信息 - // 注意这里勇士坐标要传入当前勇士坐标,不然会默认取伤害最低的地方打怪 - const damageInfo = - core.getDamageInfo( - enemyId, - { x: core.status.hero.loc.x, y: core.status.hero.loc.y }, - x, - y - ) ?? {}; - // 战斗伤害 - const damage = damageInfo.damage; - // 判定是否致死 - if (damage == null || damage >= core.status.hero.hp) { - core.status.hero.hp = 0; - core.updateStatusBar(false, true); - core.events.lose('战斗失败'); - return; - } - - // 扣减体力值并记录统计数据 - core.status.hero.hp -= damage; - core.status.hero.statistics.battleDamage += damage; - core.status.hero.statistics.battle++; - - // 智慧之源 - if (core.hasSpecial(special, 14) && flags.hard === 2) { - core.addFlag( - 'inte_' + floorId, - Math.ceil((core.status.hero.mdef / 10) * 0.3) * 10 - ); - core.status.hero.mdef -= - Math.ceil((core.status.hero.mdef / 10) * 0.3) * 10; - } - - // 极昼永夜 - if (core.hasSpecial(special, 22)) { - flags[`night_${floorId}`] ??= 0; - flags[`night_${floorId}`] -= enemy.night; - } - if (core.hasSpecial(special, 23)) { - flags[`night_${floorId}`] ??= 0; - flags[`night_${floorId}`] += enemy.day; - } - - if (core.plugin.skillTree.getSkillLevel(11) > 0) { - core.plugin.study.declineStudiedSkill(); - } - - // 如果是融化怪,需要特殊标记一下 - if (core.hasSpecial(special, 25) && core.has(x) && core.has(y)) { - flags[`melt_${floorId}`] ??= {}; - flags[`melt_${floorId}`][`${x},${y}`] = enemy.melt; - } - - // 获得金币 - const money = enemy.money; - core.status.hero.money += money; - core.status.hero.statistics.money += money; - - // 获得经验 - const exp = enemy.exp; - core.status.hero.exp += exp; - core.status.hero.statistics.exp += exp; - - const hint = - '打败 ' + 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); - } - - // 事件的处理 - var todo = []; - - // 战后事件 - if (core.status.floorId != null) { - core.push( - todo, - core.floors[core.status.floorId].afterBattle[x + ',' + y] - ); - } - core.push(todo, enemy.afterBattle); - - // 如果事件不为空,将其插入 - if (todo.length > 0) core.insertAction(todo, x, y); - - // 因为removeBlock和hideBlock都会刷新状态栏,因此将删除部分移动到这里并保证刷新只执行一次,以提升效率 - if (core.getBlock(x, y) != null) { - core.removeBlock(x, y); - } else { - core.updateStatusBar(); - } - - // 如果已有事件正在处理中 - if (core.status.event.id == null) core.continueAutomaticRoute(); - else core.clearContinueAutomaticRoute(); - }, afterOpenDoor: function (doorId, x, y) { // 开一个门后触发的事件 diff --git a/src/plugin/game/battle.ts b/src/plugin/game/battle.ts new file mode 100644 index 0000000..f1d49d0 --- /dev/null +++ b/src/plugin/game/battle.ts @@ -0,0 +1,232 @@ +import { DamageDir, DamageEnemy, getNeedCalDir } from './damage'; +import { findDir, has } from './utils'; + +export function getEnemy( + x: number, + y: number, + floorId: FloorIds = core.status.floorId +) { + const enemy = core.status.maps[floorId].enemy.list.find(v => { + return v.x === x && v.y === y; + }); + if (!enemy) { + throw new Error( + `Get null when getting enemy on '${x},${y}' in '${floorId}'` + ); + } + return enemy; +} + +core.enemys.canBattle = function ( + x: number, + y: number, + floorId: FloorIds = core.status.floorId, + dir: DamageDir | DamageDir[] = getNeedCalDir(x, y, floorId) +) { + const enemy = getEnemy(x, y, floorId); + const damage = enemy.calEnemyDamage(core.status.hero, dir); + + return damage.some(v => { + return v.damage < core.status.hero.hp; + }); +}; + +core.events.battle = function ( + x: number, + y: number, + dir: DamageDir, + force: boolean = false, + callback?: () => void +) { + core.saveAndStopAutomaticRoute(); + const enemy = getEnemy(x, y); + // 非强制战斗 + if ( + !core.enemys.canBattle(x, y, void 0, dir) && + !force && + !core.status.event.id + ) { + core.stopSound(); + core.playSound('操作失败'); + core.drawTip('你打不过此怪物!', enemy.id); + return core.clearContinueAutomaticRoute(callback); + } + // 自动存档 + if (!core.status.event.id) core.autosave(true); + // 战前事件 + if (!this.beforeBattle(enemy, x, y, dir)) + return core.clearContinueAutomaticRoute(callback); + // 战后事件 + this.afterBattle(enemy, x, y, dir); + callback?.(); +}; + +core.events.beforeBattle = function () { + return true; +}; + +core.events.afterBattle = function ( + enemy: DamageEnemy, + x?: number, + y?: number, + dir: DamageDir = 'none' +) { + const floorId = core.status.floorId; + const special = enemy.info.special; + + // 播放战斗动画 + let animate: AnimationIds = 'hand'; + // 检查当前装备是否存在攻击动画 + const equipId = core.getEquip(0); + if (equipId && (core.material.items[equipId].equip || {}).animate) + animate = core.material.items[equipId].equip.animate; + + // 检查该动画是否存在SE,如果不存在则使用默认音效 + if (!core.material.animates[animate]?.se) core.playSound('attack.mp3'); + + // 战斗伤害 + const info = enemy.calEnemyDamage(core.status.hero, dir)[0]; + const damage = info.damage; + // 判定是否致死 + if (damage >= core.status.hero.hp) { + core.status.hero.hp = 0; + core.updateStatusBar(false, true); + core.events.lose('战斗失败'); + return; + } + + // 扣减体力值并记录统计数据 + core.status.hero.hp -= damage; + core.status.hero.statistics.battleDamage += damage; + core.status.hero.statistics.battle++; + + // 智慧之源 + if (core.hasSpecial(special, 14) && flags.hard === 2) { + core.addFlag( + 'inte_' + floorId, + Math.ceil((core.status.hero.mdef / 10) * 0.3) * 10 + ); + core.status.hero.mdef -= + Math.ceil((core.status.hero.mdef / 10) * 0.3) * 10; + } + + // 极昼永夜 + if (core.hasSpecial(special, 22)) { + flags[`night_${floorId}`] ??= 0; + flags[`night_${floorId}`] -= enemy.enemy.night!; + } + if (core.hasSpecial(special, 23)) { + flags[`night_${floorId}`] ??= 0; + flags[`night_${floorId}`] += enemy.enemy.day; + } + + // if (core.plugin.skillTree.getSkillLevel(11) > 0) { + // core.plugin.study.declineStudiedSkill(); + // } + + // 如果是融化怪,需要特殊标记一下 + if (core.hasSpecial(special, 25) && core.has(x) && core.has(y)) { + flags[`melt_${floorId}`] ??= {}; + flags[`melt_${floorId}`][`${x},${y}`] = enemy.enemy.melt; + } + + // 获得金币 + const money = enemy.enemy.money; + core.status.hero.money += money; + core.status.hero.statistics.money += money; + + // 获得经验 + const exp = enemy.enemy.exp; + core.status.hero.exp += exp; + core.status.hero.statistics.exp += exp; + + const hint = + '打败 ' + 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); + } + + // 事件的处理 + const todo: MotaEvent = []; + + // 战后事件 + if (has(core.status.floorId)) { + const loc = `${x},${y}` as LocString; + todo.push(...(core.floors[core.status.floorId].afterBattle[loc] ?? [])); + } + todo.push(...(enemy.enemy.afterBattle ?? [])); + + // 如果事件不为空,将其插入 + if (todo.length > 0) core.insertAction(todo, x, y); + + if (has(x) && has(y)) { + core.drawAnimate(animate, x, y); + core.removeBlock(x, y); + } else core.drawHeroAnimate(animate); + + // 如果已有事件正在处理中 + if (core.status.event.id == null) core.continueAutomaticRoute(); + else core.clearContinueAutomaticRoute(); +}; + +core.events._sys_battle = function (data: Block, callback?: () => void) { + // todo: 重写这个函数的一部分 + + // 检查战前事件 + const floor = core.floors[core.status.floorId]; + const beforeBattle: MotaEvent = []; + const loc = `${data.x},${data.y}` as LocString; + const enemy = getEnemy(data.x, data.y); + + beforeBattle.push(...(floor.beforeBattle[loc] ?? [])); + beforeBattle.push(...(enemy.enemy.beforeBattle ?? [])); + + if (beforeBattle.length > 0) { + beforeBattle.push({ type: 'battle', x: data.x, y: data.y }); + core.clearContinueAutomaticRoute(); + + // 自动存档 + var inAction = core.status.event.id == 'action'; + if (inAction) { + core.insertAction(beforeBattle, data.x, data.y); + core.doAction(); + } else { + core.autosave(true); + core.insertAction(beforeBattle, data.x, data.y, callback); + } + } else { + const dir = findDir(data, core.status.hero.loc) as DamageDir; + this.battle(data.x, data.y, dir, false, callback); + } +}; + +declare global { + interface Events { + /** + * 与怪物战斗前 + * @param x 怪物横坐标 + * @param y 怪物纵坐标 + */ + beforeBattle( + enemy: DamageEnemy, + x: number, + y: number, + dir: DamageDir + ): boolean; + + /** + * 与怪物战斗后 + */ + afterBattle( + enemy: DamageEnemy, + x: number, + y: number, + dir: DamageDir + ): void; + } +} diff --git a/src/plugin/game/damage.ts b/src/plugin/game/damage.ts index d81bcee..2f057a0 100644 --- a/src/plugin/game/damage.ts +++ b/src/plugin/game/damage.ts @@ -73,7 +73,7 @@ interface CriticalDamageDelta extends Omit { } type HaloFn = (info: EnemyInfo, enemy: Enemy) => void; -type DamageDir = Dir | 'none'; +export type DamageDir = Dir | 'none'; /** 光环属性 */ export const haloSpecials: number[] = [8, 21, 25, 26, 27]; @@ -695,7 +695,7 @@ export class DamageEnemy { damage[loc].type.add(type); } - private calEnemyDamage( + calEnemyDamage( hero: Partial = core.status.hero, dir: DamageDir | DamageDir[] ): DamageInfo[] { diff --git a/src/plugin/game/index.js b/src/plugin/game/index.js index b30632e..66daccf 100644 --- a/src/plugin/game/index.js +++ b/src/plugin/game/index.js @@ -18,6 +18,7 @@ import * as towerBoss from './towerBoss'; import * as utils from './utils'; import * as chase from './chase'; import * as damage from './damage'; +import * as battle from './battle'; export { halo, @@ -32,5 +33,6 @@ export { towerBoss, utils, chase, - damage + damage, + battle }; diff --git a/src/plugin/game/replay.js b/src/plugin/game/replay.js index 7c4ca74..6c254f1 100644 --- a/src/plugin/game/replay.js +++ b/src/plugin/game/replay.js @@ -1,6 +1,6 @@ /// -import { studySkill, canStudySkill } from './study.js'; +import { studySkill, canStudySkill } from './study'; const replayableSettings = ['autoSkill']; diff --git a/src/plugin/game/study.js b/src/plugin/game/study.ts similarity index 80% rename from src/plugin/game/study.js rename to src/plugin/game/study.ts index f7471ec..75f7e22 100644 --- a/src/plugin/game/study.js +++ b/src/plugin/game/study.ts @@ -1,7 +1,5 @@ -/// - // 负责勇士技能:学习 -const values = { +const values: Record = { 1: ['crit'], 6: ['n'], 7: ['hungry'], @@ -12,7 +10,7 @@ const values = { const cannotStudy = [9, 12, 14, 15, 24]; -export function canStudySkill(number) { +export function canStudySkill(number: number) { const s = (core.status.hero.special ??= { num: [], last: [] }); if (core.plugin.skillTree.getSkillLevel(11) === 0) return false; if (s.num.length >= 1) return false; @@ -21,7 +19,7 @@ export function canStudySkill(number) { return true; } -export function studySkill(enemy, number) { +export function studySkill(enemy: any, number: number) { core.status.hero.special ??= { num: [], last: [] }; const s = core.status.hero.special; const specials = core.getSpecials(); @@ -41,13 +39,13 @@ export function studySkill(enemy, number) { } } -export function forgetStudiedSkill(num, i) { +export function forgetStudiedSkill(num: number, i: number) { const s = core.status.hero.special; const index = i !== void 0 && i !== null ? i : s.num.indexOf(num); if (index === -1) return; s.num.splice(index, 1); s.last.splice(index, 1); - const value = values[number] ?? []; + const value = values[num] ?? []; for (const key of value) { delete s[key]; } @@ -62,16 +60,8 @@ export function checkStudiedSkill() { const s = core.status.hero.special; for (let i = 0; i < s.last.length; i++) { if (s.last[i] <= 0) { - this.forgetStudiedSkill(void 0, i); + forgetStudiedSkill(1, i); i--; } } } - -core.plugin.study = { - canStudySkill, - studySkill, - forgetStudiedSkill, - declineStudiedSkill, - checkStudiedSkill -}; diff --git a/src/plugin/game/utils.ts b/src/plugin/game/utils.ts index a52b6ca..1df59f1 100644 --- a/src/plugin/game/utils.ts +++ b/src/plugin/game/utils.ts @@ -155,6 +155,21 @@ export function boundary(arr: any, key?: any) { } } +/** + * 获取两个坐标的相对方向 + * @param from 初始坐标 + * @param to 指向坐标 + */ +export function findDir(from: Loc, to: Loc): Dir2 | 'none' { + const dx = to.x - from.x; + const dy = to.y - from.y; + return ( + (Object.entries(core.utils.scan2).find(v => { + v[1].x === dx && v[1].y === dy; + })?.[0] as Dir2) ?? 'none' + ); +} + declare global { interface GamePluginUtils { ofDir: typeof ofDir; diff --git a/src/types/enemy.d.ts b/src/types/enemy.d.ts index a1887fe..43629e7 100644 --- a/src/types/enemy.d.ts +++ b/src/types/enemy.d.ts @@ -26,7 +26,10 @@ type PartialNumbericEnemyProperty = | 'courage' | 'charge' | 'paleShield' - | 'iceHalo'; + | 'iceHalo' + | 'day' + | 'night' + | 'melt'; type BooleanEnemyProperty = | 'zoneSquare' @@ -314,10 +317,10 @@ interface Enemys extends EnemyData { * @returns true表示可以打败,false表示无法打败 */ canBattle( - enemy: EnemyIds | Enemy, - x?: number, - y?: number, - floorId?: FloorIds + x: number, + y: number, + floorId?: FloorIds, + dir?: Dir | 'none' | (Dir | 'none')[] ): boolean; /** diff --git a/src/types/event.d.ts b/src/types/event.d.ts index 69c829a..3f34d22 100644 --- a/src/types/event.d.ts +++ b/src/types/event.d.ts @@ -109,10 +109,10 @@ interface Events extends EventData { * @param callback 回调函数 */ battle( - id: AllIdsOf<'enemys' | 'enemy48'>, - x?: number, - y?: number, - force?: boolean, + x: number, + y: number, + dir: Dir | 'none', + force: boolean = false, callback?: () => void ): void; @@ -758,6 +758,8 @@ interface Events extends EventData { * @param itemId 道具id,其中敌人手册、传送器和飞行器会被特殊处理 */ tryUseItem(itemId: ItemIdOf<'tools' | 'constants'>): void; + + _sys_battle(data: Block, callback?: () => void): void; } declare const events: new () => Events; diff --git a/src/types/function.d.ts b/src/types/function.d.ts index d5e2820..ae90b56 100644 --- a/src/types/function.d.ts +++ b/src/types/function.d.ts @@ -161,18 +161,6 @@ interface EventData { */ flyTo(toId: FloorIds, callback?: () => void): boolean; - /** - * 与怪物战斗前 - * @param enemyId 打败的怪物 - * @param x 怪物横坐标 - * @param y 怪物纵坐标 - */ - beforeBattle( - enemyId: AllIdsOf<'enemys' | 'enemy48'>, - x?: number, - y?: number - ): void; - /** * 与怪物战斗后 * @param enemyId 打败的怪物 diff --git a/src/types/plugin.d.ts b/src/types/plugin.d.ts index 37d3d11..3b3d046 100644 --- a/src/types/plugin.d.ts +++ b/src/types/plugin.d.ts @@ -462,8 +462,6 @@ interface Skill { effect: string[]; } -interface DamageEnemy {} - type Forward = { [K in keyof T as T[K] extends Function ? K extends `_${string}` diff --git a/src/types/status.d.ts b/src/types/status.d.ts index c0077b9..7f16d16 100644 --- a/src/types/status.d.ts +++ b/src/types/status.d.ts @@ -963,8 +963,8 @@ interface HeroStatus { * 勇士学习的特技 */ special: { - num: []; - last: []; + num: number[]; + last: number[]; [k: string]: any; };