Fixed merge conflicts with dev

This commit is contained in:
danielyxie 2018-11-15 19:45:03 -08:00
commit 9b3ff6d2d3
29 changed files with 4879 additions and 4314 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;

7365
dist/engine.bundle.js vendored

File diff suppressed because it is too large Load Diff

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 {

754
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

@ -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
^^^^ ^^^^
@ -931,9 +951,10 @@ getPortHandle
rm rm
^^ ^^
.. js:function:: rm(fn) .. js:function:: rm(fn[, hostname/ip=current server])
:param string fn: Filename of file to remove. Must include the extension :param string fn: Filename of file to remove. Must include the extension
:param string hostname/ip: Hostname or IP Address of the server on which to delete the file. Optional. Defaults to current server
:returns: True if it successfully deletes the file, and false otherwise :returns: True if it successfully deletes the file, and false otherwise
:RAM cost: 1 GB :RAM cost: 1 GB
@ -991,7 +1012,7 @@ getScriptRam
.. js:function:: getScriptRam(scriptname[, hostname/ip]) .. js:function:: getScriptRam(scriptname[, hostname/ip])
:param string scriptname: Filename of script. This is case-sensitive. :param string scriptname: Filename of script. This is case-sensitive.
:param string hostname/ip: Hostname or IP of target server the script is located on. This is optional, If it is not specified then the function will se the current server as the target server. :param string hostname/ip: Hostname or IP of target server the script is located on. This is optional, If it is not specified then the function will set the current server as the target server.
:RAM cost: 0.1 GB :RAM cost: 0.1 GB
Returns the amount of RAM required to run the specified script on the target server. Returns Returns the amount of RAM required to run the specified script on the target server. Returns

@ -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
@ -234,6 +234,17 @@ setTerritoryWarfare
Set whether or not the gang should engage in territory warfare Set whether or not the gang should engage in territory warfare
getChanceToWinClash
-------------------
.. js:function:: getChanceToWinClash(gangName)
:param string gangName: Target gang
Returns the chance you have to win a clash with the specified gang. The chance
is returned in decimal form, not percentage
getBonusTime getBonusTime
------------ ------------

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

@ -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>
@ -787,8 +790,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|" +
@ -106,7 +107,7 @@ let NetscriptFunctions =
"getMemberNames|getGangInformation|getMemberInformation|canRecruitMember|" + "getMemberNames|getGangInformation|getMemberInformation|canRecruitMember|" +
"recruitMember|getTaskNames|setMemberTask|getEquipmentNames|" + "recruitMember|getTaskNames|setMemberTask|getEquipmentNames|" +
"getEquipmentCost|purchaseEquipment|ascendMember|setTerritoryWarfare|" + "getEquipmentCost|purchaseEquipment|ascendMember|setTerritoryWarfare|" +
"getBonusTime|" + "getChanceToWinClash|getBonusTime|" +
// Bladeburner API // Bladeburner API
"bladeburner|getContractNames|getOperationNames|getBlackOpNames|" + "bladeburner|getContractNames|getOperationNames|getBlackOpNames|" +

@ -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);
if (this.consoleLogs.length === 0) {
this.postToConsole("Bladeburner Console BETA"); this.postToConsole("Bladeburner Console BETA");
this.postToConsole("Type 'help' to see console commands"); 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) {

@ -185,7 +185,7 @@ export const companyPositionMetadata: IConstructorParams[] = [
baseSalary: 410, baseSalary: 410,
charismaEffectiveness: 20, charismaEffectiveness: 20,
charismaExpGain: 0.1, charismaExpGain: 0.1,
hackingEffectiveness: 0.80, hackingEffectiveness: 80,
hackingExpGain: 0.5, hackingExpGain: 0.5,
reqdCharisma: 76, reqdCharisma: 76,
reqdHacking: 251, reqdHacking: 251,
@ -419,7 +419,7 @@ export const companyPositionMetadata: IConstructorParams[] = [
}, },
{ {
name: posNames.AgentCompanyPositions[0], // Field Agent name: posNames.AgentCompanyPositions[0], // Field Agent
nextPosition: posNames.AgentCompanyPositions[0], // Secret Agent nextPosition: posNames.AgentCompanyPositions[1], // Secret Agent
baseSalary: 330, baseSalary: 330,
hackingEffectiveness: 10, hackingEffectiveness: 10,
strengthEffectiveness: 15, strengthEffectiveness: 15,
@ -443,8 +443,8 @@ export const companyPositionMetadata: IConstructorParams[] = [
repMultiplier: 1, repMultiplier: 1,
}, },
{ {
name: posNames.AgentCompanyPositions[0], // Secret Agent name: posNames.AgentCompanyPositions[1], // Secret Agent
nextPosition: posNames.AgentCompanyPositions[0], // Special Operative nextPosition: posNames.AgentCompanyPositions[2], // Special Operative
baseSalary: 990, baseSalary: 990,
hackingEffectiveness: 15, hackingEffectiveness: 15,
strengthEffectiveness: 15, strengthEffectiveness: 15,
@ -468,7 +468,7 @@ export const companyPositionMetadata: IConstructorParams[] = [
repMultiplier: 1.25, repMultiplier: 1.25,
}, },
{ {
name: posNames.AgentCompanyPositions[0], // Special Operative name: posNames.AgentCompanyPositions[2], // Special Operative
nextPosition: null, nextPosition: null,
baseSalary: 2000, baseSalary: 2000,
hackingEffectiveness: 15, hackingEffectiveness: 15,
@ -558,7 +558,7 @@ export const companyPositionMetadata: IConstructorParams[] = [
repMultiplier: 1, repMultiplier: 1,
}, },
{ {
name: posNames.BusinessConsultantCompanyPositions[0], // Senior Business Consultant name: posNames.BusinessConsultantCompanyPositions[1], // Senior Business Consultant
nextPosition: null, nextPosition: null,
baseSalary: 525, baseSalary: 525,
hackingEffectiveness: 15, hackingEffectiveness: 15,

@ -1,7 +1,7 @@
import {IMap} from "./types"; import {IMap} from "./types";
export let CONSTANTS: IMap<any> = { export let CONSTANTS: IMap<any> = {
Version: "0.41.0", Version: "0.41.2",
//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
@ -504,16 +504,13 @@ export let CONSTANTS: IMap<any> = {
LatestUpdate: LatestUpdate:
` `
v0.41.1 v0.41.2
* Stock Market changes: * IMPORTANT - Netscript Changes:
*** Stocks now have "maximum prices" ** rm() now takes an optional parameter that lets you specify on which server to delete the file
*** 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
* Gang Changes:
** UI now displays your chance to win a clash with other gangs
** Added getChanceToWinClash() function to the Gang API
` `
} }

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

@ -1521,9 +1521,10 @@ Gang.prototype.updateGangContent = function() {
// Update territory information // Update territory information
UIElems.gangTerritoryInfoText.innerHTML = ""; UIElems.gangTerritoryInfoText.innerHTML = "";
for (var gangname in AllGangs) { const playerPower = AllGangs[this.facName].power;
for (const gangname in AllGangs) {
if (AllGangs.hasOwnProperty(gangname)) { if (AllGangs.hasOwnProperty(gangname)) {
var gangTerritoryInfo = AllGangs[gangname]; const gangTerritoryInfo = AllGangs[gangname];
let territory = gangTerritoryInfo.territory * 100; let territory = gangTerritoryInfo.territory * 100;
//Fix some rounding issues graphically //Fix some rounding issues graphically
@ -1536,12 +1537,16 @@ Gang.prototype.updateGangContent = function() {
displayNumber = formatNumber(territory, 2); displayNumber = formatNumber(territory, 2);
} }
if (gangname == this.facName) { if (gangname === this.facName) {
UIElems.gangTerritoryInfoText.innerHTML += ("<b>" + gangname + "</b><br>(Power: " + formatNumber(gangTerritoryInfo.power, 6) + "): " + let newHTML = `<b><u>${gangname}</u></b><br>Power: ${formatNumber(gangTerritoryInfo.power, 6)}<br>`;
displayNumber + "%<br><br>"); newHTML += `Territory: ${displayNumber}%<br><br>`;
UIElems.gangTerritoryInfoText.innerHTML += newHTML;
} else { } else {
UIElems.gangTerritoryInfoText.innerHTML += (gangname + "<br>(Power: " + formatNumber(gangTerritoryInfo.power, 6) + "): " + const clashVictoryChance = playerPower / (gangTerritoryInfo.power + playerPower);
displayNumber + "%<br><br>"); let newHTML = `<u>${gangname}</u><br>Power: ${formatNumber(gangTerritoryInfo.power, 6)}<br>`;
newHTML += `Territory: ${displayNumber}%<br>`;
newHTML += `Chance to win clash with this gang: ${numeralWrapper.format(clashVictoryChance, "0.000%")}<br><br>`;
UIElems.gangTerritoryInfoText.innerHTML += newHTML;
} }
} }
} }

@ -1955,7 +1955,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 " +
@ -1985,7 +1984,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 {

@ -108,11 +108,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,
@ -547,8 +550,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){
@ -1698,6 +1723,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);
@ -1725,7 +1812,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;
@ -2053,14 +2140,18 @@ function NetscriptFunctions(workerScript) {
} }
return port; return port;
}, },
rm : function(fn) { rm : function(fn, ip) {
if (workerScript.checkingRam) { if (workerScript.checkingRam) {
return updateStaticRam("rm", CONSTANTS.ScriptReadWriteRamCost); return updateStaticRam("rm", CONSTANTS.ScriptReadWriteRamCost);
} }
updateDynamicRam("rm", CONSTANTS.ScriptReadWriteRamCost); updateDynamicRam("rm", CONSTANTS.ScriptReadWriteRamCost);
var s = getServer(workerScript.serverIp);
if (ip == null || ip === "") {
ip = workerScript.serverIp;
}
var s = getServer(ip);
if (s == null) { if (s == null) {
throw makeRuntimeRejectMsg(workerScript, "Error getting Server for this script in clear(). This is a bug please contact game dev"); throw makeRuntimeRejectMsg(workerScript, `Invalid server specified for rm(): ${ip}`);
} }
if (fn.includes(".exe")) { if (fn.includes(".exe")) {
@ -3784,7 +3875,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")) {
@ -3813,13 +3904,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));
@ -3848,6 +3939,27 @@ function NetscriptFunctions(workerScript) {
throw makeRuntimeRejectMsg(workerScript, nsGang.unknownGangApiExceptionMessage("setTerritoryWarfare", e)); throw makeRuntimeRejectMsg(workerScript, nsGang.unknownGangApiExceptionMessage("setTerritoryWarfare", e));
} }
}, },
getChanceToWinClash : function(otherGang) {
if (workerScript.checkingRam) {
return updateStaticRam("getChanceToWinClash", CONSTANTS.ScriptGangApiBaseRamCost);
}
updateDynamicRam("getChanceToWinClash", CONSTANTS.ScriptGangApiBaseRamCost);
nsGang.checkGangApiAccess(workerScript, "getChanceToWinClash");
try {
if (AllGangs[otherGang] == null) {
workerScript.log(`Invalid gang specified in gang.getChanceToWinClash() : ${otherGang}`);
return 0;
}
const playerPower = AllGangs[Player.gang.facName].power;
const otherPower = AllGangs[otherGang].power;
return playerPower / (otherPower + playerPower);
} catch(e) {
throw makeRuntimeRejectMsg(workerScript, nsGang.unknownGangApiExceptionMessage("getChanceToWinClash", e));
}
},
getBonusTime : function() { getBonusTime : function() {
if (workerScript.checkingRam) { return 0; } if (workerScript.checkingRam) { return 0; }
nsGang.checkGangApiAccess(workerScript, "getBonusTime"); nsGang.checkGangApiAccess(workerScript, "getBonusTime");

@ -8,6 +8,7 @@ import {Companies} from "./Company/Companies";
import {getNextCompanyPosition} from "./Company/GetNextCompanyPosition"; import {getNextCompanyPosition} from "./Company/GetNextCompanyPosition";
import {getJobRequirementText} from "./Company/GetJobRequirementText"; import {getJobRequirementText} from "./Company/GetJobRequirementText";
import {CompanyPositions} from "./Company/CompanyPositions"; import {CompanyPositions} from "./Company/CompanyPositions";
import * as posNames from "./Company/data/CompanyPositionNames";
import {CONSTANTS} from "./Constants"; import {CONSTANTS} from "./Constants";
import {Corporation} from "./CompanyManagement"; import {Corporation} from "./CompanyManagement";
import {Programs} from "./CreateProgram"; import {Programs} from "./CreateProgram";
@ -193,7 +194,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;
@ -1749,6 +1749,9 @@ PlayerObject.prototype.applyForJob = function(entryPosType, sing=false) {
this.companyName = company.name; this.companyName = company.name;
this.companyPosition = pos.name; this.companyPosition = pos.name;
document.getElementById("world-menu-header").click();
document.getElementById("world-menu-header").click();
if (leaveCompany) { if (leaveCompany) {
if (sing) { return true; } if (sing) { return true; }
dialogBoxCreate([`Congratulations! You were offered a new job at ${this.companyName} as a ${pos.name}!`, dialogBoxCreate([`Congratulations! You were offered a new job at ${this.companyName} as a ${pos.name}!`,
@ -1794,21 +1797,21 @@ PlayerObject.prototype.getNextCompanyPosition = function(company, entryPosType)
} }
PlayerObject.prototype.applyForSoftwareJob = function(sing=false) { PlayerObject.prototype.applyForSoftwareJob = function(sing=false) {
return this.applyForJob(CompanyPositions.SoftwareIntern, sing); return this.applyForJob(CompanyPositions[posNames.SoftwareCompanyPositions[0]], sing);
} }
PlayerObject.prototype.applyForSoftwareConsultantJob = function(sing=false) { PlayerObject.prototype.applyForSoftwareConsultantJob = function(sing=false) {
return this.applyForJob(CompanyPositions.SoftwareConsultant, sing); return this.applyForJob(CompanyPositions[posNames.SoftwareConsultantCompanyPositions[0]], sing);
} }
PlayerObject.prototype.applyForItJob = function(sing=false) { PlayerObject.prototype.applyForItJob = function(sing=false) {
return this.applyForJob(CompanyPositions.ITIntern, sing); return this.applyForJob(CompanyPositions[posNames.ITCompanyPositions[0]], sing);
} }
PlayerObject.prototype.applyForSecurityEngineerJob = function(sing=false) { PlayerObject.prototype.applyForSecurityEngineerJob = 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.SecurityEngineer)) { if (this.isQualified(company, CompanyPositions[posNames.SecurityEngineerCompanyPositions[0]])) {
return this.applyForJob(CompanyPositions.SecurityEngineer, sing); return this.applyForJob(CompanyPositions[posNames.SecurityEngineerCompanyPositions[0]], sing);
} else { } else {
if (sing) {return false;} if (sing) {return false;}
dialogBoxCreate("Unforunately, you do not qualify for this position"); dialogBoxCreate("Unforunately, you do not qualify for this position");
@ -1817,8 +1820,8 @@ PlayerObject.prototype.applyForSecurityEngineerJob = function(sing=false) {
PlayerObject.prototype.applyForNetworkEngineerJob = function(sing=false) { PlayerObject.prototype.applyForNetworkEngineerJob = 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.NetworkEngineer)) { if (this.isQualified(company, CompanyPositions[posNames.NetworkEngineerCompanyPositions[0]])) {
return this.applyForJob(CompanyPositions.NetworkEngineer, sing); return this.applyForJob(CompanyPositions[posNames.NetworkEngineerCompanyPositions[0]], sing);
} else { } else {
if (sing) {return false;} if (sing) {return false;}
dialogBoxCreate("Unforunately, you do not qualify for this position"); dialogBoxCreate("Unforunately, you do not qualify for this position");
@ -1826,22 +1829,23 @@ PlayerObject.prototype.applyForNetworkEngineerJob = function(sing=false) {
} }
PlayerObject.prototype.applyForBusinessJob = function(sing=false) { PlayerObject.prototype.applyForBusinessJob = function(sing=false) {
return this.applyForJob(CompanyPositions.BusinessIntern, sing); return this.applyForJob(CompanyPositions[posNames.BusinessCompanyPositions[0]], sing);
} }
PlayerObject.prototype.applyForBusinessConsultantJob = function(sing=false) { PlayerObject.prototype.applyForBusinessConsultantJob = function(sing=false) {
return this.applyForJob(CompanyPositions.BusinessConsultant, sing); return this.applyForJob(CompanyPositions[posNames.BusinessConsultantCompanyPositions[0]], sing);
} }
PlayerObject.prototype.applyForSecurityJob = function(sing=false) { PlayerObject.prototype.applyForSecurityJob = function(sing=false) {
//TODO If case for POlice departments // TODO Police Jobs
return this.applyForJob(CompanyPositions.SecurityGuard, sing); // Indexing starts at 2 because 0 is for police officer
return this.applyForJob(CompanyPositions[posNames.SecurityCompanyPositions[2]], sing);
} }
PlayerObject.prototype.applyForAgentJob = function(sing=false) { PlayerObject.prototype.applyForAgentJob = 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.FieldAgent)) { if (this.isQualified(company, CompanyPositions[posNames.AgentCompanyPositions[0]])) {
return this.applyForJob(CompanyPositions.FieldAgent, sing); return this.applyForJob(CompanyPositions[posNames.AgentCompanyPositions[0]], sing);
} else { } else {
if (sing) {return false;} if (sing) {return false;}
dialogBoxCreate("Unforunately, you do not qualify for this position"); dialogBoxCreate("Unforunately, you do not qualify for this position");
@ -1850,15 +1854,11 @@ 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[posNames.MiscCompanyPositions[1]])) {
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[posNames.MiscCompanyPositions[1]];
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();
@ -1870,15 +1870,11 @@ 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[posNames.PartTimeCompanyPositions[1]])) {
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[posNames.PartTimeCompanyPositions[1]];
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();
@ -1890,15 +1886,11 @@ 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[posNames.MiscCompanyPositions[0]])) {
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[posNames.MiscCompanyPositions[0]];
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();
@ -1910,15 +1902,11 @@ 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[posNames.PartTimeCompanyPositions[0]])) {
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[posNames.PartTimeCompanyPositions[0]];
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);
} }

@ -110,6 +110,31 @@ BitburnerSaveObject.prototype.saveGame = function(db) {
createStatusText("Game saved!"); createStatusText("Game saved!");
} }
// Makes necessary changes to the loaded/imported data to ensure
// the game stills works with new versions
function evaluateVersionCompatibility(ver) {
// This version refactored the Company/job-related code
if (ver <= "0.41.2") {
// Player's company position is now a string
if (Player.companyPosition != null && typeof Player.companyPosition !== "string") {
console.log("Changed Player.companyPosition value to be compatible with v0.41.2");
Player.companyPosition = Player.companyPosition.positionName;
if (Player.companyPosition == null) {
Player.companyPosition = "";
}
}
// The "companyName" property of all Companies is renamed to "name"
for (var companyName in Companies) {
const company = Companies[companyName];
if (company.name == null && company.companyName != null) {
console.log("Changed company name property to be compatible with v0.41.2");
company.name = company.companyName;
}
}
}
}
function loadGame(saveString) { function loadGame(saveString) {
if (saveString === "" || saveString == null || saveString === undefined) { if (saveString === "" || saveString == null || saveString === undefined) {
if (!window.localStorage.getItem("bitburnerSave")) { if (!window.localStorage.getItem("bitburnerSave")) {
@ -187,23 +212,8 @@ function loadGame(saveString) {
if (saveObj.hasOwnProperty("VersionSave")) { if (saveObj.hasOwnProperty("VersionSave")) {
try { try {
var ver = JSON.parse(saveObj.VersionSave, Reviver); var ver = JSON.parse(saveObj.VersionSave, Reviver);
// This version refactored the Company/job-related code evaluateVersionCompatibility(ver);
if (ver < "0.41.2") {
// Player's company position is now a string
if (Player.companyPosition !== "" || Player.companyPosition instanceof CompanyPosition) {
console.log("Changed Player.companyPosition value to be compatible with v0.41.2");
Player.companyPosition = Player.companyPosition.positionName;
}
// The "companyName" property of all Companies is renamed to "name"
for (var companyName in Companies) {
const company = Companies[companyName];
if (company.name == null && company.companyName != null) {
console.log("Changed company name property to be compatible with v0.41.2");
company.name = company.companyName;
}
}
}
if (window.location.href.toLowerCase().includes("bitburner-beta")) { if (window.location.href.toLowerCase().includes("bitburner-beta")) {
//Beta branch, always show changes //Beta branch, always show changes
createBetaUpdateText(); createBetaUpdateText();
@ -301,23 +311,7 @@ function loadImportedGame(saveObj, saveString) {
if (tempSaveObj.hasOwnProperty("VersionSave")) { if (tempSaveObj.hasOwnProperty("VersionSave")) {
try { try {
var ver = JSON.parse(tempSaveObj.VersionSave, Reviver); var ver = JSON.parse(tempSaveObj.VersionSave, Reviver);
// This version refactored the Company/job-related code evaluateVersionCompatibility(ver);
if (ver < "0.41.2") {
// Player's company position is now a string
if (Player.companyPosition !== "" || Player.companyPosition instanceof CompanyPosition) {
console.log("Changed Player.companyPosition value to be compatible with v0.41.2");
Player.companyPosition = Player.companyPosition.positionName;
}
// The "companyName" property of all Companies is renamed to "name"
for (var companyName in Companies) {
const company = Companies[companyName];
if (company.name == null && company.companyName != null) {
console.log("Changed company name property to be compatible with v0.41.2");
company.name = company.companyName;
}
}
}
} catch(e) { } catch(e) {
console.error("Parsing Version save failed: " + e); console.error("Parsing Version save failed: " + e);
} }
@ -400,23 +394,8 @@ function loadImportedGame(saveObj, saveString) {
if (saveObj.hasOwnProperty("VersionSave")) { if (saveObj.hasOwnProperty("VersionSave")) {
try { try {
var ver = JSON.parse(saveObj.VersionSave, Reviver); var ver = JSON.parse(saveObj.VersionSave, Reviver);
// This version refactored the Company/job-related code evaluateVersionCompatibility(ver);
if (ver < "0.41.2") {
// Player's company position is now a string
if (Player.companyPosition !== "" || Player.companyPosition instanceof CompanyPosition) {
console.log("Changed Player.companyPosition value to be compatible with v0.41.2");
Player.companyPosition = Player.companyPosition.positionName;
}
// The "companyName" property of all Companies is renamed to "name"
for (var companyName in Companies) {
const company = Companies[companyName];
if (company.name == null && company.companyName != null) {
console.log("Changed company name property to be compatible with v0.41.2");
company.name = company.companyName;
}
}
}
if (ver != CONSTANTS.Version) { if (ver != CONSTANTS.Version) {
createNewUpdateText(); createNewUpdateText();
} }

@ -466,7 +466,7 @@ async function parseOnlyRamCalculate(server, code, workerScript) {
const nextModule = parseQueue.shift(); const nextModule = parseQueue.shift();
let code; let code;
if (nextModule.startsWith("https://")) { if (nextModule.startsWith("https://") || nextModule.startsWith("http://")) {
try { try {
const module = await eval('import(nextModule)'); const module = await eval('import(nextModule)');
code = ""; code = "";

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

@ -547,7 +547,7 @@ function sellShort(stock, shares, workerScript=null) {
} }
function processStockPrices(numCycles=1) { function processStockPrices(numCycles=1) {
if (isNaN(StockMarket.storedCycles)) { StockMarket.storedCycles = 0; } if (StockMarket.storedCycles == null || isNaN(StockMarket.storedCycles)) { StockMarket.storedCycles = 0; }
StockMarket.storedCycles += numCycles; StockMarket.storedCycles += numCycles;
// Stock Prices updated every 6 seconds on average. But if there are stored // Stock Prices updated every 6 seconds on average. But if there are stored
@ -743,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();
@ -782,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();
@ -893,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);

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

@ -79,6 +79,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";
@ -173,6 +174,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,
@ -1187,6 +1189,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");
@ -1243,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);
@ -1275,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);}
@ -1323,6 +1333,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";
@ -1545,22 +1556,32 @@ const Engine = {
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 stockmarket = document.getElementById("stock-market-tab");
var stockmarketLink = document.getElementById("stock-market-menu-link");
var bladeburner = document.getElementById("bladeburner-tab"); var bladeburner = document.getElementById("bladeburner-tab");
var bladeburnerLink = document.getElementById("bladeburner-menu-link"); var bladeburnerLink = document.getElementById("bladeburner-menu-link");
var corporation = document.getElementById("corporation-tab"); var corporation = document.getElementById("corporation-tab");
var corporationLink = document.getElementById("corporation-menu-link"); var corporationLink = document.getElementById("corporation-menu-link");
var gang = document.getElementById("gang-tab"); var gang = document.getElementById("gang-tab");
var gangLink = document.getElementById("gang-menu-link"); 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]
); );
} }
} }
@ -1633,6 +1654,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>