Powerline.io Wall Hugger
// ==UserScript==
// @name Powerline Wall Hugger
// @version 2.1
// @description Powerline.io Wall Hugger
// @author Rumini - Discord: rumini
// @match *://powerline.io/*
// @icon https://i.imgur.com/9k4SFr0.png
// @grant unsafeWindow
// @license MIT
// @run-at document-start
// @namespace https://greasyfork.org/users/1356205
// ==/UserScript==
if (window.location.href === 'https://powerline.io/') {
window.location.href = 'https://powerline.io/maindev.html';
}
(function() {
'use strict';
const DIRECTION_NONE = 0;
const DIRECTION_UP = 1;
const DIRECTION_LEFT = 2;
const DIRECTION_DOWN = 3;
const DIRECTION_RIGHT = 4;
const BASE_WALL_DISTANCE = 0.000000001;
const WALL_DISTANCE_INCREMENT = 0.00001;
let wallHuggerEnabled = false;
let originalSendTurnPoint;
let isTeleporting = false;
let currentDirection = DIRECTION_NONE;
let wallDistance = BASE_WALL_DISTANCE;
let GAME_SCALE;
const waitForGame = (callback) => {
if (typeof Snake !== 'undefined' && typeof localPlayerID !== 'undefined' && typeof network !== 'undefined') {
GAME_SCALE = unsafeWindow.GAME_SCALE || 10;
callback();
} else {
setTimeout(() => waitForGame(callback), 100);
}
};
const findNearestWall = (x, y) => {
const halfArena = unsafeWindow.arenaWidth / 2;
const distances = [
{ wall: 'left', distance: Math.abs(halfArena + x) },
{ wall: 'right', distance: Math.abs(halfArena - x) },
{ wall: 'top', distance: Math.abs(halfArena + y) },
{ wall: 'bottom', distance: Math.abs(halfArena - y) }
];
return distances.reduce((nearest, current) =>
current.distance < nearest.distance ? current : nearest
);
};
const teleportToWall = (newDirection) => {
if (!localPlayer || isTeleporting) return;
isTeleporting = true;
const nearestWall = findNearestWall(localPlayer.x, localPlayer.y);
const halfArena = unsafeWindow.arenaWidth / 2;
wallDistance += WALL_DISTANCE_INCREMENT * GAME_SCALE;
let newX = localPlayer.x;
let newY = localPlayer.y;
switch (nearestWall.wall) {
case 'left':
newX = -halfArena + wallDistance;
if (newDirection === DIRECTION_UP) {
newY = halfArena - wallDistance;
} else if (newDirection === DIRECTION_DOWN) {
newY = -halfArena + wallDistance;
}
break;
case 'right':
newX = halfArena - wallDistance;
if (newDirection === DIRECTION_UP) {
newY = halfArena - wallDistance;
} else if (newDirection === DIRECTION_DOWN) {
newY = -halfArena + wallDistance;
}
break;
case 'top':
newY = halfArena - wallDistance;
if (newDirection === DIRECTION_LEFT) {
newX = -halfArena + wallDistance;
} else if (newDirection === DIRECTION_RIGHT) {
newX = halfArena - wallDistance;
}
break;
case 'bottom':
newY = -halfArena + wallDistance;
if (newDirection === DIRECTION_LEFT) {
newX = -halfArena + wallDistance;
} else if (newDirection === DIRECTION_RIGHT) {
newX = halfArena - wallDistance;
}
break;
}
localPlayer.x = newX;
localPlayer.y = newY;
localPlayer.direction = newDirection;
// X and Y Axis is for some reason flipped when you are near the top and bottom wall
if (nearestWall.wall === 'top' || nearestWall.wall === 'bottom') {
originalSendTurnPoint.call(network, newDirection, newY / GAME_SCALE, -newX / GAME_SCALE);
} else if (nearestWall.wall === 'left' && currentDirection === DIRECTION_UP && newDirection === DIRECTION_RIGHT) {
originalSendTurnPoint.call(network, newDirection, -newX / GAME_SCALE, newY / GAME_SCALE);
} else if (nearestWall.wall === 'right' && currentDirection === DIRECTION_DOWN && newDirection === DIRECTION_LEFT) {
originalSendTurnPoint.call(network, newDirection, -newX / GAME_SCALE, newY / GAME_SCALE);
} else {
originalSendTurnPoint.call(network, newDirection, newX / GAME_SCALE, -newY / GAME_SCALE);
}
isTeleporting = false;
};
const toggleWallHugger = (enable) => {
wallHuggerEnabled = enable !== undefined ? enable : !wallHuggerEnabled;
if (wallHuggerEnabled) {
originalSendTurnPoint = network.sendTurnPoint;
network.sendTurnPoint = function(direction, x, y) {
if (wallHuggerEnabled && !isTeleporting && direction !== DIRECTION_NONE) {
teleportToWall(direction);
} else {
originalSendTurnPoint.call(this, direction, x, y);
}
};
startDirectionTracking();
hud.showTip("Wall Hugger Enabled", 2000);
} else {
if (originalSendTurnPoint) {
network.sendTurnPoint = originalSendTurnPoint;
}
stopDirectionTracking();
hud.showTip("Wall Hugger Disabled", 2000);
}
};
const startDirectionTracking = () => {
if (typeof requestAnimationFrame !== 'undefined') {
const trackDirection = () => {
if (wallHuggerEnabled && localPlayer) {
currentDirection = localPlayer.direction;
}
if (wallHuggerEnabled) {
requestAnimationFrame(trackDirection);
}
};
requestAnimationFrame(trackDirection);
} else {
window.directionTrackingInterval = setInterval(() => {
if (localPlayer) {
currentDirection = localPlayer.direction;
}
}, 16);
}
};
const stopDirectionTracking = () => {
if (window.directionTrackingInterval) {
clearInterval(window.directionTrackingInterval);
}
};
const checkCollisionAndReset = () => {
const observer = new MutationObserver(() => {
if (localPlayerID === 0 && wallHuggerEnabled) {
toggleWallHugger(false);
wallDistance = BASE_WALL_DISTANCE;
}
});
observer.observe(document.body, {
childList: true,
subtree: true
});
};
const setupKeyBindings = () => {
document.addEventListener('keydown', (e) => {
if (e.key.toLowerCase() === 'h') {
toggleWallHugger();
}
});
};
waitForGame(() => {
setupKeyBindings();
checkCollisionAndReset();
});
})();