Advertisement
Monkguru

Infiltration Script

Oct 19th, 2022
3,520
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
JavaScript 21.99 KB | Gaming | 0 0
  1. const state = {
  2.     // Name of the company that's infiltrated.
  3.     company: "",
  4.  
  5.     // Whether infiltration started. False means, we're
  6.     // waiting to arrive on the infiltration screen.
  7.     started: false,
  8.  
  9.     // Details/state of the current mini game.
  10.     // Is reset after every game.
  11.     game: {},
  12. };
  13.  
  14. // Speed of game actions, in milliseconds.
  15. const speed = 22;
  16.  
  17. // Small hack to save RAM.
  18. // This will work smoothly, because the script does not use
  19. // any "ns" functions, it's a pure browser automation tool.
  20. const wnd = eval("window");
  21. const doc = wnd["document"];
  22.  
  23. // List of all games and an automated solver.
  24. const infiltrationGames = [
  25.     {
  26.         name: "type it backward",
  27.         init: function (screen) {
  28.             const lines = getLines(getEl(screen, "p"));
  29.             state.game.data = lines[0].split("");
  30.         },
  31.         play: function (screen) {
  32.             if (!state.game.data || !state.game.data.length) {
  33.                 delete state.game.data;
  34.                 return;
  35.             }
  36.  
  37.             pressKey(state.game.data.shift());
  38.         },
  39.     },
  40.     {
  41.         name: "enter the code",
  42.         init: function (screen) { },
  43.         play: function (screen) {
  44.             const h4 = getEl(screen, "h4");
  45.             const code = h4[1].textContent;
  46.  
  47.             switch (code) {
  48.                 case "↑":
  49.                     pressKey("w");
  50.                     break;
  51.                 case "↓":
  52.                     pressKey("s");
  53.                     break;
  54.                 case "←":
  55.                     pressKey("a");
  56.                     break;
  57.                 case "→":
  58.                     pressKey("d");
  59.                     break;
  60.             }
  61.         },
  62.     },
  63.     {
  64.         name: "close the brackets",
  65.         init: function (screen) {
  66.             const data = getLines(getEl(screen, "p"));
  67.             const brackets = data.join("").split("");
  68.             state.game.data = [];
  69.  
  70.             for (let i = brackets.length - 1; i >= 0; i--) {
  71.                 const char = brackets[i];
  72.  
  73.                 if ("<" == char) {
  74.                     state.game.data.push(">");
  75.                 } else if ("(" == char) {
  76.                     state.game.data.push(")");
  77.                 } else if ("{" == char) {
  78.                     state.game.data.push("}");
  79.                 } else if ("[" == char) {
  80.                     state.game.data.push("]");
  81.                 }
  82.             }
  83.         },
  84.         play: function (screen) {
  85.             if (!state.game.data || !state.game.data.length) {
  86.                 delete state.game.data;
  87.                 return;
  88.             }
  89.  
  90.             pressKey(state.game.data.shift());
  91.         },
  92.     },
  93.     {
  94.         name: "slash when his guard is down",
  95.         init: function (screen) {
  96.             state.game.data = "wait";
  97.         },
  98.         play: function (screen) {
  99.             const data = getLines(getEl(screen, "h4"));
  100.  
  101.             if ("attack" === state.game.data) {
  102.                 pressKey(" ");
  103.                 state.game.data = "done";
  104.             }
  105.  
  106.             // Attack in next frame - instant attack sometimes
  107.             // ends in failure.
  108.             if ('wait' === state.game.data && -1 !== data.indexOf("ATTACKING!")) {
  109.                 state.game.data = "attack";
  110.             }
  111.         },
  112.     },
  113.     {
  114.         name: "say something nice about the guard",
  115.         init: function (screen) { },
  116.         play: function (screen) {
  117.             const correct = [
  118.                 "affectionate",
  119.                 "agreeable",
  120.                 "bright",
  121.                 "charming",
  122.                 "creative",
  123.                 "determined",
  124.                 "energetic",
  125.                 "friendly",
  126.                 "funny",
  127.                 "generous",
  128.                 "polite",
  129.                 "likable",
  130.                 "diplomatic",
  131.                 "helpful",
  132.                 "giving",
  133.                 "kind",
  134.                 "hardworking",
  135.                 "patient",
  136.                 "dynamic",
  137.                 "loyal",
  138.                 "based",
  139.             ];
  140.             const word = getLines(getEl(screen, "h5"))[1];
  141.  
  142.             if (-1 !== correct.indexOf(word)) {
  143.                 pressKey(" ");
  144.             } else {
  145.                 pressKey("w");
  146.             }
  147.         },
  148.     },
  149.     {
  150.         name: "remember all the mines",
  151.         init: function (screen) {
  152.             const rows = getEl(screen, "p");
  153.             let gridSize = null;
  154.             switch (rows.length) {
  155.                 case 9:
  156.                     gridSize = [3, 3];
  157.                     break;
  158.                 case 12:
  159.                     gridSize = [3, 4];
  160.                     break;
  161.                 case 16:
  162.                     gridSize = [4, 4];
  163.                     break;
  164.                 case 20:
  165.                     gridSize = [4, 5];
  166.                     break;
  167.                 case 25:
  168.                     gridSize = [5, 5];
  169.                     break;
  170.                 case 30:
  171.                     gridSize = [5, 6];
  172.                     break;
  173.                 case 36:
  174.                     gridSize = [6, 6];
  175.                     break;
  176.             }
  177.             if (gridSize == null) {
  178.                 return;
  179.             }
  180.             //12 20 30 42
  181.             state.game.data = [];
  182.             let index = 0;
  183.             //for each row
  184.             for (let y = 0; y < gridSize[1]; y++) {
  185.                 //initialize array data
  186.                 state.game.data[y] = [];
  187.                 for (let x = 0; x < gridSize[0]; x++) {
  188.                     //for each column in the row add to state data if it has a child
  189.                     if (rows[index].children.length > 0) {
  190.                         state.game.data[y].push(true);
  191.                     } else state.game.data[y].push(false);
  192.                     index += 1;
  193.                 }
  194.             }
  195.         },
  196.         play: function (screen) { },
  197.     },
  198.     {
  199.         name: "mark all the mines",
  200.         init: function (screen) {
  201.             state.game.x = 0;
  202.             state.game.y = 0;
  203.             state.game.cols = state.game.data[0].length;
  204.             state.game.dir = 1;
  205.         },
  206.         play: function (screen) {
  207.             let { data, x, y, cols, dir } = state.game;
  208.  
  209.             if (data[y][x]) {
  210.                 pressKey(" ");
  211.                 data[y][x] = false;
  212.             }
  213.  
  214.             x += dir;
  215.  
  216.             if (x < 0 || x >= cols) {
  217.                 x = Math.max(0, Math.min(cols - 1, x));
  218.                 y++;
  219.                 dir *= -1;
  220.                 pressKey("s");
  221.             } else {
  222.                 pressKey(dir > 0 ? "d" : "a");
  223.             }
  224.  
  225.             state.game.data = data;
  226.             state.game.x = x;
  227.             state.game.y = y;
  228.             state.game.dir = dir;
  229.         },
  230.     },
  231.     {
  232.         name: "match the symbols",
  233.         init: function (screen) {
  234.             const data = getLines(getEl(screen, "h5 span"));
  235.             const rows = getLines(getEl(screen, "p"));
  236.             const keypad = [];
  237.             const targets = [];
  238.             let gridSize = null;
  239.             switch (rows.length) {
  240.                 case 9:
  241.                     gridSize = [3, 3];
  242.                     break;
  243.                 case 12:
  244.                     gridSize = [3, 4];
  245.                     break;
  246.                 case 16:
  247.                     gridSize = [4, 4];
  248.                     break;
  249.                 case 20:
  250.                     gridSize = [4, 5];
  251.                     break;
  252.                 case 25:
  253.                     gridSize = [5, 5];
  254.                     break;
  255.                 case 30:
  256.                     gridSize = [5, 6];
  257.                     break;
  258.                 case 36:
  259.                     gridSize = [6, 6];
  260.                     break;
  261.             }
  262.             if (gridSize == null) {
  263.                 return;
  264.             }
  265.             //build the keypad grid.
  266.             let index = 0;
  267.             for (let i = 0; i < gridSize[1]; i++) {
  268.                 keypad[i] = [];
  269.                 for (let y = 0; y < gridSize[0]; y++) {
  270.  
  271.                     keypad[i].push(rows[index]);
  272.                     index += 1;
  273.                 }
  274.             }
  275.             //foreach data get coords of keypad entry
  276.             for (let i = 0; i < data.length; i++) {
  277.                 const symbol = data[i].trim();
  278.                 //for each keypad entry
  279.                 for (let j = 0; j < keypad.length; j++) {
  280.                     const k = keypad[j].indexOf(symbol);
  281.  
  282.                     if (-1 !== k) {
  283.                         targets.push([j, k]);
  284.                         break;
  285.                     }
  286.                 }
  287.             }
  288.             state.game.data = targets;
  289.             state.game.x = 0;
  290.             state.game.y = 0;
  291.         },
  292.         play: function (screen) {
  293.             const target = state.game.data[0];
  294.             let { x, y } = state.game;
  295.  
  296.             if (!target) {
  297.                 return;
  298.             }
  299.  
  300.             const to_y = target[0];
  301.             const to_x = target[1];
  302.  
  303.             if (to_y < y) {
  304.                 y--;
  305.                 pressKey("w");
  306.             } else if (to_y > y) {
  307.                 y++;
  308.                 pressKey("s");
  309.             } else if (to_x < x) {
  310.                 x--;
  311.                 pressKey("a");
  312.             } else if (to_x > x) {
  313.                 x++;
  314.                 pressKey("d");
  315.             } else {
  316.                 pressKey(" ");
  317.                 state.game.data.shift();
  318.             }
  319.  
  320.             state.game.x = x;
  321.             state.game.y = y;
  322.         },
  323.     },
  324.     {
  325.         name: "cut the wires with the following properties",
  326.         init: function (screen) {
  327.             let numberHack = ["1","2","3","4","5","6","7","8","9"];
  328.             const colors = {
  329.                 red: "red",
  330.                 white: "white",
  331.                 blue: "blue",
  332.                 "rgb(255, 193, 7)": "yellow",
  333.             };
  334.             const wireColor = {
  335.                 red: [],
  336.                 white: [],
  337.                 blue: [],
  338.                 yellow: [],
  339.             };
  340.             //gather the instructions
  341.             var instructions = []
  342.             for (let child of screen.children) instructions.push(child);
  343.             var wiresData = instructions.pop();
  344.             instructions.shift();
  345.             instructions = getLines(instructions);
  346.             //get the wire information
  347.             const samples = getEl(wiresData, "p");
  348.             const wires = [];
  349.             //get the amount of wires
  350.             let wireCount = 0;
  351.             for (let i = wireCount; i < samples.length; i++) {
  352.                 if (numberHack.includes(samples[i].innerText)) wireCount += 1;
  353.                 else break;
  354.             }
  355.             let index = 0;
  356.             //get just the first 3 rows of wires.
  357.             for (let i = 0; i < 3; i++) {
  358.                 //for each row
  359.                 for (let j = 0; j < wireCount; j++) {
  360.                     const node = samples[index];
  361.                     const color = colors[node.style.color];
  362.                     if (!color) {
  363.                         index += 1;
  364.                         continue;
  365.                     }
  366.                     wireColor[color].push(j+1);
  367.                     index += 1;
  368.                 }
  369.             }
  370.  
  371.             for (let i = 0; i < instructions.length; i++) {
  372.                 const line = instructions[i].trim().toLowerCase();
  373.  
  374.                 if (!line || line.length < 10) {
  375.                     continue;
  376.                 }
  377.                 if (-1 !== line.indexOf("cut wires number")) {
  378.                     const parts = line.split(/(number\s*|\.)/);
  379.                     wires.push(parseInt(parts[2]));
  380.                 }
  381.                 if (-1 !== line.indexOf("cut all wires colored")) {
  382.                     const parts = line.split(/(colored\s*|\.)/);
  383.                     const color = parts[2];
  384.  
  385.                     if (!wireColor[color]) {
  386.                         // should never happen.
  387.                         continue;
  388.                     }
  389.  
  390.                     wireColor[color].forEach((num) => wires.push(num));
  391.                 }
  392.             }
  393.  
  394.             // new Set() removes duplicate elements.
  395.             state.game.data = [...new Set(wires)];
  396.         },
  397.         play: function (screen) {
  398.             const wire = state.game.data;
  399.             //state.game.data.shift();
  400.             if (!wire) {
  401.                 return;
  402.             }
  403.             for (let i=0;i<wire.length;i++) {
  404.                 pressKey(wire[i].toString());
  405.             }
  406.         },
  407.     },
  408. ];
  409.  
  410. /** @param {NS} ns **/
  411. export async function main(ns) {
  412.     const args = ns.flags([
  413.         ["start", false],
  414.         ["stop", false],
  415.         ["status", false],
  416.         ["quiet", false],
  417.     ]);
  418.  
  419.     function print(msg) {
  420.         if (!args.quiet) {
  421.             ns.tprint(`\n${msg}\n`);
  422.         }
  423.     }
  424.  
  425.     if (args.status) {
  426.         if (wnd.tmrAutoInf) {
  427.             print("Automated infiltration is active");
  428.         } else {
  429.             print("Automated infiltration is inactive");
  430.         }
  431.         return;
  432.     }
  433.  
  434.     if (wnd.tmrAutoInf) {
  435.         print("Stopping automated infiltration...");
  436.         clearInterval(wnd.tmrAutoInf);
  437.         delete wnd.tmrAutoInf;
  438.     }
  439.  
  440.     if (args.stop) {
  441.         return;
  442.     }
  443.  
  444.     print(
  445.         "Automated infiltration is enabled...\nVWhen you visit the infiltration screen of any company, all tasks are completed automatically."
  446.     );
  447.  
  448.     endInfiltration();
  449.  
  450.     // Monitor the current screen and start infiltration once a
  451.     // valid screen is detected.
  452.     wnd.tmrAutoInf = setInterval(infLoop, speed);
  453.  
  454.     // Modify the addEventListener logic.
  455.     wrapEventListeners();
  456. }
  457.  
  458. /**
  459.  * The infiltration loop, which is called at a rapid interval
  460.  */
  461. function infLoop() {
  462.     if (!state.started) {
  463.         waitForStart();
  464.     } else {
  465.         playGame();
  466.     }
  467. }
  468.  
  469. /**
  470.  * Returns a list of DOM elements from the main game
  471.  * container.
  472.  */
  473. function getEl(parent, selector) {
  474.     let prefix = ":scope";
  475.  
  476.     if ("string" === typeof parent) {
  477.         selector = parent;
  478.         parent = doc;
  479.  
  480.         prefix = ".MuiBox-root>.MuiBox-root>.MuiBox-root";
  481.  
  482.         if (!doc.querySelectorAll(prefix).length) {
  483.             prefix = ".MuiBox-root>.MuiBox-root>.MuiGrid-root";
  484.         }
  485.         if (!doc.querySelectorAll(prefix).length) {
  486.             prefix = ".MuiContainer-root>.MuiPaper-root";
  487.         }
  488.         if (!doc.querySelectorAll(prefix).length) {
  489.             return [];
  490.         }
  491.     }
  492.  
  493.     selector = selector.split(",");
  494.     selector = selector.map((item) => `${prefix} ${item}`);
  495.     selector = selector.join(",");
  496.  
  497.     return parent.querySelectorAll(selector);
  498. }
  499.  
  500. /**
  501.  * Returns the first element with matching text content.
  502.  */
  503. function filterByText(elements, text) {
  504.     text = text.toLowerCase();
  505.  
  506.     for (let i = 0; i < elements.length; i++) {
  507.         const content = elements[i].textContent.toLowerCase();
  508.  
  509.         if (-1 !== content.indexOf(text)) {
  510.             return elements[i];
  511.         }
  512.     }
  513.  
  514.     return null;
  515. }
  516.  
  517. /**
  518.  * Returns an array with the text-contents of the given elements.
  519.  *
  520.  * @param {NodeList} elements
  521.  * @returns {string[]}
  522.  */
  523. function getLines(elements) {
  524.     const lines = [];
  525.     elements.forEach((el) => lines.push(el.textContent));
  526.  
  527.     return lines;
  528. }
  529.  
  530. /**
  531.  * Reset the state after infiltration is done.
  532.  */
  533. function endInfiltration() {
  534.     unwrapEventListeners();
  535.     state.company = "";
  536.     state.started = false;
  537. }
  538.  
  539. /**
  540.  * Simulate a keyboard event (keydown + keyup).
  541.  *
  542.  * @param {string|int} keyOrCode A single letter (string) or key-code to send.
  543.  */
  544. function pressKey(keyOrCode) {
  545.     let keyCode = 0;
  546.     let key = "";
  547.  
  548.     if ("string" === typeof keyOrCode && keyOrCode.length > 0) {
  549.         key = keyOrCode.toLowerCase().substr(0, 1);
  550.         keyCode = key.charCodeAt(0);
  551.     } else if ("number" === typeof keyOrCode) {
  552.         keyCode = keyOrCode;
  553.         key = String.fromCharCode(keyCode);
  554.     }
  555.  
  556.     if (!keyCode || key.length !== 1) {
  557.         return;
  558.     }
  559.  
  560.     function sendEvent(event) {
  561.         const keyboardEvent = new KeyboardEvent(event, {
  562.             key,
  563.             keyCode,
  564.         });
  565.  
  566.         doc.dispatchEvent(keyboardEvent);
  567.     }
  568.  
  569.     sendEvent("keydown");
  570. }
  571.  
  572. /**
  573.  * Infiltration monitor to start automatic infiltration.
  574.  *
  575.  * This function runs asynchronously, after the "main" function ended,
  576.  * so we cannot use any "ns" function here!
  577.  */
  578. function waitForStart() {
  579.     if (state.started) {
  580.         return;
  581.     }
  582.  
  583.     const h4 = getEl("h4");
  584.  
  585.     if (!h4.length) {
  586.         return;
  587.     }
  588.     const title = h4[0].textContent;
  589.     if (0 !== title.indexOf("Infiltrating")) {
  590.         return;
  591.     }
  592.  
  593.     const btnStart = filterByText(getEl("button"), "Start");
  594.     if (!btnStart) {
  595.         return;
  596.     }
  597.  
  598.     state.company = title.substr(13);
  599.     state.started = true;
  600.     wrapEventListeners();
  601.  
  602.     console.log("Start automatic infiltration of", state.company);
  603.     btnStart.click();
  604. }
  605.  
  606. /**
  607.  * Identify the current infiltration game.
  608.  */
  609. function playGame() {
  610.     const screens = doc.querySelectorAll(".MuiContainer-root");
  611.  
  612.     if (!screens.length) {
  613.         endInfiltration();
  614.         return;
  615.     }
  616.     if (screens[0].children.length < 3) {
  617.         return;
  618.     }
  619.  
  620.     const screen = screens[0].children[2];
  621.     const h4 = getEl(screen, "h4");
  622.  
  623.     if (!h4.length) {
  624.         endInfiltration();
  625.         return;
  626.     }
  627.  
  628.     const title = h4[0].textContent.trim().toLowerCase().split(/[!.(]/)[0];
  629.  
  630.     if ("infiltration successful" === title) {
  631.         endInfiltration();
  632.         return;
  633.     }
  634.  
  635.     if ("get ready" === title) {
  636.         return;
  637.     }
  638.  
  639.     const game = infiltrationGames.find((game) => game.name === title);
  640.  
  641.     if (game) {
  642.         if (state.game.current !== title) {
  643.             state.game.current = title;
  644.             game.init(screen);
  645.         }
  646.  
  647.         game.play(screen);
  648.     } else {
  649.         console.error("Unknown game:", title);
  650.     }
  651. }
  652.  
  653. /**
  654.  * Wrap all event listeners with a custom function that injects
  655.  * the "isTrusted" flag.
  656.  *
  657.  * Is this cheating? Or is it real hacking? Don't care, as long
  658.  * as it's working :)
  659.  */
  660. function wrapEventListeners() {
  661.     if (!doc._addEventListener) {
  662.         doc._addEventListener = doc.addEventListener;
  663.  
  664.         doc.addEventListener = function (type, callback, options) {
  665.             if ("undefined" === typeof options) {
  666.                 options = false;
  667.             }
  668.             let handler = false;
  669.  
  670.             // For this script, we only want to modify "keydown" events.
  671.             if ("keydown" === type) {
  672.                 handler = function (...args) {
  673.                     if (!args[0].isTrusted) {
  674.                         const hackedEv = {};
  675.  
  676.                         for (const key in args[0]) {
  677.                             if ("isTrusted" === key) {
  678.                                 hackedEv.isTrusted = true;
  679.                             } else if ("function" === typeof args[0][key]) {
  680.                                 hackedEv[key] = args[0][key].bind(args[0]);
  681.                             } else {
  682.                                 hackedEv[key] = args[0][key];
  683.                             }
  684.                         }
  685.  
  686.                         args[0] = hackedEv;
  687.                     }
  688.  
  689.                     return callback.apply(callback, args);
  690.                 };
  691.  
  692.                 for (const prop in callback) {
  693.                     if ("function" === typeof callback[prop]) {
  694.                         handler[prop] = callback[prop].bind(callback);
  695.                     } else {
  696.                         handler[prop] = callback[prop];
  697.                     }
  698.                 }
  699.             }
  700.  
  701.             if (!this.eventListeners) {
  702.                 this.eventListeners = {};
  703.             }
  704.             if (!this.eventListeners[type]) {
  705.                 this.eventListeners[type] = [];
  706.             }
  707.             this.eventListeners[type].push({
  708.                 listener: callback,
  709.                 useCapture: options,
  710.                 wrapped: handler,
  711.             });
  712.  
  713.             return this._addEventListener(
  714.                 type,
  715.                 handler ? handler : callback,
  716.                 options
  717.             );
  718.         };
  719.     }
  720.  
  721.     if (!doc._removeEventListener) {
  722.         doc._removeEventListener = doc.removeEventListener;
  723.  
  724.         doc.removeEventListener = function (type, callback, options) {
  725.             if ("undefined" === typeof options) {
  726.                 options = false;
  727.             }
  728.  
  729.             if (!this.eventListeners) {
  730.                 this.eventListeners = {};
  731.             }
  732.             if (!this.eventListeners[type]) {
  733.                 this.eventListeners[type] = [];
  734.             }
  735.  
  736.             for (let i = 0; i < this.eventListeners[type].length; i++) {
  737.                 if (
  738.                     this.eventListeners[type][i].listener === callback &&
  739.                     this.eventListeners[type][i].useCapture === options
  740.                 ) {
  741.                     if (this.eventListeners[type][i].wrapped) {
  742.                         callback = this.eventListeners[type][i].wrapped;
  743.                     }
  744.  
  745.                     this.eventListeners[type].splice(i, 1);
  746.                     break;
  747.                 }
  748.             }
  749.  
  750.             if (this.eventListeners[type].length == 0) {
  751.                 delete this.eventListeners[type];
  752.             }
  753.  
  754.             return this._removeEventListener(type, callback, options);
  755.         };
  756.     }
  757. }
  758.  
  759. /**
  760.  * Revert the "wrapEventListeners" changes.
  761.  */
  762. function unwrapEventListeners() {
  763.     if (doc._addEventListener) {
  764.         doc.addEventListener = doc._addEventListener;
  765.         delete doc._addEventListener;
  766.     }
  767.     if (doc._removeEventListener) {
  768.         doc.removeEventListener = doc._removeEventListener;
  769.         delete doc._removeEventListener;
  770.     }
  771.     delete doc.eventListeners;
  772. }
Tags: Bitburner
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement