diff --git a/doc/source/netscript.rst b/doc/source/netscript.rst index edc3d6c4c..13272cd50 100644 --- a/doc/source/netscript.rst +++ b/doc/source/netscript.rst @@ -3,9 +3,10 @@ Netscript Documentation Netscript is the programming language used in the world of Bitburner. When you write scripts in Bitburner, they are written in the Netscript language. -Netscript is simply a tiny subset of Javascript. This means that Netscript's -syntax is almost idental to Javascript's, but it does not implement many of the -features that Javascript has. +Netscript is simply a subset of `JavaScript `_,. +This means that Netscript's syntax is +identical to that of JavaScript, but it does not implement some of the features +that JavaScript has. If you have any requests or suggestions to improve the Netscript language, feel free to reach out to the developer! diff --git a/doc/source/netscript1.rst b/doc/source/netscript1.rst index d6adf3b39..59e9a70a6 100644 --- a/doc/source/netscript1.rst +++ b/doc/source/netscript1.rst @@ -2,14 +2,18 @@ Netscript 1.0 ============= -Netscript 1.0 is implemented using modified version of Neil Fraser's +Netscript 1.0 is implemented using a modified version of Neil Fraser's `JS-Interpreter `_. -This interpreter was created for ES5, which means that the code written -for Netscript 1.0 must be compliant for that version. However, some additional -ES6+ features are implemented through polyfills. +This is an ES5 JavaScript interpreter. This means that (almost) any JavaScript feature +that is available in ES5 is also available in Netscript 1.0. However, this also means +that the interpreter does not natively support any JavaScript features introduced in versions +ES6 or after. -Netscript 1.0 scripts end with the ".script" extension. +If you are confused by the ES5/ES6/etc. terminology, consider reading this: +`WTF is ES6, ES8, ES2017, ECMAScript... `_ + +Netscript 1.0 scripts end with the ".script" extension in their filenames. Which ES6+ features are supported? ---------------------------------- diff --git a/doc/source/netscriptfunctions.rst b/doc/source/netscriptfunctions.rst index 514a3d484..2e558944f 100644 --- a/doc/source/netscriptfunctions.rst +++ b/doc/source/netscriptfunctions.rst @@ -659,14 +659,14 @@ getNextHacknetNodeCost .. js:function:: getNextHacknetNodeCost() - Deprecated (no longer usable). See :doc:`netscripthacknetnodeapi` + Deprecated (no longer usable). See :doc:`netscripthacknetnodeapi` purchaseHacknetNode ^^^^^^^^^^^^^^^^^^^ .. js:function:: purchaseHacknetNode() - Deprecated (no longer usable). See :doc:`netscripthacknetnodeapi` + Deprecated (no longer usable). See :doc:`netscripthacknetnodeapi` getPurchasedServerCost ^^^^^^^^^^^^^^^^^^^^^^ @@ -772,6 +772,18 @@ write is set to "w", then the data is written in "write" mode which means that it will overwrite all existing data on the text file. If *mode* is set to any other value then the data will be written in "append" mode which means that the data will be added at the end of the text file. +tryWrite +^^^^^^^^ + +.. js:function:: tryWrite(port, data="") + + :param number port: Port to be written to + :param string data: Data to try to write + :returns: True if the data is successfully written to the port, and false otherwise + + Attempts to write data to the specified Netscript Port. If the port is full, the data will + not be written. Otherwise, the data will be written normally + read ^^^^ @@ -813,6 +825,17 @@ clear If the *port/fn* argument is a string, then it specifies the name of a text file (.txt) and will delete all data from that text file. +getPortHandle +^^^^^^^^^^^^^ + +.. js:function:: getPortHandle(port) + + :param number port: Port number + + Get a handle to a Netscript Port. See more details here: :ref:`netscript_ports` + + **WARNING:** Port Handles only work in :ref:`netscriptjs`. They will not work in :ref:`netscript1`. + rm ^^ diff --git a/doc/source/netscriptmisc.rst b/doc/source/netscriptmisc.rst index 5686f817a..ac7cb9610 100644 --- a/doc/source/netscriptmisc.rst +++ b/doc/source/netscriptmisc.rst @@ -1,9 +1,13 @@ +.. _netscript_misc: + Netscript Miscellaneous ======================= +.. _netscript_ports: + Netscript Ports --------------- -Netscript ports are endpoints that can be used to communicate between scripts. +Netscript Ports are endpoints that can be used to communicate between scripts. A port is implemented as a sort of serialized queue, where you can only write and read one element at a time from the port. When you read data from a port, the element that is read is removed from the port. @@ -55,9 +59,11 @@ And the data in port 1 will look like:: **Port Handles** +WARNING: Port Handles only work in :ref:`netscriptjs`. They do not work in :ref:`netscript1` + The :js:func:`getPortHandle` Netscript function can be used to get a handle to a Netscript Port. This handle allows you to access several new port-related functions and the -port's underlying data structure, which is just a Javascript array. The functions are: +port's underlying data structure, which is just a JavaScript array. The functions are: .. js:method:: NetscriptPort.write(data) diff --git a/src/Constants.js b/src/Constants.js index ee1a8d382..ae0c6ac5d 100644 --- a/src/Constants.js +++ b/src/Constants.js @@ -6,6 +6,9 @@ let CONSTANTS = { //the player will have this level assuming no multipliers. Multipliers can cause skills to go above this. MaxSkillLevel: 975, + //Milliseconds per game cycle + MilliPerCycle: 200, + //How much reputation is needed to join a megacorporation's faction CorpFactionRepRequirement: 200e3, @@ -493,12 +496,13 @@ let CONSTANTS = { "World Stock Exchange account and TIX API Access
", LatestUpdate: - "v0.40.3
" + - "* b1t_flum3.exe program can now be created immediately at Hacking level 1 (rather than hacking level 5)
" + - "* UI improvements for the character overview panel and the left-hand menu (by mat-jaworski)
" + - "* Improved the introductory tutorial
" - - + `v0.40.3
+ * b1t_flum3.exe program can now be created immediately at Hacking level 1 (rather than hacking level 5) + * UI improvements for the character overview panel and the left-hand menu (by mat-jaworski) + * Updated documentation to reflect the fact that Netscript port handles (getPortHandle()) only works in NetscriptJS (2.0), NOT Netscript 1.0 + * Added tryWrite() Netscript function + * When working (for a company/faction), experience is gained immediately/continuously rather than all at once when the work is finished + * Improved the introductory tutorial` } export {CONSTANTS}; diff --git a/src/InteractiveTutorial.js b/src/InteractiveTutorial.js index 0e721d9d8..5eccc4d09 100644 --- a/src/InteractiveTutorial.js +++ b/src/InteractiveTutorial.js @@ -268,7 +268,7 @@ function iTutorialEvaluateStep() { "written in the Netscript language, a programming language created for " + "this game. There are details about the Netscript language in the documentation, which " + "can be accessed in the 'Tutorial' tab on the main navigation menu. I highly suggest you check " + - "it out after this tutorial. For now, just copy " + + "it out after this tutorial. For now, just copy " + "and paste the following code into the script editor:

" + "while(true) {
" + "  hack('foodnstuff');
" + diff --git a/src/NetscriptFunctions.js b/src/NetscriptFunctions.js index 418f04233..0fbbba9fd 100644 --- a/src/NetscriptFunctions.js +++ b/src/NetscriptFunctions.js @@ -1847,6 +1847,25 @@ function NetscriptFunctions(workerScript) { throw makeRuntimeRejectMsg(workerScript, "Invalid argument passed in for write: " + port); } }, + tryWrite : function(port, data="") { + if (workerScript.checkingRam) { + return updateStaticRam("tryWrite", CONSTANTS.ScriptReadWriteRamCost); + } + updateDynamicRam("tryWrite", CONSTANTS.ScriptReadWriteRamCost); + if (!isNaN(port)) { + port = Math.round(port); + if (port < 1 || port > CONSTANTS.NumNetscriptPorts) { + throw makeRuntimeRejectMsg(workerScript, "ERROR: tryWrite() called on invalid port: " + port + ". Only ports 1-" + CONSTANTS.NumNetscriptPorts + " are valid."); + } + var port = NetscriptPorts[port-1]; + if (port == null || !(port instanceof NetscriptPort)) { + throw makeRuntimeRejectMsg(workerScript, "Could not find port: " + port + ". This is a bug contact the game developer"); + } + return port.tryWrite(data); + } else { + throw makeRuntimeRejectMsg(workerScript, "Invalid argument passed in for tryWrite: " + port); + } + }, read : function(port) { if (workerScript.checkingRam) { return updateStaticRam("read", CONSTANTS.ScriptReadWriteRamCost); diff --git a/src/Player.js b/src/Player.js index 27ad67086..e444cfc3e 100644 --- a/src/Player.js +++ b/src/Player.js @@ -30,6 +30,8 @@ import numeral from "numeral/min/numeral.min"; import {formatNumber, convertTimeMsToTimeElapsedString} from "../utils/StringHelperFunctions"; +const CYCLES_PER_SEC = 1000 / CONSTANTS.MilliPerCycle; + function PlayerObject() { //Skills and stats this.hacking_skill = 1; @@ -613,6 +615,7 @@ PlayerObject.prototype.resetWorkStatus = function() { this.workChaExpGainRate = 0; this.workRepGainRate = 0; this.workMoneyGainRate = 0; + this.workMoneyLossRate = 0; this.workHackExpGained = 0; this.workStrExpGained = 0; @@ -634,24 +637,109 @@ PlayerObject.prototype.resetWorkStatus = function() { document.getElementById("work-in-progress-text").innerHTML = ""; } -PlayerObject.prototype.gainWorkExp = function() { - this.gainHackingExp(this.workHackExpGained); - this.gainStrengthExp(this.workStrExpGained); - this.gainDefenseExp(this.workDefExpGained); - this.gainDexterityExp(this.workDexExpGained); - this.gainAgilityExp(this.workAgiExpGained); - this.gainCharismaExp(this.workChaExpGained); +PlayerObject.prototype.processWorkEarnings = function(numCycles=1) { + var hackExpGain = this.workHackExpGainRate * numCycles; + var strExpGain = this.workStrExpGainRate * numCycles; + var defExpGain = this.workDefExpGainRate * numCycles; + var dexExpGain = this.workDexExpGainRate * numCycles; + var agiExpGain = this.workAgiExpGainRate * numCycles; + var chaExpGain = this.workChaExpGainRate * numCycles; + + this.gainHackingExp(hackExpGain); + this.gainStrengthExp(strExpGain); + this.gainDefenseExp(defExpGain); + this.gainDexterityExp(dexExpGain); + this.gainAgilityExp(agiExpGain); + this.gainCharismaExp(chaExpGain); + this.workHackExpGained += hackExpGain; + this.workStrExpGained += strExpGain; + this.workDefExpGained += defExpGain; + this.workDexExpGained += dexExpGain; + this.workAgiExpGained += agiExpGain; + this.workChaExpGained += chaExpGain; + this.workRepGained += this.workRepGainRate * numCycles; + this.workMoneyGained += this.workMoneyGainRate * numCycles; + this.workMoneyGained -= this.workMoneyLossRate * numCycles; } /* Working for Company */ +PlayerObject.prototype.startWork = function() { + this.resetWorkStatus(); + this.isWorking = true; + this.workType = CONSTANTS.WorkTypeCompany; + + this.workHackExpGainRate = this.getWorkHackExpGain(); + this.workStrExpGainRate = this.getWorkStrExpGain(); + this.workDefExpGainRate = this.getWorkDefExpGain(); + this.workDexExpGainRate = this.getWorkDexExpGain(); + this.workAgiExpGainRate = this.getWorkAgiExpGain(); + this.workChaExpGainRate = this.getWorkChaExpGain(); + this.workRepGainRate = this.getWorkRepGain(); + this.workMoneyGainRate = this.getWorkMoneyGain(); + + this.timeNeededToCompleteWork = CONSTANTS.MillisecondsPer8Hours; + + //Remove all old event listeners from Cancel button + var newCancelButton = clearEventListeners("work-in-progress-cancel-button"); + newCancelButton.innerHTML = "Cancel Work"; + newCancelButton.addEventListener("click", function() { + Player.finishWork(true); + return false; + }); + + //Display Work In Progress Screen + Engine.loadWorkInProgressContent(); +} + +PlayerObject.prototype.work = function(numCycles) { + //Cap the number of cycles being processed to whatever would put you at + //the work time limit (8 hours) + var overMax = false; + if (this.timeWorked + (Engine._idleSpeed * numCycles) >= CONSTANTS.MillisecondsPer8Hours) { + overMax = true; + numCycles = Math.round((CONSTANTS.MillisecondsPer8Hours - this.timeWorked) / Engine._idleSpeed); + } + this.timeWorked += Engine._idleSpeed * numCycles; + + this.workRepGainRate = this.getWorkRepGain(); + this.processWorkEarnings(numCycles); + + //If timeWorked == 8 hours, then finish. You can only gain 8 hours worth of exp and money + if (overMax || this.timeWorked >= CONSTANTS.MillisecondsPer8Hours) { + return this.finishWork(false); + } + + var comp = Companies[this.companyName], companyRep = "0"; + if (comp == null || !(comp instanceof Company)) { + console.log("ERROR: Could not find Company: " + this.companyName); + } else { + companyRep = comp.playerReputation; + } + + var txt = document.getElementById("work-in-progress-text"); + txt.innerHTML = "You are currently working as a " + this.companyPosition.positionName + + " at " + this.companyName + " (Current Company Reputation: " + + formatNumber(companyRep, 0) + ")

" + + "You have been working for " + convertTimeMsToTimeElapsedString(this.timeWorked) + "

" + + "You have earned:

" + + "$" + formatNumber(this.workMoneyGained, 2) + " ($" + formatNumber(this.workMoneyGainRate * CYCLES_PER_SEC, 2) + " / sec)

" + + formatNumber(this.workRepGained, 4) + " (" + formatNumber(this.workRepGainRate * CYCLES_PER_SEC, 4) + " / sec) reputation for this company

" + + formatNumber(this.workHackExpGained, 4) + " (" + formatNumber(this.workHackExpGainRate * CYCLES_PER_SEC, 4) + " / sec) hacking exp

" + + formatNumber(this.workStrExpGained, 4) + " (" + formatNumber(this.workStrExpGainRate * CYCLES_PER_SEC, 4) + " / sec) strength exp
" + + formatNumber(this.workDefExpGained, 4) + " (" + formatNumber(this.workDefExpGainRate * CYCLES_PER_SEC, 4) + " / sec) defense exp
" + + formatNumber(this.workDexExpGained, 4) + " (" + formatNumber(this.workDexExpGainRate * CYCLES_PER_SEC, 4) + " / sec) dexterity exp
" + + formatNumber(this.workAgiExpGained, 4) + " (" + formatNumber(this.workAgiExpGainRate * CYCLES_PER_SEC, 4) + " / sec) agility exp

" + + formatNumber(this.workChaExpGained, 4) + " (" + formatNumber(this.workChaExpGainRate * CYCLES_PER_SEC, 4) + " / sec) charisma exp

" + + "You will automatically finish after working for 8 hours. You can cancel earlier if you wish, " + + "but you will only gain half of the reputation you've earned so far." +} + PlayerObject.prototype.finishWork = function(cancelled, sing=false) { //Since the work was cancelled early, player only gains half of what they've earned so far if (cancelled) { this.workRepGained /= 2; } - this.gainWorkExp(); - var company = Companies[this.companyName]; company.playerReputation += (this.workRepGained); @@ -698,91 +786,6 @@ PlayerObject.prototype.finishWork = function(cancelled, sing=false) { this.resetWorkStatus(); } -PlayerObject.prototype.startWork = function() { - this.resetWorkStatus(); - this.isWorking = true; - this.workType = CONSTANTS.WorkTypeCompany; - - this.workHackExpGainRate = this.getWorkHackExpGain(); - this.workStrExpGainRate = this.getWorkStrExpGain(); - this.workDefExpGainRate = this.getWorkDefExpGain(); - this.workDexExpGainRate = this.getWorkDexExpGain(); - this.workAgiExpGainRate = this.getWorkAgiExpGain(); - this.workChaExpGainRate = this.getWorkChaExpGain(); - this.workRepGainRate = this.getWorkRepGain(); - this.workMoneyGainRate = this.getWorkMoneyGain(); - - this.timeNeededToCompleteWork = CONSTANTS.MillisecondsPer8Hours; - - //Remove all old event listeners from Cancel button - var newCancelButton = clearEventListeners("work-in-progress-cancel-button"); - newCancelButton.innerHTML = "Cancel Work"; - newCancelButton.addEventListener("click", function() { - Player.finishWork(true); - return false; - }); - - //Display Work In Progress Screen - Engine.loadWorkInProgressContent(); -} - -PlayerObject.prototype.work = function(numCycles) { - this.workRepGainRate = this.getWorkRepGain(); - - this.workHackExpGained += this.workHackExpGainRate * numCycles; - this.workStrExpGained += this.workStrExpGainRate * numCycles; - this.workDefExpGained += this.workDefExpGainRate * numCycles; - this.workDexExpGained += this.workDexExpGainRate * numCycles; - this.workAgiExpGained += this.workAgiExpGainRate * numCycles; - this.workChaExpGained += this.workChaExpGainRate * numCycles; - this.workRepGained += this.workRepGainRate * numCycles; - this.workMoneyGained += this.workMoneyGainRate * numCycles; - - var cyclesPerSec = 1000 / Engine._idleSpeed; - - this.timeWorked += Engine._idleSpeed * numCycles; - - //If timeWorked == 8 hours, then finish. You can only gain 8 hours worth of exp and money - if (this.timeWorked >= CONSTANTS.MillisecondsPer8Hours) { - var maxCycles = CONSTANTS.GameCyclesPer8Hours; - this.workHackExpGained = this.workHackExpGainRate * maxCycles; - this.workStrExpGained = this.workStrExpGainRate * maxCycles; - this.workDefExpGained = this.workDefExpGainRate * maxCycles; - this.workDexExpGained = this.workDexExpGainRate * maxCycles; - this.workAgiExpGained = this.workAgiExpGainRate * maxCycles; - this.workChaExpGained = this.workChaExpGainRate * maxCycles; - this.workRepGained = this.workRepGainRate * maxCycles; - this.workMoneyGained = this.workMoneyGainRate * maxCycles; - this.finishWork(false); - return; - } - - var comp = Companies[this.companyName], companyRep = "0"; - if (comp == null || !(comp instanceof Company)) { - console.log("ERROR: Could not find Company: " + this.companyName); - } else { - companyRep = comp.playerReputation; - } - - var txt = document.getElementById("work-in-progress-text"); - txt.innerHTML = "You are currently working as a " + this.companyPosition.positionName + - " at " + this.companyName + " (Current Company Reputation: " + - formatNumber(companyRep, 0) + ")

" + - "You have been working for " + convertTimeMsToTimeElapsedString(this.timeWorked) + "

" + - "You have earned:

" + - "$" + formatNumber(this.workMoneyGained, 2) + " ($" + formatNumber(this.workMoneyGainRate * cyclesPerSec, 2) + " / sec)

" + - formatNumber(this.workRepGained, 4) + " (" + formatNumber(this.workRepGainRate * cyclesPerSec, 4) + " / sec) reputation for this company

" + - formatNumber(this.workHackExpGained, 4) + " (" + formatNumber(this.workHackExpGainRate * cyclesPerSec, 4) + " / sec) hacking exp

" + - formatNumber(this.workStrExpGained, 4) + " (" + formatNumber(this.workStrExpGainRate * cyclesPerSec, 4) + " / sec) strength exp
" + - formatNumber(this.workDefExpGained, 4) + " (" + formatNumber(this.workDefExpGainRate * cyclesPerSec, 4) + " / sec) defense exp
" + - formatNumber(this.workDexExpGained, 4) + " (" + formatNumber(this.workDexExpGainRate * cyclesPerSec, 4) + " / sec) dexterity exp
" + - formatNumber(this.workAgiExpGained, 4) + " (" + formatNumber(this.workAgiExpGainRate * cyclesPerSec, 4) + " / sec) agility exp

" + - formatNumber(this.workChaExpGained, 4) + " (" + formatNumber(this.workChaExpGainRate * cyclesPerSec, 4) + " / sec) charisma exp

" + - "You will automatically finish after working for 8 hours. You can cancel earlier if you wish, " + - "but you will only gain half of the reputation you've earned so far." - -} - PlayerObject.prototype.startWorkPartTime = function() { this.resetWorkStatus(); this.isWorking = true; @@ -811,57 +814,50 @@ PlayerObject.prototype.startWorkPartTime = function() { } PlayerObject.prototype.workPartTime = function(numCycles) { - this.workRepGainRate = this.getWorkRepGain(); - - this.workHackExpGained += this.workHackExpGainRate * numCycles; - this.workStrExpGained += this.workStrExpGainRate * numCycles; - this.workDefExpGained += this.workDefExpGainRate * numCycles; - this.workDexExpGained += this.workDexExpGainRate * numCycles; - this.workAgiExpGained += this.workAgiExpGainRate * numCycles; - this.workChaExpGained += this.workChaExpGainRate * numCycles; - this.workRepGained += this.workRepGainRate * numCycles; - this.workMoneyGained += this.workMoneyGainRate * numCycles; - - var cyclesPerSec = 1000 / Engine._idleSpeed; - + //Cap the number of cycles being processed to whatever would put you at the + //work time limit (8 hours) + var overMax = false; + if (this.timeWorked + (Engine._idleSpeed * numCycles) >= CONSTANTS.MillisecondsPer8Hours) { + overMax = true; + numCycles = Math.round((CONSTANTS.MillisecondsPer8Hours - this.timeWorked) / Engine._idleSpeed); + } this.timeWorked += Engine._idleSpeed * numCycles; + this.workRepGainRate = this.getWorkRepGain(); + this.processWorkEarnings(numCycles); + //If timeWorked == 8 hours, then finish. You can only gain 8 hours worth of exp and money - if (this.timeWorked >= CONSTANTS.MillisecondsPer8Hours) { - var maxCycles = CONSTANTS.GameCyclesPer8Hours; - this.workHackExpGained = this.workHackExpGainRate * maxCycles; - this.workStrExpGained = this.workStrExpGainRate * maxCycles; - this.workDefExpGained = this.workDefExpGainRate * maxCycles; - this.workDexExpGained = this.workDexExpGainRate * maxCycles; - this.workAgiExpGained = this.workAgiExpGainRate * maxCycles; - this.workChaExpGained = this.workChaExpGainRate * maxCycles; - this.workRepGained = this.workRepGainRate * maxCycles; - this.workMoneyGained = this.workMoneyGainRate * maxCycles; - this.finishWorkPartTime(); - return; + if (overMax || this.timeWorked >= CONSTANTS.MillisecondsPer8Hours) { + return this.finishWorkPartTime(); + } + + var comp = Companies[this.companyName], companyRep = "0"; + if (comp == null || !(comp instanceof Company)) { + console.log("ERROR: Could not find Company: " + this.companyName); + } else { + companyRep = comp.playerReputation; } var txt = document.getElementById("work-in-progress-text"); txt.innerHTML = "You are currently working as a " + this.companyPosition.positionName + - " at " + Player.companyName + "

" + + " at " + Player.companyName + " (Current Company Reputation: " + + formatNumber(companyRep, 0) + ")

" + "You have been working for " + convertTimeMsToTimeElapsedString(this.timeWorked) + "

" + "You have earned:

" + - "$" + formatNumber(this.workMoneyGained, 2) + " ($" + formatNumber(this.workMoneyGainRate * cyclesPerSec, 2) + " / sec)

" + - formatNumber(this.workRepGained, 4) + " (" + formatNumber(this.workRepGainRate * cyclesPerSec, 4) + " / sec) reputation for this company

" + - formatNumber(this.workHackExpGained, 4) + " (" + formatNumber(this.workHackExpGainRate * cyclesPerSec, 4) + " / sec) hacking exp

" + - formatNumber(this.workStrExpGained, 4) + " (" + formatNumber(this.workStrExpGainRate * cyclesPerSec, 4) + " / sec) strength exp
" + - formatNumber(this.workDefExpGained, 4) + " (" + formatNumber(this.workDefExpGainRate * cyclesPerSec, 4) + " / sec) defense exp
" + - formatNumber(this.workDexExpGained, 4) + " (" + formatNumber(this.workDexExpGainRate * cyclesPerSec, 4) + " / sec) dexterity exp
" + - formatNumber(this.workAgiExpGained, 4) + " (" + formatNumber(this.workAgiExpGainRate * cyclesPerSec, 4) + " / sec) agility exp

" + - formatNumber(this.workChaExpGained, 4) + " (" + formatNumber(this.workChaExpGainRate * cyclesPerSec, 4) + " / sec) charisma exp

" + + "$" + formatNumber(this.workMoneyGained, 2) + " ($" + formatNumber(this.workMoneyGainRate * CYCLES_PER_SEC, 2) + " / sec)

" + + formatNumber(this.workRepGained, 4) + " (" + formatNumber(this.workRepGainRate * CYCLES_PER_SEC, 4) + " / sec) reputation for this company

" + + formatNumber(this.workHackExpGained, 4) + " (" + formatNumber(this.workHackExpGainRate * CYCLES_PER_SEC, 4) + " / sec) hacking exp

" + + formatNumber(this.workStrExpGained, 4) + " (" + formatNumber(this.workStrExpGainRate * CYCLES_PER_SEC, 4) + " / sec) strength exp
" + + formatNumber(this.workDefExpGained, 4) + " (" + formatNumber(this.workDefExpGainRate * CYCLES_PER_SEC, 4) + " / sec) defense exp
" + + formatNumber(this.workDexExpGained, 4) + " (" + formatNumber(this.workDexExpGainRate * CYCLES_PER_SEC, 4) + " / sec) dexterity exp
" + + formatNumber(this.workAgiExpGained, 4) + " (" + formatNumber(this.workAgiExpGainRate * CYCLES_PER_SEC, 4) + " / sec) agility exp

" + + formatNumber(this.workChaExpGained, 4) + " (" + formatNumber(this.workChaExpGainRate * CYCLES_PER_SEC, 4) + " / sec) charisma exp

" + "You will automatically finish after working for 8 hours. You can cancel earlier if you wish,
" + "and there will be no penalty because this is a part-time job."; } PlayerObject.prototype.finishWorkPartTime = function(sing=false) { - this.gainWorkExp(); - var company = Companies[this.companyName]; company.playerReputation += (this.workRepGained); @@ -903,51 +899,6 @@ PlayerObject.prototype.finishWorkPartTime = function(sing=false) { } /* Working for Faction */ -PlayerObject.prototype.finishFactionWork = function(cancelled, sing=false) { - this.gainWorkExp(); - - var faction = Factions[this.currentWorkFactionName]; - faction.playerReputation += (this.workRepGained); - - this.gainMoney(this.workMoneyGained); - - this.updateSkillLevels(); - - var txt = "You worked for your faction " + faction.name + " for a total of " + convertTimeMsToTimeElapsedString(this.timeWorked) + "

" + - "You earned a total of:
" + - "$" + formatNumber(this.workMoneyGained, 2) + "
" + - formatNumber(this.workRepGained, 4) + " reputation for the faction
" + - formatNumber(this.workHackExpGained, 4) + " hacking exp
" + - formatNumber(this.workStrExpGained, 4) + " strength exp
" + - formatNumber(this.workDefExpGained, 4) + " defense exp
" + - formatNumber(this.workDexExpGained, 4) + " dexterity exp
" + - formatNumber(this.workAgiExpGained, 4) + " agility exp
" + - formatNumber(this.workChaExpGained, 4) + " charisma exp
"; - if (!sing) {dialogBoxCreate(txt);} - - var mainMenu = document.getElementById("mainmenu-container"); - mainMenu.style.visibility = "visible"; - - this.isWorking = false; - - Engine.loadFactionContent(); - displayFactionContent(faction.name); - if (sing) { - var res="You worked for your faction " + faction.name + " for a total of " + convertTimeMsToTimeElapsedString(this.timeWorked) + ". " + - "You earned " + - formatNumber(this.workRepGained, 4) + " rep, " + - formatNumber(this.workHackExpGained, 4) + " hacking exp, " + - formatNumber(this.workStrExpGained, 4) + " str exp, " + - formatNumber(this.workDefExpGained, 4) + " def exp, " + - formatNumber(this.workDexExpGained, 4) + " dex exp, " + - formatNumber(this.workAgiExpGained, 4) + " agi exp, and " + - formatNumber(this.workChaExpGained, 4) + " cha exp."; - this.resetWorkStatus(); - return res; - } - this.resetWorkStatus(); -} - PlayerObject.prototype.startFactionWork = function(faction) { //Update reputation gain rate to account for faction favor var favorMult = 1 + (faction.favor / 100); @@ -1042,32 +993,19 @@ PlayerObject.prototype.workForFaction = function(numCycles) { this.workRepGainRate *= favorMult; this.workRepGainRate *= BitNodeMultipliers.FactionWorkRepGain; - this.workHackExpGained += this.workHackExpGainRate * numCycles; - this.workStrExpGained += this.workStrExpGainRate * numCycles; - this.workDefExpGained += this.workDefExpGainRate * numCycles; - this.workDexExpGained += this.workDexExpGainRate * numCycles; - this.workAgiExpGained += this.workAgiExpGainRate * numCycles; - this.workChaExpGained += this.workChaExpGainRate * numCycles; - this.workRepGained += this.workRepGainRate * numCycles; - this.workMoneyGained += this.workMoneyGainRate * numCycles; - - var cyclesPerSec = 1000 / Engine._idleSpeed; - + //Cap the number of cycles being processed to whatever would put you at limit (20 hours) + var overMax = false; + if (this.timeWorked + (Engine._idleSpeed * numCycles) >= CONSTANTS.MillisecondsPer20Hours) { + overMax = true; + numCycles = Math.round((CONSTANTS.MillisecondsPer20Hours - this.timeWorked) / Engine._idleSpeed); + } this.timeWorked += Engine._idleSpeed * numCycles; + this.processWorkEarnings(numCycles); + //If timeWorked == 20 hours, then finish. You can only work for the faction for 20 hours - if (this.timeWorked >= CONSTANTS.MillisecondsPer20Hours) { - var maxCycles = CONSTANTS.GameCyclesPer20Hours; - this.timeWorked = CONSTANTS.MillisecondsPer20Hours; - this.workHackExpGained = this.workHackExpGainRate * maxCycles; - this.workStrExpGained = this.workStrExpGainRate * maxCycles; - this.workDefExpGained = this.workDefExpGainRate * maxCycles; - this.workDexExpGained = this.workDexExpGainRate * maxCycles; - this.workAgiExpGained = this.workAgiExpGainRate * maxCycles; - this.workChaExpGained = this.workChaExpGainRate * maxCycles; - this.workRepGained = this.workRepGainRate * maxCycles; - this.workMoneyGained = this.workMoneyGainRate * maxCycles; - this.finishFactionWork(false); + if (overMax || this.timeWorked >= CONSTANTS.MillisecondsPer20Hours) { + return this.finishWork(false); } var txt = document.getElementById("work-in-progress-text"); @@ -1075,19 +1013,61 @@ PlayerObject.prototype.workForFaction = function(numCycles) { " (Current Faction Reputation: " + formatNumber(faction.playerReputation, 0) + "). " + "You have been doing this for " + convertTimeMsToTimeElapsedString(this.timeWorked) + "

" + "You have earned:

" + - "$" + formatNumber(this.workMoneyGained, 2) + " (" + formatNumber(this.workMoneyGainRate * cyclesPerSec, 2) + " / sec)

" + - formatNumber(this.workRepGained, 4) + " (" + formatNumber(this.workRepGainRate * cyclesPerSec, 4) + " / sec) reputation for this faction

" + - formatNumber(this.workHackExpGained, 4) + " (" + formatNumber(this.workHackExpGainRate * cyclesPerSec, 4) + " / sec) hacking exp

" + - formatNumber(this.workStrExpGained, 4) + " (" + formatNumber(this.workStrExpGainRate * cyclesPerSec, 4) + " / sec) strength exp
" + - formatNumber(this.workDefExpGained, 4) + " (" + formatNumber(this.workDefExpGainRate * cyclesPerSec, 4) + " / sec) defense exp
" + - formatNumber(this.workDexExpGained, 4) + " (" + formatNumber(this.workDexExpGainRate * cyclesPerSec, 4) + " / sec) dexterity exp
" + - formatNumber(this.workAgiExpGained, 4) + " (" + formatNumber(this.workAgiExpGainRate * cyclesPerSec, 4) + " / sec) agility exp

" + - formatNumber(this.workChaExpGained, 4) + " (" + formatNumber(this.workChaExpGainRate * cyclesPerSec, 4) + " / sec) charisma exp

" + + "$" + formatNumber(this.workMoneyGained, 2) + " (" + formatNumber(this.workMoneyGainRate * CYCLES_PER_SEC, 2) + " / sec)

" + + formatNumber(this.workRepGained, 4) + " (" + formatNumber(this.workRepGainRate * CYCLES_PER_SEC, 4) + " / sec) reputation for this faction

" + + formatNumber(this.workHackExpGained, 4) + " (" + formatNumber(this.workHackExpGainRate * CYCLES_PER_SEC, 4) + " / sec) hacking exp

" + + formatNumber(this.workStrExpGained, 4) + " (" + formatNumber(this.workStrExpGainRate * CYCLES_PER_SEC, 4) + " / sec) strength exp
" + + formatNumber(this.workDefExpGained, 4) + " (" + formatNumber(this.workDefExpGainRate * CYCLES_PER_SEC, 4) + " / sec) defense exp
" + + formatNumber(this.workDexExpGained, 4) + " (" + formatNumber(this.workDexExpGainRate * CYCLES_PER_SEC, 4) + " / sec) dexterity exp
" + + formatNumber(this.workAgiExpGained, 4) + " (" + formatNumber(this.workAgiExpGainRate * CYCLES_PER_SEC, 4) + " / sec) agility exp

" + + formatNumber(this.workChaExpGained, 4) + " (" + formatNumber(this.workChaExpGainRate * CYCLES_PER_SEC, 4) + " / sec) charisma exp

" + "You will automatically finish after working for 20 hours. You can cancel earlier if you wish.
" + "There is no penalty for cancelling earlier."; } +PlayerObject.prototype.finishFactionWork = function(cancelled, sing=false) { + var faction = Factions[this.currentWorkFactionName]; + faction.playerReputation += (this.workRepGained); + + this.gainMoney(this.workMoneyGained); + + this.updateSkillLevels(); + + var txt = "You worked for your faction " + faction.name + " for a total of " + convertTimeMsToTimeElapsedString(this.timeWorked) + "

" + + "You earned a total of:
" + + "$" + formatNumber(this.workMoneyGained, 2) + "
" + + formatNumber(this.workRepGained, 4) + " reputation for the faction
" + + formatNumber(this.workHackExpGained, 4) + " hacking exp
" + + formatNumber(this.workStrExpGained, 4) + " strength exp
" + + formatNumber(this.workDefExpGained, 4) + " defense exp
" + + formatNumber(this.workDexExpGained, 4) + " dexterity exp
" + + formatNumber(this.workAgiExpGained, 4) + " agility exp
" + + formatNumber(this.workChaExpGained, 4) + " charisma exp
"; + if (!sing) {dialogBoxCreate(txt);} + + var mainMenu = document.getElementById("mainmenu-container"); + mainMenu.style.visibility = "visible"; + + this.isWorking = false; + + Engine.loadFactionContent(); + displayFactionContent(faction.name); + if (sing) { + var res="You worked for your faction " + faction.name + " for a total of " + convertTimeMsToTimeElapsedString(this.timeWorked) + ". " + + "You earned " + + formatNumber(this.workRepGained, 4) + " rep, " + + formatNumber(this.workHackExpGained, 4) + " hacking exp, " + + formatNumber(this.workStrExpGained, 4) + " str exp, " + + formatNumber(this.workDefExpGained, 4) + " def exp, " + + formatNumber(this.workDexExpGained, 4) + " dex exp, " + + formatNumber(this.workAgiExpGained, 4) + " agi exp, and " + + formatNumber(this.workChaExpGained, 4) + " cha exp."; + this.resetWorkStatus(); + return res; + } + this.resetWorkStatus(); +} //Money gained per game cycle PlayerObject.prototype.getWorkMoneyGain = function() { @@ -1363,36 +1343,25 @@ PlayerObject.prototype.takeClass = function(numCycles) { this.timeWorked += Engine._idleSpeed * numCycles; var className = this.className; - this.workHackExpGained += this.workHackExpGainRate * numCycles; - this.workStrExpGained += this.workStrExpGainRate * numCycles; - this.workDefExpGained += this.workDefExpGainRate * numCycles; - this.workDexExpGained += this.workDexExpGainRate * numCycles; - this.workAgiExpGained += this.workAgiExpGainRate * numCycles; - this.workChaExpGained += this.workChaExpGainRate * numCycles; - this.workRepGained += this.workRepGainRate * numCycles; - this.workMoneyGained += this.workMoneyGainRate * numCycles; - this.workMoneyGained -= this.workMoneyLossRate * numCycles; - - var cyclesPerSec = 1000 / Engine._idleSpeed; + this.processWorkEarnings(numCycles); var txt = document.getElementById("work-in-progress-text"); txt.innerHTML = "You have been " + className + " for " + convertTimeMsToTimeElapsedString(this.timeWorked) + "

" + "This has cost you:
" + - "$" + formatNumber(this.workMoneyGained, 2) + " ($" + formatNumber(this.workMoneyLossRate * cyclesPerSec, 2) + " / sec)

" + + "$" + formatNumber(this.workMoneyGained, 2) + " ($" + formatNumber(this.workMoneyLossRate * CYCLES_PER_SEC, 2) + " / sec)

" + "You have gained:
" + - formatNumber(this.workHackExpGained, 4) + " (" + formatNumber(this.workHackExpGainRate * cyclesPerSec, 4) + " / sec) hacking exp
" + - formatNumber(this.workStrExpGained, 4) + " (" + formatNumber(this.workStrExpGainRate * cyclesPerSec, 4) + " / sec) strength exp
" + - formatNumber(this.workDefExpGained, 4) + " (" + formatNumber(this.workDefExpGainRate * cyclesPerSec, 4) + " / sec) defense exp
" + - formatNumber(this.workDexExpGained, 4) + " (" + formatNumber(this.workDexExpGainRate * cyclesPerSec, 4) + " / sec) dexterity exp
" + - formatNumber(this.workAgiExpGained, 4) + " (" + formatNumber(this.workAgiExpGainRate * cyclesPerSec, 4) + " / sec) agility exp
" + - formatNumber(this.workChaExpGained, 4) + " (" + formatNumber(this.workChaExpGainRate * cyclesPerSec, 4) + " / sec) charisma exp
" + + formatNumber(this.workHackExpGained, 4) + " (" + formatNumber(this.workHackExpGainRate * CYCLES_PER_SEC, 4) + " / sec) hacking exp
" + + formatNumber(this.workStrExpGained, 4) + " (" + formatNumber(this.workStrExpGainRate * CYCLES_PER_SEC, 4) + " / sec) strength exp
" + + formatNumber(this.workDefExpGained, 4) + " (" + formatNumber(this.workDefExpGainRate * CYCLES_PER_SEC, 4) + " / sec) defense exp
" + + formatNumber(this.workDexExpGained, 4) + " (" + formatNumber(this.workDexExpGainRate * CYCLES_PER_SEC, 4) + " / sec) dexterity exp
" + + formatNumber(this.workAgiExpGained, 4) + " (" + formatNumber(this.workAgiExpGainRate * CYCLES_PER_SEC, 4) + " / sec) agility exp
" + + formatNumber(this.workChaExpGained, 4) + " (" + formatNumber(this.workChaExpGainRate * CYCLES_PER_SEC, 4) + " / sec) charisma exp
" + "You may cancel at any time"; } //The 'sing' argument defines whether or not this function was called //through a Singularity Netscript function PlayerObject.prototype.finishClass = function(sing=false) { - this.gainWorkExp(); this.gainIntelligenceExp(CONSTANTS.IntelligenceClassBaseExpGain * Math.round(this.timeWorked / 1000)); if (this.workMoneyGained > 0) { @@ -1567,7 +1536,12 @@ PlayerObject.prototype.finishCrime = function(cancelled) { } } - this.gainWorkExp(); + this.gainHackingExp(this.workHackExpGained); + this.gainStrengthExp(this.workStrExpGained); + this.gainDefenseExp(this.workDefExpGained); + this.gainDexterityExp(this.workDexExpGained); + this.gainAgilityExp(this.workAgiExpGained); + this.gainCharismaExp(this.workChaExpGained); } this.committingCrimeThruSingFn = false; this.singFnCrimeWorkerScript = null;