返回首頁 

Greasy Fork is available in English.

Building Health Bars

Shows the health of buildings.

// ==UserScript==// @name         Building Health Bars// @namespace    https://github.com/Nudo-o// @version      1// @description  Shows the health of buildings.// @author       @nudoo// @match        *://moomoo.io/*// @match        *://*.moomoo.io/*// @icon         https://www.google.com/s2/favicons?sz=64&domain=moomoo.io// @require      https://update.greasyfork.org/scripts/480301/1283571/CowJS.js// @require      https://update.greasyfork.org/scripts/480303/1282926/MooUI.js// @license      MIT// @grant        none// @run-at       document-start// ==/UserScript==(function() {"use strict"const { Cow, CowUtils, MooUI } = windowlet settings = {"health-bars": true,"circle-bars": false,"in-look-dir": false,"in-weapon-range": false,"weapon-range-mult": "1","bars-color": "#933db8","hit-counter": false}const settingsMap = Object.entries(settings)const storageName = "building-health-settings"function setVisualSetting(key, value) {settings[key] = valuelocalStorage.setItem(storageName, JSON.stringify(settings))}for (let i = 0; i < settingsMap.length; i++) {const visualSettings = JSON.parse(localStorage.getItem(storageName) || null)if (!visualSettings) {localStorage.setItem(storageName, JSON.stringify(settings))break}if (!visualSettings.hasOwnProperty(settingsMap[i][0])) {setVisualSetting(settingsMap[i][0], settingsMap[i][1])}}settings = JSON.parse(localStorage.getItem(storageName))const columnsSettings = {settings: {targetColumn: "settings",togglers: [{key: "health-bars",name: "Health bars",description: "Shows the health of buildings.",isActive: settings["health-bars"],options: [new MooUI.OptionCheckbox({key: "circle-bars",name: "Circle bars",description: "If enabled, the bars will be displayed as circles",isActive: settings["circle-bars"]}),new MooUI.OptionCheckbox({key: "in-look-dir",name: "In look dir",description: "Bars will be drawn only when you look in their direction.",isActive: settings["in-look-dir"]}),new MooUI.OptionCheckbox({key: "in-weapon-range",name: "In weapon range",description: "Bars will only be drawn when your weapon can reach them.",isActive: settings["in-weapon-range"]}),new window.MooUI.OptionIRange({key: "weapon-range-mult",name: "Weapon range mult",description: "Adds the distance to the range of the weapon so that the drawing of the bars is further than the distance of the weapon.",min: 1,max: 3,step: "any",fixValue: 1,value: settings["weapon-range-mult"]}),new window.MooUI.OptionIColor({key: "bars-color",name: "Color",description: "Color of bars",value: settings["bars-color"]})]}, {key: "hit-counter",name: "Hit counter",description: "Shows how many hits you need to hit the building.",isActive: settings["hit-counter"]}]}}class MenuBuilder {constructor() {this.menu = void 0this.settings = new MooUI.Column()}buildTogglers() {for (const columnSettings of Object.values(columnsSettings)) {const column = this[columnSettings.targetColumn]for (const toggler of columnSettings.togglers) {column.add(new MooUI.Checkbox(toggler))}}}build() {this.menu = MooUI.createMenu({toggleKey: {code: "Escape"},appendNode: document.getElementById("gameUI")})document.head.insertAdjacentHTML("beforeend", `<style>.column-container {border-radius: 0 0 6px 6px !important;}.ui-model {border-radius: 4px !important;}.ui-model.show-options {border-radius: 4px 4px 0px 0px !important;}.options-container {border-radius: 0px 0px 4px 4px !important;}.ui-option-input-color {border-radius: 4px !important;}</style>`)this.settings.setHeaderText("Settings")this.settings.collisionWidth = -999999this.buildTogglers()this.menu.add(this.settings)this.menu.onModelsAction(setVisualSetting)this.menu.columns.forEach((column) => {column.header.element.style.borderRadius = "6px"column.header.element.addEventListener("mousedown", (event) => {if (event.button !== 2) returncolumn.header.isOpen ??= falsecolumn.header.isOpen = !column.header.isOpencolumn.header.element.style.borderRadius = column.header.isOpen ? "6px 6px 0 0" : "6px"})})}}const menuBuilder = new MenuBuilder()let menu = void 0let lastWeaponRangeMultChange = nullwindow.addEventListener("DOMContentLoaded", () => {menuBuilder.build()menu = menuBuilder.menumenu.getModel("weapon-range-mult").on("input", () => {lastWeaponRangeMultChange = Date.now()})})function drawCircleBar(color, width, scale, endAngle) {const { context } = Cow.renderercontext.strokeStyle = colorcontext.lineWidth = widthcontext.lineCap = "round"context.beginPath()context.arc(0, 0, scale, 0, endAngle)context.stroke()context.closePath()}Cow.addRender("building-health-bars", () => {if (!Cow.player) returnconst { context } = Cow.rendererconst weaponRange = (Cow.player.weapon.range + Cow.player.scale / 2) * parseFloat(menu.getModelValue("weapon-range-mult"))if ((Date.now() - lastWeaponRangeMultChange) <= 1500) {const color = menu.getModelValue("bars-color")context.save()context.fillStyle = colorcontext.strokeStyle = colorcontext.globalAlpha = .3context.lineWidth = 4context.translate(Cow.player.renderX, Cow.player.renderY)context.beginPath()context.arc(0, 0, weaponRange, 0, Math.PI * 2)context.fill()context.globalAlpha = .7context.stroke()context.closePath()context.restore()} else {lastWeaponRangeMultChange = null}Cow.objectsManager.eachVisible((object) => {if (!object.isItem) returnconst distance = CowUtils.getDistance(Cow.player, object) - object.scaleconst angle = CowUtils.getDirection(object, Cow.player)if (menu.getModelActive("in-weapon-range") && distance > weaponRange) returnif (menu.getModelActive("in-look-dir") && CowUtils.getAngleDist(angle, Cow.player.lookAngle) > Cow.config.gatherAngle) returnif (menu.getModelActive("hit-counter")) {const damage = Cow.player.weapon.dmg * Cow.items.variants[Cow.player.weaponVariant].valconst damageAmount = damage * (Cow.player.weapon.sDmg || 1) * (Cow.player.skin?.id === 40 ? 3.3 : 1)const hits = Math.ceil(object.health / damageAmount)const offsetY = menu.getModelActive("circle-bars") ? 2 : 22context.save()context.font = `18px Hammersmith One`context.fillStyle = "#fff"context.textBaseline = "middle"context.textAlign = "center"context.lineWidth = 8context.lineJoin = "round"context.translate(object.renderX, object.renderY)context.strokeText(hits, 0, offsetY)context.fillText(hits, 0, offsetY)context.restore()}if (!menu.getModelActive("health-bars")) returnif (menu.getModelActive("circle-bars")) {const endAngle = ((object.health / object.maxHealth) * 360) * (Math.PI / 180)const width = 14const scale = 22context.save()context.translate(object.renderX, object.renderY)context.rotate(object.dir ?? object.dir2)drawCircleBar("#3d3f42", width, scale, endAngle)drawCircleBar(menu.getModelValue("bars-color"), width / 2.5, scale, endAngle)context.restore()return}const { healthBarWidth, healthBarPad } = window.configconst width = healthBarWidth / 2 - healthBarPad / 2const height = 17const radius = 8context.save()context.translate(object.renderX, object.renderY)context.fillStyle = "#3d3f42"context.roundRect(-width - healthBarPad, -height / 2, 2 * width + 2 * healthBarPad, height, radius)context.fill()context.fillStyle = menu.getModelValue("bars-color")context.roundRect(-width, -height / 2 + healthBarPad, 2 * width * (object.health / object.maxHealth), height - 2 * healthBarPad, radius - 1)context.fill()context.restore()})})})()