梅尔沃放置(Melvor Idle)从Python、JavaScript自动化到F12开发者工具更改游戏数值

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[] > ul > li > li[]').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[]>div>div:nth-child(4)>p:first-of-type>button[]').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[]>div>div:nth-child(4)>p:first-of-type>button[]').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[]>div>div:nth-child(4)>p:first-of-type>button[]').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)

设置已装备的武器攻击周期为25ms

game.combat.player.equipmentSets.forEach((equipmenSet) => {if (equipmenSet.equipment.slots.Weapon.item.equipmentStats.length > 0 ) {if (equipmenSet.equipment.slots.Weapon.item.equipmentStats[0].key === "attackSpeed") {equipmenSet.equipment.slots.Weapon.item.equipmentStats[0].value = 25}}})
设置所有武器攻击周期为25msgame.items.weapons.registeredObjects.forEach((i) => {i.equipmentStats[0].value = 25})

设置怪物重生时间为10ms    

game.combat.player.baseSpawnInterval = 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})})
设置诅咒魔法符文消耗为0game.curseSpells.registeredObjects.forEach((i) => {i.runesRequired.forEach((j) => {j.quantity = 0})})
设置光环咒语符文消耗为0game.auroraSpells.registeredObjects.forEach((i) => {i.runesRequired.forEach((j) => {j.quantity = 0})})

4.2 农务

4.3 城镇

添加1000的城镇技能经验

game.township._xp += 1000

添加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
所有建筑花费设置为0game.township.buildings.registeredObjects.forEach((i) => {i.costs.forEach((j) => {j.forEach((k) => {k.quantity = 0})})})

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

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 生火

4.7 烹饪

4.8 采矿

4.9 锻造

4.10 扒窃

设置扒窃基础间隔为250ms

game.thieving.baseInterval = 250

设置眩晕基础时长为250ms

game.thieving.baseStunInterval = 250

设置扒窃到物品的几率100%

game.thieving.itemChance = 100
设置所有扒窃NPC感知为1game.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})})