// 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; }