Merge pull request #973 from danielyxie/v0.59.10

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

@ -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);

@ -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,10 +1,11 @@
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:
@ -13,3 +14,4 @@ tFormat() Netscript Function
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 -->

@ -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;

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

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

@ -871,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;
@ -1581,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) {
@ -2486,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"));

@ -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();
} }

@ -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;

@ -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>
</>
) )
} }
} }