diff options
Diffstat (limited to 'bitburnerFiles1026/autoinfiltrate.js')
-rw-r--r-- | bitburnerFiles1026/autoinfiltrate.js | 803 |
1 files changed, 803 insertions, 0 deletions
diff --git a/bitburnerFiles1026/autoinfiltrate.js b/bitburnerFiles1026/autoinfiltrate.js new file mode 100644 index 0000000..eb7717f --- /dev/null +++ b/bitburnerFiles1026/autoinfiltrate.js @@ -0,0 +1,803 @@ +// This script is awesome and will autocomplete the infiltrate tasks in bitburner. +// It does not always run properly, it could be a browser issue and works 95% with game running on edge browser. +// This was copied from https://pastebin.com/7DuFYDpJ and modified to work with shadows of anarchy augments. +// Type "wget https://raw.githubusercontent.com/5p0ng3b0b/bitburner-scripts/main/autoinfiltrate.js autoinfiltrate.js" from you home terminal to download. +// Type 'run autoinfiltrate.js' from home terminal. options are --start --stop --quiet although the --start option is not required. +// Try always running it via an alias eg 'alias autoinfil="run autoinfiltrate.js --stop --quiet; run autoinfiltrate.js --quiet"" +// Once the script is running, It will activate when you visit any company and click the infiltrate button. +// You can use infiltrate to quickly get alot of money early in the game or quickly earn rep for any faction. +// ecorp in Aevum is the highest earner followed by megacorp in sector-12 and then KuaiGong International in Chongqing. + + +const state = { + // Name of the company that's infiltrated. + company: "", + + // Whether infiltration started. False means, we're + // waiting to arrive on the infiltration screen. + started: false, + + // Details/state of the current mini game. + // Is reset after every game. + game: {}, +}; + +// Speed of game actions, in milliseconds. Default 22 +const speed = 25; + +// Small hack to save RAM. +// This will work smoothly, because the script does not use +// any "ns" functions, it's a pure browser automation tool. +const wnd = eval("window"); +const doc = wnd["document"]; + +// List of all games and an automated solver. +const infiltrationGames = [ + { + name: "type it", + init: function (screen) { + const lines = getLines(getEl(screen, "p")); + state.game.data = lines[0].split(""); + }, + play: function (screen) { + if (!state.game.data || !state.game.data.length) { + delete state.game.data; + return; + } + + pressKey(state.game.data.shift()); + }, + }, + { + name: "type it backward", + init: function (screen) { + const lines = getLines(getEl(screen, "p")); + state.game.data = lines[0].split(""); + }, + play: function (screen) { + if (!state.game.data || !state.game.data.length) { + delete state.game.data; + return; + } + + pressKey(state.game.data.shift()); + }, + }, + { + // name: "enter the code", + init: function (screen) { }, + play: function (screen) { + const h4 = getEl(screen, "h4"); + const spanElements = h4[1].querySelectorAll("span"); + const code = Array.from(spanElements) + .filter(span => span.textContent !== "?") + .map(span => span.textContent) + .pop(); + + switch (code) { + case "↑": + pressKey("w"); + break; + case "↓": + pressKey("s"); + break; + case "←": + pressKey("a"); + break; + case "→": + pressKey("d"); + break; + } + }, + }, + { + name: "close the brackets", + init: function (screen) { + const data = getLines(getEl(screen, "p")); + const brackets = data.join("").split(""); + state.game.data = []; + + for (let i = brackets.length - 1; i >= 0; i--) { + const char = brackets[i]; + + if ("<" == char) { + state.game.data.push(">"); + } else if ("(" == char) { + state.game.data.push(")"); + } else if ("{" == char) { + state.game.data.push("}"); + } else if ("[" == char) { + state.game.data.push("]"); + } + } + }, + play: function (screen) { + if (!state.game.data || !state.game.data.length) { + delete state.game.data; + return; + } + + pressKey(state.game.data.shift()); + }, + }, + { + name: "Attack after the guard drops his guard and is distracted. Do not alert him!", + init: function (screen) { + state.game.data = "wait"; + }, + play: function (screen) { + const data = getLines(getEl(screen, "h4")); + + if ("Distracted!" === state.game.data) { + pressKey(" "); + state.game.data = "done"; + } + + // Attack in next frame - instant attack sometimes + // ends in failure. + if ('wait' === state.game.data && -1 !== data.indexOf("Alerted!")) { + state.game.data = "attack"; + } + }, + }, + { + name: "say something nice about the guard", + init: function (screen) { }, + play: function (screen) { + const correct = [ + "affectionate", + "agreeable", + "bright", + "charming", + "creative", + "determined", + "energetic", + "friendly", + "funny", + "generous", + "polite", + "likable", + "diplomatic", + "helpful", + "giving", + "kind", + "hardworking", + "patient", + "dynamic", + "loyal", + "based", + "straightforward" + ]; + const word = getLines(getEl(screen, "h5"))[1]; + + if (-1 !== correct.indexOf(word)) { + pressKey(" "); + } else { + pressKey("w"); + } + }, + }, + { + name: "remember all the mines", + init: function (screen) { + const rows = getEl(screen, "p"); + let gridSize = null; + switch (rows.length) { + case 9: + gridSize = [3, 3]; + break; + case 12: + gridSize = [3, 4]; + break; + case 16: + gridSize = [4, 4]; + break; + case 20: + gridSize = [4, 5]; + break; + case 25: + gridSize = [5, 5]; + break; + case 30: + gridSize = [5, 6]; + break; + case 36: + gridSize = [6, 6]; + break; + } + if (gridSize == null) { + return; + } + //12 20 30 42 + state.game.data = []; + let index = 0; + //for each row + for (let y = 0; y < gridSize[1]; y++) { + //initialize array data + state.game.data[y] = []; + for (let x = 0; x < gridSize[0]; x++) { + //for each column in the row add to state data if it has a child + if (rows[index].children.length > 0) { + state.game.data[y].push(true); + } else state.game.data[y].push(false); + index += 1; + } + } + }, + play: function (screen) { }, + }, + { + name: "mark all the mines", + init: function (screen) { + state.game.x = 0; + state.game.y = 0; + state.game.cols = state.game.data[0].length; + state.game.dir = 1; + }, + play: function (screen) { + let { data, x, y, cols, dir } = state.game; + + if (data[y][x]) { + pressKey(" "); + data[y][x] = false; + } + + x += dir; + + if (x < 0 || x >= cols) { + x = Math.max(0, Math.min(cols - 1, x)); + y++; + dir *= -1; + pressKey("s"); + } else { + pressKey(dir > 0 ? "d" : "a"); + } + + state.game.data = data; + state.game.x = x; + state.game.y = y; + state.game.dir = dir; + }, + }, + { + name: "match the symbols", + init: function (screen) { + const data = getLines(getEl(screen, "h5 span")); + const rows = getLines(getEl(screen, "p")); + const keypad = []; + const targets = []; + let gridSize = null; + switch (rows.length) { + case 9: + gridSize = [3, 3]; + break; + case 12: + gridSize = [3, 4]; + break; + case 16: + gridSize = [4, 4]; + break; + case 20: + gridSize = [4, 5]; + break; + case 25: + gridSize = [5, 5]; + break; + case 30: + gridSize = [5, 6]; + break; + case 36: + gridSize = [6, 6]; + break; + } + if (gridSize == null) { + return; + } + //build the keypad grid. + let index = 0; + for (let i = 0; i < gridSize[1]; i++) { + keypad[i] = []; + for (let y = 0; y < gridSize[0]; y++) { + + keypad[i].push(rows[index]); + index += 1; + } + } + //foreach data get coords of keypad entry + for (let i = 0; i < data.length; i++) { + const symbol = data[i].trim(); + //for each keypad entry + for (let j = 0; j < keypad.length; j++) { + const k = keypad[j].indexOf(symbol); + + if (-1 !== k) { + targets.push([j, k]); + break; + } + } + } + state.game.data = targets; + state.game.x = 0; + state.game.y = 0; + }, + play: function (screen) { + const target = state.game.data[0]; + let { x, y } = state.game; + + if (!target) { + return; + } + + const to_y = target[0]; + const to_x = target[1]; + + if (to_y < y) { + y--; + pressKey("w"); + } else if (to_y > y) { + y++; + pressKey("s"); + } else if (to_x < x) { + x--; + pressKey("a"); + } else if (to_x > x) { + x++; + pressKey("d"); + } else { + pressKey(" "); + state.game.data.shift(); + } + + state.game.x = x; + state.game.y = y; + }, + }, + { + name: "cut the wires with the following properties", + init: function (screen) { + let numberHack = ["1", "2", "3", "4", "5", "6", "7", "8", "9"]; + const colors = { + red: "red", + white: "white", + blue: "blue", + "rgb(255, 193, 7)": "yellow", + }; + const wireColor = { + red: [], + white: [], + blue: [], + yellow: [], + }; + //gather the instructions + var instructions = [] + for (let child of screen.children) instructions.push(child); + var wiresData = instructions.pop(); + instructions.shift(); + instructions = getLines(instructions); + //get the wire information + const samples = getEl(wiresData, "p"); + const wires = []; + //get the amount of wires + let wireCount = 0; + for (let i = wireCount; i < samples.length; i++) { + if (numberHack.includes(samples[i].innerText)) wireCount += 1; + else break; + } + let index = 0; + //get just the first 3 rows of wires. + for (let i = 0; i < 3; i++) { + //for each row + for (let j = 0; j < wireCount; j++) { + const node = samples[index]; + const color = colors[node.style.color]; + if (!color) { + index += 1; + continue; + } + wireColor[color].push(j + 1); + index += 1; + } + } + + for (let i = 0; i < instructions.length; i++) { + const line = instructions[i].trim().toLowerCase(); + + if (!line || line.length < 10) { + continue; + } + if (-1 !== line.indexOf("cut wires number")) { + const parts = line.split(/(number\s*|\.)/); + wires.push(parseInt(parts[2])); + } + if (-1 !== line.indexOf("cut all wires colored")) { + const parts = line.split(/(colored\s*|\.)/); + const color = parts[2]; + + if (!wireColor[color]) { + // should never happen. + continue; + } + + wireColor[color].forEach((num) => wires.push(num)); + } + } + + // new Set() removes duplicate elements. + state.game.data = [...new Set(wires)]; + }, + play: function (screen) { + const wire = state.game.data; + //state.game.data.shift(); + if (!wire) { + return; + } + for (let i = 0; i < wire.length; i++) { + pressKey(wire[i].toString()); + } + }, + }, +]; + +/** @param {NS} ns **/ +export async function main(ns) { + const args = ns.flags([ + ["start", false], + ["stop", false], + ["status", false], + ["quiet", false], + ]); + + function print(msg) { + if (!args.quiet) { + ns.tprint(`\n${msg}\n`); + } + } + + if (args.status) { + if (wnd.tmrAutoInf) { + print("Automated infiltration is active"); + } else { + print("Automated infiltration is inactive"); + } + return; + } + + if (wnd.tmrAutoInf) { + print("Stopping automated infiltration..."); + clearInterval(wnd.tmrAutoInf); + delete wnd.tmrAutoInf; + } + + if (args.stop) { + return; + } + + print( + "Automated infiltration is enabled...\nVWhen you visit the infiltration screen of any company, all tasks are completed automatically." + ); + + endInfiltration(); + + // Monitor the current screen and start infiltration once a + // valid screen is detected. + wnd.tmrAutoInf = setInterval(infLoop, speed); + + // Modify the addEventListener logic. + wrapEventListeners(); +} + +/** + * The infiltration loop, which is called at a rapid interval + */ +function infLoop() { + if (!state.started) { + waitForStart(); + } else { + playGame(); + } +} + +/** + * Returns a list of DOM elements from the main game + * container. + */ +function getEl(parent, selector) { + let prefix = ":scope"; + + if ("string" === typeof parent) { + selector = parent; + parent = doc; + + prefix = ".MuiBox-root>.MuiBox-root>.MuiBox-root"; + + if (!doc.querySelectorAll(prefix).length) { + prefix = ".MuiBox-root>.MuiBox-root>.MuiGrid-root"; + } + if (!doc.querySelectorAll(prefix).length) { + prefix = ".MuiContainer-root>.MuiPaper-root"; + } + if (!doc.querySelectorAll(prefix).length) { + return []; + } + } + + selector = selector.split(","); + selector = selector.map((item) => `${prefix} ${item}`); + selector = selector.join(","); + + return parent.querySelectorAll(selector); +} + +/** + * Returns the first element with matching text content. + */ +function filterByText(elements, text) { + text = text.toLowerCase(); + + for (let i = 0; i < elements.length; i++) { + const content = elements[i].textContent.toLowerCase(); + + if (-1 !== content.indexOf(text)) { + return elements[i]; + } + } + + return null; +} + +/** + * Returns an array with the text-contents of the given elements. + * + * @param {NodeList} elements + * @returns {string[]} + */ +function getLines(elements) { + const lines = []; + elements.forEach((el) => lines.push(el.textContent)); + + return lines; +} + +/** + * Reset the state after infiltration is done. + */ +function endInfiltration() { + unwrapEventListeners(); + state.company = ""; + state.started = false; +} + +/** + * Simulate a keyboard event (keydown + keyup). + * + * @param {string|int} keyOrCode A single letter (string) or key-code to send. + */ +function pressKey(keyOrCode) { + let keyCode = 0; + let key = ""; + + if ("string" === typeof keyOrCode && keyOrCode.length > 0) { + key = keyOrCode.toLowerCase().substr(0, 1); + keyCode = key.charCodeAt(0); + } else if ("number" === typeof keyOrCode) { + keyCode = keyOrCode; + key = String.fromCharCode(keyCode); + } + + if (!keyCode || key.length !== 1) { + return; + } + + function sendEvent(event) { + const keyboardEvent = new KeyboardEvent(event, { + key, + keyCode, + }); + + doc.dispatchEvent(keyboardEvent); + } + + sendEvent("keydown"); +} + +/** + * Infiltration monitor to start automatic infiltration. + * + * This function runs asynchronously, after the "main" function ended, + * so we cannot use any "ns" function here! + */ +function waitForStart() { + if (state.started) { + return; + } + + const h4 = getEl("h4"); + + if (!h4.length) { + return; + } + const title = h4[0].textContent; + if (0 !== title.indexOf("Infiltrating")) { + return; + } + + const btnStart = filterByText(getEl("button"), "Start"); + if (!btnStart) { + return; + } + + state.company = title.substr(13); + state.started = true; + wrapEventListeners(); + + console.log("Start automatic infiltration of", state.company); + btnStart.click(); +} + +/** + * Identify the current infiltration game. + */ +function playGame() { + const screens = doc.querySelectorAll(".MuiContainer-root"); + + if (!screens.length) { + endInfiltration(); + return; + } + if (screens[0].children.length < 3) { + return; + } + + const screen = screens[0].children[2]; + const h4 = getEl(screen, "h4"); + + if (!h4.length) { + endInfiltration(); + return; + } + + const title = h4[0].textContent.trim().toLowerCase().split(/[!.(]/)[0]; + + if ("infiltration successful" === title) { + endInfiltration(); + return; + } + + if ("get ready" === title) { + return; + } + + const game = infiltrationGames.find((game) => game.name === title); + + if (game) { + if (state.game.current !== title) { + state.game.current = title; + game.init(screen); + } + + game.play(screen); + } else { + console.error("Unknown game:", title); + } +} + +/** + * Wrap all event listeners with a custom function that injects + * the "isTrusted" flag. + * + * Is this cheating? Or is it real hacking? Don't care, as long + * as it's working :) + */ +function wrapEventListeners() { + if (!doc._addEventListener) { + doc._addEventListener = doc.addEventListener; + + doc.addEventListener = function (type, callback, options) { + if ("undefined" === typeof options) { + options = false; + } + let handler = false; + + // For this script, we only want to modify "keydown" events. + if ("keydown" === type) { + handler = function (...args) { + if (!args[0].isTrusted) { + const hackedEv = {}; + + for (const key in args[0]) { + if ("isTrusted" === key) { + hackedEv.isTrusted = true; + } else if ("function" === typeof args[0][key]) { + hackedEv[key] = args[0][key].bind(args[0]); + } else { + hackedEv[key] = args[0][key]; + } + } + + args[0] = hackedEv; + } + + return callback.apply(callback, args); + }; + + for (const prop in callback) { + if ("function" === typeof callback[prop]) { + handler[prop] = callback[prop].bind(callback); + } else { + handler[prop] = callback[prop]; + } + } + } + + if (!this.eventListeners) { + this.eventListeners = {}; + } + if (!this.eventListeners[type]) { + this.eventListeners[type] = []; + } + this.eventListeners[type].push({ + listener: callback, + useCapture: options, + wrapped: handler, + }); + + return this._addEventListener( + type, + handler ? handler : callback, + options + ); + }; + } + + if (!doc._removeEventListener) { + doc._removeEventListener = doc.removeEventListener; + + doc.removeEventListener = function (type, callback, options) { + if ("undefined" === typeof options) { + options = false; + } + + if (!this.eventListeners) { + this.eventListeners = {}; + } + if (!this.eventListeners[type]) { + this.eventListeners[type] = []; + } + + for (let i = 0; i < this.eventListeners[type].length; i++) { + if ( + this.eventListeners[type][i].listener === callback && + this.eventListeners[type][i].useCapture === options + ) { + if (this.eventListeners[type][i].wrapped) { + callback = this.eventListeners[type][i].wrapped; + } + + this.eventListeners[type].splice(i, 1); + break; + } + } + + if (this.eventListeners[type].length == 0) { + delete this.eventListeners[type]; + } + + return this._removeEventListener(type, callback, options); + }; + } +} + +/** + * Revert the "wrapEventListeners" changes. + */ +function unwrapEventListeners() { + if (doc._addEventListener) { + doc.addEventListener = doc._addEventListener; + delete doc._addEventListener; + } + if (doc._removeEventListener) { + doc.removeEventListener = doc._removeEventListener; + delete doc._removeEventListener; + } + delete doc.eventListeners; +} |