Merge pull request #509 from danielyxie/dev

v0.41.1
This commit is contained in:
danielyxie 2018-11-13 16:43:58 -06:00 committed by GitHub
commit 82fe74f301
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
29 changed files with 696 additions and 403 deletions

@ -0,0 +1,89 @@
@import "mixins";
@import "theme";
/**
* Styling for the Character Overview Panel (top-right)
*/
#character-overview-wrapper {
position: relative;
}
#character-overview-container {
display: none;
position: absolute; /* Stay in place */
right: 0;
top: 0;
height: auto; /* Full height */
padding: 10px 2px;
border: 2px solid var(--my-highlight-color);
width: auto;
max-width: 280px;
overflow: auto; /* Enable scroll if needed */
background-color: rgba(57, 54, 54, 0.9); /* Fallback color */
z-index: 1;
}
#character-overview-text {
color: $my-stat-physical;
table {
border-collapse: collapse;
margin: auto;
}
td {
padding: 2px;
vertical-align: middle;
}
}
.character-stat-text {
color: #fff;
background-color: #444;
}
.character-stat-cell {
text-align: right;
}
#character-hack-wrapper td,
#character-agi-wrapper td {
border-bottom: 1px #aaa solid;
padding-bottom: 10px;
}
#character-str-wrapper td,
#character-cha-wrapper td {
padding-top: 10px;
}
#character-hp-wrapper { color: $my-stat-hp-color; }
#character-money-wrapper { color: $my-stat-money-color; }
#character-hack-wrapper { color: $my-stat-hack-color; }
#character-cha-wrapper { color: $my-stat-cha-color; }
#character-int-wrapper { color: $my-stat-int-color; }
.character-overview-btn {
@include borderRadius(12px);
@include boxShadow(1px 1px 3px #000);
color: #cecece;
display: inline-block;
font-size: $defaultFontSize * 0.875;
font-weight: bold;
height: 25px;
background-color: #000;
padding: 5px 8px;
}
.character-quick-options {
margin-top: 10px;
text-align: center;
}
.character-overview-btn:hover,
.character-overview-btn:focus {
color: #fff;
text-decoration: none;
cursor: pointer;
}

@ -296,93 +296,6 @@ a:visited {
width: auto; width: auto;
} }
/* Character Overview */
#character-overview-wrapper {
position: relative;
}
#character-overview-container {
display: none;
position: absolute; /* Stay in place */
right: 0;
top: 0;
height: auto; /* Full height */
padding: 10px 2px;
border: 2px solid var(--my-highlight-color);
width: auto;
max-width: 280px;
overflow: auto; /* Enable scroll if needed */
background-color: rgba(57, 54, 54, 0.9); /* Fallback color */
z-index: 1;
}
#character-overview-text {
color: $my-stat-physical;
table {
border-collapse: collapse;
margin: auto;
}
td {
padding: 2px;
vertical-align: middle;
}
}
.character-stat-text {
color: #fff;
background-color: #444;
}
.character-stat-cell {
text-align: right;
}
#character-hack-wrapper td,
#character-agi-wrapper td {
border-bottom: 1px #aaa solid;
padding-bottom: 10px;
}
#character-str-wrapper td,
#character-cha-wrapper td {
padding-top: 10px;
}
#character-hp-wrapper { color: $my-stat-hp-color; }
#character-money-wrapper { color: $my-stat-money-color; }
#character-hack-wrapper { color: $my-stat-hack-color; }
#character-cha-wrapper { color: $my-stat-cha-color; }
#character-int-wrapper { color: $my-stat-int-color; }
#character-overview-save-button,
#character-overview-options-button {
@include borderRadius(12px);
@include boxShadow(1px 1px 3px #000);
color: #cecece;
display: inline-block;
font-size: $defaultFontSize * 0.875;
font-weight: bold;
height: 25px;
background-color: #000;
padding: 5px 8px;
}
.character-quick-options {
margin-top: 10px;
text-align: center;
}
#character-overview-save-button:hover,
#character-overview-save-button:focus,
#character-overview-options-button:hover,
#character-overview-options-button:focus {
color: #fff;
text-decoration: none;
cursor: pointer;
}
/* Scan analyze links from AutoLink */ /* Scan analyze links from AutoLink */
.scan-analyze-link { .scan-analyze-link {
cursor: pointer; cursor: pointer;

File diff suppressed because one or more lines are too long

181
dist/engine.css vendored

@ -305,96 +305,6 @@ a:visited {
top: 0; top: 0;
width: auto; } width: auto; }
/* Character Overview */
#character-overview-wrapper {
position: relative; }
#character-overview-container {
display: none;
position: absolute;
/* Stay in place */
right: 0;
top: 0;
height: auto;
/* Full height */
padding: 10px 2px;
border: 2px solid var(--my-highlight-color);
width: auto;
max-width: 280px;
overflow: auto;
/* Enable scroll if needed */
background-color: rgba(57, 54, 54, 0.9);
/* Fallback color */
z-index: 1; }
#character-overview-text {
color: #faffdf; }
#character-overview-text table {
border-collapse: collapse;
margin: auto; }
#character-overview-text td {
padding: 2px;
vertical-align: middle; }
.character-stat-text {
color: #fff;
background-color: #444; }
.character-stat-cell {
text-align: right; }
#character-hack-wrapper td,
#character-agi-wrapper td {
border-bottom: 1px #aaa solid;
padding-bottom: 10px; }
#character-str-wrapper td,
#character-cha-wrapper td {
padding-top: 10px; }
#character-hp-wrapper {
color: #dd3434; }
#character-money-wrapper {
color: #ffd700; }
#character-hack-wrapper {
color: #adff2f; }
#character-cha-wrapper {
color: #a671d1; }
#character-int-wrapper {
color: #6495ed; }
#character-overview-save-button,
#character-overview-options-button {
-webkit-border-radius: 12px;
-moz-border-radius: 12px;
border-radius: 12px;
-webkit-box-shadow: 1px 1px 3px #000;
-moz-box-shadow: 1px 1px 3px #000;
box-shadow: 1px 1px 3px #000;
color: #cecece;
display: inline-block;
font-size: 14px;
font-weight: bold;
height: 25px;
background-color: #000;
padding: 5px 8px; }
.character-quick-options {
margin-top: 10px;
text-align: center; }
#character-overview-save-button:hover,
#character-overview-save-button:focus,
#character-overview-options-button:hover,
#character-overview-options-button:focus {
color: #fff;
text-decoration: none;
cursor: pointer; }
/* Scan analyze links from AutoLink */ /* Scan analyze links from AutoLink */
.scan-analyze-link { .scan-analyze-link {
cursor: pointer; cursor: pointer;
@ -678,6 +588,97 @@ button {
opacity: 1; opacity: 1;
transition: max-height 0.2s ease-out; } transition: max-height 0.2s ease-out; }
/* COLORS */
/* Attributes */
/**
* Styling for the Character Overview Panel (top-right)
*/
#character-overview-wrapper {
position: relative; }
#character-overview-container {
display: none;
position: absolute;
/* Stay in place */
right: 0;
top: 0;
height: auto;
/* Full height */
padding: 10px 2px;
border: 2px solid var(--my-highlight-color);
width: auto;
max-width: 280px;
overflow: auto;
/* Enable scroll if needed */
background-color: rgba(57, 54, 54, 0.9);
/* Fallback color */
z-index: 1; }
#character-overview-text {
color: #faffdf; }
#character-overview-text table {
border-collapse: collapse;
margin: auto; }
#character-overview-text td {
padding: 2px;
vertical-align: middle; }
.character-stat-text {
color: #fff;
background-color: #444; }
.character-stat-cell {
text-align: right; }
#character-hack-wrapper td,
#character-agi-wrapper td {
border-bottom: 1px #aaa solid;
padding-bottom: 10px; }
#character-str-wrapper td,
#character-cha-wrapper td {
padding-top: 10px; }
#character-hp-wrapper {
color: #dd3434; }
#character-money-wrapper {
color: #ffd700; }
#character-hack-wrapper {
color: #adff2f; }
#character-cha-wrapper {
color: #a671d1; }
#character-int-wrapper {
color: #6495ed; }
.character-overview-btn {
-webkit-border-radius: 12px;
-moz-border-radius: 12px;
border-radius: 12px;
-webkit-box-shadow: 1px 1px 3px #000;
-moz-box-shadow: 1px 1px 3px #000;
box-shadow: 1px 1px 3px #000;
color: #cecece;
display: inline-block;
font-size: 14px;
font-weight: bold;
height: 25px;
background-color: #000;
padding: 5px 8px; }
.character-quick-options {
margin-top: 10px;
text-align: center; }
.character-overview-btn:hover,
.character-overview-btn:focus {
color: #fff;
text-decoration: none;
cursor: pointer; }
/* COLORS */ /* COLORS */
/* Attributes */ /* Attributes */
#terminal-container { #terminal-container {

72
dist/vendor.bundle.js vendored

File diff suppressed because one or more lines are too long

@ -3,6 +3,33 @@
Changelog Changelog
========= =========
v0.41.1 - 11/5/2018
-------------------
* IMPORTANT - Netscript Changes:
* purchaseTor() now returns true if you already have a TOR router (it used to return false)
* getPurchasedServerCost() now returns Infinity if the specified RAM is an invalid amount or is greater than the max amount of RAM (2 ^ 20 GB)
* Added purchase4SMarketData() and purchase4SMarketDataTixApi() functions
* getScriptLogs() now takes in optional arguments that let you get the logs of another script
* Stock Market changes:
* Stocks now have "maximum prices". These are hidden from the player
* If a stock reaches its "maximum price", it will most likely drop in value (although it might still rise)
* Each stock has its own, unique maximum price
* Maximum price for each stock are randomly generated and change during each 'reset'
* Stock Market cycles are now accumulated/stored, much like it is for Gangs and Bladeburners
* Accumulated/stored cycles cause stock prices to update up to 50% faster (from every 6 seconds to 4 seconds)
* This means that after coming back from being offline, stock prices will update faster to make up for offline time
* Decreased the Hacking Level multiplier for BitNodes 6 and 7 to 0.4 (from 0.5)
* Bladeburner console history is now saved and persists when switching screens or closing/reopening the game
* In Bladeburner, if your stamina reaches 0 your current action will be cancelled
* b1t_flum3.exe is no longer removed from your home computer upon reset
* Added main menu link for the Stock Market (once you've purchased an account)
* Job main menu link only appears if you actually have a job
* Bug Fix: Netscript Gang API functions purchaseEquipment() and ascendMember() should now work properly
* Bug Fix: After installing Augs, the "Portfolio Mode" button on the Stock Market page should be properly reset
* Bug Fix: bladeburner.getActionCountRemaining()'s return value is now rounded down (by Kline-)
v0.41.0 - 10/29/2018 v0.41.0 - 10/29/2018
-------------------- --------------------
* WARNING: In NetscriptJS, defining a function called print() is no longer possible * WARNING: In NetscriptJS, defining a function called print() is no longer possible
@ -23,7 +50,7 @@ v0.41.0 - 10/29/2018
* RAM Cost of accessing the global document object lowered from 100 GB to 25 GB * RAM Cost of accessing the global document object lowered from 100 GB to 25 GB
* RAM Cost to use Singularity Functions outside of BitNode-4 lowered by 75%. They now only cost twice as much as they do in BitNode-4 * RAM Cost to use Singularity Functions outside of BitNode-4 lowered by 75%. They now only cost twice as much as they do in BitNode-4
* b1t_flum3.exe now takes significantly less time to create * b1t_flum3.exe now takes significantly less time to create
* Crimes commited through Singularity function no longer give half money/exp * Crimes commited through Singularity function no longer give half money/exp (there is now no penalty)
* Improved number formatting for Player 'work' actions (including crimes, etc.). These numbers should also adhere to locale settings now (by Kline-) * Improved number formatting for Player 'work' actions (including crimes, etc.). These numbers should also adhere to locale settings now (by Kline-)
* The order that Augmentations are listed in (when purchasing from Faction and viewing your Augmentations) is now saved and persists when choosing different orders * The order that Augmentations are listed in (when purchasing from Faction and viewing your Augmentations) is now saved and persists when choosing different orders
* getCharacterInformation() Singularity function now returns multiplier information (from Augmentations/Source Files) * getCharacterInformation() Singularity function now returns multiplier information (from Augmentations/Source Files)

@ -153,17 +153,37 @@ isLogEnabled
getScriptLogs getScriptLogs
^^^^^^^^^^^^^ ^^^^^^^^^^^^^
.. js:function:: getScriptLogs() .. js:function:: getScriptLogs([fn], [hostname/ip=current ip], [args...])
:param string fn: Optional. Filename of script to get logs from.
:param string ip: Optional. IP or hostname of the server that the script is on
:param args...: Arguments to identify which scripts to get logs for
:RAM cost: 0 GB :RAM cost: 0 GB
Returns the script's logs. The logs are returned as an array, where each Returns a script's logs. The logs are returned as an array, where each
line is an element in the array. The most recently logged line is at the line is an element in the array. The most recently logged line is at the
end of the array. end of the array.
Note that there is a maximum number of lines that a script stores in its logs. Note that there is a maximum number of lines that a script stores in its logs.
This is configurable in the game's options. This is configurable in the game's options.
If the function is called with no arguments, it will return the current script's logs.
Otherwise, the `fn`, `hostname/ip,` and `args...` arguments can be used to get the logs
from another script. Remember that scripts are uniquely identified by both
their names and arguments.
Examples::
// Get logs from foo.script on the current server that was run with no args
getScriptLogs("foo.script");
// Get logs from foo.script on the foodnstuff server that was run with no args
getScriptLogs("foo.script", "foodnstuff");
// Get logs from foo.script on the foodnstuff server that was run with the arguments [1, "test"]
getScriptLogs("foo.script", "foodnstuff", 1, "test");
scan scan
^^^^ ^^^^

@ -100,7 +100,7 @@ getMemberInformation
agility: Agility stat agility: Agility stat
agilityEquipMult: Agility multiplier from equipment. Decimal form agilityEquipMult: Agility multiplier from equipment. Decimal form
agilityAscensionMult: Agility multiplier from ascension. Decimal form agilityAscensionMult: Agility multiplier from ascension. Decimal form
augmentation: Array of names of all owned Augmentations augmentations: Array of names of all owned Augmentations
charisma: Charisma stat charisma: Charisma stat
charismaEquipMult: Charisma multiplier from equipment. Decimal form charismaEquipMult: Charisma multiplier from equipment. Decimal form
charismaAscensionMult: Charisma multiplier from ascension. Decimal form charismaAscensionMult: Charisma multiplier from ascension. Decimal form

@ -2,7 +2,7 @@ Netscript Trade Information eXchange (TIX) API
============================================== ==============================================
The Trade Information eXchange (TIX) is the communications protocol supported by the World Stock Exchange (WSE). The Trade Information eXchange (TIX) is the communications protocol supported by the World Stock Exchange (WSE).
The WESE provides an API that allows you to automatically communicate with the The WSE provides an API that allows you to automatically communicate with the
`Stock Market <http://bitburner.wikia.com/wiki/Stock_Market>`_. This API lets you write code using Netscript `Stock Market <http://bitburner.wikia.com/wiki/Stock_Market>`_. This API lets you write code using Netscript
to build automated trading systems and create your own algorithmic trading strategies. Access to this to build automated trading systems and create your own algorithmic trading strategies. Access to this
TIX API can be purchased by visiting the World Stock Exchange in-game. TIX API can be purchased by visiting the World Stock Exchange in-game.
@ -11,7 +11,7 @@ Access to the TIX API currently costs $5 billion. After you purchase it, you wil
access even after you 'reset' by installing Augmentations access even after you 'reset' by installing Augmentations
getStockSymbols getStockSymbols
------------- ---------------
.. js:function:: getStockSymbols() .. js:function:: getStockSymbols()
@ -214,3 +214,23 @@ getStockForecast
In other words, if this function returned 0.30 for a stock, then this means In other words, if this function returned 0.30 for a stock, then this means
that the stock's price has a 30% chance of increasing and a 70% chance of that the stock's price has a 30% chance of increasing and a 70% chance of
decreasing during the next tick. decreasing during the next tick.
purchase4SMarketData
--------------------
.. js:function:: purchase4SMarketData()
Purchase 4S Market Data Access.
Returns true if you successfully purchased it or if you already have access.
Returns false otherwise.
purchase4SMarketDataTixApi
--------------------------
.. js:function:: purchase4SMarketDataTixApi()
Purchase 4S Market Data TIX API Access.
Returns true if you successfully purchased it or if you already have access.
Returns false otherwise.

@ -500,8 +500,6 @@ commitCrime
This function is used to automatically attempt to commit crimes. If you are already in the middle of some 'working' action This function is used to automatically attempt to commit crimes. If you are already in the middle of some 'working' action
(such as working for a company or training at a gym), then running this function will automatically cancel that action and give you your earnings. (such as working for a company or training at a gym), then running this function will automatically cancel that action and give you your earnings.
Note that crimes committed using this function will have all of their earnings halved (this applied for both money and experience!)
This function returns the number of seconds it takes to attempt the specified crime (e.g It takes 60 seconds to attempt the 'Rob Store' crime, This function returns the number of seconds it takes to attempt the specified crime (e.g It takes 60 seconds to attempt the 'Rob Store' crime,
so running *commitCrime('rob store')* will return 60). so running *commitCrime('rob store')* will return 60).

@ -79,6 +79,9 @@
<li id="job-tab" class="mainmenu-accordion-panel"> <li id="job-tab" class="mainmenu-accordion-panel">
<button id="job-menu-link"> Job </button> <button id="job-menu-link"> Job </button>
</li> </li>
<li id="stock-market-tab" class="mainmenu-accordion-panel">
<button id="stock-market-menu-link"> Stock Market </button>
</li>
<li id="bladeburner-tab" class="mainmenu-accordion-panel"> <li id="bladeburner-tab" class="mainmenu-accordion-panel">
<button id="bladeburner-menu-link"> Bladeburner </button> <button id="bladeburner-menu-link"> Bladeburner </button>
</li> </li>
@ -785,8 +788,8 @@
</table> </table>
</div> </div>
<div class="character-quick-options"> <div class="character-quick-options">
<button id="character-overview-save-button">Save Game</button> <button id="character-overview-save-button" class="character-overview-btn">Save Game</button>
<button id="character-overview-options-button">Options</button> <button id="character-overview-options-button" class="character-overview-btn">Options</button>
</div> </div>
</div> </div>
</div> </div>

@ -62,7 +62,7 @@ let NetscriptFunctions =
"hack|sleep|grow|weaken|print|tprint|scan|nuke|brutessh|ftpcrack|" + //Netscript functions "hack|sleep|grow|weaken|print|tprint|scan|nuke|brutessh|ftpcrack|" + //Netscript functions
"clearLog|disableLog|enableLog|isLogEnabled|getScriptLogs|" + "clearLog|disableLog|enableLog|isLogEnabled|getScriptLogs|" +
"relaysmtp|httpworm|sqlinject|run|exec|spawn|kill|killall|exit|" + "relaysmtp|httpworm|sqlinject|run|exec|spawn|kill|killall|exit|" +
"scp|ls|hasRootAccess|" + "scp|ls|ps|hasRootAccess|" +
"getIp|getHackingMultipliers|getBitNodeMultipliers|getStats|isBusy|" + "getIp|getHackingMultipliers|getBitNodeMultipliers|getStats|isBusy|" +
"getHacknetMultipliers|" + "getHacknetMultipliers|" +
"getHostname|getHackingLevel|getServerMoneyAvailable|getServerMaxMoney|" + "getHostname|getHackingLevel|getServerMoneyAvailable|getServerMaxMoney|" +
@ -95,6 +95,7 @@ let NetscriptFunctions =
"getStockPrice|getStockPosition|getStockSymbols|buyStock|sellStock|" + "getStockPrice|getStockPosition|getStockSymbols|buyStock|sellStock|" +
"shortStock|sellShort|" + "shortStock|sellShort|" +
"placeOrder|cancelOrder|getStockVolatility|getStockForecast|" + "placeOrder|cancelOrder|getStockVolatility|getStockForecast|" +
"purchase4SMarketData|purchase4SMarketDataTixApi|" +
// Hacknet Node API // Hacknet Node API
"hacknet|numNodes|purchaseNode|getPurchaseNodeCost|getNodeStats|" + "hacknet|numNodes|purchaseNode|getPurchaseNodeCost|getNodeStats|" +

@ -265,7 +265,7 @@ function initBitNodeMultipliers() {
BitNodeMultipliers.CorporationValuation = 0.5; BitNodeMultipliers.CorporationValuation = 0.5;
break; break;
case 6: //Bladeburner case 6: //Bladeburner
BitNodeMultipliers.HackingLevelMultiplier = 0.5; BitNodeMultipliers.HackingLevelMultiplier = 0.4;
BitNodeMultipliers.ServerMaxMoney = 0.5; BitNodeMultipliers.ServerMaxMoney = 0.5;
BitNodeMultipliers.ServerStartingMoney = 0.5; BitNodeMultipliers.ServerStartingMoney = 0.5;
BitNodeMultipliers.ServerStartingSecurity = 1.5; BitNodeMultipliers.ServerStartingSecurity = 1.5;
@ -282,7 +282,7 @@ function initBitNodeMultipliers() {
BitNodeMultipliers.BladeburnerRank = 0.6; BitNodeMultipliers.BladeburnerRank = 0.6;
BitNodeMultipliers.BladeburnerSkillCost = 2; BitNodeMultipliers.BladeburnerSkillCost = 2;
BitNodeMultipliers.AugmentationMoneyCost = 3; BitNodeMultipliers.AugmentationMoneyCost = 3;
BitNodeMultipliers.HackingLevelMultiplier = 0.5; BitNodeMultipliers.HackingLevelMultiplier = 0.4;
BitNodeMultipliers.ServerMaxMoney = 0.5; BitNodeMultipliers.ServerMaxMoney = 0.5;
BitNodeMultipliers.ServerStartingMoney = 0.5; BitNodeMultipliers.ServerStartingMoney = 0.5;
BitNodeMultipliers.ServerStartingSecurity = 1.5; BitNodeMultipliers.ServerStartingSecurity = 1.5;

@ -74,7 +74,6 @@ var ContractBaseMoneyGain = 50e3; //Base Money Gained per contract
var ActiveActionCssClass = "bladeburner-active-action"; var ActiveActionCssClass = "bladeburner-active-action";
//Console related stuff //Console related stuff
var consoleHistory = []; //Console command history
var consoleHistoryIndex = 0; var consoleHistoryIndex = 0;
var consoleHelpText = { var consoleHelpText = {
helpList:"Use 'help [command]' to get more information about a particular Bladeburner console command.<br><br>" + helpList:"Use 'help [command]' to get more information about a particular Bladeburner console command.<br><br>" +
@ -153,6 +152,7 @@ $(document).keydown(function(event) {
//} //}
if (!(Player.bladeburner instanceof Bladeburner)) {return;} if (!(Player.bladeburner instanceof Bladeburner)) {return;}
let consoleHistory = Player.bladeburner.consoleHistory;
//NOTE: Keycodes imported from Terminal.js //NOTE: Keycodes imported from Terminal.js
if (event.keyCode === KEY.ENTER) { if (event.keyCode === KEY.ENTER) {
@ -712,6 +712,10 @@ function Bladeburner(params={}) {
this.automateActionLow = 0; this.automateActionLow = 0;
this.automateThreshLow = 0; //Stamina Threshold this.automateThreshLow = 0; //Stamina Threshold
//Console command history
this.consoleHistory = [];
this.consoleLogs = [];
//Initialization //Initialization
initBladeburner(); initBladeburner();
this.initializeDomElementRefs(); this.initializeDomElementRefs();
@ -864,6 +868,12 @@ Bladeburner.prototype.process = function() {
this.resetAction(); this.resetAction();
} }
// If the Player has no Stamina, set action to idle
if (this.stamina <= 0) {
this.log("Your Bladeburner action was cancelled because your stamina hit 0");
this.resetAction();
}
//A 'tick' for this mechanic is one second (= 5 game cycles) //A 'tick' for this mechanic is one second (= 5 game cycles)
if (this.storedCycles >= CyclesPerSecond) { if (this.storedCycles >= CyclesPerSecond) {
var seconds = Math.floor(this.storedCycles / CyclesPerSecond); var seconds = Math.floor(this.storedCycles / CyclesPerSecond);
@ -1345,7 +1355,6 @@ Bladeburner.prototype.completeAction = function() {
Player.gainIntelligenceExp(BaseIntGain); Player.gainIntelligenceExp(BaseIntGain);
Player.gainCharismaExp(charismaExpGain); Player.gainCharismaExp(charismaExpGain);
this.changeRank(0.1 * BitNodeMultipliers.BladeburnerRank); this.changeRank(0.1 * BitNodeMultipliers.BladeburnerRank);
console.log("DEBUG: Field Analysis effectiveness is " + (eff * this.skillMultipliers.successChanceEstimate));
this.getCurrentCity().improvePopulationEstimateByPercentage(eff * this.skillMultipliers.successChanceEstimate); this.getCurrentCity().improvePopulationEstimateByPercentage(eff * this.skillMultipliers.successChanceEstimate);
if (this.logging.general) { if (this.logging.general) {
this.log("Field analysis completed. Gained 0.1 rank, " + formatNumber(hackingExpGain, 1) + " hacking exp, and " + formatNumber(charismaExpGain, 1) + " charisma exp"); this.log("Field analysis completed. Gained 0.1 rank, " + formatNumber(hackingExpGain, 1) + " hacking exp, and " + formatNumber(charismaExpGain, 1) + " charisma exp");
@ -1738,8 +1747,15 @@ Bladeburner.prototype.createContent = function() {
document.getElementById("entire-game-container").appendChild(DomElems.bladeburnerDiv); document.getElementById("entire-game-container").appendChild(DomElems.bladeburnerDiv);
this.postToConsole("Bladeburner Console BETA"); if (this.consoleLogs.length === 0) {
this.postToConsole("Type 'help' to see console commands"); this.postToConsole("Bladeburner Console BETA");
this.postToConsole("Type 'help' to see console commands");
} else {
for (let i = 0; i < this.consoleLogs.length; ++i) {
this.postToConsole(this.consoleLogs[i], false);
}
}
DomElems.consoleInput.focus(); DomElems.consoleInput.focus();
} }
@ -2732,12 +2748,22 @@ Bladeburner.prototype.updateSkillsUIElement = function(el, skill) {
} }
//Bladeburner Console Window //Bladeburner Console Window
Bladeburner.prototype.postToConsole = function(input) { Bladeburner.prototype.postToConsole = function(input, saveToLogs=true) {
const MaxConsoleEntries = 100;
if (saveToLogs === true) {
this.consoleLogs.push(input);
if (this.consoleLogs.length > MaxConsoleEntries) {
this.consoleLogs.shift();
}
}
if (input == null || DomElems.consoleDiv == null) {return;} if (input == null || DomElems.consoleDiv == null) {return;}
$("#bladeubrner-console-input-row").before('<tr><td class="bladeburner-console-line" style="color: var(--my-font-color); white-space:pre-wrap;">' + input + '</td></tr>'); $("#bladeubrner-console-input-row").before('<tr><td class="bladeburner-console-line" style="color: var(--my-font-color); white-space:pre-wrap;">' + input + '</td></tr>');
if (DomElems.consoleTable.childNodes.length > 200) {
if (DomElems.consoleTable.childNodes.length > MaxConsoleEntries) {
DomElems.consoleTable.removeChild(DomElems.consoleTable.firstChild); DomElems.consoleTable.removeChild(DomElems.consoleTable.firstChild);
} }
this.updateConsoleScroll(); this.updateConsoleScroll();
} }
@ -2753,6 +2779,8 @@ Bladeburner.prototype.clearConsole = function() {
while (DomElems.consoleTable.childNodes.length > 1) { while (DomElems.consoleTable.childNodes.length > 1) {
DomElems.consoleTable.removeChild(DomElems.consoleTable.firstChild); DomElems.consoleTable.removeChild(DomElems.consoleTable.firstChild);
} }
this.consoleLogs.length = 0;
} }
Bladeburner.prototype.log = function(input) { Bladeburner.prototype.log = function(input) {
@ -2764,13 +2792,13 @@ Bladeburner.prototype.log = function(input) {
Bladeburner.prototype.executeConsoleCommands = function(commands) { Bladeburner.prototype.executeConsoleCommands = function(commands) {
try { try {
//Console History //Console History
if (consoleHistory[consoleHistory.length-1] != commands) { if (this.consoleHistory[this.consoleHistory.length-1] != commands) {
consoleHistory.push(commands); this.consoleHistory.push(commands);
if (consoleHistory.length > 50) { if (this.consoleHistory.length > 50) {
consoleHistory.splice(0, 1); this.consoleHistory.splice(0, 1);
} }
} }
consoleHistoryIndex = consoleHistory.length; consoleHistoryIndex = this.consoleHistory.length;
var arrayOfCommands = commands.split(";"); var arrayOfCommands = commands.split(";");
for (var i = 0; i < arrayOfCommands.length; ++i) { for (var i = 0; i < arrayOfCommands.length; ++i) {
@ -3469,7 +3497,7 @@ Bladeburner.prototype.getActionCountRemainingNetscriptFn = function(type, name,
switch (actionId.type) { switch (actionId.type) {
case ActionTypes["Contract"]: case ActionTypes["Contract"]:
case ActionTypes["Operation"]: case ActionTypes["Operation"]:
return actionObj.count; return Math.floor( actionObj.count );
case ActionTypes["BlackOp"]: case ActionTypes["BlackOp"]:
case ActionTypes["BlackOperation"]: case ActionTypes["BlackOperation"]:
if (this.blackops[name] != null) { if (this.blackops[name] != null) {

@ -1,5 +1,5 @@
let CONSTANTS = { let CONSTANTS = {
Version: "0.41.0", Version: "0.41.1",
//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
@ -502,38 +502,31 @@ let CONSTANTS = {
LatestUpdate: LatestUpdate:
` `
v0.41.0 v0.41.1
* WARNING: In NetscriptJS, defining a function called print() is no longer possible * IMPORTANT - Netscript Changes:
* Gang Mechanic Changes (BitNode-2): ** purchaseTor() now returns true if you already have a TOR router (it used to return false)
*** Added a Gang Netscript API ** getPurchasedServerCost() now returns Infinity if the specified RAM is an invalid amount or is greater than the max amount of RAM (2 ^ 20 GB)
*** Added new 'ascension' mechanic for Gang Members ** Added purchase4SMarketData() and purchase4SMarketDataTixApi() functions
*** The first three gang members are now 'free' (can be recruited instantly) ** getScriptLogs() now takes in optional arguments that let you get the logs of another script
*** Maximum number of increased Gang Members increased from 20 to 30
*** Changed the formula for calculating respect needed to recruit the next gang member * Stock Market changes:
*** Added a new category of upgrades for Gang Members: Augmentations ** Stocks now have "maximum prices". These are hidden from the player
*** Non-Augmentation Gang member upgrades are now significantly weaker ** If a stock reaches its "maximum price", it will most likely drop in value (although it might still rise)
*** Reputation for your Gang faction can no longer be gained through Infiltration ** Each stock has its own, unique maximum price
*** Re-worked the territory 'warfare' mechanic so that player can choose when to engage in it ** Maximum price for each stock are randomly generated and change during each 'reset'
*** Gang Members can now be killed during territory 'warfare' ** Stock Market cycles are now accumulated/stored, much like it is for Gangs and Bladeburners
*** Changed BitNode-2 Multipliers to make hacking slightly less profitable ** Accumulated/stored cycles cause stock prices to update up to 50% faster (from every 6 seconds to 4 seconds)
*** Gang Member Equipment + Upgrades now get cheaper as your gang grows in power and respect *** This means that after coming back from being offline, stock prices will update faster to make up for offline time
*** The effects of Source-File 2 are now slightly more powerful
* RAM Cost of accessing the global document object lowered from 100 GB to 25 GB * Decreased the Hacking Level multiplier for BitNodes 6 and 7 to 0.4 (from 0.5)
* RAM Cost to use Singularity Functions outside of BitNode-4 lowered by 75%. They now only cost twice as much as they do in BitNode-4 * Bladeburner console history is now saved and persists when switching screens or closing/reopening the game
* b1t_flum3.exe now takes significantly less time to create * In Bladeburner, if your stamina reaches 0 your current action will be cancelled
* Crimes commited through Singularity function no longer give half money/exp * b1t_flum3.exe is no longer removed from your home computer upon reset
* Improved number formatting for Player 'work' actions (including crimes, etc.). These numbers should also adhere to locale settings now (by Kline-) * Added main menu link for the Stock Market (once you've purchased an account)
* The order that Augmentations are listed in (when purchasing from Faction and viewing your Augmentations) is now saved and persists when choosing different orders * Job main menu link only appears if you actually have a job
* getCharacterInformation() Singularity function now returns multiplier information (from Augmentations/Source Files) * Bug Fix: Netscript Gang API functions purchaseEquipment() and ascendMember() should now work properly
* Bug Fix: Calling print() in NetscriptJS no longer brings up the print dialog * Bug Fix: After installing Augs, the "Portfolio Mode" button on the Stock Market page should be properly reset
* Bug Fix: Fixed a bug that sometimes caused a blank black screen when destroying/resetting/switching BitNodes * Bug Fix: bladeburner.getActionCountRemaining()'s return value is now rounded down (by Kline-)
* Bug Fix: Netscript calls that throw errors will now no longer cause the 'concurrent calls' error if they are caught in the script. i.e. try/catch should now work properly in scripts
* Bug Fix: Fixed a bug where sometimes the NeuroFlux Governor Augmentation level would be incorrectly calculated when the game was loaded
* Bug Fix: Fixed a bug where calling the scp() Netscript function with invalid hostname/ips would throw an unclear error message
* Bug Fix: Bladeburner API function getActionCountRemaining() should now work properly for BlackOps
* Bug Fix: Black Ops can no longer be attempted out-of-order or without the required rank via Bladeburner API
* Bug Fix: Dynamic RAM Calculation now properly accounts for number of threads
* RAM cost for basic Netscript functions added to documentation (by CBJamo)
` `
} }

@ -5,7 +5,12 @@ import {Factions} from "./Faction";
import {Player} from "./Player"; import {Player} from "./Player";
import {AllServers} from "./Server"; import {AllServers} from "./Server";
import {hackWorldDaemon} from "./RedPill"; import {hackWorldDaemon} from "./RedPill";
import {StockMarket,
SymbolToStockMap} from "./StockMarket";
import {Stock} from "./Stock";
import {Terminal} from "./Terminal"; import {Terminal} from "./Terminal";
import {numeralWrapper} from "./ui/numeralFormat";
import {dialogBoxCreate} from "../utils/DialogBox";
import {exceptionAlert} from "../utils/helpers/exceptionAlert"; import {exceptionAlert} from "../utils/helpers/exceptionAlert";
import {createElement} from "../utils/uiHelpers/createElement"; import {createElement} from "../utils/uiHelpers/createElement";
import {removeElementById} from "../utils/uiHelpers/removeElementById"; import {removeElementById} from "../utils/uiHelpers/removeElementById";
@ -322,6 +327,7 @@ export function createDevMenu() {
const bladeburnerGainRankInput = createElement("input", { const bladeburnerGainRankInput = createElement("input", {
class: "text-input", class: "text-input",
margin: "5px",
placeholder: "Rank to gain (or negative to lose rank)", placeholder: "Rank to gain (or negative to lose rank)",
type: "number", type: "number",
}); });
@ -344,6 +350,7 @@ export function createDevMenu() {
const gangStoredCyclesInput = createElement("input", { const gangStoredCyclesInput = createElement("input", {
class: "text-input", class: "text-input",
margin: "5px",
placeholder: "# Cycles to add", placeholder: "# Cycles to add",
type: "number", type: "number",
}); });
@ -372,6 +379,73 @@ export function createDevMenu() {
innerText: "Generate Random Contract", innerText: "Generate Random Contract",
}); });
// Stock Market
const stockmarketHeader = createElement("h2", {innerText: "Stock Market"});
const stockInput = createElement("input", {
class: "text-input",
display: "block",
placeholder: "Stock symbol(s), or 'all'",
});
function processStocks(cb) {
const input = stockInput.value.toString().replace(/\s/g, '');
// Empty input, or "all", will process all stocks
if (input === "" || input.toLowerCase() === "all") {
for (const name in StockMarket) {
if (StockMarket.hasOwnProperty(name)) {
const stock = StockMarket[name];
if (stock instanceof Stock) {
cb(stock);
}
}
}
return;
}
const stockSymbols = input.split(",");
for (let i = 0; i < stockSymbols.length; ++i) {
const stock = SymbolToStockMap[stockSymbols];
if (stock instanceof Stock) {
cb(stock);
}
}
}
const stockPriceChangeInput = createElement("input", {
class: "text-input",
margin: "5px",
placeholder: "Price to change stock(s) to",
type: "number",
});
const stockPriceChangeBtn = createElement("button", {
class: "std-button",
clickListener: () => {
const price = parseInt(stockPriceChangeInput.value);
if (isNaN(price)) { return; }
processStocks((stock) => {
stock.price = price;
});
dialogBoxCreate(`Stock Prices changed to ${price}`);
},
innerText: "Change Stock Price(s)",
});
const stockViewPriceCapBtn = createElement("button", {
class: "std-button",
clickListener: () => {
let text = "";
processStocks((stock) => {
text += `${stock.symbol}: ${numeralWrapper.format(stock.cap, '$0.000a')}<br>`;
});
dialogBoxCreate(text);
},
innerText: "View Stock Price Caps",
});
// Add everything to container, then append to main menu // Add everything to container, then append to main menu
const devMenuContainer = createElement("div", { const devMenuContainer = createElement("div", {
class: "generic-menupage-container", class: "generic-menupage-container",
@ -433,6 +507,12 @@ export function createDevMenu() {
devMenuContainer.appendChild(createElement("br")); devMenuContainer.appendChild(createElement("br"));
devMenuContainer.appendChild(contractsHeader); devMenuContainer.appendChild(contractsHeader);
devMenuContainer.appendChild(generateRandomContractBtn); devMenuContainer.appendChild(generateRandomContractBtn);
devMenuContainer.appendChild(stockmarketHeader);
devMenuContainer.appendChild(stockInput);
devMenuContainer.appendChild(stockPriceChangeInput);
devMenuContainer.appendChild(stockPriceChangeBtn);
devMenuContainer.appendChild(createElement("br"));
devMenuContainer.appendChild(stockViewPriceCapBtn);
const entireGameContainer = document.getElementById("entire-game-container"); const entireGameContainer = document.getElementById("entire-game-container");
if (entireGameContainer == null) { if (entireGameContainer == null) {

@ -394,7 +394,6 @@ function displayFactionContent(factionName) {
var hacking = false; var hacking = false;
if (factionName === "NiteSec" || factionName === "The Black Hand") {hacking = true;} if (factionName === "NiteSec" || factionName === "The Black Hand") {hacking = true;}
Player.startGang(factionName, hacking); Player.startGang(factionName, hacking);
document.getElementById("gang-tab").style.display = "list-item";
document.getElementById("world-menu-header").click(); document.getElementById("world-menu-header").click();
document.getElementById("world-menu-header").click(); document.getElementById("world-menu-header").click();
Engine.loadGangContent(); Engine.loadGangContent();

@ -1953,7 +1953,6 @@ function initLocationButtons() {
name:companyName, name:companyName,
}); });
displayLocationContent(); displayLocationContent();
document.getElementById("corporation-tab").style.display = "list-item";
document.getElementById("world-menu-header").click(); document.getElementById("world-menu-header").click();
document.getElementById("world-menu-header").click(); document.getElementById("world-menu-header").click();
dialogBoxCreate("Congratulations! You just started your own corporation. You can visit " + dialogBoxCreate("Congratulations! You just started your own corporation. You can visit " +
@ -1983,7 +1982,6 @@ function initLocationButtons() {
Player.bladeburner = new Bladeburner({new:true}); Player.bladeburner = new Bladeburner({new:true});
dialogBoxCreate("You have been accepted into the Bladeburner division!"); dialogBoxCreate("You have been accepted into the Bladeburner division!");
displayLocationContent(); displayLocationContent();
document.getElementById("bladeburner-tab").style.display = "list-item";
document.getElementById("world-menu-header").click(); document.getElementById("world-menu-header").click();
document.getElementById("world-menu-header").click(); document.getElementById("world-menu-header").click();
} else { } else {

@ -35,10 +35,9 @@ import {Server, getServer, AddToAllServers,
import {Settings} from "./Settings"; import {Settings} from "./Settings";
import {SpecialServerIps} from "./SpecialServerIps"; import {SpecialServerIps} from "./SpecialServerIps";
import {Stock} from "./Stock"; import {Stock} from "./Stock";
import {StockMarket, StockSymbols, SymbolToStockMap, initStockSymbols, import {StockMarket, StockSymbols, SymbolToStockMap,
initStockMarket, initSymbolToStockMap, stockMarketCycle, buyStock, initStockMarket, initSymbolToStockMap, buyStock,
sellStock, updateStockPrices, displayStockMarketContent, sellStock, updateStockPlayerPosition,
updateStockTicker, updateStockPlayerPosition,
shortStock, sellShort, OrderTypes, shortStock, sellShort, OrderTypes,
PositionTypes, placeOrder, cancelOrder} from "./StockMarket"; PositionTypes, placeOrder, cancelOrder} from "./StockMarket";
import {post} from "./ui/postToTerminal"; import {post} from "./ui/postToTerminal";
@ -107,11 +106,14 @@ var possibleLogs = {
getServerGrowth: true, getServerGrowth: true,
getServerNumPortsRequired: true, getServerNumPortsRequired: true,
getServerRam: true, getServerRam: true,
// TIX API // TIX API
buyStock: true, buyStock: true,
sellStock: true, sellStock: true,
shortStock: true, shortStock: true,
sellShort: true, sellShort: true,
purchase4SMarketData: true,
purchase4SMarketDataTixApi: true,
// Singularity Functions // Singularity Functions
purchaseServer: true, purchaseServer: true,
@ -546,8 +548,30 @@ function NetscriptFunctions(workerScript) {
} }
return workerScript.disableLogs[fn] ? false : true; return workerScript.disableLogs[fn] ? false : true;
}, },
getScriptLogs : function() { getScriptLogs : function(fn, ip) {
if (workerScript.checkingRam) {return 0;} if (workerScript.checkingRam) {return 0;}
if (fn != null && typeof fn === 'string') {
// Get Logs of another script
if (ip == null) { ip = workerScript.serverIp; }
const server = getServer(ip);
if (server == null) {
workerScript.log(`getScriptLogs() failed. Invalid IP or hostname passed in: ${ip}`);
throw makeRuntimeRejectMsg(workerScript, `getScriptLogs() failed. Invalid IP or hostname passed in: ${ip}`);
}
let argsForTarget = [];
for (let i = 2; i < arguments.length; ++i) {
argsForTarget.push(arguments[i]);
}
const runningScriptObj = findRunningScript(fn, argsForTarget, server);
if (runningScriptObj == null) {
workerScript.scriptRef.log(`getScriptLogs() failed. No such script ${fn} on ${server.hostname} with args: ${arrayToString(argsForTarget)}`);
return "";
}
return runningScriptObj.logs.slice();
}
return workerScript.scriptRef.logs.slice(); return workerScript.scriptRef.logs.slice();
}, },
nuke : function(ip){ nuke : function(ip){
@ -801,7 +825,7 @@ function NetscriptFunctions(workerScript) {
} }
NetscriptFunctions(workerScript).exit(); NetscriptFunctions(workerScript).exit();
}, },
kill : function(filename,ip) { kill : function(filename, ip) {
if (workerScript.checkingRam) { if (workerScript.checkingRam) {
return updateStaticRam("kill", CONSTANTS.ScriptKillRamCost); return updateStaticRam("kill", CONSTANTS.ScriptKillRamCost);
} }
@ -1697,6 +1721,68 @@ function NetscriptFunctions(workerScript) {
stock.b ? forecast += stock.otlkMag : forecast -= stock.otlkMag; stock.b ? forecast += stock.otlkMag : forecast -= stock.otlkMag;
return forecast / 100; //Convert from percentage to decimal return forecast / 100; //Convert from percentage to decimal
}, },
purchase4SMarketData : function() {
if (workerScript.checkingRam) {
return updateStaticRam("purchase4SMarketData", CONSTANTS.ScriptBuySellStockRamCost);
}
updateDynamicRam("purchase4SMarketData", CONSTANTS.ScriptBuySellStockRamCost);
if (!Player.hasTixApiAccess) {
throw makeRuntimeRejectMsg(workerScript, "You don't have TIX API Access! Cannot use purchase4SMarketData()");
}
if (Player.has4SData) {
if (workerScript.shouldLog("purchase4SMarketData")) {
workerScript.log("Already purchased 4S Market Data");
}
return true;
}
if (Player.money.lt(CONSTANTS.MarketData4SCost)) {
if (workerScript.shouldLog("purchase4SMarketData")) {
workerScript.log("Failed to purchase 4S Market Data - Not enough money");
}
return false;
}
Player.has4SData = true;
Player.loseMoney(CONSTANTS.MarketData4SCost);
if (workerScript.shouldLog("purchase4SMarketData")) {
workerScript.log("Purchased 4S Market Data");
}
return true;
},
purchase4SMarketDataTixApi : function() {
if (workerScript.checkingRam) {
return updateStaticRam("purchase4SMarketDataTixApi", CONSTANTS.ScriptBuySellStockRamCost);
}
updateDynamicRam("purchase4SMarketDataTixApi", CONSTANTS.ScriptBuySellStockRamCost);
if (!Player.hasTixApiAccess) {
throw makeRuntimeRejectMsg(workerScript, "You don't have TIX API Access! Cannot use purchase4SMarketDataTixApi()");
}
if (Player.has4SDataTixApi) {
if (workerScript.shouldLog("purchase4SMarketDataTixApi")) {
workerScript.log("Already purchased 4S Market Data TIX API");
}
return true;
}
if (Player.money.lt(CONSTANTS.MarketDataTixApi4SCost)) {
if (workerScript.shouldLog("purchase4SMarketDataTixApi")) {
workerScript.log("Failed to purchase 4S Market Data TIX API - Not enough money");
}
return false;
}
Player.has4SDataTixApi = true;
Player.loseMoney(CONSTANTS.MarketDataTixApi4SCost);
if (workerScript.shouldLog("purchase4SMarketDataTixApi")) {
workerScript.log("Purchased 4S Market Data TIX API");
}
return true;
},
getPurchasedServerLimit : function() { getPurchasedServerLimit : function() {
if (workerScript.checkingRam) { if (workerScript.checkingRam) {
return updateStaticRam("getPurchasedServerLimit", CONSTANTS.ScriptGetPurchasedServerLimit); return updateStaticRam("getPurchasedServerLimit", CONSTANTS.ScriptGetPurchasedServerLimit);
@ -1724,7 +1810,7 @@ function NetscriptFunctions(workerScript) {
cost = getPurchaseServerRamCostGuard(ram); cost = getPurchaseServerRamCostGuard(ram);
} catch (e) { } catch (e) {
workerScript.scriptRef.log("ERROR: 'getPurchasedServerCost()' " + e.message); workerScript.scriptRef.log("ERROR: 'getPurchasedServerCost()' " + e.message);
return ""; return Infinity;
} }
return cost; return cost;
@ -3782,7 +3868,7 @@ function NetscriptFunctions(workerScript) {
nsGang.checkGangApiAccess(workerScript, "purchaseEquipment"); nsGang.checkGangApiAccess(workerScript, "purchaseEquipment");
try { try {
for (const member in Player.gang.members) { for (const member of Player.gang.members) {
if (member.name === memberName) { if (member.name === memberName) {
const res = member.buyUpgrade(equipName, Player, Player.gang); const res = member.buyUpgrade(equipName, Player, Player.gang);
if (workerScript.shouldLog("purchaseEquipment")) { if (workerScript.shouldLog("purchaseEquipment")) {
@ -3811,13 +3897,13 @@ function NetscriptFunctions(workerScript) {
nsGang.checkGangApiAccess(workerScript, "ascendMember"); nsGang.checkGangApiAccess(workerScript, "ascendMember");
try { try {
for (const member in Player.gang.members) { for (const member of Player.gang.members) {
if (member.name === name) { if (member.name === name) {
return Player.gang.ascendMember(member, workerScript); return Player.gang.ascendMember(member, workerScript);
} }
} }
workerScript.log(`Invalid argument passed to gang.ascendMember(). No gang member could be found with name ${memberName}`); workerScript.log(`Invalid argument passed to gang.ascendMember(). No gang member could be found with name ${name}`);
return false; return false;
} catch(e) { } catch(e) {
throw makeRuntimeRejectMsg(workerScript, nsGang.unknownGangApiExceptionMessage("ascendMember", e)); throw makeRuntimeRejectMsg(workerScript, nsGang.unknownGangApiExceptionMessage("ascendMember", e));

@ -73,7 +73,7 @@ export function _getScriptUrls(script, scripts, seen) {
// import {foo} from "blob://<uuid>" // import {foo} from "blob://<uuid>"
// //
// Where the blob URL contains the script content. // Where the blob URL contains the script content.
let transformedCode = script.code.replace(/((?:from|import)\s+(?:'|"))([^'"]+)('|";)/g, let transformedCode = script.code.replace(/((?:from|import)\s+(?:'|"))(?:\.\/)?([^'"]+)('|";)/g,
(unmodified, prefix, filename, suffix) => { (unmodified, prefix, filename, suffix) => {
const isAllowedImport = scripts.some(s => s.filename == filename); const isAllowedImport = scripts.some(s => s.filename == filename);
if (!isAllowedImport) return unmodified; if (!isAllowedImport) return unmodified;

@ -191,7 +191,6 @@ function PlayerObject() {
//Flags for determining whether certain "thresholds" have been achieved //Flags for determining whether certain "thresholds" have been achieved
this.firstFacInvRecvd = false; this.firstFacInvRecvd = false;
this.firstAugPurchased = false; this.firstAugPurchased = false;
this.firstJobRecvd = false;
this.firstTimeTraveled = false; this.firstTimeTraveled = false;
this.firstProgramAvailable = false; this.firstProgramAvailable = false;
@ -1687,12 +1686,8 @@ PlayerObject.prototype.applyForJob = function(entryPosType, sing=false) {
this.companyName = company.companyName; this.companyName = company.companyName;
this.companyPosition = pos; this.companyPosition = pos;
if (this.firstJobRecvd === false) { document.getElementById("world-menu-header").click();
this.firstJobRecvd = true; document.getElementById("world-menu-header").click();
document.getElementById("job-tab").style.display = "list-item";
document.getElementById("world-menu-header").click();
document.getElementById("world-menu-header").click();
}
if (leaveCompany) { if (leaveCompany) {
if (sing) {return true;} if (sing) {return true;}
@ -1797,14 +1792,10 @@ PlayerObject.prototype.applyForAgentJob = function(sing=false) {
PlayerObject.prototype.applyForEmployeeJob = function(sing=false) { PlayerObject.prototype.applyForEmployeeJob = function(sing=false) {
var company = Companies[this.location]; //Company being applied to var company = Companies[this.location]; //Company being applied to
if (this.isQualified(company, CompanyPositions.Employee)) { if (this.isQualified(company, CompanyPositions.Employee)) {
if (this.firstJobRecvd === false) {
this.firstJobRecvd = true;
document.getElementById("job-tab").style.display = "list-item";
document.getElementById("world-menu-header").click();
document.getElementById("world-menu-header").click();
}
this.companyName = company.companyName; this.companyName = company.companyName;
this.companyPosition = CompanyPositions.Employee; this.companyPosition = CompanyPositions.Employee;
document.getElementById("world-menu-header").click();
document.getElementById("world-menu-header").click();
if (sing) {return true;} if (sing) {return true;}
dialogBoxCreate("Congratulations, you are now employed at " + this.companyName); dialogBoxCreate("Congratulations, you are now employed at " + this.companyName);
Engine.loadLocationContent(); Engine.loadLocationContent();
@ -1817,14 +1808,10 @@ PlayerObject.prototype.applyForEmployeeJob = function(sing=false) {
PlayerObject.prototype.applyForPartTimeEmployeeJob = function(sing=false) { PlayerObject.prototype.applyForPartTimeEmployeeJob = function(sing=false) {
var company = Companies[this.location]; //Company being applied to var company = Companies[this.location]; //Company being applied to
if (this.isQualified(company, CompanyPositions.PartTimeEmployee)) { if (this.isQualified(company, CompanyPositions.PartTimeEmployee)) {
if (this.firstJobRecvd === false) {
this.firstJobRecvd = true;
document.getElementById("job-tab").style.display = "list-item";
document.getElementById("world-menu-header").click();
document.getElementById("world-menu-header").click();
}
this.companyName = company.companyName; this.companyName = company.companyName;
this.companyPosition = CompanyPositions.PartTimeEmployee; this.companyPosition = CompanyPositions.PartTimeEmployee;
document.getElementById("world-menu-header").click();
document.getElementById("world-menu-header").click();
if (sing) {return true;} if (sing) {return true;}
dialogBoxCreate("Congratulations, you are now employed part-time at " + this.companyName); dialogBoxCreate("Congratulations, you are now employed part-time at " + this.companyName);
Engine.loadLocationContent(); Engine.loadLocationContent();
@ -1837,14 +1824,10 @@ PlayerObject.prototype.applyForPartTimeEmployeeJob = function(sing=false) {
PlayerObject.prototype.applyForWaiterJob = function(sing=false) { PlayerObject.prototype.applyForWaiterJob = function(sing=false) {
var company = Companies[this.location]; //Company being applied to var company = Companies[this.location]; //Company being applied to
if (this.isQualified(company, CompanyPositions.Waiter)) { if (this.isQualified(company, CompanyPositions.Waiter)) {
if (this.firstJobRecvd === false) {
this.firstJobRecvd = true;
document.getElementById("job-tab").style.display = "list-item";
document.getElementById("world-menu-header").click();
document.getElementById("world-menu-header").click();
}
this.companyName = company.companyName; this.companyName = company.companyName;
this.companyPosition = CompanyPositions.Waiter; this.companyPosition = CompanyPositions.Waiter;
document.getElementById("world-menu-header").click();
document.getElementById("world-menu-header").click();
if (sing) {return true;} if (sing) {return true;}
dialogBoxCreate("Congratulations, you are now employed as a waiter at " + this.companyName); dialogBoxCreate("Congratulations, you are now employed as a waiter at " + this.companyName);
Engine.loadLocationContent(); Engine.loadLocationContent();
@ -1857,14 +1840,10 @@ PlayerObject.prototype.applyForWaiterJob = function(sing=false) {
PlayerObject.prototype.applyForPartTimeWaiterJob = function(sing=false) { PlayerObject.prototype.applyForPartTimeWaiterJob = function(sing=false) {
var company = Companies[this.location]; //Company being applied to var company = Companies[this.location]; //Company being applied to
if (this.isQualified(company, CompanyPositions.PartTimeWaiter)) { if (this.isQualified(company, CompanyPositions.PartTimeWaiter)) {
if (this.firstJobRecvd === false) {
this.firstJobRecvd = true;
document.getElementById("job-tab").style.display = "list-item";
document.getElementById("world-menu-header").click();
document.getElementById("world-menu-header").click();
}
this.companyName = company.companyName; this.companyName = company.companyName;
this.companyPosition = CompanyPositions.PartTimeWaiter; this.companyPosition = CompanyPositions.PartTimeWaiter;
document.getElementById("world-menu-header").click();
document.getElementById("world-menu-header").click();
if (sing) {return true;} if (sing) {return true;}
dialogBoxCreate("Congratulations, you are now employed as a part-time waiter at " + this.companyName); dialogBoxCreate("Congratulations, you are now employed as a part-time waiter at " + this.companyName);
Engine.loadLocationContent(); Engine.loadLocationContent();

@ -148,6 +148,10 @@ function prestigeAugmentation() {
Terminal.resetTerminalInput(); Terminal.resetTerminalInput();
Engine.loadTerminalContent(); Engine.loadTerminalContent();
// Refresh Main Menu (the 'World' menu, specifically)
document.getElementById("world-menu-header").click();
document.getElementById("world-menu-header").click();
//Red Pill //Red Pill
if (augmentationExists(AugmentationNames.TheRedPill) && if (augmentationExists(AugmentationNames.TheRedPill) &&
Augmentations[AugmentationNames.TheRedPill].owned) { Augmentations[AugmentationNames.TheRedPill].owned) {
@ -319,6 +323,10 @@ function prestigeSourceFile() {
Player.corporation = null; Player.corporation = null;
Player.bladeburner = null; Player.bladeburner = null;
// Refresh Main Menu (the 'World' menu, specifically)
document.getElementById("world-menu-header").click();
document.getElementById("world-menu-header").click();
//Gain int exp //Gain int exp
Player.gainIntelligenceExp(5); Player.gainIntelligenceExp(5);
} }

@ -198,16 +198,12 @@ function loadGame(saveString) {
//that everything should be available //that everything should be available
Player.firstFacInvRecvd = true; Player.firstFacInvRecvd = true;
Player.firstAugPurchased = true; Player.firstAugPurchased = true;
Player.firstJobRecvd = true;
Player.firstTimeTraveled = true; Player.firstTimeTraveled = true;
Player.firstProgramAvailable = true; Player.firstProgramAvailable = true;
} else { } else {
if (Player.factions.length > 0 || Player.factionInvitations.length > 0) { if (Player.factions.length > 0 || Player.factionInvitations.length > 0) {
Player.firstFacInvRecvd = true; Player.firstFacInvRecvd = true;
} }
if (Player.companyName !== "" || Player.companyPosition !== "") {
Player.firstJobRecvd = true;
}
if (Player.hacking_skill >= 25) { if (Player.hacking_skill >= 25) {
Player.firstScriptAvailable = true; Player.firstScriptAvailable = true;
} }
@ -417,16 +413,12 @@ function loadImportedGame(saveObj, saveString) {
//that everything should be available //that everything should be available
Player.firstFacInvRecvd = true; Player.firstFacInvRecvd = true;
Player.firstAugPurchased = true; Player.firstAugPurchased = true;
Player.firstJobRecvd = true;
Player.firstTimeTraveled = true; Player.firstTimeTraveled = true;
Player.firstProgramAvailable = true; Player.firstProgramAvailable = true;
} else { } else {
if (Player.factions.length > 0 || Player.factionInvitations.length > 0) { if (Player.factions.length > 0 || Player.factionInvitations.length > 0) {
Player.firstFacInvRecvd = true; Player.firstFacInvRecvd = true;
} }
if (Player.companyName !== "" || Player.companyPosition !== "") {
Player.firstJobRecvd = true;
}
if (Player.hacking_skill >= 25) { if (Player.hacking_skill >= 25) {
Player.firstScriptAvailable = true; Player.firstScriptAvailable = true;
} }

@ -344,12 +344,15 @@ function processSingleServerGrowth(server, numCycles) {
} }
function prestigeHomeComputer(homeComp) { function prestigeHomeComputer(homeComp) {
const hasBitflume = homeComp.programs.includes(Programs.BitFlume.name);
homeComp.programs.length = 0; //Remove programs homeComp.programs.length = 0; //Remove programs
homeComp.runningScripts = []; homeComp.runningScripts = [];
homeComp.serversOnNetwork = []; homeComp.serversOnNetwork = [];
homeComp.isConnectedTo = true; homeComp.isConnectedTo = true;
homeComp.ramUsed = 0; homeComp.ramUsed = 0;
homeComp.programs.push(Programs.NukeProgram.name); homeComp.programs.push(Programs.NukeProgram.name);
if (hasBitflume) { homeComp.programs.push(Programs.BitFlume.name); }
//Update RAM usage on all scripts //Update RAM usage on all scripts
homeComp.scripts.forEach(function(script) { homeComp.scripts.forEach(function(script) {

@ -1,4 +1,5 @@
import { Generic_fromJSON, Generic_toJSON, Reviver } from "../utils/JSONReviver"; import { Generic_fromJSON, Generic_toJSON, Reviver } from "../utils/JSONReviver";
import { getRandomInt } from "../utils/helpers/getRandomInt";
/** /**
* Represents the valuation of a company in the World Stock Exchange. * Represents the valuation of a company in the World Stock Exchange.
@ -16,6 +17,11 @@ export class Stock {
*/ */
b: boolean; b: boolean;
/**
* Maximum price of a stock (per share)
*/
readonly cap: number;
/** /**
* Maximum volatility * Maximum volatility
*/ */
@ -83,6 +89,7 @@ export class Stock {
this.mv = mv; this.mv = mv;
this.b = b; this.b = b;
this.otlkMag = otlkMag; this.otlkMag = otlkMag;
this.cap = getRandomInt(initPrice * 1e3, initPrice * 25e3);
this.posTxtEl = null; this.posTxtEl = null;
} }

@ -23,8 +23,6 @@ import {yesNoBoxCreate, yesNoTxtInpBoxCreate,
yesNoTxtInpBoxGetInput, yesNoBoxClose, yesNoTxtInpBoxGetInput, yesNoBoxClose,
yesNoTxtInpBoxClose, yesNoBoxOpen} from "../utils/YesNoBox"; yesNoTxtInpBoxClose, yesNoBoxOpen} from "../utils/YesNoBox";
let StockPriceCap = 1e9; //Put a limit on how high a price can go
var OrderTypes = { var OrderTypes = {
LimitBuy: "Limit Buy Order", LimitBuy: "Limit Buy Order",
LimitSell: "Limit Sell Order", LimitSell: "Limit Sell Order",
@ -227,136 +225,138 @@ function initStockMarket() {
} }
} }
const randInt = getRandomInt;
var ecorp = Locations.AevumECorp; var ecorp = Locations.AevumECorp;
var ecorpStk = new Stock(ecorp, StockSymbols[ecorp], getRandomInt(40, 50)/100, true, 19, getRandomInt(17e3, 28e3)); var ecorpStk = new Stock(ecorp, StockSymbols[ecorp], randInt(40, 50) / 100, true, 19, randInt(17e3, 28e3));
StockMarket[ecorp] = ecorpStk; StockMarket[ecorp] = ecorpStk;
var megacorp = Locations.Sector12MegaCorp; var megacorp = Locations.Sector12MegaCorp;
var megacorpStk = new Stock(megacorp, StockSymbols[megacorp], getRandomInt(40,50)/100, true, 19, getRandomInt(24e3, 34e3)); var megacorpStk = new Stock(megacorp, StockSymbols[megacorp], randInt(40,50)/100, true, 19, randInt(24e3, 34e3));
StockMarket[megacorp] = megacorpStk; StockMarket[megacorp] = megacorpStk;
var blade = Locations.Sector12BladeIndustries; var blade = Locations.Sector12BladeIndustries;
var bladeStk = new Stock(blade, StockSymbols[blade], getRandomInt(70, 80)/100, true, 13, getRandomInt(12e3, 25e3)); var bladeStk = new Stock(blade, StockSymbols[blade], randInt(70, 80)/100, true, 13, randInt(12e3, 25e3));
StockMarket[blade] = bladeStk; StockMarket[blade] = bladeStk;
var clarke = Locations.AevumClarkeIncorporated; var clarke = Locations.AevumClarkeIncorporated;
var clarkeStk = new Stock(clarke, StockSymbols[clarke], getRandomInt(65, 75)/100, true, 12, getRandomInt(10e3, 25e3)); var clarkeStk = new Stock(clarke, StockSymbols[clarke], randInt(65, 75)/100, true, 12, randInt(10e3, 25e3));
StockMarket[clarke] = clarkeStk; StockMarket[clarke] = clarkeStk;
var omnitek = Locations.VolhavenOmniTekIncorporated; var omnitek = Locations.VolhavenOmniTekIncorporated;
var omnitekStk = new Stock(omnitek, StockSymbols[omnitek], getRandomInt(60, 70)/100, true, 12, getRandomInt(32e3, 43e3)); var omnitekStk = new Stock(omnitek, StockSymbols[omnitek], randInt(60, 70)/100, true, 12, randInt(32e3, 43e3));
StockMarket[omnitek] = omnitekStk; StockMarket[omnitek] = omnitekStk;
var foursigma = Locations.Sector12FourSigma; var foursigma = Locations.Sector12FourSigma;
var foursigmaStk = new Stock(foursigma, StockSymbols[foursigma], getRandomInt(100, 110)/100, true, 17, getRandomInt(50e3, 80e3)); var foursigmaStk = new Stock(foursigma, StockSymbols[foursigma], randInt(100, 110)/100, true, 17, randInt(50e3, 80e3));
StockMarket[foursigma] = foursigmaStk; StockMarket[foursigma] = foursigmaStk;
var kuaigong = Locations.ChongqingKuaiGongInternational; var kuaigong = Locations.ChongqingKuaiGongInternational;
var kuaigongStk = new Stock(kuaigong, StockSymbols[kuaigong], getRandomInt(75, 85)/100, true, 10, getRandomInt(16e3, 28e3)); var kuaigongStk = new Stock(kuaigong, StockSymbols[kuaigong], randInt(75, 85)/100, true, 10, randInt(16e3, 28e3));
StockMarket[kuaigong] = kuaigongStk; StockMarket[kuaigong] = kuaigongStk;
var fulcrum = Locations.AevumFulcrumTechnologies; var fulcrum = Locations.AevumFulcrumTechnologies;
var fulcrumStk = new Stock(fulcrum, StockSymbols[fulcrum], getRandomInt(120, 130)/100, true, 16, getRandomInt(29e3, 36e3)); var fulcrumStk = new Stock(fulcrum, StockSymbols[fulcrum], randInt(120, 130)/100, true, 16, randInt(29e3, 36e3));
StockMarket[fulcrum] = fulcrumStk; StockMarket[fulcrum] = fulcrumStk;
var storm = Locations.IshimaStormTechnologies; var storm = Locations.IshimaStormTechnologies;
var stormStk = new Stock(storm, StockSymbols[storm], getRandomInt(80, 90)/100, true, 7, getRandomInt(20e3, 25e3)); var stormStk = new Stock(storm, StockSymbols[storm], randInt(80, 90)/100, true, 7, randInt(20e3, 25e3));
StockMarket[storm] = stormStk; StockMarket[storm] = stormStk;
var defcomm = Locations.NewTokyoDefComm; var defcomm = Locations.NewTokyoDefComm;
var defcommStk = new Stock(defcomm, StockSymbols[defcomm], getRandomInt(60, 70)/100, true, 10, getRandomInt(6e3, 19e3)); var defcommStk = new Stock(defcomm, StockSymbols[defcomm], randInt(60, 70)/100, true, 10, randInt(6e3, 19e3));
StockMarket[defcomm] = defcommStk; StockMarket[defcomm] = defcommStk;
var helios = Locations.VolhavenHeliosLabs; var helios = Locations.VolhavenHeliosLabs;
var heliosStk = new Stock(helios, StockSymbols[helios], getRandomInt(55, 65)/100, true, 9, getRandomInt(10e3, 18e3)); var heliosStk = new Stock(helios, StockSymbols[helios], randInt(55, 65)/100, true, 9, randInt(10e3, 18e3));
StockMarket[helios] = heliosStk; StockMarket[helios] = heliosStk;
var vitalife = Locations.NewTokyoVitaLife; var vitalife = Locations.NewTokyoVitaLife;
var vitalifeStk = new Stock(vitalife, StockSymbols[vitalife], getRandomInt(70, 80)/100, true, 7, getRandomInt(8e3, 14e3)); var vitalifeStk = new Stock(vitalife, StockSymbols[vitalife], randInt(70, 80)/100, true, 7, randInt(8e3, 14e3));
StockMarket[vitalife] = vitalifeStk; StockMarket[vitalife] = vitalifeStk;
var icarus = Locations.Sector12IcarusMicrosystems; var icarus = Locations.Sector12IcarusMicrosystems;
var icarusStk = new Stock(icarus, StockSymbols[icarus], getRandomInt(60, 70)/100, true, 7.5, getRandomInt(12e3, 24e3)); var icarusStk = new Stock(icarus, StockSymbols[icarus], randInt(60, 70)/100, true, 7.5, randInt(12e3, 24e3));
StockMarket[icarus] = icarusStk; StockMarket[icarus] = icarusStk;
var universalenergy = Locations.Sector12UniversalEnergy; var universalenergy = Locations.Sector12UniversalEnergy;
var universalenergyStk = new Stock(universalenergy, StockSymbols[universalenergy], getRandomInt(50, 60)/100, true, 10, getRandomInt(16e3, 29e3)); var universalenergyStk = new Stock(universalenergy, StockSymbols[universalenergy], randInt(50, 60)/100, true, 10, randInt(16e3, 29e3));
StockMarket[universalenergy] = universalenergyStk; StockMarket[universalenergy] = universalenergyStk;
var aerocorp = Locations.AevumAeroCorp; var aerocorp = Locations.AevumAeroCorp;
var aerocorpStk = new Stock(aerocorp, StockSymbols[aerocorp], getRandomInt(55, 65)/100, true, 6, getRandomInt(8e3, 17e3)); var aerocorpStk = new Stock(aerocorp, StockSymbols[aerocorp], randInt(55, 65)/100, true, 6, randInt(8e3, 17e3));
StockMarket[aerocorp] = aerocorpStk; StockMarket[aerocorp] = aerocorpStk;
var omnia = Locations.VolhavenOmniaCybersystems; var omnia = Locations.VolhavenOmniaCybersystems;
var omniaStk = new Stock(omnia, StockSymbols[omnia], getRandomInt(65, 75)/100, true, 4.5, getRandomInt(6e3, 15e3)); var omniaStk = new Stock(omnia, StockSymbols[omnia], randInt(65, 75)/100, true, 4.5, randInt(6e3, 15e3));
StockMarket[omnia] = omniaStk; StockMarket[omnia] = omniaStk;
var solaris = Locations.ChongqingSolarisSpaceSystems; var solaris = Locations.ChongqingSolarisSpaceSystems;
var solarisStk = new Stock(solaris, StockSymbols[solaris], getRandomInt(70, 80)/100, true, 8.5, getRandomInt(14e3, 28e3)); var solarisStk = new Stock(solaris, StockSymbols[solaris], randInt(70, 80)/100, true, 8.5, randInt(14e3, 28e3));
StockMarket[solaris] = solarisStk; StockMarket[solaris] = solarisStk;
var globalpharm = Locations.NewTokyoGlobalPharmaceuticals; var globalpharm = Locations.NewTokyoGlobalPharmaceuticals;
var globalpharmStk = new Stock(globalpharm, StockSymbols[globalpharm], getRandomInt(55, 65)/100, true, 10.5, getRandomInt(12e3, 30e3)); var globalpharmStk = new Stock(globalpharm, StockSymbols[globalpharm], randInt(55, 65)/100, true, 10.5, randInt(12e3, 30e3));
StockMarket[globalpharm] = globalpharmStk; StockMarket[globalpharm] = globalpharmStk;
var nova = Locations.IshimaNovaMedical; var nova = Locations.IshimaNovaMedical;
var novaStk = new Stock(nova, StockSymbols[nova], getRandomInt(70, 80)/100, true, 5, getRandomInt(15e3, 27e3)); var novaStk = new Stock(nova, StockSymbols[nova], randInt(70, 80)/100, true, 5, randInt(15e3, 27e3));
StockMarket[nova] = novaStk; StockMarket[nova] = novaStk;
var watchdog = Locations.AevumWatchdogSecurity; var watchdog = Locations.AevumWatchdogSecurity;
var watchdogStk = new Stock(watchdog, StockSymbols[watchdog], getRandomInt(240, 260)/100, true, 1.5, getRandomInt(4e3, 8.5e3)); var watchdogStk = new Stock(watchdog, StockSymbols[watchdog], randInt(240, 260)/100, true, 1.5, randInt(4e3, 8.5e3));
StockMarket[watchdog] = watchdogStk; StockMarket[watchdog] = watchdogStk;
var lexocorp = Locations.VolhavenLexoCorp; var lexocorp = Locations.VolhavenLexoCorp;
var lexocorpStk = new Stock(lexocorp, StockSymbols[lexocorp], getRandomInt(115, 135)/100, true, 6, getRandomInt(4.5e3, 8e3)); var lexocorpStk = new Stock(lexocorp, StockSymbols[lexocorp], randInt(115, 135)/100, true, 6, randInt(4.5e3, 8e3));
StockMarket[lexocorp] = lexocorpStk; StockMarket[lexocorp] = lexocorpStk;
var rho = Locations.AevumRhoConstruction; var rho = Locations.AevumRhoConstruction;
var rhoStk = new Stock(rho, StockSymbols[rho], getRandomInt(50, 70)/100, true, 1, getRandomInt(2e3, 7e3)); var rhoStk = new Stock(rho, StockSymbols[rho], randInt(50, 70)/100, true, 1, randInt(2e3, 7e3));
StockMarket[rho] = rhoStk; StockMarket[rho] = rhoStk;
var alpha = Locations.Sector12AlphaEnterprises; var alpha = Locations.Sector12AlphaEnterprises;
var alphaStk = new Stock(alpha, StockSymbols[alpha], getRandomInt(175, 205)/100, true, 10, getRandomInt(4e3, 8.5e3)); var alphaStk = new Stock(alpha, StockSymbols[alpha], randInt(175, 205)/100, true, 10, randInt(4e3, 8.5e3));
StockMarket[alpha] = alphaStk; StockMarket[alpha] = alphaStk;
var syscore = Locations.VolhavenSysCoreSecurities; var syscore = Locations.VolhavenSysCoreSecurities;
var syscoreStk = new Stock(syscore, StockSymbols[syscore], getRandomInt(150, 170)/100, true, 3, getRandomInt(3e3, 8e3)); var syscoreStk = new Stock(syscore, StockSymbols[syscore], randInt(150, 170)/100, true, 3, randInt(3e3, 8e3));
StockMarket[syscore] = syscoreStk; StockMarket[syscore] = syscoreStk;
var computek = Locations.VolhavenCompuTek; var computek = Locations.VolhavenCompuTek;
var computekStk = new Stock(computek, StockSymbols[computek], getRandomInt(80, 100)/100, true, 4, getRandomInt(1e3, 6e3)); var computekStk = new Stock(computek, StockSymbols[computek], randInt(80, 100)/100, true, 4, randInt(1e3, 6e3));
StockMarket[computek] = computekStk; StockMarket[computek] = computekStk;
var netlink = Locations.AevumNetLinkTechnologies; var netlink = Locations.AevumNetLinkTechnologies;
var netlinkStk = new Stock(netlink, StockSymbols[netlink], getRandomInt(400, 430)/100, true, 1, getRandomInt(1e3, 5e3)); var netlinkStk = new Stock(netlink, StockSymbols[netlink], randInt(400, 430)/100, true, 1, randInt(1e3, 5e3));
StockMarket[netlink] = netlinkStk; StockMarket[netlink] = netlinkStk;
var omega = Locations.IshimaOmegaSoftware; var omega = Locations.IshimaOmegaSoftware;
var omegaStk = new Stock(omega, StockSymbols[omega], getRandomInt(90, 110)/100, true, 0.5, getRandomInt(1e3, 8e3)); var omegaStk = new Stock(omega, StockSymbols[omega], randInt(90, 110)/100, true, 0.5, randInt(1e3, 8e3));
StockMarket[omega] = omegaStk; StockMarket[omega] = omegaStk;
var fns = Locations.Sector12FoodNStuff; var fns = Locations.Sector12FoodNStuff;
var fnsStk = new Stock(fns, StockSymbols[fns], getRandomInt(70, 80)/100, false, 1, getRandomInt(500, 4.5e3)); var fnsStk = new Stock(fns, StockSymbols[fns], randInt(70, 80)/100, false, 1, randInt(500, 4.5e3));
StockMarket[fns] = fnsStk; StockMarket[fns] = fnsStk;
var sigmacosm = "Sigma Cosmetics"; var sigmacosm = "Sigma Cosmetics";
var sigmacosmStk = new Stock(sigmacosm, StockSymbols[sigmacosm], getRandomInt(260, 300)/100, true, 0, getRandomInt(1.5e3, 3.5e3)); var sigmacosmStk = new Stock(sigmacosm, StockSymbols[sigmacosm], randInt(260, 300)/100, true, 0, randInt(1.5e3, 3.5e3));
StockMarket[sigmacosm] = sigmacosmStk; StockMarket[sigmacosm] = sigmacosmStk;
var joesguns = "Joes Guns"; var joesguns = "Joes Guns";
var joesgunsStk = new Stock(joesguns, StockSymbols[joesguns], getRandomInt(360, 400)/100, true, 1, getRandomInt(250, 1.5e3)); var joesgunsStk = new Stock(joesguns, StockSymbols[joesguns], randInt(360, 400)/100, true, 1, randInt(250, 1.5e3));
StockMarket[joesguns] = joesgunsStk; StockMarket[joesguns] = joesgunsStk;
var catalyst = "Catalyst Ventures"; var catalyst = "Catalyst Ventures";
var catalystStk = new Stock(catalyst, StockSymbols[catalyst], getRandomInt(120, 175)/100, true, 13.5, getRandomInt(250, 1.5e3)); var catalystStk = new Stock(catalyst, StockSymbols[catalyst], randInt(120, 175)/100, true, 13.5, randInt(250, 1.5e3));
StockMarket[catalyst] = catalystStk; StockMarket[catalyst] = catalystStk;
var microdyne = "Microdyne Technologies"; var microdyne = "Microdyne Technologies";
var microdyneStk = new Stock(microdyne, StockSymbols[microdyne], getRandomInt(70, 80)/100, true, 8, getRandomInt(15e3, 30e3)); var microdyneStk = new Stock(microdyne, StockSymbols[microdyne], randInt(70, 80)/100, true, 8, randInt(15e3, 30e3));
StockMarket[microdyne] = microdyneStk; StockMarket[microdyne] = microdyneStk;
var titanlabs = "Titan Laboratories"; var titanlabs = "Titan Laboratories";
var titanlabsStk = new Stock(titanlabs, StockSymbols[titanlabs], getRandomInt(50, 70)/100, true, 11, getRandomInt(12e3, 24e3)); var titanlabsStk = new Stock(titanlabs, StockSymbols[titanlabs], randInt(50, 70)/100, true, 11, randInt(12e3, 24e3));
StockMarket[titanlabs] = titanlabsStk; StockMarket[titanlabs] = titanlabsStk;
var orders = {}; var orders = {};
@ -368,6 +368,9 @@ function initStockMarket() {
} }
} }
StockMarket["Orders"] = orders; StockMarket["Orders"] = orders;
StockMarket.storedCycles = 0;
StockMarket.lastUpdate = 0;
} }
function initSymbolToStockMap() { function initSymbolToStockMap() {
@ -375,7 +378,7 @@ function initSymbolToStockMap() {
if (StockSymbols.hasOwnProperty(name)) { if (StockSymbols.hasOwnProperty(name)) {
var stock = StockMarket[name]; var stock = StockMarket[name];
if (stock == null) { if (stock == null) {
console.log("ERROR finding stock"); console.error(`Could not find Stock for ${name}`);
continue; continue;
} }
var symbol = StockSymbols[name]; var symbol = StockSymbols[name];
@ -543,25 +546,40 @@ function sellShort(stock, shares, workerScript=null) {
return true; return true;
} }
function updateStockPrices() { function processStockPrices(numCycles=1) {
if (StockMarket.storedCycles == null || isNaN(StockMarket.storedCycles)) { StockMarket.storedCycles = 0; }
StockMarket.storedCycles += numCycles;
// Stock Prices updated every 6 seconds on average. But if there are stored
// cycles they update 50% faster, so every 4 seconds
const msPerStockUpdate = 6e3;
const cyclesPerStockUpdate = msPerStockUpdate / CONSTANTS.MilliPerCycle;
if (StockMarket.storedCycles < cyclesPerStockUpdate) { return; }
const timeNow = new Date().getTime();
if (timeNow - StockMarket.lastUpdate < 4e3) { return; }
StockMarket.lastUpdate = timeNow;
StockMarket.storedCycles -= cyclesPerStockUpdate;
var v = Math.random(); var v = Math.random();
for (var name in StockMarket) { for (var name in StockMarket) {
if (StockMarket.hasOwnProperty(name)) { if (StockMarket.hasOwnProperty(name)) {
var stock = StockMarket[name]; var stock = StockMarket[name];
if (!(stock instanceof Stock)) {continue;} if (!(stock instanceof Stock)) { continue; }
var av = (v * stock.mv) / 100; var av = (v * stock.mv) / 100;
if (isNaN(av)) {av = .02;} if (isNaN(av)) {av = .02;}
var chc = 50; var chc = 50;
if (stock.b) { if (stock.b) {
chc = (chc + stock.otlkMag)/100; chc = (chc + stock.otlkMag) / 100;
if (isNaN(chc)) {chc = 0.5;} if (isNaN(chc)) {chc = 0.5;}
} else { } else {
chc = (chc - stock.otlkMag)/100; chc = (chc - stock.otlkMag) / 100;
if (isNaN(chc)) {chc = 0.5;} if (isNaN(chc)) {chc = 0.5;}
} }
if (stock.price >= StockPriceCap) { if (stock.price >= stock.cap) {
chc = -1; //Limit on stock price chc = 0.1; // "Soft Limit" on stock price. It could still go up but its unlikely
stock.b = false; stock.b = false;
} }
@ -725,6 +743,7 @@ function displayStockMarketContent() {
"Buy 4S Market Data Access - " + numeralWrapper.format(CONSTANTS.MarketData4SCost, '($0.000a)'), "Buy 4S Market Data Access - " + numeralWrapper.format(CONSTANTS.MarketData4SCost, '($0.000a)'),
"4S Market Data - Purchased"); "4S Market Data - Purchased");
marketDataButton.addEventListener("click", function() { marketDataButton.addEventListener("click", function() {
if (Player.money.lt(CONSTANTS.MarketData4SCost)) { return false; }
Player.has4SData = true; Player.has4SData = true;
Player.loseMoney(CONSTANTS.MarketData4SCost); Player.loseMoney(CONSTANTS.MarketData4SCost);
displayStockMarketContent(); displayStockMarketContent();
@ -764,6 +783,7 @@ function displayStockMarketContent() {
"4S Market Data TIX API - Purchased"); "4S Market Data TIX API - Purchased");
if (Player.hasTixApiAccess) { if (Player.hasTixApiAccess) {
marketDataTixButton.addEventListener("click", function() { marketDataTixButton.addEventListener("click", function() {
if (Player.money.lt(CONSTANTS.MarketDataTixApi4SCost)) { return false; }
Player.has4SDataTixApi = true; Player.has4SDataTixApi = true;
Player.loseMoney(CONSTANTS.MarketDataTixApi4SCost); Player.loseMoney(CONSTANTS.MarketDataTixApi4SCost);
displayStockMarketContent(); displayStockMarketContent();
@ -875,6 +895,7 @@ function displayStockMarketContent() {
//Switch to Portfolio Mode Button //Switch to Portfolio Mode Button
if (modeBtn) { if (modeBtn) {
stockMarketPortfolioMode = false;
modeBtn.innerHTML = "Switch to 'Portfolio' Mode" + modeBtn.innerHTML = "Switch to 'Portfolio' Mode" +
"<span class='tooltiptext'>Displays only the stocks for which you have shares or orders</span>"; "<span class='tooltiptext'>Displays only the stocks for which you have shares or orders</span>";
modeBtn.addEventListener("click", switchToPortfolioMode); modeBtn.addEventListener("click", switchToPortfolioMode);
@ -1459,6 +1480,6 @@ function updateStockOrderList(stock) {
export {StockMarket, StockSymbols, SymbolToStockMap, initStockSymbols, export {StockMarket, StockSymbols, SymbolToStockMap, initStockSymbols,
initStockMarket, initSymbolToStockMap, stockMarketCycle, buyStock, initStockMarket, initSymbolToStockMap, stockMarketCycle, buyStock,
sellStock, shortStock, sellShort, updateStockPrices, displayStockMarketContent, sellStock, shortStock, sellShort, processStockPrices, displayStockMarketContent,
updateStockTicker, updateStockPlayerPosition, loadStockMarket, updateStockTicker, updateStockPlayerPosition, loadStockMarket,
setStockMarketContentCreated, placeOrder, cancelOrder, Order, OrderTypes, PositionTypes}; setStockMarketContentCreated, placeOrder, cancelOrder, Order, OrderTypes, PositionTypes};

@ -105,7 +105,7 @@ export const codingContractTypesMetadata: ICodingContractTypeMetadata[] = [
" 2 + 2\n", " 2 + 2\n",
" 2 + 1 + 1\n", " 2 + 1 + 1\n",
" 1 + 1 + 1 + 1\n\n", " 1 + 1 + 1 + 1\n\n",
`How many different ways can ${n} be written as a sum of at least`, `How many different ways can the number ${n} be written as a sum of at least`,
"two positive integers?"].join(" "); "two positive integers?"].join(" ");
}, },
difficulty: 1.5, difficulty: 1.5,
@ -387,8 +387,8 @@ export const codingContractTypesMetadata: ICodingContractTypeMetadata[] = [
}, },
{ {
desc: (data: number[]) => { desc: (data: number[]) => {
return ["You are given the following array of stock prices where the i-th element", return ["You are given the following array of stock prices (which are numbers)",
"represents the stock price on day i:\n\n", "where the i-th element represents the stock price on day i:\n\n",
`${data}\n\n`, `${data}\n\n`,
"Determine the maximum possible profit you can earn using at most", "Determine the maximum possible profit you can earn using at most",
"one transaction (i.e. you can only buy and sell the stock once). If no profit can be made", "one transaction (i.e. you can only buy and sell the stock once). If no profit can be made",
@ -421,8 +421,8 @@ export const codingContractTypesMetadata: ICodingContractTypeMetadata[] = [
}, },
{ {
desc: (data: number[]) => { desc: (data: number[]) => {
return ["You are given the following array of stock prices where the i-th element", return ["You are given the following array of stock prices (which are numbers)",
"represents the stock price on day i:\n\n", "where the i-th element represents the stock price on day i:\n\n",
`${data}\n\n`, `${data}\n\n`,
"Determine the maximum possible profit you can earn using as many", "Determine the maximum possible profit you can earn using as many",
"transactions as you'd like. A transaction is defined as buying", "transactions as you'd like. A transaction is defined as buying",
@ -455,8 +455,8 @@ export const codingContractTypesMetadata: ICodingContractTypeMetadata[] = [
}, },
{ {
desc: (data: number[]) => { desc: (data: number[]) => {
return ["You are given the following array of stock prices where the i-th element", return ["You are given the following array of stock prices (which are numbers)",
"represents the stock price on day i:\n\n", "where the i-th element represents the stock price on day i:\n\n",
`${data}\n\n`, `${data}\n\n`,
"Determine the maximum possible profit you can earn using at most", "Determine the maximum possible profit you can earn using at most",
"two transactions. A transaction is defined as buying", "two transactions. A transaction is defined as buying",

@ -66,7 +66,7 @@ import {SpecialServerIps, initSpecialServerIps} from "./SpecialServerIps
import {StockMarket, StockSymbols, import {StockMarket, StockSymbols,
SymbolToStockMap, initStockSymbols, SymbolToStockMap, initStockSymbols,
initSymbolToStockMap, stockMarketCycle, initSymbolToStockMap, stockMarketCycle,
updateStockPrices, processStockPrices,
displayStockMarketContent} from "./StockMarket"; displayStockMarketContent} from "./StockMarket";
import {Terminal, postNetburnerText} from "./Terminal"; import {Terminal, postNetburnerText} from "./Terminal";
import {KEY} from "../utils/helpers/keyCodes"; import {KEY} from "../utils/helpers/keyCodes";
@ -78,6 +78,7 @@ import 'normalize.css';
import "../css/styles.scss"; import "../css/styles.scss";
import "../css/buttons.scss"; import "../css/buttons.scss";
import "../css/mainmenu.scss"; import "../css/mainmenu.scss";
import "../css/characteroverview.scss";
import "../css/terminal.scss"; import "../css/terminal.scss";
import "../css/menupages.scss"; import "../css/menupages.scss";
import "../css/workinprogress.scss"; import "../css/workinprogress.scss";
@ -172,6 +173,7 @@ const Engine = {
worldMainMenuButton: null, worldMainMenuButton: null,
travelMainMenuButton: null, travelMainMenuButton: null,
jobMainMenuButton: null, jobMainMenuButton: null,
stockmarketMainMenuButton: null,
createProgramMainMenuButton: null, createProgramMainMenuButton: null,
factionsMainMenuButton: null, factionsMainMenuButton: null,
augmentationsMainMenuButton: null, augmentationsMainMenuButton: null,
@ -885,6 +887,11 @@ const Engine = {
} }
} }
// Update stock prices
if (Player.hasWseAccount) {
processStockPrices(numCycles);
}
//Gang, if applicable //Gang, if applicable
if (Player.bitNodeN == 2 && Player.inGang()) { if (Player.bitNodeN == 2 && Player.inGang()) {
Player.gang.process(numCycles, Player); Player.gang.process(numCycles, Player);
@ -935,7 +942,6 @@ const Engine = {
checkFactionInvitations: 100, //Check whether you qualify for any faction invitations checkFactionInvitations: 100, //Check whether you qualify for any faction invitations
passiveFactionGrowth: 600, passiveFactionGrowth: 600,
messages: 150, messages: 150,
stockTick: 30, //Update stock prices
sCr: 1500, sCr: 1500,
mechanicProcess: 5, //Processes certain mechanics (Corporation, Bladeburner) mechanicProcess: 5, //Processes certain mechanics (Corporation, Bladeburner)
contractGeneration: 3000 //Generate Coding Contracts contractGeneration: 3000 //Generate Coding Contracts
@ -1056,13 +1062,6 @@ const Engine = {
} }
} }
if (Engine.Counters.stockTick <= 0) {
if (Player.hasWseAccount) {
updateStockPrices();
}
Engine.Counters.stockTick = 30;
}
if (Engine.Counters.sCr <= 0) { if (Engine.Counters.sCr <= 0) {
if (Player.hasWseAccount) { if (Player.hasWseAccount) {
stockMarketCycle(); stockMarketCycle();
@ -1189,6 +1188,7 @@ const Engine = {
var city = document.getElementById("city-tab"); var city = document.getElementById("city-tab");
var travel = document.getElementById("travel-tab"); var travel = document.getElementById("travel-tab");
var job = document.getElementById("job-tab"); var job = document.getElementById("job-tab");
var stockmarket = document.getElementById("stock-market-tab");
var bladeburner = document.getElementById("bladeburner-tab"); var bladeburner = document.getElementById("bladeburner-tab");
var corp = document.getElementById("corporation-tab"); var corp = document.getElementById("corporation-tab");
var gang = document.getElementById("gang-tab"); var gang = document.getElementById("gang-tab");
@ -1246,6 +1246,11 @@ const Engine = {
//Passive faction rep gain offline //Passive faction rep gain offline
processPassiveFactionRepGain(numCyclesOffline); processPassiveFactionRepGain(numCyclesOffline);
// Stock Market offline progress
if (Player.hasWseAccount) {
processStockPrices(numCyclesOffline);
}
//Gang progress for BitNode 2 //Gang progress for BitNode 2
if (Player.bitNodeN != null && Player.bitNodeN === 2 && Player.inGang()) { if (Player.bitNodeN != null && Player.bitNodeN === 2 && Player.inGang()) {
Player.gang.process(numCyclesOffline, Player); Player.gang.process(numCyclesOffline, Player);
@ -1278,12 +1283,14 @@ const Engine = {
else {factions.style.display = "none";} else {factions.style.display = "none";}
if (Player.firstAugPurchased) {visibleMenuTabs.push(augmentations);} if (Player.firstAugPurchased) {visibleMenuTabs.push(augmentations);}
else {augmentations.style.display = "none";} else {augmentations.style.display = "none";}
if (Player.firstJobRecvd) {visibleMenuTabs.push(job);} if (Player.companyPosition !== "") {visibleMenuTabs.push(job);}
else {job.style.display = "none";} else {job.style.display = "none";}
if (Player.firstTimeTraveled) {visibleMenuTabs.push(travel);} if (Player.firstTimeTraveled) {visibleMenuTabs.push(travel);}
else {travel.style.display = "none";} else {travel.style.display = "none";}
if (Player.firstProgramAvailable) {visibleMenuTabs.push(createProgram);} if (Player.firstProgramAvailable) {visibleMenuTabs.push(createProgram);}
else {createProgram.style.display = "none";} else {createProgram.style.display = "none";}
if (Player.hasWseAccount) {visibleMenuTabs.push(stockmarket);}
else {stockmarket.style.display = "none";}
if(Player.bladeburner instanceof Bladeburner) {visibleMenuTabs.push(bladeburner);} if(Player.bladeburner instanceof Bladeburner) {visibleMenuTabs.push(bladeburner);}
else {bladeburner.style.display = "none";} else {bladeburner.style.display = "none";}
if(Player.corporation instanceof Corporation) {visibleMenuTabs.push(corp);} if(Player.corporation instanceof Corporation) {visibleMenuTabs.push(corp);}
@ -1327,6 +1334,7 @@ const Engine = {
factions.style.display = "none"; factions.style.display = "none";
augmentations.style.display = "none"; augmentations.style.display = "none";
job.style.display = "none"; job.style.display = "none";
stockmarket.style.display = "none";
travel.style.display = "none"; travel.style.display = "none";
createProgram.style.display = "none"; createProgram.style.display = "none";
bladeburner.style.display = "none"; bladeburner.style.display = "none";
@ -1543,28 +1551,38 @@ const Engine = {
} }
worldHdr.onclick = function() { worldHdr.onclick = function() {
var city = document.getElementById("city-tab"); var city = document.getElementById("city-tab");
var cityLink = document.getElementById("city-menu-link"); var cityLink = document.getElementById("city-menu-link");
var travel = document.getElementById("travel-tab"); var travel = document.getElementById("travel-tab");
var travelLink = document.getElementById("travel-menu-link"); var travelLink = document.getElementById("travel-menu-link");
var job = document.getElementById("job-tab"); var job = document.getElementById("job-tab");
var jobLink = document.getElementById("job-menu-link"); var jobLink = document.getElementById("job-menu-link");
var bladeburner = document.getElementById("bladeburner-tab"); var stockmarket = document.getElementById("stock-market-tab");
var bladeburnerLink = document.getElementById("bladeburner-menu-link"); var stockmarketLink = document.getElementById("stock-market-menu-link");
var corporation = document.getElementById("corporation-tab"); var bladeburner = document.getElementById("bladeburner-tab");
var corporationLink = document.getElementById("corporation-menu-link"); var bladeburnerLink = document.getElementById("bladeburner-menu-link");
var gang = document.getElementById("gang-tab"); var corporation = document.getElementById("corporation-tab");
var gangLink = document.getElementById("gang-menu-link"); var corporationLink = document.getElementById("corporation-menu-link");
var gang = document.getElementById("gang-tab");
var gangLink = document.getElementById("gang-menu-link");
// Determine whether certain links should show up
job.style.display = Player.companyPosition !== "" ? "list-item" : "none";
stockmarket.style.display = Player.hasWseAccount ? "list-item" : "none";
bladeburner.style.display = Player.bladeburner instanceof Bladeburner ? "list-item" : "none";
corporation.style.display = Player.corporation instanceof Corporation ? "list-item" : "none";
gang.style.display = Player.inGang() ? "list-item" : "none";
this.classList.toggle("opened"); this.classList.toggle("opened");
if (city.style.maxHeight) { if (city.style.maxHeight) {
Engine.toggleMainMenuHeader(false, Engine.toggleMainMenuHeader(false,
[city, travel, job, bladeburner, corporation, gang], [city, travel, job, stockmarket, bladeburner, corporation, gang],
[cityLink, travelLink, jobLink, bladeburnerLink, corporationLink, gangLink] [cityLink, travelLink, jobLink, stockmarketLink, bladeburnerLink, corporationLink, gangLink]
); );
} else { } else {
Engine.toggleMainMenuHeader(true, Engine.toggleMainMenuHeader(true,
[city, travel, job, bladeburner, corporation, gang], [city, travel, job, stockmarket, bladeburner, corporation, gang],
[cityLink, travelLink, jobLink, bladeburnerLink, corporationLink, gangLink] [cityLink, travelLink, jobLink, stockmarketLink, bladeburnerLink, corporationLink, gangLink]
); );
} }
} }
@ -1637,6 +1655,12 @@ const Engine = {
return false; return false;
}); });
Engine.Clickables.stockmarketMainMenuButton = clearEventListeners("stock-market-menu-link");
Engine.Clickables.stockmarketMainMenuButton.addEventListener("click", function() {
Engine.loadStockMarketContent();
return false;
});
Engine.Clickables.createProgramMainMenuButton = clearEventListeners("create-program-menu-link"); Engine.Clickables.createProgramMainMenuButton = clearEventListeners("create-program-menu-link");
Engine.Clickables.createProgramMainMenuButton.addEventListener("click", function() { Engine.Clickables.createProgramMainMenuButton.addEventListener("click", function() {

@ -81,6 +81,9 @@ if (htmlWebpackPlugin.options.googleAnalytics.trackingId) { %>
<li id="job-tab" class="mainmenu-accordion-panel"> <li id="job-tab" class="mainmenu-accordion-panel">
<button id="job-menu-link"> Job </button> <button id="job-menu-link"> Job </button>
</li> </li>
<li id="stock-market-tab" class="mainmenu-accordion-panel">
<button id="stock-market-menu-link"> Stock Market </button>
</li>
<li id="bladeburner-tab" class="mainmenu-accordion-panel"> <li id="bladeburner-tab" class="mainmenu-accordion-panel">
<button id="bladeburner-menu-link"> Bladeburner </button> <button id="bladeburner-menu-link"> Bladeburner </button>
</li> </li>
@ -789,8 +792,8 @@ if (htmlWebpackPlugin.options.googleAnalytics.trackingId) { %>
</table> </table>
</div> </div>
<div class="character-quick-options"> <div class="character-quick-options">
<button id="character-overview-save-button">Save Game</button> <button id="character-overview-save-button" class="character-overview-btn">Save Game</button>
<button id="character-overview-options-button">Options</button> <button id="character-overview-options-button" class="character-overview-btn">Options</button>
</div> </div>
</div> </div>
</div> </div>