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 {
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

29
dist/engineStyle.css vendored

@ -356,6 +356,35 @@ a:visited {
.smallfont {
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 */
/* Attributes */
/* 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
=========
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**
* Travel Agency now displays a world map
* Cities are now top view of metro station maps
**Netscript**
* 'softReset' is a new netscript function that performs a soft reset
regardless of if the player has bought augmentations or not.
* '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.
**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.**
* Fixed an issue where SF3 was listed as infinitly repeatable and SF12 as
having a limit of 3.
* 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)
:RAM cost: 4 GB
:param string type: Type of action. See :ref:`bladeburner_action_types`

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

@ -2,6 +2,7 @@ upgradeSkill() Netscript Function
=================================
.. js:function:: upgradeSkill(skillName)
:RAM cost: 4 GB
: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">
<!-- Netscript execution time -->
<fieldset>
<label for="settingsNSExecTimeRangeVal" class="tooltip">Netscript exec time:
<label for="settingsNSExecTimeRangeVal" class="tooltip">Netscript exec time:&nbsp;
<span class="tooltiptext">
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.
@ -401,13 +401,13 @@
</span>
</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>
</fieldset>
<!-- Log capacity -->
<fieldset>
<label for="settingsNSLogRangeVal" class="tooltip">Netscript log size:
<label for="settingsNSLogRangeVal" class="tooltip">Netscript log size:&nbsp;&nbsp;
<span class="tooltiptext">
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.
@ -415,13 +415,13 @@
</span>
</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>
</fieldset>
<!-- Port capacity -->
<fieldset>
<label for="settingsNSPortRangeVal" class="tooltip">Netscript port size:
<label for="settingsNSPortRangeVal" class="tooltip">Netscript port size:&nbsp;
<span class="tooltiptext">
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.
@ -429,19 +429,19 @@
</span>
</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>
</fieldset>
<!-- Autosave Interval -->
<fieldset>
<label for="settingsAutosaveIntervalVal" class="tooltip">Autosave Interval
<label for="settingsAutosaveIntervalVal" class="tooltip">Autosave Interval:&nbsp;&nbsp;&nbsp;
<span class="tooltiptext">
The time (in seconds) between each autosave. Set to 0 to disable autosave.
</span>
</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>
</fieldset>
@ -454,7 +454,7 @@
and can be viewed with the 'cat' Terminal command.
</span>
</label>
<input type="checkbox" name="settingsSuppressMessages" id="settingsSuppressMessages">
<input class="optionCheckbox" type="checkbox" name="settingsSuppressMessages" id="settingsSuppressMessages">
</fieldset>
<!-- Suppress faction invites -->
@ -465,7 +465,7 @@
on the screen. Your outstanding faction invites can be viewed in the 'Factions' page.
</span>
</label>
<input type="checkbox" name="settingsSuppressFactionInvites" id="settingsSuppressFactionInvites">
<input class="optionCheckbox" type="checkbox" name="settingsSuppressFactionInvites" id="settingsSuppressFactionInvites">
</fieldset>
<!-- 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.
</span>
</label>
<input type="checkbox" name="settingsSuppressTravelConfirmation" id="settingsSuppressTravelConfirmation">
<input class="optionCheckbox" type="checkbox" name="settingsSuppressTravelConfirmation" id="settingsSuppressTravelConfirmation">
</fieldset>
@ -486,7 +486,7 @@
If this is set, the confirmation message before buying augmentation will not show up.
</span>
</label>
<input type="checkbox" name="settingsSuppressBuyAugmentationConfirmation" id="settingsSuppressBuyAugmentationConfirmation">
<input class="optionCheckbox" type="checkbox" name="settingsSuppressBuyAugmentationConfirmation" id="settingsSuppressBuyAugmentationConfirmation">
</fieldset>
<!-- 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.
</span>
</label>
<input type="checkbox" name="settingsSuppressHospitalizationPopup" id="settingsSuppressHospitalizationPopup">
<input class="optionCheckbox" type="checkbox" name="settingsSuppressHospitalizationPopup" id="settingsSuppressHospitalizationPopup">
</fieldset>
<!-- Disable Terminal and Navigation Shortcuts -->
@ -508,7 +508,7 @@
and the "Save and Close (Ctrl + b)" hotkey in the Text Editor.
</span>
</label>
<input type="checkbox" name="settingsDisableHotkeys" id="settingsDisableHotkeys">
<input class="optionCheckbox" type="checkbox" name="settingsDisableHotkeys" id="settingsDisableHotkeys">
</fieldset>
<!-- Locale for displaying numbers -->

190
package-lock.json generated

@ -1,11 +1,11 @@
{
"name": "bitburner",
"version": "0.47.0",
"version": "0.47.3",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"version": "0.47.0",
"version": "0.47.3",
"hasInstallScript": true,
"license": "SEE LICENSE IN license.txt",
"dependencies": {
@ -67,7 +67,7 @@
"json5": "^1.0.1",
"less": "^3.9.0",
"less-loader": "^4.1.0",
"lodash": "^4.17.10",
"lodash": "^4.17.21",
"mini-css-extract-plugin": "^0.4.1",
"mkdirp": "^0.5.1",
"mocha": "^6.1.4",
@ -1225,6 +1225,11 @@
"integrity": "sha512-jp/uFnooOiO+L211eZOoSyzpOITMXx1rBITauYykG3BRYPu8h0UcxsPNB04RR5vo4Tyz3+ay17tR6JVf9qzYWg==",
"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": {
"version": "0.4.0",
"resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
@ -1501,6 +1506,12 @@
"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": {
"version": "3.2.0",
"resolved": "https://registry.npmjs.org/big.js/-/big.js-3.2.0.tgz",
@ -4379,6 +4390,12 @@
"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": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz",
@ -5607,6 +5624,12 @@
"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": {
"version": "4.2.3",
"resolved": "https://registry.npmjs.org/gonzales-pe/-/gonzales-pe-4.2.3.tgz",
@ -6040,6 +6063,12 @@
"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": {
"version": "3.9.2",
"resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-3.9.2.tgz",
@ -6402,6 +6431,12 @@
"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": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz",
@ -7652,9 +7687,10 @@
}
},
"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=="
"version": "4.17.21",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==",
"dev": true
},
"node_modules/lodash.camelcase": {
"version": "4.3.0",
@ -8982,6 +9018,12 @@
"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": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz",
@ -9507,12 +9549,6 @@
"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": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz",
@ -11029,6 +11065,12 @@
"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": {
"version": "6.0.23",
"resolved": "https://registry.npmjs.org/postcss/-/postcss-6.0.23.tgz",
@ -11283,6 +11325,12 @@
"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": {
"version": "6.0.23",
"resolved": "https://registry.npmjs.org/postcss/-/postcss-6.0.23.tgz",
@ -14079,6 +14127,12 @@
"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": {
"version": "6.0.23",
"resolved": "https://registry.npmjs.org/postcss/-/postcss-6.0.23.tgz",
@ -14335,6 +14389,12 @@
"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": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/map-obj/-/map-obj-2.0.0.tgz",
@ -14724,6 +14784,12 @@
"integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==",
"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": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/tapable/-/tapable-1.0.0.tgz",
@ -16144,6 +16210,12 @@
"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": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz",
@ -18457,6 +18529,13 @@
"integrity": "sha512-fNEiL2+AZt6AlAw/29Cr0UDe4sRAHCpEHh54WMz+Bb7QfNcFw4h3loofyJpLeQs4Yx7yuqu/2dLgM5hKOs6HlQ==",
"requires": {
"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": {
@ -18711,6 +18790,14 @@
"requires": {
"lodash": "4.17.10",
"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": {
@ -21164,6 +21251,12 @@
"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": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz",
@ -22223,6 +22316,12 @@
"once": "1.4.0",
"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",
"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=",
"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": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz",
@ -23908,9 +24019,10 @@
}
},
"lodash": {
"version": "4.17.10",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.10.tgz",
"integrity": "sha512-UejweD1pDoXu+AD825lWwp4ZGtSwgnpZxb3JDViD7StjQz+Nb/6l093lx4OQ0foGWNRoc19mWy7BzL+UAK2iVg=="
"version": "4.17.21",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==",
"dev": true
},
"lodash.camelcase": {
"version": "4.3.0",
@ -24999,6 +25111,12 @@
"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": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz",
@ -25416,12 +25534,6 @@
"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": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz",
@ -26731,6 +26843,12 @@
"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": {
"version": "6.0.23",
"resolved": "https://registry.npmjs.org/postcss/-/postcss-6.0.23.tgz",
@ -26942,6 +27060,12 @@
"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": {
"version": "6.0.23",
"resolved": "https://registry.npmjs.org/postcss/-/postcss-6.0.23.tgz",
@ -29479,6 +29603,12 @@
"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": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/map-obj/-/map-obj-2.0.0.tgz",
@ -29676,6 +29806,12 @@
"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": {
"version": "6.0.23",
"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",
"integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==",
"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"
}
},
"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": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz",

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

@ -2054,7 +2054,7 @@ function applyAugmentation(aug, reapply=false) {
}
}
function installAugmentations(cbScript=null) {
function installAugmentations() {
if (Player.queuedAugmentations.length == 0) {
dialogBoxCreate("You have not purchased any Augmentations to install!");
return false;
@ -2063,7 +2063,7 @@ function installAugmentations(cbScript=null) {
for (var i = 0; i < Player.queuedAugmentations.length; ++i) {
var aug = Augmentations[Player.queuedAugmentations[i].name];
if (aug == null) {
console.log("ERROR. Invalid augmentation");
console.error(`Invalid augmentation: ${Player.queuedAugmentations[i].name}`);
continue;
}
applyAugmentation(Player.queuedAugmentations[i]);
@ -2074,24 +2074,6 @@ function installAugmentations(cbScript=null) {
"to install the following Augmentations:<br>" + augmentationList +
"<br>You wake up in your home...you feel different...");
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) {

@ -10,6 +10,7 @@ import * as React from "react";
import { InstalledAugmentations } from "./InstalledAugmentations";
import { ListConfiguration } from "./ListConfiguration";
import { OwnedSourceFiles } from "./OwnedSourceFiles";
import { SourceFileMinus1 } from "./SourceFileMinus1";
import { Settings } from "../../Settings/Settings";
import { OwnedAugmentationsOrderSetting } from "../../Settings/SettingEnums";
@ -98,6 +99,7 @@ export class InstalledAugmentationsAndSourceFiles extends React.Component<IProps
sortInOrderFn={this.sortInOrder}
/>
<ul className="augmentations-list" ref={this.listRef}>
<SourceFileMinus1 />
<OwnedSourceFiles />
<InstalledAugmentations />
</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;
break;
default:
console.log("WARNING: Player.bitNodeN invalid");
console.warn("Player.bitNodeN invalid");
break;
}
}

@ -495,7 +495,7 @@ Action.prototype.getSuccessChance = function(inst, params={}) {
var key = "eff" + stat.charAt(0).toUpperCase() + stat.slice(1);
var effMultiplier = inst.skillMultipliers[key];
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;
}
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) {
if (this.action.type === ActionTypes["Idle"]) {return;}
if (this.actionTimeToComplete <= 0) {
console.log("action.type: " + this.action.type);
throw new Error("Invalid actionTimeToComplete value: " + this.actionTimeToComplete);
throw new Error(`Invalid actionTimeToComplete value: ${this.actionTimeToComplete}, type; ${this.action.type}`);
}
if (!(this.action instanceof ActionIdentifier)) {
throw new Error("Bladeburner.action is not an ActionIdentifier Object");
@ -1720,7 +1719,7 @@ Bladeburner.prototype.randomEvent = function() {
Bladeburner.prototype.triggerPotentialMigration = function(sourceCityName, 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 (Math.random() < chance) {this.triggerMigration(sourceCityName);}
@ -2310,7 +2309,7 @@ Bladeburner.prototype.createSkillsContent = function() {
// TODO in the future if items are ever implemented
break;
default:
console.log("Warning: Unrecognized SkillMult Key: " + multKeys[i]);
console.warn(`Unrecognized SkillMult Key: ${multKeys[i]}`);
break;
}
}
@ -3022,7 +3021,6 @@ Bladeburner.prototype.parseCommandArguments = function(command) {
++i;
}
if (start !== i) {args.push(command.substr(start, i-start));}
console.log("Bladeburner console command parsing returned: " + args);
return args;
}
@ -3286,7 +3284,7 @@ Bladeburner.prototype.executeSkillConsoleCommand = function(args) {
// TODO if items are ever implemented
break;
default:
console.log("Warning: Unrecognized SkillMult Key: " + multKeys[i]);
console.warn(`Unrecognized SkillMult Key: ${multKeys[i]}`);
break;
}
}
@ -3829,43 +3827,6 @@ Bladeburner.prototype.setTeamSizeNetscriptFn = function(type, name, size, worker
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) {
var bladeburnerFac = Factions["Bladeburners"];
if (bladeburnerFac.isMember) {

@ -6,7 +6,7 @@
import { IMap } from "./types";
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
* 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:
`
v0.48.0 - ASCII
v0.49.0 - 2021-03-11 Source-File -1
-------
ASCII
* Travel Agency now displays a world map
* Cities are now top view of metro station maps
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
* 'softReset' is a new netscript function that performs a soft reset
regardless of if the player has bought augmentations or not.
* 'getAugmentationStats' is a new netscript function that returns the stats of
an augmentation.
* getCharacterInformation now additionally returns exp
* pid resets back to 1 when installing or destroying a BitNode.
* 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.
* '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.
* Fixed an issue where SF3 was listed as infinitly repeatable and SF12 as
having a limit of 3.
* 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.
* Minor formatting under Hacking>Active Scripts
* option menu colors now match the rest of the game, kinda.
`
}

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

@ -153,7 +153,6 @@ export class Product {
const opsRatio = employeeProd[EmployeePositions.Operations] / employeeProd["total"];
const busRatio = employeeProd[EmployeePositions.Business] / employeeProd["total"];
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) +
(1.5 * opsRatio) + (busRatio);
var sciMult = 1 + (Math.pow(industry.sciResearch.qty, industry.sciFac) / 800);
@ -221,7 +220,7 @@ export class Product {
calculateRating(industry: IIndustry): void {
const weights: IProductRatingWeight = ProductRatingWeights[industry.type];
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;
}
this.rat = 0;

@ -110,7 +110,6 @@ export class CorporationEventHandler {
} else {
var totalAmount = money + (stockShares * stockPrice);
var repGain = totalAmount / BribeToRepRatio;
console.log("repGain: " + repGain);
repGainText.innerText = "You will gain " + numeralWrapper.format(repGain, "0,0") +
" reputation with " +
factionSelector.options[factionSelector.selectedIndex].value +
@ -1539,8 +1538,7 @@ export class CorporationEventHandler {
this.corp.numShares -= shares;
if (isNaN(this.corp.issuedShares)) {
console.log("ERROR: Corporation issuedShares is NaN: " + this.corp.issuedShares);
console.log("Converting to number now");
console.error(`Corporation issuedShares is NaN: ${this.corp.issuedShares}`);
var res = parseInt(this.corp.issuedShares);
if (isNaN(res)) {
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);
value = String(value);
if (setting == null || value == null || FconfSettings[setting] == null) {
console.log("WARNING: Invalid .fconf setting: " + setting);
console.warn(`Invalid .fconf setting: ${setting}`);
return;
}
@ -184,7 +184,7 @@ function setTheme() {
FconfSettings.THEME_FONT_COLOR == null ||
FconfSettings.THEME_BACKGROUND_COLOR == null ||
FconfSettings.THEME_PROMPT_COLOR == null) {
console.log("ERROR: Cannot find Theme Settings");
console.error("Cannot find Theme Settings");
return;
}
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) {
this.storedTerritoryAndPowerCycles += numCycles;
if (this.storedTerritoryAndPowerCycles < CyclesPerTerritoryAndPowerUpdate) { return; }
this.storedTerritoryAndPowerCycles -= CyclesPerTerritoryAndPowerUpdate;
// Process power first
var gangName = this.facName;
const gangName = this.facName;
for (const name in AllGangs) {
if (AllGangs.hasOwnProperty(name)) {
if (name == gangName) {
@ -327,12 +333,14 @@ Gang.prototype.processTerritoryAndPowerGains = function(numCycles=1) {
const otherPwr = AllGangs[otherGang].power;
const thisChance = thisPwr / (thisPwr + otherPwr);
if (Math.random() < thisChance) {
if (AllGangs[otherGang].territory <= 0) {
return;
}
AllGangs[thisGang].territory += 0.0001;
AllGangs[otherGang].territory -= 0.0001;
const territoryGain = calculateTerritoryGain(thisGang, otherGang);
AllGangs[thisGang].territory += territoryGain;
AllGangs[otherGang].territory -= territoryGain;
if (thisGang === gangName) {
this.clash(true); // Player won
AllGangs[otherGang].power *= (1 / 1.01);
@ -345,8 +353,9 @@ Gang.prototype.processTerritoryAndPowerGains = function(numCycles=1) {
if (AllGangs[thisGang].territory <= 0) {
return;
}
AllGangs[thisGang].territory -= 0.0001;
AllGangs[otherGang].territory += 0.0001;
const territoryGain = calculateTerritoryGain(otherGang, thisGang);
AllGangs[thisGang].territory -= territoryGain;
AllGangs[otherGang].territory += territoryGain;
if (thisGang === gangName) {
this.clash(false); // Player lost
} 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
GangMember.prototype.getAscensionResults = function() {
/**
@ -814,13 +837,14 @@ GangMember.prototype.getAscensionResults = function() {
}
// Subtract 1 because we're only interested in the actual "bonus" part
const eff = this.getAscensionEfficiency();
return {
hack: (Math.max(0, hack - 1) * AscensionMultiplierRatio),
str: (Math.max(0, str - 1) * AscensionMultiplierRatio),
def: (Math.max(0, def - 1) * AscensionMultiplierRatio),
dex: (Math.max(0, dex - 1) * AscensionMultiplierRatio),
agi: (Math.max(0, agi - 1) * AscensionMultiplierRatio),
cha: (Math.max(0, cha - 1) * AscensionMultiplierRatio),
hack: (Math.max(0, hack - 1) * AscensionMultiplierRatio * eff.hack),
str: (Math.max(0, str - 1) * AscensionMultiplierRatio * eff.str),
def: (Math.max(0, def - 1) * AscensionMultiplierRatio * eff.def),
dex: (Math.max(0, dex - 1) * AscensionMultiplierRatio * eff.dex),
agi: (Math.max(0, agi - 1) * AscensionMultiplierRatio * eff.agi),
cha: (Math.max(0, cha - 1) * AscensionMultiplierRatio * eff.cha),
}
}
@ -912,7 +936,7 @@ GangMemberTask.fromJSON = function(value) {
Reviver.constructors.GangMemberTask = GangMemberTask;
const GangMemberTasks = {};
export const GangMemberTasks = {};
function addGangMemberTask(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;
// Initialize Gang Member Upgrades
const GangMemberUpgrades = {}
export const GangMemberUpgrades = {}
function addGangMemberUpgrade(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 mult = HacknetServerPurchaseMult;
if (numOwned > MaxNumberHacknetServers) { return Infinity; }
if (numOwned >= MaxNumberHacknetServers) { return Infinity; }
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
Engine.Counters.autoSaveCounter = Infinity;
console.log("Interactive Tutorial started");
ITutorial.currStep = 0;
ITutorial.isRunning = true;
@ -100,7 +99,7 @@ function iTutorialStart() {
}
function iTutorialEvaluateStep() {
if (!ITutorial.isRunning) {console.log("Interactive Tutorial not running"); return;}
if (!ITutorial.isRunning) {return;}
// Disable and clear main menu
var terminalMainMenu = clearEventListeners("terminal-menu-link");
@ -476,8 +475,6 @@ function iTutorialEnd() {
Engine.Counters.autoSaveCounter = Settings.AutosaveInterval * 5;
}
console.log("Ending interactive tutorial");
// Initialize references to main menu links
// We have to call initializeMainMenuLinks() again because the Interactive Tutorial
// re-creates Main menu links with clearEventListeners()

@ -165,7 +165,7 @@ Node.prototype.deselect = function(actionButtons) {
Node.prototype.untarget = function() {
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;
}
--this.targetedCount;
@ -214,7 +214,6 @@ function HackingMission(rep, fac) {
this.jsplumbinstance = null;
this.difficulty = rep / CONSTANTS.HackingMissionRepToDiffConversion + 1;
console.log("difficulty: " + this.difficulty);
this.reward = 250 + (rep / CONSTANTS.HackingMissionRepToRewardConversion);
}
@ -408,7 +407,7 @@ HackingMission.prototype.createPageDom = function() {
// Set Action Button event listeners
this.actionButtons[0].addEventListener("click", ()=>{
if (!(this.selectedNode.length > 0)) {
console.log("ERR: Pressing Action button without selected node");
console.error("Pressing Action button without selected node");
return;
}
if (this.selectedNode[0].type !== NodeTypes.Core) {return;}
@ -421,7 +420,7 @@ HackingMission.prototype.createPageDom = function() {
this.actionButtons[1].addEventListener("click", ()=>{
if (!(this.selectedNode.length > 0)) {
console.log("ERR: Pressing Action button without selected node");
console.error("Pressing Action button without selected node");
return;
}
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", ()=>{
if (!(this.selectedNode.length > 0)) {
console.log("ERR: Pressing Action button without selected node");
console.error("Pressing Action button without selected node");
return;
}
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", ()=>{
if (!(this.selectedNode.length > 0)) {
console.log("ERR: Pressing Action button without selected node");
console.error("Pressing Action button without selected node");
return;
}
this.setActionButtonsActive(this.selectedNode[0].type);
@ -461,7 +460,7 @@ HackingMission.prototype.createPageDom = function() {
this.actionButtons[4].addEventListener("click", ()=>{
if (!(this.selectedNode.length > 0)) {
console.log("ERR: Pressing Action button without selected node");
console.error("Pressing Action button without selected node");
return;
}
var nodeType = this.selectedNode[0].type;
@ -475,7 +474,7 @@ HackingMission.prototype.createPageDom = function() {
this.actionButtons[5].addEventListener("click", ()=>{
if (!(this.selectedNode.length > 0)) {
console.log("ERR: Pressing Action button without selected node");
console.error("Pressing Action button without selected node");
return;
}
this.selectedNode.forEach(function(node){
@ -637,18 +636,16 @@ HackingMission.prototype.removeAvailablePosition = function(x, y) {
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) {
if (!(nodeObj instanceof Node)) {
console.log("WARNING: Non-Node object passed into setNodePOsition");
console.warn("Non-Node object passed into setNodePOsition");
return;
}
if (isNaN(x) || isNaN(y)) {
console.log("ERR: Invalid values passed as x and y for setNodePosition");
console.log(x);
console.log(y);
console.error(`Invalid values (${x}, ${y}) passed as (x, y) for setNodePosition`);
return;
}
nodeObj.pos = [x, y];
@ -725,7 +722,6 @@ HackingMission.prototype.createMap = function() {
// Configure all Player CPUS
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);
}
}
@ -793,7 +789,7 @@ HackingMission.prototype.createNodeDomElement = function(nodeObj) {
HackingMission.prototype.updateNodeDomElement = function(nodeObj) {
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;
}
@ -853,12 +849,12 @@ HackingMission.prototype.getNodeFromElement = function(el) {
id = id.replace("hacking-mission-node-", "");
var res = id.split('-');
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;
}
var x = res[0], y = res[1];
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 this.map[x][y];
@ -866,7 +862,7 @@ HackingMission.prototype.getNodeFromElement = function(el) {
function selectNode(hackMissionInst, 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;}
clearAllSelectedNodes(hackMissionInst);
@ -876,7 +872,7 @@ function selectNode(hackMissionInst, el) {
function multiselectNode(hackMissionInst, 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;}
clearAllSelectedNodes(hackMissionInst);
@ -912,7 +908,7 @@ function clearAllSelectedNodes(hackMissionInst) {
*/
HackingMission.prototype.configurePlayerNodeElement = function(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
var self = this;
@ -1239,7 +1235,7 @@ HackingMission.prototype.processNode = function(nodeObj, numCycles=1) {
calcStats = true;
break;
default:
console.log("ERR: Invalid Node Action: " + nodeObj.action);
console.error(`Invalid Node Action: ${nodeObj.action}`);
break;
}
@ -1452,7 +1448,7 @@ HackingMission.prototype.enemyAISelectAction = function(nodeObj) {
targetNode = this.getNodeFromElement(nodeObj.conn.targetId);
}
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) {
@ -1529,9 +1525,6 @@ HackingMission.prototype.finishMission = function(win) {
if (win) {
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;
dialogBoxCreate("Mission won! You earned " +
formatNumber(gain, 3) + " reputation with " + this.faction.name);

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

@ -188,7 +188,17 @@ export class WorkerScript {
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);
}
}

@ -12,15 +12,4 @@ function unknownBladeburnerExceptionMessage(functionName, 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};

@ -2,6 +2,7 @@ import { setTimeoutRef } from "./utils/SetTimeoutRef";
import { isValidIPAddress } from "../utils/helpers/isValidIPAddress";
import { isString } from "../utils/helpers/isString";
import { AllServers } from "./Server/AllServers";
export function netscriptDelay(time, workerScript) {
return new Promise(function(resolve, reject) {
@ -19,7 +20,12 @@ export function makeRuntimeRejectMsg(workerScript, msg, exp=null) {
var num = getErrorLineNumber(exp, workerScript);
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) {
@ -57,8 +63,5 @@ export function isScriptErrorMessage(msg) {
return false;
}
var ip = splitMsg[1];
if (!isValidIPAddress(ip)) {
return false;
}
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;
}
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 { Script } from "./Script/Script";
import { ScriptUrl } from "./Script/ScriptUrl";
// Makes a blob that contains the code of a given script.
export function makeScriptBlob(code) {
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
// 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
// by placing it inside an eval call.
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.dependencies = urls.map(u => u.filename);
script.dependencies = urls;
}
loadedModule = await script.module;
@ -68,7 +60,7 @@ export async function executeJSScript(scripts = [], workerScript) {
function shouldCompile(script, scripts) {
if (script.module === "") return true;
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
// compilation errors.

@ -501,7 +501,7 @@ export function createAndAddWorkerScript(runningScriptObj, server) {
if (!w.running) { return; }
killWorkerScript(s);
w.log("Script finished running");
w.log("", "Script finished running");
}).catch(function(w) {
if (w instanceof Error) {
dialogBoxCreate("Script runtime unknown error. This is a bug please contact game developer");
@ -509,22 +509,27 @@ export function createAndAddWorkerScript(runningScriptObj, server) {
return;
} else if (w instanceof WorkerScript) {
if (isScriptErrorMessage(w.errorMessage)) {
var errorTextArray = w.errorMessage.split("|");
const errorTextArray = w.errorMessage.split("|");
if (errorTextArray.length != 4) {
console.error("ERROR: Something wrong with Error text in evaluator...");
console.error("Error text: " + errorText);
return;
}
var serverIp = errorTextArray[1];
var scriptName = errorTextArray[2];
var errorMsg = errorTextArray[3];
const serverIp = errorTextArray[1];
const scriptName = errorTextArray[2];
const errorMsg = errorTextArray[3];
dialogBoxCreate("Script runtime error: <br>Server Ip: " + serverIp +
"<br>Script name: " + scriptName +
"<br>Args:" + arrayToString(w.args) + "<br>" + errorMsg);
w.log("Script crashed with runtime error");
let msg = `RUNTIME ERROR<br>${scriptName}@${serverIp}<br>`
if (w.args.length > 0) {
msg += `Args: ${arrayToString(w.args)}<br>`
}
msg += "<br>";
msg += errorMsg;
dialogBoxCreate(msg);
w.log("", "Script crashed with runtime error");
} else {
w.log("Script killed");
w.log("", "Script killed");
return; // Already killed, so stop here
}
w.running = false;
@ -594,14 +599,14 @@ export function loadAllRunningScripts() {
/**
* 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
if (!(workerScript instanceof WorkerScript)) {
return 0;
}
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`);
return 0;
}
@ -609,14 +614,14 @@ export function runScriptFromScript(server, scriptname, args, workerScript, thre
// Check if the script is already running
let runningScriptObj = server.getRunningScript(scriptname, args);
if (runningScriptObj != null) {
workerScript.log(`${scriptname} is already running on ${server.hostname}`);
workerScript.log(caller, `'${scriptname}' is already running on '${server.hostname}'`);
return 0;
}
// 'null/undefined' arguments are not allowed
for (let i = 0; i < args.length; ++i) {
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;
}
}
@ -633,16 +638,14 @@ export function runScriptFromScript(server, scriptname, args, workerScript, thre
const ramAvailable = server.maxRam - server.ramUsed;
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;
} 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;
} else {
// Able to run script
if (workerScript.disableLogs.ALL == null && workerScript.disableLogs.exec == null && workerScript.disableLogs.run == null && workerScript.disableLogs.spawn == null) {
workerScript.log(`Running script: ${scriptname} on ${server.hostname} with ${threads} threads and args: ${arrayToString(args)}.`);
}
workerScript.log(caller, `'${scriptname}' on '${server.hostname}' with ${threads} threads and args: ${arrayToString(args)}.`);
let runningScriptObj = new RunningScript(script, args);
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;
}

@ -62,7 +62,7 @@ function Perk(name, reqRep, info) {
Perk.prototype.setCompany = function(companyName) {
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;
}
this.companyPerk = true;
@ -71,7 +71,7 @@ Perk.prototype.setCompany = function(companyName) {
Perk.prototype.setFaction = function(factionName) {
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;
}
this.factionPerk = true;
@ -145,7 +145,7 @@ applyPerk = function(perk) {
case PerkNames.InsiderKnowledgeFactionPerk:
break;
default:
console.log("WARNING: Unrecognized perk: " + perk.name);
console.warn(`Unrecognized perk: ${perk.name}`);
return;
}
}

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

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

@ -37,6 +37,7 @@ import { safetlyCreateUniqueServer } from "../../Server/ServerHelpers";
import { Settings } from "../../Settings/Settings";
import { SpecialServerIps, SpecialServerNames } from "../../Server/SpecialServerIps";
import { applySourceFile } from "../../SourceFile/applySourceFile";
import { applyExploit } from "../../Exploits/applyExploits";
import { SourceFiles } from "../../SourceFile/SourceFiles";
import { SourceFileFlags } from "../../SourceFile/SourceFileFlags";
import { influenceStockThroughCompanyWork } from "../../StockMarket/PlayerInfluencing";
@ -726,7 +727,7 @@ export function workPartTime(numCycles) {
var comp = Companies[this.companyName], companyRep = "0";
if (comp == null || !(comp instanceof Company)) {
console.log("ERROR: Could not find Company: " + this.companyName);
console.error(`Could not find Company: ${this.companyName}`);
} else {
companyRep = comp.playerReputation;
}
@ -1417,8 +1418,7 @@ export function finishCrime(cancelled) {
}
}
if(crime == null) {
console.log(this.crimeType);
dialogBoxCreate("ERR: Unrecognized crime type. This is probably a bug please contact the developer");
dialogBoxCreate(`ERR: Unrecognized crime type (${this.crimeType}). This is probably a bug please contact the developer`);
}
this.gainMoney(this.workMoneyGained);
this.recordMoneySource(this.workMoneyGained, "crime");
@ -1529,7 +1529,7 @@ export function singularityStopWork() {
res = this.finishCrime(true);
break;
default:
console.log("ERROR: Unrecognized work type");
console.error(`Unrecognized work type (${this.workType})`);
return "";
}
return res;
@ -1840,7 +1840,7 @@ export function reapplyAllAugmentations(resetMultipliers=true) {
const augName = this.augmentations[i].name;
var aug = Augmentations[augName];
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;
}
aug.owned = true;
@ -1862,11 +1862,12 @@ export function reapplyAllSourceFiles() {
var srcFileKey = "SourceFile" + this.sourceFiles[i].n;
var sourceFileObject = SourceFiles[srcFileKey];
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;
}
applySourceFile(this.sourceFiles[i]);
}
applyExploit();
}
/*************** Check for Faction Invitations *************/
@ -2003,7 +2004,7 @@ export function checkForFactionInvitations() {
var fulcrumsecrettechonologiesFac = Factions["Fulcrum Secret Technologies"];
var fulcrumSecretServer = AllServers[SpecialServerIps[SpecialServerNames.FulcrumSecretTechnologies]];
if (fulcrumSecretServer == null) {
console.log("ERROR: Could not find Fulcrum Secret Technologies Server");
console.error("Could not find Fulcrum Secret Technologies Server");
} else {
if (!fulcrumsecrettechonologiesFac.isBanned && !fulcrumsecrettechonologiesFac.isMember &&
!fulcrumsecrettechonologiesFac.alreadyInvited &&
@ -2018,7 +2019,7 @@ export function checkForFactionInvitations() {
var homeComp = this.getHomeComputer();
var bitrunnersServer = AllServers[SpecialServerIps[SpecialServerNames.BitRunnersServer]];
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 &&
!bitrunnersFac.alreadyInvited && this.hacking_skill >= 500 && homeComp.maxRam >= 128) {
invitedFactions.push(bitrunnersFac);
@ -2028,7 +2029,7 @@ export function checkForFactionInvitations() {
var theblackhandFac = Factions["The Black Hand"];
var blackhandServer = AllServers[SpecialServerIps[SpecialServerNames.TheBlackHandServer]];
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 &&
!theblackhandFac.alreadyInvited && this.hacking_skill >= 350 && homeComp.maxRam >= 64) {
invitedFactions.push(theblackhandFac);
@ -2038,7 +2039,7 @@ export function checkForFactionInvitations() {
var nitesecFac = Factions["NiteSec"];
var nitesecServer = AllServers[SpecialServerIps[SpecialServerNames.NiteSecServer]];
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 &&
!nitesecFac.alreadyInvited && this.hacking_skill >= 200 && homeComp.maxRam >= 32) {
invitedFactions.push(nitesecFac);
@ -2182,7 +2183,7 @@ export function checkForFactionInvitations() {
var cybersecFac = Factions["CyberSec"];
var cybersecServer = AllServers[SpecialServerIps[SpecialServerNames.CyberSecServer]];
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 &&
!cybersecFac.alreadyInvited && this.hacking_skill >= 50) {
invitedFactions.push(cybersecFac);
@ -2199,14 +2200,14 @@ export function setBitNodeNumber(n) {
export function queueAugmentation(name) {
for(const i in this.queuedAugmentations) {
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;
}
}
for(const i in this.augmentations) {
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;
}
}
@ -2299,3 +2300,9 @@ export function gotoLocation(to) {
export function canAccessResleeving() {
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 { PlayerObject } from "./PersonObjects/Player/PlayerObject";
import { sanitizeExploits } from "./Exploits/Exploit";
import { Reviver } from "../utils/JSONReviver";
@ -26,4 +27,6 @@ export function loadPlayer(saveString) {
ind.thisCycleExpenses = new Decimal(ind.thisCycleExpenses);
}
}
Player.exploits = sanitizeExploits(Player.exploits);
}

@ -96,7 +96,7 @@ function hackWorldDaemon(currentNodeNumber, flume=false) {
}).then(function() {
return loadBitVerse(currentNodeNumber, flume);
}).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 sourceFile = SourceFiles[sourceFileKey];
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;
}
@ -264,7 +264,7 @@ function loadBitVerse(destroyedBitNodeNum, flume=false) {
}).then(function() {
return Promise.resolve(true);
}).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
Player.bitNodeN = newBitNode;
console.log(`Entering Bit Node ${Player.bitNodeN}`);
// Reenable terminal
$("#hack-progress-bar").attr('id', "old-hack-progress-bar");

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

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

@ -5,6 +5,7 @@
* being evaluated. See RunningScript for that
*/
import { calculateRamUsage } from "./RamCalculations";
import { ScriptUrl } from "./ScriptUrl";
import { Page, routing } from "../ui/navigationTracking";
import { setTimeoutRef } from "../utils/SetTimeoutRef";
@ -29,6 +30,9 @@ export class Script {
// Filename for the script file
filename: string = "";
// url of the script if any, only for NS2.
url: string = "";
// The dynamic module generated for this script when it is run.
// This is only applicable for NetscriptJS
module: any = "";
@ -39,7 +43,7 @@ export class Script {
// 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
// has been updated since it was last run.
dependencies: string[] = [];
dependencies: ScriptUrl[] = [];
// Amount of RAM this Script requres to run
ramUsage: number = 0;

@ -167,7 +167,6 @@ export function getCurrentEditor() {
case EditorSetting.CodeMirror:
return CodeMirrorEditor;
default:
console.log(`Invalid Editor Setting: ${Settings.Editor}`);
throw new Error(`Invalid Editor Setting: ${Settings.Editor}`);
return null;
}
@ -334,7 +333,6 @@ export function scriptCalculateOfflineProduction(runningScriptObj) {
var serv = AllServers[ip];
if (serv == null) {continue;}
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");
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");
@ -356,7 +354,6 @@ export function scriptCalculateOfflineProduction(runningScriptObj) {
totalOfflineProduction += production;
Player.gainMoney(production);
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);
serv.moneyAvailable -= production;
if (serv.moneyAvailable < 0) {serv.moneyAvailable = 0;}
@ -383,7 +380,6 @@ export function scriptCalculateOfflineProduction(runningScriptObj) {
var serv = AllServers[ip];
if (serv == null) {continue;}
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");
serv.fortify(CONSTANTS.ServerFortifyAmount * timesHacked);
}
@ -396,7 +392,6 @@ export function scriptCalculateOfflineProduction(runningScriptObj) {
var serv = AllServers[ip];
if (serv == null) {continue;}
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");
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,11 +87,11 @@ let NetscriptFunctions =
"getCompanyFavor|stopAction|getFactionFavor|" +
"getFavorToDonate|getFactionFavorGain|getCompanyFavorGain|" +
"checkFactionInvitations|joinFaction|workForFaction|getFactionRep|" +
"donateToFaction|" +
"donateToFaction|getCrimeStats|" +
"createProgram|commitCrime|getCrimeChance|getOwnedAugmentations|" +
"getOwnedSourceFiles|getAugmentationsFromFaction|" +
"getAugmentationPrereq|getAugmentationCost|purchaseAugmentation|" +
"softReset|installAugmentations|getAugmentationStats|" +
"softReset|installAugmentations|getAugmentationStats|" +
// TIX API
"getStockPrice|getStockPosition|getStockSymbols|getStockMaxShares|" +
@ -110,7 +110,7 @@ let NetscriptFunctions =
"getMemberNames|getGangInformation|getMemberInformation|canRecruitMember|" +
"recruitMember|getTaskNames|setMemberTask|getEquipmentNames|" +
"getEquipmentCost|getEquipmentType|purchaseEquipment|ascendMember|" +
"setTerritoryWarfare|" +
"setTerritoryWarfare|getEquipmentStats|getTaskStats|" +
"getChanceToWinClash|getBonusTime|" +
// Bladeburner API

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

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

@ -43,7 +43,7 @@ export function buyStock(stock: Stock, shares: number, workerScript: WorkerScrip
if (shares <= 0) { return false; }
if (stock == null || isNaN(shares)) {
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) {
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 (Player.money.lt(totalPrice)) {
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) {
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?
if (shares + stock.playerShares + stock.playerShortShares > stock.maxShares) {
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) {
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)}. ` +
`Paid ${numeralWrapper.formatMoney(CONSTANTS.StockMarketCommission)} in commission fees.`
if (tixApi) {
if (workerScript!.shouldLog("buyStock")) { workerScript!.log(resultTxt); }
workerScript!.log("buyStock", resultTxt)
} else if (opts.suppressDialog !== true) {
dialogBoxCreate(resultTxt);
}
@ -110,7 +110,7 @@ export function sellStock(stock: Stock, shares: number, workerScript: WorkerScri
// Sanitize/Validate arguments
if (stock == null || shares < 0 || isNaN(shares)) {
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) {
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}. ` +
`After commissions, you gained a total of ${numeralWrapper.formatMoney(gains)}.`;
if (tixApi) {
if (workerScript!.shouldLog("sellStock")) { workerScript!.log(resultTxt); }
workerScript!.log("sellStock", resultTxt)
} else if (opts.suppressDialog !== true) {
dialogBoxCreate(resultTxt);
}
@ -170,7 +170,7 @@ export function shortStock(stock: Stock, shares: number, workerScript: WorkerScr
if (shares <= 0) { return false; }
if (stock == null || isNaN(shares)) {
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) {
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");
@ -183,7 +183,7 @@ export function shortStock(stock: Stock, shares: number, workerScript: WorkerScr
if (totalPrice == null) { return false; }
if (Player.money.lt(totalPrice)) {
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 " +
numeralWrapper.formatMoney(totalPrice));
} 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?
if (shares + stock.playerShares + stock.playerShortShares > stock.maxShares) {
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) {
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)} ` +
`in commission fees.`;
if (tixApi) {
if (workerScript!.shouldLog("shortStock")) { workerScript!.log(resultTxt); }
workerScript!.log("shortStock", resultTxt);
} else if (!opts.suppressDialog) {
dialogBoxCreate(resultTxt);
}
@ -241,7 +241,7 @@ export function sellShort(stock: Stock, shares: number, workerScript: WorkerScri
if (stock == null || isNaN(shares) || shares < 0) {
if (tixApi) {
workerScript!.log("ERROR: sellShort() failed because of invalid arguments.");
workerScript!.log("sellShort", `Invalid arguments: stock='${stock}' shares='${shares}'`);
} else if (!opts.suppressDialog) {
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");
@ -257,7 +257,7 @@ export function sellShort(stock: Stock, shares: number, workerScript: WorkerScri
const totalGain = getSellTransactionGain(stock, shares, PositionTypes.Short);
if (totalGain == null || isNaN(totalGain) || origCost == null) {
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) {
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}. ` +
`After commissions, you gained a total of ${numeralWrapper.formatMoney(totalGain)}`;
if (tixApi) {
if (workerScript!.shouldLog("sellShort")) { workerScript!.log(resultTxt); }
workerScript!.log("sellShort", resultTxt);
} else if (!opts.suppressDialog) {
dialogBoxCreate(resultTxt);
}

@ -38,7 +38,7 @@ export function placeOrder(stock: Stock, shares: number, price: number, type: Or
const tixApi = (workerScript instanceof WorkerScript);
if (!(stock instanceof Stock)) {
if (tixApi) {
workerScript!.log(`ERROR: Invalid stock passed to placeOrder() function`);
workerScript!.log("placeOrder", `Invalid stock: '${stock}'`);
} else {
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 (tixApi) {
workerScript!.log("ERROR: Invalid numeric value provided for either 'shares' or 'price' argument");
workerScript!.log("placeOrder", `Invalid arguments: shares='${shares}' price='${price}'`);
} else {
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);
} else {
Engine.loadScriptEditorContent(filepath, script.code);

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

@ -406,7 +406,7 @@ if (htmlWebpackPlugin.options.googleAnalytics.trackingId) { %>
<div id="game-options-left-panel">
<!-- Netscript execution time -->
<fieldset>
<label for="settingsNSExecTimeRangeVal" class="tooltip">Netscript exec time:
<label for="settingsNSExecTimeRangeVal" class="tooltip">Netscript exec time:&nbsp;
<span class="tooltiptext">
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.
@ -414,13 +414,13 @@ if (htmlWebpackPlugin.options.googleAnalytics.trackingId) { %>
</span>
</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>
</fieldset>
<!-- Log capacity -->
<fieldset>
<label for="settingsNSLogRangeVal" class="tooltip">Netscript log size:
<label for="settingsNSLogRangeVal" class="tooltip">Netscript log size:&nbsp;&nbsp;
<span class="tooltiptext">
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.
@ -428,13 +428,13 @@ if (htmlWebpackPlugin.options.googleAnalytics.trackingId) { %>
</span>
</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>
</fieldset>
<!-- Port capacity -->
<fieldset>
<label for="settingsNSPortRangeVal" class="tooltip">Netscript port size:
<label for="settingsNSPortRangeVal" class="tooltip">Netscript port size:&nbsp;
<span class="tooltiptext">
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.
@ -442,19 +442,19 @@ if (htmlWebpackPlugin.options.googleAnalytics.trackingId) { %>
</span>
</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>
</fieldset>
<!-- Autosave Interval -->
<fieldset>
<label for="settingsAutosaveIntervalVal" class="tooltip">Autosave Interval
<label for="settingsAutosaveIntervalVal" class="tooltip">Autosave Interval:&nbsp;&nbsp;&nbsp;
<span class="tooltiptext">
The time (in seconds) between each autosave. Set to 0 to disable autosave.
</span>
</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>
</fieldset>
@ -467,7 +467,7 @@ if (htmlWebpackPlugin.options.googleAnalytics.trackingId) { %>
and can be viewed with the 'cat' Terminal command.
</span>
</label>
<input type="checkbox" name="settingsSuppressMessages" id="settingsSuppressMessages">
<input class="optionCheckbox" type="checkbox" name="settingsSuppressMessages" id="settingsSuppressMessages">
</fieldset>
<!-- 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.
</span>
</label>
<input type="checkbox" name="settingsSuppressFactionInvites" id="settingsSuppressFactionInvites">
<input class="optionCheckbox" type="checkbox" name="settingsSuppressFactionInvites" id="settingsSuppressFactionInvites">
</fieldset>
<!-- 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.
</span>
</label>
<input type="checkbox" name="settingsSuppressTravelConfirmation" id="settingsSuppressTravelConfirmation">
<input class="optionCheckbox" type="checkbox" name="settingsSuppressTravelConfirmation" id="settingsSuppressTravelConfirmation">
</fieldset>
@ -499,7 +499,7 @@ if (htmlWebpackPlugin.options.googleAnalytics.trackingId) { %>
If this is set, the confirmation message before buying augmentation will not show up.
</span>
</label>
<input type="checkbox" name="settingsSuppressBuyAugmentationConfirmation" id="settingsSuppressBuyAugmentationConfirmation">
<input class="optionCheckbox" type="checkbox" name="settingsSuppressBuyAugmentationConfirmation" id="settingsSuppressBuyAugmentationConfirmation">
</fieldset>
<!-- 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.
</span>
</label>
<input type="checkbox" name="settingsSuppressHospitalizationPopup" id="settingsSuppressHospitalizationPopup">
<input class="optionCheckbox" type="checkbox" name="settingsSuppressHospitalizationPopup" id="settingsSuppressHospitalizationPopup">
</fieldset>
<!-- 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.
</span>
</label>
<input type="checkbox" name="settingsDisableHotkeys" id="settingsDisableHotkeys">
<input class="optionCheckbox" type="checkbox" name="settingsDisableHotkeys" id="settingsDisableHotkeys">
</fieldset>
<!-- Locale for displaying numbers -->

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

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

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