Merge pull request #813 from danielyxie/dev

v0.49.0
This commit is contained in:
hydroflame 2021-03-11 20:41:05 -05:00 committed by GitHub
commit 640795dbe9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
93 changed files with 1659 additions and 1861 deletions

@ -359,3 +359,38 @@ a:visited {
.smallfont { .smallfont {
font-size: $defaultFontSize * 0.8125; font-size: $defaultFontSize * 0.8125;
} }
.optionCheckbox {
filter: invert(1) sepia(1) hue-rotate(41deg) brightness(100%) saturate(10);
margin: 5px;
float: right;
}
.optionRange {
-webkit-appearance: none;
background: #777;
outline: none;
opacity: 0.7;
height: 10px;
-webkit-transition: .2s;
transition: opacity .2s;
margin: 3px;
}
.optionRange::-webkit-slider-thumb {
-webkit-appearance: none;
appearance: none;
width: 10px;
height: 10px;
background: var(--my-font-color);
cursor: pointer;
}
.optionRange::-moz-range-thumb {
width: 10px;
height: 10px;
background: var(--my-font-color);
cursor: pointer;
}

File diff suppressed because one or more lines are too long

@ -1,2 +1,2 @@
!function(n){function t(t){for(var e,i,f=t[0],c=t[1],l=t[2],p=0,s=[];p<f.length;p++)i=f[p],u[i]&&s.push(u[i][0]),u[i]=0;for(e in c)Object.prototype.hasOwnProperty.call(c,e)&&(n[e]=c[e]);for(a&&a(t);s.length;)s.shift()();return r.push.apply(r,l||[]),o()}function o(){for(var n,t=0;t<r.length;t++){for(var o=r[t],e=!0,f=1;f<o.length;f++){var c=o[f];0!==u[c]&&(e=!1)}e&&(r.splice(t--,1),n=i(i.s=o[0]))}return n}var e={},u={1:0},r=[];function i(t){if(e[t])return e[t].exports;var o=e[t]={i:t,l:!1,exports:{}};return n[t].call(o.exports,o,o.exports,i),o.l=!0,o.exports}i.m=n,i.c=e,i.d=function(n,t,o){i.o(n,t)||Object.defineProperty(n,t,{enumerable:!0,get:o})},i.r=function(n){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(n,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(n,"__esModule",{value:!0})},i.t=function(n,t){if(1&t&&(n=i(n)),8&t)return n;if(4&t&&"object"==typeof n&&n&&n.__esModule)return n;var o=Object.create(null);if(i.r(o),Object.defineProperty(o,"default",{enumerable:!0,value:n}),2&t&&"string"!=typeof n)for(var e in n)i.d(o,e,function(t){return n[t]}.bind(null,e));return o},i.n=function(n){var t=n&&n.__esModule?function(){return n.default}:function(){return n};return i.d(t,"a",t),t},i.o=function(n,t){return Object.prototype.hasOwnProperty.call(n,t)},i.p="";var f=window.webpackJsonp=window.webpackJsonp||[],c=f.push.bind(f);f.push=t,f=f.slice();for(var l=0;l<f.length;l++)t(f[l]);var a=c;r.push([363,0]),o()}({306:function(n,t,o){},308:function(n,t,o){},310:function(n,t,o){},312:function(n,t,o){},314:function(n,t,o){},316:function(n,t,o){},318:function(n,t,o){},320:function(n,t,o){},322:function(n,t,o){},324:function(n,t,o){},326:function(n,t,o){},328:function(n,t,o){},330:function(n,t,o){},332:function(n,t,o){},334:function(n,t,o){},336:function(n,t,o){},338:function(n,t,o){},340:function(n,t,o){},342:function(n,t,o){},344:function(n,t,o){},346:function(n,t,o){},348:function(n,t,o){},350:function(n,t,o){},352:function(n,t,o){},354:function(n,t,o){},356:function(n,t,o){},358:function(n,t,o){},360:function(n,t,o){},363:function(n,t,o){"use strict";o.r(t);o(362),o(360),o(358),o(356),o(354),o(352),o(350),o(348),o(346),o(344),o(342),o(340),o(338),o(336),o(334),o(332),o(330),o(328),o(326),o(324),o(322),o(320),o(318),o(316),o(314),o(312),o(310),o(308),o(306)}}); !function(n){function t(t){for(var e,i,f=t[0],c=t[1],l=t[2],p=0,s=[];p<f.length;p++)i=f[p],u[i]&&s.push(u[i][0]),u[i]=0;for(e in c)Object.prototype.hasOwnProperty.call(c,e)&&(n[e]=c[e]);for(a&&a(t);s.length;)s.shift()();return r.push.apply(r,l||[]),o()}function o(){for(var n,t=0;t<r.length;t++){for(var o=r[t],e=!0,f=1;f<o.length;f++){var c=o[f];0!==u[c]&&(e=!1)}e&&(r.splice(t--,1),n=i(i.s=o[0]))}return n}var e={},u={1:0},r=[];function i(t){if(e[t])return e[t].exports;var o=e[t]={i:t,l:!1,exports:{}};return n[t].call(o.exports,o,o.exports,i),o.l=!0,o.exports}i.m=n,i.c=e,i.d=function(n,t,o){i.o(n,t)||Object.defineProperty(n,t,{enumerable:!0,get:o})},i.r=function(n){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(n,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(n,"__esModule",{value:!0})},i.t=function(n,t){if(1&t&&(n=i(n)),8&t)return n;if(4&t&&"object"==typeof n&&n&&n.__esModule)return n;var o=Object.create(null);if(i.r(o),Object.defineProperty(o,"default",{enumerable:!0,value:n}),2&t&&"string"!=typeof n)for(var e in n)i.d(o,e,function(t){return n[t]}.bind(null,e));return o},i.n=function(n){var t=n&&n.__esModule?function(){return n.default}:function(){return n};return i.d(t,"a",t),t},i.o=function(n,t){return Object.prototype.hasOwnProperty.call(n,t)},i.p="";var f=window.webpackJsonp=window.webpackJsonp||[],c=f.push.bind(f);f.push=t,f=f.slice();for(var l=0;l<f.length;l++)t(f[l]);var a=c;r.push([364,0]),o()}({307:function(n,t,o){},309:function(n,t,o){},311:function(n,t,o){},313:function(n,t,o){},315:function(n,t,o){},317:function(n,t,o){},319:function(n,t,o){},321:function(n,t,o){},323:function(n,t,o){},325:function(n,t,o){},327:function(n,t,o){},329:function(n,t,o){},331:function(n,t,o){},333:function(n,t,o){},335:function(n,t,o){},337:function(n,t,o){},339:function(n,t,o){},341:function(n,t,o){},343:function(n,t,o){},345:function(n,t,o){},347:function(n,t,o){},349:function(n,t,o){},351:function(n,t,o){},353:function(n,t,o){},355:function(n,t,o){},357:function(n,t,o){},359:function(n,t,o){},361:function(n,t,o){},364:function(n,t,o){"use strict";o.r(t);o(363),o(361),o(359),o(357),o(355),o(353),o(351),o(349),o(347),o(345),o(343),o(341),o(339),o(337),o(335),o(333),o(331),o(329),o(327),o(325),o(323),o(321),o(319),o(317),o(315),o(313),o(311),o(309),o(307)}});
//# sourceMappingURL=engineStyle.bundle.js.map //# sourceMappingURL=engineStyle.bundle.js.map

29
dist/engineStyle.css vendored

@ -356,6 +356,35 @@ a:visited {
.smallfont { .smallfont {
font-size: 13px; } font-size: 13px; }
.optionCheckbox {
filter: invert(1) sepia(1) hue-rotate(41deg) brightness(100%) saturate(10);
margin: 5px;
float: right; }
.optionRange {
-webkit-appearance: none;
background: #777;
outline: none;
opacity: 0.7;
height: 10px;
-webkit-transition: .2s;
transition: opacity .2s;
margin: 3px; }
.optionRange::-webkit-slider-thumb {
-webkit-appearance: none;
appearance: none;
width: 10px;
height: 10px;
background: var(--my-font-color);
cursor: pointer; }
.optionRange::-moz-range-thumb {
width: 10px;
height: 10px;
background: var(--my-font-color);
cursor: pointer; }
/* COLORS */ /* COLORS */
/* Attributes */ /* Attributes */
/* Styling for tooltip-style elements */ /* Styling for tooltip-style elements */

22
dist/vendor.bundle.js vendored

File diff suppressed because one or more lines are too long

@ -3,15 +3,44 @@
Changelog Changelog
========= =========
v0.49.0 - 2021-03-11 Source-File -1 (hydroflame)
-------
v0.48.0 - ASCII - 2020-03-07 **Source-File -1**
* For advanced players: The game now embraces exploits and will reward
players for doing so.
**Gang**
* ascension is less effective as the ascension multiplier goes up.
* territory gain scales with power difference.
**Netscript**
* 'gang.getEquipmentStats' returns the stats of the equipment.
* 'gang.getTaskStats' returns the stats of a task.
* 'getCrimeStats' returns the stats of a crime.
* Crashes should now print the ns stack trace.
* Log messages are now more consistent.
* 'softReset' now accepts a callback script like 'installAugmentations'
**Misc.**
* Minor formatting under Hacking>Active Scripts
* option menu colors now match the rest of the game, kinda.
v0.48.0 - ASCII - 2021-03-07 (hydroflame)
------- -------
**ASCII** **ASCII**
* Travel Agency now displays a world map * Travel Agency now displays a world map
* Cities are now top view of metro station maps * Cities are now top view of metro station maps
**Netscript** **Netscript**
* 'softReset' is a new netscript function that performs a soft reset * 'softReset' is a new netscript function that performs a soft reset
regardless of if the player has bought augmentations or not. regardless of if the player has bought augmentations or not.
* 'getAugmentationStats' is a new netscript function that returns the stats of * 'getAugmentationStats' is a new netscript function that returns the stats of
@ -22,11 +51,13 @@ v0.48.0 - ASCII - 2020-03-07
* 'hacknet.maxNumNodes' returns the maximum number of hacknet nodes. * 'hacknet.maxNumNodes' returns the maximum number of hacknet nodes.
**Bladeburner** **Bladeburner**
* Current stamina will scale as max stamina increases, this prevents players * Current stamina will scale as max stamina increases, this prevents players
from having very high penalty when they gain huge amount of exp at the from having very high penalty when they gain huge amount of exp at the
start of a reset. start of a reset.
**Misc.** **Misc.**
* Fixed an issue where SF3 was listed as infinitly repeatable and SF12 as * Fixed an issue where SF3 was listed as infinitly repeatable and SF12 as
having a limit of 3. having a limit of 3.
* Fixed an issue where the gang equipment screen would freeze the game if a * Fixed an issue where the gang equipment screen would freeze the game if a

@ -2,6 +2,7 @@ getActionAutolevel() Netscript Function
======================================= =======================================
.. js:function:: getActionAutolevel(type, name) .. js:function:: getActionAutolevel(type, name)
:RAM cost: 4 GB :RAM cost: 4 GB
:param string type: Type of action. See :ref:`bladeburner_action_types` :param string type: Type of action. See :ref:`bladeburner_action_types`

@ -2,6 +2,7 @@ getActionCountRemaining() Netscript Function
============================================ ============================================
.. js:function:: getActionCountRemaining(type, name) .. js:function:: getActionCountRemaining(type, name)
:RAM cost: 4 GB :RAM cost: 4 GB
:param string type: Type of action. See :ref:`bladeburner_action_types` :param string type: Type of action. See :ref:`bladeburner_action_types`

@ -2,6 +2,7 @@ getActionCurrentLevel() Netscript Function
========================================== ==========================================
.. js:function:: getActionCurrentLevel(type, name) .. js:function:: getActionCurrentLevel(type, name)
:RAM cost: 4 GB :RAM cost: 4 GB
:param string type: Type of action. See :ref:`bladeburner_action_types` :param string type: Type of action. See :ref:`bladeburner_action_types`

@ -2,6 +2,7 @@ getActionEstimatedSuccessChance() Netscript Function
==================================================== ====================================================
.. js:function:: getActionEstimatedSuccessChance(type, name) .. js:function:: getActionEstimatedSuccessChance(type, name)
:RAM cost: 4 GB :RAM cost: 4 GB
:param string type: Type of action. See :ref:`bladeburner_action_types` :param string type: Type of action. See :ref:`bladeburner_action_types`

@ -2,6 +2,7 @@ getActionMaxLevel() Netscript Function
====================================== ======================================
.. js:function:: getActionMaxLevel(type, name) .. js:function:: getActionMaxLevel(type, name)
:RAM cost: 4 GB :RAM cost: 4 GB
:param string type: Type of action. See :ref:`bladeburner_action_types` :param string type: Type of action. See :ref:`bladeburner_action_types`

@ -2,6 +2,7 @@ getActionRepGain() Netscript Function
===================================== =====================================
.. js:function:: getActionRepGain(type, name[, level=current level]) .. js:function:: getActionRepGain(type, name[, level=current level])
:RAM cost: 4 GB :RAM cost: 4 GB
:param string type: Type of action. See :ref:`bladeburner_action_types` :param string type: Type of action. See :ref:`bladeburner_action_types`

@ -2,6 +2,7 @@ getActionTime() Netscript Function
================================== ==================================
.. js:function:: getActionTime(type, name) .. js:function:: getActionTime(type, name)
:RAM cost: 4 GB :RAM cost: 4 GB
:param string type: Type of action. See :ref:`bladeburner_action_types` :param string type: Type of action. See :ref:`bladeburner_action_types`

@ -2,6 +2,7 @@ getBlackOpNames() Netscript Function
==================================== ====================================
.. js:function:: getBlackOpNames() .. js:function:: getBlackOpNames()
:RAM cost: 0.4 GB :RAM cost: 0.4 GB
Returns an array of strings containing the names of all Bladeburner Black Ops Returns an array of strings containing the names of all Bladeburner Black Ops

@ -2,6 +2,7 @@ getBlackOpRank() Netscript Function
==================================== ====================================
.. js:function:: getBlackOpRank(name) .. js:function:: getBlackOpRank(name)
:RAM cost: 2 GB :RAM cost: 2 GB
:param string name: name of the BlackOp. Must be an exact match. :param string name: name of the BlackOp. Must be an exact match.

@ -2,6 +2,7 @@ getBonusTime() Netscript Function
================================= =================================
.. js:function:: getBonusTime() .. js:function:: getBonusTime()
:RAM cost: 0 GB :RAM cost: 0 GB
Returns the amount of accumulated "bonus time" (seconds) for the Bladeburner mechanic. Returns the amount of accumulated "bonus time" (seconds) for the Bladeburner mechanic.

@ -2,6 +2,7 @@ getCity() Netscript Function
============================ ============================
.. js:function:: getCity() .. js:function:: getCity()
:RAM cost: 4 GB :RAM cost: 4 GB
Returns the city that the player is currently in (for Bladeburner). Returns the city that the player is currently in (for Bladeburner).

@ -2,6 +2,7 @@ getCityChaos() Netscript Function
================================= =================================
.. js:function:: getCityChaos(cityName) .. js:function:: getCityChaos(cityName)
:RAM cost: 4 GB :RAM cost: 4 GB
:param string cityName: Name of city. Case-sensitive :param string cityName: Name of city. Case-sensitive

@ -2,6 +2,7 @@ getCityEstimatedCommunities() Netscript Function
================================================ ================================================
.. js:function:: getCityEstimatedCommunities(cityName) .. js:function:: getCityEstimatedCommunities(cityName)
:RAM cost: 4 GB :RAM cost: 4 GB
:param string cityName: Name of city. Case-sensitive :param string cityName: Name of city. Case-sensitive

@ -2,6 +2,7 @@ getCityEstimatedPopulation() Netscript Function
=============================================== ===============================================
.. js:function:: getCityEstimatedPopulation(cityName) .. js:function:: getCityEstimatedPopulation(cityName)
:RAM cost: 4 GB :RAM cost: 4 GB
:param string cityName: Name of city. Case-sensitive :param string cityName: Name of city. Case-sensitive

@ -2,6 +2,7 @@ getContractNames() Netscript Function
===================================== =====================================
.. js:function:: getContractNames() .. js:function:: getContractNames()
:RAM cost: 0.4 GB :RAM cost: 0.4 GB
Returns an array of strings containing the names of all Bladeburner contracts Returns an array of strings containing the names of all Bladeburner contracts

@ -2,6 +2,7 @@ getCurrentAction() Netscript Function
===================================== =====================================
.. js:function:: getCurrentAction() .. js:function:: getCurrentAction()
:RAM cost: 1 GB :RAM cost: 1 GB
Returns an object that represents the player's current Bladeburner action:: Returns an object that represents the player's current Bladeburner action::

@ -2,6 +2,7 @@ getGeneralActionNames() Netscript Function
========================================== ==========================================
.. js:function:: getGeneralActionNames() .. js:function:: getGeneralActionNames()
:RAM cost: 0.4 GB :RAM cost: 0.4 GB
Returns an array of strings containing the names of all general Bladeburner actions Returns an array of strings containing the names of all general Bladeburner actions

@ -2,6 +2,7 @@ getOperationNames() Netscript Function
====================================== ======================================
.. js:function:: getOperationNames() .. js:function:: getOperationNames()
:RAM cost: 0.4 GB :RAM cost: 0.4 GB
Returns an array of strings containing the names of all Bladeburner operations Returns an array of strings containing the names of all Bladeburner operations

@ -2,6 +2,7 @@ getRank() Netscript Function
============================ ============================
.. js:function:: getRank() .. js:function:: getRank()
:RAM cost: 4 GB :RAM cost: 4 GB
Returns the player's Bladeburner Rank Returns the player's Bladeburner Rank

@ -2,6 +2,7 @@ getSkillLevel() Netscript Function
================================== ==================================
.. js:function:: getSkillLevel(skillName="") .. js:function:: getSkillLevel(skillName="")
:RAM cost: 4 GB :RAM cost: 4 GB
:param string skillName: Name of skill. Case-sensitive and must be an exact match :param string skillName: Name of skill. Case-sensitive and must be an exact match

@ -2,6 +2,7 @@ getSkillNames() Netscript Function
================================== ==================================
.. js:function:: getSkillNames() .. js:function:: getSkillNames()
:RAM cost: 0.4 GB :RAM cost: 0.4 GB
Returns an array of strings containing the names of all Bladeburner skills Returns an array of strings containing the names of all Bladeburner skills

@ -2,6 +2,7 @@ getSkillPoints() Netscript Function
=================================== ===================================
.. js:function:: getSkillPoints() .. js:function:: getSkillPoints()
:RAM cost: 4 GB :RAM cost: 4 GB
Returns the number of Bladeburner skill points you have Returns the number of Bladeburner skill points you have

@ -2,6 +2,7 @@ getSkillUpgradeCost() Netscript Function
======================================== ========================================
.. js:function:: getSkillUpgradeCost(skillName="") .. js:function:: getSkillUpgradeCost(skillName="")
:RAM cost: 4 GB :RAM cost: 4 GB
:param string skillName: Name of skill. Case-sensitive and must be an exact match :param string skillName: Name of skill. Case-sensitive and must be an exact match

@ -2,6 +2,7 @@ getStamina() Netscript Function
=============================== ===============================
.. js:function:: getStamina() .. js:function:: getStamina()
:RAM cost: 4 GB :RAM cost: 4 GB
Returns an array with two elements: Returns an array with two elements:

@ -2,6 +2,7 @@ getTeamSize() Netscript Function
================================ ================================
.. js:function:: getTeamSize(type, name) .. js:function:: getTeamSize(type, name)
:RAM cost: 4 GB :RAM cost: 4 GB
:param string type: Type of action. See :ref:`bladeburner_action_types` :param string type: Type of action. See :ref:`bladeburner_action_types`

@ -2,6 +2,7 @@ joinBladeburnerDivision() Netscript Function
============================================ ============================================
.. js:function:: joinBladeburnerDivision() .. js:function:: joinBladeburnerDivision()
:RAM cost: 4 GB :RAM cost: 4 GB
Attempts to join the Bladeburner division. Attempts to join the Bladeburner division.

@ -2,6 +2,7 @@ joinBladeburnerFaction() Netscript Function
=========================================== ===========================================
.. js:function:: joinBladeburnerFaction() .. js:function:: joinBladeburnerFaction()
:RAM cost: 4 GB :RAM cost: 4 GB
Attempts to join the Bladeburner faction. Attempts to join the Bladeburner faction.

@ -2,6 +2,7 @@ setActionAutolevel() Netscript Function
======================================= =======================================
.. js:function:: setActionAutolevel(type, name, autoLevel) .. js:function:: setActionAutolevel(type, name, autoLevel)
:RAM cost: 4 GB :RAM cost: 4 GB
:param string type: Type of action. See :ref:`bladeburner_action_types` :param string type: Type of action. See :ref:`bladeburner_action_types`

@ -2,6 +2,7 @@ setActionLevel() Netscript Function
=================================== ===================================
.. js:function:: setActionLevel(type, name, level) .. js:function:: setActionLevel(type, name, level)
:RAM cost: 4 GB :RAM cost: 4 GB
:param string type: Type of action. See :ref:`bladeburner_action_types` :param string type: Type of action. See :ref:`bladeburner_action_types`

@ -2,6 +2,7 @@ setTeamSize() Netscript Function
================================ ================================
.. js:function:: setTeamSize(type, name, size) .. js:function:: setTeamSize(type, name, size)
:RAM cost: 4 GB :RAM cost: 4 GB
:param string type: Type of action. See :ref:`bladeburner_action_types` :param string type: Type of action. See :ref:`bladeburner_action_types`

@ -2,6 +2,7 @@ startAction() Netscript Function
================================ ================================
.. js:function:: startAction(type, name) .. js:function:: startAction(type, name)
:RAM cost: 4 GB :RAM cost: 4 GB
:param string type: Type of action. See :ref:`bladeburner_action_types` :param string type: Type of action. See :ref:`bladeburner_action_types`

@ -2,6 +2,7 @@ stopBladeburnerAction() Netscript Function
========================================== ==========================================
.. js:function:: stopBladeburnerAction() .. js:function:: stopBladeburnerAction()
:RAM cost: 2 GB :RAM cost: 2 GB
Stops the current Bladeburner action Stops the current Bladeburner action

@ -2,6 +2,7 @@ switchCity() Netscript Function
=============================== ===============================
.. js:function:: switchCity(cityName) .. js:function:: switchCity(cityName)
:RAM cost: 4 GB :RAM cost: 4 GB
:param string cityName: Name of city :param string cityName: Name of city

@ -2,6 +2,7 @@ upgradeSkill() Netscript Function
================================= =================================
.. js:function:: upgradeSkill(skillName) .. js:function:: upgradeSkill(skillName)
:RAM cost: 4 GB :RAM cost: 4 GB
:param string skillName: Name of Skill to be upgraded. Case-sensitive and must be an exact match :param string skillName: Name of Skill to be upgraded. Case-sensitive and must be an exact match

@ -0,0 +1,17 @@
getEquipmentStats() Netscript Function
=====================================
.. js:function:: getEquipmentStats(equipName)
:RAM cost: 2 GB
:param string equipName: Name of equipment
:returns: A dictionary containing the stats of the equipment.
Get the specified equipment stats.
{
"str":1.04,
"def":1.04
}

@ -0,0 +1,35 @@
getTaskStats() Netscript Function
======================================
.. js:function:: getTaskStats(taskName)
:RAM cost: 1 GB
:param string name: Name of the task.
Get the stats of a gang member stats. This is typically used to evaluate
which action should be executed next.
{
name: Terrorism,
desc: "Assign this gang member to commit acts of terrorism
Greatly increases respect - Greatly increases wanted level - Scales heavily with territory",
isHacking: false,
isCombat: true,
baseRespect: 0.01,
baseWanted: 6,
baseMoney: 0,
hackWeight: 20,
strWeight: 20,
defWeight: 20,
dexWeight: 20,
agiWeight: 0,
chaWeight: 20,
difficulty: 36,
territory: {
money: 1,
respect: 2,
wanted: 2
}
}

@ -0,0 +1,37 @@
getCrimeStats() Netscript Function
===================================
.. js:function:: getCrimeStats(crime)
:RAM cost: 5 GB
:param string crime:
Name of crime. Not case-sensitive. This argument is fairlyn lenient in terms of what inputs it accepts.
Check the documentation for the *commitCrime()* function for a list of example inputs.
If you are not in BitNode-4, then you must have Level 3 of Source-File 4 in order to use this function.
:return The stats of the crime
{
"difficulty": 0.2,
"karma": 0.25,
"kills": 0,
"money": 36000,
"name": "Mug",
"time": 4000,
"type": "mug someone",
"hacking_success_weight": 0,
"strength_success_weight": 1.5,
"defense_success_weight": 0.5,
"dexterity_success_weight": 1.5,
"agility_success_weight": 0.5,
"charisma_success_weight": 0,
"hacking_exp": 0,
"strength_exp": 3,
"defense_exp": 3,
"dexterity_exp": 3,
"agility_exp": 3,
"charisma_exp": 0,
"intelligence_exp": 0
}

@ -393,7 +393,7 @@
<div id="game-options-left-panel"> <div id="game-options-left-panel">
<!-- Netscript execution time --> <!-- Netscript execution time -->
<fieldset> <fieldset>
<label for="settingsNSExecTimeRangeVal" class="tooltip">Netscript exec time: <label for="settingsNSExecTimeRangeVal" class="tooltip">Netscript exec time:&nbsp;
<span class="tooltiptext"> <span class="tooltiptext">
The minimum number of milliseconds it takes to execute an operation in Netscript. 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. Setting this too low can result in poor performance if you have many scripts running.
@ -401,13 +401,13 @@
</span> </span>
</label> </label>
<input type="range" max="100" min="10" step="1" name="settingsNSExecTimeRangeVal" id="settingsNSExecTimeRangeVal" value="25"/> <input class="optionRange" type="range" max="100" min="10" step="1" name="settingsNSExecTimeRangeVal" id="settingsNSExecTimeRangeVal" value="25"/>
<em id="settingsNSExecTimeRangeValLabel" style="font-style: normal;"></em> <em id="settingsNSExecTimeRangeValLabel" style="font-style: normal;"></em>
</fieldset> </fieldset>
<!-- Log capacity --> <!-- Log capacity -->
<fieldset> <fieldset>
<label for="settingsNSLogRangeVal" class="tooltip">Netscript log size: <label for="settingsNSLogRangeVal" class="tooltip">Netscript log size:&nbsp;&nbsp;
<span class="tooltiptext"> <span class="tooltiptext">
The maximum number of lines a script's logs can hold. Setting this too high The maximum number of lines a script's logs can hold. Setting this too high
can cause the game to use a lot of memory if you have many scripts running. can cause the game to use a lot of memory if you have many scripts running.
@ -415,13 +415,13 @@
</span> </span>
</label> </label>
<input type="range" max="100" min="20" step="1" name="settingsNSLogRangeVal" id="settingsNSLogRangeVal" value="50"/> <input class="optionRange" type="range" max="100" min="20" step="1" name="settingsNSLogRangeVal" id="settingsNSLogRangeVal" value="50"/>
<em id="settingsNSLogRangeValLabel" style="font-style: normal;"></em> <em id="settingsNSLogRangeValLabel" style="font-style: normal;"></em>
</fieldset> </fieldset>
<!-- Port capacity --> <!-- Port capacity -->
<fieldset> <fieldset>
<label for="settingsNSPortRangeVal" class="tooltip">Netscript port size: <label for="settingsNSPortRangeVal" class="tooltip">Netscript port size:&nbsp;
<span class="tooltiptext"> <span class="tooltiptext">
The maximum number of entries that can be written to a port using Netscript's The maximum number of entries that can be written to a port using Netscript's
write() function. Setting this too high can cause the game to use a lot of memory. write() function. Setting this too high can cause the game to use a lot of memory.
@ -429,19 +429,19 @@
</span> </span>
</label> </label>
<input type="range" max="100" min="20" step="1" name="settingsNSPortRangeVal" id="settingsNSPortRangeVal" value="50"/> <input class="optionRange" type="range" max="100" min="20" step="1" name="settingsNSPortRangeVal" id="settingsNSPortRangeVal" value="50"/>
<em id="settingsNSPortRangeValLabel" style="font-style: normal;"></em> <em id="settingsNSPortRangeValLabel" style="font-style: normal;"></em>
</fieldset> </fieldset>
<!-- Autosave Interval --> <!-- Autosave Interval -->
<fieldset> <fieldset>
<label for="settingsAutosaveIntervalVal" class="tooltip">Autosave Interval <label for="settingsAutosaveIntervalVal" class="tooltip">Autosave Interval:&nbsp;&nbsp;&nbsp;
<span class="tooltiptext"> <span class="tooltiptext">
The time (in seconds) between each autosave. Set to 0 to disable autosave. The time (in seconds) between each autosave. Set to 0 to disable autosave.
</span> </span>
</label> </label>
<input type="range" max="600" min="0" step="1" name="settingsAutosaveIntervalVal" id="settingsAutosaveIntervalVal" value="60"/> <input class="optionRange" type="range" max="600" min="0" step="1" name="settingsAutosaveIntervalVal" id="settingsAutosaveIntervalVal" value="60"/>
<em id="settingsAutosaveIntervalValLabel" style="font-style: normal;"></em> <em id="settingsAutosaveIntervalValLabel" style="font-style: normal;"></em>
</fieldset> </fieldset>
@ -454,7 +454,7 @@
and can be viewed with the 'cat' Terminal command. and can be viewed with the 'cat' Terminal command.
</span> </span>
</label> </label>
<input type="checkbox" name="settingsSuppressMessages" id="settingsSuppressMessages"> <input class="optionCheckbox" type="checkbox" name="settingsSuppressMessages" id="settingsSuppressMessages">
</fieldset> </fieldset>
<!-- Suppress faction invites --> <!-- Suppress faction invites -->
@ -465,7 +465,7 @@
on the screen. Your outstanding faction invites can be viewed in the 'Factions' page. on the screen. Your outstanding faction invites can be viewed in the 'Factions' page.
</span> </span>
</label> </label>
<input type="checkbox" name="settingsSuppressFactionInvites" id="settingsSuppressFactionInvites"> <input class="optionCheckbox" type="checkbox" name="settingsSuppressFactionInvites" id="settingsSuppressFactionInvites">
</fieldset> </fieldset>
<!-- Suppress travel confirmation --> <!-- Suppress travel confirmation -->
@ -475,7 +475,7 @@
If this is set, the confirmation message before traveling will not show up. You will automatically be deducted the travel cost as soon as you click. If this is set, the confirmation message before traveling will not show up. You will automatically be deducted the travel cost as soon as you click.
</span> </span>
</label> </label>
<input type="checkbox" name="settingsSuppressTravelConfirmation" id="settingsSuppressTravelConfirmation"> <input class="optionCheckbox" type="checkbox" name="settingsSuppressTravelConfirmation" id="settingsSuppressTravelConfirmation">
</fieldset> </fieldset>
@ -486,7 +486,7 @@
If this is set, the confirmation message before buying augmentation will not show up. If this is set, the confirmation message before buying augmentation will not show up.
</span> </span>
</label> </label>
<input type="checkbox" name="settingsSuppressBuyAugmentationConfirmation" id="settingsSuppressBuyAugmentationConfirmation"> <input class="optionCheckbox" type="checkbox" name="settingsSuppressBuyAugmentationConfirmation" id="settingsSuppressBuyAugmentationConfirmation">
</fieldset> </fieldset>
<!-- Hospitalization Popup --> <!-- Hospitalization Popup -->
@ -496,7 +496,7 @@
If this is set, a popup message will no longer be shown when you are hospitalized after taking too much damage. If this is set, a popup message will no longer be shown when you are hospitalized after taking too much damage.
</span> </span>
</label> </label>
<input type="checkbox" name="settingsSuppressHospitalizationPopup" id="settingsSuppressHospitalizationPopup"> <input class="optionCheckbox" type="checkbox" name="settingsSuppressHospitalizationPopup" id="settingsSuppressHospitalizationPopup">
</fieldset> </fieldset>
<!-- Disable Terminal and Navigation Shortcuts --> <!-- Disable Terminal and Navigation Shortcuts -->
@ -508,7 +508,7 @@
and the "Save and Close (Ctrl + b)" hotkey in the Text Editor. and the "Save and Close (Ctrl + b)" hotkey in the Text Editor.
</span> </span>
</label> </label>
<input type="checkbox" name="settingsDisableHotkeys" id="settingsDisableHotkeys"> <input class="optionCheckbox" type="checkbox" name="settingsDisableHotkeys" id="settingsDisableHotkeys">
</fieldset> </fieldset>
<!-- Locale for displaying numbers --> <!-- Locale for displaying numbers -->

190
package-lock.json generated

@ -1,11 +1,11 @@
{ {
"name": "bitburner", "name": "bitburner",
"version": "0.47.0", "version": "0.47.3",
"lockfileVersion": 2, "lockfileVersion": 2,
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"version": "0.47.0", "version": "0.47.3",
"hasInstallScript": true, "hasInstallScript": true,
"license": "SEE LICENSE IN license.txt", "license": "SEE LICENSE IN license.txt",
"dependencies": { "dependencies": {
@ -67,7 +67,7 @@
"json5": "^1.0.1", "json5": "^1.0.1",
"less": "^3.9.0", "less": "^3.9.0",
"less-loader": "^4.1.0", "less-loader": "^4.1.0",
"lodash": "^4.17.10", "lodash": "^4.17.21",
"mini-css-extract-plugin": "^0.4.1", "mini-css-extract-plugin": "^0.4.1",
"mkdirp": "^0.5.1", "mkdirp": "^0.5.1",
"mocha": "^6.1.4", "mocha": "^6.1.4",
@ -1225,6 +1225,11 @@
"integrity": "sha512-jp/uFnooOiO+L211eZOoSyzpOITMXx1rBITauYykG3BRYPu8h0UcxsPNB04RR5vo4Tyz3+ay17tR6JVf9qzYWg==", "integrity": "sha512-jp/uFnooOiO+L211eZOoSyzpOITMXx1rBITauYykG3BRYPu8h0UcxsPNB04RR5vo4Tyz3+ay17tR6JVf9qzYWg==",
"dev": true "dev": true
}, },
"node_modules/async/node_modules/lodash": {
"version": "4.17.10",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.10.tgz",
"integrity": "sha512-UejweD1pDoXu+AD825lWwp4ZGtSwgnpZxb3JDViD7StjQz+Nb/6l093lx4OQ0foGWNRoc19mWy7BzL+UAK2iVg=="
},
"node_modules/asynckit": { "node_modules/asynckit": {
"version": "0.4.0", "version": "0.4.0",
"resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
@ -1501,6 +1506,12 @@
"platform": "1.3.5" "platform": "1.3.5"
} }
}, },
"node_modules/benchmark/node_modules/lodash": {
"version": "4.17.10",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.10.tgz",
"integrity": "sha512-UejweD1pDoXu+AD825lWwp4ZGtSwgnpZxb3JDViD7StjQz+Nb/6l093lx4OQ0foGWNRoc19mWy7BzL+UAK2iVg==",
"dev": true
},
"node_modules/big.js": { "node_modules/big.js": {
"version": "3.2.0", "version": "3.2.0",
"resolved": "https://registry.npmjs.org/big.js/-/big.js-3.2.0.tgz", "resolved": "https://registry.npmjs.org/big.js/-/big.js-3.2.0.tgz",
@ -4379,6 +4390,12 @@
"js-yaml": "bin/js-yaml.js" "js-yaml": "bin/js-yaml.js"
} }
}, },
"node_modules/eslint/node_modules/lodash": {
"version": "4.17.10",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.10.tgz",
"integrity": "sha512-UejweD1pDoXu+AD825lWwp4ZGtSwgnpZxb3JDViD7StjQz+Nb/6l093lx4OQ0foGWNRoc19mWy7BzL+UAK2iVg==",
"dev": true
},
"node_modules/eslint/node_modules/strip-ansi": { "node_modules/eslint/node_modules/strip-ansi": {
"version": "4.0.0", "version": "4.0.0",
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz",
@ -5607,6 +5624,12 @@
"node": "*" "node": "*"
} }
}, },
"node_modules/globule/node_modules/lodash": {
"version": "4.17.10",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.10.tgz",
"integrity": "sha512-UejweD1pDoXu+AD825lWwp4ZGtSwgnpZxb3JDViD7StjQz+Nb/6l093lx4OQ0foGWNRoc19mWy7BzL+UAK2iVg==",
"dev": true
},
"node_modules/gonzales-pe": { "node_modules/gonzales-pe": {
"version": "4.2.3", "version": "4.2.3",
"resolved": "https://registry.npmjs.org/gonzales-pe/-/gonzales-pe-4.2.3.tgz", "resolved": "https://registry.npmjs.org/gonzales-pe/-/gonzales-pe-4.2.3.tgz",
@ -6040,6 +6063,12 @@
"object-assign": "4.1.1" "object-assign": "4.1.1"
} }
}, },
"node_modules/html-webpack-plugin/node_modules/lodash": {
"version": "4.17.10",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.10.tgz",
"integrity": "sha512-UejweD1pDoXu+AD825lWwp4ZGtSwgnpZxb3JDViD7StjQz+Nb/6l093lx4OQ0foGWNRoc19mWy7BzL+UAK2iVg==",
"dev": true
},
"node_modules/htmlparser2": { "node_modules/htmlparser2": {
"version": "3.9.2", "version": "3.9.2",
"resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-3.9.2.tgz", "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-3.9.2.tgz",
@ -6402,6 +6431,12 @@
"node": ">=4" "node": ">=4"
} }
}, },
"node_modules/inquirer/node_modules/lodash": {
"version": "4.17.10",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.10.tgz",
"integrity": "sha512-UejweD1pDoXu+AD825lWwp4ZGtSwgnpZxb3JDViD7StjQz+Nb/6l093lx4OQ0foGWNRoc19mWy7BzL+UAK2iVg==",
"dev": true
},
"node_modules/inquirer/node_modules/strip-ansi": { "node_modules/inquirer/node_modules/strip-ansi": {
"version": "4.0.0", "version": "4.0.0",
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz",
@ -7652,9 +7687,10 @@
} }
}, },
"node_modules/lodash": { "node_modules/lodash": {
"version": "4.17.10", "version": "4.17.21",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.10.tgz", "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
"integrity": "sha512-UejweD1pDoXu+AD825lWwp4ZGtSwgnpZxb3JDViD7StjQz+Nb/6l093lx4OQ0foGWNRoc19mWy7BzL+UAK2iVg==" "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==",
"dev": true
}, },
"node_modules/lodash.camelcase": { "node_modules/lodash.camelcase": {
"version": "4.3.0", "version": "4.3.0",
@ -8982,6 +9018,12 @@
"node": ">=4" "node": ">=4"
} }
}, },
"node_modules/mochapack/node_modules/lodash": {
"version": "4.17.10",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.10.tgz",
"integrity": "sha512-UejweD1pDoXu+AD825lWwp4ZGtSwgnpZxb3JDViD7StjQz+Nb/6l093lx4OQ0foGWNRoc19mWy7BzL+UAK2iVg==",
"dev": true
},
"node_modules/mochapack/node_modules/pify": { "node_modules/mochapack/node_modules/pify": {
"version": "3.0.0", "version": "3.0.0",
"resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz",
@ -9507,12 +9549,6 @@
"node": "*" "node": "*"
} }
}, },
"node_modules/node-sass/node_modules/lodash": {
"version": "4.17.21",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==",
"dev": true
},
"node_modules/node-sass/node_modules/path-key": { "node_modules/node-sass/node_modules/path-key": {
"version": "3.1.1", "version": "3.1.1",
"resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz",
@ -11029,6 +11065,12 @@
"node": ">=4" "node": ">=4"
} }
}, },
"node_modules/postcss-reporter/node_modules/lodash": {
"version": "4.17.10",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.10.tgz",
"integrity": "sha512-UejweD1pDoXu+AD825lWwp4ZGtSwgnpZxb3JDViD7StjQz+Nb/6l093lx4OQ0foGWNRoc19mWy7BzL+UAK2iVg==",
"dev": true
},
"node_modules/postcss-reporter/node_modules/postcss": { "node_modules/postcss-reporter/node_modules/postcss": {
"version": "6.0.23", "version": "6.0.23",
"resolved": "https://registry.npmjs.org/postcss/-/postcss-6.0.23.tgz", "resolved": "https://registry.npmjs.org/postcss/-/postcss-6.0.23.tgz",
@ -11283,6 +11325,12 @@
"node": ">=4" "node": ">=4"
} }
}, },
"node_modules/postcss-sorting/node_modules/lodash": {
"version": "4.17.10",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.10.tgz",
"integrity": "sha512-UejweD1pDoXu+AD825lWwp4ZGtSwgnpZxb3JDViD7StjQz+Nb/6l093lx4OQ0foGWNRoc19mWy7BzL+UAK2iVg==",
"dev": true
},
"node_modules/postcss-sorting/node_modules/postcss": { "node_modules/postcss-sorting/node_modules/postcss": {
"version": "6.0.23", "version": "6.0.23",
"resolved": "https://registry.npmjs.org/postcss/-/postcss-6.0.23.tgz", "resolved": "https://registry.npmjs.org/postcss/-/postcss-6.0.23.tgz",
@ -14079,6 +14127,12 @@
"node": ">=4" "node": ">=4"
} }
}, },
"node_modules/stylelint-order/node_modules/lodash": {
"version": "4.17.10",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.10.tgz",
"integrity": "sha512-UejweD1pDoXu+AD825lWwp4ZGtSwgnpZxb3JDViD7StjQz+Nb/6l093lx4OQ0foGWNRoc19mWy7BzL+UAK2iVg==",
"dev": true
},
"node_modules/stylelint-order/node_modules/postcss": { "node_modules/stylelint-order/node_modules/postcss": {
"version": "6.0.23", "version": "6.0.23",
"resolved": "https://registry.npmjs.org/postcss/-/postcss-6.0.23.tgz", "resolved": "https://registry.npmjs.org/postcss/-/postcss-6.0.23.tgz",
@ -14335,6 +14389,12 @@
"node": ">=4" "node": ">=4"
} }
}, },
"node_modules/stylelint/node_modules/lodash": {
"version": "4.17.10",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.10.tgz",
"integrity": "sha512-UejweD1pDoXu+AD825lWwp4ZGtSwgnpZxb3JDViD7StjQz+Nb/6l093lx4OQ0foGWNRoc19mWy7BzL+UAK2iVg==",
"dev": true
},
"node_modules/stylelint/node_modules/map-obj": { "node_modules/stylelint/node_modules/map-obj": {
"version": "2.0.0", "version": "2.0.0",
"resolved": "https://registry.npmjs.org/map-obj/-/map-obj-2.0.0.tgz", "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-2.0.0.tgz",
@ -14724,6 +14784,12 @@
"integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==",
"dev": true "dev": true
}, },
"node_modules/table/node_modules/lodash": {
"version": "4.17.10",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.10.tgz",
"integrity": "sha512-UejweD1pDoXu+AD825lWwp4ZGtSwgnpZxb3JDViD7StjQz+Nb/6l093lx4OQ0foGWNRoc19mWy7BzL+UAK2iVg==",
"dev": true
},
"node_modules/tapable": { "node_modules/tapable": {
"version": "1.0.0", "version": "1.0.0",
"resolved": "https://registry.npmjs.org/tapable/-/tapable-1.0.0.tgz", "resolved": "https://registry.npmjs.org/tapable/-/tapable-1.0.0.tgz",
@ -16144,6 +16210,12 @@
"node": ">=6.0.0" "node": ">=6.0.0"
} }
}, },
"node_modules/webpack-cli/node_modules/lodash": {
"version": "4.17.10",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.10.tgz",
"integrity": "sha512-UejweD1pDoXu+AD825lWwp4ZGtSwgnpZxb3JDViD7StjQz+Nb/6l093lx4OQ0foGWNRoc19mWy7BzL+UAK2iVg==",
"dev": true
},
"node_modules/webpack-cli/node_modules/strip-ansi": { "node_modules/webpack-cli/node_modules/strip-ansi": {
"version": "4.0.0", "version": "4.0.0",
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz",
@ -18457,6 +18529,13 @@
"integrity": "sha512-fNEiL2+AZt6AlAw/29Cr0UDe4sRAHCpEHh54WMz+Bb7QfNcFw4h3loofyJpLeQs4Yx7yuqu/2dLgM5hKOs6HlQ==", "integrity": "sha512-fNEiL2+AZt6AlAw/29Cr0UDe4sRAHCpEHh54WMz+Bb7QfNcFw4h3loofyJpLeQs4Yx7yuqu/2dLgM5hKOs6HlQ==",
"requires": { "requires": {
"lodash": "4.17.10" "lodash": "4.17.10"
},
"dependencies": {
"lodash": {
"version": "4.17.10",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.10.tgz",
"integrity": "sha512-UejweD1pDoXu+AD825lWwp4ZGtSwgnpZxb3JDViD7StjQz+Nb/6l093lx4OQ0foGWNRoc19mWy7BzL+UAK2iVg=="
}
} }
}, },
"async-each": { "async-each": {
@ -18711,6 +18790,14 @@
"requires": { "requires": {
"lodash": "4.17.10", "lodash": "4.17.10",
"platform": "1.3.5" "platform": "1.3.5"
},
"dependencies": {
"lodash": {
"version": "4.17.10",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.10.tgz",
"integrity": "sha512-UejweD1pDoXu+AD825lWwp4ZGtSwgnpZxb3JDViD7StjQz+Nb/6l093lx4OQ0foGWNRoc19mWy7BzL+UAK2iVg==",
"dev": true
}
} }
}, },
"big.js": { "big.js": {
@ -21164,6 +21251,12 @@
"esprima": "4.0.0" "esprima": "4.0.0"
} }
}, },
"lodash": {
"version": "4.17.10",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.10.tgz",
"integrity": "sha512-UejweD1pDoXu+AD825lWwp4ZGtSwgnpZxb3JDViD7StjQz+Nb/6l093lx4OQ0foGWNRoc19mWy7BzL+UAK2iVg==",
"dev": true
},
"strip-ansi": { "strip-ansi": {
"version": "4.0.0", "version": "4.0.0",
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz",
@ -22223,6 +22316,12 @@
"once": "1.4.0", "once": "1.4.0",
"path-is-absolute": "1.0.1" "path-is-absolute": "1.0.1"
} }
},
"lodash": {
"version": "4.17.10",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.10.tgz",
"integrity": "sha512-UejweD1pDoXu+AD825lWwp4ZGtSwgnpZxb3JDViD7StjQz+Nb/6l093lx4OQ0foGWNRoc19mWy7BzL+UAK2iVg==",
"dev": true
} }
} }
}, },
@ -22580,6 +22679,12 @@
"json5": "0.5.1", "json5": "0.5.1",
"object-assign": "4.1.1" "object-assign": "4.1.1"
} }
},
"lodash": {
"version": "4.17.10",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.10.tgz",
"integrity": "sha512-UejweD1pDoXu+AD825lWwp4ZGtSwgnpZxb3JDViD7StjQz+Nb/6l093lx4OQ0foGWNRoc19mWy7BzL+UAK2iVg==",
"dev": true
} }
} }
}, },
@ -22882,6 +22987,12 @@
"integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=",
"dev": true "dev": true
}, },
"lodash": {
"version": "4.17.10",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.10.tgz",
"integrity": "sha512-UejweD1pDoXu+AD825lWwp4ZGtSwgnpZxb3JDViD7StjQz+Nb/6l093lx4OQ0foGWNRoc19mWy7BzL+UAK2iVg==",
"dev": true
},
"strip-ansi": { "strip-ansi": {
"version": "4.0.0", "version": "4.0.0",
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz",
@ -23908,9 +24019,10 @@
} }
}, },
"lodash": { "lodash": {
"version": "4.17.10", "version": "4.17.21",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.10.tgz", "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
"integrity": "sha512-UejweD1pDoXu+AD825lWwp4ZGtSwgnpZxb3JDViD7StjQz+Nb/6l093lx4OQ0foGWNRoc19mWy7BzL+UAK2iVg==" "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==",
"dev": true
}, },
"lodash.camelcase": { "lodash.camelcase": {
"version": "4.3.0", "version": "4.3.0",
@ -24999,6 +25111,12 @@
"slash": "1.0.0" "slash": "1.0.0"
} }
}, },
"lodash": {
"version": "4.17.10",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.10.tgz",
"integrity": "sha512-UejweD1pDoXu+AD825lWwp4ZGtSwgnpZxb3JDViD7StjQz+Nb/6l093lx4OQ0foGWNRoc19mWy7BzL+UAK2iVg==",
"dev": true
},
"pify": { "pify": {
"version": "3.0.0", "version": "3.0.0",
"resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz",
@ -25416,12 +25534,6 @@
"path-is-absolute": "1.0.1" "path-is-absolute": "1.0.1"
} }
}, },
"lodash": {
"version": "4.17.21",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==",
"dev": true
},
"path-key": { "path-key": {
"version": "3.1.1", "version": "3.1.1",
"resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz",
@ -26731,6 +26843,12 @@
"supports-color": "5.4.0" "supports-color": "5.4.0"
} }
}, },
"lodash": {
"version": "4.17.10",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.10.tgz",
"integrity": "sha512-UejweD1pDoXu+AD825lWwp4ZGtSwgnpZxb3JDViD7StjQz+Nb/6l093lx4OQ0foGWNRoc19mWy7BzL+UAK2iVg==",
"dev": true
},
"postcss": { "postcss": {
"version": "6.0.23", "version": "6.0.23",
"resolved": "https://registry.npmjs.org/postcss/-/postcss-6.0.23.tgz", "resolved": "https://registry.npmjs.org/postcss/-/postcss-6.0.23.tgz",
@ -26942,6 +27060,12 @@
"supports-color": "5.4.0" "supports-color": "5.4.0"
} }
}, },
"lodash": {
"version": "4.17.10",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.10.tgz",
"integrity": "sha512-UejweD1pDoXu+AD825lWwp4ZGtSwgnpZxb3JDViD7StjQz+Nb/6l093lx4OQ0foGWNRoc19mWy7BzL+UAK2iVg==",
"dev": true
},
"postcss": { "postcss": {
"version": "6.0.23", "version": "6.0.23",
"resolved": "https://registry.npmjs.org/postcss/-/postcss-6.0.23.tgz", "resolved": "https://registry.npmjs.org/postcss/-/postcss-6.0.23.tgz",
@ -29479,6 +29603,12 @@
"strip-bom": "3.0.0" "strip-bom": "3.0.0"
} }
}, },
"lodash": {
"version": "4.17.10",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.10.tgz",
"integrity": "sha512-UejweD1pDoXu+AD825lWwp4ZGtSwgnpZxb3JDViD7StjQz+Nb/6l093lx4OQ0foGWNRoc19mWy7BzL+UAK2iVg==",
"dev": true
},
"map-obj": { "map-obj": {
"version": "2.0.0", "version": "2.0.0",
"resolved": "https://registry.npmjs.org/map-obj/-/map-obj-2.0.0.tgz", "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-2.0.0.tgz",
@ -29676,6 +29806,12 @@
"supports-color": "5.4.0" "supports-color": "5.4.0"
} }
}, },
"lodash": {
"version": "4.17.10",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.10.tgz",
"integrity": "sha512-UejweD1pDoXu+AD825lWwp4ZGtSwgnpZxb3JDViD7StjQz+Nb/6l093lx4OQ0foGWNRoc19mWy7BzL+UAK2iVg==",
"dev": true
},
"postcss": { "postcss": {
"version": "6.0.23", "version": "6.0.23",
"resolved": "https://registry.npmjs.org/postcss/-/postcss-6.0.23.tgz", "resolved": "https://registry.npmjs.org/postcss/-/postcss-6.0.23.tgz",
@ -29854,6 +29990,12 @@
"resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
"integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==",
"dev": true "dev": true
},
"lodash": {
"version": "4.17.10",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.10.tgz",
"integrity": "sha512-UejweD1pDoXu+AD825lWwp4ZGtSwgnpZxb3JDViD7StjQz+Nb/6l093lx4OQ0foGWNRoc19mWy7BzL+UAK2iVg==",
"dev": true
} }
} }
}, },
@ -31120,6 +31262,12 @@
"through": "2.3.8" "through": "2.3.8"
} }
}, },
"lodash": {
"version": "4.17.10",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.10.tgz",
"integrity": "sha512-UejweD1pDoXu+AD825lWwp4ZGtSwgnpZxb3JDViD7StjQz+Nb/6l093lx4OQ0foGWNRoc19mWy7BzL+UAK2iVg==",
"dev": true
},
"strip-ansi": { "strip-ansi": {
"version": "4.0.0", "version": "4.0.0",
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz",

@ -65,7 +65,7 @@
"json5": "^1.0.1", "json5": "^1.0.1",
"less": "^3.9.0", "less": "^3.9.0",
"less-loader": "^4.1.0", "less-loader": "^4.1.0",
"lodash": "^4.17.10", "lodash": "^4.17.21",
"mini-css-extract-plugin": "^0.4.1", "mini-css-extract-plugin": "^0.4.1",
"mkdirp": "^0.5.1", "mkdirp": "^0.5.1",
"mocha": "^6.1.4", "mocha": "^6.1.4",

@ -2054,7 +2054,7 @@ function applyAugmentation(aug, reapply=false) {
} }
} }
function installAugmentations(cbScript=null) { function installAugmentations() {
if (Player.queuedAugmentations.length == 0) { if (Player.queuedAugmentations.length == 0) {
dialogBoxCreate("You have not purchased any Augmentations to install!"); dialogBoxCreate("You have not purchased any Augmentations to install!");
return false; return false;
@ -2063,7 +2063,7 @@ function installAugmentations(cbScript=null) {
for (var i = 0; i < Player.queuedAugmentations.length; ++i) { for (var i = 0; i < Player.queuedAugmentations.length; ++i) {
var aug = Augmentations[Player.queuedAugmentations[i].name]; var aug = Augmentations[Player.queuedAugmentations[i].name];
if (aug == null) { if (aug == null) {
console.log("ERROR. Invalid augmentation"); console.error(`Invalid augmentation: ${Player.queuedAugmentations[i].name}`);
continue; continue;
} }
applyAugmentation(Player.queuedAugmentations[i]); applyAugmentation(Player.queuedAugmentations[i]);
@ -2074,24 +2074,6 @@ function installAugmentations(cbScript=null) {
"to install the following Augmentations:<br>" + augmentationList + "to install the following Augmentations:<br>" + augmentationList +
"<br>You wake up in your home...you feel different..."); "<br>You wake up in your home...you feel different...");
prestigeAugmentation(); prestigeAugmentation();
//Run a script after prestiging
if (cbScript && isString(cbScript)) {
var home = Player.getHomeComputer();
for (const script of home.scripts) {
if (script.filename === cbScript) {
const ramUsage = script.ramUsage;
const ramAvailable = home.maxRam - home.ramUsed;
if (ramUsage > ramAvailable) {
return; // Not enough RAM
}
const runningScriptObj = new RunningScript(script, []); // No args
runningScriptObj.threads = 1; // Only 1 thread
startWorkerScript(runningScriptObj, home);
}
}
}
} }
function augmentationExists(name) { function augmentationExists(name) {

@ -10,6 +10,7 @@ import * as React from "react";
import { InstalledAugmentations } from "./InstalledAugmentations"; import { InstalledAugmentations } from "./InstalledAugmentations";
import { ListConfiguration } from "./ListConfiguration"; import { ListConfiguration } from "./ListConfiguration";
import { OwnedSourceFiles } from "./OwnedSourceFiles"; import { OwnedSourceFiles } from "./OwnedSourceFiles";
import { SourceFileMinus1 } from "./SourceFileMinus1";
import { Settings } from "../../Settings/Settings"; import { Settings } from "../../Settings/Settings";
import { OwnedAugmentationsOrderSetting } from "../../Settings/SettingEnums"; import { OwnedAugmentationsOrderSetting } from "../../Settings/SettingEnums";
@ -98,6 +99,7 @@ export class InstalledAugmentationsAndSourceFiles extends React.Component<IProps
sortInOrderFn={this.sortInOrder} sortInOrderFn={this.sortInOrder}
/> />
<ul className="augmentations-list" ref={this.listRef}> <ul className="augmentations-list" ref={this.listRef}>
<SourceFileMinus1 />
<OwnedSourceFiles /> <OwnedSourceFiles />
<InstalledAugmentations /> <InstalledAugmentations />
</ul> </ul>

@ -0,0 +1,44 @@
/**
* React Component for displaying a list of the player's Source-Files
* on the Augmentations UI
*/
import * as React from "react";
import { Player } from "../../Player";
import { Settings } from "../../Settings/Settings";
import { OwnedAugmentationsOrderSetting } from "../../Settings/SettingEnums";
import { SourceFiles } from "../../SourceFile/SourceFiles";
import { Exploit, ExploitName } from "../../Exploits/Exploit";
import { Accordion } from "../../ui/React/Accordion";
export function SourceFileMinus1(): React.ReactElement {
let exploits = Player.exploits;
if(exploits.length === 0) {
return <></>
}
return (<li key={-1}>
<Accordion
headerContent={
<>
Source-File -1: Exploits in the BitNodes
<br />
Level {exploits.length} / ?
</>
}
panelContent={
<>
<p>This Source-File can only be acquired with obscure knowledge of the game, javascript, and the web ecosystem.</p>
<p>It increases all of the player's multipliers by 0.1%</p><br />
<p>You have found the following exploits:</p>
<ul>
{exploits.map((c: Exploit) => <li key={c}>* {ExploitName(c)}</li>)}
</ul>
</>
}
/>
</li>)
}

@ -492,7 +492,7 @@ export function initBitNodeMultipliers(p: IPlayer) {
BitNodeMultipliers.BladeburnerSkillCost = inc; BitNodeMultipliers.BladeburnerSkillCost = inc;
break; break;
default: default:
console.log("WARNING: Player.bitNodeN invalid"); console.warn("Player.bitNodeN invalid");
break; break;
} }
} }

@ -495,7 +495,7 @@ Action.prototype.getSuccessChance = function(inst, params={}) {
var key = "eff" + stat.charAt(0).toUpperCase() + stat.slice(1); var key = "eff" + stat.charAt(0).toUpperCase() + stat.slice(1);
var effMultiplier = inst.skillMultipliers[key]; var effMultiplier = inst.skillMultipliers[key];
if (effMultiplier == null) { if (effMultiplier == null) {
console.log("ERROR: Failed to find Bladeburner Skill multiplier for: " + stat); console.error(`Failed to find Bladeburner Skill multiplier for: ${stat}`);
effMultiplier = 1; effMultiplier = 1;
} }
competence += (this.weights[stat] * Math.pow(effMultiplier*playerStatLvl, this.decays[stat])); competence += (this.weights[stat] * Math.pow(effMultiplier*playerStatLvl, this.decays[stat]));
@ -1218,8 +1218,7 @@ Bladeburner.prototype.startAction = function(actionId) {
Bladeburner.prototype.processAction = function(seconds) { Bladeburner.prototype.processAction = function(seconds) {
if (this.action.type === ActionTypes["Idle"]) {return;} if (this.action.type === ActionTypes["Idle"]) {return;}
if (this.actionTimeToComplete <= 0) { if (this.actionTimeToComplete <= 0) {
console.log("action.type: " + this.action.type); throw new Error(`Invalid actionTimeToComplete value: ${this.actionTimeToComplete}, type; ${this.action.type}`);
throw new Error("Invalid actionTimeToComplete value: " + this.actionTimeToComplete);
} }
if (!(this.action instanceof ActionIdentifier)) { if (!(this.action instanceof ActionIdentifier)) {
throw new Error("Bladeburner.action is not an ActionIdentifier Object"); throw new Error("Bladeburner.action is not an ActionIdentifier Object");
@ -1720,7 +1719,7 @@ Bladeburner.prototype.randomEvent = function() {
Bladeburner.prototype.triggerPotentialMigration = function(sourceCityName, chance) { Bladeburner.prototype.triggerPotentialMigration = function(sourceCityName, chance) {
if (chance == null || isNaN(chance)) { if (chance == null || isNaN(chance)) {
console.log("ERROR: Invalid 'chance' parameter passed into Bladeburner.triggerPotentialMigration()"); console.error("Invalid 'chance' parameter passed into Bladeburner.triggerPotentialMigration()");
} }
if (chance > 1) {chance /= 100;} if (chance > 1) {chance /= 100;}
if (Math.random() < chance) {this.triggerMigration(sourceCityName);} if (Math.random() < chance) {this.triggerMigration(sourceCityName);}
@ -2310,7 +2309,7 @@ Bladeburner.prototype.createSkillsContent = function() {
// TODO in the future if items are ever implemented // TODO in the future if items are ever implemented
break; break;
default: default:
console.log("Warning: Unrecognized SkillMult Key: " + multKeys[i]); console.warn(`Unrecognized SkillMult Key: ${multKeys[i]}`);
break; break;
} }
} }
@ -3022,7 +3021,6 @@ Bladeburner.prototype.parseCommandArguments = function(command) {
++i; ++i;
} }
if (start !== i) {args.push(command.substr(start, i-start));} if (start !== i) {args.push(command.substr(start, i-start));}
console.log("Bladeburner console command parsing returned: " + args);
return args; return args;
} }
@ -3286,7 +3284,7 @@ Bladeburner.prototype.executeSkillConsoleCommand = function(args) {
// TODO if items are ever implemented // TODO if items are ever implemented
break; break;
default: default:
console.log("Warning: Unrecognized SkillMult Key: " + multKeys[i]); console.warn(`Unrecognized SkillMult Key: ${multKeys[i]}`);
break; break;
} }
} }
@ -3829,43 +3827,6 @@ Bladeburner.prototype.setTeamSizeNetscriptFn = function(type, name, size, worker
return sanitizedSize; return sanitizedSize;
} }
Bladeburner.prototype.getCityEstimatedPopulationNetscriptFn = function(cityName, workerScript) {
if (!this.cities.hasOwnProperty(cityName)) {
workerScript.log("ERROR: bladeburner.getCityEstimatedPopulation() failed because the specified " +
"city was invalid: " + cityName + ". Note that this city argument is case-sensitive");
return -1;
}
return this.cities[cityName].popEst;
}
Bladeburner.prototype.getCityEstimatedCommunitiesNetscriptFn = function(cityName, workerScript) {
if (!this.cities.hasOwnProperty(cityName)) {
workerScript.log("ERROR: bladeburner.getCityEstimatedCommunities() failed because the specified " +
"city was invalid: " + cityName + ". Note that this city argument is case-sensitive");
return -1;
}
return this.cities[cityName].commsEst;
}
Bladeburner.prototype.getCityChaosNetscriptFn = function(cityName, workerScript) {
if (!this.cities.hasOwnProperty(cityName)) {
workerScript.log("ERROR: bladeburner.getCityChaos() failed because the specified " +
"city was invalid: " + cityName + ". Note that this city argument is case-sensitive");
return -1;
}
return this.cities[cityName].chaos;
}
Bladeburner.prototype.switchCityNetscriptFn = function(cityName, workerScript) {
if (!this.cities.hasOwnProperty(cityName)) {
workerScript.log("ERROR: bladeburner.switchCity() failed because the specified " +
"city was invalid: " + cityName + ". Note that this city argument is case-sensitive");
return false;
}
this.city = cityName;
return true;
}
Bladeburner.prototype.joinBladeburnerFactionNetscriptFn = function(workerScript) { Bladeburner.prototype.joinBladeburnerFactionNetscriptFn = function(workerScript) {
var bladeburnerFac = Factions["Bladeburners"]; var bladeburnerFac = Factions["Bladeburners"];
if (bladeburnerFac.isMember) { if (bladeburnerFac.isMember) {

@ -6,7 +6,7 @@
import { IMap } from "./types"; import { IMap } from "./types";
export let CONSTANTS: IMap<any> = { export let CONSTANTS: IMap<any> = {
Version: "0.48.0", Version: "0.49.0",
/** Max level for any skill, assuming no multipliers. Determined by max numerical value in javascript for experience /** 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 * and the skill level formula in Player.js. Note that all this means it that when experience hits MAX_INT, then
@ -228,46 +228,27 @@ export let CONSTANTS: IMap<any> = {
LatestUpdate: LatestUpdate:
` `
v0.48.0 - ASCII v0.49.0 - 2021-03-11 Source-File -1
------- -------
ASCII Source-File -1
* Travel Agency now displays a world map * For advanced players: The game now embraces exploits and will reward
* Cities are now top view of metro station maps players for doing so.
Gang
* ascension is less effective as the ascension multiplier goes up.
* territory gain scales with power difference.
Netscript Netscript
* 'softReset' is a new netscript function that performs a soft reset * 'gang.getEquipmentStats' returns the stats of the equipment.
regardless of if the player has bought augmentations or not. * 'gang.getTaskStats' returns the stats of a task.
* 'getAugmentationStats' is a new netscript function that returns the stats of * 'getCrimeStats' returns the stats of a crime.
an augmentation. * Crashes should now print the ns stack trace.
* getCharacterInformation now additionally returns exp * Log messages are now more consistent.
* pid resets back to 1 when installing or destroying a BitNode. * 'softReset' now accepts a callback script like 'installAugmentations'
* New '.ns' scripts start with a main function.
* 'hacknet.maxNumNodes' returns the maximum number of hacknet nodes.
Bladeburner
* Current stamina will scale as max stamina increases, this prevents players
from having very high penalty when they gain huge amount of exp at the
start of a reset.
Misc. Misc.
* Fixed an issue where SF3 was listed as infinitly repeatable and SF12 as * Minor formatting under Hacking>Active Scripts
having a limit of 3. * option menu colors now match the rest of the game, kinda.
* Fixed an issue where the gang equipment screen would freeze the game if a
script installed augmentations while it is open.
* All BonusTime now displays in the 'H M S' format.
* Donation textbox style updated to match the rest of the game.
* Corporation name style updated to match the rest of the game.
* minor formatting under Hacking>Active Scripts
* typo in BN12 description
* BN12 now reduces contract money
* Character>Stats percentages are aligned, server and hacknet limit are
displayed, if the player has SF5 the reduces stats are shown.
* Character>Augmentations now displays by how much the player stats will
increase.
* Character>Augmentations has a badge indicating how many augs the player
has bought but not installed
* Character>Factions has a badge indicating how many factions have pending
invites.
` `
} }

@ -383,7 +383,7 @@ Industry.prototype.init = function() {
this.makesProducts = true; this.makesProducts = true;
break; break;
default: default:
console.log("ERR: Invalid Industry Type passed into Industry.init(): " + this.type); console.error(`Invalid Industry Type passed into Industry.init(): ${this.type}`);
return; return;
} }
} }
@ -409,7 +409,7 @@ Industry.prototype.getProductDescriptionText = function() {
case Industries.RealEstate: case Industries.RealEstate:
return "develop and manage real estate properties"; return "develop and manage real estate properties";
default: default:
console.log("ERROR: Invalid industry type in Industry.getProductDescriptionText"); console.error("Invalid industry type in Industry.getProductDescriptionText");
return ""; return "";
} }
} }
@ -477,9 +477,7 @@ Industry.prototype.process = function(marketCycles=1, state, company) {
//Then calculate salaries and processs the markets //Then calculate salaries and processs the markets
if (state === "START") { if (state === "START") {
if (isNaN(this.thisCycleRevenue) || isNaN(this.thisCycleExpenses)) { if (isNaN(this.thisCycleRevenue) || isNaN(this.thisCycleExpenses)) {
console.log("ERROR: NaN in Corporation's computed revenue/expenses"); console.error("NaN in Corporation's computed revenue/expenses");
console.log(this.thisCycleRevenue.toString());
console.log(this.thisCycleExpenses.toString());
dialogBoxCreate("Something went wrong when compting Corporation's revenue/expenses. This is a bug. Please report to game developer"); dialogBoxCreate("Something went wrong when compting Corporation's revenue/expenses. This is a bug. Please report to game developer");
this.thisCycleRevenue = new Decimal(0); this.thisCycleRevenue = new Decimal(0);
this.thisCycleExpenses = new Decimal(0); this.thisCycleExpenses = new Decimal(0);
@ -898,7 +896,7 @@ Industry.prototype.processMaterials = function(marketCycles=1, company) {
var expIndustry = company.divisions[foo]; var expIndustry = company.divisions[foo];
var expWarehouse = expIndustry.warehouses[exp.city]; var expWarehouse = expIndustry.warehouses[exp.city];
if (!(expWarehouse instanceof Warehouse)) { if (!(expWarehouse instanceof Warehouse)) {
console.log("ERROR: Invalid export! " + expIndustry.name + " " + exp.city); console.error(`Invalid export! ${expIndustry.name} ${exp.city}`);
break; break;
} }
@ -931,7 +929,7 @@ Industry.prototype.processMaterials = function(marketCycles=1, company) {
case "START": case "START":
break; break;
default: default:
console.log("ERROR: Invalid state: " + this.state); console.error(`Invalid state: ${this.state}`);
break; break;
} //End switch(this.state) } //End switch(this.state)
this.updateWarehouseSizeUsed(warehouse); this.updateWarehouseSizeUsed(warehouse);
@ -1181,7 +1179,7 @@ Industry.prototype.processProduct = function(marketCycles=1, product, corporatio
case "EXPORT": case "EXPORT":
break; break;
default: default:
console.log("ERROR: Invalid State: " + this.state); console.error(`Invalid State: ${this.state}`);
break; break;
} //End switch(this.state) } //End switch(this.state)
} }
@ -1221,7 +1219,7 @@ Industry.prototype.upgrade = function(upgrade, refs) {
this.popularity *= ((1 + getRandomInt(1, 3) / 100) * advMult); this.popularity *= ((1 + getRandomInt(1, 3) / 100) * advMult);
break; break;
default: default:
console.log("ERROR: Un-implemented function index: " + upgN); console.error(`Un-implemented function index: ${upgN}`);
break; break;
} }
} }
@ -1287,7 +1285,6 @@ Industry.prototype.updateResearchTree = function() {
// Since ResearchTree data isnt saved, we'll update the Research Tree data // Since ResearchTree data isnt saved, we'll update the Research Tree data
// based on the stored 'researched' property in the Industry object // based on the stored 'researched' property in the Industry object
if (Object.keys(researchTree.researched).length !== Object.keys(this.researched).length) { if (Object.keys(researchTree.researched).length !== Object.keys(this.researched).length) {
console.log("Updating Corporation Research Tree Data");
for (let research in this.researched) { for (let research in this.researched) {
researchTree.research(research); researchTree.research(research);
} }
@ -1547,7 +1544,7 @@ Employee.prototype.calculateProductivity = function(corporation, industry) {
prodMult = 0; prodMult = 0;
break; break;
default: default:
console.log("ERROR: Invalid employee position: " + this.pos); console.error(`Invalid employee position: ${this.pos}`);
break; break;
} }
return prodBase * prodMult; return prodBase * prodMult;

@ -153,7 +153,6 @@ export class Product {
const opsRatio = employeeProd[EmployeePositions.Operations] / employeeProd["total"]; const opsRatio = employeeProd[EmployeePositions.Operations] / employeeProd["total"];
const busRatio = employeeProd[EmployeePositions.Business] / employeeProd["total"]; const busRatio = employeeProd[EmployeePositions.Business] / employeeProd["total"];
var designMult = 1 + (Math.pow(this.designCost, 0.1) / 100); var designMult = 1 + (Math.pow(this.designCost, 0.1) / 100);
console.log("designMult: " + designMult);
var balanceMult = (1.2 * engrRatio) + (0.9 * mgmtRatio) + (1.3 * rndRatio) + var balanceMult = (1.2 * engrRatio) + (0.9 * mgmtRatio) + (1.3 * rndRatio) +
(1.5 * opsRatio) + (busRatio); (1.5 * opsRatio) + (busRatio);
var sciMult = 1 + (Math.pow(industry.sciResearch.qty, industry.sciFac) / 800); var sciMult = 1 + (Math.pow(industry.sciResearch.qty, industry.sciFac) / 800);
@ -221,7 +220,7 @@ export class Product {
calculateRating(industry: IIndustry): void { calculateRating(industry: IIndustry): void {
const weights: IProductRatingWeight = ProductRatingWeights[industry.type]; const weights: IProductRatingWeight = ProductRatingWeights[industry.type];
if (weights == null) { if (weights == null) {
console.log("ERROR: Could not find product rating weights for: " + industry); console.error(`Could not find product rating weights for: ${industry}`);
return; return;
} }
this.rat = 0; this.rat = 0;

@ -110,7 +110,6 @@ export class CorporationEventHandler {
} else { } else {
var totalAmount = money + (stockShares * stockPrice); var totalAmount = money + (stockShares * stockPrice);
var repGain = totalAmount / BribeToRepRatio; var repGain = totalAmount / BribeToRepRatio;
console.log("repGain: " + repGain);
repGainText.innerText = "You will gain " + numeralWrapper.format(repGain, "0,0") + repGainText.innerText = "You will gain " + numeralWrapper.format(repGain, "0,0") +
" reputation with " + " reputation with " +
factionSelector.options[factionSelector.selectedIndex].value + factionSelector.options[factionSelector.selectedIndex].value +
@ -1539,8 +1538,7 @@ export class CorporationEventHandler {
this.corp.numShares -= shares; this.corp.numShares -= shares;
if (isNaN(this.corp.issuedShares)) { if (isNaN(this.corp.issuedShares)) {
console.log("ERROR: Corporation issuedShares is NaN: " + this.corp.issuedShares); console.error(`Corporation issuedShares is NaN: ${this.corp.issuedShares}`);
console.log("Converting to number now");
var res = parseInt(this.corp.issuedShares); var res = parseInt(this.corp.issuedShares);
if (isNaN(res)) { if (isNaN(res)) {
this.corp.issuedShares = 0; this.corp.issuedShares = 0;

37
src/Exploits/Exploit.ts Normal file

@ -0,0 +1,37 @@
/*
The game cannot block every possible exploits. Specially since one of them is
that you can just edit your save file and that's impragmatic to prevent.
So instead we have source file minus 1. It is not obtained by destroying a
BitNode but instead it is awarded when the player finds innovative ways to break
the game, this serves 2 purpose, [one] the developpers don't have to spend time
trying to implement anti-cheat measures and [two] finding ways to break a
hacking game is very much in the spirit of the game.
Source-File minus 1 is extremely weak because it can be fully level up quickly.
*/
export enum Exploit {
UndocumentedFunctionCall = 'UndocumentedFunctionCall',
PrototypeTampering = 'PrototypeTampering',
// To the players reading this. Yes you're supposed to add EditSaveFile by
// editing your save file, yes you could add them all, no we don't care
// that's not the point
EditSaveFile = 'EditSaveFile'
}
const names: {
[key: string]: string;
} = {
'UndocumentedFunctionCall': 'by looking beyond the documentation.',
'EditSaveFile': 'by editing your save file.',
'PrototypeTampering': 'by tampering with Numbers prototype.',
}
export function ExploitName(exploit: string): string {
return names[exploit];
}
export function sanitizeExploits(exploits: string[]): string[] {
return exploits.filter((e: string) => Object.keys(Exploit).includes(e));
}

@ -0,0 +1,42 @@
import { Player } from "../Player";
export function applyExploit() {
if (Player.exploits && Player.exploits.length === 0) {
return;
}
const inc = Math.pow(1.0001, Player.exploits.length);
const dec = Math.pow(0.9999, Player.exploits.length);
Player.hacking_chance_mult *= inc;
Player.hacking_speed_mult *= inc;
Player.hacking_money_mult *= inc;
Player.hacking_grow_mult *= inc;
Player.hacking_mult *= inc;
Player.strength_mult *= inc;
Player.defense_mult *= inc;
Player.dexterity_mult *= inc;
Player.agility_mult *= inc;
Player.charisma_mult *= inc;
Player.hacking_exp_mult *= inc;
Player.strength_exp_mult *= inc;
Player.defense_exp_mult *= inc;
Player.dexterity_exp_mult *= inc;
Player.agility_exp_mult *= inc;
Player.charisma_exp_mult *= inc;
Player.company_rep_mult *= inc;
Player.faction_rep_mult *= inc;
Player.crime_money_mult *= inc;
Player.crime_success_mult *= inc;
Player.hacknet_node_money_mult *= inc;
Player.hacknet_node_purchase_cost_mult *= dec;
Player.hacknet_node_ram_cost_mult *= dec;
Player.hacknet_node_core_cost_mult *= dec;
Player.hacknet_node_level_cost_mult *= dec;
Player.work_money_mult *= inc;
}

11
src/Exploits/tampering.ts Normal file

@ -0,0 +1,11 @@
import { Player } from "../Player";
import { Exploit } from "./Exploit";
(function() {
const a = 55;
setInterval(function() {
if (a.toExponential() !== "5.5e+1") {
Player.giveExploit(Exploit.PrototypeTampering);
}
}, 15*60*1000); // 15 minutes
})()

@ -91,7 +91,7 @@ function parseFconfSetting(setting, value) {
setting = String(setting); setting = String(setting);
value = String(value); value = String(value);
if (setting == null || value == null || FconfSettings[setting] == null) { if (setting == null || value == null || FconfSettings[setting] == null) {
console.log("WARNING: Invalid .fconf setting: " + setting); console.warn(`Invalid .fconf setting: ${setting}`);
return; return;
} }
@ -184,7 +184,7 @@ function setTheme() {
FconfSettings.THEME_FONT_COLOR == null || FconfSettings.THEME_FONT_COLOR == null ||
FconfSettings.THEME_BACKGROUND_COLOR == null || FconfSettings.THEME_BACKGROUND_COLOR == null ||
FconfSettings.THEME_PROMPT_COLOR == null) { FconfSettings.THEME_PROMPT_COLOR == null) {
console.log("ERROR: Cannot find Theme Settings"); console.error("Cannot find Theme Settings");
return; return;
} }
if (/^#[0-9a-f]{3}(?:[0-9a-f]{3})?$/i.test(FconfSettings.THEME_HIGHLIGHT_COLOR) && if (/^#[0-9a-f]{3}(?:[0-9a-f]{3})?$/i.test(FconfSettings.THEME_HIGHLIGHT_COLOR) &&

@ -270,13 +270,19 @@ Gang.prototype.processGains = function(numCycles=1, player) {
} }
} }
function calculateTerritoryGain(winGang, loseGang) {
const powerBonus = Math.max(1, 1+Math.log(AllGangs[winGang].power/AllGangs[loseGang].power)/Math.log(50));
const gains = Math.min(AllGangs[loseGang].territory, powerBonus*0.0001*(Math.random()+.5))
return gains;
}
Gang.prototype.processTerritoryAndPowerGains = function(numCycles=1) { Gang.prototype.processTerritoryAndPowerGains = function(numCycles=1) {
this.storedTerritoryAndPowerCycles += numCycles; this.storedTerritoryAndPowerCycles += numCycles;
if (this.storedTerritoryAndPowerCycles < CyclesPerTerritoryAndPowerUpdate) { return; } if (this.storedTerritoryAndPowerCycles < CyclesPerTerritoryAndPowerUpdate) { return; }
this.storedTerritoryAndPowerCycles -= CyclesPerTerritoryAndPowerUpdate; this.storedTerritoryAndPowerCycles -= CyclesPerTerritoryAndPowerUpdate;
// Process power first // Process power first
var gangName = this.facName; const gangName = this.facName;
for (const name in AllGangs) { for (const name in AllGangs) {
if (AllGangs.hasOwnProperty(name)) { if (AllGangs.hasOwnProperty(name)) {
if (name == gangName) { if (name == gangName) {
@ -327,12 +333,14 @@ Gang.prototype.processTerritoryAndPowerGains = function(numCycles=1) {
const otherPwr = AllGangs[otherGang].power; const otherPwr = AllGangs[otherGang].power;
const thisChance = thisPwr / (thisPwr + otherPwr); const thisChance = thisPwr / (thisPwr + otherPwr);
if (Math.random() < thisChance) { if (Math.random() < thisChance) {
if (AllGangs[otherGang].territory <= 0) { if (AllGangs[otherGang].territory <= 0) {
return; return;
} }
AllGangs[thisGang].territory += 0.0001; const territoryGain = calculateTerritoryGain(thisGang, otherGang);
AllGangs[otherGang].territory -= 0.0001; AllGangs[thisGang].territory += territoryGain;
AllGangs[otherGang].territory -= territoryGain;
if (thisGang === gangName) { if (thisGang === gangName) {
this.clash(true); // Player won this.clash(true); // Player won
AllGangs[otherGang].power *= (1 / 1.01); AllGangs[otherGang].power *= (1 / 1.01);
@ -345,8 +353,9 @@ Gang.prototype.processTerritoryAndPowerGains = function(numCycles=1) {
if (AllGangs[thisGang].territory <= 0) { if (AllGangs[thisGang].territory <= 0) {
return; return;
} }
AllGangs[thisGang].territory -= 0.0001; const territoryGain = calculateTerritoryGain(otherGang, thisGang);
AllGangs[otherGang].territory += 0.0001; AllGangs[thisGang].territory -= territoryGain;
AllGangs[otherGang].territory += territoryGain;
if (thisGang === gangName) { if (thisGang === gangName) {
this.clash(false); // Player lost this.clash(false); // Player lost
} else if (otherGang === gangName) { } else if (otherGang === gangName) {
@ -790,6 +799,20 @@ GangMember.prototype.ascend = function() {
}; };
} }
GangMember.prototype.getAscensionEfficiency = function() {
function formula(mult) {
return 1/(1+Math.log(mult)/Math.log(10));
}
return {
hack: formula(this.hack_asc_mult),
str: formula(this.str_asc_mult),
def: formula(this.def_asc_mult),
dex: formula(this.dex_asc_mult),
agi: formula(this.agi_asc_mult),
cha: formula(this.cha_asc_mult),
};
}
// Returns the multipliers that would be gained from ascension // Returns the multipliers that would be gained from ascension
GangMember.prototype.getAscensionResults = function() { GangMember.prototype.getAscensionResults = function() {
/** /**
@ -814,13 +837,14 @@ GangMember.prototype.getAscensionResults = function() {
} }
// Subtract 1 because we're only interested in the actual "bonus" part // Subtract 1 because we're only interested in the actual "bonus" part
const eff = this.getAscensionEfficiency();
return { return {
hack: (Math.max(0, hack - 1) * AscensionMultiplierRatio), hack: (Math.max(0, hack - 1) * AscensionMultiplierRatio * eff.hack),
str: (Math.max(0, str - 1) * AscensionMultiplierRatio), str: (Math.max(0, str - 1) * AscensionMultiplierRatio * eff.str),
def: (Math.max(0, def - 1) * AscensionMultiplierRatio), def: (Math.max(0, def - 1) * AscensionMultiplierRatio * eff.def),
dex: (Math.max(0, dex - 1) * AscensionMultiplierRatio), dex: (Math.max(0, dex - 1) * AscensionMultiplierRatio * eff.dex),
agi: (Math.max(0, agi - 1) * AscensionMultiplierRatio), agi: (Math.max(0, agi - 1) * AscensionMultiplierRatio * eff.agi),
cha: (Math.max(0, cha - 1) * AscensionMultiplierRatio), cha: (Math.max(0, cha - 1) * AscensionMultiplierRatio * eff.cha),
} }
} }
@ -912,7 +936,7 @@ GangMemberTask.fromJSON = function(value) {
Reviver.constructors.GangMemberTask = GangMemberTask; Reviver.constructors.GangMemberTask = GangMemberTask;
const GangMemberTasks = {}; export const GangMemberTasks = {};
function addGangMemberTask(name, desc, isHacking, isCombat, params) { function addGangMemberTask(name, desc, isHacking, isCombat, params) {
GangMemberTasks[name] = new GangMemberTask(name, desc, isHacking, isCombat, params); GangMemberTasks[name] = new GangMemberTask(name, desc, isHacking, isCombat, params);
@ -981,7 +1005,7 @@ GangMemberUpgrade.fromJSON = function(value) {
Reviver.constructors.GangMemberUpgrade = GangMemberUpgrade; Reviver.constructors.GangMemberUpgrade = GangMemberUpgrade;
// Initialize Gang Member Upgrades // Initialize Gang Member Upgrades
const GangMemberUpgrades = {} export const GangMemberUpgrades = {}
function addGangMemberUpgrade(name, cost, type, mults) { function addGangMemberUpgrade(name, cost, type, mults) {
GangMemberUpgrades[name] = new GangMemberUpgrade(name, cost, type, mults); GangMemberUpgrades[name] = new GangMemberUpgrade(name, cost, type, mults);

@ -120,7 +120,7 @@ export function getCostOfNextHacknetServer() {
const numOwned = Player.hacknetNodes.length; const numOwned = Player.hacknetNodes.length;
const mult = HacknetServerPurchaseMult; const mult = HacknetServerPurchaseMult;
if (numOwned > MaxNumberHacknetServers) { return Infinity; } if (numOwned >= MaxNumberHacknetServers) { return Infinity; }
return BaseCostForHacknetServer * Math.pow(mult, numOwned) * Player.hacknet_node_purchase_cost_mult; return BaseCostForHacknetServer * Math.pow(mult, numOwned) * Player.hacknet_node_purchase_cost_mult;
} }

@ -69,7 +69,6 @@ function iTutorialStart() {
// Don't autosave during this interactive tutorial // Don't autosave during this interactive tutorial
Engine.Counters.autoSaveCounter = Infinity; Engine.Counters.autoSaveCounter = Infinity;
console.log("Interactive Tutorial started");
ITutorial.currStep = 0; ITutorial.currStep = 0;
ITutorial.isRunning = true; ITutorial.isRunning = true;
@ -100,7 +99,7 @@ function iTutorialStart() {
} }
function iTutorialEvaluateStep() { function iTutorialEvaluateStep() {
if (!ITutorial.isRunning) {console.log("Interactive Tutorial not running"); return;} if (!ITutorial.isRunning) {return;}
// Disable and clear main menu // Disable and clear main menu
var terminalMainMenu = clearEventListeners("terminal-menu-link"); var terminalMainMenu = clearEventListeners("terminal-menu-link");
@ -476,8 +475,6 @@ function iTutorialEnd() {
Engine.Counters.autoSaveCounter = Settings.AutosaveInterval * 5; Engine.Counters.autoSaveCounter = Settings.AutosaveInterval * 5;
} }
console.log("Ending interactive tutorial");
// Initialize references to main menu links // Initialize references to main menu links
// We have to call initializeMainMenuLinks() again because the Interactive Tutorial // We have to call initializeMainMenuLinks() again because the Interactive Tutorial
// re-creates Main menu links with clearEventListeners() // re-creates Main menu links with clearEventListeners()

@ -165,7 +165,7 @@ Node.prototype.deselect = function(actionButtons) {
Node.prototype.untarget = function() { Node.prototype.untarget = function() {
if (this.targetedCount === 0) { if (this.targetedCount === 0) {
console.log("WARN: Node " + this.el.id + " is being 'untargeted' when it has no target count"); console.warn(`Node ${this.el.id} is being 'untargeted' when it has no target count`);
return; return;
} }
--this.targetedCount; --this.targetedCount;
@ -214,7 +214,6 @@ function HackingMission(rep, fac) {
this.jsplumbinstance = null; this.jsplumbinstance = null;
this.difficulty = rep / CONSTANTS.HackingMissionRepToDiffConversion + 1; this.difficulty = rep / CONSTANTS.HackingMissionRepToDiffConversion + 1;
console.log("difficulty: " + this.difficulty);
this.reward = 250 + (rep / CONSTANTS.HackingMissionRepToRewardConversion); this.reward = 250 + (rep / CONSTANTS.HackingMissionRepToRewardConversion);
} }
@ -408,7 +407,7 @@ HackingMission.prototype.createPageDom = function() {
// Set Action Button event listeners // Set Action Button event listeners
this.actionButtons[0].addEventListener("click", ()=>{ this.actionButtons[0].addEventListener("click", ()=>{
if (!(this.selectedNode.length > 0)) { if (!(this.selectedNode.length > 0)) {
console.log("ERR: Pressing Action button without selected node"); console.error("Pressing Action button without selected node");
return; return;
} }
if (this.selectedNode[0].type !== NodeTypes.Core) {return;} if (this.selectedNode[0].type !== NodeTypes.Core) {return;}
@ -421,7 +420,7 @@ HackingMission.prototype.createPageDom = function() {
this.actionButtons[1].addEventListener("click", ()=>{ this.actionButtons[1].addEventListener("click", ()=>{
if (!(this.selectedNode.length > 0)) { if (!(this.selectedNode.length > 0)) {
console.log("ERR: Pressing Action button without selected node"); console.error("Pressing Action button without selected node");
return; return;
} }
var nodeType = this.selectedNode[0].type; // In a multiselect, every Node will have the same type var nodeType = this.selectedNode[0].type; // In a multiselect, every Node will have the same type
@ -435,7 +434,7 @@ HackingMission.prototype.createPageDom = function() {
this.actionButtons[2].addEventListener("click", ()=>{ this.actionButtons[2].addEventListener("click", ()=>{
if (!(this.selectedNode.length > 0)) { if (!(this.selectedNode.length > 0)) {
console.log("ERR: Pressing Action button without selected node"); console.error("Pressing Action button without selected node");
return; return;
} }
var nodeType = this.selectedNode[0].type; // In a multiselect, every Node will have the same type var nodeType = this.selectedNode[0].type; // In a multiselect, every Node will have the same type
@ -449,7 +448,7 @@ HackingMission.prototype.createPageDom = function() {
this.actionButtons[3].addEventListener("click", ()=>{ this.actionButtons[3].addEventListener("click", ()=>{
if (!(this.selectedNode.length > 0)) { if (!(this.selectedNode.length > 0)) {
console.log("ERR: Pressing Action button without selected node"); console.error("Pressing Action button without selected node");
return; return;
} }
this.setActionButtonsActive(this.selectedNode[0].type); this.setActionButtonsActive(this.selectedNode[0].type);
@ -461,7 +460,7 @@ HackingMission.prototype.createPageDom = function() {
this.actionButtons[4].addEventListener("click", ()=>{ this.actionButtons[4].addEventListener("click", ()=>{
if (!(this.selectedNode.length > 0)) { if (!(this.selectedNode.length > 0)) {
console.log("ERR: Pressing Action button without selected node"); console.error("Pressing Action button without selected node");
return; return;
} }
var nodeType = this.selectedNode[0].type; var nodeType = this.selectedNode[0].type;
@ -475,7 +474,7 @@ HackingMission.prototype.createPageDom = function() {
this.actionButtons[5].addEventListener("click", ()=>{ this.actionButtons[5].addEventListener("click", ()=>{
if (!(this.selectedNode.length > 0)) { if (!(this.selectedNode.length > 0)) {
console.log("ERR: Pressing Action button without selected node"); console.error("Pressing Action button without selected node");
return; return;
} }
this.selectedNode.forEach(function(node){ this.selectedNode.forEach(function(node){
@ -637,18 +636,16 @@ HackingMission.prototype.removeAvailablePosition = function(x, y) {
return; return;
} }
} }
console.log("WARNING: removeAvailablePosition() did not remove " + x + ", " + y); console.warn(`removeAvailablePosition() did not remove ${x}, ${y}`);
} }
HackingMission.prototype.setNodePosition = function(nodeObj, x, y) { HackingMission.prototype.setNodePosition = function(nodeObj, x, y) {
if (!(nodeObj instanceof Node)) { if (!(nodeObj instanceof Node)) {
console.log("WARNING: Non-Node object passed into setNodePOsition"); console.warn("Non-Node object passed into setNodePOsition");
return; return;
} }
if (isNaN(x) || isNaN(y)) { if (isNaN(x) || isNaN(y)) {
console.log("ERR: Invalid values passed as x and y for setNodePosition"); console.error(`Invalid values (${x}, ${y}) passed as (x, y) for setNodePosition`);
console.log(x);
console.log(y);
return; return;
} }
nodeObj.pos = [x, y]; nodeObj.pos = [x, y];
@ -725,7 +722,6 @@ HackingMission.prototype.createMap = function() {
// Configure all Player CPUS // Configure all Player CPUS
for (var i = 0; i < this.playerCores.length; ++i) { for (var i = 0; i < this.playerCores.length; ++i) {
console.log("Configuring Player Node: " + this.playerCores[i].el.id);
this.configurePlayerNodeElement(this.playerCores[i].el); this.configurePlayerNodeElement(this.playerCores[i].el);
} }
} }
@ -793,7 +789,7 @@ HackingMission.prototype.createNodeDomElement = function(nodeObj) {
HackingMission.prototype.updateNodeDomElement = function(nodeObj) { HackingMission.prototype.updateNodeDomElement = function(nodeObj) {
if (nodeObj.el == null) { if (nodeObj.el == null) {
console.log("ERR: Calling updateNodeDomElement on a Node without an element"); console.error("Calling updateNodeDomElement on a Node without an element");
return; return;
} }
@ -853,12 +849,12 @@ HackingMission.prototype.getNodeFromElement = function(el) {
id = id.replace("hacking-mission-node-", ""); id = id.replace("hacking-mission-node-", "");
var res = id.split('-'); var res = id.split('-');
if (res.length != 2) { if (res.length != 2) {
console.log("ERROR Parsing Hacking Mission Node Id. Could not find coordinates"); console.error("Parsing hacking mission node id. could not find coordinates");
return null; return null;
} }
var x = res[0], y = res[1]; var x = res[0], y = res[1];
if (isNaN(x) || isNaN(y) || x >= 8 || y >= 8 || x < 0 || y < 0) { if (isNaN(x) || isNaN(y) || x >= 8 || y >= 8 || x < 0 || y < 0) {
console.log("ERROR: Unexpected values for x and y: " + x + ", " + y); console.error(`Unexpected values (${x}, ${y}) for (x, y)`);
return null; return null;
} }
return this.map[x][y]; return this.map[x][y];
@ -866,7 +862,7 @@ HackingMission.prototype.getNodeFromElement = function(el) {
function selectNode(hackMissionInst, el) { function selectNode(hackMissionInst, el) {
var nodeObj = hackMissionInst.getNodeFromElement(el); var nodeObj = hackMissionInst.getNodeFromElement(el);
if (nodeObj == null) {console.log("Error getting Node object");} if (nodeObj == null) {console.error("Failed getting Node object");}
if (!nodeObj.plyrCtrl) {return;} if (!nodeObj.plyrCtrl) {return;}
clearAllSelectedNodes(hackMissionInst); clearAllSelectedNodes(hackMissionInst);
@ -876,7 +872,7 @@ function selectNode(hackMissionInst, el) {
function multiselectNode(hackMissionInst, el) { function multiselectNode(hackMissionInst, el) {
var nodeObj = hackMissionInst.getNodeFromElement(el); var nodeObj = hackMissionInst.getNodeFromElement(el);
if (nodeObj == null) {console.log("ERROR: Getting Node Object in multiselectNode()");} if (nodeObj == null) {console.error("Failed getting Node Object in multiselectNode()");}
if (!nodeObj.plyrCtrl) {return;} if (!nodeObj.plyrCtrl) {return;}
clearAllSelectedNodes(hackMissionInst); clearAllSelectedNodes(hackMissionInst);
@ -912,7 +908,7 @@ function clearAllSelectedNodes(hackMissionInst) {
*/ */
HackingMission.prototype.configurePlayerNodeElement = function(el) { HackingMission.prototype.configurePlayerNodeElement = function(el) {
var nodeObj = this.getNodeFromElement(el); var nodeObj = this.getNodeFromElement(el);
if (nodeObj == null) {console.log("Error getting Node object");} if (nodeObj == null) {console.error("Failed getting Node object");}
// Add event listener // Add event listener
var self = this; var self = this;
@ -1239,7 +1235,7 @@ HackingMission.prototype.processNode = function(nodeObj, numCycles=1) {
calcStats = true; calcStats = true;
break; break;
default: default:
console.log("ERR: Invalid Node Action: " + nodeObj.action); console.error(`Invalid Node Action: ${nodeObj.action}`);
break; break;
} }
@ -1452,7 +1448,7 @@ HackingMission.prototype.enemyAISelectAction = function(nodeObj) {
targetNode = this.getNodeFromElement(nodeObj.conn.targetId); targetNode = this.getNodeFromElement(nodeObj.conn.targetId);
} }
if (targetNode == null) { if (targetNode == null) {
console.log("Error getting Target node Object in enemyAISelectAction()"); console.error("Error getting Target node Object in enemyAISelectAction()");
} }
if (targetNode.def > this.enemyAtk + 15) { if (targetNode.def > this.enemyAtk + 15) {
@ -1529,9 +1525,6 @@ HackingMission.prototype.finishMission = function(win) {
if (win) { if (win) {
var favorMult = 1 + (this.faction.favor / 100); var favorMult = 1 + (this.faction.favor / 100);
console.log("Hacking mission base reward: " + this.reward);
console.log("favorMult: " + favorMult);
console.log("rep mult: " + Player.faction_rep_mult);
var gain = this.reward * Player.faction_rep_mult * favorMult; var gain = this.reward * Player.faction_rep_mult * favorMult;
dialogBoxCreate("Mission won! You earned " + dialogBoxCreate("Mission won! You earned " +
formatNumber(gain, 3) + " reputation with " + this.faction.name); formatNumber(gain, 3) + " reputation with " + this.faction.name);

@ -197,6 +197,7 @@ export const RamCosts: IMap<any> = {
createProgram: () => RamCostConstants.ScriptSingularityFn3RamCost, createProgram: () => RamCostConstants.ScriptSingularityFn3RamCost,
commitCrime: () => RamCostConstants.ScriptSingularityFn3RamCost, commitCrime: () => RamCostConstants.ScriptSingularityFn3RamCost,
getCrimeChance: () => RamCostConstants.ScriptSingularityFn3RamCost, getCrimeChance: () => RamCostConstants.ScriptSingularityFn3RamCost,
getCrimeStats: () => RamCostConstants.ScriptSingularityFn3RamCost,
getOwnedAugmentations: () => RamCostConstants.ScriptSingularityFn3RamCost, getOwnedAugmentations: () => RamCostConstants.ScriptSingularityFn3RamCost,
getOwnedSourceFiles: () => RamCostConstants.ScriptSingularityFn3RamCost, getOwnedSourceFiles: () => RamCostConstants.ScriptSingularityFn3RamCost,
getAugmentationsFromFaction: () => RamCostConstants.ScriptSingularityFn3RamCost, getAugmentationsFromFaction: () => RamCostConstants.ScriptSingularityFn3RamCost,
@ -216,10 +217,12 @@ export const RamCosts: IMap<any> = {
canRecruitMember: () => RamCostConstants.ScriptGangApiBaseRamCost / 4, canRecruitMember: () => RamCostConstants.ScriptGangApiBaseRamCost / 4,
recruitMember: () => RamCostConstants.ScriptGangApiBaseRamCost / 2, recruitMember: () => RamCostConstants.ScriptGangApiBaseRamCost / 2,
getTaskNames: () => RamCostConstants.ScriptGangApiBaseRamCost / 4, getTaskNames: () => RamCostConstants.ScriptGangApiBaseRamCost / 4,
getTaskStats: () => RamCostConstants.ScriptGangApiBaseRamCost / 4,
setMemberTask: () => RamCostConstants.ScriptGangApiBaseRamCost / 2, setMemberTask: () => RamCostConstants.ScriptGangApiBaseRamCost / 2,
getEquipmentNames: () => RamCostConstants.ScriptGangApiBaseRamCost / 4, getEquipmentNames: () => RamCostConstants.ScriptGangApiBaseRamCost / 4,
getEquipmentCost: () => RamCostConstants.ScriptGangApiBaseRamCost / 2, getEquipmentCost: () => RamCostConstants.ScriptGangApiBaseRamCost / 2,
getEquipmentType: () => RamCostConstants.ScriptGangApiBaseRamCost / 2, getEquipmentType: () => RamCostConstants.ScriptGangApiBaseRamCost / 2,
getEquipmentStats: () => RamCostConstants.ScriptGangApiBaseRamCost / 2,
purchaseEquipment: () => RamCostConstants.ScriptGangApiBaseRamCost, purchaseEquipment: () => RamCostConstants.ScriptGangApiBaseRamCost,
ascendMember: () => RamCostConstants.ScriptGangApiBaseRamCost, ascendMember: () => RamCostConstants.ScriptGangApiBaseRamCost,
setTerritoryWarfare: () => RamCostConstants.ScriptGangApiBaseRamCost / 2, setTerritoryWarfare: () => RamCostConstants.ScriptGangApiBaseRamCost / 2,

@ -188,7 +188,17 @@ export class WorkerScript {
return (this.disableLogs.ALL == null && this.disableLogs[fn] == null); return (this.disableLogs.ALL == null && this.disableLogs[fn] == null);
} }
log(txt: string): void { log(func: string, txt: string): void {
if(this.shouldLog(func)) {
if(func !== "" && txt !== ""){
this.scriptRef.log(`${func}: ${txt}`);
} else {
this.scriptRef.log(func+txt);
}
}
}
print(txt: string): void {
this.scriptRef.log(txt); this.scriptRef.log(txt);
} }
} }

@ -12,15 +12,4 @@ function unknownBladeburnerExceptionMessage(functionName, err) {
return `bladeburner.${functionName}() failed with exception: ` + err; return `bladeburner.${functionName}() failed with exception: ` + err;
} }
function checkBladeburnerAccess(workerScript, functionName) {
const accessDenied = `${functionName}() failed because you do not ` +
"currently have access to the Bladeburner API. To access the Bladeburner API" +
"you must be employed at the Bladeburner division, AND you must either be in " +
"BitNode-7 or have Source-File 7.";
const hasAccess = Player.bladeburner instanceof Bladeburner && (Player.bitNodeN === 7 || Player.sourceFiles.some(a=>{return a.n === 7}));
if(!hasAccess) {
throw makeRuntimeRejectMsg(workerScript, accessDenied);
}
}
export {unknownBladeburnerActionErrorMessage, unknownBladeburnerExceptionMessage, checkBladeburnerAccess}; export {unknownBladeburnerActionErrorMessage, unknownBladeburnerExceptionMessage, checkBladeburnerAccess};

@ -2,6 +2,7 @@ import { setTimeoutRef } from "./utils/SetTimeoutRef";
import { isValidIPAddress } from "../utils/helpers/isValidIPAddress"; import { isValidIPAddress } from "../utils/helpers/isValidIPAddress";
import { isString } from "../utils/helpers/isString"; import { isString } from "../utils/helpers/isString";
import { AllServers } from "./Server/AllServers";
export function netscriptDelay(time, workerScript) { export function netscriptDelay(time, workerScript) {
return new Promise(function(resolve, reject) { return new Promise(function(resolve, reject) {
@ -19,7 +20,12 @@ export function makeRuntimeRejectMsg(workerScript, msg, exp=null) {
var num = getErrorLineNumber(exp, workerScript); var num = getErrorLineNumber(exp, workerScript);
lineNum = " (Line " + num + ")" lineNum = " (Line " + num + ")"
} }
return "|"+workerScript.serverIp+"|"+workerScript.name+"|" + msg + lineNum; const server = AllServers[workerScript.serverIp];
if (server == null) {
throw new Error(`WorkerScript constructed with invalid server ip: ${this.serverIp}`);
}
return "|"+server.hostname+"|"+workerScript.name+"|" + msg + lineNum;
} }
export function resolveNetscriptRequestedThreads(workerScript, functionName, requestedThreads) { export function resolveNetscriptRequestedThreads(workerScript, functionName, requestedThreads) {
@ -57,8 +63,5 @@ export function isScriptErrorMessage(msg) {
return false; return false;
} }
var ip = splitMsg[1]; var ip = splitMsg[1];
if (!isValidIPAddress(ip)) {
return false;
}
return true; return true;
} }

File diff suppressed because it is too large Load Diff

@ -6,10 +6,3 @@ export function unknownGangApiExceptionMessage(functionName, err) {
return `gang.${functionName}() failed with exception: ` + err; return `gang.${functionName}() failed with exception: ` + err;
} }
export function checkGangApiAccess(workerScript, functionName) {
const accessDenied = `gang.${functionName}() failed because you do not currently have a Gang`;
const hasAccess = Player.gang instanceof Gang;
if (!hasAccess) {
throw makeRuntimeRejectMsg(workerScript, accessDenied);
}
}

@ -1,21 +1,12 @@
import { makeRuntimeRejectMsg } from "./NetscriptEvaluator"; import { makeRuntimeRejectMsg } from "./NetscriptEvaluator";
import { Script } from "./Script/Script"; import { Script } from "./Script/Script";
import { ScriptUrl } from "./Script/ScriptUrl";
// Makes a blob that contains the code of a given script. // Makes a blob that contains the code of a given script.
export function makeScriptBlob(code) { export function makeScriptBlob(code) {
return new Blob([code], {type: "text/javascript"}); return new Blob([code], {type: "text/javascript"});
} }
class ScriptUrl {
/**
* @param {string} filename
* @param {string} url
*/
constructor(filename, url) {
this.filename = filename;
this.url = url;
}
}
// Begin executing a user JS script, and return a promise that resolves // Begin executing a user JS script, and return a promise that resolves
// or rejects when the script finishes. // or rejects when the script finishes.
@ -38,8 +29,9 @@ export async function executeJSScript(scripts = [], workerScript) {
// load fully dynamic content. So we hide the import from webpack // load fully dynamic content. So we hide the import from webpack
// by placing it inside an eval call. // by placing it inside an eval call.
urls = _getScriptUrls(script, scripts, []); urls = _getScriptUrls(script, scripts, []);
script.url = urls[urls.length - 1].url;
script.module = new Promise(resolve => resolve(eval('import(urls[urls.length - 1].url)'))); script.module = new Promise(resolve => resolve(eval('import(urls[urls.length - 1].url)')));
script.dependencies = urls.map(u => u.filename); script.dependencies = urls;
} }
loadedModule = await script.module; loadedModule = await script.module;
@ -68,7 +60,7 @@ export async function executeJSScript(scripts = [], workerScript) {
function shouldCompile(script, scripts) { function shouldCompile(script, scripts) {
if (script.module === "") return true; if (script.module === "") return true;
return script.dependencies.some(dep => { return script.dependencies.some(dep => {
const depScript = scripts.find(s => s.filename == dep); const depScript = scripts.find(s => s.filename == dep.url);
// If the script is not present on the server, we should recompile, if only to get any necessary // If the script is not present on the server, we should recompile, if only to get any necessary
// compilation errors. // compilation errors.

@ -501,7 +501,7 @@ export function createAndAddWorkerScript(runningScriptObj, server) {
if (!w.running) { return; } if (!w.running) { return; }
killWorkerScript(s); killWorkerScript(s);
w.log("Script finished running"); w.log("", "Script finished running");
}).catch(function(w) { }).catch(function(w) {
if (w instanceof Error) { if (w instanceof Error) {
dialogBoxCreate("Script runtime unknown error. This is a bug please contact game developer"); dialogBoxCreate("Script runtime unknown error. This is a bug please contact game developer");
@ -509,22 +509,27 @@ export function createAndAddWorkerScript(runningScriptObj, server) {
return; return;
} else if (w instanceof WorkerScript) { } else if (w instanceof WorkerScript) {
if (isScriptErrorMessage(w.errorMessage)) { if (isScriptErrorMessage(w.errorMessage)) {
var errorTextArray = w.errorMessage.split("|"); const errorTextArray = w.errorMessage.split("|");
if (errorTextArray.length != 4) { if (errorTextArray.length != 4) {
console.error("ERROR: Something wrong with Error text in evaluator..."); console.error("ERROR: Something wrong with Error text in evaluator...");
console.error("Error text: " + errorText); console.error("Error text: " + errorText);
return; return;
} }
var serverIp = errorTextArray[1]; const serverIp = errorTextArray[1];
var scriptName = errorTextArray[2]; const scriptName = errorTextArray[2];
var errorMsg = errorTextArray[3]; const errorMsg = errorTextArray[3];
dialogBoxCreate("Script runtime error: <br>Server Ip: " + serverIp + let msg = `RUNTIME ERROR<br>${scriptName}@${serverIp}<br>`
"<br>Script name: " + scriptName + if (w.args.length > 0) {
"<br>Args:" + arrayToString(w.args) + "<br>" + errorMsg); msg += `Args: ${arrayToString(w.args)}<br>`
w.log("Script crashed with runtime error"); }
msg += "<br>";
msg += errorMsg;
dialogBoxCreate(msg);
w.log("", "Script crashed with runtime error");
} else { } else {
w.log("Script killed"); w.log("", "Script killed");
return; // Already killed, so stop here return; // Already killed, so stop here
} }
w.running = false; w.running = false;
@ -594,14 +599,14 @@ export function loadAllRunningScripts() {
/** /**
* Run a script from inside another script (run(), exec(), spawn(), etc.) * Run a script from inside another script (run(), exec(), spawn(), etc.)
*/ */
export function runScriptFromScript(server, scriptname, args, workerScript, threads=1) { export function runScriptFromScript(caller, server, scriptname, args, workerScript, threads=1) {
// Sanitize arguments // Sanitize arguments
if (!(workerScript instanceof WorkerScript)) { if (!(workerScript instanceof WorkerScript)) {
return 0; return 0;
} }
if (typeof scriptname !== "string" || !Array.isArray(args)) { if (typeof scriptname !== "string" || !Array.isArray(args)) {
workerScript.log(`ERROR: runScriptFromScript() failed due to invalid arguments`); workerScript.log(caller, `Invalid arguments: scriptname='${scriptname} args='${ags}'`);
console.error(`runScriptFromScript() failed due to invalid arguments`); console.error(`runScriptFromScript() failed due to invalid arguments`);
return 0; return 0;
} }
@ -609,14 +614,14 @@ export function runScriptFromScript(server, scriptname, args, workerScript, thre
// Check if the script is already running // Check if the script is already running
let runningScriptObj = server.getRunningScript(scriptname, args); let runningScriptObj = server.getRunningScript(scriptname, args);
if (runningScriptObj != null) { if (runningScriptObj != null) {
workerScript.log(`${scriptname} is already running on ${server.hostname}`); workerScript.log(caller, `'${scriptname}' is already running on '${server.hostname}'`);
return 0; return 0;
} }
// 'null/undefined' arguments are not allowed // 'null/undefined' arguments are not allowed
for (let i = 0; i < args.length; ++i) { for (let i = 0; i < args.length; ++i) {
if (args[i] == null) { if (args[i] == null) {
workerScript.log("ERROR: Cannot execute a script with null/undefined as an argument"); workerScript.log(caller, "Cannot execute a script with null/undefined as an argument");
return 0; return 0;
} }
} }
@ -633,16 +638,14 @@ export function runScriptFromScript(server, scriptname, args, workerScript, thre
const ramAvailable = server.maxRam - server.ramUsed; const ramAvailable = server.maxRam - server.ramUsed;
if (server.hasAdminRights == false) { if (server.hasAdminRights == false) {
workerScript.log(`Cannot run script ${scriptname} on ${server.hostname} because you do not have root access!`); workerScript.log(caller, `You do not have root access on '${server.hostname}'`);
return 0; return 0;
} else if (ramUsage > ramAvailable){ } else if (ramUsage > ramAvailable){
workerScript.log(`Cannot run script ${scriptname} (t=${threads}) on ${server.hostname} because there is not enough available RAM!`); workerScript.log(caller, `Cannot run script '${scriptname}' (t=${threads}) on '${server.hostname}' because there is not enough available RAM!`);
return 0; return 0;
} else { } else {
// Able to run script // Able to run script
if (workerScript.disableLogs.ALL == null && workerScript.disableLogs.exec == null && workerScript.disableLogs.run == null && workerScript.disableLogs.spawn == null) { workerScript.log(caller, `'${scriptname}' on '${server.hostname}' with ${threads} threads and args: ${arrayToString(args)}.`);
workerScript.log(`Running script: ${scriptname} on ${server.hostname} with ${threads} threads and args: ${arrayToString(args)}.`);
}
let runningScriptObj = new RunningScript(script, args); let runningScriptObj = new RunningScript(script, args);
runningScriptObj.threads = threads; runningScriptObj.threads = threads;
@ -651,6 +654,6 @@ export function runScriptFromScript(server, scriptname, args, workerScript, thre
} }
} }
workerScript.log(`Could not find script ${scriptname} on ${server.hostname}`); workerScript.log(caller, `Could not find script '${scriptname}' on '${server.hostname}'`);
return 0; return 0;
} }

@ -62,7 +62,7 @@ function Perk(name, reqRep, info) {
Perk.prototype.setCompany = function(companyName) { Perk.prototype.setCompany = function(companyName) {
if (this.factionPerk) { if (this.factionPerk) {
console.log("ERR: Perk cannot be both faction and company perk"); console.error("Perk cannot be both faction and company perk");
return; return;
} }
this.companyPerk = true; this.companyPerk = true;
@ -71,7 +71,7 @@ Perk.prototype.setCompany = function(companyName) {
Perk.prototype.setFaction = function(factionName) { Perk.prototype.setFaction = function(factionName) {
if (this.companyPerk) { if (this.companyPerk) {
console.log("ERR: Perk cannot be both faction and company perk"); console.error("Perk cannot be both faction and company perk");
return; return;
} }
this.factionPerk = true; this.factionPerk = true;
@ -145,7 +145,7 @@ applyPerk = function(perk) {
case PerkNames.InsiderKnowledgeFactionPerk: case PerkNames.InsiderKnowledgeFactionPerk:
break; break;
default: default:
console.log("WARNING: Unrecognized perk: " + perk.name); console.warn(`Unrecognized perk: ${perk.name}`);
return; return;
} }
} }

@ -19,6 +19,7 @@ import { LocationName } from "../Locations/data/LocationNames";
import { Server } from "../Server/Server"; import { Server } from "../Server/Server";
import { IPlayerOwnedSourceFile } from "../SourceFile/PlayerOwnedSourceFile"; import { IPlayerOwnedSourceFile } from "../SourceFile/PlayerOwnedSourceFile";
import { MoneySourceTracker } from "../utils/MoneySourceTracker"; import { MoneySourceTracker } from "../utils/MoneySourceTracker";
import { Exploit } from "../Exploits/Exploit";
export interface IPlayer { export interface IPlayer {
// Class members // Class members
@ -56,6 +57,7 @@ export interface IPlayer {
sleeves: Sleeve[]; sleeves: Sleeve[];
sleevesFromCovenant: number; sleevesFromCovenant: number;
sourceFiles: IPlayerOwnedSourceFile[]; sourceFiles: IPlayerOwnedSourceFile[];
exploits: Exploit[];
totalPlaytime: number; totalPlaytime: number;
// Stats // Stats
@ -173,4 +175,5 @@ export interface IPlayer {
startWork(companyName: string): void; startWork(companyName: string): void;
startWorkPartTime(companyName: string): void; startWorkPartTime(companyName: string): void;
travel(to: CityName): boolean; travel(to: CityName): boolean;
giveExploit(exploit: Exploit): void;
} }

@ -201,6 +201,8 @@ export function PlayerObject() {
// Production since last Augmentation installation // Production since last Augmentation installation
this.scriptProdSinceLastAug = 0; this.scriptProdSinceLastAug = 0;
this.exploits = [];
}; };
// Apply player methods to the prototype using Object.assign() // Apply player methods to the prototype using Object.assign()

@ -37,6 +37,7 @@ import { safetlyCreateUniqueServer } from "../../Server/ServerHelpers";
import { Settings } from "../../Settings/Settings"; import { Settings } from "../../Settings/Settings";
import { SpecialServerIps, SpecialServerNames } from "../../Server/SpecialServerIps"; import { SpecialServerIps, SpecialServerNames } from "../../Server/SpecialServerIps";
import { applySourceFile } from "../../SourceFile/applySourceFile"; import { applySourceFile } from "../../SourceFile/applySourceFile";
import { applyExploit } from "../../Exploits/applyExploits";
import { SourceFiles } from "../../SourceFile/SourceFiles"; import { SourceFiles } from "../../SourceFile/SourceFiles";
import { SourceFileFlags } from "../../SourceFile/SourceFileFlags"; import { SourceFileFlags } from "../../SourceFile/SourceFileFlags";
import { influenceStockThroughCompanyWork } from "../../StockMarket/PlayerInfluencing"; import { influenceStockThroughCompanyWork } from "../../StockMarket/PlayerInfluencing";
@ -726,7 +727,7 @@ export function workPartTime(numCycles) {
var comp = Companies[this.companyName], companyRep = "0"; var comp = Companies[this.companyName], companyRep = "0";
if (comp == null || !(comp instanceof Company)) { if (comp == null || !(comp instanceof Company)) {
console.log("ERROR: Could not find Company: " + this.companyName); console.error(`Could not find Company: ${this.companyName}`);
} else { } else {
companyRep = comp.playerReputation; companyRep = comp.playerReputation;
} }
@ -1417,8 +1418,7 @@ export function finishCrime(cancelled) {
} }
} }
if(crime == null) { if(crime == null) {
console.log(this.crimeType); dialogBoxCreate(`ERR: Unrecognized crime type (${this.crimeType}). This is probably a bug please contact the developer`);
dialogBoxCreate("ERR: Unrecognized crime type. This is probably a bug please contact the developer");
} }
this.gainMoney(this.workMoneyGained); this.gainMoney(this.workMoneyGained);
this.recordMoneySource(this.workMoneyGained, "crime"); this.recordMoneySource(this.workMoneyGained, "crime");
@ -1529,7 +1529,7 @@ export function singularityStopWork() {
res = this.finishCrime(true); res = this.finishCrime(true);
break; break;
default: default:
console.log("ERROR: Unrecognized work type"); console.error(`Unrecognized work type (${this.workType})`);
return ""; return "";
} }
return res; return res;
@ -1840,7 +1840,7 @@ export function reapplyAllAugmentations(resetMultipliers=true) {
const augName = this.augmentations[i].name; const augName = this.augmentations[i].name;
var aug = Augmentations[augName]; var aug = Augmentations[augName];
if (aug == null) { if (aug == null) {
console.log(`WARNING: Invalid augmentation name in Player.reapplyAllAugmentations(). Aug ${augName} will be skipped`); console.warn(`Invalid augmentation name in Player.reapplyAllAugmentations(). Aug ${augName} will be skipped`);
continue; continue;
} }
aug.owned = true; aug.owned = true;
@ -1862,11 +1862,12 @@ export function reapplyAllSourceFiles() {
var srcFileKey = "SourceFile" + this.sourceFiles[i].n; var srcFileKey = "SourceFile" + this.sourceFiles[i].n;
var sourceFileObject = SourceFiles[srcFileKey]; var sourceFileObject = SourceFiles[srcFileKey];
if (sourceFileObject == null) { if (sourceFileObject == null) {
console.log("ERROR: Invalid source file number: " + this.sourceFiles[i].n); console.error(`Invalid source file number: ${this.sourceFiles[i].n}`);
continue; continue;
} }
applySourceFile(this.sourceFiles[i]); applySourceFile(this.sourceFiles[i]);
} }
applyExploit();
} }
/*************** Check for Faction Invitations *************/ /*************** Check for Faction Invitations *************/
@ -2003,7 +2004,7 @@ export function checkForFactionInvitations() {
var fulcrumsecrettechonologiesFac = Factions["Fulcrum Secret Technologies"]; var fulcrumsecrettechonologiesFac = Factions["Fulcrum Secret Technologies"];
var fulcrumSecretServer = AllServers[SpecialServerIps[SpecialServerNames.FulcrumSecretTechnologies]]; var fulcrumSecretServer = AllServers[SpecialServerIps[SpecialServerNames.FulcrumSecretTechnologies]];
if (fulcrumSecretServer == null) { if (fulcrumSecretServer == null) {
console.log("ERROR: Could not find Fulcrum Secret Technologies Server"); console.error("Could not find Fulcrum Secret Technologies Server");
} else { } else {
if (!fulcrumsecrettechonologiesFac.isBanned && !fulcrumsecrettechonologiesFac.isMember && if (!fulcrumsecrettechonologiesFac.isBanned && !fulcrumsecrettechonologiesFac.isMember &&
!fulcrumsecrettechonologiesFac.alreadyInvited && !fulcrumsecrettechonologiesFac.alreadyInvited &&
@ -2018,7 +2019,7 @@ export function checkForFactionInvitations() {
var homeComp = this.getHomeComputer(); var homeComp = this.getHomeComputer();
var bitrunnersServer = AllServers[SpecialServerIps[SpecialServerNames.BitRunnersServer]]; var bitrunnersServer = AllServers[SpecialServerIps[SpecialServerNames.BitRunnersServer]];
if (bitrunnersServer == null) { if (bitrunnersServer == null) {
console.log("ERROR: Could not find BitRunners Server"); console.error("Could not find BitRunners Server");
} else if (!bitrunnersFac.isBanned && !bitrunnersFac.isMember && bitrunnersServer.manuallyHacked && } else if (!bitrunnersFac.isBanned && !bitrunnersFac.isMember && bitrunnersServer.manuallyHacked &&
!bitrunnersFac.alreadyInvited && this.hacking_skill >= 500 && homeComp.maxRam >= 128) { !bitrunnersFac.alreadyInvited && this.hacking_skill >= 500 && homeComp.maxRam >= 128) {
invitedFactions.push(bitrunnersFac); invitedFactions.push(bitrunnersFac);
@ -2028,7 +2029,7 @@ export function checkForFactionInvitations() {
var theblackhandFac = Factions["The Black Hand"]; var theblackhandFac = Factions["The Black Hand"];
var blackhandServer = AllServers[SpecialServerIps[SpecialServerNames.TheBlackHandServer]]; var blackhandServer = AllServers[SpecialServerIps[SpecialServerNames.TheBlackHandServer]];
if (blackhandServer == null) { if (blackhandServer == null) {
console.log("ERROR: Could not find The Black Hand Server"); console.error("Could not find The Black Hand Server");
} else if (!theblackhandFac.isBanned && !theblackhandFac.isMember && blackhandServer.manuallyHacked && } else if (!theblackhandFac.isBanned && !theblackhandFac.isMember && blackhandServer.manuallyHacked &&
!theblackhandFac.alreadyInvited && this.hacking_skill >= 350 && homeComp.maxRam >= 64) { !theblackhandFac.alreadyInvited && this.hacking_skill >= 350 && homeComp.maxRam >= 64) {
invitedFactions.push(theblackhandFac); invitedFactions.push(theblackhandFac);
@ -2038,7 +2039,7 @@ export function checkForFactionInvitations() {
var nitesecFac = Factions["NiteSec"]; var nitesecFac = Factions["NiteSec"];
var nitesecServer = AllServers[SpecialServerIps[SpecialServerNames.NiteSecServer]]; var nitesecServer = AllServers[SpecialServerIps[SpecialServerNames.NiteSecServer]];
if (nitesecServer == null) { if (nitesecServer == null) {
console.log("ERROR: Could not find NiteSec Server"); console.error("Could not find NiteSec Server");
} else if (!nitesecFac.isBanned && !nitesecFac.isMember && nitesecServer.manuallyHacked && } else if (!nitesecFac.isBanned && !nitesecFac.isMember && nitesecServer.manuallyHacked &&
!nitesecFac.alreadyInvited && this.hacking_skill >= 200 && homeComp.maxRam >= 32) { !nitesecFac.alreadyInvited && this.hacking_skill >= 200 && homeComp.maxRam >= 32) {
invitedFactions.push(nitesecFac); invitedFactions.push(nitesecFac);
@ -2182,7 +2183,7 @@ export function checkForFactionInvitations() {
var cybersecFac = Factions["CyberSec"]; var cybersecFac = Factions["CyberSec"];
var cybersecServer = AllServers[SpecialServerIps[SpecialServerNames.CyberSecServer]]; var cybersecServer = AllServers[SpecialServerIps[SpecialServerNames.CyberSecServer]];
if (cybersecServer == null) { if (cybersecServer == null) {
console.log("ERROR: Could not find CyberSec Server"); console.error("Could not find CyberSec Server");
} else if (!cybersecFac.isBanned && !cybersecFac.isMember && cybersecServer.manuallyHacked && } else if (!cybersecFac.isBanned && !cybersecFac.isMember && cybersecServer.manuallyHacked &&
!cybersecFac.alreadyInvited && this.hacking_skill >= 50) { !cybersecFac.alreadyInvited && this.hacking_skill >= 50) {
invitedFactions.push(cybersecFac); invitedFactions.push(cybersecFac);
@ -2199,14 +2200,14 @@ export function setBitNodeNumber(n) {
export function queueAugmentation(name) { export function queueAugmentation(name) {
for(const i in this.queuedAugmentations) { for(const i in this.queuedAugmentations) {
if(this.queuedAugmentations[i].name == name) { if(this.queuedAugmentations[i].name == name) {
console.log('tried to queue '+name+' twice, this may be a bug'); console.warn(`tried to queue ${name} twice, this may be a bug`);
return; return;
} }
} }
for(const i in this.augmentations) { for(const i in this.augmentations) {
if(this.augmentations[i].name == name) { if(this.augmentations[i].name == name) {
console.log('tried to queue '+name+' but we already have that aug'); console.warn(`tried to queue ${name} twice, this may be a bug`);
return; return;
} }
} }
@ -2299,3 +2300,9 @@ export function gotoLocation(to) {
export function canAccessResleeving() { export function canAccessResleeving() {
return this.bitNodeN === 10 || (SourceFileFlags[10] > 0); return this.bitNodeN === 10 || (SourceFileFlags[10] > 0);
} }
export function giveExploit(exploit) {
if(!this.exploits.includes(exploit)) {
this.exploits.push(exploit);
}
}

@ -1,5 +1,6 @@
import { Corporation } from "./Corporation/Corporation"; import { Corporation } from "./Corporation/Corporation";
import { PlayerObject } from "./PersonObjects/Player/PlayerObject"; import { PlayerObject } from "./PersonObjects/Player/PlayerObject";
import { sanitizeExploits } from "./Exploits/Exploit";
import { Reviver } from "../utils/JSONReviver"; import { Reviver } from "../utils/JSONReviver";
@ -26,4 +27,6 @@ export function loadPlayer(saveString) {
ind.thisCycleExpenses = new Decimal(ind.thisCycleExpenses); ind.thisCycleExpenses = new Decimal(ind.thisCycleExpenses);
} }
} }
Player.exploits = sanitizeExploits(Player.exploits);
} }

@ -96,7 +96,7 @@ function hackWorldDaemon(currentNodeNumber, flume=false) {
}).then(function() { }).then(function() {
return loadBitVerse(currentNodeNumber, flume); return loadBitVerse(currentNodeNumber, flume);
}).catch(function(e){ }).catch(function(e){
console.log("ERROR: " + e.toString()); console.error(e.toString());
}); });
} }
@ -104,7 +104,7 @@ function giveSourceFile(bitNodeNumber) {
var sourceFileKey = "SourceFile"+ bitNodeNumber.toString(); var sourceFileKey = "SourceFile"+ bitNodeNumber.toString();
var sourceFile = SourceFiles[sourceFileKey]; var sourceFile = SourceFiles[sourceFileKey];
if (sourceFile == null) { if (sourceFile == null) {
console.log("ERROR: could not find source file for Bit node: " + bitNodeNumber); console.error(`Could not find source file for Bit node: ${bitNodeNumber}`);
return; return;
} }
@ -264,7 +264,7 @@ function loadBitVerse(destroyedBitNodeNum, flume=false) {
}).then(function() { }).then(function() {
return Promise.resolve(true); return Promise.resolve(true);
}).catch(function(e){ }).catch(function(e){
console.log("ERROR: " + e.toString()); console.error(e.toString());
}); });
} }
@ -308,7 +308,6 @@ function createBitNodeYesNoEventListener(newBitNode, destroyedBitNode, flume=fal
// Set new Bit Node // Set new Bit Node
Player.bitNodeN = newBitNode; Player.bitNodeN = newBitNode;
console.log(`Entering Bit Node ${Player.bitNodeN}`);
// Reenable terminal // Reenable terminal
$("#hack-progress-bar").attr('id', "old-hack-progress-bar"); $("#hack-progress-bar").attr('id', "old-hack-progress-bar");

@ -322,7 +322,7 @@ function loadImportedGame(saveObj, saveString) {
try { try {
tempAliases = JSON.parse(tempSaveObj.AliasesSave, Reviver); tempAliases = JSON.parse(tempSaveObj.AliasesSave, Reviver);
} catch(e) { } catch(e) {
console.log("Parsing Aliases save failed: " + e); console.error(`Parsing Aliases save failed: ${e}`);
tempAliases = {}; tempAliases = {};
} }
} else { } else {
@ -332,7 +332,7 @@ function loadImportedGame(saveObj, saveString) {
try { try {
tempGlobalAliases = JSON.parse(tempSaveObj.AliasesSave, Reviver); tempGlobalAliases = JSON.parse(tempSaveObj.AliasesSave, Reviver);
} catch(e) { } catch(e) {
console.log("Parsing Global Aliases save failed: " + e); console.error(`Parsing Global Aliases save failed: ${e}`);
tempGlobalAliases = {}; tempGlobalAliases = {};
} }
} else { } else {
@ -342,7 +342,7 @@ function loadImportedGame(saveObj, saveString) {
try { try {
tempMessages = JSON.parse(tempSaveObj.MessagesSave, Reviver); tempMessages = JSON.parse(tempSaveObj.MessagesSave, Reviver);
} catch(e) { } catch(e) {
console.log("Parsing Messages save failed: " + e); console.error(`Parsing Messages save failed: ${e}`);
initMessages(); initMessages();
} }
} else { } else {
@ -352,7 +352,7 @@ function loadImportedGame(saveObj, saveString) {
try { try {
tempStockMarket = JSON.parse(tempSaveObj.StockMarketSave, Reviver); tempStockMarket = JSON.parse(tempSaveObj.StockMarketSave, Reviver);
} catch(e) { } catch(e) {
console.log("Parsing StockMarket save failed: " + e); console.error(`Parsing StockMarket save failed: ${e}`);
tempStockMarket = {}; tempStockMarket = {};
} }
} else { } else {
@ -479,7 +479,6 @@ function loadImportedGame(saveObj, saveString) {
gameOptionsBoxClose(); gameOptionsBoxClose();
// Re-start game // Re-start game
console.log("Importing game");
Engine.setDisplayElements(); // Sets variables for important DOM elements Engine.setDisplayElements(); // Sets variables for important DOM elements
Engine.init(); // Initialize buttons, work, etc. Engine.init(); // Initialize buttons, work, etc.
@ -491,7 +490,6 @@ function loadImportedGame(saveObj, saveString) {
// Process offline progress // Process offline progress
var offlineProductionFromScripts = loadAllRunningScripts(); // This also takes care of offline production for those scripts var offlineProductionFromScripts = loadAllRunningScripts(); // This also takes care of offline production for those scripts
if (Player.isWorking) { if (Player.isWorking) {
console.log("work() called in load() for " + numCyclesOffline * Engine._idleSpeed + " milliseconds");
if (Player.workType == CONSTANTS.WorkTypeFaction) { if (Player.workType == CONSTANTS.WorkTypeFaction) {
Player.workForFaction(numCyclesOffline); Player.workForFaction(numCyclesOffline);
} else if (Player.workType == CONSTANTS.WorkTypeCreateProgram) { } else if (Player.workType == CONSTANTS.WorkTypeCreateProgram) {
@ -588,7 +586,7 @@ BitburnerSaveObject.prototype.deleteGame = function(db) {
console.log("Successfully deleted save from indexedDb"); console.log("Successfully deleted save from indexedDb");
} }
request.onerror = function(e) { request.onerror = function(e) {
console.log("Failed to delete save from indexedDb: " + e); console.error(`Failed to delete save from indexedDb: ${e}`);
} }
createStatusText("Game deleted!"); createStatusText("Game deleted!");
} }

@ -167,7 +167,7 @@ async function parseOnlyRamCalculate(otherScripts, code, workerScript) {
} }
return 0; return 0;
} catch(e) { } catch(e) {
console.log("ERROR applying function: " + e); console.error(`Error applying function: ${e}`);
return 0; return 0;
} }
} else { } else {

@ -5,6 +5,7 @@
* being evaluated. See RunningScript for that * being evaluated. See RunningScript for that
*/ */
import { calculateRamUsage } from "./RamCalculations"; import { calculateRamUsage } from "./RamCalculations";
import { ScriptUrl } from "./ScriptUrl";
import { Page, routing } from "../ui/navigationTracking"; import { Page, routing } from "../ui/navigationTracking";
import { setTimeoutRef } from "../utils/SetTimeoutRef"; import { setTimeoutRef } from "../utils/SetTimeoutRef";
@ -29,6 +30,9 @@ export class Script {
// Filename for the script file // Filename for the script file
filename: string = ""; filename: string = "";
// url of the script if any, only for NS2.
url: string = "";
// The dynamic module generated for this script when it is run. // The dynamic module generated for this script when it is run.
// This is only applicable for NetscriptJS // This is only applicable for NetscriptJS
module: any = ""; module: any = "";
@ -39,7 +43,7 @@ export class Script {
// Only used with NS2 scripts; the list of dependency script filenames. This is constructed // Only used with NS2 scripts; the list of dependency script filenames. This is constructed
// whenever the script is first evaluated, and therefore may be out of date if the script // whenever the script is first evaluated, and therefore may be out of date if the script
// has been updated since it was last run. // has been updated since it was last run.
dependencies: string[] = []; dependencies: ScriptUrl[] = [];
// Amount of RAM this Script requres to run // Amount of RAM this Script requres to run
ramUsage: number = 0; ramUsage: number = 0;

@ -167,7 +167,6 @@ export function getCurrentEditor() {
case EditorSetting.CodeMirror: case EditorSetting.CodeMirror:
return CodeMirrorEditor; return CodeMirrorEditor;
default: default:
console.log(`Invalid Editor Setting: ${Settings.Editor}`);
throw new Error(`Invalid Editor Setting: ${Settings.Editor}`); throw new Error(`Invalid Editor Setting: ${Settings.Editor}`);
return null; return null;
} }
@ -334,7 +333,6 @@ export function scriptCalculateOfflineProduction(runningScriptObj) {
var serv = AllServers[ip]; var serv = AllServers[ip];
if (serv == null) {continue;} if (serv == null) {continue;}
var timesGrown = Math.round(0.5 * runningScriptObj.dataMap[ip][2] / runningScriptObj.onlineRunningTime * timePassed); var timesGrown = Math.round(0.5 * runningScriptObj.dataMap[ip][2] / runningScriptObj.onlineRunningTime * timePassed);
console.log(runningScriptObj.filename + " called grow() on " + serv.hostname + " " + timesGrown + " times while offline");
runningScriptObj.log("Called grow() on " + serv.hostname + " " + timesGrown + " times while offline"); runningScriptObj.log("Called grow() on " + serv.hostname + " " + timesGrown + " times while offline");
var growth = processSingleServerGrowth(serv, timesGrown * 450, Player); var growth = processSingleServerGrowth(serv, timesGrown * 450, Player);
runningScriptObj.log(serv.hostname + " grown by " + numeralWrapper.format(growth * 100 - 100, '0.000000%') + " from grow() calls made while offline"); runningScriptObj.log(serv.hostname + " grown by " + numeralWrapper.format(growth * 100 - 100, '0.000000%') + " from grow() calls made while offline");
@ -356,7 +354,6 @@ export function scriptCalculateOfflineProduction(runningScriptObj) {
totalOfflineProduction += production; totalOfflineProduction += production;
Player.gainMoney(production); Player.gainMoney(production);
Player.recordMoneySource(production, "hacking"); Player.recordMoneySource(production, "hacking");
console.log(runningScriptObj.filename + " generated $" + production + " while offline by hacking " + serv.hostname);
runningScriptObj.log(runningScriptObj.filename + " generated $" + production + " while offline by hacking " + serv.hostname); runningScriptObj.log(runningScriptObj.filename + " generated $" + production + " while offline by hacking " + serv.hostname);
serv.moneyAvailable -= production; serv.moneyAvailable -= production;
if (serv.moneyAvailable < 0) {serv.moneyAvailable = 0;} if (serv.moneyAvailable < 0) {serv.moneyAvailable = 0;}
@ -383,7 +380,6 @@ export function scriptCalculateOfflineProduction(runningScriptObj) {
var serv = AllServers[ip]; var serv = AllServers[ip];
if (serv == null) {continue;} if (serv == null) {continue;}
var timesHacked = Math.round(0.5 * runningScriptObj.dataMap[ip][1] / runningScriptObj.onlineRunningTime * timePassed); var timesHacked = Math.round(0.5 * runningScriptObj.dataMap[ip][1] / runningScriptObj.onlineRunningTime * timePassed);
console.log(runningScriptObj.filename + " hacked " + serv.hostname + " " + timesHacked + " times while offline");
runningScriptObj.log("Hacked " + serv.hostname + " " + timesHacked + " times while offline"); runningScriptObj.log("Hacked " + serv.hostname + " " + timesHacked + " times while offline");
serv.fortify(CONSTANTS.ServerFortifyAmount * timesHacked); serv.fortify(CONSTANTS.ServerFortifyAmount * timesHacked);
} }
@ -396,7 +392,6 @@ export function scriptCalculateOfflineProduction(runningScriptObj) {
var serv = AllServers[ip]; var serv = AllServers[ip];
if (serv == null) {continue;} if (serv == null) {continue;}
var timesWeakened = Math.round(0.5 * runningScriptObj.dataMap[ip][3] / runningScriptObj.onlineRunningTime * timePassed); var timesWeakened = Math.round(0.5 * runningScriptObj.dataMap[ip][3] / runningScriptObj.onlineRunningTime * timePassed);
console.log(runningScriptObj.filename + " called weaken() on " + serv.hostname + " " + timesWeakened + " times while offline");
runningScriptObj.log("Called weaken() on " + serv.hostname + " " + timesWeakened + " times while offline"); runningScriptObj.log("Called weaken() on " + serv.hostname + " " + timesWeakened + " times while offline");
serv.weaken(CONSTANTS.ServerWeakenAmount * timesWeakened); serv.weaken(CONSTANTS.ServerWeakenAmount * timesWeakened);
} }

9
src/Script/ScriptUrl.ts Normal file

@ -0,0 +1,9 @@
export class ScriptUrl {
filename: string;
url: string;
constructor(filename: string, url: string) {
this.filename = filename;
this.url = url;
}
}

@ -87,7 +87,7 @@ let NetscriptFunctions =
"getCompanyFavor|stopAction|getFactionFavor|" + "getCompanyFavor|stopAction|getFactionFavor|" +
"getFavorToDonate|getFactionFavorGain|getCompanyFavorGain|" + "getFavorToDonate|getFactionFavorGain|getCompanyFavorGain|" +
"checkFactionInvitations|joinFaction|workForFaction|getFactionRep|" + "checkFactionInvitations|joinFaction|workForFaction|getFactionRep|" +
"donateToFaction|" + "donateToFaction|getCrimeStats|" +
"createProgram|commitCrime|getCrimeChance|getOwnedAugmentations|" + "createProgram|commitCrime|getCrimeChance|getOwnedAugmentations|" +
"getOwnedSourceFiles|getAugmentationsFromFaction|" + "getOwnedSourceFiles|getAugmentationsFromFaction|" +
"getAugmentationPrereq|getAugmentationCost|purchaseAugmentation|" + "getAugmentationPrereq|getAugmentationCost|purchaseAugmentation|" +
@ -110,7 +110,7 @@ let NetscriptFunctions =
"getMemberNames|getGangInformation|getMemberInformation|canRecruitMember|" + "getMemberNames|getGangInformation|getMemberInformation|canRecruitMember|" +
"recruitMember|getTaskNames|setMemberTask|getEquipmentNames|" + "recruitMember|getTaskNames|setMemberTask|getEquipmentNames|" +
"getEquipmentCost|getEquipmentType|purchaseEquipment|ascendMember|" + "getEquipmentCost|getEquipmentType|purchaseEquipment|ascendMember|" +
"setTerritoryWarfare|" + "setTerritoryWarfare|getEquipmentStats|getTaskStats|" +
"getChanceToWinClash|getBonusTime|" + "getChanceToWinClash|getBonusTime|" +
// Bladeburner API // Bladeburner API

@ -74,7 +74,7 @@ export function processSingleServerGrowth(server: Server, numCycles: number, p:
//Apply serverGrowth for the calculated number of growth cycles //Apply serverGrowth for the calculated number of growth cycles
let serverGrowth = Math.pow(adjGrowthRate, numServerGrowthCyclesAdjusted * p.hacking_grow_mult); let serverGrowth = Math.pow(adjGrowthRate, numServerGrowthCyclesAdjusted * p.hacking_grow_mult);
if (serverGrowth < 1) { if (serverGrowth < 1) {
console.log("WARN: serverGrowth calculated to be less than 1"); console.warn("serverGrowth calculated to be less than 1");
serverGrowth = 1; serverGrowth = 1;
} }

@ -168,7 +168,7 @@ export function applySourceFile(srcFile: PlayerOwnedSourceFile) {
Player.work_money_mult *= inc; Player.work_money_mult *= inc;
break; break;
default: default:
console.log("ERROR: Invalid source file number: " + srcFile.n); console.error(`Invalid source file number: ${srcFile.n}`);
break; break;
} }

@ -43,7 +43,7 @@ export function buyStock(stock: Stock, shares: number, workerScript: WorkerScrip
if (shares <= 0) { return false; } if (shares <= 0) { return false; }
if (stock == null || isNaN(shares)) { if (stock == null || isNaN(shares)) {
if (tixApi) { if (tixApi) {
workerScript!.log(`ERROR: buyStock() failed due to invalid arguments`); workerScript!.log("buyStock", `Invalid arguments: stock='${stock}' shares='${shares}'`);
} else if (opts.suppressDialog !== true) { } else if (opts.suppressDialog !== true) {
dialogBoxCreate("Failed to buy stock. This may be a bug, contact developer"); dialogBoxCreate("Failed to buy stock. This may be a bug, contact developer");
} }
@ -56,7 +56,7 @@ export function buyStock(stock: Stock, shares: number, workerScript: WorkerScrip
if (totalPrice == null) { return false; } if (totalPrice == null) { return false; }
if (Player.money.lt(totalPrice)) { if (Player.money.lt(totalPrice)) {
if (tixApi) { if (tixApi) {
workerScript!.log(`ERROR: buyStock() failed because you do not have enough money to purchase this position. You need ${numeralWrapper.formatMoney(totalPrice)}`); workerScript!.log("buyStock", `You do not have enough money to purchase this position. You need ${numeralWrapper.formatMoney(totalPrice)}.`);
} else if (opts.suppressDialog !== true) { } else if (opts.suppressDialog !== true) {
dialogBoxCreate(`You do not have enough money to purchase this. You need ${numeralWrapper.formatMoney(totalPrice)}`); dialogBoxCreate(`You do not have enough money to purchase this. You need ${numeralWrapper.formatMoney(totalPrice)}`);
} }
@ -67,7 +67,7 @@ export function buyStock(stock: Stock, shares: number, workerScript: WorkerScrip
// Would this purchase exceed the maximum number of shares? // Would this purchase exceed the maximum number of shares?
if (shares + stock.playerShares + stock.playerShortShares > stock.maxShares) { if (shares + stock.playerShares + stock.playerShortShares > stock.maxShares) {
if (tixApi) { if (tixApi) {
workerScript!.log(`ERROR: buyStock() failed because purchasing this many shares would exceed ${stock.symbol}'s maximum number of shares`); workerScript!.log("buyStock", `Purchasing '${shares + stock.playerShares + stock.playerShortShares}' shares would exceed ${stock.symbol}'s maximum (${stock.maxShares}) number of shares`);
} else if (opts.suppressDialog !== true) { } else if (opts.suppressDialog !== true) {
dialogBoxCreate(`You cannot purchase this many shares. ${stock.symbol} has a maximum of ${numeralWrapper.formatBigNumber(stock.maxShares)} shares.`); dialogBoxCreate(`You cannot purchase this many shares. ${stock.symbol} has a maximum of ${numeralWrapper.formatBigNumber(stock.maxShares)} shares.`);
} }
@ -88,7 +88,7 @@ export function buyStock(stock: Stock, shares: number, workerScript: WorkerScrip
const resultTxt = `Bought ${numeralWrapper.format(shares, '0,0')} shares of ${stock.symbol} for ${numeralWrapper.formatMoney(totalPrice)}. ` + const resultTxt = `Bought ${numeralWrapper.format(shares, '0,0')} shares of ${stock.symbol} for ${numeralWrapper.formatMoney(totalPrice)}. ` +
`Paid ${numeralWrapper.formatMoney(CONSTANTS.StockMarketCommission)} in commission fees.` `Paid ${numeralWrapper.formatMoney(CONSTANTS.StockMarketCommission)} in commission fees.`
if (tixApi) { if (tixApi) {
if (workerScript!.shouldLog("buyStock")) { workerScript!.log(resultTxt); } workerScript!.log("buyStock", resultTxt)
} else if (opts.suppressDialog !== true) { } else if (opts.suppressDialog !== true) {
dialogBoxCreate(resultTxt); dialogBoxCreate(resultTxt);
} }
@ -110,7 +110,7 @@ export function sellStock(stock: Stock, shares: number, workerScript: WorkerScri
// Sanitize/Validate arguments // Sanitize/Validate arguments
if (stock == null || shares < 0 || isNaN(shares)) { if (stock == null || shares < 0 || isNaN(shares)) {
if (tixApi) { if (tixApi) {
workerScript!.log(`ERROR: sellStock() failed due to invalid arguments`); workerScript!.log("sellStock", `Invalid arguments: stock='${stock}' shares='${shares}'`);
} else if (opts.suppressDialog !== true) { } else if (opts.suppressDialog !== true) {
dialogBoxCreate("Failed to sell stock. This is probably due to an invalid quantity. Otherwise, this may be a bug, contact developer"); dialogBoxCreate("Failed to sell stock. This is probably due to an invalid quantity. Otherwise, this may be a bug, contact developer");
} }
@ -146,7 +146,7 @@ export function sellStock(stock: Stock, shares: number, workerScript: WorkerScri
const resultTxt = `Sold ${numeralWrapper.format(shares, '0,0')} shares of ${stock.symbol}. ` + const resultTxt = `Sold ${numeralWrapper.format(shares, '0,0')} shares of ${stock.symbol}. ` +
`After commissions, you gained a total of ${numeralWrapper.formatMoney(gains)}.`; `After commissions, you gained a total of ${numeralWrapper.formatMoney(gains)}.`;
if (tixApi) { if (tixApi) {
if (workerScript!.shouldLog("sellStock")) { workerScript!.log(resultTxt); } workerScript!.log("sellStock", resultTxt)
} else if (opts.suppressDialog !== true) { } else if (opts.suppressDialog !== true) {
dialogBoxCreate(resultTxt); dialogBoxCreate(resultTxt);
} }
@ -170,7 +170,7 @@ export function shortStock(stock: Stock, shares: number, workerScript: WorkerScr
if (shares <= 0) { return false; } if (shares <= 0) { return false; }
if (stock == null || isNaN(shares)) { if (stock == null || isNaN(shares)) {
if (tixApi) { if (tixApi) {
workerScript!.log("ERROR: shortStock() failed because of invalid arguments."); workerScript!.log("shortStock", `Invalid arguments: stock='${stock}' shares='${shares}'`);
} else if (opts.suppressDialog !== true) { } else if (opts.suppressDialog !== true) {
dialogBoxCreate("Failed to initiate a short position in a stock. This is probably " + dialogBoxCreate("Failed to initiate a short position in a stock. This is probably " +
"due to an invalid quantity. Otherwise, this may be a bug, so contact developer"); "due to an invalid quantity. Otherwise, this may be a bug, so contact developer");
@ -183,7 +183,7 @@ export function shortStock(stock: Stock, shares: number, workerScript: WorkerScr
if (totalPrice == null) { return false; } if (totalPrice == null) { return false; }
if (Player.money.lt(totalPrice)) { if (Player.money.lt(totalPrice)) {
if (tixApi) { if (tixApi) {
workerScript!.log("ERROR: shortStock() failed because you do not have enough " + workerScript!.log("shortStock", "You do not have enough " +
"money to purchase this short position. You need " + "money to purchase this short position. You need " +
numeralWrapper.formatMoney(totalPrice)); numeralWrapper.formatMoney(totalPrice));
} else if (opts.suppressDialog !== true) { } else if (opts.suppressDialog !== true) {
@ -197,7 +197,7 @@ export function shortStock(stock: Stock, shares: number, workerScript: WorkerScr
// Would this purchase exceed the maximum number of shares? // Would this purchase exceed the maximum number of shares?
if (shares + stock.playerShares + stock.playerShortShares > stock.maxShares) { if (shares + stock.playerShares + stock.playerShortShares > stock.maxShares) {
if (tixApi) { if (tixApi) {
workerScript!.log(`ERROR: shortStock() failed because purchasing this many short shares would exceed ${stock.symbol}'s maximum number of shares.`); workerScript!.log("shortStock", `This '${shares + stock.playerShares + stock.playerShortShares}' short shares would exceed ${stock.symbol}'s maximum (${stock.maxShares}) number of shares.`);
} else if (opts.suppressDialog !== true) { } else if (opts.suppressDialog !== true) {
dialogBoxCreate(`You cannot purchase this many shares. ${stock.symbol} has a maximum of ${stock.maxShares} shares.`); dialogBoxCreate(`You cannot purchase this many shares. ${stock.symbol} has a maximum of ${stock.maxShares} shares.`);
} }
@ -220,7 +220,7 @@ export function shortStock(stock: Stock, shares: number, workerScript: WorkerScr
`for ${numeralWrapper.formatMoney(totalPrice)}. Paid ${numeralWrapper.formatMoney(CONSTANTS.StockMarketCommission)} ` + `for ${numeralWrapper.formatMoney(totalPrice)}. Paid ${numeralWrapper.formatMoney(CONSTANTS.StockMarketCommission)} ` +
`in commission fees.`; `in commission fees.`;
if (tixApi) { if (tixApi) {
if (workerScript!.shouldLog("shortStock")) { workerScript!.log(resultTxt); } workerScript!.log("shortStock", resultTxt);
} else if (!opts.suppressDialog) { } else if (!opts.suppressDialog) {
dialogBoxCreate(resultTxt); dialogBoxCreate(resultTxt);
} }
@ -241,7 +241,7 @@ export function sellShort(stock: Stock, shares: number, workerScript: WorkerScri
if (stock == null || isNaN(shares) || shares < 0) { if (stock == null || isNaN(shares) || shares < 0) {
if (tixApi) { if (tixApi) {
workerScript!.log("ERROR: sellShort() failed because of invalid arguments."); workerScript!.log("sellShort", `Invalid arguments: stock='${stock}' shares='${shares}'`);
} else if (!opts.suppressDialog) { } else if (!opts.suppressDialog) {
dialogBoxCreate("Failed to sell a short position in a stock. This is probably " + dialogBoxCreate("Failed to sell a short position in a stock. This is probably " +
"due to an invalid quantity. Otherwise, this may be a bug, so contact developer"); "due to an invalid quantity. Otherwise, this may be a bug, so contact developer");
@ -257,7 +257,7 @@ export function sellShort(stock: Stock, shares: number, workerScript: WorkerScri
const totalGain = getSellTransactionGain(stock, shares, PositionTypes.Short); const totalGain = getSellTransactionGain(stock, shares, PositionTypes.Short);
if (totalGain == null || isNaN(totalGain) || origCost == null) { if (totalGain == null || isNaN(totalGain) || origCost == null) {
if (tixApi) { if (tixApi) {
workerScript!.log(`Failed to sell short position in a stock. This is probably either due to invalid arguments, or a bug`); workerScript!.log("sellShort", `Failed to sell short position in a stock. This is probably either due to invalid arguments, or a bug`);
} else if (!opts.suppressDialog) { } else if (!opts.suppressDialog) {
dialogBoxCreate(`Failed to sell short position in a stock. This is probably either due to invalid arguments, or a bug`); dialogBoxCreate(`Failed to sell short position in a stock. This is probably either due to invalid arguments, or a bug`);
} }
@ -286,7 +286,7 @@ export function sellShort(stock: Stock, shares: number, workerScript: WorkerScri
const resultTxt = `Sold your short position of ${numeralWrapper.format(shares, '0,0')} shares of ${stock.symbol}. ` + const resultTxt = `Sold your short position of ${numeralWrapper.format(shares, '0,0')} shares of ${stock.symbol}. ` +
`After commissions, you gained a total of ${numeralWrapper.formatMoney(totalGain)}`; `After commissions, you gained a total of ${numeralWrapper.formatMoney(totalGain)}`;
if (tixApi) { if (tixApi) {
if (workerScript!.shouldLog("sellShort")) { workerScript!.log(resultTxt); } workerScript!.log("sellShort", resultTxt);
} else if (!opts.suppressDialog) { } else if (!opts.suppressDialog) {
dialogBoxCreate(resultTxt); dialogBoxCreate(resultTxt);
} }

@ -38,7 +38,7 @@ export function placeOrder(stock: Stock, shares: number, price: number, type: Or
const tixApi = (workerScript instanceof WorkerScript); const tixApi = (workerScript instanceof WorkerScript);
if (!(stock instanceof Stock)) { if (!(stock instanceof Stock)) {
if (tixApi) { if (tixApi) {
workerScript!.log(`ERROR: Invalid stock passed to placeOrder() function`); workerScript!.log("placeOrder", `Invalid stock: '${stock}'`);
} else { } else {
dialogBoxCreate(`ERROR: Invalid stock passed to placeOrder() function`); dialogBoxCreate(`ERROR: Invalid stock passed to placeOrder() function`);
} }
@ -46,7 +46,7 @@ export function placeOrder(stock: Stock, shares: number, price: number, type: Or
} }
if (typeof shares !== "number" || typeof price !== "number") { if (typeof shares !== "number" || typeof price !== "number") {
if (tixApi) { if (tixApi) {
workerScript!.log("ERROR: Invalid numeric value provided for either 'shares' or 'price' argument"); workerScript!.log("placeOrder", `Invalid arguments: shares='${shares}' price='${price}'`);
} else { } else {
dialogBoxCreate("ERROR: Invalid numeric value provided for either 'shares' or 'price' argument"); dialogBoxCreate("ERROR: Invalid numeric value provided for either 'shares' or 'price' argument");
} }

@ -1766,7 +1766,6 @@ let Terminal = {
}`; }`;
} }
console.log('default code');
Engine.loadScriptEditorContent(filepath, code); Engine.loadScriptEditorContent(filepath, code);
} else { } else {
Engine.loadScriptEditorContent(filepath, script.code); Engine.loadScriptEditorContent(filepath, script.code);

@ -102,6 +102,7 @@ import { createElement } from "../utils/uiHelpers/createElement";
import { exceptionAlert } from "../utils/helpers/exceptionAlert"; import { exceptionAlert } from "../utils/helpers/exceptionAlert";
import { removeLoadingScreen } from "../utils/uiHelpers/removeLoadingScreen"; import { removeLoadingScreen } from "../utils/uiHelpers/removeLoadingScreen";
import { KEY } from "../utils/helpers/keyCodes"; import { KEY } from "../utils/helpers/keyCodes";
import "./Exploits/tampering";
import React from "react"; import React from "react";
import ReactDOM from "react-dom"; import ReactDOM from "react-dom";
@ -1079,7 +1080,6 @@ const Engine = {
// Process offline progress // Process offline progress
var offlineProductionFromScripts = loadAllRunningScripts(); // This also takes care of offline production for those scripts var offlineProductionFromScripts = loadAllRunningScripts(); // This also takes care of offline production for those scripts
if (Player.isWorking) { if (Player.isWorking) {
console.log("work() called in load() for " + numCyclesOffline * Engine._idleSpeed + " milliseconds");
if (Player.workType == CONSTANTS.WorkTypeFaction) { if (Player.workType == CONSTANTS.WorkTypeFaction) {
Player.workForFaction(numCyclesOffline); Player.workForFaction(numCyclesOffline);
} else if (Player.workType == CONSTANTS.WorkTypeCreateProgram) { } else if (Player.workType == CONSTANTS.WorkTypeCreateProgram) {
@ -1180,7 +1180,6 @@ const Engine = {
Engine.closeMainMenuHeader(visibleMenuTabs); Engine.closeMainMenuHeader(visibleMenuTabs);
} else { } else {
// No save found, start new game // No save found, start new game
console.log("Initializing new game");
initBitNodeMultipliers(Player); initBitNodeMultipliers(Player);
initSpecialServerIps(); initSpecialServerIps();
Engine.setDisplayElements(); // Sets variables for important DOM elements Engine.setDisplayElements(); // Sets variables for important DOM elements
@ -1525,7 +1524,6 @@ const Engine = {
// DEBUG Delete active Scripts on home // DEBUG Delete active Scripts on home
document.getElementById("debug-delete-scripts-link").addEventListener("click", function() { document.getElementById("debug-delete-scripts-link").addEventListener("click", function() {
console.log("Deleting running scripts on home computer");
Player.getHomeComputer().runningScripts = []; Player.getHomeComputer().runningScripts = [];
dialogBoxCreate("Forcefully deleted all running scripts on home computer. Please save and refresh page"); dialogBoxCreate("Forcefully deleted all running scripts on home computer. Please save and refresh page");
gameOptionsBoxClose(); gameOptionsBoxClose();

@ -406,7 +406,7 @@ if (htmlWebpackPlugin.options.googleAnalytics.trackingId) { %>
<div id="game-options-left-panel"> <div id="game-options-left-panel">
<!-- Netscript execution time --> <!-- Netscript execution time -->
<fieldset> <fieldset>
<label for="settingsNSExecTimeRangeVal" class="tooltip">Netscript exec time: <label for="settingsNSExecTimeRangeVal" class="tooltip">Netscript exec time:&nbsp;
<span class="tooltiptext"> <span class="tooltiptext">
The minimum number of milliseconds it takes to execute an operation in Netscript. 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. Setting this too low can result in poor performance if you have many scripts running.
@ -414,13 +414,13 @@ if (htmlWebpackPlugin.options.googleAnalytics.trackingId) { %>
</span> </span>
</label> </label>
<input type ="range" max="100" min="10" step="1" name="settingsNSExecTimeRangeVal" id="settingsNSExecTimeRangeVal" value="25" /> <input class="optionRange" type="range" max="100" min="10" step="1" name="settingsNSExecTimeRangeVal" id="settingsNSExecTimeRangeVal" value="25" />
<em id="settingsNSExecTimeRangeValLabel" style="font-style: normal;"></em> <em id="settingsNSExecTimeRangeValLabel" style="font-style: normal;"></em>
</fieldset> </fieldset>
<!-- Log capacity --> <!-- Log capacity -->
<fieldset> <fieldset>
<label for="settingsNSLogRangeVal" class="tooltip">Netscript log size: <label for="settingsNSLogRangeVal" class="tooltip">Netscript log size:&nbsp;&nbsp;
<span class="tooltiptext"> <span class="tooltiptext">
The maximum number of lines a script's logs can hold. Setting this too high The maximum number of lines a script's logs can hold. Setting this too high
can cause the game to use a lot of memory if you have many scripts running. can cause the game to use a lot of memory if you have many scripts running.
@ -428,13 +428,13 @@ if (htmlWebpackPlugin.options.googleAnalytics.trackingId) { %>
</span> </span>
</label> </label>
<input type="range" max="100" min="20" step="1" name="settingsNSLogRangeVal" id="settingsNSLogRangeVal" value="50" /> <input class="optionRange" type="range" max="100" min="20" step="1" name="settingsNSLogRangeVal" id="settingsNSLogRangeVal" value="50" />
<em id="settingsNSLogRangeValLabel" style="font-style: normal;"></em> <em id="settingsNSLogRangeValLabel" style="font-style: normal;"></em>
</fieldset> </fieldset>
<!-- Port capacity --> <!-- Port capacity -->
<fieldset> <fieldset>
<label for="settingsNSPortRangeVal" class="tooltip">Netscript port size: <label for="settingsNSPortRangeVal" class="tooltip">Netscript port size:&nbsp;
<span class="tooltiptext"> <span class="tooltiptext">
The maximum number of entries that can be written to a port using Netscript's The maximum number of entries that can be written to a port using Netscript's
write() function. Setting this too high can cause the game to use a lot of memory. write() function. Setting this too high can cause the game to use a lot of memory.
@ -442,19 +442,19 @@ if (htmlWebpackPlugin.options.googleAnalytics.trackingId) { %>
</span> </span>
</label> </label>
<input type="range" max="100" min="20" step="1" name="settingsNSPortRangeVal" id="settingsNSPortRangeVal" value="50" /> <input class="optionRange" type="range" max="100" min="20" step="1" name="settingsNSPortRangeVal" id="settingsNSPortRangeVal" value="50" />
<em id="settingsNSPortRangeValLabel" style="font-style: normal;"></em> <em id="settingsNSPortRangeValLabel" style="font-style: normal;"></em>
</fieldset> </fieldset>
<!-- Autosave Interval --> <!-- Autosave Interval -->
<fieldset> <fieldset>
<label for="settingsAutosaveIntervalVal" class="tooltip">Autosave Interval <label for="settingsAutosaveIntervalVal" class="tooltip">Autosave Interval:&nbsp;&nbsp;&nbsp;
<span class="tooltiptext"> <span class="tooltiptext">
The time (in seconds) between each autosave. Set to 0 to disable autosave. The time (in seconds) between each autosave. Set to 0 to disable autosave.
</span> </span>
</label> </label>
<input type="range" max="600" min="0" step="1" name="settingsAutosaveIntervalVal" id="settingsAutosaveIntervalVal" value="60" /> <input class="optionRange" type="range" max="600" min="0" step="1" name="settingsAutosaveIntervalVal" id="settingsAutosaveIntervalVal" value="60" />
<em id="settingsAutosaveIntervalValLabel" style="font-style: normal;"></em> <em id="settingsAutosaveIntervalValLabel" style="font-style: normal;"></em>
</fieldset> </fieldset>
@ -467,7 +467,7 @@ if (htmlWebpackPlugin.options.googleAnalytics.trackingId) { %>
and can be viewed with the 'cat' Terminal command. and can be viewed with the 'cat' Terminal command.
</span> </span>
</label> </label>
<input type="checkbox" name="settingsSuppressMessages" id="settingsSuppressMessages"> <input class="optionCheckbox" type="checkbox" name="settingsSuppressMessages" id="settingsSuppressMessages">
</fieldset> </fieldset>
<!-- Suppress faction invites --> <!-- Suppress faction invites -->
@ -478,7 +478,7 @@ if (htmlWebpackPlugin.options.googleAnalytics.trackingId) { %>
on the screen. Your outstanding faction invites can be viewed in the 'Factions' page. on the screen. Your outstanding faction invites can be viewed in the 'Factions' page.
</span> </span>
</label> </label>
<input type="checkbox" name="settingsSuppressFactionInvites" id="settingsSuppressFactionInvites"> <input class="optionCheckbox" type="checkbox" name="settingsSuppressFactionInvites" id="settingsSuppressFactionInvites">
</fieldset> </fieldset>
<!-- Suppress travel confirmation --> <!-- Suppress travel confirmation -->
@ -488,7 +488,7 @@ if (htmlWebpackPlugin.options.googleAnalytics.trackingId) { %>
If this is set, the confirmation message before traveling will not show up. You will automatically be deducted the travel cost as soon as you click. If this is set, the confirmation message before traveling will not show up. You will automatically be deducted the travel cost as soon as you click.
</span> </span>
</label> </label>
<input type="checkbox" name="settingsSuppressTravelConfirmation" id="settingsSuppressTravelConfirmation"> <input class="optionCheckbox" type="checkbox" name="settingsSuppressTravelConfirmation" id="settingsSuppressTravelConfirmation">
</fieldset> </fieldset>
@ -499,7 +499,7 @@ if (htmlWebpackPlugin.options.googleAnalytics.trackingId) { %>
If this is set, the confirmation message before buying augmentation will not show up. If this is set, the confirmation message before buying augmentation will not show up.
</span> </span>
</label> </label>
<input type="checkbox" name="settingsSuppressBuyAugmentationConfirmation" id="settingsSuppressBuyAugmentationConfirmation"> <input class="optionCheckbox" type="checkbox" name="settingsSuppressBuyAugmentationConfirmation" id="settingsSuppressBuyAugmentationConfirmation">
</fieldset> </fieldset>
<!-- Hospitalization Popup --> <!-- Hospitalization Popup -->
@ -509,7 +509,7 @@ if (htmlWebpackPlugin.options.googleAnalytics.trackingId) { %>
If this is set, a popup message will no longer be shown when you are hospitalized after taking too much damage. If this is set, a popup message will no longer be shown when you are hospitalized after taking too much damage.
</span> </span>
</label> </label>
<input type="checkbox" name="settingsSuppressHospitalizationPopup" id="settingsSuppressHospitalizationPopup"> <input class="optionCheckbox" type="checkbox" name="settingsSuppressHospitalizationPopup" id="settingsSuppressHospitalizationPopup">
</fieldset> </fieldset>
<!-- Disable Terminal and Navigation Shortcuts --> <!-- Disable Terminal and Navigation Shortcuts -->
@ -521,7 +521,7 @@ if (htmlWebpackPlugin.options.googleAnalytics.trackingId) { %>
and the "Save and Close (Ctrl + b)" hotkey in the Text Editor. and the "Save and Close (Ctrl + b)" hotkey in the Text Editor.
</span> </span>
</label> </label>
<input type="checkbox" name="settingsDisableHotkeys" id="settingsDisableHotkeys"> <input class="optionCheckbox" type="checkbox" name="settingsDisableHotkeys" id="settingsDisableHotkeys">
</fieldset> </fieldset>
<!-- Locale for displaying numbers --> <!-- Locale for displaying numbers -->

@ -36,7 +36,7 @@ export function ScriptProduction(props: IProps): React.ReactElement {
{numeralWrapper.formatMoney(props.p.scriptProdSinceLastAug)} {numeralWrapper.formatMoney(props.p.scriptProdSinceLastAug)}
</span> </span>
(<span className="money-gold"> &nbsp;(<span className="money-gold">
<span id="active-scripts-total-prod-aug-avg" className="money-gold"> <span id="active-scripts-total-prod-aug-avg" className="money-gold">
{numeralWrapper.formatMoney(prodRateSinceLastAug)} {numeralWrapper.formatMoney(prodRateSinceLastAug)}
</span> / sec </span> / sec

@ -11,7 +11,6 @@ import { SourceFileFlags } from "../SourceFile/SourceFileFlags";
import { getPurchaseServerLimit } from "../Server/ServerPurchases"; import { getPurchaseServerLimit } from "../Server/ServerPurchases";
import { MaxNumberHacknetServers } from "../Hacknet/HacknetServer"; import { MaxNumberHacknetServers } from "../Hacknet/HacknetServer";
export function CharacterInfo(p: IPlayer): React.ReactElement { export function CharacterInfo(p: IPlayer): React.ReactElement {
function LastEmployer(): React.ReactElement { function LastEmployer(): React.ReactElement {
if (p.companyName) { if (p.companyName) {
@ -225,7 +224,7 @@ export function CharacterInfo(p: IPlayer): React.ReactElement {
<b>Misc.</b><br /><br /> <b>Misc.</b><br /><br />
<span>Servers owned: {p.purchasedServers.length} / {getPurchaseServerLimit()}</span><br /> <span>Servers owned: {p.purchasedServers.length} / {getPurchaseServerLimit()}</span><br />
<span>Hacknet Nodes owned: {p.hacknetNodes.length} / {MaxNumberHacknetServers}</span><br /> <span>Hacknet Nodes owned: {p.hacknetNodes.length}</span><br />
<span>Augmentations installed: {p.augmentations.length}</span><br /> <span>Augmentations installed: {p.augmentations.length}</span><br />
<span>Time played since last Augmentation: {convertTimeMsToTimeElapsedString(p.playtimeSinceLastAug)}</span><br /> <span>Time played since last Augmentation: {convertTimeMsToTimeElapsedString(p.playtimeSinceLastAug)}</span><br />
<BitNodeTimeText /> <BitNodeTimeText />

@ -5,17 +5,25 @@ import {numeralWrapper} from "./numeralFormat";
function setSettingsLabels() { function setSettingsLabels() {
var nsExecTime = document.getElementById("settingsNSExecTimeRangeValLabel"); function setAutosaveLabel(elem) {
var nsLogLimit = document.getElementById("settingsNSLogRangeValLabel"); if(Settings.AutosaveInterval === 0) {
var nsPortLimit = document.getElementById("settingsNSPortRangeValLabel"); elem.innerHTML = `disabled`;
var suppressMsgs = document.getElementById("settingsSuppressMessages"); } else {
var suppressFactionInv = document.getElementById("settingsSuppressFactionInvites") elem.innerHTML = `every ${Settings.AutosaveInterval}s`;
var suppressTravelConfirmation = document.getElementById("settingsSuppressTravelConfirmation"); }
var suppressBuyAugmentationConfirmation = document.getElementById("settingsSuppressBuyAugmentationConfirmation"); }
var suppressHospitalizationPopup = document.getElementById("settingsSuppressHospitalizationPopup");
var autosaveInterval = document.getElementById("settingsAutosaveIntervalValLabel"); const nsExecTime = document.getElementById("settingsNSExecTimeRangeValLabel");
var disableHotkeys = document.getElementById("settingsDisableHotkeys"); const nsLogLimit = document.getElementById("settingsNSLogRangeValLabel");
var locale = document.getElementById("settingsLocale"); const nsPortLimit = document.getElementById("settingsNSPortRangeValLabel");
const suppressMsgs = document.getElementById("settingsSuppressMessages");
const suppressFactionInv = document.getElementById("settingsSuppressFactionInvites")
const suppressTravelConfirmation = document.getElementById("settingsSuppressTravelConfirmation");
const suppressBuyAugmentationConfirmation = document.getElementById("settingsSuppressBuyAugmentationConfirmation");
const suppressHospitalizationPopup = document.getElementById("settingsSuppressHospitalizationPopup");
const autosaveInterval = document.getElementById("settingsAutosaveIntervalValLabel");
const disableHotkeys = document.getElementById("settingsDisableHotkeys");
const locale = document.getElementById("settingsLocale");
//Initialize values on labels //Initialize values on labels
nsExecTime.innerHTML = Settings.CodeInstructionRunTime + "ms"; nsExecTime.innerHTML = Settings.CodeInstructionRunTime + "ms";
@ -26,16 +34,16 @@ function setSettingsLabels() {
suppressTravelConfirmation.checked = Settings.SuppressTravelConfirmation; suppressTravelConfirmation.checked = Settings.SuppressTravelConfirmation;
suppressBuyAugmentationConfirmation.checked = Settings.SuppressBuyAugmentationConfirmation; suppressBuyAugmentationConfirmation.checked = Settings.SuppressBuyAugmentationConfirmation;
suppressHospitalizationPopup.checked = Settings.SuppressHospitalizationPopup; suppressHospitalizationPopup.checked = Settings.SuppressHospitalizationPopup;
autosaveInterval.innerHTML = Settings.AutosaveInterval; setAutosaveLabel(autosaveInterval);
disableHotkeys.checked = Settings.DisableHotkeys; disableHotkeys.checked = Settings.DisableHotkeys;
locale.value = Settings.Locale; locale.value = Settings.Locale;
numeralWrapper.updateLocale(Settings.Locale); //Initialize locale numeralWrapper.updateLocale(Settings.Locale); //Initialize locale
//Set handlers for when input changes for sliders //Set handlers for when input changes for sliders
var nsExecTimeInput = document.getElementById("settingsNSExecTimeRangeVal"); const nsExecTimeInput = document.getElementById("settingsNSExecTimeRangeVal");
var nsLogRangeInput = document.getElementById("settingsNSLogRangeVal"); const nsLogRangeInput = document.getElementById("settingsNSLogRangeVal");
var nsPortRangeInput = document.getElementById("settingsNSPortRangeVal"); const nsPortRangeInput = document.getElementById("settingsNSPortRangeVal");
var nsAutosaveIntervalInput = document.getElementById("settingsAutosaveIntervalVal"); const nsAutosaveIntervalInput = document.getElementById("settingsAutosaveIntervalVal");
nsExecTimeInput.value = Settings.CodeInstructionRunTime; nsExecTimeInput.value = Settings.CodeInstructionRunTime;
nsLogRangeInput.value = Settings.MaxLogCapacity; nsLogRangeInput.value = Settings.MaxLogCapacity;
nsPortRangeInput.value = Settings.MaxPortCapacity; nsPortRangeInput.value = Settings.MaxPortCapacity;
@ -57,8 +65,8 @@ function setSettingsLabels() {
}; };
nsAutosaveIntervalInput.oninput = function() { nsAutosaveIntervalInput.oninput = function() {
autosaveInterval.innerHTML = this.value;
Settings.AutosaveInterval = Number(this.value); Settings.AutosaveInterval = Number(this.value);
setAutosaveLabel(autosaveInterval)
if (Number(this.value) === 0) { if (Number(this.value) === 0) {
Engine.Counters.autoSaveCounter = Infinity; Engine.Counters.autoSaveCounter = Infinity;
} else { } else {