您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Plugin for Planets.nu which helps to find homeworlds and show areas
// ==UserScript== // @name Planets.nu - Meteor's Homeworlds Plugin // @description Plugin for Planets.nu which helps to find homeworlds and show areas // @namespace Planets.nu // @version 2.4 // @grant none // @date 2022-01-02 // @author meteor // @include http://planets.nu/* // @include http://*.planets.nu/* // @include https://planets.nu/* // @include https://*.planets.nu/* // @exclude http://help.planets.nu/* // @exclude https://help.planets.nu/* // @exclude http://profile*.planets.nu/* // @exclude https://profile*.planets.nu/* // @exclude http://planets.nu/_library/* // @exclude http://api.planets.nu/* // ==/UserScript== /* ----------------------------------------------------------------------- Change log: 2.0: - Feature: Support for new/mobile client added - Bug-Fix: checks for Meteor's Library improved 2.1: - Bug-Fix: Treatment of intersection points for parallel lines was incorrect 2.2: - Feature: New switch to use only very close planets (81 ly) 2.3: - Feature from 2.2. removed - Feature: 6 levels of potential HW prediction and button to switch through them 2.4: - Feature Improved delta comparison (less false positives) - incl. Bug-Fix: some ambiguous planets between 80..82 ly and 161..163 ly were counted or ignored twice - Details: no negative delta; positive delta = 1 / sqrt(2); positive delta applies for veryclose-, close- and next-planets - Bug-Fix: A selected HW had a brown square around the red square when it was a high-level (thick-square) potential HW and both potential and selected were shown. Not nice to look at and maybe confusing => only the red one now - Change: tools menu interaction - Exit-Button added (all clients) - In the old client (play.planets.nu): - the way the homeworldtools button group interacts with the tool menu is renewed. - Blocking the map tools from closing was removed - incl. Bug-Fix: after exiting the game while the homeworldtools were open and entering any game (same or other) the map tools didn't work any more - "side effect": - Now, when you close the maptools while the homeworldtools are open, the homeworldtools will stay open. - You can close them with the new exit button, or reopen the maptools and toggle the HW-button there. - While not perfect, this is usable and will not be changed any more (if you don't like it, call it a known bug ;)) - Feature: Simple support for debris disks (alpha) - Details: - The central planetoid of a debris disk counts as a planet assuming it is in the position of an original planet. - Other planetoids do not count. - There is no attempt to incorporate planets drift due to the creation of a debris disks/explosion of the planet. ----------------------------------------------------------------------- */ "use strict"; function wrapper(plugin_version) { let fullName = "Meteor's Homeworlds Plugin"; if (typeof xLibrary == 'undefined') { window.alert("Cannot start " + fullName + "!\n\nThe plugin requires Meteor's Library.\nIf the library is installed already make sure it runs before the plugin."); throw "Cannot start " + fullName + ". Meteor's Library not found. Plugin disabled."; } let plugin = new XPlugin(fullName, "xHomeworlds", plugin_version, -20160918, 2.1); plugin.setLogEnabled(false); let containerRight = xUtils.isMobileClient() ? 40 : 240; let css = "<style type='text/css'>"; css += "#HWToolsContainer {position: absolute; right: " + containerRight + "px; z-index: 16; height: 30px;}"; css += "#HWToolsContainer .mapbutton {margin-left: 10px; margin-bottom: 10px; float: left;}"; css += ".HWTools::before {position: absolute; left: 7px; top: 7px; width: 16px; height: 16px; content: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAV0lEQVQ4jWNgYGD4TyHGLflWRoU0AwhpwCGPXTEyINkL6JoIGILqNFyKkcXRvILfdiJcQVx0UWQASWFAjGa8YUCCzVQ2gMhki00dDbyAbgsB1xGXDnBhAEpcONJRmdhMAAAAAElFTkSuQmCC');}"; css += ".HWPotential::before {position: absolute; left: 7px; top: 7px; width: 16px; height: 16px; content: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAQ0lEQVQ4jWNgYGD4TyGmkgH/DzSQhLEaQKytRBnA+P8/CibJAHTN6IbgNQCXZmRDhrsBFAciVaKR7IREUVKmODORiwGQfMmwgj8zPAAAAABJRU5ErkJggg==');}"; css += ".HWSelected::before {position: absolute; left: 7px; top: 7px; width: 16px; height: 16px; content: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAQ0lEQVQ4jWNgYGD4TyGmkgFvZVRIwlgNINZWogxg/P8fBZNkALpmdEPwGoBLM7Ihw90AigORKtFIdkKiKClTnJnIxQDXSJqYYNY0/QAAAABJRU5ErkJggg==');}"; css += ".HWPieslices::before {position: absolute; left: 7px; top: 7px; width: 16px; height: 16px; content: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABEAAAAQCAYAAADwMZRfAAAASklEQVQ4jWNgYGD4Twn+////fwYYgxLAgGQauum4bEXh09YQYg2mjyHI4vjkCRpCjByKIZQA6rqEJmGCLoZLDW0NIeQ92hpCCQAAX3xOztMy/IoAAAAASUVORK5CYII=');}"; css += ".HWAreas::before {position: absolute; left: 7px; top: 7px; width: 16px; height: 16px; content: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAZElEQVQ4jZWSMRIAIQgD9/+fzhVe4aiEUNAgLBECIEkCrqjyR9TFHeB/9w2BOt8QQO8HB3kA+8kVGNDKmn/a5tcOpvsoAQNv1HIjyLmDUPY+sJfeODIrjK6QeD820uC8c8Be/wE4e5R6/RMhbwAAAABJRU5ErkJggg==');}"; css += ".HWSelectMode::before {position: absolute; left: 7px; top: 7px; width: 16px; height: 16px; content: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAATUlEQVQ4jbXSMQ4AIAwCQP7/aVyN2gIaB5YON1AAgHNIcr2J7ECInIEAqQET6QED0YBAPKBBfKBAPnUQbKJfYlzixTL12qIvfAEE8gYMPuqsYu1i0jgAAAAASUVORK5CYII=');}"; css += ".HWSave::before {position: absolute; left: 7px; top: 7px; width: 16px; height: 16px; content: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAS0lEQVQ4jWNgYGD4TyGGMBwc/pOEcRpACOA0ACb5//////X19VgxshrquwDZAEIuoE0YUM0AiqORYgMYGA7gxSQYwDDUDKA4N5KLAVUbBv9JdSpFAAAAAElFTkSuQmCC');}"; css += "</style>"; $("head:first").append(css); const DELTA = 1 / Math.sqrt(2); const MAX_LEVEL = 6; const LEVEL_COLORS = ["#806020", "#C09050", "#FFC080", "#FFC080", "#FFC080", "#FFE0A0"]; plugin.toolsContainerTop = 12; plugin.processload = function() { plugin.selectedHomeworlds = plugin.getObjectFromNote(0); if (plugin.selectedHomeworlds == null) { plugin.selectedHomeworlds = new Array(); } plugin.isSelectedHomeworldsModified = false; plugin.show = plugin.getObjectFromNote(1); if (plugin.show == null) { plugin.show = { potentialHomeworlds: false, selectedHomeworlds: false, pieslices: false, areas: false, }; } if (plugin.show.level == null) { plugin.show.level = (vgap.settings.nextplanets > 0) ? 2 : 3; } plugin.isInSelectMode = false; if (plugin.gameId != vgap.game.id) { plugin.gameId = vgap.game.id; } plugin.potentialHomeworlds = null; plugin.homeworldAreas = null; plugin.initPotentialHomeworlds(); }; plugin.initPotentialHomeworlds = function() { let planets = []; for (let i = 0; i < vgap.planets.length; i++) { let planet = vgap.planets[i]; if (planet.id < 0) { continue; } if (planet.debrisdisk > 0) { continue; } planets.push(planet); } for (let planet of vgap.debrisdisks) { if (planet.id < 0) { continue; } planets.push(planet); } let counts = []; for (let i = 0; i < planets.length; i++) { counts.push( { veryClose: 0, veryCloseAmbiguous: 0, totalClose: 0, totalCloseAmbiguous: 0, totalNext: 0, totalNextAmbiguous: 0 }); } for (let i = 0; i < planets.length; i++) { let p1 = planets[i]; for (let k = i + 1; k < planets.length; k++) { let p2 = planets[k]; let dist = xMapUtils.getSphereDistance(p1, p2); if (plugin.isLogEnabled() // && ( ((dist > 80) && (dist < 82)) // || ((dist > 161) && (dist < 163)) // || ((dist > 323) && (dist < 325)))) { plugin.log(p1.id + " <-> " + p2.id + " = " + dist); } if (dist < 81 + DELTA) { counts[i].veryClose++; counts[i].totalClose++; counts[i].totalNext++; counts[k].veryClose++; counts[k].totalClose++; counts[k].totalNext++; if (dist > vgap.settings.otherplanetsminhomeworlddist) { counts[i].veryCloseAmbiguous++; counts[i].totalCloseAmbiguous++; counts[i].totalNextAmbiguous++; counts[k].veryCloseAmbiguous++; counts[k].totalCloseAmbiguous++; counts[k].totalNextAmbiguous++; } else if (dist > 81) { counts[i].veryCloseAmbiguous++; counts[k].veryCloseAmbiguous++; } } else if (dist < 162 + DELTA) { counts[i].totalClose++; counts[i].totalNext++; counts[k].totalClose++; counts[k].totalNext++; if (dist > vgap.settings.otherplanetsminhomeworlddist) { counts[i].totalCloseAmbiguous++; counts[i].totalNextAmbiguous++; counts[k].totalCloseAmbiguous++; counts[k].totalNextAmbiguous++; } else if (dist > 162) { counts[i].totalCloseAmbiguous++; counts[k].totalCloseAmbiguous++; } } else if (dist < 324 + DELTA) { counts[i].totalNext++; counts[k].totalNext++; if ((dist > 324) || (dist > vgap.settings.otherplanetsminhomeworlddist)) { counts[i].totalNextAmbiguous++; counts[k].totalNextAmbiguous++; } } } } plugin.potentialHomeworlds = []; for (let level = 0; level < MAX_LEVEL; level++) { plugin.potentialHomeworlds.push([]); } if (plugin.isLogEnabled()) { for (let i = 0; i < counts.length; i++) { if (planets[i].id >= 0) { plugin.log(planets[i].id + ": [" + counts[i].veryClose + ", " + counts[i].veryCloseAmbiguous + ", " + counts[i].totalClose + ", " + counts[i].totalCloseAmbiguous + ", " + counts[i].totalNext + ", " + counts[i].totalNextAmbiguous + "]"); } } } let veryClose = vgap.settings.verycloseplanets; let totalClose = veryClose + vgap.settings.closeplanets; let totalNext = totalClose + (vgap.settings.nextplanets > 0 ? vgap.settings.nextplanets : 0); for (let i = 0; i < counts.length; i++) { let count = counts[i]; if ((count.veryClose >= veryClose) && (count.veryClose - count.veryCloseAmbiguous <= veryClose)) { plugin.potentialHomeworlds[0].push(planets[i].id); if (count.totalClose >= totalClose) { plugin.potentialHomeworlds[1].push(planets[i].id); let isCloseExact = false; if (count.totalClose - count.totalCloseAmbiguous <= totalClose) { isCloseExact = true; plugin.potentialHomeworlds[3].push(planets[i].id); } if ((vgap.settings.nextplanets > 0) && (count.totalNext >= totalNext)) { plugin.potentialHomeworlds[2].push(planets[i].id); if (isCloseExact) { plugin.potentialHomeworlds[4].push(planets[i].id); if (count.totalNext - count.totalNextAmbiguous <= totalNext) { plugin.potentialHomeworlds[5].push(planets[i].id); } } } } } } if (plugin.isLogEnabled()) { for (let level = 0; level < MAX_LEVEL; level++) { if (!plugin.isLevelAvailable(level)) { continue; } let potentialHomeworldIds = "potentialHomeworldIds[" + (level + 1) + "] = ["; for (let i = 0; i < plugin.potentialHomeworlds[level].length; i++) { potentialHomeworldIds += ((i > 0) ? ", " : "") + plugin.potentialHomeworlds[level][i]; } plugin.log(potentialHomeworldIds + "]"); } } }; plugin.isLevelAvailable = function(level) { return (vgap.settings.nextplanets > 0) || (level == 0) || (level == 1) || (level == 3); }; plugin.calculateAreas = function() { if (plugin.selectedHomeworlds.length == 0) { return; } plugin.homeworldAreas = []; let mapBoundingRect = xMapUtils.getMapBoundingRect(); let mapWidth = mapBoundingRect.getWidth(); let mapHeight = mapBoundingRect.getHeight(); let allLines = []; for (let i = 0; i < plugin.selectedHomeworlds.length; i++) { let p1 = XPoint.fromPoint(vgap.getPlanet(plugin.selectedHomeworlds[i])); let lines = []; for (let j = 0; j < plugin.selectedHomeworlds.length; j++) { if (j == i) { continue; } let p2 = XPoint.fromPoint(vgap.getPlanet(plugin.selectedHomeworlds[j])); lines.push(XLine.getPerpendicularBisector(p1, p2)); if (vgap.settings.sphere) { lines.push(XLine.getPerpendicularBisector(p1, p2.offsetXY(-mapWidth, -mapHeight))); lines.push(XLine.getPerpendicularBisector(p1, p2.offsetXY(-mapWidth, 0))); lines.push(XLine.getPerpendicularBisector(p1, p2.offsetXY(-mapWidth, +mapHeight))); lines.push(XLine.getPerpendicularBisector(p1, p2.offsetXY(0, -mapHeight))); lines.push(XLine.getPerpendicularBisector(p1, p2.offsetXY(0, +mapHeight))); lines.push(XLine.getPerpendicularBisector(p1, p2.offsetXY(+mapWidth, -mapHeight))); lines.push(XLine.getPerpendicularBisector(p1, p2.offsetXY(+mapWidth, 0))); lines.push(XLine.getPerpendicularBisector(p1, p2.offsetXY(+mapWidth, +mapHeight))); } } if (vgap.settings.sphere) { lines.push(XLine.getPerpendicularBisector(p1, p1.offsetXY(-mapWidth, -mapHeight))); lines.push(XLine.getPerpendicularBisector(p1, p1.offsetXY(-mapWidth, 0))); lines.push(XLine.getPerpendicularBisector(p1, p1.offsetXY(-mapWidth, +mapHeight))); lines.push(XLine.getPerpendicularBisector(p1, p1.offsetXY(0, -mapHeight))); lines.push(XLine.getPerpendicularBisector(p1, p1.offsetXY(0, +mapHeight))); lines.push(XLine.getPerpendicularBisector(p1, p1.offsetXY(+mapWidth, -mapHeight))); lines.push(XLine.getPerpendicularBisector(p1, p1.offsetXY(+mapWidth, 0))); lines.push(XLine.getPerpendicularBisector(p1, p1.offsetXY(+mapWidth, +mapHeight))); } else { lines.push(mapBoundingRect.getLeftSection().getLine()); lines.push(mapBoundingRect.getRightSection().getLine()); lines.push(mapBoundingRect.getTopSection().getLine()); lines.push(mapBoundingRect.getBottomSection().getLine()); } allLines.push(lines); } iterate_homeworlds: // for (let i = 0; i < plugin.selectedHomeworlds.length; i++) { let homeworld = vgap.getPlanet(plugin.selectedHomeworlds[i]); let p1 = XPoint.fromPoint(homeworld); lines = allLines[i]; let closestP2 = null; let closestDist = mapWidth + mapHeight; let startLine; let startPoint; if (plugin.selectedHomeworlds.length == 1) { let virtualP2 = new XPoint(p1.x - mapWidth, p1.y); startLine = lines[1]; // intentionally not 0, suits to virtualP2 in both cases startPoint = startLine.getIntersectionPoint(XLine.fromPoints(p1, virtualP2)); } else { for (let j = 0; j < plugin.selectedHomeworlds.length; j++) { if (j == i) { continue; } let p2 = XPoint.fromPoint(vgap.getPlanet(plugin.selectedHomeworlds[j])); let dist = xMapUtils.getSphereDistance(p1, p2); if (dist < closestDist) { closestDist = dist; closestP2 = p2; } } if (vgap.settings.sphere) { if (closestP2.x - p1.x > mapWidth / 2) { closestP2.x -= mapWidth; } if (closestP2.x - p1.x < -mapWidth / 2) { closestP2.x += mapWidth; } if (closestP2.y - p1.y > mapHeight / 2) { closestP2.y -= mapHeight; } if (closestP2.y - p1.y < -mapHeight / 2) { closestP2.y += mapHeight; } } startLine = XLine.getPerpendicularBisector(p1, closestP2); startPoint = startLine.getIntersectionPoint(XLine.fromPoints(p1, closestP2)); } let heading = xMapUtils.getHeading(p1, startPoint) + 90; if (heading >= 360) { heading -= 360; } let area = []; let maxCycles = lines.length + 2; for (var cycle = 0; cycle < maxCycles; cycle++) { let bestPoint = null; let bestLine = null; let bestHeading = null; for (let k = 0; k < lines.length; k++) { let curLine = lines[k]; let curPoint = startLine.getIntersectionPoint(curLine); if (curPoint != null) { if (((bestPoint != null) && (curPoint.x == bestPoint.x) && (curPoint.y == bestPoint.y) && this.isBetterHeading(this.getNewHeading(curLine, heading), bestHeading, heading)) || this.isCloser(curPoint, bestPoint, startPoint, heading)) { bestPoint = curPoint; bestLine = curLine; bestHeading = this.getNewHeading(bestLine, heading); } } } if (bestPoint == null) { plugin.logWarning("bestPoint not found"); continue iterate_homeworlds; } if ((area.length > 0) && (area[0].x == bestPoint.x) && (area[0].y == bestPoint.y)) { plugin.homeworldAreas.push( { homeworld: homeworld, area: area }); break; } area.push(bestPoint); startPoint = bestPoint; startLine = bestLine; heading = bestHeading; } if (cycle >= maxCycles) { plugin.logWarning("Cannot calculate area!"); for (i = 0; i < area.length; i++) { plugin.logWarning("area[" + i + "] = (" + area[i].x + ", " + area[i].y + ")"); } } } }; plugin.isCloser = function(curPoint, bestPoint, startPoint, heading) { if (curPoint == null) { return false; } if ((heading >= 45) && (heading < 135)) { return ((curPoint.x > startPoint.x) && ((bestPoint == null) || (curPoint.x < bestPoint.x))); } if ((heading >= 135) && (heading < 225)) { return ((curPoint.y < startPoint.y) && ((bestPoint == null) || (curPoint.y > bestPoint.y))); } if ((heading >= 225) && (heading < 315)) { return ((curPoint.x < startPoint.x) && ((bestPoint == null) || (curPoint.x > bestPoint.x))); } return ((curPoint.y > startPoint.y) && ((bestPoint == null) || (curPoint.y < bestPoint.y))); }; plugin.getNewHeading = function(line, curHeading) { let newHeading = line.getHeading(); while (newHeading < curHeading) { newHeading += 180; } if (newHeading >= 360) { newHeading -= 360; } return newHeading; }; plugin.isBetterHeading = function(newHeading, bestHeading, curHeading) { let h2 = newHeading; if (h2 - curHeading < 0) { h2 += 360; } let h1 = bestHeading; if (h1 - curHeading < 0) { h1 += 360; } return h2 > h1; }; plugin.loadmap = function() { xMapUtils.addMapTool("Homeworlds", "HWTools", plugin.toggleHomeworldTools); }; plugin.toggleHomeworldTools = function(e) { if ($("#HWToolsContainer").length == 0) { plugin.openHomeworldTools(e); } else { plugin.closeHomeworldTools(e); } }; plugin.openHomeworldTools = function(e) { if (e != null) { e.stopPropagation(); e.preventDefault(); } $(".HWTools").toggleClass(xUtils.isMobileClient() ? "toolactive" : "selectedmaptool", true); plugin.updateHomeworldTools(); } plugin.closeHomeworldTools = function(e) { if (e != null) { e.stopPropagation(); e.preventDefault(); } if (plugin.isInSelectMode) { plugin.toggleSelectMode(e); } plugin.saveObjectAsNote(1, plugin.show); $("#HWToolsContainer").remove(); $(".HWTools").toggleClass(xUtils.isMobileClient() ? "toolactive" : "selectedmaptool", false); vgap.map.closeTools(); }; plugin.updateHomeworldTools = function() { $("#HWToolsContainer").remove(); let showPieslicesButton = ((vgap.settings.hwdistribution == 2) // hw in a circle || (vgap.settings.hwdistribution == 4)); // center + circle (MvM) $("<div id='HWToolsContainer'></div>").appendTo("#MapControls"); if (xUtils.isMobileClient() || $("#MapTools").is(":visible")) { plugin.toolsContainerTop = document.getElementsByClassName("HWTools")[0].offsetTop; } $("#HWToolsContainer").css("top", plugin.toolsContainerTop + "px").css("width", "160px"); xMapUtils.addMapTool("Show Potential Homeworlds", "HWPotential" + (plugin.show.potentialHomeworlds ? " toolactive" : ""), plugin.toggleShowPotentialHomeworlds, "#HWToolsContainer"); xMapUtils.addMapTool("Show Selected Homeworlds", "HWSelected" + (plugin.show.selectedHomeworlds ? " toolactive" : ""), plugin.toggleShowSelectedHomeworlds, "#HWToolsContainer"); if (showPieslicesButton) { xMapUtils.addMapTool("Show Pieslices", "HWPieslices" + (plugin.show.pieslices ? " toolactive" : ""), plugin.toggleShowPieslices, "#HWToolsContainer"); } xMapUtils.addMapTool("Show Areas", "HWAreas" + (plugin.show.areas ? " toolactive" : ""), plugin.toggleShowAreas, "#HWToolsContainer"); xMapUtils.addMapTool("Select HW", "HWSelectMode" + (plugin.isInSelectMode ? " toolactive" : ""), plugin.toggleSelectMode, "#HWToolsContainer"); xMapUtils.addMapTool("Save Selected HWs", "HWSave", plugin.saveSelectedHomeworlds, "#HWToolsContainer"); if (plugin.isSelectedHomeworldsModified) { $("#HWToolsContainer .HWSave").css("background", "#00FF00"); } xMapUtils.addMapTool("Potential Homeworlds Level", "HWLevel", plugin.toggleLevel, "#HWToolsContainer"); $("#HWToolsContainer .HWLevel").append("<div style='margin-top: 5px;'>" + (plugin.show.level + 1) + "</div>"); xMapUtils.addMapTool("Exit", "HWExit", plugin.closeHomeworldTools, "#HWToolsContainer"); $("#HWToolsContainer .HWExit").append("<div style='margin-top: 5px;'>X</div>"); if (!showPieslicesButton) { $("#HWToolsContainer .HWExit").detach().insertAfter("#HWToolsContainer .HWAreas"); } $("body").css("cursor", (plugin.isInSelectMode ? "crosshair" : "")); }; plugin.showdashboard = function() { $("#HWToolsContainer").hide(); }; plugin.showmap = function() { $("#HWToolsContainer").show(); }; plugin.toggleShowPotentialHomeworlds = function(e) { if (e != null) { e.stopPropagation(); e.preventDefault(); } plugin.show.potentialHomeworlds = !plugin.show.potentialHomeworlds; plugin.updateHomeworldTools(); vgap.map.draw(); }; plugin.toggleShowSelectedHomeworlds = function(e) { if (e != null) { e.stopPropagation(); e.preventDefault(); } plugin.show.selectedHomeworlds = !plugin.show.selectedHomeworlds; plugin.updateHomeworldTools(); vgap.map.draw(); }; plugin.toggleShowPieslices = function(e) { if (e != null) { e.stopPropagation(); e.preventDefault(); } plugin.show.pieslices = !plugin.show.pieslices; plugin.updateHomeworldTools(); vgap.map.draw(); }; plugin.toggleShowAreas = function(e) { if (e != null) { e.stopPropagation(); e.preventDefault(); } plugin.show.areas = !plugin.show.areas; plugin.updateHomeworldTools(); vgap.map.draw(); }; plugin.toggleSelectMode = function(e) { if (e != null) { e.stopPropagation(); e.preventDefault(); } plugin.isInSelectMode = !plugin.isInSelectMode; plugin.updateHomeworldTools(); vgap.map.draw(); }; plugin.saveSelectedHomeworlds = function(e) { if (e != null) { e.stopPropagation(); e.preventDefault(); } if (plugin.isSelectedHomeworldsModified) { plugin.saveObjectAsNote(0, plugin.selectedHomeworlds); plugin.isSelectedHomeworldsModified = false; plugin.updateHomeworldTools(); } }; plugin.toggleLevel = function(e) { if (e != null) { e.stopPropagation(); e.preventDefault(); } let level = plugin.show.level; do { level--; if (level < 0) { level = MAX_LEVEL - 1; } } while (!plugin.isLevelAvailable(level)); plugin.show.level = level; plugin.updateHomeworldTools(); vgap.map.draw(); }; plugin.draw = function() { let map = vgap.map; let mapBoundingRect = xMapUtils.getMapBoundingRect(); let homeworldCenter = mapBoundingRect.getCenterPoint(); // draw rectangles around potential HWs if ((plugin.show.potentialHomeworlds || plugin.isInSelectMode)) { for (let level = plugin.show.level; level < MAX_LEVEL; level++) { if (!plugin.isLevelAvailable(level)) { continue; } let drawParams = new XDrawParams().setStrokeStyle(LEVEL_COLORS[level]); for (let i = 0; i < plugin.potentialHomeworlds[level].length; i++) { let planet = vgap.getPlanet(plugin.potentialHomeworlds[level][i]); let rad = (map.planetRad(planet) + 3) / map.zoom; let rect = new XRect(planet.x - rad, planet.y - rad, planet.x + rad, planet.y + rad); xMapUtils.drawRect(rect, drawParams); if (level > 3) { if ((plugin.show.selectedHomeworlds || plugin.isInSelectMode) && plugin.selectedHomeworlds.includes(planet.id)) { continue; } let rad = (map.planetRad(planet) + 4) / map.zoom; let rect = new XRect(planet.x - rad, planet.y - rad, planet.x + rad, planet.y + rad); xMapUtils.drawRect(rect, drawParams); } } } } // draw rectangles around selected HWs if (plugin.show.selectedHomeworlds || plugin.isInSelectMode) { let drawParams = new XDrawParams().setStrokeStyle("#FF0000"); for (let i = 0; i < plugin.selectedHomeworlds.length; i++) { let planet = vgap.getPlanet(plugin.selectedHomeworlds[i]); let rad = (map.planetRad(planet) + 3) / map.zoom; let rect = new XRect(planet.x - rad, planet.y - rad, planet.x + rad, planet.y + rad); xMapUtils.drawRect(rect, drawParams); } } // draw circles to assist the user in localizing HWs if (plugin.isInSelectMode) { if (vgap.settings.hwdistribution == 1) // HW random spaced { let rad = Math.sqrt((mapBoundingRect.getWidth() * mapBoundingRect.getHeight()) / vgap.players.length); for (let i = 0; i < vgap.planets.length; i++) { let planet = vgap.planets[i]; let id = planet.id < 0 ? -planet.id : planet.id; if (plugin.selectedHomeworlds.indexOf(id) >= 0) { map.drawCircle(map.ctx, xMapUtils.screenX(planet.x), xMapUtils.screenY(planet.y), rad * map.zoom, "#FFFFFF", 1); } } } else if ((vgap.settings.hwdistribution == 2) // HW in a circle || (vgap.settings.hwdistribution == 4)) // center + circle (MvM) { let centerRadius = mapBoundingRect.getWidth() / 6; if (vgap.settings.hwdistribution == 4) { map.drawCircle(map.ctx, xMapUtils.screenX(homeworldCenter.x), xMapUtils.screenY(homeworldCenter.y), centerRadius * map.zoom, "#0000FF", 1); } let countCenterHomeworlds = 0; let dist = 0; for (let i = 0; i < plugin.selectedHomeworlds.length; i++) { let planet = vgap.getPlanet(plugin.selectedHomeworlds[i]); let curDist = xMapUtils.getSphereDistance(homeworldCenter, planet); if ((vgap.settings.hwdistribution == 4) && (curDist < centerRadius)) { countCenterHomeworlds += 1; } else { dist += curDist; } } if (plugin.selectedHomeworlds.length - countCenterHomeworlds > 0) { dist /= (plugin.selectedHomeworlds.length - countCenterHomeworlds); map.drawCircle(map.ctx, xMapUtils.screenX(homeworldCenter.x), xMapUtils.screenY(homeworldCenter.y), dist * map.zoom, "#FFFFFF", 1); let rad = 2 * Math.sin(Math.PI / (vgap.players.length - ((vgap.settings.hwdistribution == 4) ? 1 : 0))) * dist; for (let i = 0; i < plugin.selectedHomeworlds.length; i++) { let planet = vgap.getPlanet(plugin.selectedHomeworlds[i]); if ((vgap.settings.hwdistribution != 4) || (xMapUtils.getSphereDistance(homeworldCenter, planet) >= centerRadius)) { map.drawCircle(map.ctx, xMapUtils.screenX(planet.x), xMapUtils.screenY(planet.y), rad * map.zoom, "#FFFFFF", 1); } } } } } // draw pie slices if (plugin.show.pieslices) { let centerRadius = mapBoundingRect.getWidth() / 6; if (vgap.settings.hwdistribution == 4) { map.drawCircle(map.ctx, xMapUtils.screenX(homeworldCenter.x), xMapUtils.screenY(homeworldCenter.y), centerRadius * map.zoom, "#FFFFFF", 1); } let mapAngles = new Array(); mapAngles.push(xMapUtils.getHeading(homeworldCenter, mapBoundingRect.getRightTopPoint())); mapAngles.push(xMapUtils.getHeading(homeworldCenter, mapBoundingRect.getRightBottomPoint())); mapAngles.push(xMapUtils.getHeading(homeworldCenter, mapBoundingRect.getLeftBottomPoint())); mapAngles.push(xMapUtils.getHeading(homeworldCenter, mapBoundingRect.getLeftTopPoint())); let angles = new Array(); for (let i = 0; i < plugin.selectedHomeworlds.length; i++) { let planet = vgap.getPlanet(plugin.selectedHomeworlds[i]); let curDist = xMapUtils.getSphereDistance(homeworldCenter, planet); if ((vgap.settings.hwdistribution != 4) || (curDist >= centerRadius)) { angles.push(xMapUtils.getHeading(homeworldCenter, planet)); } } angles.sort(function(a, b) { return a - b; }); let sections = []; for (let i = 0; i < angles.length; i++) { let angle1 = angles[i]; let angle2 = angles[i == angles.length - 1 ? 0 : i + 1] + (i == angles.length - 1 ? 360 : 0); let angle = (angle1 + angle2) / 2; let angleRad = angle * Math.PI / 180; let x1 = (vgap.settings.hwdistribution == 4) ? homeworldCenter.x + centerRadius * Math.sin(angleRad) : homeworldCenter.x; let y1 = (vgap.settings.hwdistribution == 4) ? homeworldCenter.y + centerRadius * Math.cos(angleRad) : homeworldCenter.y; let x2; let y2; if ((angle <= mapAngles[0]) || (angle > mapAngles[3])) { y2 = mapBoundingRect.top; x2 = homeworldCenter.x + Math.tan(angleRad) * (y2 - homeworldCenter.y); } else if ((angle > mapAngles[0]) && (angle <= mapAngles[1])) { x2 = mapBoundingRect.right; y2 = homeworldCenter.y + (x2 - homeworldCenter.x) / Math.tan(angleRad); } else if ((angle > mapAngles[1]) && (angle <= mapAngles[2])) { y2 = mapBoundingRect.bottom; x2 = homeworldCenter.x + Math.tan(angleRad) * (y2 - homeworldCenter.y); } else if ((angle > mapAngles[2]) && (angle <= mapAngles[3])) { x2 = mapBoundingRect.left; y2 = homeworldCenter.y + (x2 - homeworldCenter.x) / Math.tan(angleRad); } sections.push(new XLineSection(x1, y1, x2, y2)); } let drawParams = new XDrawParams().setStrokeStyle("#FFFFFF").setSphereDuplication(xConst.sphereDuplication.NONE); for (let i = 0; i < sections.length; i++) { xMapUtils.drawLineSection(sections[i], drawParams); } xMapUtils.drawRect(mapBoundingRect, drawParams); } // draw areas if (plugin.show.areas && (plugin.selectedHomeworlds.length > 0)) { if (plugin.homeworldAreas == null) { plugin.calculateAreas(); } let drawParams = new XDrawParams().setStrokeStyle("#FFFFFF"); for (let i = 0; i < plugin.homeworldAreas.length; i++) { let area = plugin.homeworldAreas[i].area; let lastPoint = area[area.length - 1]; for (let j = 0; j < area.length; j++) { let curPoint = area[j]; xMapUtils.drawLineSection(XLineSection.fromPoints(lastPoint, curPoint), drawParams); lastPoint = curPoint; } } } }; plugin.oldVgapMapClick = vgapMap.prototype.click; vgapMap.prototype.click = function(_shift) { let map = vgap.map; if (plugin.isInSelectMode) { if ((map.over != null) && map.over.isPlanet) { let planet = map.over; let id = planet.id < 0 ? -planet.id : planet.id; let found = false; for (let i = 0; i < plugin.selectedHomeworlds.length; i++) { if (id == plugin.selectedHomeworlds[i]) { plugin.selectedHomeworlds.splice(i, 1); found = true; break; } } if (!found) { plugin.selectedHomeworlds.push(id); } plugin.isSelectedHomeworldsModified = true; plugin.homeworldAreas = null; plugin.updateHomeworldTools(); map.draw(); } } else { plugin.oldVgapMapClick.apply(this, arguments); } }; } // wrapper for injection let script = document.createElement("script"); script.type = "application/javascript"; script.textContent = "(" + wrapper + ")(\"" + GM_info.script.version + "\");"; document.body.appendChild(script); document.body.removeChild(script);