diff --git a/css/companymanagement.css b/css/companymanagement.css index 9e2b08c1f..e14856bea 100644 --- a/css/companymanagement.css +++ b/css/companymanagement.css @@ -1,5 +1,6 @@ #cmpy-mgmt-container p, -#cmpy-mgmt-container a { +#cmpy-mgmt-container a, +#cmpy-mgmt-container div { font-size: 14px; } @@ -98,3 +99,36 @@ padding:2px; border:1px solid white; } + +/* Exporting materials/products */ +.cmpy-mgmt-existing-export { + border:1px solid white; + border-radius:25px; + margin:4px; + padding:4px; +} + +.cmpy-mgmt-existing-export:hover { + background-color:#333333; +} + + +/* Upgrades */ +.cmpy-mgmt-upgrade-container { + border:1px solid white; + width: 60%; + margin:4px; +} + +.cmpy-mgmt-upgrade-div { + border:1px solid white; + margin:4px; + padding:12px; + border-radius:25px; + width:95%; + color:var(--my-font-color); +} + +.cmpy-mgmt-upgrade-div:hover { + background-color:#333333; +} diff --git a/dist/bundle.js b/dist/bundle.js index 8f995bce6..39b708099 100644 --- a/dist/bundle.js +++ b/dist/bundle.js @@ -465,6 +465,7 @@ PlayerObject.prototype.prestigeSourceFile = function() { //BitNode 3: Corporatocracy if (this.bitNodeN === 3) {this.money = new __WEBPACK_IMPORTED_MODULE_15__utils_decimal_js___default.a(150e9);} + this.corporation = 0; //BitNode 8: Ghost of Wall Street if (this.bitNodeN === 8) {this.money = new __WEBPACK_IMPORTED_MODULE_15__utils_decimal_js___default.a(100000000);} @@ -2720,7 +2721,7 @@ function powerOfTwo(n) { "use strict"; /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "a", function() { return CONSTANTS; }); let CONSTANTS = { - Version: "0.33.0", + Version: "0.34.0", //Max level for any skill, assuming no multipliers. Determined by max numerical value in javascript for experience //and the skill level formula in Player.js. Note that all this means it that when experience hits MAX_INT, then @@ -2850,44 +2851,45 @@ let CONSTANTS = { HackingMissionSpamTimeIncrease: 25000, //How much time limit increase is gained when conquering a Spam Node (ms) HackingMissionTransferAttackIncrease: 1.05, //Multiplier by which the attack for all Core Nodes is increased when conquering a Transfer Node HackingMissionMiscDefenseIncrease: 1.05, //The amount by which every misc node's defense is multiplied when one is conquered - HackingMissionDifficultyToHacking: 150, //Difficulty is multiplied by this to determine enemy's "hacking" level (to determine effects of scan/attack, etc) + HackingMissionDifficultyToHacking: 135, //Difficulty is multiplied by this to determine enemy's "hacking" level (to determine effects of scan/attack, etc) HackingMissionHowToPlay: "Hacking missions are a minigame that, if won, will reward you with faction reputation.

" + "In this game you control a set of Nodes and use them to try and defeat an enemy. Your Nodes " + "are colored blue, while the enemy's are red. There are also other nodes on the map colored gray " + "that initially belong to neither you nor the enemy. The goal of the game is " + - "to capture all of the enemy's database nodes within the time limit. " + - "If you cannot capture all of the enemy's database nodes in the time limit, you will lose.

" + + "to capture all of the enemy's Database nodes within the time limit. " + + "If you fail to do this, you will lose.

" + "Each Node has three stats: Attack, Defense, and HP. There are five different actions that " + "a Node can take:

" + "Attack - Targets an enemy Node and lowers its HP. The effectiveness is determined by the owner's Attack, the Player's " + - "hacking level, and the enemy's defense.
" + + "hacking level, and the enemy's defense.

" + "Scan - Targets an enemy Node and lowers its Defense. The effectiveness is determined by the owner's Attack, the Player's hacking level, and the " + - "enemy's defense.
" + + "enemy's defense.

" + "Weaken - Targets an enemy Node and lowers its Attack. The effectiveness is determined by the owner's Attack, the Player's hacking level, and the enemy's " + - "defense.
" + - "Fortify - Raises the Node's Defense. The effectiveness is determined by your hacking level.
" + + "defense.

" + + "Fortify - Raises the Node's Defense. The effectiveness is determined by your hacking level.

" + "Overflow - Raises the Node's Attack but lowers its Defense. The effectiveness is determined by your hacking level.

" + "Note that when determining the effectiveness of the above actions, the TOTAL Attack or Defense of the team is used, not just the " + "Attack/Defense of the individual Node that is performing the action.

" + "To capture a Node, you must lower its HP down to 0.

" + "There are six different types of Nodes:

" + - "CPU Core - These are your main Nodes that are used to perform actions. Capable of performing every action
" + - "Firewall - Nodes with high defense. These Nodes cannot perform any actions
" + + "CPU Core - These are your main Nodes that are used to perform actions. Capable of performing every action

" + + "Firewall - Nodes with high defense. These Nodes can 'Fortify'

" + "Database - A special type of Node. The player's objective is to conquer all of the enemy's Database Nodes within " + - "the time limit. These Nodes cannot perform any actions
" + + "the time limit. These Nodes cannot perform any actions

" + "Spam - Conquering one of these Nodes will slow the enemy's trace, giving the player additional time to complete " + - "the mission. These Nodes cannot perform any actions
" + + "the mission. These Nodes cannot perform any actions

" + "Transfer - Conquering one of these nodes will increase the Attack of all of your CPU Cores by a small fixed percentage. " + - "These Nodes are capable of performing every action except the 'Attack' action
" + - "Shield - Nodes with high defense. These Nodes cannot perform any actions

" + - "To assign an action to a Node, you must first select one of your Nodes. This can be done by simply clicking on it. Only " + - "one Node can be selected at a time, and it will be denoted with a white highlight. After selecting the Node, " + + "These Nodes are capable of performing every action except the 'Attack' action

" + + "Shield - Nodes with high defense. These Nodes can 'Fortify'

" + + "To assign an action to a Node, you must first select one of your Nodes. This can be done by simply clicking on it. Double-clicking " + + "a node will select all of your Nodes of the same type (e.g. select all CPU Core Nodes or all Transfer Nodes). Note that only Nodes " + + "that can perform actions (CPU Core, Transfer, Shield, Firewall) can be selected. Selected Nodes will be denoted with a white highlight. After selecting a Node or multiple Nodes, " + "select its action using the Action Buttons near the top of the screen. Every action also has a corresponding keyboard " + "shortcut.

" + "For certain actions such as attacking, scanning, and weakening, the Node performing the action must have a target. To target " + "another node, simply click-and-drag from the 'source' Node to a target. A Node can only have one target, and you can target " + "any Node that is adjacent to one of your Nodes (immediately above, below, or to the side. NOT diagonal). Furthermore, only CPU Cores and Transfer Nodes " + - "can target, since they are the only ones that can perform actions. To remove a target, you can simply click on the line that represents " + + "can target, since they are the only ones that can perform the related actions. To remove a target, you can simply click on the line that represents " + "the connection between one of your Nodes and its target. Alternatively, you can select the 'source' Node and click the 'Drop Connection' button, " + "or press 'd'.

" + "Other Notes:

" + @@ -3834,17 +3836,26 @@ let CONSTANTS = { LatestUpdate: "v0.34.0
" + + "-Added clear() and exit() Netscript functions
" + + "-When starting out or prestiging, you will now receive a 'Hacking Starter Guide'. It provides tips/pointers for new players
" + + "-Doubled the amount of RAM on low-level servers (up to required hacking level 150)
" + "-Slightly increased experience gain from Infiltration
" + "-buyStock(), sellStock(), shortStock(), and sellShort() Netscript function now return the stock price at which the transaction occurred, rather than a boolean. " + "If the function fails for some reason, 0 will be returned.
" + "-Hacking Mission Changes:
" + + "---You can now select multiple Nodes of the same type by double clicking. This allows you to set the " + + "action of all of selected nodes at once (e.g. set all Transfer Nodes to Fortify). Creating connections " + + "does not work with this multi-select functionality yet
" + "---Shield and Firewall Nodes can now fortify
" + - "---The effects of Fortifying are now ~30% lower
" + - "---Conquering a Spam Node now increases your time limit by 25 secs instead of 15
" + + "---The effects of Fortifying are now ~5% lower
" + + "---Conquering a Spam Node now increases your time limit by 25 seconds instead of 15
" + "---Damage dealt by Attacking was slightly reduced
" + "---The effect of Scanning was slightly reduced
" + - "" - + "---Enemy CPU Core Nodes start with slightly more attack. Misc Nodes start with slightly less defense
" + + "-Corporation Management changes:
" + + "---Added several upgrades that unlock new features
" + + "---Implemented Exporting mechanic
" + + "---Fixed many bugs
" } @@ -6236,23 +6247,23 @@ function initForeignServers() { AddToAllServers(JohnsonOrthopedicsServer); //"Low level" targets - var FoodNStuffServer = new Server(Object(__WEBPACK_IMPORTED_MODULE_7__utils_IPAddress_js__["a" /* createRandomIp */])(), "foodnstuff", "Food N Stuff Supermarket", false, false, false, 8); + var FoodNStuffServer = new Server(Object(__WEBPACK_IMPORTED_MODULE_7__utils_IPAddress_js__["a" /* createRandomIp */])(), "foodnstuff", "Food N Stuff Supermarket", false, false, false, 16); FoodNStuffServer.setHackingParameters(1, 2000000, 10, 5); FoodNStuffServer.setPortProperties(0); FoodNStuffServer.messages.push("sector-12-crime.lit"); AddToAllServers(FoodNStuffServer); - var SigmaCosmeticsServer = new Server(Object(__WEBPACK_IMPORTED_MODULE_7__utils_IPAddress_js__["a" /* createRandomIp */])(), "sigma-cosmetics", "Sigma Cosmetics", false, false, false, 8); + var SigmaCosmeticsServer = new Server(Object(__WEBPACK_IMPORTED_MODULE_7__utils_IPAddress_js__["a" /* createRandomIp */])(), "sigma-cosmetics", "Sigma Cosmetics", false, false, false, 16); SigmaCosmeticsServer.setHackingParameters(5, 2300000, 10, 10); SigmaCosmeticsServer.setPortProperties(0); AddToAllServers(SigmaCosmeticsServer); - var JoesGunsServer = new Server(Object(__WEBPACK_IMPORTED_MODULE_7__utils_IPAddress_js__["a" /* createRandomIp */])(), "joesguns", "Joe's Guns", false, false, false, 8); + var JoesGunsServer = new Server(Object(__WEBPACK_IMPORTED_MODULE_7__utils_IPAddress_js__["a" /* createRandomIp */])(), "joesguns", "Joe's Guns", false, false, false, 16); JoesGunsServer.setHackingParameters(10, 2500000, 15, 20); JoesGunsServer.setPortProperties(0); AddToAllServers(JoesGunsServer); - var Zer0NightclubServer = new Server(Object(__WEBPACK_IMPORTED_MODULE_7__utils_IPAddress_js__["a" /* createRandomIp */])(), "zer0", "ZER0 Nightclub", false, false, false, 16); + var Zer0NightclubServer = new Server(Object(__WEBPACK_IMPORTED_MODULE_7__utils_IPAddress_js__["a" /* createRandomIp */])(), "zer0", "ZER0 Nightclub", false, false, false, 32); Zer0NightclubServer.setHackingParameters(75, 7500000, 25, 40); Zer0NightclubServer.setPortProperties(1); AddToAllServers(Zer0NightclubServer); @@ -6262,40 +6273,40 @@ function initForeignServers() { NectarNightclubServer.setPortProperties(0); AddToAllServers(NectarNightclubServer); - var NeoNightclubServer = new Server(Object(__WEBPACK_IMPORTED_MODULE_7__utils_IPAddress_js__["a" /* createRandomIp */])(), "neo-net", "Neo Nightclub Network", false, false, false, 16); + var NeoNightclubServer = new Server(Object(__WEBPACK_IMPORTED_MODULE_7__utils_IPAddress_js__["a" /* createRandomIp */])(), "neo-net", "Neo Nightclub Network", false, false, false, 32); NeoNightclubServer.setHackingParameters(50, 5000000, 25, 25); NeoNightclubServer.setPortProperties(1); NeoNightclubServer.messages.push("the-hidden-world.lit"); AddToAllServers(NeoNightclubServer); - var SilverHelixServer = new Server(Object(__WEBPACK_IMPORTED_MODULE_7__utils_IPAddress_js__["a" /* createRandomIp */])(), "silver-helix", "Silver Helix", false, false, false, 32); + var SilverHelixServer = new Server(Object(__WEBPACK_IMPORTED_MODULE_7__utils_IPAddress_js__["a" /* createRandomIp */])(), "silver-helix", "Silver Helix", false, false, false, 64); SilverHelixServer.setHackingParameters(150, 45000000, 30, 30); SilverHelixServer.setPortProperties(2); SilverHelixServer.messages.push("new-triads.lit"); AddToAllServers(SilverHelixServer); - var HongFangTeaHouseServer = new Server(Object(__WEBPACK_IMPORTED_MODULE_7__utils_IPAddress_js__["a" /* createRandomIp */])(), "hong-fang-tea", "HongFang Teahouse", false, false, false, 8); + var HongFangTeaHouseServer = new Server(Object(__WEBPACK_IMPORTED_MODULE_7__utils_IPAddress_js__["a" /* createRandomIp */])(), "hong-fang-tea", "HongFang Teahouse", false, false, false, 16); HongFangTeaHouseServer.setHackingParameters(30, 3000000, 15, 20); HongFangTeaHouseServer.setPortProperties(0); HongFangTeaHouseServer.messages.push("brighter-than-the-sun.lit"); AddToAllServers(HongFangTeaHouseServer); - var HaraKiriSushiBarServer = new Server(Object(__WEBPACK_IMPORTED_MODULE_7__utils_IPAddress_js__["a" /* createRandomIp */])(), "harakiri-sushi", "HaraKiri Sushi Bar Network", false, false, false, 8); + var HaraKiriSushiBarServer = new Server(Object(__WEBPACK_IMPORTED_MODULE_7__utils_IPAddress_js__["a" /* createRandomIp */])(), "harakiri-sushi", "HaraKiri Sushi Bar Network", false, false, false, 16); HaraKiriSushiBarServer.setHackingParameters(40, 4000000, 15, 40); HaraKiriSushiBarServer.setPortProperties(0); AddToAllServers(HaraKiriSushiBarServer); - var PhantasyServer = new Server(Object(__WEBPACK_IMPORTED_MODULE_7__utils_IPAddress_js__["a" /* createRandomIp */])(), "phantasy", "Phantasy Club", false, false, false, 16); + var PhantasyServer = new Server(Object(__WEBPACK_IMPORTED_MODULE_7__utils_IPAddress_js__["a" /* createRandomIp */])(), "phantasy", "Phantasy Club", false, false, false, 32); PhantasyServer.setHackingParameters(100, 24000000, 20, 35); PhantasyServer.setPortProperties(2); AddToAllServers(PhantasyServer); - var MaxHardwareServer = new Server(Object(__WEBPACK_IMPORTED_MODULE_7__utils_IPAddress_js__["a" /* createRandomIp */])(), "max-hardware", "Max Hardware Store", false, false, false, 16); + var MaxHardwareServer = new Server(Object(__WEBPACK_IMPORTED_MODULE_7__utils_IPAddress_js__["a" /* createRandomIp */])(), "max-hardware", "Max Hardware Store", false, false, false, 32); MaxHardwareServer.setHackingParameters(80, 10000000, 15, 30); MaxHardwareServer.setPortProperties(1); AddToAllServers(MaxHardwareServer); - var OmegaSoftwareServer = new Server(Object(__WEBPACK_IMPORTED_MODULE_7__utils_IPAddress_js__["a" /* createRandomIp */])(), "omega-net", "Omega Software", false, false, false, 16); + var OmegaSoftwareServer = new Server(Object(__WEBPACK_IMPORTED_MODULE_7__utils_IPAddress_js__["a" /* createRandomIp */])(), "omega-net", "Omega Software", false, false, false, 32); OmegaSoftwareServer.setHackingParameters(Object(__WEBPACK_IMPORTED_MODULE_6__utils_HelperFunctions_js__["h" /* getRandomInt */])(180, 220), Object(__WEBPACK_IMPORTED_MODULE_6__utils_HelperFunctions_js__["h" /* getRandomInt */])(60000000, 70000000), Object(__WEBPACK_IMPORTED_MODULE_6__utils_HelperFunctions_js__["h" /* getRandomInt */])(25, 35), Object(__WEBPACK_IMPORTED_MODULE_6__utils_HelperFunctions_js__["h" /* getRandomInt */])(30, 40)); OmegaSoftwareServer.setPortProperties(2); OmegaSoftwareServer.messages.push("the-new-god.lit"); @@ -6307,7 +6318,7 @@ function initForeignServers() { CrushFitnessGymServer.setPortProperties(2); AddToAllServers(CrushFitnessGymServer); - var IronGymServer = new Server(Object(__WEBPACK_IMPORTED_MODULE_7__utils_IPAddress_js__["a" /* createRandomIp */])(), "iron-gym", "Iron Gym Network", false, false, false, 16); + var IronGymServer = new Server(Object(__WEBPACK_IMPORTED_MODULE_7__utils_IPAddress_js__["a" /* createRandomIp */])(), "iron-gym", "Iron Gym Network", false, false, false, 32); IronGymServer.setHackingParameters(100, 20000000, 30, 20); IronGymServer.setPortProperties(1); AddToAllServers(IronGymServer); @@ -6531,6 +6542,7 @@ function prestigeHomeComputer(homeComp) { homeComp.programs.push(__WEBPACK_IMPORTED_MODULE_2__CreateProgram_js__["a" /* Programs */].NukeProgram); homeComp.messages.length = 0; + homeComp.messages.push("hackers-starting-handbook.lit"); } //List of all servers that exist in the game, indexed by their ip @@ -21513,7 +21525,8 @@ function calculateRamUsage(codeCopy) { var sqlinjectCount = Object(__WEBPACK_IMPORTED_MODULE_11__utils_StringHelperFunctions_js__["h" /* numOccurrences */])(codeCopy, "sqlinject("); var runCount = Object(__WEBPACK_IMPORTED_MODULE_11__utils_StringHelperFunctions_js__["h" /* numOccurrences */])(codeCopy, "run("); var execCount = Object(__WEBPACK_IMPORTED_MODULE_11__utils_StringHelperFunctions_js__["h" /* numOccurrences */])(codeCopy, "exec("); - var killCount = Object(__WEBPACK_IMPORTED_MODULE_11__utils_StringHelperFunctions_js__["h" /* numOccurrences */])(codeCopy, "kill(") + Object(__WEBPACK_IMPORTED_MODULE_11__utils_StringHelperFunctions_js__["h" /* numOccurrences */])(codeCopy, "killall("); + var killCount = Object(__WEBPACK_IMPORTED_MODULE_11__utils_StringHelperFunctions_js__["h" /* numOccurrences */])(codeCopy, "kill(") + Object(__WEBPACK_IMPORTED_MODULE_11__utils_StringHelperFunctions_js__["h" /* numOccurrences */])(codeCopy, "killall(") + + Object(__WEBPACK_IMPORTED_MODULE_11__utils_StringHelperFunctions_js__["h" /* numOccurrences */])(codeCopy, "exit("); var scpCount = Object(__WEBPACK_IMPORTED_MODULE_11__utils_StringHelperFunctions_js__["h" /* numOccurrences */])(codeCopy, "scp("); var hasRootAccessCount = Object(__WEBPACK_IMPORTED_MODULE_11__utils_StringHelperFunctions_js__["h" /* numOccurrences */])(codeCopy, "hasRootAccess("); var getHostnameCount = Object(__WEBPACK_IMPORTED_MODULE_11__utils_StringHelperFunctions_js__["h" /* numOccurrences */])(codeCopy, "getHostname(") + @@ -21550,7 +21563,7 @@ function calculateRamUsage(codeCopy) { Object(__WEBPACK_IMPORTED_MODULE_11__utils_StringHelperFunctions_js__["h" /* numOccurrences */])(codeCopy, "deleteServer(") + Object(__WEBPACK_IMPORTED_MODULE_11__utils_StringHelperFunctions_js__["h" /* numOccurrences */])(codeCopy, "getPurchasedServers("); var scriptRoundCount = Object(__WEBPACK_IMPORTED_MODULE_11__utils_StringHelperFunctions_js__["h" /* numOccurrences */])(codeCopy, "round("); - var scriptWriteCount = Object(__WEBPACK_IMPORTED_MODULE_11__utils_StringHelperFunctions_js__["h" /* numOccurrences */])(codeCopy, "write("); + var scriptWriteCount = Object(__WEBPACK_IMPORTED_MODULE_11__utils_StringHelperFunctions_js__["h" /* numOccurrences */])(codeCopy, "write(") + Object(__WEBPACK_IMPORTED_MODULE_11__utils_StringHelperFunctions_js__["h" /* numOccurrences */])(codeCopy, "clear("); var scriptReadCount = Object(__WEBPACK_IMPORTED_MODULE_11__utils_StringHelperFunctions_js__["h" /* numOccurrences */])(codeCopy, "read("); var arbScriptCount = Object(__WEBPACK_IMPORTED_MODULE_11__utils_StringHelperFunctions_js__["h" /* numOccurrences */])(codeCopy, "scriptRunning(") + Object(__WEBPACK_IMPORTED_MODULE_11__utils_StringHelperFunctions_js__["h" /* numOccurrences */])(codeCopy, "scriptKill("); @@ -25649,6 +25662,17 @@ function NetscriptFunctions(workerScript) { workerScript.scriptRef.log("killall(): Killing all scripts on " + server.hostname + ". May take a few minutes for the scripts to die"); return true; }, + exit : function() { + var server = Object(__WEBPACK_IMPORTED_MODULE_16__Server_js__["e" /* getServer */])(workerScript.serverIp); + if (server == null) { + throw Object(__WEBPACK_IMPORTED_MODULE_23__NetscriptEvaluator_js__["d" /* makeRuntimeRejectMsg */])(workerScript, "Error getting Server for this script in exit(). This is a bug please contact game dev"); + } + if (Object(__WEBPACK_IMPORTED_MODULE_22__NetscriptWorker_js__["d" /* killWorkerScript */])(workerScript.scriptRef, server.ip)) { + workerScript.scriptRef.log("Exiting..."); + } else { + workerScript.scriptRef.log("Exit failed(). This is a bug please contact game developer"); + } + }, scp : function(scriptname, ip1, ip2){ if (arguments.length !== 2 && arguments.length !== 3) { throw Object(__WEBPACK_IMPORTED_MODULE_23__NetscriptEvaluator_js__["d" /* makeRuntimeRejectMsg */])(workerScript, "Error: scp() call has incorrect number of arguments. Takes 2 or 3 arguments"); @@ -26322,7 +26346,7 @@ function NetscriptFunctions(workerScript) { if (!isNaN(port)) { //Write to port //Port 1-10 if (port < 1 || port > 10) { - throw Object(__WEBPACK_IMPORTED_MODULE_23__NetscriptEvaluator_js__["d" /* makeRuntimeRejectMsg */])(workerScript, "Trying to write to invalid port: " + port + ". Only ports 1-10 are valid."); + throw Object(__WEBPACK_IMPORTED_MODULE_23__NetscriptEvaluator_js__["d" /* makeRuntimeRejectMsg */])(workerScript, "ERR: Trying to write to invalid port: " + port + ". Only ports 1-10 are valid."); } var portName = "Port" + String(port); var port = __WEBPACK_IMPORTED_MODULE_22__NetscriptWorker_js__["a" /* NetscriptPorts */][portName]; @@ -26353,19 +26377,19 @@ function NetscriptFunctions(workerScript) { } return true; } else { - throw Object(__WEBPACK_IMPORTED_MODULE_23__NetscriptEvaluator_js__["d" /* makeRuntimeRejectMsg */])(workerScript, "Invalid argument passed in for port: " + port + ". Must be a number between 1 and 10"); + throw Object(__WEBPACK_IMPORTED_MODULE_23__NetscriptEvaluator_js__["d" /* makeRuntimeRejectMsg */])(workerScript, "Invalid argument passed in for write: " + port); } }, read : function(port) { if (!isNaN(port)) { //Read from port //Port 1-10 if (port < 1 || port > 10) { - throw Object(__WEBPACK_IMPORTED_MODULE_23__NetscriptEvaluator_js__["d" /* makeRuntimeRejectMsg */])(workerScript, "Trying to write to invalid port: " + port + ". Only ports 1-10 are valid."); + throw Object(__WEBPACK_IMPORTED_MODULE_23__NetscriptEvaluator_js__["d" /* makeRuntimeRejectMsg */])(workerScript, "ERR: Trying to read from invalid port: " + port + ". Only ports 1-10 are valid."); } var portName = "Port" + String(port); var port = __WEBPACK_IMPORTED_MODULE_22__NetscriptWorker_js__["a" /* NetscriptPorts */][portName]; if (port == null) { - throw Object(__WEBPACK_IMPORTED_MODULE_23__NetscriptEvaluator_js__["d" /* makeRuntimeRejectMsg */])(workerScript, "Could not find port: " + port + ". This is a bug contact the game developer"); + throw Object(__WEBPACK_IMPORTED_MODULE_23__NetscriptEvaluator_js__["d" /* makeRuntimeRejectMsg */])(workerScript, "ERR: Could not find port: " + port + ". This is a bug contact the game developer"); } if (port.length == 0) { return "NULL PORT DATA"; @@ -26385,9 +26409,35 @@ function NetscriptFunctions(workerScript) { return ""; } } else { - throw Object(__WEBPACK_IMPORTED_MODULE_23__NetscriptEvaluator_js__["d" /* makeRuntimeRejectMsg */])(workerScript, "Invalid argument passed in for port: " + port + ". Must be a number between 1 and 10"); + throw Object(__WEBPACK_IMPORTED_MODULE_23__NetscriptEvaluator_js__["d" /* makeRuntimeRejectMsg */])(workerScript, "Invalid argument passed in for read(): " + port); } }, + clear : function(port) { + if (!isNaN(port)) { //Clear port + if (port < 1 || port > 10) { + throw Object(__WEBPACK_IMPORTED_MODULE_23__NetscriptEvaluator_js__["d" /* makeRuntimeRejectMsg */])(workerScript, "ERR: Trying to read from invalid port: " + port + ". Only ports 1-10 are valid"); + } + var portName = "Port" + String(port); + var port = __WEBPACK_IMPORTED_MODULE_22__NetscriptWorker_js__["a" /* NetscriptPorts */][portName]; + if (port == null) { + throw Object(__WEBPACK_IMPORTED_MODULE_23__NetscriptEvaluator_js__["d" /* makeRuntimeRejectMsg */])(workerScript, "ERR: Could not find port: " + port + ". This is a bug contact the game developer"); + } + port.length = 0; + } else if (Object(__WEBPACK_IMPORTED_MODULE_29__utils_StringHelperFunctions_js__["f" /* isString */])(port)) { //Clear text file + var fn = port; + var server = Object(__WEBPACK_IMPORTED_MODULE_16__Server_js__["e" /* getServer */])(workerScript.serverIp); + if (server == null) { + throw Object(__WEBPACK_IMPORTED_MODULE_23__NetscriptEvaluator_js__["d" /* makeRuntimeRejectMsg */])(workerScript, "Error getting Server for this script in clear(). This is a bug please contact game dev"); + } + var txtFile = Object(__WEBPACK_IMPORTED_MODULE_21__TextFile_js__["b" /* getTextFile */])(fn, server); + if (txtFile != null) { + txtFile.write(""); + } + } else { + throw Object(__WEBPACK_IMPORTED_MODULE_23__NetscriptEvaluator_js__["d" /* makeRuntimeRejectMsg */])(workerScript, "Invalid argument passed in for clear(): " + port); + } + return 0; + }, scriptRunning : function(scriptname, ip) { var server = Object(__WEBPACK_IMPORTED_MODULE_16__Server_js__["e" /* getServer */])(ip); if (server == null) { @@ -28570,7 +28620,7 @@ let Terminal = { //Check programs var delTarget = commandArray[1]; - if (delTarget.endsWith(".exe")) { + if (delTarget.includes(".exe")) { for (var i = 0; i < s.programs.length; ++i) { if (s.programs[i] == delTarget) { s.programs.splice(i, 1); @@ -34641,8 +34691,10 @@ function updateActiveScriptsText(workerscript, item, statsEl=null) { /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "a", function() { return currITutorialStep; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "b", function() { return iTutorialIsRunning; }); /* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__engine_js__ = __webpack_require__(5); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_1__utils_DialogBox_js__ = __webpack_require__(1); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_2__utils_HelperFunctions_js__ = __webpack_require__(2); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_1__Player_js__ = __webpack_require__(0); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_2__utils_DialogBox_js__ = __webpack_require__(1); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_3__utils_HelperFunctions_js__ = __webpack_require__(2); + @@ -34695,14 +34747,14 @@ function iTutorialStart() { iTutorialEvaluateStep(); //Exit tutorial button - var exitButton = Object(__WEBPACK_IMPORTED_MODULE_2__utils_HelperFunctions_js__["b" /* clearEventListeners */])("interactive-tutorial-exit"); + var exitButton = Object(__WEBPACK_IMPORTED_MODULE_3__utils_HelperFunctions_js__["b" /* clearEventListeners */])("interactive-tutorial-exit"); exitButton.addEventListener("click", function() { iTutorialEnd(); return false; }); //Back button - var backButton = Object(__WEBPACK_IMPORTED_MODULE_2__utils_HelperFunctions_js__["b" /* clearEventListeners */])("interactive-tutorial-back"); + var backButton = Object(__WEBPACK_IMPORTED_MODULE_3__utils_HelperFunctions_js__["b" /* clearEventListeners */])("interactive-tutorial-back"); backButton.style.display = "none"; backButton.addEventListener("click", function() { iTutorialPrevStep(); @@ -34720,7 +34772,7 @@ function iTutorialEvaluateStep() { "The game takes place in a dark, dystopian future...The year is 2077...

" + "This tutorial will show you the basics of the game. " + "You may skip the tutorial at any time."); - var next = Object(__WEBPACK_IMPORTED_MODULE_2__utils_HelperFunctions_js__["b" /* clearEventListeners */])("interactive-tutorial-next"); + var next = Object(__WEBPACK_IMPORTED_MODULE_3__utils_HelperFunctions_js__["b" /* clearEventListeners */])("interactive-tutorial-next"); next.style.display = "inline-block"; next.addEventListener("click", function() { iTutorialNextStep(); @@ -34732,7 +34784,7 @@ function iTutorialEvaluateStep() { "the main navigation menu (left-hand side of the screen)"); //No next button - var next = Object(__WEBPACK_IMPORTED_MODULE_2__utils_HelperFunctions_js__["b" /* clearEventListeners */])("interactive-tutorial-next"); + var next = Object(__WEBPACK_IMPORTED_MODULE_3__utils_HelperFunctions_js__["b" /* clearEventListeners */])("interactive-tutorial-next"); next.style.display = "none"; //Flash Character tab @@ -34743,14 +34795,14 @@ function iTutorialEvaluateStep() { charaterMainMenuButton.addEventListener("click", function() { __WEBPACK_IMPORTED_MODULE_0__engine_js__["Engine"].loadCharacterContent(); iTutorialNextStep(); //Opening the character page will go to the next step - Object(__WEBPACK_IMPORTED_MODULE_2__utils_HelperFunctions_js__["b" /* clearEventListeners */])("stats-menu-link"); + Object(__WEBPACK_IMPORTED_MODULE_3__utils_HelperFunctions_js__["b" /* clearEventListeners */])("stats-menu-link"); return false; }); break; case iTutorialSteps.CharacterPage: iTutorialSetText("The Stats page shows a lot of important information about your progress, " + "such as your skills, money, and bonuses/multipliers. ") - var next = Object(__WEBPACK_IMPORTED_MODULE_2__utils_HelperFunctions_js__["b" /* clearEventListeners */])("interactive-tutorial-next"); + var next = Object(__WEBPACK_IMPORTED_MODULE_3__utils_HelperFunctions_js__["b" /* clearEventListeners */])("interactive-tutorial-next"); next.style.display = "inline-block"; next.addEventListener("click", function() { iTutorialNextStep(); @@ -34761,7 +34813,7 @@ function iTutorialEvaluateStep() { iTutorialSetText("Let's head to your computer's terminal by clicking the 'Terminal' tab on the " + "main navigation menu."); //No next button - var next = Object(__WEBPACK_IMPORTED_MODULE_2__utils_HelperFunctions_js__["b" /* clearEventListeners */])("interactive-tutorial-next"); + var next = Object(__WEBPACK_IMPORTED_MODULE_3__utils_HelperFunctions_js__["b" /* clearEventListeners */])("interactive-tutorial-next"); next.style.display = "none"; document.getElementById("terminal-menu-link").setAttribute("class", "flashing-button"); @@ -34771,14 +34823,14 @@ function iTutorialEvaluateStep() { terminalMainMenuButton.addEventListener("click", function() { __WEBPACK_IMPORTED_MODULE_0__engine_js__["Engine"].loadTerminalContent(); iTutorialNextStep(); - Object(__WEBPACK_IMPORTED_MODULE_2__utils_HelperFunctions_js__["b" /* clearEventListeners */])("terminal-menu-link"); + Object(__WEBPACK_IMPORTED_MODULE_3__utils_HelperFunctions_js__["b" /* clearEventListeners */])("terminal-menu-link"); return false; }); break; case iTutorialSteps.TerminalIntro: iTutorialSetText("The Terminal is used to interface with your home computer as well as " + "all of the other machines around the world."); - var next = Object(__WEBPACK_IMPORTED_MODULE_2__utils_HelperFunctions_js__["b" /* clearEventListeners */])("interactive-tutorial-next"); + var next = Object(__WEBPACK_IMPORTED_MODULE_3__utils_HelperFunctions_js__["b" /* clearEventListeners */])("interactive-tutorial-next"); next.style.display = "inline-block"; next.addEventListener("click", function() { iTutorialNextStep(); @@ -34788,7 +34840,7 @@ function iTutorialEvaluateStep() { case iTutorialSteps.TerminalHelp: iTutorialSetText("Let's try it out. Start by entering the 'help' command into the Terminal " + "(Don't forget to press Enter after typing the command)"); - var next = Object(__WEBPACK_IMPORTED_MODULE_2__utils_HelperFunctions_js__["b" /* clearEventListeners */])("interactive-tutorial-next"); + var next = Object(__WEBPACK_IMPORTED_MODULE_3__utils_HelperFunctions_js__["b" /* clearEventListeners */])("interactive-tutorial-next"); next.style.display = "none"; //next step triggered by terminal command break; @@ -34864,7 +34916,7 @@ function iTutorialEvaluateStep() { "the server's security level.

The amount of money on a server is not limitless. So, if " + "you constantly hack a server and deplete its money, then you will encounter " + "diminishing returns in your hacking."); - var next = Object(__WEBPACK_IMPORTED_MODULE_2__utils_HelperFunctions_js__["b" /* clearEventListeners */])("interactive-tutorial-next"); + var next = Object(__WEBPACK_IMPORTED_MODULE_3__utils_HelperFunctions_js__["b" /* clearEventListeners */])("interactive-tutorial-next"); next.style.display = "inline-block"; next.addEventListener("click", function() { iTutorialNextStep(); @@ -34878,7 +34930,7 @@ function iTutorialEvaluateStep() { "command. Scripts must end with the '.script' extension. Let's make a script now by " + "entering 'nano foodnstuff.script' after the hack command finishes running (Sidenote: Pressing ctrl + c" + " will end a command like hack early)"); - var next = Object(__WEBPACK_IMPORTED_MODULE_2__utils_HelperFunctions_js__["b" /* clearEventListeners */])("interactive-tutorial-next"); + var next = Object(__WEBPACK_IMPORTED_MODULE_3__utils_HelperFunctions_js__["b" /* clearEventListeners */])("interactive-tutorial-next"); next.style.display = "none"; //next step triggered by terminal command break; @@ -34923,7 +34975,7 @@ function iTutorialEvaluateStep() { activeScriptsMainMenuButton.addEventListener("click", function() { __WEBPACK_IMPORTED_MODULE_0__engine_js__["Engine"].loadActiveScriptsContent(); iTutorialNextStep(); - Object(__WEBPACK_IMPORTED_MODULE_2__utils_HelperFunctions_js__["b" /* clearEventListeners */])("active-scripts-menu-link"); + Object(__WEBPACK_IMPORTED_MODULE_3__utils_HelperFunctions_js__["b" /* clearEventListeners */])("active-scripts-menu-link"); return false; }); break; @@ -34934,11 +34986,11 @@ function iTutorialEvaluateStep() { "link."); document.getElementById("terminal-menu-link").setAttribute("class", "flashing-button"); //Initialize everything necessary to open the 'Terminal' Page - var terminalMainMenuButton = Object(__WEBPACK_IMPORTED_MODULE_2__utils_HelperFunctions_js__["b" /* clearEventListeners */])("terminal-menu-link"); + var terminalMainMenuButton = Object(__WEBPACK_IMPORTED_MODULE_3__utils_HelperFunctions_js__["b" /* clearEventListeners */])("terminal-menu-link"); terminalMainMenuButton.addEventListener("click", function() { __WEBPACK_IMPORTED_MODULE_0__engine_js__["Engine"].loadTerminalContent(); iTutorialNextStep(); - Object(__WEBPACK_IMPORTED_MODULE_2__utils_HelperFunctions_js__["b" /* clearEventListeners */])("terminal-menu-link"); + Object(__WEBPACK_IMPORTED_MODULE_3__utils_HelperFunctions_js__["b" /* clearEventListeners */])("terminal-menu-link"); return false; }); break; @@ -34955,7 +35007,7 @@ function iTutorialEvaluateStep() { "scripts using the Netscript language, select the 'Tutorial' link in the " + "main navigation menu to look at the documentation. For now, let's move on " + "to something else!"); - var next = Object(__WEBPACK_IMPORTED_MODULE_2__utils_HelperFunctions_js__["b" /* clearEventListeners */])("interactive-tutorial-next"); + var next = Object(__WEBPACK_IMPORTED_MODULE_3__utils_HelperFunctions_js__["b" /* clearEventListeners */])("interactive-tutorial-next"); next.style.display = "inline-block"; next.addEventListener("click", function() { iTutorialNextStep(); @@ -34967,13 +35019,13 @@ function iTutorialEvaluateStep() { "earn money is by purchasing and upgrading Hacknet Nodes. Let's go to " + "the 'Hacknet Nodes' page through the main navigation menu now."); document.getElementById("hacknet-nodes-menu-link").setAttribute("class", "flashing-button"); - var hacknetNodesButton = Object(__WEBPACK_IMPORTED_MODULE_2__utils_HelperFunctions_js__["b" /* clearEventListeners */])("hacknet-nodes-menu-link"); - var next = Object(__WEBPACK_IMPORTED_MODULE_2__utils_HelperFunctions_js__["b" /* clearEventListeners */])("interactive-tutorial-next"); + var hacknetNodesButton = Object(__WEBPACK_IMPORTED_MODULE_3__utils_HelperFunctions_js__["b" /* clearEventListeners */])("hacknet-nodes-menu-link"); + var next = Object(__WEBPACK_IMPORTED_MODULE_3__utils_HelperFunctions_js__["b" /* clearEventListeners */])("interactive-tutorial-next"); next.style.display = "none"; hacknetNodesButton.addEventListener("click", function() { __WEBPACK_IMPORTED_MODULE_0__engine_js__["Engine"].loadHacknetNodesContent(); iTutorialNextStep(); - Object(__WEBPACK_IMPORTED_MODULE_2__utils_HelperFunctions_js__["b" /* clearEventListeners */])("hacknet-nodes-menu-link"); + Object(__WEBPACK_IMPORTED_MODULE_3__utils_HelperFunctions_js__["b" /* clearEventListeners */])("hacknet-nodes-menu-link"); return false; }); break; @@ -34989,11 +35041,11 @@ function iTutorialEvaluateStep() { "your newly-purchased Hacknet Node below.

" + "Let's go to the 'City' page through the main navigation menu."); document.getElementById("city-menu-link").setAttribute("class", "flashing-button"); - var worldButton = Object(__WEBPACK_IMPORTED_MODULE_2__utils_HelperFunctions_js__["b" /* clearEventListeners */])("city-menu-link"); + var worldButton = Object(__WEBPACK_IMPORTED_MODULE_3__utils_HelperFunctions_js__["b" /* clearEventListeners */])("city-menu-link"); worldButton.addEventListener("click", function() { __WEBPACK_IMPORTED_MODULE_0__engine_js__["Engine"].loadWorldContent(); iTutorialNextStep(); - Object(__WEBPACK_IMPORTED_MODULE_2__utils_HelperFunctions_js__["b" /* clearEventListeners */])("city-menu-link"); + Object(__WEBPACK_IMPORTED_MODULE_3__utils_HelperFunctions_js__["b" /* clearEventListeners */])("city-menu-link"); return false; }); break; @@ -35004,11 +35056,11 @@ function iTutorialEvaluateStep() { "you explore and discover!

" + "Lastly, click on the 'Tutorial' link in the main navigation menu."); document.getElementById("tutorial-menu-link").setAttribute("class", "flashing-button"); - var tutorialButton = Object(__WEBPACK_IMPORTED_MODULE_2__utils_HelperFunctions_js__["b" /* clearEventListeners */])("tutorial-menu-link"); + var tutorialButton = Object(__WEBPACK_IMPORTED_MODULE_3__utils_HelperFunctions_js__["b" /* clearEventListeners */])("tutorial-menu-link"); tutorialButton.addEventListener("click", function() { __WEBPACK_IMPORTED_MODULE_0__engine_js__["Engine"].loadTutorialContent(); iTutorialNextStep(); - Object(__WEBPACK_IMPORTED_MODULE_2__utils_HelperFunctions_js__["b" /* clearEventListeners */])("tutorial-menu-link"); + Object(__WEBPACK_IMPORTED_MODULE_3__utils_HelperFunctions_js__["b" /* clearEventListeners */])("tutorial-menu-link"); return false; }); break; @@ -35018,11 +35070,11 @@ function iTutorialEvaluateStep() { "content and mechanics. I know it's a lot, but I highly suggest you read " + "(or at least skim) through this before you start playing. That's the end of the tutorial. " + "Hope you enjoy the game!"); - var next = Object(__WEBPACK_IMPORTED_MODULE_2__utils_HelperFunctions_js__["b" /* clearEventListeners */])("interactive-tutorial-next"); + var next = Object(__WEBPACK_IMPORTED_MODULE_3__utils_HelperFunctions_js__["b" /* clearEventListeners */])("interactive-tutorial-next"); next.style.display = "inline-block"; next.innerHTML = "Finish Tutorial"; - var backButton = Object(__WEBPACK_IMPORTED_MODULE_2__utils_HelperFunctions_js__["b" /* clearEventListeners */])("interactive-tutorial-back"); + var backButton = Object(__WEBPACK_IMPORTED_MODULE_3__utils_HelperFunctions_js__["b" /* clearEventListeners */])("interactive-tutorial-back"); backButton.style.display = "none"; next.addEventListener("click", function() { @@ -35289,9 +35341,12 @@ function iTutorialEnd() { currITutorialStep = iTutorialSteps.End; iTutorialIsRunning = false; document.getElementById("interactive-tutorial-container").style.display = "none"; - Object(__WEBPACK_IMPORTED_MODULE_1__utils_DialogBox_js__["a" /* dialogBoxCreate */])("If you are new to the game, the following links may be useful for you!

" + + Object(__WEBPACK_IMPORTED_MODULE_2__utils_DialogBox_js__["a" /* dialogBoxCreate */])("If you are new to the game, the following links may be useful for you!

" + "Getting Started Guide" + - "Wiki"); + "Wiki

" + + "The Beginner's Guide to Hacking was added to your home computer! It contains stop tips/pointers for starting out with the game. " + + "To read it, go to Terminal and enter

cat hackers-starting-handbook.lit"); + __WEBPACK_IMPORTED_MODULE_1__Player_js__["a" /* Player */].getHomeComputer().messages.push("hackers-starting-handbook.lit"); } function iTutorialSetText(txt) { @@ -35344,7 +35399,7 @@ function setInMission(bool, mission) { //Keyboard shortcuts $(document).keydown(function(e) { - if (inMission && currMission && currMission.selectedNode != null) { + if (inMission && currMission && currMission.selectedNode.length != 0) { switch (e.keyCode) { case 65: //a for Attack currMission.actionButtons[0].click(); @@ -35508,7 +35563,7 @@ function HackingMission(rep, fac) { this.miscNodes = []; - this.selectedNode = null; //Which of the player's nodes is currently selected + this.selectedNode = []; //Which of the player's nodes are currently selected this.actionButtons = []; //DOM buttons for actions @@ -35552,15 +35607,15 @@ HackingMission.prototype.init = function() { //Randomly generate enemy nodes (CPU and Firewall) based on difficulty var numNodes = Math.min(8, Math.max(1, Math.round(this.difficulty / 4))); var numFirewalls = Math.min(20, - Object(__WEBPACK_IMPORTED_MODULE_5__utils_HelperFunctions_js__["h" /* getRandomInt */])(Math.round(this.difficulty/2), Math.round(this.difficulty/2) + 1)); + Object(__WEBPACK_IMPORTED_MODULE_5__utils_HelperFunctions_js__["h" /* getRandomInt */])(Math.round(this.difficulty/3), Math.round(this.difficulty/3) + 1)); var numDatabases = Math.min(10, Object(__WEBPACK_IMPORTED_MODULE_5__utils_HelperFunctions_js__["h" /* getRandomInt */])(1, Math.round(this.difficulty / 3) + 1)); var totalNodes = numNodes + numFirewalls + numDatabases; var xlimit = 7 - Math.floor(totalNodes / 8); var randMult = Object(__WEBPACK_IMPORTED_MODULE_5__utils_HelperFunctions_js__["a" /* addOffset */])(0.8 + (this.difficulty / 5), 10); for (var i = 0; i < numNodes; ++i) { var stats = { - atk: randMult * Object(__WEBPACK_IMPORTED_MODULE_5__utils_HelperFunctions_js__["h" /* getRandomInt */])(75, 85), - def: randMult * Object(__WEBPACK_IMPORTED_MODULE_5__utils_HelperFunctions_js__["h" /* getRandomInt */])(25, 35), + atk: randMult * Object(__WEBPACK_IMPORTED_MODULE_5__utils_HelperFunctions_js__["h" /* getRandomInt */])(80, 86), + def: randMult * Object(__WEBPACK_IMPORTED_MODULE_5__utils_HelperFunctions_js__["h" /* getRandomInt */])(5, 10), hp: randMult * Object(__WEBPACK_IMPORTED_MODULE_5__utils_HelperFunctions_js__["h" /* getRandomInt */])(210, 230) } this.enemyCores.push(new Node(NodeTypes.Core, stats)); @@ -35570,7 +35625,7 @@ HackingMission.prototype.init = function() { for (var i = 0; i < numFirewalls; ++i) { var stats = { atk: 0, - def: randMult * Object(__WEBPACK_IMPORTED_MODULE_5__utils_HelperFunctions_js__["h" /* getRandomInt */])(80, 90), + def: randMult * Object(__WEBPACK_IMPORTED_MODULE_5__utils_HelperFunctions_js__["h" /* getRandomInt */])(10, 20), hp: randMult * Object(__WEBPACK_IMPORTED_MODULE_5__utils_HelperFunctions_js__["h" /* getRandomInt */])(275, 300) } this.enemyNodes.push(new Node(NodeTypes.Firewall, stats)); @@ -35580,7 +35635,7 @@ HackingMission.prototype.init = function() { for (var i = 0; i < numDatabases; ++i) { var stats = { atk: 0, - def: randMult * Object(__WEBPACK_IMPORTED_MODULE_5__utils_HelperFunctions_js__["h" /* getRandomInt */])(70, 85), + def: randMult * Object(__WEBPACK_IMPORTED_MODULE_5__utils_HelperFunctions_js__["h" /* getRandomInt */])(30, 55), hp: randMult * Object(__WEBPACK_IMPORTED_MODULE_5__utils_HelperFunctions_js__["h" /* getRandomInt */])(210, 275) } var node = new Node(NodeTypes.Database, stats); @@ -35720,71 +35775,88 @@ HackingMission.prototype.createPageDom = function() { //Set Action Button event listeners this.actionButtons[0].addEventListener("click", ()=>{ - if (!(this.selectedNode instanceof Node)) { + if (!(this.selectedNode.length > 0)) { console.log("ERR: Pressing Action button without selected node"); return; } - if (this.selectedNode.type !== NodeTypes.Core) {return;} - this.setActionButtonsActive(this.selectedNode.type); + if (this.selectedNode[0].type !== NodeTypes.Core) {return;} + this.setActionButtonsActive(this.selectedNode[0].type); this.setActionButton(NodeActions.Attack, false); //Set attack button inactive - this.selectedNode.action = NodeActions.Attack; + this.selectedNode.forEach(function(node){ + node.action = NodeActions.Attack; + }); }); this.actionButtons[1].addEventListener("click", ()=>{ - if (!(this.selectedNode instanceof Node)) { + if (!(this.selectedNode.length > 0)) { console.log("ERR: Pressing Action button without selected node"); return; } - var nodeType = this.selectedNode.type; + var nodeType = this.selectedNode[0].type; //In a multiselect, every Node will have the same type if (nodeType !== NodeTypes.Core && nodeType !== NodeTypes.Transfer) {return;} this.setActionButtonsActive(nodeType); this.setActionButton(NodeActions.Scan, false); //Set scan button inactive - this.selectedNode.action = NodeActions.Scan; + this.selectedNode.forEach(function(node){ + node.action = NodeActions.Scan; + }); }); this.actionButtons[2].addEventListener("click", ()=>{ - if (!(this.selectedNode instanceof Node)) { + if (!(this.selectedNode.length > 0)) { console.log("ERR: Pressing Action button without selected node"); return; } - var nodeType = this.selectedNode.type; + var nodeType = this.selectedNode[0].type; //In a multiselect, every Node will have the same type if (nodeType !== NodeTypes.Core && nodeType !== NodeTypes.Transfer) {return;} this.setActionButtonsActive(nodeType); this.setActionButton(NodeActions.Weaken, false); //Set Weaken button inactive - this.selectedNode.action = NodeActions.Weaken; + this.selectedNode.forEach(function(node){ + node.action = NodeActions.Weaken; + }); }); this.actionButtons[3].addEventListener("click", ()=>{ - if (!(this.selectedNode instanceof Node)) { + if (!(this.selectedNode.length > 0)) { console.log("ERR: Pressing Action button without selected node"); return; } - this.setActionButtonsActive(this.selectedNode.type); + this.setActionButtonsActive(this.selectedNode[0].type); this.setActionButton(NodeActions.Fortify, false); //Set Fortify button inactive - this.selectedNode.action = NodeActions.Fortify; + this.selectedNode.forEach(function(node){ + node.action = NodeActions.Fortify; + }); }); this.actionButtons[4].addEventListener("click", ()=>{ - if (!(this.selectedNode instanceof Node)) { + if (!(this.selectedNode.length > 0)) { console.log("ERR: Pressing Action button without selected node"); return; } - var nodeType = this.selectedNode.type; + var nodeType = this.selectedNode[0].type; if (nodeType !== NodeTypes.Core && nodeType !== NodeTypes.Transfer) {return;} - this.setActionButtonsActive(this.selectedNode.type); + this.setActionButtonsActive(nodeType); this.setActionButton(NodeActions.Overflow, false); //Set Overflow button inactive - this.selectedNode.action = NodeActions.Overflow; + this.selectedNode.forEach(function(node){ + node.action = NodeActions.Overflow; + }); }); this.actionButtons[5].addEventListener("click", ()=>{ - if (!(this.selectedNode instanceof Node)) { + if (!(this.selectedNode.length > 0)) { console.log("ERR: Pressing Action button without selected node"); return; } - if (this.selectedNode.conn) { - var endpoints = this.selectedNode.conn.endpoints; - endpoints[0].detachFrom(endpoints[1]); - } + this.selectedNode.forEach(function(node){ + if (node.conn) { + var endpoints = node.conn.endpoints; + endpoints[0].detachFrom(endpoints[1]); + } + node.action = NodeActions.Fortify; + }); + // if (this.selectedNode.conn) { + // var endpoints = this.selectedNode.conn.endpoints; + // endpoints[0].detachFrom(endpoints[1]); + // } }) var timeDisplay = document.createElement("p"); @@ -35984,7 +36056,7 @@ HackingMission.prototype.createMap = function() { case 0: //Spam var stats = { atk: 0, - def: averageAttack * 1.15 + Object(__WEBPACK_IMPORTED_MODULE_5__utils_HelperFunctions_js__["h" /* getRandomInt */])(10, 50), + def: averageAttack * 1.1 + Object(__WEBPACK_IMPORTED_MODULE_5__utils_HelperFunctions_js__["h" /* getRandomInt */])(15, 45), hp: randMult * Object(__WEBPACK_IMPORTED_MODULE_5__utils_HelperFunctions_js__["h" /* getRandomInt */])(200, 225) } node = new Node(NodeTypes.Spam, stats); @@ -35992,7 +36064,7 @@ HackingMission.prototype.createMap = function() { case 1: //Transfer var stats = { atk: 0, - def: averageAttack * 1.15 + Object(__WEBPACK_IMPORTED_MODULE_5__utils_HelperFunctions_js__["h" /* getRandomInt */])(10, 50), + def: averageAttack * 1.1 + Object(__WEBPACK_IMPORTED_MODULE_5__utils_HelperFunctions_js__["h" /* getRandomInt */])(15, 45), hp: randMult * Object(__WEBPACK_IMPORTED_MODULE_5__utils_HelperFunctions_js__["h" /* getRandomInt */])(250, 275) } node = new Node(NodeTypes.Transfer, stats); @@ -36001,7 +36073,7 @@ HackingMission.prototype.createMap = function() { default: var stats = { atk: 0, - def: averageAttack * 1.15 + Object(__WEBPACK_IMPORTED_MODULE_5__utils_HelperFunctions_js__["h" /* getRandomInt */])(25, 75), + def: averageAttack * 1.1 + Object(__WEBPACK_IMPORTED_MODULE_5__utils_HelperFunctions_js__["h" /* getRandomInt */])(30, 70), hp: randMult * Object(__WEBPACK_IMPORTED_MODULE_5__utils_HelperFunctions_js__["h" /* getRandomInt */])(300, 320) } node = new Node(NodeTypes.Shield, stats); @@ -36165,12 +36237,40 @@ function selectNode(hackMissionInst, el) { if (nodeObj == null) {console.log("Error getting Node object");} if (!nodeObj.plyrCtrl) {return;} - if (hackMissionInst.selectedNode instanceof Node) { - hackMissionInst.selectedNode.deselect(hackMissionInst.actionButtons); - hackMissionInst.selectedNode = null; - } + clearAllSelectedNodes(hackMissionInst); nodeObj.select(hackMissionInst.actionButtons); - hackMissionInst.selectedNode = nodeObj; + hackMissionInst.selectedNode.push(nodeObj); +} + +function multiselectNode(hackMissionInst, el) { + var nodeObj = hackMissionInst.getNodeFromElement(el); + if (nodeObj == null) {console.log("ERROR: Getting Node Object in multiselectNode()");} + if (!nodeObj.plyrCtrl) {return;} + + clearAllSelectedNodes(hackMissionInst); + var type = nodeObj.type; + if (type === NodeTypes.Core) { + hackMissionInst.playerCores.forEach(function(node) { + node.select(hackMissionInst.actionButtons); + hackMissionInst.selectedNode.push(node); + }); + } else { + hackMissionInst.playerNodes.forEach(function(node) { + if (node.type === type) { + node.select(hackMissionInst.actionButtons); + hackMissionInst.selectedNode.push(node); + } + }); + } +} + +function clearAllSelectedNodes(hackMissionInst) { + if (hackMissionInst.selectedNode.length > 0) { + hackMissionInst.selectedNode.forEach(function(node){ + node.deselect(hackMissionInst.actionButtons); + }); + hackMissionInst.selectedNode.length = 0; + } } //Configures a DOM element representing a player-owned node to @@ -36187,6 +36287,12 @@ HackingMission.prototype.configurePlayerNodeElement = function(el) { } el.addEventListener("click", selectNodeWrapper); + function multiselectNodeWrapper() { + multiselectNode(self, el); + } + el.addEventListener("dblclick", multiselectNodeWrapper); + + if (el.firstChild) { el.firstChild.addEventListener("click", selectNodeWrapper); } @@ -36197,8 +36303,12 @@ HackingMission.prototype.configurePlayerNodeElement = function(el) { HackingMission.prototype.configureEnemyNodeElement = function(el) { //Deselect node if it was the selected node var nodeObj = this.getNodeFromElement(el); - if (this.selectedNode == nodeObj) { - nodeObj.deselect(this.actionButtons); + for (var i = 0; i < this.selectedNode.length; ++i) { + if (this.selectedNode[i] == nodeObj) { + nodeObj.deselect(this.actionButtons); + this.selectedNode.splice(i, 1); + break; + } } } @@ -36563,6 +36673,7 @@ HackingMission.prototype.processNode = function(nodeObj, numCycles=1) { swapNodes(this.enemyNodes, this.playerNodes, targetNode); } else { swapNodes(this.playerNodes, this.enemyNodes, targetNode); + this.configureEnemyNodeElement(targetNode.el); } break; case NodeTypes.Database: @@ -36604,6 +36715,7 @@ HackingMission.prototype.processNode = function(nodeObj, numCycles=1) { this.configurePlayerNodeElement(targetNode.el); } else { swapNodes(isMiscNode ? this.miscNodes : this.playerNodes, this.enemyNodes, targetNode); + this.configureEnemyNodeElement(targetNode.el); } break; } @@ -36742,7 +36854,7 @@ HackingMission.prototype.calculateWeakenEffect = function(atk, def, hacking=0) { } HackingMission.prototype.calculateFortifyEffect = function(hacking=0) { - return 0.6 * hacking / hackEffWeightSelf; + return 0.9 * hacking / hackEffWeightSelf; } HackingMission.prototype.calculateOverflowEffect = function(hacking=0) { @@ -38609,7 +38721,6 @@ Product.prototype.finishProduct = function(employeeProd, industry) { var advMult = 1 + (Math.pow(this.advCost, 0.1) / 100); console.log("advMult: " + advMult); this.mku = 100 / (advMult * this.qlt * (busRatio + mgmtRatio)); - console.log("product mku: " + this.mku); this.dmd = industry.awareness === 0 ? 100 : Math.min(100, advMult * (100 * (industry.popularity / industry.awareness))); this.cmp = Object(__WEBPACK_IMPORTED_MODULE_4__utils_HelperFunctions_js__["h" /* getRandomInt */])(0, 70); @@ -39105,7 +39216,7 @@ Industry.prototype.updateWarehouseSizeUsed = function(warehouse) { } } -Industry.prototype.process = function(marketCycles=1, state) { +Industry.prototype.process = function(marketCycles=1, state, company) { this.state = state; //At the start of a cycle, store and reset revenue/expenses @@ -39133,7 +39244,7 @@ Industry.prototype.process = function(marketCycles=1, state) { } //Process production, purchase, and import/export of materials - var res = this.processMaterials(marketCycles); + var res = this.processMaterials(marketCycles, company); this.thisCycleRevenue = this.thisCycleRevenue.plus(res[0]); this.thisCycleExpenses = this.thisCycleExpenses.plus(res[1]); @@ -39193,7 +39304,7 @@ Industry.prototype.processProductMarket = function(marketCycles=1) { } //Process production, purchase, and import/export of materials -Industry.prototype.processMaterials = function(marketCycles=1) { +Industry.prototype.processMaterials = function(marketCycles=1, company) { var revenue = 0, expenses = 0; for (var i = 0; i < Cities.length; ++i) { var city = Cities[i], office = this.offices[city]; @@ -39370,9 +39481,39 @@ Industry.prototype.processMaterials = function(marketCycles=1) { break; /* TODO Process Export of materials */ + case "EXPORT": + for (var matName in warehouse.materials) { + if (warehouse.materials.hasOwnProperty(matName)) { + var mat = warehouse.materials[matName]; + for (var expI = 0; expI < mat.exp.length; ++expI) { + var exp = mat.exp[expI]; + var amt = exp.amt * SecsPerMarketCycle * marketCycles; + if (mat.qty <= amt) { + amt = mat.qty; + } + if (amt === 0) { + break; //None left + } + for (var foo = 0; foo < company.divisions.length; ++foo) { + if (company.divisions[foo].name === exp.ind) { + var expIndustry = company.divisions[foo]; + var expWarehouse = expIndustry.warehouses[exp.city]; + if (!(expWarehouse instanceof Warehouse)) { + console.log("ERROR: Invalid export!"); + break; + } + expWarehouse.materials[mat.name].qty += amt; + mat.qty -= amt; + break; + } + } + } + } + } + + break; case "START": - case "EXPORT": break; default: console.log("ERROR: Invalid state: " + this.state); @@ -39514,7 +39655,6 @@ Industry.prototype.processProduct = function(marketCycles=1, product) { //Since its a product, its production cost is increased for labor product.pCost *= 3; - console.log("Product pCost:" + product.pCost); var markup = 1, markupLimit = product.rat / product.mku; if (product.sCost > product.pCost) { @@ -40083,21 +40223,31 @@ Warehouse.prototype.createMaterialUI = function(mat, matName, parentRefs) { totalExport += mat.exp[i].amt; } var totalGain = mat.buy + mat.prd + mat.imp - mat.sll - totalExport; - div.appendChild(Object(__WEBPACK_IMPORTED_MODULE_4__utils_HelperFunctions_js__["f" /* createElement */])("p", { - innerHTML: "

" + mat.name + ": " + Object(__WEBPACK_IMPORTED_MODULE_7__utils_StringHelperFunctions_js__["c" /* formatNumber */])(mat.qty, 3) + + + //If Market Research upgrades are unlocked, add competition and demand info + var cmpAndDmdText = ""; + if (company.unlockUpgrades[2] === 1) { + cmpAndDmdText += "
Competition: " + Object(__WEBPACK_IMPORTED_MODULE_7__utils_StringHelperFunctions_js__["c" /* formatNumber */])(mat.cmp, 3); + } + if (company.unlockUpgrades[3] === 1) { + cmpAndDmdText += "
Demand: " + Object(__WEBPACK_IMPORTED_MODULE_7__utils_StringHelperFunctions_js__["c" /* formatNumber */])(mat.dmd, 3); + } + var innerTxt = "

" + mat.name + ": " + Object(__WEBPACK_IMPORTED_MODULE_7__utils_StringHelperFunctions_js__["c" /* formatNumber */])(mat.qty, 3) + "(" + Object(__WEBPACK_IMPORTED_MODULE_7__utils_StringHelperFunctions_js__["c" /* formatNumber */])(totalGain, 3) + "/s)" + "Buy: " + Object(__WEBPACK_IMPORTED_MODULE_7__utils_StringHelperFunctions_js__["c" /* formatNumber */])(mat.buy, 3) + "/s
Prod: " + Object(__WEBPACK_IMPORTED_MODULE_7__utils_StringHelperFunctions_js__["c" /* formatNumber */])(mat.prd, 3) + "/s
Sell: " + Object(__WEBPACK_IMPORTED_MODULE_7__utils_StringHelperFunctions_js__["c" /* formatNumber */])(mat.sll, 3) + "/s
Export: " + Object(__WEBPACK_IMPORTED_MODULE_7__utils_StringHelperFunctions_js__["c" /* formatNumber */])(totalExport, 3) + "/s
Import: " + - Object(__WEBPACK_IMPORTED_MODULE_7__utils_StringHelperFunctions_js__["c" /* formatNumber */])(mat.imp, 3) + "/s


" + + Object(__WEBPACK_IMPORTED_MODULE_7__utils_StringHelperFunctions_js__["c" /* formatNumber */])(mat.imp, 3) + "/s" + cmpAndDmdText + "


" + "

MP: $" + Object(__WEBPACK_IMPORTED_MODULE_7__utils_StringHelperFunctions_js__["c" /* formatNumber */])(mat.bCost, 2) + "Market Price: The price you would pay if " + "you were to buy this material on the market


" + "

Quality: " + Object(__WEBPACK_IMPORTED_MODULE_7__utils_StringHelperFunctions_js__["c" /* formatNumber */])(mat.qlt, 2) + "The quality of your material. Higher quality " + - "will lead to more sales

", - id: "cmpy-mgmt-warehouse-" + matName + "-text", - display:"inline-block", + "will lead to more sales

"; + + div.appendChild(Object(__WEBPACK_IMPORTED_MODULE_4__utils_HelperFunctions_js__["f" /* createElement */])("p", { + innerHTML: innerTxt, + id: "cmpy-mgmt-warehouse-" + matName + "-text", display:"inline-block", })); var buttonPanel = Object(__WEBPACK_IMPORTED_MODULE_4__utils_HelperFunctions_js__["f" /* createElement */])("div", { @@ -40142,9 +40292,8 @@ Warehouse.prototype.createMaterialUI = function(mat, matName, parentRefs) { })); //Button to manage exports - buttonPanel.appendChild(Object(__WEBPACK_IMPORTED_MODULE_4__utils_HelperFunctions_js__["f" /* createElement */])("a", { - innerText:"Export", display:"inline-block", class:"a-link-button", - clickListener:()=>{ + if (company.unlockUpgrades[0] === 1) { //Export unlock upgrade + function createExportPopup() { var popupId = "cmpy-mgmt-export-popup"; var exportTxt = Object(__WEBPACK_IMPORTED_MODULE_4__utils_HelperFunctions_js__["f" /* createElement */])("p", { innerText:"Select the industry and city to export this material to, as well as " + @@ -40179,7 +40328,6 @@ Warehouse.prototype.createMaterialUI = function(mat, matName, parentRefs) { } //End for var currIndustry = industrySelector.options[industrySelector.selectedIndex].value; - console.log(currIndustry); for (var i = 0; i < company.divisions.length; ++i) { if (company.divisions[i].name == currIndustry) { for (var cityName in company.divisions[i].warehouses) { @@ -40247,24 +40395,25 @@ Warehouse.prototype.createMaterialUI = function(mat, matName, parentRefs) { for (var i = 0; i < mat.exp.length; ++i) { (function(i, mat, currExports){ currExports.push(Object(__WEBPACK_IMPORTED_MODULE_4__utils_HelperFunctions_js__["f" /* createElement */])("div", { + class:"cmpy-mgmt-existing-export", innerHTML: "Industry: " + mat.exp[i].ind + "
" + "City: " + mat.exp[i].city + "
" + "Amount/s: " + mat.exp[i].amt, clickListener:()=>{ - mat.exp[i].splice(i, 1); - //Go to the target city and decrease the mat.imp attribute for the corresponding material - for (var i = 0; i < company.divisions.length; ++i) { - if (company.divisions[i].name === mat.exp[i].ind) { - var warehouse = company.divisions[i].warehouses[mat.exp[i].city]; + for (var j = 0; j < company.divisions.length; ++j) { + if (company.divisions[j].name === mat.exp[i].ind) { + var warehouse = company.divisions[j].warehouses[mat.exp[i].city]; if (warehouse instanceof Warehouse) { warehouse.materials[matName].imp -= mat.exp[i].amt; - return false; } else { console.log("ERROR: Target city for export does not have warehouse in specified city"); } } } + mat.exp.splice(i, 1); //Remove export object + Object(__WEBPACK_IMPORTED_MODULE_4__utils_HelperFunctions_js__["l" /* removeElementById */])(popupId); + createExportPopup(); } })); })(i, mat, currExports); @@ -40272,8 +40421,11 @@ Warehouse.prototype.createMaterialUI = function(mat, matName, parentRefs) { Object(__WEBPACK_IMPORTED_MODULE_4__utils_HelperFunctions_js__["g" /* createPopup */])(popupId, [exportTxt, industrySelector, citySelector, exportAmount, exportBtn, cancelBtn, currExportsText].concat(currExports)); } - })); - + buttonPanel.appendChild(Object(__WEBPACK_IMPORTED_MODULE_4__utils_HelperFunctions_js__["f" /* createElement */])("a", { + innerText:"Export", display:"inline-block", class:"a-link-button", + clickListener:()=>{createExportPopup();} + })); + } buttonPanel.appendChild(Object(__WEBPACK_IMPORTED_MODULE_4__utils_HelperFunctions_js__["f" /* createElement */])("br", {})); // Force line break @@ -40575,6 +40727,81 @@ Warehouse.fromJSON = function(value) { __WEBPACK_IMPORTED_MODULE_5__utils_JSONReviver_js__["c" /* Reviver */].constructors.Warehouse = Warehouse; +//Corporation Unlock Upgrades +//Upgrades for entire corporation, unlocks features, either you have it or you dont +//The structure is [index in Corporation feature upgrades array, price ] +var CorporationUnlockUpgrades = { + //Lets you export goods + "0": [0, 20e9, "Export", + "Develop infrastructure to export your materials to your other facilities. " + + "This allows you to move materials around between different divisions and cities."], + + //Lets you buy exactly however many required materials you need for production + "1": [1, 999999e9, "Smart Supply", "NOT YET IMPLEMENTED!!!!!! - Use advanced AI to anticipate your supply needs. " + + "This allows you to purchase exactly however many materials you need for production."], + + //Displays each material/product's demand + "2": [2, 25e9, "Market Research - Demand", + "Mine and analyze market data to determine the demand of all resources. " + + "The demand attribute, which affects sales, will be displayed for every material and product."], + + //Display's each material/product's competition + "3": [3, 25e9, "Market Data - Competition", + "Mine and analyze market data to determine how much competition there is on the market " + + "for all resources. The competition attribute, which affects sales, will be displayed for " + + "for every material and product."], +} + +//Corporation Upgrades +//Upgrades for entire corporation, levelable upgrades +//The structure is [index in Corporation upgrades array, base price, price mult, benefit mult (additive), +// name, desc] +var CorporationUpgrades = { + //Smart factories, increases production + "0": [0, 10e9, 1.07, 0.02, + "Smart Factories", "Advanced AI automatically optimizes the operation and productivity " + + "of factories. Each level of this upgrade increases your global production by 2% (additive)."], + + //Smart warehouses, increases storage size + "1": [1, 20e9, 1.07, .1, + "Smart Storage", "Advanced AI automatically optimizes your warehouse storage methods. " + + "Each level of this upgrade increases your global warehouse storage size by 10% (additive)."], + + //Advertise through dreams, passive popularity/ awareness gain + "2": [2, 100e9, 1.08, .001, + "DreamSense", "Use DreamSense LCC Technologies to advertise your corporation " + + "to consumers through their dreams. Each level of this upgrade provides a passive " + + "increase in awareness of your company by 0.001 / second."], + + //Makes advertising more effective + "3": [3, 5e9, 1.11, 0.1, + "Wilson Analytics", "Purchase data and analysis from Wilson, a marketing research " + + "firm. Each level of this upgrades increases the effectiveness of your " + + "advertising by 10% (additive)."], + + //Augmentation for employees, increases cre + "4": [4, 10e9, 1.05, 0.1, + "Nuoptimal Nootropic Injector Implants", "Purchase the Nuoptimal Nootropic " + + "Injector augmentation for your employees. Each level of this upgrade " + + "globally increases the creativity of your employees by 10% (additive)."], + + //Augmentation for employees, increases cha + "5": [5, 10e9, 1.05, 0.1, + "Speech Processor Implants", "Purchase the Speech Processor augmentation for your employees. " + + "Each level of this upgrade globally increases the charisma of your employees by 10% (additive)."], + + //Augmentation for employees, increases int + "6": [6, 10e9, 1.05, 0.1, + "Neural Acelerators", "Purchase the Neural Accelerator augmentation for your employees. " + + "Each level of this upgrade globally increases the intelligence of your employees " + + "by 10% (additive)."], + + //Augmentation for employees, increases eff + "7": [7, 10e9, 1.05, 0.1, + "FocusWires", "Purchase the FocusWire augmentation for your employees. Each level " + + "of this upgrade globally increases the efficiency of your employees by 10% (additive)."], +} + function Corporation(params={}) { this.name = params.name ? params.name : "The Corporation"; @@ -40592,6 +40819,13 @@ function Corporation(params={}) { this.sharePrice = 0; this.storedCycles = 0; + var numUnlockUpgrades = Object.keys(CorporationUnlockUpgrades).length, + numUpgrades = Object.keys(CorporationUpgrades).length; + + this.unlockUpgrades = Array(numUnlockUpgrades).fill(0); + this.upgrades = Array(numUpgrades).fill(0); + this.upgradeMultipliers = Array(numUpgrades).fill(1); + this.state = new CorporationState(); } @@ -40600,12 +40834,13 @@ Corporation.prototype.getState = function() { } Corporation.prototype.process = function(numCycles=1) { + var corp = this; this.storedCycles += numCycles; if (this.storedCycles >= CyclesPerIndustryStateCycle) { var state = this.getState(), marketCycles = 1; this.storedCycles -= (marketCycles * CyclesPerIndustryStateCycle); this.divisions.forEach(function(ind) { - ind.process(marketCycles, state); + ind.process(marketCycles, state, corp); }); //At the start of a new cycle, calculate profits from previous cycle @@ -40626,13 +40861,13 @@ Corporation.prototype.process = function(numCycles=1) { } Corporation.prototype.determineValuation = function() { - var val, profit = (this.revenue - this.expenses); + var val, profit = (this.revenue.minus(this.expenses)).toNumber(); if (this.public) { - val = 50e9 + this.funds + (profit * Object(__WEBPACK_IMPORTED_MODULE_4__utils_HelperFunctions_js__["h" /* getRandomInt */])(7000, 8500)); + val = 25e9 + this.funds.toNumber() + (profit * Object(__WEBPACK_IMPORTED_MODULE_4__utils_HelperFunctions_js__["h" /* getRandomInt */])(7000, 8500)); val *= (Math.pow(1.1, this.divisions.length)); val = Math.max(val, 0); } else { - val = 10e9 + Math.max(this.funds, 0); //Base valuation + val = 10e9 + Math.max(this.funds.toNumber(), 0); //Base valuation if (profit > 0) { val += (profit * Object(__WEBPACK_IMPORTED_MODULE_4__utils_HelperFunctions_js__["h" /* getRandomInt */])(12e3, 14e3)); val *= (Math.pow(1.1, this.divisions.length)); @@ -40740,12 +40975,46 @@ Corporation.prototype.updateSharePrice = function() { } else { this.sharePrice *= (1 - (Math.random() * 0.01)); } + if (this.sharePrice <= 0.01) {this.sharePrice = 0.01;} +} + +//One time upgrades that unlock new features +Corporation.prototype.unlock = function(upgrade) { + var upgN = upgrade[0], price = upgrade[1]; + while (this.unlockUpgrades.length <= upgN) { + this.unlockUpgrades.push(0); + } + if (this.funds.lt(price)) { + Object(__WEBPACK_IMPORTED_MODULE_3__utils_DialogBox_js__["a" /* dialogBoxCreate */])("You don't have enough funds to unlock this!"); + return; + } + this.unlockUpgrades[upgN] = 1; + this.funds = this.funds.minus(price); +} + +//Levelable upgrades +Corporation.prototype.upgrade = function(upgrade) { + var upgN = upgrade[0], basePrice = upgrade[1], priceMult = upgrade[2], + upgradeAmt = upgrade[3]; //Amount by which the upgrade multiplier gets increased (additive) + while (this.upgrades.length <= upgN) {this.upgrades.push(0);} + while (this.upgradeMultipliers.length <= upgN) {this.upgradeMultipliers.push(1);} + var totalCost = basePrice * Math.pow(this.upgrades[upgN], priceMult); + if (this.funds.lt(totalCost)) { + Object(__WEBPACK_IMPORTED_MODULE_3__utils_DialogBox_js__["a" /* dialogBoxCreate */])("You don't have enough funds to purchase this!"); + return; + } + ++this.upgrades[upgN]; + this.funds = this.funds.minus(totalCost); + + //Increase upgrade multiplier + this.upgradeMultipliers[upgN] = 1 + (this.upgrades[upgN] * upgradeAmt); } //Keep 'global' variables for DOM elements so we don't have to search //through the DOM tree repeatedly when updating UI var companyManagementDiv, companyManagementHeaderTabs, companyManagementPanel, currentCityUi, + corporationUnlockUpgrades, corporationUpgrades, industryOverviewPanel, industryOverviewText, industryEmployeePanel, industryEmployeeText, industryEmployeeHireButton, industryEmployeeList, industryOfficeUpgradeSizeButton, @@ -41013,7 +41282,7 @@ Corporation.prototype.displayCorporationOverviewContent = function() { } else { this.numShares -= shares; this.issuedShares += shares; - //TODO ADD TO PLAYER MONEY + Player.gainMoney(shares * this.sharePrice); Object(__WEBPACK_IMPORTED_MODULE_4__utils_HelperFunctions_js__["l" /* removeElementById */])(popupId); return false; } @@ -41147,7 +41416,81 @@ Corporation.prototype.displayCorporationOverviewContent = function() { companyManagementPanel.appendChild(goPublic); } + //Update overview text this.updateCorporationOverviewContent(); + + //Don't show upgrades if player hasn't opened any divisions + if (this.divisions.length <= 0) {return; } + //Corporation Upgrades + var upgradeContainer = Object(__WEBPACK_IMPORTED_MODULE_4__utils_HelperFunctions_js__["f" /* createElement */])("div", { + class:"cmpy-mgmt-upgrade-container", + }); + upgradeContainer.appendChild(Object(__WEBPACK_IMPORTED_MODULE_4__utils_HelperFunctions_js__["f" /* createElement */])("h1", { + innerText:"Upgrades", margin:"6px", padding:"6px", + })); + + //Unlock upgrades + var corp = this; + if (this.unlockUpgrades == null || this.upgrades == null) { //Backwards compatibility + var numUnlockUpgrades = Object.keys(CorporationUnlockUpgrades).length, + numUpgrades = Object.keys(CorporationUpgrades).length; + + this.unlockUpgrades = Array(numUnlockUpgrades).fill(0); + this.upgrades = Array(numUpgrades).fill(0); + } + for (var i = 0; i < this.unlockUpgrades.length; ++i) { + (function(i, corp) { + if (corp.unlockUpgrades[i] === 0) { + var upgrade = CorporationUnlockUpgrades[i.toString()]; + if (upgrade == null) { + console.log("ERROR: Could not find upgrade index " + i); + return; + } + + upgradeContainer.appendChild(Object(__WEBPACK_IMPORTED_MODULE_4__utils_HelperFunctions_js__["f" /* createElement */])("div", { + class:"cmpy-mgmt-upgrade-div", + innerHTML:upgrade[2] + " - " + __WEBPACK_IMPORTED_MODULE_6__utils_numeral_min_js___default()(upgrade[1]).format("$0.000a") + "

" + upgrade[3], + clickListener:()=>{ + if (corp.funds.lt(upgrade[1])) { + Object(__WEBPACK_IMPORTED_MODULE_3__utils_DialogBox_js__["a" /* dialogBoxCreate */])("Insufficient funds"); + } else { + corp.unlock(upgrade); + corp.displayCorporationOverviewContent(); + } + } + })); + } + })(i, corp); + } + + //Levelable upgrades + /* + for (var i = 0; i < this.upgrades.length; ++i) { + (function(i, corp) { + var upgrade = CorporationUpgrades[i.toString()]; + if (upgrade == null) { + console.log("ERROR: Could not find levelable upgrade index " + i); + return; + } + + var baseCost = upgrade[1], priceMult = upgrade[2]; + var cost = baseCost * Math.pow(corp.upgrades[i], priceMult); + upgradeContainer.appendChild(createElement("div", { + class:"cmpy-mgmt-upgrade-div", + innerHTML:upgrade[4] + " - " + numeral(cost).format("$0.000a") + "

" + upgrade[5], + clickListener:()=>{ + if (corp.funds.lt(cost)) { + dialogBoxCreate("Insufficient funds"); + } else { + corp.upgrade(upgrade); + corp.displayCorporationOverviewContent(); + } + } + })); + })(i, corp); + }*/ + + companyManagementPanel.appendChild(upgradeContainer); } Corporation.prototype.updateCorporationOverviewContent = function() { @@ -41686,6 +42029,9 @@ Corporation.prototype.clearUI = function() { companyManagementPanel = null; currentCityUi = null; + corporationUnlockUpgrades = null; + corporationUpgrades = null; + industryOverviewPanel = null; industryOverviewText = null; @@ -46311,8 +46657,8 @@ function Literature(title, filename, txt) { function showLiterature(fn) { var litObj = Literatures[fn]; if (litObj == null) {return;} - var txt = litObj.title + "

" + - "" + litObj.txt + ""; + var txt = "" + litObj.title + "

" + + litObj.txt; Object(__WEBPACK_IMPORTED_MODULE_0__utils_DialogBox_js__["a" /* dialogBoxCreate */])(txt); } @@ -46320,6 +46666,24 @@ let Literatures = {} function initLiterature() { var title, fn, txt; + title = "The Beginner's Guide to Hacking"; + fn = "hackers-starting-handbook.lit"; + txt = "When starting out, hacking is the most profitable way to earn money and progress. This " + + "is a brief collection of tips/pointers on how to make the most out of your hacking scripts.

" + + "-hack() and grow() both work by percentages. hack() steals a certain percentage of the " + + "money on a server, and grow() increases the amount of money on a server by some percentage (multiplicatively)

" + + "-Because hack() and grow() work by percentages, they are more effective if the target server has a high amount of money. " + + "Therefore, you should try to increase the amount of money on a server (using grow()) to a certain amount before hacking it. Two " + + "import Netscript functions for this are getServerMoneyAvailable() and getServerMaxMoney()

" + + "-Keep security level low. Security level affects everything when hacking. Two important Netscript functions " + + "for this are getServerSecurityLevel() and getServerMinSecurityLevel()

" + + "-Purchase additional servers by visiting 'Alpha Enterprises' in the city. They are relatively cheap " + + "and give you valuable RAM to run more scripts early in the game

" + + "-Prioritize upgrading the RAM on your home computer. This can also be done at 'Alpha Enterprises'

" + + "-Many low level servers have free RAM. You can use this RAM to run your scripts. Use the scp Terminal or " + + "Netscript command to copy your scripts onto these servers and then run them."; + Literatures[fn] = new Literature(title, fn, txt); + title = "A Green Tomorrow"; fn = "A-Green-Tomorrow.lit"; txt = "Starting a few decades ago, there was a massive global movement towards the generation of renewable energy in an effort to " + @@ -71621,7 +71985,8 @@ var NetscriptHighlightRules = function(options) { "decodeURI|decodeURIComponent|encodeURI|encodeURIComponent|eval|isFinite|" + // Non-constructor functions "isNaN|parseFloat|parseInt|" + "hack|sleep|grow|weaken|print|tprint|scan|nuke|brutessh|ftpcrack|" + //Netscript functions - "relaysmtp|httpworm|sqlinject|run|exec|kill|killall|scp|ls|hasRootAccess|" + + "relaysmtp|httpworm|sqlinject|run|exec|kill|killall|exit|" + + "scp|ls|hasRootAccess|" + "getIp|getHackingMultipliers|getBitNodeMultipliers|getStats|isBusy|" + "getHostname|getHackingLevel|getServerMoneyAvailable|getServerMaxMoney|" + "getServerGrowth|getServerSecurityLevel|getServerBaseSecurityLevel|" + @@ -71629,7 +71994,8 @@ var NetscriptHighlightRules = function(options) { "getServerRequiredHackingLevel|getServerNumPortsRequired|getServerRam|" + "serverExists|fileExists|isRunning|getNextHacknetNodeCost|" + "purchaseHacknetNode|deleteServer|getPurchasedServers|" + - "purchaseServer|round|write|read|scriptRunning|scriptKill|getScriptRam|" + + "purchaseServer|round|write|read|clear|" + + "scriptRunning|scriptKill|getScriptRam|" + "getHackTime|getGrowTime|getWeakenTime|getScriptIncome|getScriptExpGain|" + "getTimeSinceLastAug|" + "universityCourse|" + @@ -71641,7 +72007,8 @@ var NetscriptHighlightRules = function(options) { "getAugmentationCost|purchaseAugmentation|" + "installAugmentations|hacknetnodes|upgradeLevel|upgradeRam|upgradeCore|" + "getLevelUpgradeCost|getRamUpgradeCost|getCoreUpgradeCost|" + - "getStockPrice|getStockPosition|buyStock|sellStock|" + + "getStockPrice|getStockPosition|buyStock|sellStock|shortStock|sellShort|" + + "placeOrder|cancelOrder|" + "JSON|Math|" + // Other "this|arguments|prototype|window|document" , // Pseudo "keyword": diff --git a/index.html b/index.html index 6c85667e2..ae292bcc4 100644 --- a/index.html +++ b/index.html @@ -905,7 +905,7 @@ The minimum number of milliseconds it takes to execute an operation in Netscript. Setting this too low can result in poor performance if you have many scripts running. - The default value is 100ms. + The default value is 50ms. diff --git a/src/CompanyManagement.js b/src/CompanyManagement.js index a630f7afc..463466906 100644 --- a/src/CompanyManagement.js +++ b/src/CompanyManagement.js @@ -352,7 +352,6 @@ Product.prototype.finishProduct = function(employeeProd, industry) { var advMult = 1 + (Math.pow(this.advCost, 0.1) / 100); console.log("advMult: " + advMult); this.mku = 100 / (advMult * this.qlt * (busRatio + mgmtRatio)); - console.log("product mku: " + this.mku); this.dmd = industry.awareness === 0 ? 100 : Math.min(100, advMult * (100 * (industry.popularity / industry.awareness))); this.cmp = getRandomInt(0, 70); @@ -848,7 +847,7 @@ Industry.prototype.updateWarehouseSizeUsed = function(warehouse) { } } -Industry.prototype.process = function(marketCycles=1, state) { +Industry.prototype.process = function(marketCycles=1, state, company) { this.state = state; //At the start of a cycle, store and reset revenue/expenses @@ -876,7 +875,7 @@ Industry.prototype.process = function(marketCycles=1, state) { } //Process production, purchase, and import/export of materials - var res = this.processMaterials(marketCycles); + var res = this.processMaterials(marketCycles, company); this.thisCycleRevenue = this.thisCycleRevenue.plus(res[0]); this.thisCycleExpenses = this.thisCycleExpenses.plus(res[1]); @@ -936,7 +935,7 @@ Industry.prototype.processProductMarket = function(marketCycles=1) { } //Process production, purchase, and import/export of materials -Industry.prototype.processMaterials = function(marketCycles=1) { +Industry.prototype.processMaterials = function(marketCycles=1, company) { var revenue = 0, expenses = 0; for (var i = 0; i < Cities.length; ++i) { var city = Cities[i], office = this.offices[city]; @@ -1113,9 +1112,39 @@ Industry.prototype.processMaterials = function(marketCycles=1) { break; /* TODO Process Export of materials */ + case "EXPORT": + for (var matName in warehouse.materials) { + if (warehouse.materials.hasOwnProperty(matName)) { + var mat = warehouse.materials[matName]; + for (var expI = 0; expI < mat.exp.length; ++expI) { + var exp = mat.exp[expI]; + var amt = exp.amt * SecsPerMarketCycle * marketCycles; + if (mat.qty <= amt) { + amt = mat.qty; + } + if (amt === 0) { + break; //None left + } + for (var foo = 0; foo < company.divisions.length; ++foo) { + if (company.divisions[foo].name === exp.ind) { + var expIndustry = company.divisions[foo]; + var expWarehouse = expIndustry.warehouses[exp.city]; + if (!(expWarehouse instanceof Warehouse)) { + console.log("ERROR: Invalid export!"); + break; + } + expWarehouse.materials[mat.name].qty += amt; + mat.qty -= amt; + break; + } + } + } + } + } + + break; case "START": - case "EXPORT": break; default: console.log("ERROR: Invalid state: " + this.state); @@ -1257,7 +1286,6 @@ Industry.prototype.processProduct = function(marketCycles=1, product) { //Since its a product, its production cost is increased for labor product.pCost *= 3; - console.log("Product pCost:" + product.pCost); var markup = 1, markupLimit = product.rat / product.mku; if (product.sCost > product.pCost) { @@ -1826,21 +1854,31 @@ Warehouse.prototype.createMaterialUI = function(mat, matName, parentRefs) { totalExport += mat.exp[i].amt; } var totalGain = mat.buy + mat.prd + mat.imp - mat.sll - totalExport; - div.appendChild(createElement("p", { - innerHTML: "

" + mat.name + ": " + formatNumber(mat.qty, 3) + + + //If Market Research upgrades are unlocked, add competition and demand info + var cmpAndDmdText = ""; + if (company.unlockUpgrades[2] === 1) { + cmpAndDmdText += "
Competition: " + formatNumber(mat.cmp, 3); + } + if (company.unlockUpgrades[3] === 1) { + cmpAndDmdText += "
Demand: " + formatNumber(mat.dmd, 3); + } + var innerTxt = "

" + mat.name + ": " + formatNumber(mat.qty, 3) + "(" + formatNumber(totalGain, 3) + "/s)" + "Buy: " + formatNumber(mat.buy, 3) + "/s
Prod: " + formatNumber(mat.prd, 3) + "/s
Sell: " + formatNumber(mat.sll, 3) + "/s
Export: " + formatNumber(totalExport, 3) + "/s
Import: " + - formatNumber(mat.imp, 3) + "/s


" + + formatNumber(mat.imp, 3) + "/s" + cmpAndDmdText + "


" + "

MP: $" + formatNumber(mat.bCost, 2) + "Market Price: The price you would pay if " + "you were to buy this material on the market


" + "

Quality: " + formatNumber(mat.qlt, 2) + "The quality of your material. Higher quality " + - "will lead to more sales

", - id: "cmpy-mgmt-warehouse-" + matName + "-text", - display:"inline-block", + "will lead to more sales

"; + + div.appendChild(createElement("p", { + innerHTML: innerTxt, + id: "cmpy-mgmt-warehouse-" + matName + "-text", display:"inline-block", })); var buttonPanel = createElement("div", { @@ -1885,9 +1923,8 @@ Warehouse.prototype.createMaterialUI = function(mat, matName, parentRefs) { })); //Button to manage exports - buttonPanel.appendChild(createElement("a", { - innerText:"Export", display:"inline-block", class:"a-link-button", - clickListener:()=>{ + if (company.unlockUpgrades[0] === 1) { //Export unlock upgrade + function createExportPopup() { var popupId = "cmpy-mgmt-export-popup"; var exportTxt = createElement("p", { innerText:"Select the industry and city to export this material to, as well as " + @@ -1922,7 +1959,6 @@ Warehouse.prototype.createMaterialUI = function(mat, matName, parentRefs) { } //End for var currIndustry = industrySelector.options[industrySelector.selectedIndex].value; - console.log(currIndustry); for (var i = 0; i < company.divisions.length; ++i) { if (company.divisions[i].name == currIndustry) { for (var cityName in company.divisions[i].warehouses) { @@ -1990,24 +2026,25 @@ Warehouse.prototype.createMaterialUI = function(mat, matName, parentRefs) { for (var i = 0; i < mat.exp.length; ++i) { (function(i, mat, currExports){ currExports.push(createElement("div", { + class:"cmpy-mgmt-existing-export", innerHTML: "Industry: " + mat.exp[i].ind + "
" + "City: " + mat.exp[i].city + "
" + "Amount/s: " + mat.exp[i].amt, clickListener:()=>{ - mat.exp[i].splice(i, 1); - //Go to the target city and decrease the mat.imp attribute for the corresponding material - for (var i = 0; i < company.divisions.length; ++i) { - if (company.divisions[i].name === mat.exp[i].ind) { - var warehouse = company.divisions[i].warehouses[mat.exp[i].city]; + for (var j = 0; j < company.divisions.length; ++j) { + if (company.divisions[j].name === mat.exp[i].ind) { + var warehouse = company.divisions[j].warehouses[mat.exp[i].city]; if (warehouse instanceof Warehouse) { warehouse.materials[matName].imp -= mat.exp[i].amt; - return false; } else { console.log("ERROR: Target city for export does not have warehouse in specified city"); } } } + mat.exp.splice(i, 1); //Remove export object + removeElementById(popupId); + createExportPopup(); } })); })(i, mat, currExports); @@ -2015,8 +2052,11 @@ Warehouse.prototype.createMaterialUI = function(mat, matName, parentRefs) { createPopup(popupId, [exportTxt, industrySelector, citySelector, exportAmount, exportBtn, cancelBtn, currExportsText].concat(currExports)); } - })); - + buttonPanel.appendChild(createElement("a", { + innerText:"Export", display:"inline-block", class:"a-link-button", + clickListener:()=>{createExportPopup();} + })); + } buttonPanel.appendChild(createElement("br", {})); // Force line break @@ -2318,6 +2358,81 @@ Warehouse.fromJSON = function(value) { Reviver.constructors.Warehouse = Warehouse; +//Corporation Unlock Upgrades +//Upgrades for entire corporation, unlocks features, either you have it or you dont +//The structure is [index in Corporation feature upgrades array, price ] +var CorporationUnlockUpgrades = { + //Lets you export goods + "0": [0, 20e9, "Export", + "Develop infrastructure to export your materials to your other facilities. " + + "This allows you to move materials around between different divisions and cities."], + + //Lets you buy exactly however many required materials you need for production + "1": [1, 999999e9, "Smart Supply", "NOT YET IMPLEMENTED!!!!!! - Use advanced AI to anticipate your supply needs. " + + "This allows you to purchase exactly however many materials you need for production."], + + //Displays each material/product's demand + "2": [2, 25e9, "Market Research - Demand", + "Mine and analyze market data to determine the demand of all resources. " + + "The demand attribute, which affects sales, will be displayed for every material and product."], + + //Display's each material/product's competition + "3": [3, 25e9, "Market Data - Competition", + "Mine and analyze market data to determine how much competition there is on the market " + + "for all resources. The competition attribute, which affects sales, will be displayed for " + + "for every material and product."], +} + +//Corporation Upgrades +//Upgrades for entire corporation, levelable upgrades +//The structure is [index in Corporation upgrades array, base price, price mult, benefit mult (additive), +// name, desc] +var CorporationUpgrades = { + //Smart factories, increases production + "0": [0, 10e9, 1.07, 0.02, + "Smart Factories", "Advanced AI automatically optimizes the operation and productivity " + + "of factories. Each level of this upgrade increases your global production by 2% (additive)."], + + //Smart warehouses, increases storage size + "1": [1, 20e9, 1.07, .1, + "Smart Storage", "Advanced AI automatically optimizes your warehouse storage methods. " + + "Each level of this upgrade increases your global warehouse storage size by 10% (additive)."], + + //Advertise through dreams, passive popularity/ awareness gain + "2": [2, 100e9, 1.08, .001, + "DreamSense", "Use DreamSense LCC Technologies to advertise your corporation " + + "to consumers through their dreams. Each level of this upgrade provides a passive " + + "increase in awareness of your company by 0.001 / second."], + + //Makes advertising more effective + "3": [3, 5e9, 1.11, 0.1, + "Wilson Analytics", "Purchase data and analysis from Wilson, a marketing research " + + "firm. Each level of this upgrades increases the effectiveness of your " + + "advertising by 10% (additive)."], + + //Augmentation for employees, increases cre + "4": [4, 10e9, 1.05, 0.1, + "Nuoptimal Nootropic Injector Implants", "Purchase the Nuoptimal Nootropic " + + "Injector augmentation for your employees. Each level of this upgrade " + + "globally increases the creativity of your employees by 10% (additive)."], + + //Augmentation for employees, increases cha + "5": [5, 10e9, 1.05, 0.1, + "Speech Processor Implants", "Purchase the Speech Processor augmentation for your employees. " + + "Each level of this upgrade globally increases the charisma of your employees by 10% (additive)."], + + //Augmentation for employees, increases int + "6": [6, 10e9, 1.05, 0.1, + "Neural Acelerators", "Purchase the Neural Accelerator augmentation for your employees. " + + "Each level of this upgrade globally increases the intelligence of your employees " + + "by 10% (additive)."], + + //Augmentation for employees, increases eff + "7": [7, 10e9, 1.05, 0.1, + "FocusWires", "Purchase the FocusWire augmentation for your employees. Each level " + + "of this upgrade globally increases the efficiency of your employees by 10% (additive)."], +} + function Corporation(params={}) { this.name = params.name ? params.name : "The Corporation"; @@ -2335,6 +2450,13 @@ function Corporation(params={}) { this.sharePrice = 0; this.storedCycles = 0; + var numUnlockUpgrades = Object.keys(CorporationUnlockUpgrades).length, + numUpgrades = Object.keys(CorporationUpgrades).length; + + this.unlockUpgrades = Array(numUnlockUpgrades).fill(0); + this.upgrades = Array(numUpgrades).fill(0); + this.upgradeMultipliers = Array(numUpgrades).fill(1); + this.state = new CorporationState(); } @@ -2343,12 +2465,13 @@ Corporation.prototype.getState = function() { } Corporation.prototype.process = function(numCycles=1) { + var corp = this; this.storedCycles += numCycles; if (this.storedCycles >= CyclesPerIndustryStateCycle) { var state = this.getState(), marketCycles = 1; this.storedCycles -= (marketCycles * CyclesPerIndustryStateCycle); this.divisions.forEach(function(ind) { - ind.process(marketCycles, state); + ind.process(marketCycles, state, corp); }); //At the start of a new cycle, calculate profits from previous cycle @@ -2369,13 +2492,13 @@ Corporation.prototype.process = function(numCycles=1) { } Corporation.prototype.determineValuation = function() { - var val, profit = (this.revenue - this.expenses); + var val, profit = (this.revenue.minus(this.expenses)).toNumber(); if (this.public) { - val = 50e9 + this.funds + (profit * getRandomInt(7000, 8500)); + val = 25e9 + this.funds.toNumber() + (profit * getRandomInt(7000, 8500)); val *= (Math.pow(1.1, this.divisions.length)); val = Math.max(val, 0); } else { - val = 10e9 + Math.max(this.funds, 0); //Base valuation + val = 10e9 + Math.max(this.funds.toNumber(), 0); //Base valuation if (profit > 0) { val += (profit * getRandomInt(12e3, 14e3)); val *= (Math.pow(1.1, this.divisions.length)); @@ -2483,12 +2606,46 @@ Corporation.prototype.updateSharePrice = function() { } else { this.sharePrice *= (1 - (Math.random() * 0.01)); } + if (this.sharePrice <= 0.01) {this.sharePrice = 0.01;} +} + +//One time upgrades that unlock new features +Corporation.prototype.unlock = function(upgrade) { + var upgN = upgrade[0], price = upgrade[1]; + while (this.unlockUpgrades.length <= upgN) { + this.unlockUpgrades.push(0); + } + if (this.funds.lt(price)) { + dialogBoxCreate("You don't have enough funds to unlock this!"); + return; + } + this.unlockUpgrades[upgN] = 1; + this.funds = this.funds.minus(price); +} + +//Levelable upgrades +Corporation.prototype.upgrade = function(upgrade) { + var upgN = upgrade[0], basePrice = upgrade[1], priceMult = upgrade[2], + upgradeAmt = upgrade[3]; //Amount by which the upgrade multiplier gets increased (additive) + while (this.upgrades.length <= upgN) {this.upgrades.push(0);} + while (this.upgradeMultipliers.length <= upgN) {this.upgradeMultipliers.push(1);} + var totalCost = basePrice * Math.pow(this.upgrades[upgN], priceMult); + if (this.funds.lt(totalCost)) { + dialogBoxCreate("You don't have enough funds to purchase this!"); + return; + } + ++this.upgrades[upgN]; + this.funds = this.funds.minus(totalCost); + + //Increase upgrade multiplier + this.upgradeMultipliers[upgN] = 1 + (this.upgrades[upgN] * upgradeAmt); } //Keep 'global' variables for DOM elements so we don't have to search //through the DOM tree repeatedly when updating UI var companyManagementDiv, companyManagementHeaderTabs, companyManagementPanel, currentCityUi, + corporationUnlockUpgrades, corporationUpgrades, industryOverviewPanel, industryOverviewText, industryEmployeePanel, industryEmployeeText, industryEmployeeHireButton, industryEmployeeList, industryOfficeUpgradeSizeButton, @@ -2756,7 +2913,7 @@ Corporation.prototype.displayCorporationOverviewContent = function() { } else { this.numShares -= shares; this.issuedShares += shares; - //TODO ADD TO PLAYER MONEY + Player.gainMoney(shares * this.sharePrice); removeElementById(popupId); return false; } @@ -2890,7 +3047,81 @@ Corporation.prototype.displayCorporationOverviewContent = function() { companyManagementPanel.appendChild(goPublic); } + //Update overview text this.updateCorporationOverviewContent(); + + //Don't show upgrades if player hasn't opened any divisions + if (this.divisions.length <= 0) {return; } + //Corporation Upgrades + var upgradeContainer = createElement("div", { + class:"cmpy-mgmt-upgrade-container", + }); + upgradeContainer.appendChild(createElement("h1", { + innerText:"Upgrades", margin:"6px", padding:"6px", + })); + + //Unlock upgrades + var corp = this; + if (this.unlockUpgrades == null || this.upgrades == null) { //Backwards compatibility + var numUnlockUpgrades = Object.keys(CorporationUnlockUpgrades).length, + numUpgrades = Object.keys(CorporationUpgrades).length; + + this.unlockUpgrades = Array(numUnlockUpgrades).fill(0); + this.upgrades = Array(numUpgrades).fill(0); + } + for (var i = 0; i < this.unlockUpgrades.length; ++i) { + (function(i, corp) { + if (corp.unlockUpgrades[i] === 0) { + var upgrade = CorporationUnlockUpgrades[i.toString()]; + if (upgrade == null) { + console.log("ERROR: Could not find upgrade index " + i); + return; + } + + upgradeContainer.appendChild(createElement("div", { + class:"cmpy-mgmt-upgrade-div", + innerHTML:upgrade[2] + " - " + numeral(upgrade[1]).format("$0.000a") + "

" + upgrade[3], + clickListener:()=>{ + if (corp.funds.lt(upgrade[1])) { + dialogBoxCreate("Insufficient funds"); + } else { + corp.unlock(upgrade); + corp.displayCorporationOverviewContent(); + } + } + })); + } + })(i, corp); + } + + //Levelable upgrades + /* + for (var i = 0; i < this.upgrades.length; ++i) { + (function(i, corp) { + var upgrade = CorporationUpgrades[i.toString()]; + if (upgrade == null) { + console.log("ERROR: Could not find levelable upgrade index " + i); + return; + } + + var baseCost = upgrade[1], priceMult = upgrade[2]; + var cost = baseCost * Math.pow(corp.upgrades[i], priceMult); + upgradeContainer.appendChild(createElement("div", { + class:"cmpy-mgmt-upgrade-div", + innerHTML:upgrade[4] + " - " + numeral(cost).format("$0.000a") + "

" + upgrade[5], + clickListener:()=>{ + if (corp.funds.lt(cost)) { + dialogBoxCreate("Insufficient funds"); + } else { + corp.upgrade(upgrade); + corp.displayCorporationOverviewContent(); + } + } + })); + })(i, corp); + }*/ + + companyManagementPanel.appendChild(upgradeContainer); } Corporation.prototype.updateCorporationOverviewContent = function() { @@ -3429,6 +3660,9 @@ Corporation.prototype.clearUI = function() { companyManagementPanel = null; currentCityUi = null; + corporationUnlockUpgrades = null; + corporationUpgrades = null; + industryOverviewPanel = null; industryOverviewText = null; diff --git a/src/Constants.js b/src/Constants.js index 816a1e5d1..a2f9ad64a 100644 --- a/src/Constants.js +++ b/src/Constants.js @@ -1,5 +1,5 @@ let CONSTANTS = { - Version: "0.33.0", + Version: "0.34.0", //Max level for any skill, assuming no multipliers. Determined by max numerical value in javascript for experience //and the skill level formula in Player.js. Note that all this means it that when experience hits MAX_INT, then @@ -129,44 +129,45 @@ let CONSTANTS = { HackingMissionSpamTimeIncrease: 25000, //How much time limit increase is gained when conquering a Spam Node (ms) HackingMissionTransferAttackIncrease: 1.05, //Multiplier by which the attack for all Core Nodes is increased when conquering a Transfer Node HackingMissionMiscDefenseIncrease: 1.05, //The amount by which every misc node's defense is multiplied when one is conquered - HackingMissionDifficultyToHacking: 150, //Difficulty is multiplied by this to determine enemy's "hacking" level (to determine effects of scan/attack, etc) + HackingMissionDifficultyToHacking: 135, //Difficulty is multiplied by this to determine enemy's "hacking" level (to determine effects of scan/attack, etc) HackingMissionHowToPlay: "Hacking missions are a minigame that, if won, will reward you with faction reputation.

" + "In this game you control a set of Nodes and use them to try and defeat an enemy. Your Nodes " + "are colored blue, while the enemy's are red. There are also other nodes on the map colored gray " + "that initially belong to neither you nor the enemy. The goal of the game is " + - "to capture all of the enemy's database nodes within the time limit. " + - "If you cannot capture all of the enemy's database nodes in the time limit, you will lose.

" + + "to capture all of the enemy's Database nodes within the time limit. " + + "If you fail to do this, you will lose.

" + "Each Node has three stats: Attack, Defense, and HP. There are five different actions that " + "a Node can take:

" + "Attack - Targets an enemy Node and lowers its HP. The effectiveness is determined by the owner's Attack, the Player's " + - "hacking level, and the enemy's defense.
" + + "hacking level, and the enemy's defense.

" + "Scan - Targets an enemy Node and lowers its Defense. The effectiveness is determined by the owner's Attack, the Player's hacking level, and the " + - "enemy's defense.
" + + "enemy's defense.

" + "Weaken - Targets an enemy Node and lowers its Attack. The effectiveness is determined by the owner's Attack, the Player's hacking level, and the enemy's " + - "defense.
" + - "Fortify - Raises the Node's Defense. The effectiveness is determined by your hacking level.
" + + "defense.

" + + "Fortify - Raises the Node's Defense. The effectiveness is determined by your hacking level.

" + "Overflow - Raises the Node's Attack but lowers its Defense. The effectiveness is determined by your hacking level.

" + "Note that when determining the effectiveness of the above actions, the TOTAL Attack or Defense of the team is used, not just the " + "Attack/Defense of the individual Node that is performing the action.

" + "To capture a Node, you must lower its HP down to 0.

" + "There are six different types of Nodes:

" + - "CPU Core - These are your main Nodes that are used to perform actions. Capable of performing every action
" + - "Firewall - Nodes with high defense. These Nodes cannot perform any actions
" + + "CPU Core - These are your main Nodes that are used to perform actions. Capable of performing every action

" + + "Firewall - Nodes with high defense. These Nodes can 'Fortify'

" + "Database - A special type of Node. The player's objective is to conquer all of the enemy's Database Nodes within " + - "the time limit. These Nodes cannot perform any actions
" + + "the time limit. These Nodes cannot perform any actions

" + "Spam - Conquering one of these Nodes will slow the enemy's trace, giving the player additional time to complete " + - "the mission. These Nodes cannot perform any actions
" + + "the mission. These Nodes cannot perform any actions

" + "Transfer - Conquering one of these nodes will increase the Attack of all of your CPU Cores by a small fixed percentage. " + - "These Nodes are capable of performing every action except the 'Attack' action
" + - "Shield - Nodes with high defense. These Nodes cannot perform any actions

" + - "To assign an action to a Node, you must first select one of your Nodes. This can be done by simply clicking on it. Only " + - "one Node can be selected at a time, and it will be denoted with a white highlight. After selecting the Node, " + + "These Nodes are capable of performing every action except the 'Attack' action

" + + "Shield - Nodes with high defense. These Nodes can 'Fortify'

" + + "To assign an action to a Node, you must first select one of your Nodes. This can be done by simply clicking on it. Double-clicking " + + "a node will select all of your Nodes of the same type (e.g. select all CPU Core Nodes or all Transfer Nodes). Note that only Nodes " + + "that can perform actions (CPU Core, Transfer, Shield, Firewall) can be selected. Selected Nodes will be denoted with a white highlight. After selecting a Node or multiple Nodes, " + "select its action using the Action Buttons near the top of the screen. Every action also has a corresponding keyboard " + "shortcut.

" + "For certain actions such as attacking, scanning, and weakening, the Node performing the action must have a target. To target " + "another node, simply click-and-drag from the 'source' Node to a target. A Node can only have one target, and you can target " + "any Node that is adjacent to one of your Nodes (immediately above, below, or to the side. NOT diagonal). Furthermore, only CPU Cores and Transfer Nodes " + - "can target, since they are the only ones that can perform actions. To remove a target, you can simply click on the line that represents " + + "can target, since they are the only ones that can perform the related actions. To remove a target, you can simply click on the line that represents " + "the connection between one of your Nodes and its target. Alternatively, you can select the 'source' Node and click the 'Drop Connection' button, " + "or press 'd'.

" + "Other Notes:

" + @@ -1113,17 +1114,26 @@ let CONSTANTS = { LatestUpdate: "v0.34.0
" + + "-Added clear() and exit() Netscript functions
" + + "-When starting out or prestiging, you will now receive a 'Hacking Starter Guide'. It provides tips/pointers for new players
" + + "-Doubled the amount of RAM on low-level servers (up to required hacking level 150)
" + "-Slightly increased experience gain from Infiltration
" + "-buyStock(), sellStock(), shortStock(), and sellShort() Netscript function now return the stock price at which the transaction occurred, rather than a boolean. " + "If the function fails for some reason, 0 will be returned.
" + "-Hacking Mission Changes:
" + + "---You can now select multiple Nodes of the same type by double clicking. This allows you to set the " + + "action of all of selected nodes at once (e.g. set all Transfer Nodes to Fortify). Creating connections " + + "does not work with this multi-select functionality yet
" + "---Shield and Firewall Nodes can now fortify
" + - "---The effects of Fortifying are now ~30% lower
" + - "---Conquering a Spam Node now increases your time limit by 25 secs instead of 15
" + + "---The effects of Fortifying are now ~5% lower
" + + "---Conquering a Spam Node now increases your time limit by 25 seconds instead of 15
" + "---Damage dealt by Attacking was slightly reduced
" + "---The effect of Scanning was slightly reduced
" + - "" - + "---Enemy CPU Core Nodes start with slightly more attack. Misc Nodes start with slightly less defense
" + + "-Corporation Management changes:
" + + "---Added several upgrades that unlock new features
" + + "---Implemented Exporting mechanic
" + + "---Fixed many bugs
" } export {CONSTANTS}; diff --git a/src/InteractiveTutorial.js b/src/InteractiveTutorial.js index 3bbd431ad..fd95c28a6 100644 --- a/src/InteractiveTutorial.js +++ b/src/InteractiveTutorial.js @@ -1,6 +1,7 @@ -import {Engine} from "./engine.js"; -import {dialogBoxCreate} from "../utils/DialogBox.js"; -import {clearEventListeners} from "../utils/HelperFunctions.js"; +import {Engine} from "./engine.js"; +import {Player} from "./Player.js"; +import {dialogBoxCreate} from "../utils/DialogBox.js"; +import {clearEventListeners} from "../utils/HelperFunctions.js"; /* InteractiveTutorial.js */ let iTutorialSteps = { @@ -646,7 +647,10 @@ function iTutorialEnd() { document.getElementById("interactive-tutorial-container").style.display = "none"; dialogBoxCreate("If you are new to the game, the following links may be useful for you!

" + "Getting Started Guide" + - "Wiki"); + "Wiki

" + + "The Beginner's Guide to Hacking was added to your home computer! It contains stop tips/pointers for starting out with the game. " + + "To read it, go to Terminal and enter

cat hackers-starting-handbook.lit"); + Player.getHomeComputer().messages.push("hackers-starting-handbook.lit"); } function iTutorialSetText(txt) { diff --git a/src/Literature.js b/src/Literature.js index 78d12f445..7c837bb52 100644 --- a/src/Literature.js +++ b/src/Literature.js @@ -12,8 +12,8 @@ function Literature(title, filename, txt) { function showLiterature(fn) { var litObj = Literatures[fn]; if (litObj == null) {return;} - var txt = litObj.title + "

" + - "" + litObj.txt + ""; + var txt = "" + litObj.title + "

" + + litObj.txt; dialogBoxCreate(txt); } @@ -21,6 +21,24 @@ let Literatures = {} function initLiterature() { var title, fn, txt; + title = "The Beginner's Guide to Hacking"; + fn = "hackers-starting-handbook.lit"; + txt = "When starting out, hacking is the most profitable way to earn money and progress. This " + + "is a brief collection of tips/pointers on how to make the most out of your hacking scripts.

" + + "-hack() and grow() both work by percentages. hack() steals a certain percentage of the " + + "money on a server, and grow() increases the amount of money on a server by some percentage (multiplicatively)

" + + "-Because hack() and grow() work by percentages, they are more effective if the target server has a high amount of money. " + + "Therefore, you should try to increase the amount of money on a server (using grow()) to a certain amount before hacking it. Two " + + "import Netscript functions for this are getServerMoneyAvailable() and getServerMaxMoney()

" + + "-Keep security level low. Security level affects everything when hacking. Two important Netscript functions " + + "for this are getServerSecurityLevel() and getServerMinSecurityLevel()

" + + "-Purchase additional servers by visiting 'Alpha Enterprises' in the city. They are relatively cheap " + + "and give you valuable RAM to run more scripts early in the game

" + + "-Prioritize upgrading the RAM on your home computer. This can also be done at 'Alpha Enterprises'

" + + "-Many low level servers have free RAM. You can use this RAM to run your scripts. Use the scp Terminal or " + + "Netscript command to copy your scripts onto these servers and then run them."; + Literatures[fn] = new Literature(title, fn, txt); + title = "A Green Tomorrow"; fn = "A-Green-Tomorrow.lit"; txt = "Starting a few decades ago, there was a massive global movement towards the generation of renewable energy in an effort to " + diff --git a/src/Missions.js b/src/Missions.js index e040ed272..c03d26292 100644 --- a/src/Missions.js +++ b/src/Missions.js @@ -22,7 +22,7 @@ function setInMission(bool, mission) { //Keyboard shortcuts $(document).keydown(function(e) { - if (inMission && currMission && currMission.selectedNode != null) { + if (inMission && currMission && currMission.selectedNode.length != 0) { switch (e.keyCode) { case 65: //a for Attack currMission.actionButtons[0].click(); @@ -186,7 +186,7 @@ function HackingMission(rep, fac) { this.miscNodes = []; - this.selectedNode = null; //Which of the player's nodes is currently selected + this.selectedNode = []; //Which of the player's nodes are currently selected this.actionButtons = []; //DOM buttons for actions @@ -230,15 +230,15 @@ HackingMission.prototype.init = function() { //Randomly generate enemy nodes (CPU and Firewall) based on difficulty var numNodes = Math.min(8, Math.max(1, Math.round(this.difficulty / 4))); var numFirewalls = Math.min(20, - getRandomInt(Math.round(this.difficulty/2), Math.round(this.difficulty/2) + 1)); + getRandomInt(Math.round(this.difficulty/3), Math.round(this.difficulty/3) + 1)); var numDatabases = Math.min(10, getRandomInt(1, Math.round(this.difficulty / 3) + 1)); var totalNodes = numNodes + numFirewalls + numDatabases; var xlimit = 7 - Math.floor(totalNodes / 8); var randMult = addOffset(0.8 + (this.difficulty / 5), 10); for (var i = 0; i < numNodes; ++i) { var stats = { - atk: randMult * getRandomInt(75, 85), - def: randMult * getRandomInt(25, 35), + atk: randMult * getRandomInt(80, 86), + def: randMult * getRandomInt(5, 10), hp: randMult * getRandomInt(210, 230) } this.enemyCores.push(new Node(NodeTypes.Core, stats)); @@ -248,7 +248,7 @@ HackingMission.prototype.init = function() { for (var i = 0; i < numFirewalls; ++i) { var stats = { atk: 0, - def: randMult * getRandomInt(80, 90), + def: randMult * getRandomInt(10, 20), hp: randMult * getRandomInt(275, 300) } this.enemyNodes.push(new Node(NodeTypes.Firewall, stats)); @@ -258,7 +258,7 @@ HackingMission.prototype.init = function() { for (var i = 0; i < numDatabases; ++i) { var stats = { atk: 0, - def: randMult * getRandomInt(70, 85), + def: randMult * getRandomInt(30, 55), hp: randMult * getRandomInt(210, 275) } var node = new Node(NodeTypes.Database, stats); @@ -398,71 +398,88 @@ HackingMission.prototype.createPageDom = function() { //Set Action Button event listeners this.actionButtons[0].addEventListener("click", ()=>{ - if (!(this.selectedNode instanceof Node)) { + if (!(this.selectedNode.length > 0)) { console.log("ERR: Pressing Action button without selected node"); return; } - if (this.selectedNode.type !== NodeTypes.Core) {return;} - this.setActionButtonsActive(this.selectedNode.type); + if (this.selectedNode[0].type !== NodeTypes.Core) {return;} + this.setActionButtonsActive(this.selectedNode[0].type); this.setActionButton(NodeActions.Attack, false); //Set attack button inactive - this.selectedNode.action = NodeActions.Attack; + this.selectedNode.forEach(function(node){ + node.action = NodeActions.Attack; + }); }); this.actionButtons[1].addEventListener("click", ()=>{ - if (!(this.selectedNode instanceof Node)) { + if (!(this.selectedNode.length > 0)) { console.log("ERR: Pressing Action button without selected node"); return; } - var nodeType = this.selectedNode.type; + var nodeType = this.selectedNode[0].type; //In a multiselect, every Node will have the same type if (nodeType !== NodeTypes.Core && nodeType !== NodeTypes.Transfer) {return;} this.setActionButtonsActive(nodeType); this.setActionButton(NodeActions.Scan, false); //Set scan button inactive - this.selectedNode.action = NodeActions.Scan; + this.selectedNode.forEach(function(node){ + node.action = NodeActions.Scan; + }); }); this.actionButtons[2].addEventListener("click", ()=>{ - if (!(this.selectedNode instanceof Node)) { + if (!(this.selectedNode.length > 0)) { console.log("ERR: Pressing Action button without selected node"); return; } - var nodeType = this.selectedNode.type; + var nodeType = this.selectedNode[0].type; //In a multiselect, every Node will have the same type if (nodeType !== NodeTypes.Core && nodeType !== NodeTypes.Transfer) {return;} this.setActionButtonsActive(nodeType); this.setActionButton(NodeActions.Weaken, false); //Set Weaken button inactive - this.selectedNode.action = NodeActions.Weaken; + this.selectedNode.forEach(function(node){ + node.action = NodeActions.Weaken; + }); }); this.actionButtons[3].addEventListener("click", ()=>{ - if (!(this.selectedNode instanceof Node)) { + if (!(this.selectedNode.length > 0)) { console.log("ERR: Pressing Action button without selected node"); return; } - this.setActionButtonsActive(this.selectedNode.type); + this.setActionButtonsActive(this.selectedNode[0].type); this.setActionButton(NodeActions.Fortify, false); //Set Fortify button inactive - this.selectedNode.action = NodeActions.Fortify; + this.selectedNode.forEach(function(node){ + node.action = NodeActions.Fortify; + }); }); this.actionButtons[4].addEventListener("click", ()=>{ - if (!(this.selectedNode instanceof Node)) { + if (!(this.selectedNode.length > 0)) { console.log("ERR: Pressing Action button without selected node"); return; } - var nodeType = this.selectedNode.type; + var nodeType = this.selectedNode[0].type; if (nodeType !== NodeTypes.Core && nodeType !== NodeTypes.Transfer) {return;} - this.setActionButtonsActive(this.selectedNode.type); + this.setActionButtonsActive(nodeType); this.setActionButton(NodeActions.Overflow, false); //Set Overflow button inactive - this.selectedNode.action = NodeActions.Overflow; + this.selectedNode.forEach(function(node){ + node.action = NodeActions.Overflow; + }); }); this.actionButtons[5].addEventListener("click", ()=>{ - if (!(this.selectedNode instanceof Node)) { + if (!(this.selectedNode.length > 0)) { console.log("ERR: Pressing Action button without selected node"); return; } - if (this.selectedNode.conn) { - var endpoints = this.selectedNode.conn.endpoints; - endpoints[0].detachFrom(endpoints[1]); - } + this.selectedNode.forEach(function(node){ + if (node.conn) { + var endpoints = node.conn.endpoints; + endpoints[0].detachFrom(endpoints[1]); + } + node.action = NodeActions.Fortify; + }); + // if (this.selectedNode.conn) { + // var endpoints = this.selectedNode.conn.endpoints; + // endpoints[0].detachFrom(endpoints[1]); + // } }) var timeDisplay = document.createElement("p"); @@ -662,7 +679,7 @@ HackingMission.prototype.createMap = function() { case 0: //Spam var stats = { atk: 0, - def: averageAttack * 1.15 + getRandomInt(10, 50), + def: averageAttack * 1.1 + getRandomInt(15, 45), hp: randMult * getRandomInt(200, 225) } node = new Node(NodeTypes.Spam, stats); @@ -670,7 +687,7 @@ HackingMission.prototype.createMap = function() { case 1: //Transfer var stats = { atk: 0, - def: averageAttack * 1.15 + getRandomInt(10, 50), + def: averageAttack * 1.1 + getRandomInt(15, 45), hp: randMult * getRandomInt(250, 275) } node = new Node(NodeTypes.Transfer, stats); @@ -679,7 +696,7 @@ HackingMission.prototype.createMap = function() { default: var stats = { atk: 0, - def: averageAttack * 1.15 + getRandomInt(25, 75), + def: averageAttack * 1.1 + getRandomInt(30, 70), hp: randMult * getRandomInt(300, 320) } node = new Node(NodeTypes.Shield, stats); @@ -843,12 +860,40 @@ function selectNode(hackMissionInst, el) { if (nodeObj == null) {console.log("Error getting Node object");} if (!nodeObj.plyrCtrl) {return;} - if (hackMissionInst.selectedNode instanceof Node) { - hackMissionInst.selectedNode.deselect(hackMissionInst.actionButtons); - hackMissionInst.selectedNode = null; - } + clearAllSelectedNodes(hackMissionInst); nodeObj.select(hackMissionInst.actionButtons); - hackMissionInst.selectedNode = nodeObj; + hackMissionInst.selectedNode.push(nodeObj); +} + +function multiselectNode(hackMissionInst, el) { + var nodeObj = hackMissionInst.getNodeFromElement(el); + if (nodeObj == null) {console.log("ERROR: Getting Node Object in multiselectNode()");} + if (!nodeObj.plyrCtrl) {return;} + + clearAllSelectedNodes(hackMissionInst); + var type = nodeObj.type; + if (type === NodeTypes.Core) { + hackMissionInst.playerCores.forEach(function(node) { + node.select(hackMissionInst.actionButtons); + hackMissionInst.selectedNode.push(node); + }); + } else { + hackMissionInst.playerNodes.forEach(function(node) { + if (node.type === type) { + node.select(hackMissionInst.actionButtons); + hackMissionInst.selectedNode.push(node); + } + }); + } +} + +function clearAllSelectedNodes(hackMissionInst) { + if (hackMissionInst.selectedNode.length > 0) { + hackMissionInst.selectedNode.forEach(function(node){ + node.deselect(hackMissionInst.actionButtons); + }); + hackMissionInst.selectedNode.length = 0; + } } //Configures a DOM element representing a player-owned node to @@ -865,6 +910,12 @@ HackingMission.prototype.configurePlayerNodeElement = function(el) { } el.addEventListener("click", selectNodeWrapper); + function multiselectNodeWrapper() { + multiselectNode(self, el); + } + el.addEventListener("dblclick", multiselectNodeWrapper); + + if (el.firstChild) { el.firstChild.addEventListener("click", selectNodeWrapper); } @@ -875,8 +926,12 @@ HackingMission.prototype.configurePlayerNodeElement = function(el) { HackingMission.prototype.configureEnemyNodeElement = function(el) { //Deselect node if it was the selected node var nodeObj = this.getNodeFromElement(el); - if (this.selectedNode == nodeObj) { - nodeObj.deselect(this.actionButtons); + for (var i = 0; i < this.selectedNode.length; ++i) { + if (this.selectedNode[i] == nodeObj) { + nodeObj.deselect(this.actionButtons); + this.selectedNode.splice(i, 1); + break; + } } } @@ -1241,6 +1296,7 @@ HackingMission.prototype.processNode = function(nodeObj, numCycles=1) { swapNodes(this.enemyNodes, this.playerNodes, targetNode); } else { swapNodes(this.playerNodes, this.enemyNodes, targetNode); + this.configureEnemyNodeElement(targetNode.el); } break; case NodeTypes.Database: @@ -1282,6 +1338,7 @@ HackingMission.prototype.processNode = function(nodeObj, numCycles=1) { this.configurePlayerNodeElement(targetNode.el); } else { swapNodes(isMiscNode ? this.miscNodes : this.playerNodes, this.enemyNodes, targetNode); + this.configureEnemyNodeElement(targetNode.el); } break; } @@ -1420,7 +1477,7 @@ HackingMission.prototype.calculateWeakenEffect = function(atk, def, hacking=0) { } HackingMission.prototype.calculateFortifyEffect = function(hacking=0) { - return 0.6 * hacking / hackEffWeightSelf; + return 0.9 * hacking / hackEffWeightSelf; } HackingMission.prototype.calculateOverflowEffect = function(hacking=0) { diff --git a/src/NetscriptFunctions.js b/src/NetscriptFunctions.js index 12f46d52d..80cb7777c 100644 --- a/src/NetscriptFunctions.js +++ b/src/NetscriptFunctions.js @@ -493,6 +493,17 @@ function NetscriptFunctions(workerScript) { workerScript.scriptRef.log("killall(): Killing all scripts on " + server.hostname + ". May take a few minutes for the scripts to die"); return true; }, + exit : function() { + var server = getServer(workerScript.serverIp); + if (server == null) { + throw makeRuntimeRejectMsg(workerScript, "Error getting Server for this script in exit(). This is a bug please contact game dev"); + } + if (killWorkerScript(workerScript.scriptRef, server.ip)) { + workerScript.scriptRef.log("Exiting..."); + } else { + workerScript.scriptRef.log("Exit failed(). This is a bug please contact game developer"); + } + }, scp : function(scriptname, ip1, ip2){ if (arguments.length !== 2 && arguments.length !== 3) { throw makeRuntimeRejectMsg(workerScript, "Error: scp() call has incorrect number of arguments. Takes 2 or 3 arguments"); @@ -1166,7 +1177,7 @@ function NetscriptFunctions(workerScript) { if (!isNaN(port)) { //Write to port //Port 1-10 if (port < 1 || port > 10) { - throw makeRuntimeRejectMsg(workerScript, "Trying to write to invalid port: " + port + ". Only ports 1-10 are valid."); + throw makeRuntimeRejectMsg(workerScript, "ERR: Trying to write to invalid port: " + port + ". Only ports 1-10 are valid."); } var portName = "Port" + String(port); var port = NetscriptPorts[portName]; @@ -1197,19 +1208,19 @@ function NetscriptFunctions(workerScript) { } return true; } else { - throw makeRuntimeRejectMsg(workerScript, "Invalid argument passed in for port: " + port + ". Must be a number between 1 and 10"); + throw makeRuntimeRejectMsg(workerScript, "Invalid argument passed in for write: " + port); } }, read : function(port) { if (!isNaN(port)) { //Read from port //Port 1-10 if (port < 1 || port > 10) { - throw makeRuntimeRejectMsg(workerScript, "Trying to write to invalid port: " + port + ". Only ports 1-10 are valid."); + throw makeRuntimeRejectMsg(workerScript, "ERR: Trying to read from invalid port: " + port + ". Only ports 1-10 are valid."); } var portName = "Port" + String(port); var port = NetscriptPorts[portName]; if (port == null) { - throw makeRuntimeRejectMsg(workerScript, "Could not find port: " + port + ". This is a bug contact the game developer"); + throw makeRuntimeRejectMsg(workerScript, "ERR: Could not find port: " + port + ". This is a bug contact the game developer"); } if (port.length == 0) { return "NULL PORT DATA"; @@ -1229,9 +1240,35 @@ function NetscriptFunctions(workerScript) { return ""; } } else { - throw makeRuntimeRejectMsg(workerScript, "Invalid argument passed in for port: " + port + ". Must be a number between 1 and 10"); + throw makeRuntimeRejectMsg(workerScript, "Invalid argument passed in for read(): " + port); } }, + clear : function(port) { + if (!isNaN(port)) { //Clear port + if (port < 1 || port > 10) { + throw makeRuntimeRejectMsg(workerScript, "ERR: Trying to read from invalid port: " + port + ". Only ports 1-10 are valid"); + } + var portName = "Port" + String(port); + var port = NetscriptPorts[portName]; + if (port == null) { + throw makeRuntimeRejectMsg(workerScript, "ERR: Could not find port: " + port + ". This is a bug contact the game developer"); + } + port.length = 0; + } else if (isString(port)) { //Clear text file + var fn = port; + var server = getServer(workerScript.serverIp); + if (server == null) { + throw makeRuntimeRejectMsg(workerScript, "Error getting Server for this script in clear(). This is a bug please contact game dev"); + } + var txtFile = getTextFile(fn, server); + if (txtFile != null) { + txtFile.write(""); + } + } else { + throw makeRuntimeRejectMsg(workerScript, "Invalid argument passed in for clear(): " + port); + } + return 0; + }, scriptRunning : function(scriptname, ip) { var server = getServer(ip); if (server == null) { diff --git a/src/Player.js b/src/Player.js index fb47b443d..44fbe7f78 100644 --- a/src/Player.js +++ b/src/Player.js @@ -376,6 +376,7 @@ PlayerObject.prototype.prestigeSourceFile = function() { //BitNode 3: Corporatocracy if (this.bitNodeN === 3) {this.money = new Decimal(150e9);} + this.corporation = 0; //BitNode 8: Ghost of Wall Street if (this.bitNodeN === 8) {this.money = new Decimal(100000000);} diff --git a/src/Script.js b/src/Script.js index 06e26f499..baed88688 100644 --- a/src/Script.js +++ b/src/Script.js @@ -258,7 +258,8 @@ function calculateRamUsage(codeCopy) { var sqlinjectCount = numOccurrences(codeCopy, "sqlinject("); var runCount = numOccurrences(codeCopy, "run("); var execCount = numOccurrences(codeCopy, "exec("); - var killCount = numOccurrences(codeCopy, "kill(") + numOccurrences(codeCopy, "killall("); + var killCount = numOccurrences(codeCopy, "kill(") + numOccurrences(codeCopy, "killall(") + + numOccurrences(codeCopy, "exit("); var scpCount = numOccurrences(codeCopy, "scp("); var hasRootAccessCount = numOccurrences(codeCopy, "hasRootAccess("); var getHostnameCount = numOccurrences(codeCopy, "getHostname(") + @@ -295,7 +296,7 @@ function calculateRamUsage(codeCopy) { numOccurrences(codeCopy, "deleteServer(") + numOccurrences(codeCopy, "getPurchasedServers("); var scriptRoundCount = numOccurrences(codeCopy, "round("); - var scriptWriteCount = numOccurrences(codeCopy, "write("); + var scriptWriteCount = numOccurrences(codeCopy, "write(") + numOccurrences(codeCopy, "clear("); var scriptReadCount = numOccurrences(codeCopy, "read("); var arbScriptCount = numOccurrences(codeCopy, "scriptRunning(") + numOccurrences(codeCopy, "scriptKill("); diff --git a/src/Server.js b/src/Server.js index 5838d1d82..840d84466 100644 --- a/src/Server.js +++ b/src/Server.js @@ -402,23 +402,23 @@ function initForeignServers() { AddToAllServers(JohnsonOrthopedicsServer); //"Low level" targets - var FoodNStuffServer = new Server(createRandomIp(), "foodnstuff", "Food N Stuff Supermarket", false, false, false, 8); + var FoodNStuffServer = new Server(createRandomIp(), "foodnstuff", "Food N Stuff Supermarket", false, false, false, 16); FoodNStuffServer.setHackingParameters(1, 2000000, 10, 5); FoodNStuffServer.setPortProperties(0); FoodNStuffServer.messages.push("sector-12-crime.lit"); AddToAllServers(FoodNStuffServer); - var SigmaCosmeticsServer = new Server(createRandomIp(), "sigma-cosmetics", "Sigma Cosmetics", false, false, false, 8); + var SigmaCosmeticsServer = new Server(createRandomIp(), "sigma-cosmetics", "Sigma Cosmetics", false, false, false, 16); SigmaCosmeticsServer.setHackingParameters(5, 2300000, 10, 10); SigmaCosmeticsServer.setPortProperties(0); AddToAllServers(SigmaCosmeticsServer); - var JoesGunsServer = new Server(createRandomIp(), "joesguns", "Joe's Guns", false, false, false, 8); + var JoesGunsServer = new Server(createRandomIp(), "joesguns", "Joe's Guns", false, false, false, 16); JoesGunsServer.setHackingParameters(10, 2500000, 15, 20); JoesGunsServer.setPortProperties(0); AddToAllServers(JoesGunsServer); - var Zer0NightclubServer = new Server(createRandomIp(), "zer0", "ZER0 Nightclub", false, false, false, 16); + var Zer0NightclubServer = new Server(createRandomIp(), "zer0", "ZER0 Nightclub", false, false, false, 32); Zer0NightclubServer.setHackingParameters(75, 7500000, 25, 40); Zer0NightclubServer.setPortProperties(1); AddToAllServers(Zer0NightclubServer); @@ -428,40 +428,40 @@ function initForeignServers() { NectarNightclubServer.setPortProperties(0); AddToAllServers(NectarNightclubServer); - var NeoNightclubServer = new Server(createRandomIp(), "neo-net", "Neo Nightclub Network", false, false, false, 16); + var NeoNightclubServer = new Server(createRandomIp(), "neo-net", "Neo Nightclub Network", false, false, false, 32); NeoNightclubServer.setHackingParameters(50, 5000000, 25, 25); NeoNightclubServer.setPortProperties(1); NeoNightclubServer.messages.push("the-hidden-world.lit"); AddToAllServers(NeoNightclubServer); - var SilverHelixServer = new Server(createRandomIp(), "silver-helix", "Silver Helix", false, false, false, 32); + var SilverHelixServer = new Server(createRandomIp(), "silver-helix", "Silver Helix", false, false, false, 64); SilverHelixServer.setHackingParameters(150, 45000000, 30, 30); SilverHelixServer.setPortProperties(2); SilverHelixServer.messages.push("new-triads.lit"); AddToAllServers(SilverHelixServer); - var HongFangTeaHouseServer = new Server(createRandomIp(), "hong-fang-tea", "HongFang Teahouse", false, false, false, 8); + var HongFangTeaHouseServer = new Server(createRandomIp(), "hong-fang-tea", "HongFang Teahouse", false, false, false, 16); HongFangTeaHouseServer.setHackingParameters(30, 3000000, 15, 20); HongFangTeaHouseServer.setPortProperties(0); HongFangTeaHouseServer.messages.push("brighter-than-the-sun.lit"); AddToAllServers(HongFangTeaHouseServer); - var HaraKiriSushiBarServer = new Server(createRandomIp(), "harakiri-sushi", "HaraKiri Sushi Bar Network", false, false, false, 8); + var HaraKiriSushiBarServer = new Server(createRandomIp(), "harakiri-sushi", "HaraKiri Sushi Bar Network", false, false, false, 16); HaraKiriSushiBarServer.setHackingParameters(40, 4000000, 15, 40); HaraKiriSushiBarServer.setPortProperties(0); AddToAllServers(HaraKiriSushiBarServer); - var PhantasyServer = new Server(createRandomIp(), "phantasy", "Phantasy Club", false, false, false, 16); + var PhantasyServer = new Server(createRandomIp(), "phantasy", "Phantasy Club", false, false, false, 32); PhantasyServer.setHackingParameters(100, 24000000, 20, 35); PhantasyServer.setPortProperties(2); AddToAllServers(PhantasyServer); - var MaxHardwareServer = new Server(createRandomIp(), "max-hardware", "Max Hardware Store", false, false, false, 16); + var MaxHardwareServer = new Server(createRandomIp(), "max-hardware", "Max Hardware Store", false, false, false, 32); MaxHardwareServer.setHackingParameters(80, 10000000, 15, 30); MaxHardwareServer.setPortProperties(1); AddToAllServers(MaxHardwareServer); - var OmegaSoftwareServer = new Server(createRandomIp(), "omega-net", "Omega Software", false, false, false, 16); + var OmegaSoftwareServer = new Server(createRandomIp(), "omega-net", "Omega Software", false, false, false, 32); OmegaSoftwareServer.setHackingParameters(getRandomInt(180, 220), getRandomInt(60000000, 70000000), getRandomInt(25, 35), getRandomInt(30, 40)); OmegaSoftwareServer.setPortProperties(2); OmegaSoftwareServer.messages.push("the-new-god.lit"); @@ -473,7 +473,7 @@ function initForeignServers() { CrushFitnessGymServer.setPortProperties(2); AddToAllServers(CrushFitnessGymServer); - var IronGymServer = new Server(createRandomIp(), "iron-gym", "Iron Gym Network", false, false, false, 16); + var IronGymServer = new Server(createRandomIp(), "iron-gym", "Iron Gym Network", false, false, false, 32); IronGymServer.setHackingParameters(100, 20000000, 30, 20); IronGymServer.setPortProperties(1); AddToAllServers(IronGymServer); @@ -697,6 +697,7 @@ function prestigeHomeComputer(homeComp) { homeComp.programs.push(Programs.NukeProgram); homeComp.messages.length = 0; + homeComp.messages.push("hackers-starting-handbook.lit"); } //List of all servers that exist in the game, indexed by their ip diff --git a/src/Terminal.js b/src/Terminal.js index e6ecaef8f..a2897ab8c 100644 --- a/src/Terminal.js +++ b/src/Terminal.js @@ -1010,7 +1010,7 @@ let Terminal = { //Check programs var delTarget = commandArray[1]; - if (delTarget.endsWith(".exe")) { + if (delTarget.includes(".exe")) { for (var i = 0; i < s.programs.length; ++i) { if (s.programs[i] == delTarget) { s.programs.splice(i, 1);