0. 游戏战斗页面
1. 前言
这篇文章主要是分享和记录我通过pyautogui、JavaScript、F12开发者工具实现梅尔沃放置(Melvor Idle)这个游戏的一些辅助功能(战斗时自动舔包、自动收菜、修改游戏数据)。小声叭叭:都怪EPIC在12月22日送的这个游戏,害得我之前天天盯着我的角色去砍奶牛,浪费了我好多刷视频的时间。。。
2. Python的PyAutoGUI库实现:自动舔包
2.1 定位舔包按钮的坐标-手动定位
1、下面代码用来输出鼠标在在主显示器中的(x, y)坐标
import pyautogui as pag
while True:
print(pag.position())
pag.sleep(0.3)
2、到游戏页面,把鼠标放在“拾取所有”按钮上,稍微停留一会获取到坐标(1782, 707)
3、切换到游戏页面,并在IDLE输入,每隔60秒会自动点一次主屏幕的该坐标(1782, 707):
while True:
pag.click(1782, 707)
pag.sleep(60)
2.2 定位舔包按钮的坐标-图片定位
1、事先截图保存按钮的图片,我放在该文件夹下“C:\Users\10479\Pictures\Screenshots”
2、在IDLE输入以下代码,每隔60秒会自动点一次该图片的中心点在主屏幕的坐标:
def f():
try:
x, y = pag.locateCenterOnScreen(r"C:\Users\10479\Pictures\Screenshots\屏幕截图 2024-01-10 203751.png", grayscale=True)
except pag.ImageNotFoundException:
print("未找到指定图片在主屏幕的坐标")
else:
while True:
pag.click(x, y)
pag.sleep(60)
3、切换到游戏页面,并在IDLE输入f(),运行脚本,注意不要将“拾取所有”按钮遮住
2.3 缺点
通过手动定位和图片定位,容易受到其他因素影响。比如,界面大小和位置、其他程序的弹窗、图片识别的准确度等等。于是改用JavaScript和油猴插件。
3. 通过JavaScript和油猴插件实现:自动舔包、自动收菜
3.1 自动舔包
1、使用右键、快捷键或直接点击的方式定位“拾取所有”按钮元素
右键 | F12-点击获取元素按钮 或 直接使用快捷键Ctrl + shift + C |
![]() | ![]() |
2、复制该元素的CSS选择器
3、在F12开发者工具中元素页面,按Ctrl + F打开搜索框,粘贴刚复制的css选择器(#combat-loot > div > div > div > div:nth-child(2) > h5 > button)能够唯一定位该按钮,同时该按钮高亮显示
4、来到F12开发者工具控制台页面,输入。可以看见掉落的物品全都拾取了。
// 输出该元素
document.querySelector("#combat-loot > div > div > div > div:nth-child(2) > h5 > button")
// 点击该元素
document.querySelector("#combat-loot > div > div > div > div:nth-child(2) > h5 > button").click()
5、在油猴插件新建脚本
6、修改脚本,设置定时器1000毫秒执行一次点击“拾取所有”按钮的操作,修改完按Ctrl + S保存
// ==UserScript==
// @name New Userscript
// @namespace http://tampermonkey.net/
// @version 2024-01-10
// @description try to take over the world!
// @author Lerdo
// @match https://melvoridle.com/index_game.php
// @icon https://www.google.com/s2/favicons?sz=64&domain=melvoridle.com
// @grant none
// ==/UserScript==
(function () {
'use strict';
var t1 = setInterval(()=>{
autoLoot()
}, 1000)
function autoLoot() {
// document.querySelector("lang-string[lang-id='COMBAT_MISC_46']").parentElement.click()
document.querySelector('#combat-loot > div > div > div > div:nth-child(2) > h5 > button').click()
}
})();
7、勾选并启用刚刚编辑的脚本:New Userscript
8、F5刷新界面,重新进入游戏,查看到脚本成功执行,实际游戏界面会自动舔包,不在战斗页面也可以自动舔包
3.2 自动舔包+自动收菜
懒得写了直接上代码:
(function () {
'use strict';
var t1 = setInterval(()=>{
autoLoot()
oneKeyHarvest()
}, 1000)
function autoLoot() {
document.querySelector("lang-string[lang-id='COMBAT_MISC_46']").parentElement.click()
}
function oneKeyHarvest() {
// 1. 检查到农务在闪烁(检查到闪烁的li数量>0)
if (document.querySelectorAll('div[class="content-side content-side-full pt-1"] > ul > li > li[class="nav-main-item glow-animation"]').length) {
// 2. 农作物、草药、树木全部尝试收获一遍
// 2.1 更新农作物的farming-plot(每个种菜格子)并收获,点击a标签会触发更新农作物类farming-plot
// farming-category-button:nth-child(1) 索引从1开始而不是0,表示第1个farming-category-button
document.querySelector('div[id="farming-category-container"] > farming-category-button:nth-child(1) > a').click()
// farming-plot-container > 已解锁且不是d-done类(d-done不显示)的farming-plot > div > 第4个div > 第1个p > 不是d-done类(d-done不显示)的button
document.querySelectorAll('#farming-plot-container>farming-plot[class="col-6 col-xl-3"]>div>div:nth-child(4)>p:first-of-type>button[class="btn btn-lg btn-success mr-1"]').forEach((item) => {
item.click()
})
// 2.2 更新草药的farming-plot(每个种菜格子)并收获,点击a标签会触发更新草药类farming-plot
// farming-category-button:nth-child(2) 表示第2个farming-category-button
document.querySelector('div[id="farming-category-container"]>farming-category-button:nth-child(2)>a').click()
document.querySelectorAll('#farming-plot-container>farming-plot[class="col-6 col-xl-3"]>div>div:nth-child(4)>p:first-of-type>button[class="btn btn-lg btn-success mr-1"]').forEach((item) => {
item.click()
})
// 2.3 更新树木的farming-plot(每个种菜格子)并收获,点击a标签会触发更新树木类farming-plot
// farming-category-button:nth-child(3) 表示第3个farming-category-button
document.querySelector('div[id="farming-category-container"]>farming-category-button:nth-child(3)>a').click()
document.querySelectorAll('#farming-plot-container>farming-plot[class="col-6 col-xl-3"]>div>div:nth-child(4)>p:first-of-type>button[class="btn btn-lg btn-success mr-1"]').forEach((item) => {
item.click()
})
}
}
})();
4. 浏览器F12开发者工具实现游戏修改
找的流程太繁琐,懒得写了,直接上控制台js代码。建议备份存档
4.1 战斗
添加1金币 | game.gp.add(1) |
删除1金币 | game.gp.remove(1) |
添加1个屠杀者硬币 | game.slayerCoins.add(1) |
添加1点祝祭点 | game.combat.player.addPrayerPoints(1) |
设置自动舔包周期为2000ms(游戏在前台才会自动拾取) | let intervalId = setInterval(() => { document.querySelector("#combat-loot > div > div.block-header.block-header-default.bg-dark-bank-block-header.px-3.py-1.mb-2 > div > div.col-4 > h5 > button").click() }, 2000); |
再次修改自动舔包周期用这个(游戏在前台才会自动拾取) | {clearInterval(intervalId); intervalId = setInterval(() => { document.querySelector("#combat-loot > div > div.block-header.block-header-default.bg-dark-bank-block-header.px-3.py-1.mb-2 > div > div.col-4 > h5 > button").click() }, 5000);} |
设置已装备的武器攻击周期为25ms | game.combat.player.equipmentSets.forEach((equipmenSet) => {if (equipmenSet.equipment.equippedItems["melvorD:Weapon"].item.equipmentStats.length > 0 ) {if (equipmenSet.equipment.equippedItems["melvorD:Weapon"].item.equipmentStats[0].key === "attackSpeed") {equipmenSet.equipment.equippedItems["melvorD:Weapon"].item.equipmentStats[0].value = 25}}}) |
设置所有武器攻击周期为25ms | game.items.weapons.registeredObjects.forEach((i) => {i.equipmentStats[0].value = 25}) |
设置怪物重生时间为10ms | game.combat.player.baseSpawnInterval = 10 |
设置当前怪物的普通攻击间隔 | game.combat.enemy.monster.equipmentStats[0].value *= 10 |
设置所有怪物的普通攻击间隔时间为原来的10倍 | game.monsters.registeredObjects.forEach((value, key) => {if((value.equipmentStats.length > 0) && (value.equipmentStats[0].key === "attackSpeed")){value.equipmentStats[0].value *= 10}}) |
设置攻击生命偷取为2000%,怪物也会获得生命偷取 | game.combat.player.availableAttacks[0].attack.lifesteal = 2000 |
设置当前近战风格经验倍率100,默认为4 | game.combat.player.attackStyles.melee.experienceGain[0].ratio = 100 |
设置当前远程风格经验倍率100,默认为4 | game.combat.player.attackStyles.ranged.experienceGain[0].ratio = 100 |
设置当前魔法风格经验倍率100,默认为4 | game.combat.player.attackStyles.magic.experienceGain[0].ratio = 100 |
设置标准魔法符文消耗为0 | game.standardSpells.registeredObjects.forEach((i) => {i.runesRequired.forEach((j) => {j.quantity = 0}); if (i.hasOwnProperty("runesRequiredAlt")) {i.runesRequiredAlt.forEach((j) => {j.quantity = 0})}}) |
设置古代魔法符文消耗为0 | game.ancientSpells.registeredObjects.forEach((i) => {i.runesRequired.forEach((j) => {j.quantity = 0})}) |
设置诅咒魔法符文消耗为0 | game.curseSpells.registeredObjects.forEach((i) => {i.runesRequired.forEach((j) => {j.quantity = 0})}) |
设置光环咒语符文消耗为0 | game.auroraSpells.registeredObjects.forEach((i) => {i.runesRequired.forEach((j) => {j.quantity = 0})}) |
4.2 农务
添加1000的农务技能经验(其他类型经验在输入add后根据代码提示修改) | game.farming.addXP(1000) |
设置所有作物生长时间为250ms | game.farming.actions.registeredObjects.forEach((i) => {i.baseInterval = 250}) |
设置所有作物每次种植消耗数量为1 | game.farming.actions.registeredObjects.forEach((value, key) => {value.seedCost.quantity = 1}) |
设置所有作物收获时的基础数量为20(这个数量是未计算增益的) | game.farming.actions.registeredObjects.forEach((i) => {i.baseQuantity = 20}) |
设置每个农田的生长率为100%(收获后失效) | game.farming.plots.registeredObjects.forEach(i => {i.compostLevel = 100}) |
4.3 城镇
添加1000的城镇技能经验 | game.township.addXP(1000) |
设置城镇所有任务的需求数量为1(不包括休闲任务) | game.township.tasks.tasks.registeredObjects.forEach((i) => {i.goals.allGoals.forEach((j) => {j.quantity = 1})}) |
设置城镇的所有休闲任务需求数量为1 | game.township.casualTasks.allCasualTasks.registeredObjects.forEach(i => {i.goals.allGoals.forEach(j => {j.quantity = 1})}) |
所有建筑花费设置为0 | game.township.buildings.registeredObjects.forEach((i) => {i.costs.forEach((j) => {j.forEach((k) => {k.quantity = 0})})}) |
添加1食物(更新后有效) | game.township.resources["registeredObjects"].get("melvorF:Food").amount = 1 |
添加1木材(更新后有效) | game.township.resources["registeredObjects"].get("melvorF:Wood").amount = 1 |
添加1石材(更新后有效) | game.township.resources["registeredObjects"].get("melvorF:Stone").amount = 1 |
添加1矿石(更新后有效) | game.township.resources["registeredObjects"].get("melvorF:Ore").amount = 1 |
添加1煤炭(更新后有效) | game.township.resources["registeredObjects"].get("melvorF:Coal").amount = 1 |
添加1矿石锭(更新后有效) | game.township.resources["registeredObjects"].get("melvorF:Bar").amount = 1 |
添加1草药(更新后有效) | game.township.resources["registeredObjects"].get("melvorF:Herbs").amount = 1 |
添加1符文精华(更新后有效) | game.township.resources["registeredObjects"].get("melvorF:Rune_Essence").amount = 1 |
添加1皮革(更新后有效) | game.township.resources["registeredObjects"].get("melvorF:Leather").amount = 1 |
添加1药水(更新后有效) | game.township.resources["registeredObjects"].get("melvorF:Potions").amount = 1 |
添加1板材(更新后有效) | game.township.resources["registeredObjects"].get("melvorF:Planks").amount = 1 |
添加1服装(更新后有效) | game.township.resources["registeredObjects"].get("melvorF:Clothing").amount = 1 |
4.4 伐木
添加1000的伐木技能经验 | game.woodcutting._xp += 1000 |
添加1000的伐木技能精通池经验 | game.woodcutting._masteryPoolXP += 1000 |
设置所有树木的伐木间隔为10ticks | game.woodcutting.actions.registeredObjects.forEach((i) => {i.baseInterval = 10}) |
鸟巢掉落率增加100% | game.modifiers.increasedBirdNestDropRate += 100 |
设置同时砍树的数量上限为9 | (这条不是控制台指令,需要手动修改) 1.开发者工具进入【源代码】工具 2.在top/melvoridle.com/assets/js/built文件路径下,找到woodcutting.js文件 3.在该文件168行修改treeCutLimit()方法为如下 4.ctrl+s保存,立即生效 |
4.5 钓鱼
添加1000的钓鱼技能经验 | game.fishing._xp += 1000 |
添加1000的钓鱼技能精通池经验 | game.fishing._masteryPoolXP += 1000 |
设置所有鱼的钓鱼间隔为10ticks | game.fishing.actions.registeredObjects.forEach((i) => {i.baseMaxInterval = 10; i.baseMinInterval = 10;}) |
设置所有钓鱼区域渔获率60%、垃圾掉率1%、特殊掉率39% | game.fishing.areas.registeredObjects.forEach((i) => {i.fishChance = 60; i.junkChance = 1; i.specialChance = 39}) |
设置当前钓鱼区域渔获率10%、垃圾钓率0%、特殊钓率90% | {game.fishing.activeFishingArea.fishChance = 10; game.fishing.activeFishingArea.junkChance = 0; game.fishing.activeFishingArea.specialChance = 90;} |
设置钓鱼获得各种特殊渔获的权重相同 | {game.fishing.specialItems.totalWeight = 0; game.fishing.specialItems.drops.forEach((i) => {i.weight = 1; game.fishing.specialItems.totalWeight += 1})} |
4.6 生火
设置木材燃烧间隔为250ms | game.firemaking.actions.registeredObjects.forEach((i) => {i.baseInterval = 250}) |
设置篝火的持续时间为原来的100倍 | game.firemaking.actions.registeredObjects.forEach((i) => {i.baseBonfireInterval *= 100}) |
设置每次点燃篝火消耗的木材数量为1 | game.firemaking.actions.registeredObjects.forEach((i) => {i.bonfireCost = 1}) |
设置当前点燃的篝火经验值加成为20% | game.firemaking.litBonfireRecipe.bonfireXPBonus = 20 |
设置煤矿石和灰烬的掉率为100% | game.firemaking.primaryProducts.forEach((i) => {i.chance = 100}) |
设置每次掉落数量为100 | game.firemaking.primaryProducts.forEach((i) => {i.quantity = 100}) |
4.7 烹饪
添加1000的烹饪技能经验 | game.cooking.addXP(1000) |
设置所有食物的烹饪时间为250ms | game.cooking.actions.registeredObjects.forEach((i) => {i.baseInterval = 250}) |
设置所有食物原材料的消耗为1 | game.cooking.actions.registeredObjects.forEach((i) => {i.itemCosts.forEach((j) => {j.quantity = 1})}) |
设置所有食物每次烹饪生成的数量为10 | game.cooking.actions.registeredObjects.forEach((i) => {i.baseQuantity= 10}) |
4.8 采矿
4.9 锻造
4.10 扒窃
设置扒窃基础间隔为250ms | game.thieving.baseInterval = 250 |
设置眩晕基础时长为250ms | game.thieving.baseStunInterval = 250 |
设置扒窃到物品的几率100% | game.thieving.itemChance = 100 |
设置所有扒窃NPC感知为1 | game.thieving.actions.registeredObjects.forEach((item) => {item.perception = 1}) |
设置扒窃到的物品数量为原来的10倍 | {ratio = 10; game.thieving.actions.registeredObjects.forEach((i) => {i.lootTable.drops.forEach((j) => {j.maxQuantity *= ratio; j.minQuantity *= ratio})})} |
4.11 弓匠
4.12 制造
4.13 符文锻造
4.14 草药学
4.15 灵巧
4.16 召唤
4.17 星象学
4.18 生活类魔法
4.19 其他
设置宝箱类物品开启物品数量为原来10倍 | game.items.openables.registeredObjects.forEach((i) => {ratio = 10; i.dropTable.drops.forEach((j) => {j.maxQuantity *= ratio; j.minQuantity *= ratio})}) |
设置宝箱类物品,开启物品概率相同 | game.items.openables.registeredObjects.forEach((i) => {i.dropTable.totalWeight = 0; i.dropTable.drops.forEach((j) => {j.weight = 1; i.dropTable.totalWeight += 1})}) |