From 970b2824aa243df0f2d071187f6b96126064a716 Mon Sep 17 00:00:00 2001 From: bdf1 Date: Wed, 9 Nov 2022 05:32:27 +1300 Subject: [PATCH] add showValue, autoGet, autoBattle but with bug --- project/plugins.js | 431 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 431 insertions(+) diff --git a/project/plugins.js b/project/plugins.js index 78c402f..29322cb 100644 --- a/project/plugins.js +++ b/project/plugins.js @@ -2276,5 +2276,436 @@ var plugins_bb40132b_638b_4a9f_b028_d3fe47acc8d1 = } } core.registerAnimationFrame('startAnimation', false, draw); +}, + "showValue": function () { + /* 宝石血瓶左下角显示数值 + * 需要将 变量:itemDetail改为true才可正常运行 + * 请尽量减少勇士的属性数量,否则可能会出现严重卡顿 + * 注意:这里的属性必须是core.status.hero里面的,flag无法显示 + * 如果不想显示,可以core.setFlag("itemDetail", false); + * 然后再core.getItemDetail(); + * 如有bug在大群或造塔群@古祠 + */ + + // 谁tm在即捡即用效果里面调用带有含刷新状态栏的函数 + var origin = core.control.updateStatusBar; + core.updateStatusBar = core.control.updateStatusBar = function () { + if (core.getFlag('__statistics__')) return; + else return origin.apply(core.control, arguments); + } + + core.bigmap.threshold = 256; + + core.control.updateDamage = function (floorId, ctx) { + floorId = floorId || core.status.floorId; + if (!floorId || core.status.gameOver || main.mode != 'play') return; + var onMap = ctx == null; + + // 没有怪物手册 + if (!core.hasItem('book')) return; + core.status.damage.posX = core.bigmap.posX; + core.status.damage.posY = core.bigmap.posY; + if (!onMap) { + var width = core.floors[floorId].width, + height = core.floors[floorId].height; + // 地图过大的缩略图不绘制显伤 + if (width * height > core.bigmap.threshold) return; + } + this._updateDamage_damage(floorId, onMap); + this._updateDamage_extraDamage(floorId, onMap); + core.getItemDetail(floorId); // 宝石血瓶详细信息 + this.drawDamage(ctx); + }; + // 绘制地图显示 + control.prototype._drawDamage_draw = function (ctx, onMap) { + if (!core.hasItem('book')) return; + // *** 下一句话可以更改你想要的显示字体 + core.setFont(ctx, "bold 11px Arial"); + // *** + core.setTextAlign(ctx, 'left'); + core.status.damage.data.forEach(function (one) { + var px = one.px, + py = one.py; + if (onMap && core.bigmap.v2) { + px -= core.bigmap.posX * 32; + py -= core.bigmap.posY * 32; + if (px < -32 * 2 || px > core.__PX__ + 32 || py < -32 || py > core.__PY__ + 32) + return; + } + core.fillBoldText(ctx, one.text, px, py, one.color); + }); + core.setTextAlign(ctx, 'center'); + core.status.damage.extraData.forEach(function (one) { + var px = one.px, + py = one.py; + if (onMap && core.bigmap.v2) { + px -= core.bigmap.posX * 32; + py -= core.bigmap.posY * 32; + if (px < -32 || px > core.__PX__ + 32 || py < -32 || py > core.__PY__ + 32) + return; + } + core.fillBoldText(ctx, one.text, px, py, one.color); + }); + }; + // 获取宝石信息 并绘制 + this.getItemDetail = function (floorId) { + if (!core.getFlag("itemDetail")) return; + floorId = floorId || core.status.thisMap.floorId; + core.status.maps[floorId].blocks.forEach(function (block) { + if (block.event.cls !== 'items' || block.event.id === 'superPotion') return; + var x = block.x, + y = block.y; + // v2优化,只绘制范围内的部分 + if (core.bigmap.v2) { + if (x < core.bigmap.posX - core.bigmap.extend || x > core.bigmap.posX + core.__SIZE__ + core.bigmap.extend || + y < core.bigmap.posY - core.bigmap.extend || y > core.bigmap.posY + core.__SIZE__ + core.bigmap.extend) { + return; + } + } + var id = block.event.id; + var item = core.material.items[id]; + if (item.cls === 'equips') { + // 装备也显示 + var diff = core.clone(item.equip.value || {}); + var per = item.equip.percentage; + for (var name in per) { + diff[name + 'per'] = per[name].toString() + '%'; + } + drawItemDetail(diff, x, y); + return; + } + var before = core.clone(core.status.hero); + // 跟数据统计原理一样 执行效果 前后比较 + core.setFlag("__statistics__", true); + try { + eval(item.itemEffect); + } catch (error) {} + var diff = compareObject(before, core.status.hero); + core.status.hero = hero = before; + flags = core.status.hero.flags; + drawItemDetail(diff, x, y); + }); + }; + // 比较两个对象之间每一项的数值差异(弱等于) 返回数值差异 + function compareObject(a, b) { + a = a || {}; + b = b || {}; + var diff = {}; // 差异 + for (var name in a) { + diff[name] = b[name] - (a[name] || 0); + if (!diff[name]) diff[name] = void 0; + } + return diff; + }; + // 绘制 + function drawItemDetail(diff, x, y) { + var px = 32 * x + 2, + py = 32 * y + 30; + var content = ""; + // 获得数据和颜色 + var i = 0; + for (var name in diff) { + if (!diff[name]) continue; + var color = "#ffffff"; + if (typeof diff[name] === 'number') + diff[name] = core.formatBigNumber(diff[name], true); + switch (name) { + case 'atk': + case 'atkper': + color = "#FF7A7A"; + break; + case 'def': + case 'defper': + color = "#00E6F1"; + break; + case 'mdef': + case 'mdefper': + color = "#6EFF83"; + break; + case 'hp': + color = "#A4FF00"; + break; + case 'hpmax': + case 'hpmaxper': + color = "#F9FF00"; + break; + case 'mana': + color = "#cc6666"; + break; + } + content = diff[name]; + // 绘制 + core.status.damage.data.push({ text: content, px: px, py: py - 10 * i, color: color }); + i++; + } + } +}, + "autoBattle": function () { + /** + * --------------- 安装说明 --------------- + * + * 复制到插件编写里面即可 + * + * --------------- 使用说明 --------------- + * + * 把变量 __autoBattle__ 设置成true开启,设置成false关闭,然后在想要清的时刻,比如战后,每步后等加上core.autoBattle()即可 + * + * --------------- 自定义说明 --------------- + * + * 可以更改canBattle函数自定义某个怪物是否应该被清 + */ + + /** + * 是否清这个怪,可以修改这里来实现对不同怪的不同操作 + * @param {string} enemy + * @param {number} x + * @param {number} y + */ + function canBattle(enemy, x, y) { + const loc = `${x},${y}`; + const floor = core.floors[core.status.floorId]; + const e = core.material.enemys[enemy]; + const hasEvent = + has(floor.afterBattle[loc]) || + has(floor.beforeBattle[loc]) || + has(e.beforeBattle) || + has(e.afterBattle) || + has(floor.events[loc]); + // 有事件,不清 + if (hasEvent) return false; + const damage = core.getDamageInfo(enemy, void 0, x, y); + // 0伤或负伤,清 + if (has(damage) && has(damage.damage) && damage.damage <= 0) return true; + return false; + } + + /** + * @template T + * @param {T} v + * @returns {v is NonNullable} + */ + function has(v) { + return v !== null && v !== undefined; + } + + /** + * 广搜,搜索可以到达的需要清的怪 + * @param {string} floorId + */ + function bfs(floorId, deep = Infinity) { + core.extractBlocks(floorId); + const objs = core.getMapBlocksObj(floorId); + const { x, y } = core.status.hero.loc; + /** @type {[direction, number, number][]} */ + const dir = Object.entries(core.utils.scan).map(v => [ + v[0], + v[1].x, + v[1].y + ]); + + /** @type {[number, number][]} */ + const queue = [ + [x, y] + ]; + const mapped = { + [`${x},${y}`]: true + }; + while (queue.length > 0 && deep > 0) { + const [nx, ny] = queue.shift(); + dir.forEach(v => { + const [tx, ty] = [nx + v[1], ny + v[2]]; + const loc = `${tx},${ty}`; + if (mapped[loc]) return; + const block = objs[loc]; + mapped[loc] = true; + const isEnemy = + has(block) && block.event.cls.startsWith('enemy'); + const changeFloor = core.floors[floorId].changeFloor[loc]; + if ( + (!core.canMoveHero(nx, ny, v[0]) && !isEnemy) || + (has(block) && block.event.cls === 'items') || + (core.noPass(tx, ty) && !isEnemy) || + has(core.floors[floorId].events[loc]) || + (has(changeFloor) && + changeFloor.ignoreChangeFloor === false) + ) + return; + + if (isEnemy) { + if (canBattle(block.event.id, tx, ty) && !block.disable) { + console.log(block.event.id, tx, ty); + // 能打且没有事件就直接干他丫的 + core.battle(block.event.id, tx, ty); + } else return; + } + // 然后判断目标点是否有地图伤害等,没有就直接添加到队列 + const damage = core.status.checkBlock.damage[loc]; + const ambush = core.status.checkBlock.ambush[loc]; + const repulse = core.status.checkBlock.repulse[loc]; + if ( + (!has(damage) || (has(damage) && damage <= 0)) && + !has(ambush) && + !has(repulse) + ) + queue.push([tx, ty]); + }); + deep--; + } + } + + this.autoBattle = function () { + if (!flags.__autoBattle__) return; + // 如果勇士当前点有地图伤害,只清周围 + const { x, y } = core.status.hero.loc; + const floor = core.floors[core.status.floorId]; + const hasEvent = has(floor.events[`${x},${y}`]); + if (hasEvent) return; + const damage = core.status.checkBlock.damage[`${x},${y}`]; + let deep = Infinity; + if (has(damage) && damage > 0) { + deep = 1; + } + bfs(core.status.floorId, deep); + }; +}, + "autoGet": function () { + var enable = true; + if (!enable) return; + // + // var noUpdate = false; + ////// 更新状态栏 ////// 不建议状态栏刷新后触发 容易导致录像不一致的问题 + //control.prototype.updateStatusBar = function (doNotCheckAutoEvents) { + // if (!core.isPlaying()) return; + // if (noUpdate) return; + // noUpdate = true; + // core.autoGetItem(); + // noUpdate = false; + // this.controldata.updateStatusBar(); + // if (!doNotCheckAutoEvents) core.checkAutoEvents(); + // this._updateStatusBar_setToolboxIcon(); + // core.clearRouteFolding(); + //} + + ////// 每移动一格后执行的事件 ////// + control.prototype.moveOneStep = function (callback) { + core.autoGetItem(); + core.autoBattle(); + return this.controldata.moveOneStep(callback); + } + + function bfsFlood(sx, sy, blockfn) { + var canMoveArray = core.generateMovableArray(); + var blocksObj = core.getMapBlocksObj(); + var bgMap = core.getBgMapArray(); + + var visited = [], + queue = []; + visited[sx + "," + sy] = 0; + queue.push(sx + "," + sy); + + while (queue.length > 0) { + var now = queue.shift().split(","), + x = ~~now[0], + y = ~~now[1]; + for (var direction in core.utils.scan) { + if (!core.inArray(canMoveArray[x][y], direction)) continue; + var nx = x + core.utils.scan[direction].x, + ny = y + core.utils.scan[direction].y, + nindex = nx + "," + ny; + if (visited[nindex]) continue; + if (core.onSki(bgMap[ny][nx])) continue; + if (blockfn && !blockfn(blocksObj, nx, ny)) continue; + visited[nindex] = visited[now] + 1; + queue.push(nindex); + } + } + } + + function attractAnimate() { + var name = 'attractAnimate'; + var isPlaying = false; + this.nodes = []; + + this.add = function (id, x, y, callback) { + this.nodes.push({ id: id, x: x, y: y, callback: callback }); + } + this.start = function () { + if (isPlaying) return; + isPlaying = true; + core.registerAnimationFrame(name, true, this.update); + this.ctx = core.createCanvas(name, 0, 0, core.__PIXELS__, core.__PIXELS__, 120); + } + this.remove = function () { + core.unregisterAnimationFrame(name); + core.deleteCanvas(name); + isPlaying = false; + } + this.clear = function () { + this.nodes = []; + this.remove(); + } + var lastTime = -1; + var self = this; + this.update = function (timeStamp) { + if (lastTime < 0) lastTime = timeStamp; + if (timeStamp - lastTime < 20) return; + lastTime = timeStamp; + core.clearMap(name); + var cx = core.status.heroCenter.px - 16, + cy = core.status.heroCenter.py - 16; + var thr = 5; //缓动比例倒数 越大移动越慢 + self.nodes.forEach(function (n) { + var dx = cx - n.x, + dy = cy - n.y; + if (Math.abs(dx) <= thr && Math.abs(dy) <= thr) { + n.dead = true; + } else { + n.x += ~~(dx / thr); + n.y += ~~(dy / thr); + } + core.drawIcon(name, n.id, n.x, n.y, 32, 32); + }); + self.nodes = self.nodes.filter(function (n) { + if (n.dead && n.callback) { + n.callback(); + } + return !n.dead; + }); + if (self.nodes.length == 0) + self.remove(); + } + } + + + var animateHwnd = new attractAnimate(); + + this.stopAttractAnimate = function () { + animateHwnd.clear(); + } + + this.autoGetItem = function () { + if (!flags.__autoGetItem__) return; + var canGetItems = {}; + if (!core.status.floorId || !core.status.checkBlock.damage || core.status.event.id == 'action' || core.status.lockControl) return; + + bfsFlood(core.getHeroLoc('x'), core.getHeroLoc('y'), function (blockMap, x, y) { + var idx = x + ',' + y; + if (idx in canGetItems) return false; + var blk = blockMap[idx]; + if (blk && !blk.disable && blk.event.cls == 'items' && !core.isMapBlockDisabled(core.status.floorId, blk.x, blk.y) && blk.event.trigger == 'getItem') { + canGetItems[idx] = { x: x, y: y, id: blk.event.id }; + return !core.status.checkBlock.damage[idx] && !core.status.checkBlock.ambush[idx]; + } + return core.maps._canMoveDirectly_checkNextPoint(blockMap, x, y); + }); + for (var k in canGetItems) { + var x = canGetItems[k].x, + y = canGetItems[k].y, + id = canGetItems[k].id; + core.trigger(x, y); + animateHwnd.add(id, x * 32, y * 32); + } + animateHwnd.start(); + } } } \ No newline at end of file