Testing/bug fixes in v0.41.1. Updated Dev Menu features. Fixed 'Portfolio Mode' button on Stock market bugs

This commit is contained in:
danielyxie 2018-11-04 16:39:30 -06:00
parent 5b06a0b800
commit e2b7418780
8 changed files with 147 additions and 15 deletions

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

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

@ -714,6 +714,7 @@ function Bladeburner(params={}) {
//Console command history
this.consoleHistory = [];
this.consoleLogs = [];
//Initialization
initBladeburner();
@ -867,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);
@ -1348,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");
@ -1741,11 +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");
for (let i = 0; i < this.consoleHistory.length; ++i) {
this.postToConsole(this.consoleHistory[i]);
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();
}
@ -2738,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();
}
@ -2759,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) {

@ -505,6 +505,7 @@ let CONSTANTS = {
v0.41.1
* 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
* Stock Market changes:
@ -518,9 +519,11 @@ let CONSTANTS = {
* 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
* 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: After installing Augs, the "Portfolio Mode" button on the Stock Market page should be properly reset
`
}

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

@ -1715,7 +1715,7 @@ function NetscriptFunctions(workerScript) {
throw makeRuntimeRejectMsg(workerScript, "You don't have TIX API Access! Cannot use purchase4SMarketData()");
}
if (Player.Player.has4SData) {
if (Player.has4SData) {
if (workerScript.shouldLog("purchase4SMarketData")) {
workerScript.log("Already purchased 4S Market Data");
}
@ -1794,7 +1794,7 @@ function NetscriptFunctions(workerScript) {
cost = getPurchaseServerRamCostGuard(ram);
} catch (e) {
workerScript.scriptRef.log("ERROR: 'getPurchasedServerCost()' " + e.message);
return "";
return Infinity;
}
return cost;

@ -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) {
@ -895,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);

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