summaryrefslogtreecommitdiff
path: root/misc/autoinfiltrate.js
diff options
context:
space:
mode:
authorAlmightyMiau <almightymeow612@gmail.com>2024-11-13 10:56:53 -0800
committerAlmightyMiau <almightymeow612@gmail.com>2024-11-13 10:56:53 -0800
commit40843e35434d56e883655e4377994ac76746b184 (patch)
tree786c3acc109b4add11c88ca58a534fd19d4e77cb /misc/autoinfiltrate.js
parent1ca00b3b73a9699e41f81e154cea32934c16de03 (diff)
Organized scripts into folders
Diffstat (limited to 'misc/autoinfiltrate.js')
-rw-r--r--misc/autoinfiltrate.js803
1 files changed, 803 insertions, 0 deletions
diff --git a/misc/autoinfiltrate.js b/misc/autoinfiltrate.js
new file mode 100644
index 0000000..eb7717f
--- /dev/null
+++ b/misc/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;
+}