//Terminal /* Write text to terminal */ var post = function(input) { $("#terminal-input").before('' + input.replace( / /g, " " ) + ''); updateTerminalScroll(); } //Same thing as post but the td cells have ids so they can be animated for the hack progress bar var hackProgressBarPost = function(input) { $("#terminal-input").before('' + input + ''); updateTerminalScroll(); } var hackProgressPost = function(input) { $("#terminal-input").before('' + input + ''); updateTerminalScroll(); } function updateTerminalScroll() { var element = document.getElementById("terminal-container"); element.scrollTop = element.scrollHeight; } var postNetburnerText = function() { post("Netburner v0.1"); } //Defines key commands in terminal $(document).keyup(function(event) { //Terminal if (Engine.currentPage == Engine.Page.Terminal) { //Enter if (event.keyCode == 13) { var command = $('input[class=terminal-input]').val(); if (command.length > 0) { post("> " + command); //TODO Do i have to switch the order of these two? Terminal.executeCommand(command); $('input[class=terminal-input]').val(""); } } //Ctrl + c when an "Action" is in progress if (event.keyCode == 67 && event.ctrlKey && Engine._actionInProgress) { post("Cancelling..."); Engine._actionInProgress = false; Terminal.finishAction(true); } } }); //Keep terminal in focus terminalCtrlPressed = false; $(document).ready(function() { if (Engine.currentPage == Engine.Page.Terminal) { $('.terminal-input').focus(); } }); $(document).keydown(function(e) { if (Engine.currentPage == Engine.Page.Terminal) { if (e.which == 17) { terminalCtrlPressed = true; } else if (terminalCtrlPressed == true) { //Don't focus } else { $('.terminal-input').focus(); terminalCtrlPressed = false; } } }) $(document).keyup(function(e) { if (Engine.currentPage == Engine.Page.Terminal) { if (e.which == 17) { terminalCtrlPressed = false; } } }) var Terminal = { //Flags to determine whether the player is currently running a hack or an analyze hackFlag: false, analyzeFlag: false, finishAction: function(cancelled = false) { if (Terminal.hackFlag) { Terminal.finishHack(cancelled); } else if (Terminal.analyzeFlag) { Terminal.finishAnalyze(cancelled); } }, //Complete the hack/analyze command finishHack: function(cancelled = false) { if (cancelled == false) { console.log("Hack done. Determining success/failure of hack. Re-enabling terminal and changing the id of the hack progress bar"); //Calculate whether hack was successful var hackChance = Player.calculateHackingChance(); var rand = Math.random(); console.log("Hack success chance: " + hackChance + ", rand: " + rand); var expGainedOnSuccess = Player.calculateExpGain(); var expGainedOnFailure = Math.round(expGainedOnSuccess / 4); if (rand < hackChance) { //Success! var moneyGained = Player.calculatePercentMoneyHacked(); moneyGained = Math.floor(Player.getCurrentServer().moneyAvailable * moneyGained); //Safety check if (moneyGained <= 0) {moneyGained = 0;} Player.getCurrentServer().moneyAvailable -= moneyGained; Player.gainMoney(moneyGained); Player.hacking_exp += expGainedOnSuccess; post("Hack successful! Gained $" + moneyGained + " and " + expGainedOnSuccess + " hacking EXP"); } else { //Failure //Player only gains 25% exp for failure? TODO Can change this later to balance Player.hacking_exp += expGainedOnFailure; post("Failed to hack " + Player.getCurrentServer().hostname + ". Gained " + expGainedOnFailure + " hacking EXP"); } } //Rename the progress bar so that the next hacks dont trigger it. Re-enable terminal $("#hack-progress-bar").attr('id', "old-hack-progress-bar"); $("#hack-progress").attr('id', "old-hack-progress"); document.getElementById("terminal-input-td").innerHTML = '$ '; $('input[class=terminal-input]').prop('disabled', false); Terminal.hackFlag = false; }, finishAnalyze: function(cancelled = false) { if (cancelled == false) { post(Player.getCurrentServer().hostname + ": "); post("Required hacking skill: " + Player.getCurrentServer().requiredHackingSkill); //TODO Make these actual estimates by adding a random offset to result? //TODO Change the text to sound better post("Estimated chance to hack: " + Math.round(Player.calculateHackingChance() * 100) + "%"); post("Estimated time to hack: " + Math.round(Player.calculateHackingTime()) + " seconds"); post("Estimed total money available on server: $" + Player.getCurrentServer().moneyAvailable); post("Required number of open ports for NUKE: " + Player.getCurrentServer().numOpenPortsRequired); if (Player.getCurrentServer().sshPortOpen) { post("SSH port: Open") } else { post("SSH port: Closed") } if (Player.getCurrentServer().ftpPortOpen) { post("FTP port: Open") } else { post("FTP port: Closed") } if (Player.getCurrentServer().smtpPortOpen) { post("SMTP port: Open") } else { post("SMTP port: Closed") } if (Player.getCurrentServer().httpPortOpen) { post("HTTP port: Open") } else { post("HTTP port: Closed") } if (Player.getCurrentServer().sqlPortOpen) { post("SQL port: Open") } else { post("SQL port: Closed") } } Terminal.analyzeFlag = false; //Rename the progress bar so that the next hacks dont trigger it. Re-enable terminal $("#hack-progress-bar").attr('id', "old-hack-progress-bar"); $("#hack-progress").attr('id', "old-hack-progress"); document.getElementById("terminal-input-td").innerHTML = '$ '; $('input[class=terminal-input]').prop('disabled', false); }, executeCommand: function(command) { var commandArray = command.split(" "); if (commandArray.length == 0) { return; } switch (commandArray[0]) { case "analyze": if (commandArray.length != 1) { post("Incorrect usage of analyze command. Usage: analyze"); return; } //Analyze the current server for information console.log("analyze terminal command called"); Terminal.analyzeFlag = true; post("Analyzing system..."); hackProgressPost("Time left:"); hackProgressBarPost("["); Player.analyze(); //Disable terminal console.log("Disabling terminal"); document.getElementById("terminal-input-td").innerHTML = ''; $('input[class=terminal-input]').prop('disabled', true); break; case "clear": case "cls": if (commandArray.length != 1) { post("Incorrect usage of clear/cls command. Usage: clear/cls"); return; } console.log("cls/clear terminal command called"); $("#terminal tr:not(:last)").remove(); postNetburnerText(); break; case "connect": case "telnet": //Disconnect from current server in terminal and connect to new one if (commandArray.length != 2) { post("Incorrect usage of connect/telnet command. Usage: connect/telnet [ip/hostname]"); return; } var ip = commandArray[1]; for (var i = 0; i < Player.getCurrentServer().serversOnNetwork.length; i++) { if (Player.getCurrentServer().getServerOnNetwork(i).ip == ip || Player.getCurrentServer().getServerOnNetwork(i).hostname == ip) { Player.getCurrentServer().isConnectedTo = false; Player.currentServer = Player.getCurrentServer().getServerOnNetwork(i).ip; Player.getCurrentServer().isConnectedTo = true; post("Connected to " + ip); return; } } post("Host not found"); break; case "free": if (commandArray.length != 1) { post("Incorrect usage of free command. Usage: free"); return; } console.log("free terminal command called"); post("Total: " + Player.getCurrentServer().maxRam.toString() + " GB"); post("Used: " + Player.getCurrentServer().ramUsed.toString() + " GB"); post("Available: " + (Player.getCurrentServer().maxRam - Player.getCurrentServer().ramUsed).toString() + " GB"); break; case "hack": if (commandArray.length != 1) { post("Incorrect usage of hack command. Usage: hack"); return; } //Hack the current PC (usually for money) //You can't hack your home pc or servers you purchased if (Player.getCurrentServer().purchasedByPlayer) { post("Cannot hack your own machines! You are currently connected to your home PC or one of your purchased servers"); } else if (Player.getCurrentServer().hasAdminRights == false ) { post("You do not have admin rights for this machine! Cannot hack"); } else if (Player.getCurrentServer().requiredHackingSkill > Player.hacking_skill) { post("Your hacking skill is not high enough to attempt hacking this machine. Try analyzing the machine to determine the required hacking skill"); } else { Terminal.hackFlag = true; hackProgressPost("Time left:"); hackProgressBarPost("["); Player.hack(); //Disable terminal console.log("Disabling terminal"); document.getElementById("terminal-input-td").innerHTML = ''; $('input[class=terminal-input]').prop('disabled', true); } break; case "help": if (commandArray.length != 1) { post("Incorrect usage of help command. Usage: help"); return; } post(CONSTANTS.HelpText); break; case "home": //TODO return to home computer break; case "hostname": if (commandArray.length != 1) { post("Incorrect usage of hostname command. Usage: hostname"); return; } //Print the hostname of current system post(Player.getCurrentServer().hostname); break; case "ifconfig": if (commandArray.length != 1) { post("Incorrect usage of ifconfig command. Usage: ifconfig"); return; } //Print the IP address of the current system post(Player.getCurrentServer().ip); break; case "kill": if (commandArray.length != 2) { post("Incorrect usage of kill command. Usage: kill [scriptname]"); return; } var scriptName = commandArray[1]; for (var i = 0; i < Player.getCurrentServer().runningScripts.length; i++) { if (Player.getCurrentServer().runningScripts[i] == scriptName) { killWorkerScript(scriptName, Player.getCurrentServer().ip); post("Killing " + scriptName + ". May take a few seconds"); return; } } post("No such script is running. Nothing to kill"); break; case "ls": if (commandArray.length != 1) { post("Incorrect usage of ls command. Usage: ls"); return; } //Display all programs and scripts var allFiles = []; //Get all of the programs and scripts on the machine into one temporary array for (var i = 0; i < Player.getCurrentServer().programs.length; i++) { allFiles.push(Player.getCurrentServer().programs[i]); } for (var i = 0; i < Player.getCurrentServer().scripts.length; i++) { allFiles.push(Player.getCurrentServer().scripts[i].filename); } //Sort the files alphabetically then print each allFiles.sort(); for (var i = 0; i < allFiles.length; i++) { post(allFiles[i]); } break; case "nano": if (commandArray.length != 2) { post("Incorrect usage of nano command. Usage: nano [scriptname]"); return; } var filename = commandArray[1]; //Can only edit script files if (filename.endsWith(".script") == false) { post("Error: Only .script files are editable with nano (filename must end with .script)"); return; } //Script name is the filename without the .script at the end var scriptname = filename.substr(0, filename.indexOf(".script")); //Cannot edit scripts that are currently running for (var i = 0; i < Player.getCurrentServer().runningScripts.length; i++) { if (filename == Player.getCurrentServer().runningScripts[i].filename) { post("Cannot open/edit scripts that are currently running!"); return; } } //Check if the script already exists for (var i = 0; i < Player.getCurrentServer().scripts.length; i++) { if (filename == Player.getCurrentServer().scripts[i].filename) { Engine.loadScriptEditorContent(scriptname, Player.getCurrentServer().scripts[i].code); return; } } Engine.loadScriptEditorContent(scriptname, ""); break; case "netstat": case "scan": if (commandArray.length != 1) { post("Incorrect usage of netstat/scan command. Usage: netstat/scan"); return; } //Displays available network connections using TCP console.log("netstat/scan terminal command called"); post("Hostname IP Root Access"); for (var i = 0; i < Player.getCurrentServer().serversOnNetwork.length; i++) { //Add hostname var entry = Player.getCurrentServer().getServerOnNetwork(i).hostname; //Calculate padding and add IP var numSpaces = 21 - entry.length; var spaces = Array(numSpaces+1).join(" "); entry += spaces; entry += Player.getCurrentServer().getServerOnNetwork(i).ip; //Calculate padding and add root access info var hasRoot; if (Player.getCurrentServer().getServerOnNetwork(i).hasAdminRights) { hasRoot = 'Y'; } else { hasRoot = 'N'; } numSpaces = 21 - Player.getCurrentServer().getServerOnNetwork(i).ip.length; spaces = Array(numSpaces+1).join(" "); entry += spaces; entry += hasRoot; post(entry); } break; case "ps": if (commandArray.length != 1) { post("Incorrect usage of ps command. Usage: ps"); return; } for (var i = 0; i < Player.getCurrentServer().runningScripts.length; i++) { post(Player.getCurrentServer().runningScripts[i]); } break; case "rm": if (commandArray.length != 2) { post("Incorrect number of arguments. Usage: rm [program/script]"); return; } //Check programs var delTarget = commandArray[1]; var s = Player.getCurrentServer(); for (var i = 0; i < s.programs.length; ++i) { if (s.programs[i] == delTarget) { s.programs.splice(i, 1); return; } } //Check scripts for (var i = 0; i < s.scripts.length; ++i) { if (s.scripts[i].filename == delTarget) { //Check that the script isnt currently running if (s.runningScripts.indexOf(delTarget) > -1) { post("Cannot delete a script that is currently running!"); } else { s.scripts.splice(i, 1); } return; } } post("No such file exists"); break; case "run": //Run a program or a script if (commandArray.length != 2) { post("Incorrect number of arguments. Usage: run [program/script]"); } else { var executableName = commandArray[1]; //Check if its a script or just a program/executable if (executableName.indexOf(".script") == -1) { //Not a script Terminal.runProgram(executableName); } else { //Script Terminal.runScript(executableName); } } break; case "scp": //TODO break; case "tail": if (commandArray.length != 2) { post("Incorrect number of arguments. Usage: tail [script]"); } else { var scriptName = commandArray[1]; //Can only tail script files if (scriptName.endsWith(".script") == false) { post("Error: tail can only be called on .script files (filename must end with .script)"); return; } //Check that the script exists on this machine var currScripts = Player.getCurrentServer().scripts; for (var i = 0; i < currScripts.length; ++i) { if (scriptName == currScripts[i].filename) { currScripts[i].displayLog(); return; } } post("Error: No such script exists"); } break; case "top": //TODO List each's script RAM usage break; default: post("Command not found"); } }, //First called when the "run [program]" command is called. Checks to see if you //have the executable and, if you do, calls the executeProgram() function runProgram: function(programName) { //Check if you have the program on your computer. If you do, execute it, otherwise //display an error message for (var i = 0; i < Player.getHomeComputer().programs.length; i++) { if (Player.getHomeComputer().programs[i] == programName) { Terminal.executeProgram(programName); return; } } post("ERROR: No such executable on home computer (Only programs that exist on your home computer can be run)"); }, //Contains the implementations of all possible programs executeProgram: function(programName) { switch (programName) { case Programs.NukeProgram: if (Player.getCurrentServer().hasAdminRights) { post("You already have root access to this computer. There is no reason to run NUKE.exe"); } else { console.log("Running NUKE executable"); if (Player.getCurrentServer().openPortCount >= Player.getCurrentServer().numOpenPortsRequired) { Player.getCurrentServer().hasAdminRights = true; post("NUKE successful! Gained root access to " + Player.getCurrentServer().hostname); //TODO Make this take time rather than be instant } else { post("NUKE unsuccessful. Not enough ports have been opened"); } } break; default: post("Executable not found"); return; } }, runScript: function(scriptName) { var server = Player.getCurrentServer(); //Check if this script is already running for (var i = 0; i < server.runningScripts.length; i++) { if (server.runningScripts[i] == scriptName) { post("ERROR: This script is already running. Cannot run multiple instances"); return; } } //Check if the script exists and if it does run it for (var i = 0; i < server.scripts.length; i++) { if (server.scripts[i].filename == scriptName) { //Check for admin rights and that there is enough RAM availble to run var ramUsage = server.scripts[i].ramUsage; var ramAvailable = server.maxRam - server.ramUsed; if (server.hasAdminRights == false) { post("Need root access to run script"); return; } else if (ramUsage > ramAvailable){ post("This machine does not have enough RAM to run this script. Script requires " + ramUsage + "GB of RAM"); return; }else { //Able to run script post("Running script. May take a few seconds to start up the process..."); var script = server.scripts[i]; server.runningScripts.push(script.filename); //Push onto runningScripts addWorkerScript(script, server); return; } } } post("ERROR: No such script"); } };