Merge pull request #974 from danielyxie/dev

v0.59.10
This commit is contained in:
hydroflame 2021-05-31 17:35:35 -04:00 committed by GitHub
commit 531c0ce5c0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
53 changed files with 381 additions and 174 deletions

@ -27,5 +27,4 @@
button { button {
padding: 4px; padding: 4px;
} }
} }

@ -80,7 +80,7 @@
transform: rotate(-45deg); transform: rotate(-45deg);
} }
} }
input[type=checkbox] { input[type="checkbox"] {
margin: 3px; margin: 3px;
visibility: hidden; visibility: hidden;
&:checked + label:after { &:checked + label:after {

@ -11,7 +11,7 @@
} }
.casino-card .value { .casino-card .value {
font-size:15pt; font-size: 15pt;
font-family: sans-serif; font-family: sans-serif;
} }

@ -47,17 +47,16 @@
text-align: right; text-align: right;
} }
#character-hack-wrapper td,
#character-agi-wrapper td {
border-bottom: 1px #aaa solid;
padding-bottom: 10px;
}
#character-str-wrapper td, #character-str-wrapper td,
#character-cha-wrapper td { #character-cha-wrapper td {
padding-top: 10px; padding-top: 10px;
} }
.character-divider td {
border-top: 1px #aaa solid;
padding-top: 10px;
}
#character-hp-wrapper { color: $my-stat-hp-color; } #character-hp-wrapper { color: $my-stat-hp-color; }
.character-hp-cell { color: $my-stat-hp-color; } .character-hp-cell { color: $my-stat-hp-color; }
#character-money-wrapper { color: $my-stat-money-color; } #character-money-wrapper { color: $my-stat-money-color; }
@ -69,6 +68,8 @@
#character-int-wrapper { color: $my-stat-int-color; } #character-int-wrapper { color: $my-stat-int-color; }
.character-int-cell { color: $my-stat-int-color; } .character-int-cell { color: $my-stat-int-color; }
.character-combat-cell { color: $my-stat-physical; } .character-combat-cell { color: $my-stat-physical; }
#character-work-wrapper { color: $my-stat-hack-color; }
.character-work-cell { color: $my-stat-hack-color; }
.character-overview-btn { .character-overview-btn {
@include borderRadius(12px); @include borderRadius(12px);

@ -3,15 +3,11 @@
} }
.remove-exp-button { .remove-exp-button {
margin-left:0; margin-left: 0;
} }
.exp-input { .exp-input {
margin-right: 0; margin: 5px 0 5px 0;
margin-left:0;
margin-top: 5px;
margin-bottom: 5px;
padding: 2px 5px; padding: 2px 5px;
} }

1
css/grid.min.css vendored

@ -1,3 +1,4 @@
/* stylelint-disable */
/*! /*!
* Bootstrap Grid v4.1.2 (https://getbootstrap.com/) * Bootstrap Grid v4.1.2 (https://getbootstrap.com/)
* Copyright 2011-2018 The Bootstrap Authors * Copyright 2011-2018 The Bootstrap Authors

@ -17,7 +17,7 @@
} }
&.level-2 { &.level-2 {
color: #48d1cc; color: #48d1cc;
} }
&.level-3 { &.level-3 {

@ -234,9 +234,9 @@ a:visited {
#status-text-container { #status-text-container {
background-color: transparent; background-color: transparent;
position:absolute; position: absolute;
top:0; top: 0;
left:50%; left: 50%;
} }
#status-text { #status-text {
@ -371,14 +371,15 @@ a:visited {
.noscrollbar { .noscrollbar {
-ms-overflow-style: none; /* IE and Edge */ -ms-overflow-style: none; /* IE and Edge */
scrollbar-width: none; /* Firefox */ /* stylelint-disable-next-line property-no-unknown */
scrollbar-width: none; /* Firefox https://developer.mozilla.org/en-US/docs/Web/CSS/scrollbar-width */
} }
.noscrollbar::-webkit-scrollbar { .noscrollbar::-webkit-scrollbar {
display: none; display: none;
} }
input[type=checkbox] { input[type="checkbox"] {
filter: invert(1) sepia(1) hue-rotate(41deg) brightness(100%) saturate(10); filter: invert(1) sepia(1) hue-rotate(41deg) brightness(100%) saturate(10);
} }
@ -398,7 +399,6 @@ input[type=checkbox] {
margin: 3px; margin: 3px;
} }
.optionRange::-webkit-slider-thumb { .optionRange::-webkit-slider-thumb {
-webkit-appearance: none; -webkit-appearance: none;
appearance: none; appearance: none;

@ -16,7 +16,7 @@
text-align: center; text-align: center;
border: 2px solid #e8e8e3; border: 2px solid #e8e8e3;
border-radius: 2px; border-radius: 2px;
box-shadow: 1px 1px 1px rgba(0,0,0,0.5); box-shadow: 1px 1px 1px rgba(0, 0, 0, 0.5);
font-size: 12px; font-size: 12px;
} }

@ -26,7 +26,7 @@
margin: 10px; margin: 10px;
} }
#work-in-progress-cancel-button { .work-button {
@include borderRadius(12px); @include borderRadius(12px);
@include boxShadow(1px 1px 3px #000); @include boxShadow(1px 1px 3px #000);
@ -39,8 +39,8 @@
border: 3px solid #fff; border: 3px solid #fff;
} }
#work-in-progress-cancel-button:hover, .work-button:hover,
#work-in-progress-cancel-button:focus { .work-button:focus {
color: #fff; color: #fff;
text-decoration: none; text-decoration: none;
cursor: pointer; 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([842,0]),o()}({781:function(n,t,o){},783:function(n,t,o){},785:function(n,t,o){},787:function(n,t,o){},789:function(n,t,o){},791:function(n,t,o){},793:function(n,t,o){},795:function(n,t,o){},797:function(n,t,o){},799:function(n,t,o){},801:function(n,t,o){},803:function(n,t,o){},805:function(n,t,o){},807:function(n,t,o){},809:function(n,t,o){},811:function(n,t,o){},813:function(n,t,o){},815:function(n,t,o){},817:function(n,t,o){},819:function(n,t,o){},821:function(n,t,o){},823:function(n,t,o){},825:function(n,t,o){},827:function(n,t,o){},829:function(n,t,o){},831:function(n,t,o){},833:function(n,t,o){},835:function(n,t,o){},837:function(n,t,o){},839:function(n,t,o){},842:function(n,t,o){"use strict";o.r(t);o(841),o(839),o(837),o(835),o(833),o(831),o(829),o(827),o(825),o(823),o(821),o(819),o(817),o(815),o(813),o(811),o(809),o(807),o(805),o(803),o(801),o(799),o(797),o(795),o(793),o(791),o(789),o(787),o(785),o(783),o(781)}}); !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([845,0]),o()}({784:function(n,t,o){},786:function(n,t,o){},788:function(n,t,o){},790:function(n,t,o){},792:function(n,t,o){},794:function(n,t,o){},796:function(n,t,o){},798:function(n,t,o){},800:function(n,t,o){},802:function(n,t,o){},804:function(n,t,o){},806:function(n,t,o){},808:function(n,t,o){},810:function(n,t,o){},812:function(n,t,o){},814:function(n,t,o){},816:function(n,t,o){},818:function(n,t,o){},820:function(n,t,o){},822:function(n,t,o){},824:function(n,t,o){},826:function(n,t,o){},828:function(n,t,o){},830:function(n,t,o){},832:function(n,t,o){},834:function(n,t,o){},836:function(n,t,o){},838:function(n,t,o){},840:function(n,t,o){},842:function(n,t,o){},845:function(n,t,o){"use strict";o.r(t);o(844),o(842),o(840),o(838),o(836),o(834),o(832),o(830),o(828),o(826),o(824),o(822),o(820),o(818),o(816),o(814),o(812),o(810),o(808),o(806),o(804),o(802),o(800),o(798),o(796),o(794),o(792),o(790),o(788),o(786),o(784)}});
//# sourceMappingURL=engineStyle.bundle.js.map //# sourceMappingURL=engineStyle.bundle.js.map

36
dist/engineStyle.css vendored

@ -366,13 +366,14 @@ a:visited {
.noscrollbar { .noscrollbar {
-ms-overflow-style: none; -ms-overflow-style: none;
/* IE and Edge */ /* IE and Edge */
/* stylelint-disable-next-line property-no-unknown */
scrollbar-width: none; scrollbar-width: none;
/* Firefox */ } /* Firefox https://developer.mozilla.org/en-US/docs/Web/CSS/scrollbar-width */ }
.noscrollbar::-webkit-scrollbar { .noscrollbar::-webkit-scrollbar {
display: none; } display: none; }
input[type=checkbox] { input[type="checkbox"] {
filter: invert(1) sepia(1) hue-rotate(41deg) brightness(100%) saturate(10); } filter: invert(1) sepia(1) hue-rotate(41deg) brightness(100%) saturate(10); }
.optionCheckbox { .optionCheckbox {
@ -784,15 +785,14 @@ button {
.character-stat-cell { .character-stat-cell {
text-align: right; } text-align: right; }
#character-hack-wrapper td,
#character-agi-wrapper td {
border-bottom: 1px #aaa solid;
padding-bottom: 10px; }
#character-str-wrapper td, #character-str-wrapper td,
#character-cha-wrapper td { #character-cha-wrapper td {
padding-top: 10px; } padding-top: 10px; }
.character-divider td {
border-top: 1px #aaa solid;
padding-top: 10px; }
#character-hp-wrapper { #character-hp-wrapper {
color: #dd3434; } color: #dd3434; }
@ -826,6 +826,12 @@ button {
.character-combat-cell { .character-combat-cell {
color: #faffdf; } color: #faffdf; }
#character-work-wrapper {
color: #adff2f; }
.character-work-cell {
color: #adff2f; }
.character-overview-btn { .character-overview-btn {
-webkit-border-radius: 12px; -webkit-border-radius: 12px;
-moz-border-radius: 12px; -moz-border-radius: 12px;
@ -1521,7 +1527,7 @@ button {
width: 70%; width: 70%;
margin: 10px; } margin: 10px; }
#work-in-progress-cancel-button { .work-button {
-webkit-border-radius: 12px; -webkit-border-radius: 12px;
-moz-border-radius: 12px; -moz-border-radius: 12px;
border-radius: 12px; border-radius: 12px;
@ -1536,8 +1542,8 @@ button {
padding: 5px; padding: 5px;
border: 3px solid #fff; } border: 3px solid #fff; }
#work-in-progress-cancel-button:hover, .work-button:hover,
#work-in-progress-cancel-button:focus { .work-button:focus {
color: #fff; color: #fff;
text-decoration: none; text-decoration: none;
cursor: pointer; } cursor: pointer; }
@ -2317,10 +2323,10 @@ button {
border-right: none; border-right: none;
opacity: 0; opacity: 0;
transform: rotate(-45deg); } transform: rotate(-45deg); }
.bbcheckbox input[type=checkbox] { .bbcheckbox input[type="checkbox"] {
margin: 3px; margin: 3px;
visibility: hidden; } visibility: hidden; }
.bbcheckbox input[type=checkbox]:checked + label:after { .bbcheckbox input[type="checkbox"]:checked + label:after {
opacity: 1; } opacity: 1; }
/* Bladeburner Console */ /* Bladeburner Console */
@ -2508,6 +2514,7 @@ button {
.Treant > .unlocked:hover { .Treant > .unlocked:hover {
background-color: #666; } background-color: #666; }
/* stylelint-disable */
/*! /*!
* Bootstrap Grid v4.1.2 (https://getbootstrap.com/) * Bootstrap Grid v4.1.2 (https://getbootstrap.com/)
* Copyright 2011-2018 The Bootstrap Authors * Copyright 2011-2018 The Bootstrap Authors
@ -4986,10 +4993,7 @@ html {
margin-left: 0; } margin-left: 0; }
.exp-input { .exp-input {
margin-right: 0; margin: 5px 0 5px 0;
margin-left: 0;
margin-top: 5px;
margin-bottom: 5px;
padding: 2px 5px; } padding: 2px 5px; }
.text-center { .text-center {

70
dist/vendor.bundle.js vendored

File diff suppressed because one or more lines are too long

@ -50,7 +50,7 @@ Duplicate Sleeves. It is a numeral value between 1 and 100, and it affects how m
is earned when the sleeve is performing a task. is earned when the sleeve is performing a task.
Let N be the sleeve's synchronization. When the sleeve earns experience by performing Let N be the sleeve's synchronization. When the sleeve earns experience by performing
a task, both the sleeve and the player's original host consciousness of N% of the a task, both the sleeve and the player's original host consciousness gain N% of the
amount of experience normally earned by the task. All of the player's other sleeves amount of experience normally earned by the task. All of the player's other sleeves
earn ((N/100)^2 * 100)% of the experience. earn ((N/100)^2 * 100)% of the experience.

@ -124,6 +124,6 @@ Gain experience by:
* Committing certain crimes * Committing certain crimes
* Infiltration * Infiltration
* Working out at a gym * Studying at a university
* Working a relevant job at a company * Working a relevant job at a company
* Doing Field work for a Faction * Doing Field work for a Faction

@ -3,6 +3,49 @@
Changelog Changelog
========= =========
v0.51.10 - 2021-05-31 Focus Mark, Focus! (hydroflame)
-----------------------------------------------------
**Focus**
* You can now use the terminal and write scripts while working for factions
but you will gain reputation at a slower rate.
**SF -1**
* Added a new SF -1: Bypass
**Gang**
* "Vigilante justice"/"Ethical hacking" now reduces wanted level by a very
small percentage as well an absolute value.
**Netscript**
* 'tFormat' now has a second argument to display with millisecond precision.
* 'purchaseSleeveAug' can no longer purchase the same aug over and over for
the same sleeve.
* fix typo in logging for 'getServerSecurityLevel'
* Fixed some weird issue where very rarely you would get 0 exp from 'grow'
* 'getActionTime' now returns correct values for Diplomacy and Regeneration.
**Corporations**
* Fixed an exploit where you could get nearly infinite corporation funds by
entering negative numbers in textboxes.
* Fixed an exploit where shares could be sold again by clicking the
"sell share" button via scripts.
**Documentation**
* typo fix in purchaseTor
* typo fix in basicgameplay/stats
**Misc.**
* Very large number will no longer appear as "$NaNt"
* Hash capacity now displays in the "big number" format.
v0.51.9 - 2021-05-17 offline progress and exports! (hydroflame & community) v0.51.9 - 2021-05-17 offline progress and exports! (hydroflame & community)
--------------------------------------------------------------- ---------------------------------------------------------------

@ -1,15 +1,17 @@
tFormat() Netscript Function tFormat() Netscript Function
============================ ============================
.. js:function:: tFormat(milliseconds) .. js:function:: tFormat(milliseconds[, milliPrecision=false])
:RAM cost: 0 GB :RAM cost: 0 GB
:param number milliseconds: Amount of milliseconds to format. :param number milliseconds: Amount of milliseconds to format.
:param number milliPrecision: Display time with millisecond precision.
:returns: milliseconds in the "D M H S" format :returns: milliseconds in the "D M H S" format
Example: Example:
.. code-block:: javascript .. code-block:: javascript
tFormat(3000); // returns: "3 seconds" tFormat(3000); // returns: "3 seconds"
tFormat(10000000); // returns: "2 hours 46 minutes 40 seconds" tFormat(10000000); // returns: "2 hours 46 minutes 40 seconds"
tFormat(10000023, true); // returns: "2 hours 46 minutes 40.023 seconds"

@ -92,7 +92,7 @@ its type and name. The following are valid values when specifying the action's t
* blackop * blackop
* blackops * blackops
**General Actions (Training, Field Analysis, Recruitment)** **General Actions (Training, Field Analysis, etc)**
* general * general
* general action * general action
* gen * gen

@ -10,6 +10,6 @@ purchaseTor() Netscript Function
This function allows you to automatically purchase a TOR router. The cost for purchasing a TOR router using this This function allows you to automatically purchase a TOR router. The cost for purchasing a TOR router using this
function is the same as if you were to manually purchase one. function is the same as if you were to manually purchase one.
This function will return true if it successfully purchase a TOR router and false otherwise. This function will return true if it successfully purchased a TOR router and false otherwise.
:RAM cost: 2 GB :RAM cost: 2 GB

@ -352,7 +352,8 @@
<div id="work-in-progress-container" class="generic-fullscreen-container"> <div id="work-in-progress-container" class="generic-fullscreen-container">
<p id="work-in-progress-text"> </p> <p id="work-in-progress-text"> </p>
<button id="work-in-progress-cancel-button"> Cancel Work </button> <button id="work-in-progress-cancel-button" class="work-button"> Cancel Work </button>
<button id="work-in-progress-something-else-button" class="work-button"> Do something else simultaneously </button>
</div> </div>
<!-- Red Pill Container --> <!-- Red Pill Container -->

@ -10,8 +10,7 @@ import { PurchasedAugmentations } from "./PurchasedAugmentations";
import { Player } from "../../Player"; import { Player } from "../../Player";
import { StdButton } from "../../ui/React/StdButton"; import { StdButton } from "../../ui/React/StdButton";
import { LastExportBonus, canGetBonus } from "../../ExportBonus"; import { canGetBonus } from "../../ExportBonus";
import { convertTimeMsToTimeElapsedString } from "../../../utils/StringHelperFunctions";
type IProps = { type IProps = {
exportGameFn: () => void; exportGameFn: () => void;
@ -31,7 +30,7 @@ export class AugmentationsRoot extends React.Component<IProps, IState> {
this.export = this.export.bind(this); this.export = this.export.bind(this);
} }
export() { export(): void {
this.props.exportGameFn(); this.props.exportGameFn();
this.setState({ this.setState({
rerender: !this.state.rerender, rerender: !this.state.rerender,

@ -574,6 +574,10 @@ Bladeburner.prototype.getActionObject = function(actionId) {
return GeneralActions["Field Analysis"]; return GeneralActions["Field Analysis"];
case ActionTypes["Recruitment"]: case ActionTypes["Recruitment"]:
return GeneralActions["Recruitment"]; return GeneralActions["Recruitment"];
case ActionTypes["Diplomacy"]:
return GeneralActions["Diplomacy"];
case ActionTypes["Hyperbolic Regeneration Chamber"]:
return GeneralActions["Hyperbolic Regeneration Chamber"];
default: default:
return null; return null;
} }
@ -3037,6 +3041,9 @@ Bladeburner.prototype.getActionTimeNetscriptFn = function(type, name, workerScri
return 30; return 30;
case ActionTypes["Recruitment"]: case ActionTypes["Recruitment"]:
return this.getRecruitmentTime(); return this.getRecruitmentTime();
case ActionTypes["Diplomacy"]:
case ActionTypes["Hyperbolic Regeneration Chamber"]:
return 60;
default: default:
workerScript.log("bladeburner.getActionTime", errorLogText); workerScript.log("bladeburner.getActionTime", errorLogText);
return -1; return -1;

@ -164,10 +164,12 @@ export class Action implements IAction {
} }
// For actions that have teams. To be implemented by subtypes. // For actions that have teams. To be implemented by subtypes.
// eslint-disable-next-line @typescript-eslint/no-unused-vars
getTeamSuccessBonus(inst: IBladeburner): number { getTeamSuccessBonus(inst: IBladeburner): number {
return 1; return 1;
} }
// eslint-disable-next-line @typescript-eslint/no-unused-vars
getActionTypeSkillSuccessBonus(inst: IBladeburner): number { getActionTypeSkillSuccessBonus(inst: IBladeburner): number {
return 1; return 1;
} }

@ -12,10 +12,7 @@ import {
Generic_toJSON, Generic_toJSON,
Reviver, Reviver,
} from "../utils/JSONReviver"; } from "../utils/JSONReviver";
import { KEY } from "../utils/helpers/keyCodes";
import { createElement } from "../utils/uiHelpers/createElement";
import { createPopup, removePopup } from "./ui/React/createPopup"; import { createPopup, removePopup } from "./ui/React/createPopup";
import { removeElementById } from "../utils/uiHelpers/removeElementById";
import { CodingContractPopup } from "./ui/React/CodingContractPopup"; import { CodingContractPopup } from "./ui/React/CodingContractPopup";
@ -174,7 +171,7 @@ export class CodingContract {
*/ */
async prompt(): Promise<CodingContractResult> { async prompt(): Promise<CodingContractResult> {
const popupId = `coding-contract-prompt-popup-${this.fn}`; const popupId = `coding-contract-prompt-popup-${this.fn}`;
return new Promise<CodingContractResult>((resolve, reject) => { return new Promise<CodingContractResult>((resolve) => {
const popup = new CodingContractPopup({ const popup = new CodingContractPopup({
c: this, c: this,
popupId: popupId, popupId: popupId,

@ -6,7 +6,7 @@
import { IMap } from "./types"; import { IMap } from "./types";
export const CONSTANTS: IMap<any> = { export const CONSTANTS: IMap<any> = {
Version: "0.51.9", Version: "0.51.10",
/** Max level for any skill, assuming no multipliers. Determined by max numerical value in javascript for experience /** Max level for any skill, assuming no multipliers. Determined by max numerical value in javascript for experience
* and the skill level formula in Player.js. Note that all this means it that when experience hits MAX_INT, then * and the skill level formula in Player.js. Note that all this means it that when experience hits MAX_INT, then
@ -228,10 +228,40 @@ export const CONSTANTS: IMap<any> = {
LatestUpdate: LatestUpdate:
` `
v0.51.9 - 2021-05-17 offline progress and exports! v0.51.10 - 2021-05-31 Focus Mark, Focus! (hydroflame)
------- -------
Focus
* You can now use the terminal and write scripts while working for factions
but you will gain reputation at a slower rate.
SF -1 SF -1
* Added a new SF -1: Bypass * Added a new SF -1: Bypass
Gang
* "Vigilante justice"/"Ethical hacking" now reduces wanted level by a very
small percentage as well an absolute value.
Netscript
* 'tFormat' now has a second argument to display with millisecond precision.
* 'purchaseSleeveAug' can no longer purchase the same aug over and over for
the same sleeve.
* fix typo in logging for 'getServerSecurityLevel'
* Fixed some weird issue where very rarely you would get 0 exp from 'grow'
* 'getActionTime' now returns correct values for Diplomacy and Regeneration.
Corporations
* Fixed an exploit where you could get nearly infinite corporation funds by
entering negative numbers in textboxes.
* Fixed an exploit where shares could be sold again by clicking the
"sell share" button via scripts.
Documentation
* typo fix in purchaseTor
* typo fix in basicgameplay/stats
Misc.
* Very large number will no longer appear as "$NaNt"
* Hash capacity now displays in the "big number" format.
`, `,
} }

@ -63,9 +63,14 @@ export class CorporationEventHandler {
const txt = createElement("p", { const txt = createElement("p", {
innerText:"You can use Corporation funds or stock shares to bribe Faction Leaders in exchange for faction reputation", innerText:"You can use Corporation funds or stock shares to bribe Faction Leaders in exchange for faction reputation",
}); });
const factionSelector = createElement("select", { margin:"3px" }); const factionSelector = createElement("select", { class: "dropdown", margin:"3px" });
for (let i = 0; i < Player.factions.length; ++i) { for (let i = 0; i < Player.factions.length; ++i) {
const facName = Player.factions[i]; const facName = Player.factions[i];
const faction = Factions[facName];
const info = faction.getInfo();
if(!info.offersWork()) continue;
factionSelector.add(createElement("option", { factionSelector.add(createElement("option", {
text: facName, value: facName, text: facName, value: facName,
})); }));
@ -73,6 +78,7 @@ export class CorporationEventHandler {
var repGainText = createElement("p"); var repGainText = createElement("p");
var stockSharesInput; var stockSharesInput;
var moneyInput = createElement("input", { var moneyInput = createElement("input", {
class: "text-input",
type:"number", placeholder:"Corporation funds", margin:"5px", type:"number", placeholder:"Corporation funds", margin:"5px",
inputListener:()=>{ inputListener:()=>{
var money = moneyInput.value == null || moneyInput.value == "" ? 0 : parseFloat(moneyInput.value); var money = moneyInput.value == null || moneyInput.value == "" ? 0 : parseFloat(moneyInput.value);
@ -96,6 +102,7 @@ export class CorporationEventHandler {
}, },
}); });
stockSharesInput = createElement("input", { stockSharesInput = createElement("input", {
class: "text-input",
type:"number", placeholder:"Stock Shares", margin: "5px", type:"number", placeholder:"Stock Shares", margin: "5px",
inputListener:()=>{ inputListener:()=>{
var money = moneyInput.value == null || moneyInput.value == "" ? 0 : parseFloat(moneyInput.value); var money = moneyInput.value == null || moneyInput.value == "" ? 0 : parseFloat(moneyInput.value);
@ -595,7 +602,10 @@ export class CorporationEventHandler {
const txt = createElement("p", { const txt = createElement("p", {
innerHTML: popupText, innerHTML: popupText,
}); });
const designCity = createElement("select", { margin: "5px" }); const designCity = createElement("select", {
class: "dropdown",
margin: "5px",
});
for (const cityName in division.offices) { for (const cityName in division.offices) {
if (division.offices[cityName] instanceof OfficeSpace) { if (division.offices[cityName] instanceof OfficeSpace) {
designCity.add(createElement("option", { designCity.add(createElement("option", {
@ -613,17 +623,20 @@ export class CorporationEventHandler {
productNamePlaceholder = "Property Name"; productNamePlaceholder = "Property Name";
} }
var productNameInput = createElement("input", { var productNameInput = createElement("input", {
class: "text-input",
margin: "5px", margin: "5px",
placeholder: productNamePlaceholder, placeholder: productNamePlaceholder,
}); });
var lineBreak1 = createElement("br"); var lineBreak1 = createElement("br");
var designInvestInput = createElement("input", { var designInvestInput = createElement("input", {
class: "text-input",
margin: "5px", margin: "5px",
placeholder: "Design investment", placeholder: "Design investment",
type: "number", type: "number",
}); });
let confirmBtn; let confirmBtn;
var marketingInvestInput = createElement("input", { var marketingInvestInput = createElement("input", {
class: "text-input",
margin: "5px", margin: "5px",
placeholder: "Marketing investment", placeholder: "Marketing investment",
type: "number", type: "number",
@ -636,8 +649,8 @@ export class CorporationEventHandler {
class: "std-button", class: "std-button",
innerText: "Develop Product", innerText: "Develop Product",
clickListener: () => { clickListener: () => {
if (designInvestInput.value == null) { designInvestInput.value = 0; } if (designInvestInput.value == null || designInvestInput.value < 0) { designInvestInput.value = 0; }
if (marketingInvestInput.value == null) { marketingInvestInput.value = 0; } if (marketingInvestInput.value == null || marketingInvestInput.value < 0) { marketingInvestInput.value = 0; }
var designInvest = parseFloat(designInvestInput.value), var designInvest = parseFloat(designInvestInput.value),
marketingInvest = parseFloat(marketingInvestInput.value); marketingInvest = parseFloat(marketingInvestInput.value);
if (productNameInput.value == null || productNameInput.value === "") { if (productNameInput.value == null || productNameInput.value === "") {
@ -1501,6 +1514,7 @@ export class CorporationEventHandler {
}); });
const profitIndicator = createElement("p"); const profitIndicator = createElement("p");
const input = createElement("input", { const input = createElement("input", {
class: "text-input",
type:"number", placeholder:"Shares to sell", margin:"5px", type:"number", placeholder:"Shares to sell", margin:"5px",
inputListener: ()=> { inputListener: ()=> {
var numShares = Math.round(input.value); var numShares = Math.round(input.value);

@ -197,7 +197,10 @@ export class Overview extends BaseReactComponent {
const sellSharesBtn = this.createButton({ const sellSharesBtn = this.createButton({
class: sellSharesClass, class: sellSharesClass,
display: "inline-block", display: "inline-block",
onClick: sellSharesOnClick, onClick: function(event) {
if(!event.isTrusted) return;
sellSharesOnClick(event);
},
text: "Sell Shares", text: "Sell Shares",
tooltip: sellSharesTooltip, tooltip: sellSharesTooltip,
}); });

@ -548,6 +548,12 @@ class DevMenuComponent extends Component {
} }
} }
addTonsCorporationFunds() {
if(Player.corporation) {
Player.corporation.funds = Player.corporation.funds.plus(1e99);
}
}
addTonsCorporationCycles() { addTonsCorporationCycles() {
if (Player.corporation) { if (Player.corporation) {
Player.corporation.storedCycles = tonsP; Player.corporation.storedCycles = tonsP;
@ -1127,6 +1133,9 @@ class DevMenuComponent extends Component {
</div> </div>
<table> <table>
<tbody> <tbody>
<tr>
<td><button className="std-button" onClick={this.addTonsCorporationFunds}>Tons of funds</button></td>
</tr>
<tr> <tr>
<td><span className="text">Cycles:</span></td> <td><span className="text">Cycles:</span></td>
<td><button className="std-button" onClick={this.addTonsCorporationCycles}>Tons</button></td> <td><button className="std-button" onClick={this.addTonsCorporationCycles}>Tons</button></td>

@ -17,3 +17,7 @@ export function onExport(p: IPlayer): void {
} }
LastExportBonus = (new Date()).getTime(); LastExportBonus = (new Date()).getTime();
} }
export function setLastExportBonus(unixTime: number): void {
LastExportBonus = unixTime;
}

@ -18,6 +18,7 @@ import {
} from "../HacknetHelpers"; } from "../HacknetHelpers";
import { Player } from "../../Player"; import { Player } from "../../Player";
import { numeralWrapper } from "../../ui/numeralFormat";
import { Money } from "../../ui/React/Money"; import { Money } from "../../ui/React/Money";
import { Hashes } from "../../ui/React/Hashes"; import { Hashes } from "../../ui/React/Hashes";
@ -172,7 +173,7 @@ export class HacknetServer extends React.Component {
</div> </div>
<div className={"row"}> <div className={"row"}>
<p>Hash Capacity:</p> <p>Hash Capacity:</p>
<span className={"text"}>{node.hashCapacity}</span> <span className={"text"}>{Hashes(node.hashCapacity)}</span>
</div> </div>
<div className={"row"}> <div className={"row"}>
<p>Level:</p><span className={"text upgradable-info"}>{node.level}</span> <p>Level:</p><span className={"text upgradable-info"}>{node.level}</span>

@ -1,5 +1,4 @@
const sprintf = require("sprintf-js").sprintf; import { vsprintf, sprintf } from 'sprintf-js';
const vsprintf = require("sprintf-js").vsprintf;
import * as libarg from 'arg'; import * as libarg from 'arg';
import { getRamCost } from "./Netscript/RamCostGenerator"; import { getRamCost } from "./Netscript/RamCostGenerator";
@ -872,9 +871,6 @@ function NetscriptFunctions(workerScript) {
const moneyAfter = server.moneyAvailable; const moneyAfter = server.moneyAvailable;
workerScript.scriptRef.recordGrow(server.ip, threads); workerScript.scriptRef.recordGrow(server.ip, threads);
var expGain = calculateHackingExpGain(server, Player) * threads; var expGain = calculateHackingExpGain(server, Player) * threads;
if (growthPercentage == 1) {
expGain = 0;
}
const logGrowPercent = (moneyAfter/moneyBefore) - 1; const logGrowPercent = (moneyAfter/moneyBefore) - 1;
workerScript.log("grow", `Available money on '${server.hostname}' grown by ${numeralWrapper.formatPercentage(logGrowPercent, 6)}. Gained ${numeralWrapper.formatExp(expGain)} hacking exp (t=${numeralWrapper.formatThreads(threads)}).`); workerScript.log("grow", `Available money on '${server.hostname}' grown by ${numeralWrapper.formatPercentage(logGrowPercent, 6)}. Gained ${numeralWrapper.formatExp(expGain)} hacking exp (t=${numeralWrapper.formatThreads(threads)}).`);
workerScript.scriptRef.onlineExpGained += expGain; workerScript.scriptRef.onlineExpGained += expGain;
@ -1582,7 +1578,7 @@ function NetscriptFunctions(workerScript) {
workerScript.log("getServerMoneyAvailable", `returned player's money: ${numeralWrapper.formatMoney(Player.money.toNumber())}`); workerScript.log("getServerMoneyAvailable", `returned player's money: ${numeralWrapper.formatMoney(Player.money.toNumber())}`);
return Player.money.toNumber(); return Player.money.toNumber();
} }
workerScript.log("getServerMoneyAvailable", `returned ${numeralWrapper.formatMoney(server.moneyAvailable)} for '${server.hostname}`); workerScript.log("getServerMoneyAvailable", `returned ${numeralWrapper.formatMoney(server.moneyAvailable)} for '${server.hostname}'`);
return server.moneyAvailable; return server.moneyAvailable;
}, },
getServerSecurityLevel: function(ip) { getServerSecurityLevel: function(ip) {
@ -2487,8 +2483,8 @@ function NetscriptFunctions(workerScript) {
return numeralWrapper.format(parseFloat(n), format); return numeralWrapper.format(parseFloat(n), format);
}, },
tFormat: function(milliseconds) { tFormat: function(milliseconds, milliPrecision=false) {
return convertTimeMsToTimeElapsedString(milliseconds); return convertTimeMsToTimeElapsedString(milliseconds, milliPrecision);
}, },
getTimeSinceLastAug: function() { getTimeSinceLastAug: function() {
updateDynamicRam("getTimeSinceLastAug", getRamCost("getTimeSinceLastAug")); updateDynamicRam("getTimeSinceLastAug", getRamCost("getTimeSinceLastAug"));
@ -4397,7 +4393,7 @@ function NetscriptFunctions(workerScript) {
hacknetServers: { hacknetServers: {
hashGainRate: function(level, ramUsed, maxRam, cores, mult=1) { hashGainRate: function(level, ramUsed, maxRam, cores, mult=1) {
checkFormulasAccess("hacknetServers.hashGainRate", 9); checkFormulasAccess("hacknetServers.hashGainRate", 9);
return HScalculateHashGainRate(level, ramUsed, maxRam, cores, mult=1); return HScalculateHashGainRate(level, ramUsed, maxRam, cores, mult);
}, },
levelUpgradeCost: function(startingLevel, extraLevels=1, costMult=1) { levelUpgradeCost: function(startingLevel, extraLevels=1, costMult=1) {
checkFormulasAccess("hacknetServers.levelUpgradeCost", 9); checkFormulasAccess("hacknetServers.levelUpgradeCost", 9);

@ -34,7 +34,7 @@ import { roundToTwo } from "../utils/helpers/roundToTwo";
import { isString } from "../utils/StringHelperFunctions"; import { isString } from "../utils/StringHelperFunctions";
import { parse } from "acorn"; import { parse } from "acorn";
const walk = require("acorn-walk"); import { simple as walksimple } from "acorn-walk";
// Netscript Ports are instantiated here // Netscript Ports are instantiated here
export const NetscriptPorts = []; export const NetscriptPorts = [];
@ -304,7 +304,7 @@ function processNetscript1Imports(code, workerScript) {
let hasImports = false; let hasImports = false;
// Walk over the tree and process ImportDeclaration nodes // Walk over the tree and process ImportDeclaration nodes
walk.simple(ast, { walksimple(ast, {
ImportDeclaration: (node) => { ImportDeclaration: (node) => {
hasImports = true; hasImports = true;
let scriptName = node.source.value; let scriptName = node.source.value;
@ -322,7 +322,7 @@ function processNetscript1Imports(code, workerScript) {
let namespace = node.specifiers[0].local.name; let namespace = node.specifiers[0].local.name;
let fnNames = []; //Names only let fnNames = []; //Names only
let fnDeclarations = []; //FunctionDeclaration Node objects let fnDeclarations = []; //FunctionDeclaration Node objects
walk.simple(scriptAst, { walksimple(scriptAst, {
FunctionDeclaration: (node) => { FunctionDeclaration: (node) => {
fnNames.push(node.id.name); fnNames.push(node.id.name);
fnDeclarations.push(node); fnDeclarations.push(node);
@ -361,7 +361,7 @@ function processNetscript1Imports(code, workerScript) {
//Walk through script and get FunctionDeclaration code for all specified fns //Walk through script and get FunctionDeclaration code for all specified fns
let fnDeclarations = []; let fnDeclarations = [];
walk.simple(scriptAst, { walksimple(scriptAst, {
FunctionDeclaration: (node) => { FunctionDeclaration: (node) => {
if (fnsToImport.includes(node.id.name)) { if (fnsToImport.includes(node.id.name)) {
fnDeclarations.push(node); fnDeclarations.push(node);

@ -112,6 +112,7 @@ export function PlayerObject() {
//Flags/variables for working (Company, Faction, Creating Program, Taking Class) //Flags/variables for working (Company, Faction, Creating Program, Taking Class)
this.isWorking = false; this.isWorking = false;
this.focus = false;
this.workType = ""; this.workType = "";
this.currentWorkFactionName = ""; this.currentWorkFactionName = "";

@ -512,7 +512,10 @@ export function queryStatFromString(str) {
} }
/******* Working functions *******/ /******* Working functions *******/
export function resetWorkStatus() { export function resetWorkStatus(generalType, group, workType) {
if(generalType === this.workType && group === this.companyName) return;
if(generalType === this.workType && group === this.currentWorkFactionName && workType === this.factionWorkType) return;
if(this.isWorking) this.singularityStopWork();
this.workHackExpGainRate = 0; this.workHackExpGainRate = 0;
this.workStrExpGainRate = 0; this.workStrExpGainRate = 0;
this.workDefExpGainRate = 0; this.workDefExpGainRate = 0;
@ -544,12 +547,13 @@ export function resetWorkStatus() {
} }
export function processWorkEarnings(numCycles=1) { export function processWorkEarnings(numCycles=1) {
const hackExpGain = this.workHackExpGainRate * numCycles; const focusBonus = this.focus? 1 : 0.8;
const strExpGain = this.workStrExpGainRate * numCycles; const hackExpGain = focusBonus * this.workHackExpGainRate * numCycles;
const defExpGain = this.workDefExpGainRate * numCycles; const strExpGain = focusBonus * this.workStrExpGainRate * numCycles;
const dexExpGain = this.workDexExpGainRate * numCycles; const defExpGain = focusBonus * this.workDefExpGainRate * numCycles;
const agiExpGain = this.workAgiExpGainRate * numCycles; const dexExpGain = focusBonus * this.workDexExpGainRate * numCycles;
const chaExpGain = this.workChaExpGainRate * numCycles; const agiExpGain = focusBonus * this.workAgiExpGainRate * numCycles;
const chaExpGain = focusBonus * this.workChaExpGainRate * numCycles;
const moneyGain = (this.workMoneyGainRate - this.workMoneyLossRate) * numCycles; const moneyGain = (this.workMoneyGainRate - this.workMoneyLossRate) * numCycles;
this.gainHackingExp(hackExpGain); this.gainHackingExp(hackExpGain);
@ -570,15 +574,16 @@ export function processWorkEarnings(numCycles=1) {
this.workDexExpGained += dexExpGain; this.workDexExpGained += dexExpGain;
this.workAgiExpGained += agiExpGain; this.workAgiExpGained += agiExpGain;
this.workChaExpGained += chaExpGain; this.workChaExpGained += chaExpGain;
this.workRepGained += this.workRepGainRate * numCycles; this.workRepGained += focusBonus * this.workRepGainRate * numCycles;
this.workMoneyGained += this.workMoneyGainRate * numCycles; this.workMoneyGained += focusBonus * this.workMoneyGainRate * numCycles;
this.workMoneyGained -= this.workMoneyLossRate * numCycles; this.workMoneyGained -= focusBonus * this.workMoneyLossRate * numCycles;
} }
/* Working for Company */ /* Working for Company */
export function startWork(companyName) { export function startWork(companyName) {
this.resetWorkStatus(); this.resetWorkStatus(CONSTANTS.WorkTypeCompany, companyName);
this.isWorking = true; this.isWorking = true;
this.focus = true;
this.companyName = companyName; this.companyName = companyName;
this.workType = CONSTANTS.WorkTypeCompany; this.workType = CONSTANTS.WorkTypeCompany;
@ -601,6 +606,14 @@ export function startWork(companyName) {
return false; return false;
}); });
const focusButton = clearEventListeners("work-in-progress-something-else-button");
focusButton.style.visibility = "visible";
focusButton.innerHTML = "Do something else simultaneously";
focusButton.addEventListener("click", () => {
this.stopFocusing();
return false;
});
//Display Work In Progress Screen //Display Work In Progress Screen
Engine.loadWorkInProgressContent(); Engine.loadWorkInProgressContent();
} }
@ -722,8 +735,9 @@ export function finishWork(cancelled, sing=false) {
} }
export function startWorkPartTime(companyName) { export function startWorkPartTime(companyName) {
this.resetWorkStatus(); this.resetWorkStatus(CONSTANTS.WorkTypeCompanyPartTime, companyName);
this.isWorking = true; this.isWorking = true;
this.focus = true;
this.companyName = companyName; this.companyName = companyName;
this.workType = CONSTANTS.WorkTypeCompanyPartTime; this.workType = CONSTANTS.WorkTypeCompanyPartTime;
@ -834,6 +848,20 @@ export function finishWorkPartTime(sing=false) {
this.resetWorkStatus(); this.resetWorkStatus();
} }
export function startFocusing() {
const mainMenu = document.getElementById("mainmenu-container");
mainMenu.style.visibility = "hidden";
this.focus = true;
Engine.loadWorkInProgressContent();
}
export function stopFocusing() {
const mainMenu = document.getElementById("mainmenu-container");
mainMenu.style.visibility = "visible";
this.focus = false;
Engine.loadTerminalContent();
}
/* Working for Faction */ /* Working for Faction */
export function startFactionWork(faction) { export function startFactionWork(faction) {
//Update reputation gain rate to account for faction favor //Update reputation gain rate to account for faction favor
@ -843,24 +871,33 @@ export function startFactionWork(faction) {
this.workRepGainRate *= BitNodeMultipliers.FactionWorkRepGain; this.workRepGainRate *= BitNodeMultipliers.FactionWorkRepGain;
this.isWorking = true; this.isWorking = true;
this.focus = true;
this.workType = CONSTANTS.WorkTypeFaction; this.workType = CONSTANTS.WorkTypeFaction;
this.currentWorkFactionName = faction.name; this.currentWorkFactionName = faction.name;
this.timeNeededToCompleteWork = CONSTANTS.MillisecondsPer20Hours; this.timeNeededToCompleteWork = CONSTANTS.MillisecondsPer20Hours;
var cancelButton = clearEventListeners("work-in-progress-cancel-button"); const cancelButton = clearEventListeners("work-in-progress-cancel-button");
cancelButton.innerHTML = "Stop Faction Work"; cancelButton.innerHTML = "Stop Faction Work";
cancelButton.addEventListener("click", () => { cancelButton.addEventListener("click", () => {
this.finishFactionWork(true); this.finishFactionWork(true);
return false; return false;
}); });
const focusButton = clearEventListeners("work-in-progress-something-else-button");
focusButton.style.visibility = "visible";
focusButton.innerHTML = "Do something else simultaneously";
focusButton.addEventListener("click", () => {
this.stopFocusing();
return false;
});
//Display Work In Progress Screen //Display Work In Progress Screen
Engine.loadWorkInProgressContent(); Engine.loadWorkInProgressContent();
} }
export function startFactionHackWork(faction) { export function startFactionHackWork(faction) {
this.resetWorkStatus(); this.resetWorkStatus(CONSTANTS.WorkTypeFaction, faction.name, CONSTANTS.FactionWorkHacking);
this.workHackExpGainRate = .15 * this.hacking_exp_mult * BitNodeMultipliers.FactionWorkExpGain; this.workHackExpGainRate = .15 * this.hacking_exp_mult * BitNodeMultipliers.FactionWorkExpGain;
this.workRepGainRate = (this.hacking_skill + this.intelligence) / CONSTANTS.MaxSkillLevel * this.faction_rep_mult * this.getIntelligenceBonus(0.5); this.workRepGainRate = (this.hacking_skill + this.intelligence) / CONSTANTS.MaxSkillLevel * this.faction_rep_mult * this.getIntelligenceBonus(0.5);
@ -872,7 +909,7 @@ export function startFactionHackWork(faction) {
} }
export function startFactionFieldWork(faction) { export function startFactionFieldWork(faction) {
this.resetWorkStatus(); this.resetWorkStatus(CONSTANTS.WorkTypeFaction, faction.name, CONSTANTS.FactionWorkField);
this.workHackExpGainRate = .1 * this.hacking_exp_mult * BitNodeMultipliers.FactionWorkExpGain; this.workHackExpGainRate = .1 * this.hacking_exp_mult * BitNodeMultipliers.FactionWorkExpGain;
this.workStrExpGainRate = .1 * this.strength_exp_mult * BitNodeMultipliers.FactionWorkExpGain; this.workStrExpGainRate = .1 * this.strength_exp_mult * BitNodeMultipliers.FactionWorkExpGain;
@ -889,7 +926,7 @@ export function startFactionFieldWork(faction) {
} }
export function startFactionSecurityWork(faction) { export function startFactionSecurityWork(faction) {
this.resetWorkStatus(); this.resetWorkStatus(CONSTANTS.WorkTypeFaction, faction.name, CONSTANTS.FactionWorkSecurity);
this.workHackExpGainRate = 0.05 * this.hacking_exp_mult * BitNodeMultipliers.FactionWorkExpGain; this.workHackExpGainRate = 0.05 * this.hacking_exp_mult * BitNodeMultipliers.FactionWorkExpGain;
this.workStrExpGainRate = 0.15 * this.strength_exp_mult * BitNodeMultipliers.FactionWorkExpGain; this.workStrExpGainRate = 0.15 * this.strength_exp_mult * BitNodeMultipliers.FactionWorkExpGain;
@ -1157,6 +1194,7 @@ export function getWorkRepGain() {
export function startCreateProgramWork(programName, time, reqLevel) { export function startCreateProgramWork(programName, time, reqLevel) {
this.resetWorkStatus(); this.resetWorkStatus();
this.isWorking = true; this.isWorking = true;
this.focus = true;
this.workType = CONSTANTS.WorkTypeCreateProgram; this.workType = CONSTANTS.WorkTypeCreateProgram;
//Time needed to complete work affected by hacking skill (linearly based on //Time needed to complete work affected by hacking skill (linearly based on
@ -1189,6 +1227,9 @@ export function startCreateProgramWork(programName, time, reqLevel) {
return false; return false;
}); });
const focusButton = clearEventListeners("work-in-progress-something-else-button");
focusButton.style.visibility = "hidden";
//Display Work In Progress Screen //Display Work In Progress Screen
Engine.loadWorkInProgressContent(); Engine.loadWorkInProgressContent();
} }
@ -1247,6 +1288,7 @@ export function finishCreateProgramWork(cancelled) {
export function startClass(costMult, expMult, className) { export function startClass(costMult, expMult, className) {
this.resetWorkStatus(); this.resetWorkStatus();
this.isWorking = true; this.isWorking = true;
this.focus = true;
this.workType = CONSTANTS.WorkTypeStudyClass; this.workType = CONSTANTS.WorkTypeStudyClass;
this.className = className; this.className = className;
@ -1402,6 +1444,7 @@ export function startCrime(crimeType, hackExp, strExp, defExp, dexExp, agiExp, c
this.resetWorkStatus(); this.resetWorkStatus();
this.isWorking = true; this.isWorking = true;
this.focus = true;
this.workType = CONSTANTS.WorkTypeCrime; this.workType = CONSTANTS.WorkTypeCrime;
if (singParams && singParams.workerscript) { if (singParams && singParams.workerscript) {
@ -1420,13 +1463,16 @@ export function startCrime(crimeType, hackExp, strExp, defExp, dexExp, agiExp, c
this.timeNeededToCompleteWork = time; this.timeNeededToCompleteWork = time;
//Remove all old event listeners from Cancel button //Remove all old event listeners from Cancel button
var newCancelButton = clearEventListeners("work-in-progress-cancel-button") const newCancelButton = clearEventListeners("work-in-progress-cancel-button")
newCancelButton.innerHTML = "Cancel crime" newCancelButton.innerHTML = "Cancel crime"
newCancelButton.addEventListener("click", () => { newCancelButton.addEventListener("click", () => {
this.finishCrime(true); this.finishCrime(true);
return false; return false;
}); });
const focusButton = clearEventListeners("work-in-progress-something-else-button");
focusButton.style.visibility = "hidden";
//Display Work In Progress Screen //Display Work In Progress Screen
Engine.loadWorkInProgressContent(); Engine.loadWorkInProgressContent();
} }

@ -529,7 +529,7 @@ export class Sleeve extends Person {
case SleeveTaskType.Recovery: case SleeveTaskType.Recovery:
this.shock = Math.min(100, this.shock + (0.0002 * cyclesUsed)); this.shock = Math.min(100, this.shock + (0.0002 * cyclesUsed));
break; break;
case SleeveTaskType.Sync: case SleeveTaskType.Synchro:
this.sync = Math.min(100, this.sync + (p.getIntelligenceBonus(0.5) * 0.0002 * cyclesUsed)); this.sync = Math.min(100, this.sync + (p.getIntelligenceBonus(0.5) * 0.0002 * cyclesUsed));
break; break;
default: default:
@ -586,7 +586,7 @@ export class Sleeve extends Person {
this.resetTaskStatus(); this.resetTaskStatus();
} }
this.currentTask = SleeveTaskType.Sync; this.currentTask = SleeveTaskType.Synchro;
return true; return true;
} }
@ -666,6 +666,11 @@ export class Sleeve extends Person {
return false; return false;
} }
// Verify that this sleeve does not already have that augmentation.
if(this.augmentations.some(a => a.name === aug.name)) {
return false;
}
p.loseMoney(aug.startingCost); p.loseMoney(aug.startingCost);
this.installAugmentation(aug); this.installAugmentation(aug);
return true; return true;

@ -10,5 +10,5 @@ export enum SleeveTaskType {
Class, Class,
Gym, Gym,
Recovery, Recovery,
Sync, Synchro,
} }

@ -8,7 +8,6 @@ import { prestigeSourceFile } from "./Prestige";
import { PlayerOwnedSourceFile } from "./SourceFile/PlayerOwnedSourceFile"; import { PlayerOwnedSourceFile } from "./SourceFile/PlayerOwnedSourceFile";
import { SourceFileFlags } from "./SourceFile/SourceFileFlags"; import { SourceFileFlags } from "./SourceFile/SourceFileFlags";
import { SourceFiles } from "./SourceFile/SourceFiles"; import { SourceFiles } from "./SourceFile/SourceFiles";
import { Terminal } from "./Terminal";
import { setTimeoutRef } from "./utils/SetTimeoutRef"; import { setTimeoutRef } from "./utils/SetTimeoutRef";
import { dialogBoxCreate } from "../utils/DialogBox"; import { dialogBoxCreate } from "../utils/DialogBox";

@ -248,9 +248,9 @@ function loadGame(saveString) {
} }
if (saveObj.hasOwnProperty("LastExportBonus")) { if (saveObj.hasOwnProperty("LastExportBonus")) {
try { try {
ExportBonus.LastExportBonus = JSON.parse(saveObj.LastExportBonus); ExportBonus.setLastExportBonus(JSON.parse(saveObj.LastExportBonus));
} catch(err) { } catch(err) {
ExportBonus.LastExportBonus = (new Date()).getTime(); ExportBonus.setLastExportBonus((new Date()).getTime());
console.error("ERROR: Failed to parse .fconf Settings "+ err); console.error("ERROR: Failed to parse .fconf Settings "+ err);
} }
} }
@ -334,9 +334,9 @@ function loadImportedGame(saveObj, saveString) {
} }
if (saveObj.hasOwnProperty("LastExportBonus")) { if (saveObj.hasOwnProperty("LastExportBonus")) {
try { try {
ExportBonus.LastExportBonus = JSON.parse(saveObj.LastExportBonus); ExportBonus.setLastExportBonus(JSON.parse(saveObj.LastExportBonus));
} catch(err) { } catch(err) {
ExportBonus.LastExportBonus = (new Date()).getTime(); ExportBonus.setLastExportBonus((new Date()).getTime());
console.error("ERROR: Failed to parse .fconf Settings "+ err); console.error("ERROR: Failed to parse .fconf Settings "+ err);
} }
} }

@ -78,6 +78,7 @@ async function parseOnlyRamCalculate(otherScripts, code, workerScript) {
let code; let code;
if (nextModule.startsWith("https://") || nextModule.startsWith("http://")) { if (nextModule.startsWith("https://") || nextModule.startsWith("http://")) {
try { try {
// eslint-disable-next-line no-await-in-loop
const module = await eval('import(nextModule)'); const module = await eval('import(nextModule)');
code = ""; code = "";
for (const prop in module) { for (const prop in module) {

@ -1,20 +1,20 @@
import { ScriptEditor } from "./ScriptEditor"; import { ScriptEditor } from "./ScriptEditor";
const ace = require('brace'); import ace from 'brace';
require('brace/mode/javascript'); import 'brace/mode/javascript';
require('./AceNetscriptMode'); import './AceNetscriptMode';
require('brace/theme/chaos'); import 'brace/theme/chaos';
require('brace/theme/chrome'); import 'brace/theme/chrome';
require('brace/theme/monokai'); import 'brace/theme/monokai';
require('brace/theme/solarized_dark'); import 'brace/theme/solarized_dark';
require('brace/theme/solarized_light'); import 'brace/theme/solarized_light';
require('brace/theme/terminal'); import 'brace/theme/terminal';
require('brace/theme/twilight'); import 'brace/theme/twilight';
require('brace/theme/xcode'); import 'brace/theme/xcode';
require("brace/keybinding/vim"); import "brace/keybinding/vim";
require("brace/keybinding/emacs"); import "brace/keybinding/emacs";
require("brace/ext/language_tools"); import "brace/ext/language_tools";
import { NetscriptFunctions } from "../NetscriptFunctions"; import { NetscriptFunctions } from "../NetscriptFunctions";
import { Settings } from "../Settings/Settings"; import { Settings } from "../Settings/Settings";

@ -87,7 +87,7 @@ import 'codemirror/addon/lint/lint.css';
import 'codemirror/addon/search/match-highlighter.js'; import 'codemirror/addon/search/match-highlighter.js';
import 'codemirror/addon/selection/active-line.js'; import 'codemirror/addon/selection/active-line.js';
window.JSHINT = require('jshint').JSHINT; import { JSHINT } from 'jshint';
import './CodeMirrorNetscriptLint.js'; import './CodeMirrorNetscriptLint.js';
import { NetscriptFunctions } from "../NetscriptFunctions"; import { NetscriptFunctions } from "../NetscriptFunctions";
@ -100,6 +100,10 @@ import { createElement } from "../../utils/uiHelpers/createElement";
import { createOptionElement } from "../../utils/uiHelpers/createOptionElement"; import { createOptionElement } from "../../utils/uiHelpers/createOptionElement";
import { removeChildrenFromElement } from "../../utils/uiHelpers/removeChildrenFromElement"; import { removeChildrenFromElement } from "../../utils/uiHelpers/removeChildrenFromElement";
(function() {
window.JSHINT = JSHINT;
})();
// Max number of invisibles to be shown in a group if the "Show Invisibles" option // Max number of invisibles to be shown in a group if the "Show Invisibles" option
// is marked // is marked
const MaxInvisibles = 20; const MaxInvisibles = 20;

@ -1,7 +1,7 @@
import { CursorPositions } from './CursorPositions'; import { CursorPositions } from './CursorPositions';
// Base Script Editor class for the Ace/CodeMirror/etc. wrappers // Base Script Editor class for the Ace/CodeMirror/etc. wrappers
const beautify = require('js-beautify').js_beautify; import { js_beautify as beautify } from 'js-beautify';
export class ScriptEditor { export class ScriptEditor {
constructor() { constructor() {

@ -588,7 +588,6 @@ let Terminal = {
post(currServ.hostname + ": "); post(currServ.hostname + ": ");
const org = currServ.organizationName const org = currServ.organizationName
post("Organization name: " + (!isHacknet ? org : "Player")); post("Organization name: " + (!isHacknet ? org : "Player"));
const admin = currServ.hasAdminRights;
let hasAdminRights = !isHacknet && currServ.hasAdminRights || isHacknet; let hasAdminRights = !isHacknet && currServ.hasAdminRights || isHacknet;
post("Root Access: " + (hasAdminRights ? "YES" : "NO")); post("Root Access: " + (hasAdminRights ? "YES" : "NO"));
const hackingSkill = currServ.requiredHackingSkill const hackingSkill = currServ.requiredHackingSkill

@ -1097,6 +1097,7 @@ const Engine = {
// Process offline progress // Process offline progress
loadAllRunningScripts(); // This also takes care of offline production for those scripts loadAllRunningScripts(); // This also takes care of offline production for those scripts
if (Player.isWorking) { if (Player.isWorking) {
Player.focus = true;
if (Player.workType == CONSTANTS.WorkTypeFaction) { if (Player.workType == CONSTANTS.WorkTypeFaction) {
Player.workForFaction(numCyclesOffline); Player.workForFaction(numCyclesOffline);
} else if (Player.workType == CONSTANTS.WorkTypeCreateProgram) { } else if (Player.workType == CONSTANTS.WorkTypeCreateProgram) {
@ -1520,6 +1521,17 @@ const Engine = {
Player.finishWork(true); Player.finishWork(true);
} }
}); });
const focusButton = document.getElementById("work-in-progress-something-else-button");
focusButton.style.visibility = "hidden";
const focusable = [CONSTANTS.WorkTypeFaction, CONSTANTS.WorkTypeCompanyPartTime, CONSTANTS.WorkTypeCompany];
if(focusable.includes(Player.workType)) {
focusButton.style.visibility = "visible";
focusButton.addEventListener("click", function() {
Player.stopFocusing();
});
}
Engine.loadWorkInProgressContent(); Engine.loadWorkInProgressContent();
} }

@ -365,7 +365,8 @@ if (htmlWebpackPlugin.options.googleAnalytics.trackingId) { %>
<div id="work-in-progress-container" class="generic-fullscreen-container"> <div id="work-in-progress-container" class="generic-fullscreen-container">
<p id="work-in-progress-text"> </p> <p id="work-in-progress-text"> </p>
<button id="work-in-progress-cancel-button"> Cancel Work </button> <button id="work-in-progress-cancel-button" class="work-button"> Cancel Work </button>
<button id="work-in-progress-something-else-button" class="work-button"> Do something else simultaneously </button>
</div> </div>
<!-- Red Pill Container --> <!-- Red Pill Container -->

@ -3,6 +3,7 @@ import React from "react";
import { Player } from "../../Player"; import { Player } from "../../Player";
import { numeralWrapper } from "../../ui/numeralFormat"; import { numeralWrapper } from "../../ui/numeralFormat";
import { Reputation } from "./Reputation";
const Component = React.Component; const Component = React.Component;
@ -14,7 +15,25 @@ export class CharacterOverviewComponent extends Component {
</tr> </tr>
); );
/*const work = (
<div>
<p>Work progress:</p>
<p>+{Reputation(Player.workRepGained)} rep</p>
<button onClick={() => Player.startFocusing()} id="character-overview-options-button" className="character-overview-btn">Focus</button>
</div>
);*/
const work = (
<>
<tr className="character-divider"><td colSpan="2">Work progress:</td></tr>
<tr><td colSpan="2">+{Reputation(Player.workRepGained)} rep</td></tr>
<tr><td colSpan="2">
<button onClick={() => Player.startFocusing()} id="character-overview-options-button" className="character-overview-btn">Focus</button>
</td></tr>
</>
);
return ( return (
<>
<table> <table>
<tbody> <tbody>
<tr id="character-hp-wrapper"> <tr id="character-hp-wrapper">
@ -26,7 +45,7 @@ export class CharacterOverviewComponent extends Component {
<tr id="character-hack-wrapper"> <tr id="character-hack-wrapper">
<td className="character-hack-cell">Hack:&nbsp;</td><td id="character-hack-text" className="character-hack-cell character-stat-cell">{numeralWrapper.formatSkill(Player.hacking_skill)}</td> <td className="character-hack-cell">Hack:&nbsp;</td><td id="character-hack-text" className="character-hack-cell character-stat-cell">{numeralWrapper.formatSkill(Player.hacking_skill)}</td>
</tr> </tr>
<tr id="character-str-wrapper"> <tr id="character-str-wrapper" className="character-divider">
<td className="character-combat-cell">Str:&nbsp;</td><td id="character-str-text" className="character-combat-cell character-stat-cell">{numeralWrapper.formatSkill(Player.strength)}</td> <td className="character-combat-cell">Str:&nbsp;</td><td id="character-str-text" className="character-combat-cell character-stat-cell">{numeralWrapper.formatSkill(Player.strength)}</td>
</tr> </tr>
<tr id="character-def-wrapper"> <tr id="character-def-wrapper">
@ -38,15 +57,20 @@ export class CharacterOverviewComponent extends Component {
<tr id="character-agi-wrapper"> <tr id="character-agi-wrapper">
<td className="character-combat-cell">Agi:&nbsp;</td><td id="character-agi-text" className="character-combat-cell character-stat-cell">{numeralWrapper.formatSkill(Player.agility)}</td> <td className="character-combat-cell">Agi:&nbsp;</td><td id="character-agi-text" className="character-combat-cell character-stat-cell">{numeralWrapper.formatSkill(Player.agility)}</td>
</tr> </tr>
<tr id="character-cha-wrapper"> <tr id="character-cha-wrapper" className="character-divider">
<td className="character-cha-cell">Cha:&nbsp;</td><td id="character-cha-text" className="character-cha-cell character-stat-cell">{numeralWrapper.formatSkill(Player.charisma)}</td> <td className="character-cha-cell">Cha:&nbsp;</td><td id="character-cha-text" className="character-cha-cell character-stat-cell">{numeralWrapper.formatSkill(Player.charisma)}</td>
</tr> </tr>
{ {
Player.intelligence >= 1 && Player.intelligence >= 1 &&
intelligence intelligence
} }
{
(Player.isWorking && !Player.focus) &&
work
}
</tbody> </tbody>
</table> </table>
</>
) )
} }
} }

@ -24,16 +24,21 @@ export class CodingContractPopup extends React.Component<IProps, IState>{
this.onInputKeydown = this.onInputKeydown.bind(this); this.onInputKeydown = this.onInputKeydown.bind(this);
} }
setAnswer(event: any) { setAnswer(event: React.ChangeEvent<HTMLInputElement>): void {
this.setState({ answer: event.target.value }); this.setState({ answer: event.target.value });
} }
onInputKeydown(e:any){ onInputKeydown(event: React.KeyboardEvent<HTMLInputElement>): void {
if (e.keyCode === KEY.ENTER && e.target.value !== "") { // React just won't cooperate on this one.
e.preventDefault(); // "React.KeyboardEvent<HTMLInputElement>" seems like the right type but
// whatever ...
const value = (event.target as any).value;
if (event.keyCode === KEY.ENTER && value !== "") {
event.preventDefault();
this.props.onAttempt(this.state.answer); this.props.onAttempt(this.state.answer);
} else if (e.keyCode === KEY.ESC) { } else if (event.keyCode === KEY.ESC) {
e.preventDefault(); event.preventDefault();
this.props.onClose(); this.props.onClose();
} }
} }

@ -14,7 +14,7 @@ import { removeElement } from "../../../utils/uiHelpers/removeElement";
export interface IPopupButtonProps { export interface IPopupButtonProps {
class?: string; class?: string;
popup: HTMLElement | string; popup: HTMLElement | string;
style?: object; style?: any;
text: string; text: string;
onClose?: () => void; onClose?: () => void;
} }
@ -26,15 +26,15 @@ export class PopupButton extends React.Component<IPopupButtonProps, any> {
this.keyListener = this.keyListener.bind(this); this.keyListener = this.keyListener.bind(this);
} }
componentDidMount() { componentDidMount(): void {
document.addEventListener("keydown", this.keyListener); document.addEventListener("keydown", this.keyListener);
} }
componentWillUnmount() { componentWillUnmount(): void {
document.removeEventListener("keydown", this.keyListener); document.removeEventListener("keydown", this.keyListener);
} }
handleClick() { handleClick(): void {
if(this.props.onClose) if(this.props.onClose)
this.props.onClose(); this.props.onClose();
//We might be able to remove this? //We might be able to remove this?
@ -52,7 +52,7 @@ export class PopupButton extends React.Component<IPopupButtonProps, any> {
} }
} }
keyListener(e: KeyboardEvent) { keyListener(e: KeyboardEvent): void {
//This doesn't really make sense, a button doesnt have to listen to escape IMO //This doesn't really make sense, a button doesnt have to listen to escape IMO
//Too affraid to remove it since im not sure what it will break.. But yuck.. //Too affraid to remove it since im not sure what it will break.. But yuck..
if (e.keyCode === KEY.ESC) { if (e.keyCode === KEY.ESC) {

@ -1,6 +1,5 @@
import {Engine} from "../engine"; import {Engine} from "../engine";
import {Settings} from "../Settings/Settings"; import {Settings} from "../Settings/Settings";
import {Player} from "../Player";
import {numeralWrapper} from "./numeralFormat"; import {numeralWrapper} from "./numeralFormat";

@ -44,7 +44,7 @@ module.exports = {
// "block-opening-brace-space-before": "always", // "block-opening-brace-space-before": "always",
"color-hex-case": "lower", "color-hex-case": "lower",
"color-hex-length": "short", "color-hex-length": "short",
"color-named": "never", // "color-named": "never",
//"color-no-hex": true, //"color-no-hex": true,
"color-no-invalid-hex": true, "color-no-invalid-hex": true,
// "comment-empty-line-before": "always", // "comment-empty-line-before": "always",

@ -1,6 +1,7 @@
/** /**
* Webpack configuration for building unit tests * Webpack configuration for building unit tests
*/ */
/* eslint-disable @typescript-eslint/no-var-requires */
var path = require('path'); var path = require('path');
var webpack = require('webpack'); var webpack = require('webpack');

@ -1,3 +1,4 @@
/* eslint-disable @typescript-eslint/no-var-requires */
var path = require('path'); var path = require('path');
var webpack = require('webpack'); var webpack = require('webpack');
var MiniCssExtractPlugin = require('mini-css-extract-plugin'); var MiniCssExtractPlugin = require('mini-css-extract-plugin');