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;
}
/* 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-link {
cursor: pointer;

7399
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;
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-link {
cursor: pointer;
@ -678,6 +588,97 @@ button {
opacity: 1;
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 */
/* Attributes */
#terminal-container {

754
dist/vendor.bundle.js vendored

File diff suppressed because one or more lines are too long

@ -3,6 +3,33 @@
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
--------------------
* WARNING: In NetscriptJS, defining a function called print() is no longer possible

@ -153,17 +153,37 @@ isLogEnabled
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
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
end of the array.
Note that there is a maximum number of lines that a script stores in its logs.
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
^^^^
@ -931,9 +951,10 @@ getPortHandle
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 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
:RAM cost: 1 GB
@ -991,7 +1012,7 @@ getScriptRam
.. js:function:: getScriptRam(scriptname[, hostname/ip])
: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
Returns the amount of RAM required to run the specified script on the target server. Returns

@ -100,7 +100,7 @@ getMemberInformation
agility: Agility stat
agilityEquipMult: Agility multiplier from equipment. 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
charismaEquipMult: Charisma multiplier from equipment. 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
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
------------

@ -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 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
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.
@ -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
getStockSymbols
-------------
---------------
.. js:function:: getStockSymbols()
@ -214,3 +214,23 @@ getStockForecast
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
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">
<button id="job-menu-link"> Job </button>
</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">
<button id="bladeburner-menu-link"> Bladeburner </button>
</li>
@ -787,8 +790,8 @@
</table>
</div>
<div class="character-quick-options">
<button id="character-overview-save-button">Save Game</button>
<button id="character-overview-options-button">Options</button>
<button id="character-overview-save-button" class="character-overview-btn">Save Game</button>
<button id="character-overview-options-button" class="character-overview-btn">Options</button>
</div>
</div>
</div>

@ -62,7 +62,7 @@ let NetscriptFunctions =
"hack|sleep|grow|weaken|print|tprint|scan|nuke|brutessh|ftpcrack|" + //Netscript functions
"clearLog|disableLog|enableLog|isLogEnabled|getScriptLogs|" +
"relaysmtp|httpworm|sqlinject|run|exec|spawn|kill|killall|exit|" +
"scp|ls|hasRootAccess|" +
"scp|ls|ps|hasRootAccess|" +
"getIp|getHackingMultipliers|getBitNodeMultipliers|getStats|isBusy|" +
"getHacknetMultipliers|" +
"getHostname|getHackingLevel|getServerMoneyAvailable|getServerMaxMoney|" +
@ -95,6 +95,7 @@ let NetscriptFunctions =
"getStockPrice|getStockPosition|getStockSymbols|buyStock|sellStock|" +
"shortStock|sellShort|" +
"placeOrder|cancelOrder|getStockVolatility|getStockForecast|" +
"purchase4SMarketData|purchase4SMarketDataTixApi|" +
// Hacknet Node API
"hacknet|numNodes|purchaseNode|getPurchaseNodeCost|getNodeStats|" +
@ -106,7 +107,7 @@ let NetscriptFunctions =
"getMemberNames|getGangInformation|getMemberInformation|canRecruitMember|" +
"recruitMember|getTaskNames|setMemberTask|getEquipmentNames|" +
"getEquipmentCost|purchaseEquipment|ascendMember|setTerritoryWarfare|" +
"getBonusTime|" +
"getChanceToWinClash|getBonusTime|" +
// Bladeburner API
"bladeburner|getContractNames|getOperationNames|getBlackOpNames|" +

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

@ -74,7 +74,6 @@ var ContractBaseMoneyGain = 50e3; //Base Money Gained per contract
var ActiveActionCssClass = "bladeburner-active-action";
//Console related stuff
var consoleHistory = []; //Console command history
var consoleHistoryIndex = 0;
var consoleHelpText = {
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;}
let consoleHistory = Player.bladeburner.consoleHistory;
//NOTE: Keycodes imported from Terminal.js
if (event.keyCode === KEY.ENTER) {
@ -712,6 +712,10 @@ function Bladeburner(params={}) {
this.automateActionLow = 0;
this.automateThreshLow = 0; //Stamina Threshold
//Console command history
this.consoleHistory = [];
this.consoleLogs = [];
//Initialization
initBladeburner();
this.initializeDomElementRefs();
@ -864,6 +868,12 @@ Bladeburner.prototype.process = function() {
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)
if (this.storedCycles >= CyclesPerSecond) {
var seconds = Math.floor(this.storedCycles / CyclesPerSecond);
@ -1345,7 +1355,6 @@ Bladeburner.prototype.completeAction = function() {
Player.gainIntelligenceExp(BaseIntGain);
Player.gainCharismaExp(charismaExpGain);
this.changeRank(0.1 * BitNodeMultipliers.BladeburnerRank);
console.log("DEBUG: Field Analysis effectiveness is " + (eff * this.skillMultipliers.successChanceEstimate));
this.getCurrentCity().improvePopulationEstimateByPercentage(eff * this.skillMultipliers.successChanceEstimate);
if (this.logging.general) {
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);
this.postToConsole("Bladeburner Console BETA");
this.postToConsole("Type 'help' to see console commands");
if (this.consoleLogs.length === 0) {
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();
}
@ -2732,12 +2748,22 @@ Bladeburner.prototype.updateSkillsUIElement = function(el, skill) {
}
//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;}
$("#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);
}
this.updateConsoleScroll();
}
@ -2753,6 +2779,8 @@ Bladeburner.prototype.clearConsole = function() {
while (DomElems.consoleTable.childNodes.length > 1) {
DomElems.consoleTable.removeChild(DomElems.consoleTable.firstChild);
}
this.consoleLogs.length = 0;
}
Bladeburner.prototype.log = function(input) {
@ -2764,13 +2792,13 @@ Bladeburner.prototype.log = function(input) {
Bladeburner.prototype.executeConsoleCommands = function(commands) {
try {
//Console History
if (consoleHistory[consoleHistory.length-1] != commands) {
consoleHistory.push(commands);
if (consoleHistory.length > 50) {
consoleHistory.splice(0, 1);
if (this.consoleHistory[this.consoleHistory.length-1] != commands) {
this.consoleHistory.push(commands);
if (this.consoleHistory.length > 50) {
this.consoleHistory.splice(0, 1);
}
}
consoleHistoryIndex = consoleHistory.length;
consoleHistoryIndex = this.consoleHistory.length;
var arrayOfCommands = commands.split(";");
for (var i = 0; i < arrayOfCommands.length; ++i) {
@ -3469,7 +3497,7 @@ Bladeburner.prototype.getActionCountRemainingNetscriptFn = function(type, name,
switch (actionId.type) {
case ActionTypes["Contract"]:
case ActionTypes["Operation"]:
return actionObj.count;
return Math.floor( actionObj.count );
case ActionTypes["BlackOp"]:
case ActionTypes["BlackOperation"]:
if (this.blackops[name] != null) {

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

@ -1,7 +1,7 @@
import {IMap} from "./types";
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
//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:
`
v0.41.1
* Stock Market changes:
*** Stocks now have "maximum prices"
*** 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
v0.41.2
* IMPORTANT - Netscript Changes:
** rm() now takes an optional parameter that lets you specify on which server to delete the file
* 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 {AllServers} from "./Server";
import {hackWorldDaemon} from "./RedPill";
import {StockMarket,
SymbolToStockMap} from "./StockMarket";
import {Stock} from "./Stock";
import {Terminal} from "./Terminal";
import {numeralWrapper} from "./ui/numeralFormat";
import {dialogBoxCreate} from "../utils/DialogBox";
import {exceptionAlert} from "../utils/helpers/exceptionAlert";
import {createElement} from "../utils/uiHelpers/createElement";
import {removeElementById} from "../utils/uiHelpers/removeElementById";
@ -322,6 +327,7 @@ export function createDevMenu() {
const bladeburnerGainRankInput = createElement("input", {
class: "text-input",
margin: "5px",
placeholder: "Rank to gain (or negative to lose rank)",
type: "number",
});
@ -344,6 +350,7 @@ export function createDevMenu() {
const gangStoredCyclesInput = createElement("input", {
class: "text-input",
margin: "5px",
placeholder: "# Cycles to add",
type: "number",
});
@ -372,6 +379,73 @@ export function createDevMenu() {
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
const devMenuContainer = createElement("div", {
class: "generic-menupage-container",
@ -433,6 +507,12 @@ export function createDevMenu() {
devMenuContainer.appendChild(createElement("br"));
devMenuContainer.appendChild(contractsHeader);
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");
if (entireGameContainer == null) {

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

@ -1521,9 +1521,10 @@ Gang.prototype.updateGangContent = function() {
// Update territory information
UIElems.gangTerritoryInfoText.innerHTML = "";
for (var gangname in AllGangs) {
const playerPower = AllGangs[this.facName].power;
for (const gangname in AllGangs) {
if (AllGangs.hasOwnProperty(gangname)) {
var gangTerritoryInfo = AllGangs[gangname];
const gangTerritoryInfo = AllGangs[gangname];
let territory = gangTerritoryInfo.territory * 100;
//Fix some rounding issues graphically
@ -1536,12 +1537,16 @@ Gang.prototype.updateGangContent = function() {
displayNumber = formatNumber(territory, 2);
}
if (gangname == this.facName) {
UIElems.gangTerritoryInfoText.innerHTML += ("<b>" + gangname + "</b><br>(Power: " + formatNumber(gangTerritoryInfo.power, 6) + "): " +
displayNumber + "%<br><br>");
if (gangname === this.facName) {
let newHTML = `<b><u>${gangname}</u></b><br>Power: ${formatNumber(gangTerritoryInfo.power, 6)}<br>`;
newHTML += `Territory: ${displayNumber}%<br><br>`;
UIElems.gangTerritoryInfoText.innerHTML += newHTML;
} else {
UIElems.gangTerritoryInfoText.innerHTML += (gangname + "<br>(Power: " + formatNumber(gangTerritoryInfo.power, 6) + "): " +
displayNumber + "%<br><br>");
const clashVictoryChance = playerPower / (gangTerritoryInfo.power + playerPower);
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,
});
displayLocationContent();
document.getElementById("corporation-tab").style.display = "list-item";
document.getElementById("world-menu-header").click();
document.getElementById("world-menu-header").click();
dialogBoxCreate("Congratulations! You just started your own corporation. You can visit " +
@ -1985,7 +1984,6 @@ function initLocationButtons() {
Player.bladeburner = new Bladeburner({new:true});
dialogBoxCreate("You have been accepted into the Bladeburner division!");
displayLocationContent();
document.getElementById("bladeburner-tab").style.display = "list-item";
document.getElementById("world-menu-header").click();
document.getElementById("world-menu-header").click();
} else {

@ -108,11 +108,14 @@ var possibleLogs = {
getServerGrowth: true,
getServerNumPortsRequired: true,
getServerRam: true,
// TIX API
buyStock: true,
sellStock: true,
shortStock: true,
sellShort: true,
purchase4SMarketData: true,
purchase4SMarketDataTixApi: true,
// Singularity Functions
purchaseServer: true,
@ -547,8 +550,30 @@ function NetscriptFunctions(workerScript) {
}
return workerScript.disableLogs[fn] ? false : true;
},
getScriptLogs : function() {
getScriptLogs : function(fn, ip) {
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();
},
nuke : function(ip){
@ -802,7 +827,7 @@ function NetscriptFunctions(workerScript) {
}
NetscriptFunctions(workerScript).exit();
},
kill : function(filename,ip) {
kill : function(filename, ip) {
if (workerScript.checkingRam) {
return updateStaticRam("kill", CONSTANTS.ScriptKillRamCost);
}
@ -1698,6 +1723,68 @@ function NetscriptFunctions(workerScript) {
stock.b ? forecast += stock.otlkMag : forecast -= stock.otlkMag;
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() {
if (workerScript.checkingRam) {
return updateStaticRam("getPurchasedServerLimit", CONSTANTS.ScriptGetPurchasedServerLimit);
@ -1725,7 +1812,7 @@ function NetscriptFunctions(workerScript) {
cost = getPurchaseServerRamCostGuard(ram);
} catch (e) {
workerScript.scriptRef.log("ERROR: 'getPurchasedServerCost()' " + e.message);
return "";
return Infinity;
}
return cost;
@ -2053,14 +2140,18 @@ function NetscriptFunctions(workerScript) {
}
return port;
},
rm : function(fn) {
rm : function(fn, ip) {
if (workerScript.checkingRam) {
return updateStaticRam("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) {
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")) {
@ -3784,7 +3875,7 @@ function NetscriptFunctions(workerScript) {
nsGang.checkGangApiAccess(workerScript, "purchaseEquipment");
try {
for (const member in Player.gang.members) {
for (const member of Player.gang.members) {
if (member.name === memberName) {
const res = member.buyUpgrade(equipName, Player, Player.gang);
if (workerScript.shouldLog("purchaseEquipment")) {
@ -3813,13 +3904,13 @@ function NetscriptFunctions(workerScript) {
nsGang.checkGangApiAccess(workerScript, "ascendMember");
try {
for (const member in Player.gang.members) {
for (const member of Player.gang.members) {
if (member.name === name) {
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;
} catch(e) {
throw makeRuntimeRejectMsg(workerScript, nsGang.unknownGangApiExceptionMessage("ascendMember", e));
@ -3848,6 +3939,27 @@ function NetscriptFunctions(workerScript) {
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() {
if (workerScript.checkingRam) { return 0; }
nsGang.checkGangApiAccess(workerScript, "getBonusTime");

@ -8,6 +8,7 @@ import {Companies} from "./Company/Companies";
import {getNextCompanyPosition} from "./Company/GetNextCompanyPosition";
import {getJobRequirementText} from "./Company/GetJobRequirementText";
import {CompanyPositions} from "./Company/CompanyPositions";
import * as posNames from "./Company/data/CompanyPositionNames";
import {CONSTANTS} from "./Constants";
import {Corporation} from "./CompanyManagement";
import {Programs} from "./CreateProgram";
@ -193,7 +194,6 @@ function PlayerObject() {
//Flags for determining whether certain "thresholds" have been achieved
this.firstFacInvRecvd = false;
this.firstAugPurchased = false;
this.firstJobRecvd = false;
this.firstTimeTraveled = false;
this.firstProgramAvailable = false;
@ -1749,6 +1749,9 @@ PlayerObject.prototype.applyForJob = function(entryPosType, sing=false) {
this.companyName = company.name;
this.companyPosition = pos.name;
document.getElementById("world-menu-header").click();
document.getElementById("world-menu-header").click();
if (leaveCompany) {
if (sing) { return true; }
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) {
return this.applyForJob(CompanyPositions.SoftwareIntern, sing);
return this.applyForJob(CompanyPositions[posNames.SoftwareCompanyPositions[0]], sing);
}
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) {
return this.applyForJob(CompanyPositions.ITIntern, sing);
return this.applyForJob(CompanyPositions[posNames.ITCompanyPositions[0]], sing);
}
PlayerObject.prototype.applyForSecurityEngineerJob = function(sing=false) {
var company = Companies[this.location]; //Company being applied to
if (this.isQualified(company, CompanyPositions.SecurityEngineer)) {
return this.applyForJob(CompanyPositions.SecurityEngineer, sing);
if (this.isQualified(company, CompanyPositions[posNames.SecurityEngineerCompanyPositions[0]])) {
return this.applyForJob(CompanyPositions[posNames.SecurityEngineerCompanyPositions[0]], sing);
} else {
if (sing) {return false;}
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) {
var company = Companies[this.location]; //Company being applied to
if (this.isQualified(company, CompanyPositions.NetworkEngineer)) {
return this.applyForJob(CompanyPositions.NetworkEngineer, sing);
if (this.isQualified(company, CompanyPositions[posNames.NetworkEngineerCompanyPositions[0]])) {
return this.applyForJob(CompanyPositions[posNames.NetworkEngineerCompanyPositions[0]], sing);
} else {
if (sing) {return false;}
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) {
return this.applyForJob(CompanyPositions.BusinessIntern, sing);
return this.applyForJob(CompanyPositions[posNames.BusinessCompanyPositions[0]], sing);
}
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) {
//TODO If case for POlice departments
return this.applyForJob(CompanyPositions.SecurityGuard, sing);
// TODO Police Jobs
// Indexing starts at 2 because 0 is for police officer
return this.applyForJob(CompanyPositions[posNames.SecurityCompanyPositions[2]], sing);
}
PlayerObject.prototype.applyForAgentJob = function(sing=false) {
var company = Companies[this.location]; //Company being applied to
if (this.isQualified(company, CompanyPositions.FieldAgent)) {
return this.applyForJob(CompanyPositions.FieldAgent, sing);
if (this.isQualified(company, CompanyPositions[posNames.AgentCompanyPositions[0]])) {
return this.applyForJob(CompanyPositions[posNames.AgentCompanyPositions[0]], sing);
} else {
if (sing) {return false;}
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) {
var company = Companies[this.location]; //Company being applied to
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();
}
if (this.isQualified(company, CompanyPositions[posNames.MiscCompanyPositions[1]])) {
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;}
dialogBoxCreate("Congratulations, you are now employed at " + this.companyName);
Engine.loadLocationContent();
@ -1870,15 +1870,11 @@ PlayerObject.prototype.applyForEmployeeJob = function(sing=false) {
PlayerObject.prototype.applyForPartTimeEmployeeJob = function(sing=false) {
var company = Companies[this.location]; //Company being applied to
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();
}
if (this.isQualified(company, CompanyPositions[posNames.PartTimeCompanyPositions[1]])) {
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;}
dialogBoxCreate("Congratulations, you are now employed part-time at " + this.companyName);
Engine.loadLocationContent();
@ -1890,15 +1886,11 @@ PlayerObject.prototype.applyForPartTimeEmployeeJob = function(sing=false) {
PlayerObject.prototype.applyForWaiterJob = function(sing=false) {
var company = Companies[this.location]; //Company being applied to
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();
}
if (this.isQualified(company, CompanyPositions[posNames.MiscCompanyPositions[0]])) {
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;}
dialogBoxCreate("Congratulations, you are now employed as a waiter at " + this.companyName);
Engine.loadLocationContent();
@ -1910,15 +1902,11 @@ PlayerObject.prototype.applyForWaiterJob = function(sing=false) {
PlayerObject.prototype.applyForPartTimeWaiterJob = function(sing=false) {
var company = Companies[this.location]; //Company being applied to
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();
}
if (this.isQualified(company, CompanyPositions[posNames.PartTimeCompanyPositions[0]])) {
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;}
dialogBoxCreate("Congratulations, you are now employed as a part-time waiter at " + this.companyName);
Engine.loadLocationContent();

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

@ -110,6 +110,31 @@ BitburnerSaveObject.prototype.saveGame = function(db) {
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) {
if (saveString === "" || saveString == null || saveString === undefined) {
if (!window.localStorage.getItem("bitburnerSave")) {
@ -187,23 +212,8 @@ function loadGame(saveString) {
if (saveObj.hasOwnProperty("VersionSave")) {
try {
var ver = JSON.parse(saveObj.VersionSave, Reviver);
// This version refactored the Company/job-related code
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;
}
evaluateVersionCompatibility(ver);
// 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")) {
//Beta branch, always show changes
createBetaUpdateText();
@ -301,23 +311,7 @@ function loadImportedGame(saveObj, saveString) {
if (tempSaveObj.hasOwnProperty("VersionSave")) {
try {
var ver = JSON.parse(tempSaveObj.VersionSave, Reviver);
// This version refactored the Company/job-related code
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;
}
}
}
evaluateVersionCompatibility(ver);
} catch(e) {
console.error("Parsing Version save failed: " + e);
}
@ -400,23 +394,8 @@ function loadImportedGame(saveObj, saveString) {
if (saveObj.hasOwnProperty("VersionSave")) {
try {
var ver = JSON.parse(saveObj.VersionSave, Reviver);
// This version refactored the Company/job-related code
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;
}
evaluateVersionCompatibility(ver);
// 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) {
createNewUpdateText();
}

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

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

@ -547,7 +547,7 @@ function sellShort(stock, shares, workerScript=null) {
}
function processStockPrices(numCycles=1) {
if (isNaN(StockMarket.storedCycles)) { StockMarket.storedCycles = 0; }
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
@ -572,10 +572,10 @@ function processStockPrices(numCycles=1) {
var chc = 50;
if (stock.b) {
chc = (chc + stock.otlkMag)/100;
chc = (chc + stock.otlkMag) / 100;
if (isNaN(chc)) {chc = 0.5;}
} else {
chc = (chc - stock.otlkMag)/100;
chc = (chc - stock.otlkMag) / 100;
if (isNaN(chc)) {chc = 0.5;}
}
if (stock.price >= stock.cap) {
@ -743,6 +743,7 @@ function displayStockMarketContent() {
"Buy 4S Market Data Access - " + numeralWrapper.format(CONSTANTS.MarketData4SCost, '($0.000a)'),
"4S Market Data - Purchased");
marketDataButton.addEventListener("click", function() {
if (Player.money.lt(CONSTANTS.MarketData4SCost)) { return false; }
Player.has4SData = true;
Player.loseMoney(CONSTANTS.MarketData4SCost);
displayStockMarketContent();
@ -782,6 +783,7 @@ function displayStockMarketContent() {
"4S Market Data TIX API - Purchased");
if (Player.hasTixApiAccess) {
marketDataTixButton.addEventListener("click", function() {
if (Player.money.lt(CONSTANTS.MarketDataTixApi4SCost)) { return false; }
Player.has4SDataTixApi = true;
Player.loseMoney(CONSTANTS.MarketDataTixApi4SCost);
displayStockMarketContent();
@ -893,6 +895,7 @@ function displayStockMarketContent() {
//Switch to Portfolio Mode Button
if (modeBtn) {
stockMarketPortfolioMode = false;
modeBtn.innerHTML = "Switch to 'Portfolio' Mode" +
"<span class='tooltiptext'>Displays only the stocks for which you have shares or orders</span>";
modeBtn.addEventListener("click", switchToPortfolioMode);

@ -105,7 +105,7 @@ export const codingContractTypesMetadata: ICodingContractTypeMetadata[] = [
" 2 + 2\n",
" 2 + 1 + 1\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(" ");
},
difficulty: 1.5,
@ -387,8 +387,8 @@ export const codingContractTypesMetadata: ICodingContractTypeMetadata[] = [
},
{
desc: (data: number[]) => {
return ["You are given the following array of stock prices where the i-th element",
"represents the stock price on day i:\n\n",
return ["You are given the following array of stock prices (which are numbers)",
"where the i-th element represents the stock price on day i:\n\n",
`${data}\n\n`,
"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",
@ -421,8 +421,8 @@ export const codingContractTypesMetadata: ICodingContractTypeMetadata[] = [
},
{
desc: (data: number[]) => {
return ["You are given the following array of stock prices where the i-th element",
"represents the stock price on day i:\n\n",
return ["You are given the following array of stock prices (which are numbers)",
"where the i-th element represents the stock price on day i:\n\n",
`${data}\n\n`,
"Determine the maximum possible profit you can earn using as many",
"transactions as you'd like. A transaction is defined as buying",
@ -455,8 +455,8 @@ export const codingContractTypesMetadata: ICodingContractTypeMetadata[] = [
},
{
desc: (data: number[]) => {
return ["You are given the following array of stock prices where the i-th element",
"represents the stock price on day i:\n\n",
return ["You are given the following array of stock prices (which are numbers)",
"where the i-th element represents the stock price on day i:\n\n",
`${data}\n\n`,
"Determine the maximum possible profit you can earn using at most",
"two transactions. A transaction is defined as buying",

@ -79,6 +79,7 @@ import 'normalize.css';
import "../css/styles.scss";
import "../css/buttons.scss";
import "../css/mainmenu.scss";
import "../css/characteroverview.scss";
import "../css/terminal.scss";
import "../css/menupages.scss";
import "../css/workinprogress.scss";
@ -173,6 +174,7 @@ const Engine = {
worldMainMenuButton: null,
travelMainMenuButton: null,
jobMainMenuButton: null,
stockmarketMainMenuButton: null,
createProgramMainMenuButton: null,
factionsMainMenuButton: null,
augmentationsMainMenuButton: null,
@ -1187,6 +1189,7 @@ const Engine = {
var city = document.getElementById("city-tab");
var travel = document.getElementById("travel-tab");
var job = document.getElementById("job-tab");
var stockmarket = document.getElementById("stock-market-tab");
var bladeburner = document.getElementById("bladeburner-tab");
var corp = document.getElementById("corporation-tab");
var gang = document.getElementById("gang-tab");
@ -1243,6 +1246,11 @@ const Engine = {
//Passive faction rep gain offline
processPassiveFactionRepGain(numCyclesOffline);
// Stock Market offline progress
if (Player.hasWseAccount) {
processStockPrices(numCyclesOffline);
}
//Gang progress for BitNode 2
if (Player.bitNodeN != null && Player.bitNodeN === 2 && Player.inGang()) {
Player.gang.process(numCyclesOffline, Player);
@ -1275,12 +1283,14 @@ const Engine = {
else {factions.style.display = "none";}
if (Player.firstAugPurchased) {visibleMenuTabs.push(augmentations);}
else {augmentations.style.display = "none";}
if (Player.firstJobRecvd) {visibleMenuTabs.push(job);}
if (Player.companyPosition !== "") {visibleMenuTabs.push(job);}
else {job.style.display = "none";}
if (Player.firstTimeTraveled) {visibleMenuTabs.push(travel);}
else {travel.style.display = "none";}
if (Player.firstProgramAvailable) {visibleMenuTabs.push(createProgram);}
else {createProgram.style.display = "none";}
if (Player.hasWseAccount) {visibleMenuTabs.push(stockmarket);}
else {stockmarket.style.display = "none";}
if(Player.bladeburner instanceof Bladeburner) {visibleMenuTabs.push(bladeburner);}
else {bladeburner.style.display = "none";}
if(Player.corporation instanceof Corporation) {visibleMenuTabs.push(corp);}
@ -1323,6 +1333,7 @@ const Engine = {
factions.style.display = "none";
augmentations.style.display = "none";
job.style.display = "none";
stockmarket.style.display = "none";
travel.style.display = "none";
createProgram.style.display = "none";
bladeburner.style.display = "none";
@ -1539,28 +1550,38 @@ const Engine = {
}
worldHdr.onclick = function() {
var city = document.getElementById("city-tab");
var cityLink = document.getElementById("city-menu-link");
var travel = document.getElementById("travel-tab");
var travelLink = document.getElementById("travel-menu-link");
var job = document.getElementById("job-tab");
var jobLink = document.getElementById("job-menu-link");
var bladeburner = document.getElementById("bladeburner-tab");
var bladeburnerLink = document.getElementById("bladeburner-menu-link");
var corporation = document.getElementById("corporation-tab");
var corporationLink = document.getElementById("corporation-menu-link");
var gang = document.getElementById("gang-tab");
var gangLink = document.getElementById("gang-menu-link");
var city = document.getElementById("city-tab");
var cityLink = document.getElementById("city-menu-link");
var travel = document.getElementById("travel-tab");
var travelLink = document.getElementById("travel-menu-link");
var job = document.getElementById("job-tab");
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 bladeburnerLink = document.getElementById("bladeburner-menu-link");
var corporation = document.getElementById("corporation-tab");
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");
if (city.style.maxHeight) {
Engine.toggleMainMenuHeader(false,
[city, travel, job, bladeburner, corporation, gang],
[cityLink, travelLink, jobLink, bladeburnerLink, corporationLink, gangLink]
[city, travel, job, stockmarket, bladeburner, corporation, gang],
[cityLink, travelLink, jobLink, stockmarketLink, bladeburnerLink, corporationLink, gangLink]
);
} else {
Engine.toggleMainMenuHeader(true,
[city, travel, job, bladeburner, corporation, gang],
[cityLink, travelLink, jobLink, bladeburnerLink, corporationLink, gangLink]
[city, travel, job, stockmarket, bladeburner, corporation, gang],
[cityLink, travelLink, jobLink, stockmarketLink, bladeburnerLink, corporationLink, gangLink]
);
}
}
@ -1633,6 +1654,12 @@ const Engine = {
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.addEventListener("click", function() {

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