mirror of
https://github.com/bitburner-official/bitburner-src.git
synced 2024-12-18 12:15:44 +01:00
Stock transactions can now influence forecast in addition to price. Several more minor bug/UI fixes
This commit is contained in:
parent
8726946d4a
commit
585e1ac7aa
@ -73,6 +73,14 @@ be sold at $98.01, and so on.
|
||||
This is an important concept to keep in mind if you are trying to purchase/sell a
|
||||
large number of shares, as **it can negatively affect your profits**.
|
||||
|
||||
Transactions Influencing Stock Forecast
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
In addition to influencing stock price, buying or selling a large number of shares
|
||||
of a stock will also influence that stock's "forecast". The forecast is the likelihood
|
||||
that the stock will increase or decrease in price. The magnitude of this effect depends
|
||||
on the number of shares being transacted. More shares will have a bigger effect on the
|
||||
stock forecast.
|
||||
|
||||
.. _gameplay_stock_market_order_types:
|
||||
|
||||
Order Types
|
||||
|
@ -27,6 +27,7 @@ secrets that you've been searching for.
|
||||
Script Editors <scripteditors>
|
||||
Game Frozen or Stuck? <gamefrozen>
|
||||
Guides & Tips <guidesandtips>
|
||||
Tools & Resources <toolsandresources>
|
||||
Changelog <changelog>
|
||||
Donate <https://paypal.me/danielyxie>
|
||||
|
||||
|
23
doc/source/toolsandresources.rst
Normal file
23
doc/source/toolsandresources.rst
Normal file
@ -0,0 +1,23 @@
|
||||
Tools & Resources
|
||||
=================
|
||||
|
||||
Official Script Repository
|
||||
--------------------------
|
||||
There are plans to create an official repository of Bitburner scripts. As of right now,
|
||||
this is not a priority and has not been started. However, if you'd like
|
||||
to contribute scripts now, you can find the repository
|
||||
`here <https://github.com/bitburner-official/bitburner-scripts>`_ and submit pull requests.
|
||||
|
||||
Visual Studio Code Extension
|
||||
----------------------------
|
||||
One user created a Bitburner extension for the Visual Studio Code (VSCode) editor.
|
||||
|
||||
This extension includes several features such as:
|
||||
|
||||
* Dynamic RAM calculation
|
||||
* RAM Usage breakdown
|
||||
* Typescript definition files with jsdoc comments
|
||||
* Netscript syntax highlighting
|
||||
|
||||
You can find more information and download links
|
||||
`on this reddit post <https://www.reddit.com/r/Bitburner/comments/bh48y2/visual_studio_code_ram_calculator_extra/>`_.
|
@ -2105,17 +2105,6 @@ function augmentationExists(name) {
|
||||
return Augmentations.hasOwnProperty(name);
|
||||
}
|
||||
|
||||
//Used for testing balance
|
||||
function giveAllAugmentations() {
|
||||
for (var name in Augmentations) {
|
||||
var aug = Augmentations[name];
|
||||
if (aug == null) {continue;}
|
||||
var ownedAug = new PlayerOwnedAugmentation(name);
|
||||
Player.augmentations.push(ownedAug);
|
||||
}
|
||||
Player.reapplyAllAugmentations();
|
||||
}
|
||||
|
||||
function displayAugmentationsContent(contentEl) {
|
||||
removeChildrenFromElement(contentEl);
|
||||
contentEl.appendChild(createElement("h1", {
|
||||
|
@ -205,6 +205,7 @@ export class CodingContract {
|
||||
}
|
||||
},
|
||||
placeholder: "Enter Solution here",
|
||||
width: "50%",
|
||||
}) as HTMLInputElement;
|
||||
solveBtn = createElement("a", {
|
||||
class: "a-link-button",
|
||||
|
@ -278,7 +278,7 @@ export let CONSTANTS: IMap<any> = {
|
||||
v0.47.0
|
||||
* Stock Market changes:
|
||||
** Implemented spread. Stock's now have bid and ask prices at which transactions occur
|
||||
** Large transactions will now influence a stock's price.
|
||||
** Large transactions will now influence a stock's price and forecast
|
||||
** This "influencing" can take effect in the middle of a transaction
|
||||
** See documentation for more details on these changes
|
||||
** Added getStockAskPrice(), getStockBidPrice() Netscript functions to the TIX API
|
||||
@ -286,12 +286,16 @@ export let CONSTANTS: IMap<any> = {
|
||||
|
||||
* Re-sleeves can no longer have the NeuroFlux Governor augmentation
|
||||
** This is just a temporary patch until the mechanic gets re-worked
|
||||
|
||||
|
||||
* Corporation employees no longer have an "age" stat
|
||||
* Bug Fix: Corporation employees stats should no longer become negative
|
||||
* Bug Fix: Fixed sleeve.getInformation() throwing error in certain scenarios
|
||||
* Bug Fix: Coding contracts should no longer generate on the w0r1d_d43m0n server
|
||||
* Bug Fix: Duplicate Sleeves now properly have access to all Augmentations if you have a gang
|
||||
* Bug Fix: getAugmentationsFromFaction() & purchaseAugmentation() functions should now work properly if you have a gang
|
||||
* Bug Fix: Fixed issue that caused messages (.msg) to be sent when refreshing/reloading the game
|
||||
* Bug Fix: Purchasing hash upgrades for Bladeburner/Corporation when you don't actually have access to those mechanics no longer gives hashes
|
||||
* Bug Fix: run(), exec(), and spawn() Netscript functions now throw if called with 0 threads
|
||||
* Bug Fix: Faction UI should now automatically update reputation
|
||||
`
|
||||
}
|
||||
|
@ -30,10 +30,24 @@ const infoStyleMarkup = {
|
||||
}
|
||||
|
||||
export class Info extends React.Component<IProps, any> {
|
||||
render() {
|
||||
constructor(props: IProps) {
|
||||
super(props);
|
||||
|
||||
const formattedRep = numeralWrapper.format(this.props.faction.playerReputation, "0.000a");
|
||||
this.getFavorGainText = this.getFavorGainText.bind(this);
|
||||
this.getReputationText = this.getReputationText.bind(this);
|
||||
}
|
||||
|
||||
getFavorGainText(): string {
|
||||
const favorGain = this.props.faction.getFavorGain()[0];
|
||||
return `You will earn ${numeralWrapper.format(favorGain, "0,0")} faction favor upon resetting after installing an Augmentation`
|
||||
}
|
||||
|
||||
getReputationText(): string {
|
||||
const formattedRep = numeralWrapper.format(this.props.faction.playerReputation, "0.000a");
|
||||
return `Reputation: ${formattedRep}`
|
||||
}
|
||||
|
||||
render() {
|
||||
const favorTooltip = "Faction favor increases the rate at which you earn reputation for " +
|
||||
"this faction by 1% per favor. Faction favor is gained whenever you " +
|
||||
"reset after installing an Augmentation. The amount of " +
|
||||
@ -51,8 +65,8 @@ export class Info extends React.Component<IProps, any> {
|
||||
<p style={blockStyleMarkup}>-------------------------</p>
|
||||
<AutoupdatingParagraph
|
||||
intervalTime={5e3}
|
||||
text={`Reputation: ${formattedRep}`}
|
||||
tooltip={`You will earn ${numeralWrapper.format(favorGain, "0,0")} faction favor upon resetting after installing an Augmentation`}
|
||||
getText={this.getReputationText}
|
||||
getTooltip={this.getFavorGainText}
|
||||
/>
|
||||
<p style={blockStyleMarkup}>-------------------------</p>
|
||||
<ParagraphWithTooltip
|
||||
|
@ -158,14 +158,14 @@ export function makeRuntimeRejectMsg(workerScript, msg, exp=null) {
|
||||
//Run a script from inside a script using run() command
|
||||
export function runScriptFromScript(server, scriptname, args, workerScript, threads=1) {
|
||||
//Check if the script is already running
|
||||
var runningScriptObj = findRunningScript(scriptname, args, server);
|
||||
let runningScriptObj = findRunningScript(scriptname, args, server);
|
||||
if (runningScriptObj != null) {
|
||||
workerScript.scriptRef.log(scriptname + " is already running on " + server.hostname);
|
||||
return Promise.resolve(false);
|
||||
}
|
||||
|
||||
//'null/undefined' arguments are not allowed
|
||||
for (var i = 0; i < args.length; ++i) {
|
||||
for (let i = 0; i < args.length; ++i) {
|
||||
if (args[i] == null) {
|
||||
workerScript.scriptRef.log("ERROR: Cannot execute a script with null/undefined as an argument");
|
||||
return Promise.resolve(false);
|
||||
@ -191,10 +191,10 @@ export function runScriptFromScript(server, scriptname, args, workerScript, thre
|
||||
return Promise.resolve(false);
|
||||
} else {
|
||||
//Able to run script
|
||||
if(workerScript.disableLogs.ALL == null && workerScript.disableLogs.exec == null && workerScript.disableLogs.run == null && workerScript.disableLogs.spawn == null) {
|
||||
workerScript.scriptRef.log("Running script: " + scriptname + " on " + server.hostname + " with " + threads + " threads and args: " + arrayToString(args) + ". May take a few seconds to start up...");
|
||||
if (workerScript.disableLogs.ALL == null && workerScript.disableLogs.exec == null && workerScript.disableLogs.run == null && workerScript.disableLogs.spawn == null) {
|
||||
workerScript.scriptRef.log(`Running script: ${scriptname} on ${server.hostname} with ${threads} threads and args: ${arrayToString(args)}. May take a few seconds to start up...`);
|
||||
}
|
||||
var runningScriptObj = new RunningScript(script, args);
|
||||
let runningScriptObj = new RunningScript(script, args);
|
||||
runningScriptObj.threads = threads;
|
||||
addWorkerScript(runningScriptObj, server);
|
||||
|
||||
|
@ -3692,17 +3692,26 @@ function NetscriptFunctions(workerScript) {
|
||||
}
|
||||
}
|
||||
|
||||
if (!factionExists(facname)) {
|
||||
const fac = Factions[facname];
|
||||
if (!(fac instanceof Faction)) {
|
||||
workerScript.scriptRef.log("ERROR: getAugmentationsFromFaction() failed. Invalid faction name passed in (this is case-sensitive): " + facname);
|
||||
return [];
|
||||
}
|
||||
|
||||
var fac = Factions[facname];
|
||||
var res = [];
|
||||
for (var i = 0; i < fac.augmentations.length; ++i) {
|
||||
res.push(fac.augmentations[i]);
|
||||
// If player has a gang with this faction, return all factions
|
||||
if (Player.hasGangWith(facname)) {
|
||||
const res = [];
|
||||
for (const augName in Augmentations) {
|
||||
const aug = Augmentations[augName];
|
||||
if (!aug.isSpecial) {
|
||||
res.push(augName);
|
||||
}
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
return res;
|
||||
|
||||
return fac.augmentations.slice();
|
||||
},
|
||||
getAugmentationPrereq : function(name) {
|
||||
var ramCost = CONSTANTS.ScriptSingularityFn3RamCost;
|
||||
@ -3762,50 +3771,58 @@ function NetscriptFunctions(workerScript) {
|
||||
}
|
||||
}
|
||||
|
||||
var fac = Factions[faction];
|
||||
if (fac == null || !(fac instanceof Faction)) {
|
||||
workerScript.scriptRef.log("ERROR: purchaseAugmentation() failed because of invalid faction name: " + faction);
|
||||
const fac = Factions[faction];
|
||||
if (!(fac instanceof Faction)) {
|
||||
workerScript.log("ERROR: purchaseAugmentation() failed because of invalid faction name: " + faction);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!fac.augmentations.includes(name)) {
|
||||
workerScript.scriptRef.log("ERROR: purchaseAugmentation() failed because the faction " + faction + " does not contain the " + name + " augmentation");
|
||||
let augs = [];
|
||||
if (Player.hasGangWith(faction)) {
|
||||
for (const augName in Augmentations) {
|
||||
const tempAug = Augmentations[augName];
|
||||
if (!tempAug.isSpecial) {
|
||||
augs.push(augName);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
augs = fac.augmentations;
|
||||
}
|
||||
|
||||
if (!augs.includes(name)) {
|
||||
workerScript.log("ERROR: purchaseAugmentation() failed because the faction " + faction + " does not contain the " + name + " augmentation");
|
||||
return false;
|
||||
}
|
||||
|
||||
var aug = Augmentations[name];
|
||||
if (aug == null || !(aug instanceof Augmentation)) {
|
||||
workerScript.scriptRef.log("ERROR: purchaseAugmentation() failed because of invalid augmentation name: " + name);
|
||||
const aug = Augmentations[name];
|
||||
if (!(aug instanceof Augmentation)) {
|
||||
workerScript.log("ERROR: purchaseAugmentation() failed because of invalid augmentation name: " + name);
|
||||
return false;
|
||||
}
|
||||
|
||||
var isNeuroflux = false;
|
||||
if (aug.name === AugmentationNames.NeuroFluxGovernor) {
|
||||
isNeuroflux = true;
|
||||
}
|
||||
|
||||
let isNeuroflux = (aug.name === AugmentationNames.NeuroFluxGovernor);
|
||||
if (!isNeuroflux) {
|
||||
for (var j = 0; j < Player.queuedAugmentations.length; ++j) {
|
||||
for (let j = 0; j < Player.queuedAugmentations.length; ++j) {
|
||||
if (Player.queuedAugmentations[j].name === aug.name) {
|
||||
workerScript.scriptRef.log("ERROR: purchaseAugmentation() failed because you already have " + name);
|
||||
workerScript.log("ERROR: purchaseAugmentation() failed because you already have " + name);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
for (var j = 0; j < Player.augmentations.length; ++j) {
|
||||
for (let j = 0; j < Player.augmentations.length; ++j) {
|
||||
if (Player.augmentations[j].name === aug.name) {
|
||||
workerScript.scriptRef.log("ERROR: purchaseAugmentation() failed because you already have " + name);
|
||||
workerScript.log("ERROR: purchaseAugmentation() failed because you already have " + name);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (fac.playerReputation < aug.baseRepRequirement) {
|
||||
workerScript.scriptRef.log("ERROR: purchaseAugmentation() failed because you do not have enough reputation with " + fac.name);
|
||||
workerScript.log("ERROR: purchaseAugmentation() failed because you do not have enough reputation with " + fac.name);
|
||||
return false;
|
||||
}
|
||||
|
||||
var res = purchaseAugmentation(aug, fac, true);
|
||||
workerScript.scriptRef.log(res);
|
||||
workerScript.log(res);
|
||||
if (isString(res) && res.startsWith("You purchased")) {
|
||||
Player.gainIntelligenceExp(CONSTANTS.IntelligenceSingFnBaseExpGain);
|
||||
return true;
|
||||
|
@ -136,6 +136,7 @@ export interface IPlayer {
|
||||
getUpgradeHomeRamCost(): number;
|
||||
gotoLocation(to: LocationName): boolean;
|
||||
hasCorporation(): boolean;
|
||||
hasGangWith(facName: string): boolean;
|
||||
hasTorRouter(): boolean;
|
||||
inBladeburner(): boolean;
|
||||
inGang(): boolean;
|
||||
|
@ -23,7 +23,11 @@ export function getGangFaction() {
|
||||
}
|
||||
|
||||
export function getGangName() {
|
||||
return this.gang.facName;
|
||||
return this.inGang() ? this.gang.facName : "";
|
||||
}
|
||||
|
||||
export function hasGangWith(facName) {
|
||||
return this.inGang() && this.gang.facName === facName;
|
||||
}
|
||||
|
||||
export function inGang() {
|
||||
|
@ -424,7 +424,7 @@ function scriptCalculateOfflineProduction(runningScriptObj) {
|
||||
//designated server, and false otherwise
|
||||
export function findRunningScript(filename, args, server) {
|
||||
for (var i = 0; i < server.runningScripts.length; ++i) {
|
||||
if (server.runningScripts[i].filename == filename &&
|
||||
if (server.runningScripts[i].filename === filename &&
|
||||
compareArrays(server.runningScripts[i].args, args)) {
|
||||
return server.runningScripts[i];
|
||||
}
|
||||
|
@ -206,6 +206,7 @@ export function stockMarketCycle() {
|
||||
if (stock.b) { thresh = 0.4; }
|
||||
if (Math.random() < thresh) {
|
||||
stock.b = !stock.b;
|
||||
if (stock.otlkMag < 10) { stock.otlkMag += 0.4; }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2,6 +2,9 @@ import { Stock } from "./Stock";
|
||||
import { PositionTypes } from "./data/PositionTypes";
|
||||
import { CONSTANTS } from "../Constants";
|
||||
|
||||
// Amount by which a stock's forecast changes during each price movement
|
||||
const forecastChangePerPriceMovement = 0.4;
|
||||
|
||||
/**
|
||||
* Given a stock, calculates the amount by which the stock price is multiplied
|
||||
* for an 'upward' price movement. This does not actually increase the stock's price,
|
||||
@ -86,7 +89,7 @@ export function getBuyTransactionCost(stock: Stock, shares: number, posType: Pos
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes a buy transaction's resulting price movement.
|
||||
* Processes a buy transaction's resulting price AND forecast movement.
|
||||
* @param {Stock} stock - Stock being purchased
|
||||
* @param {number} shares - Number of shares being transacted
|
||||
* @param {PositionTypes} posType - Long or short position
|
||||
@ -125,6 +128,10 @@ export function processBuyTransactionPriceMovement(stock: Stock, shares: number,
|
||||
|
||||
stock.price = currPrice;
|
||||
stock.shareTxUntilMovement = stock.shareTxForMovement - ((shares - stock.shareTxUntilMovement) % stock.shareTxForMovement);
|
||||
|
||||
// Forecast always decreases in magnitude
|
||||
const forecastChange = Math.min(5, forecastChangePerPriceMovement * numIterations);
|
||||
stock.otlkMag -= forecastChange;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -228,6 +235,10 @@ export function processSellTransactionPriceMovement(stock: Stock, shares: number
|
||||
|
||||
stock.price = currPrice;
|
||||
stock.shareTxUntilMovement = stock.shareTxForMovement - ((shares - stock.shareTxUntilMovement) % stock.shareTxForMovement);
|
||||
|
||||
// Forecast always decreases in magnitude
|
||||
const forecastChange = Math.min(5, forecastChangePerPriceMovement * numIterations);
|
||||
stock.otlkMag -= forecastChange;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -25,7 +25,7 @@ export class StockTickerPositionText extends React.Component<IProps, any> {
|
||||
|
||||
// Caculate total returns
|
||||
const totalCost = stock.playerShares * stock.playerAvgPx;
|
||||
const gains = (stock.price - stock.playerAvgPx) * stock.playerShares;
|
||||
const gains = (stock.getBidPrice() - stock.playerAvgPx) * stock.playerShares;
|
||||
let percentageGains = gains / totalCost;
|
||||
if (isNaN(percentageGains)) { percentageGains = 0; }
|
||||
|
||||
@ -56,7 +56,7 @@ export class StockTickerPositionText extends React.Component<IProps, any> {
|
||||
|
||||
// Caculate total returns
|
||||
const totalCost = stock.playerShortShares * stock.playerAvgShortPx;
|
||||
const gains = (stock.playerAvgShortPx - stock.price) * stock.playerShortShares;
|
||||
const gains = (stock.playerAvgShortPx - stock.getAskPrice()) * stock.playerShortShares;
|
||||
let percentageGains = gains / totalCost;
|
||||
if (isNaN(percentageGains)) { percentageGains = 0; }
|
||||
|
||||
|
@ -8,8 +8,8 @@ import * as React from "react";
|
||||
interface IProps {
|
||||
intervalTime?: number;
|
||||
style?: object;
|
||||
text: string;
|
||||
tooltip?: string;
|
||||
getText: () => string;
|
||||
getTooltip?: () => string;
|
||||
}
|
||||
|
||||
interface IState {
|
||||
@ -49,7 +49,14 @@ export class AutoupdatingParagraph extends React.Component<IProps, IState> {
|
||||
}
|
||||
|
||||
render() {
|
||||
const hasTooltip = this.props.tooltip != null && this.props.tooltip !== "";
|
||||
let hasTooltip = this.props.getTooltip != null;
|
||||
let tooltip: string | null;
|
||||
if (hasTooltip) {
|
||||
tooltip = this.props.getTooltip!();
|
||||
if (tooltip === "") {
|
||||
hasTooltip = false;
|
||||
}
|
||||
}
|
||||
|
||||
const className = "tooltip";
|
||||
|
||||
@ -57,13 +64,13 @@ export class AutoupdatingParagraph extends React.Component<IProps, IState> {
|
||||
let tooltipMarkup: IInnerHTMLMarkup | null;
|
||||
if (hasTooltip) {
|
||||
tooltipMarkup = {
|
||||
__html: this.props.tooltip!
|
||||
__html: tooltip!
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<p className={className} style={this.props.style}>
|
||||
{this.props.text}
|
||||
{this.props.getText()}
|
||||
{
|
||||
hasTooltip &&
|
||||
<span className={"tooltiptext"} dangerouslySetInnerHTML={tooltipMarkup!}></span>
|
||||
|
@ -9,11 +9,13 @@ export function arrayToString<T>(a: T[]) {
|
||||
const vals: any[] = [];
|
||||
for (let i = 0; i < a.length; ++i) {
|
||||
let elem: any = a[i];
|
||||
if (typeof elem === "string") {
|
||||
if (Array.isArray(elem)) {
|
||||
elem = arrayToString(elem);
|
||||
} else if (typeof elem === "string") {
|
||||
elem = `"${elem}"`;
|
||||
}
|
||||
vals.push(elem);
|
||||
}
|
||||
|
||||
|
||||
return `[${vals.join(", ")}]`;
|
||||
}
|
||||
|
@ -9,8 +9,19 @@ export function compareArrays<T>(a1: T[], a2: T[]) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (let i: number = 0; i < a1.length; ++i) {
|
||||
if (a1[i] !== a2[i]) {
|
||||
for (let i = 0; i < a1.length; ++i) {
|
||||
if (Array.isArray(a1[i])) {
|
||||
// If the other element is not an array, then these cannot be equal
|
||||
if (!Array.isArray(a2[i])) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const elem1 = <any[]><any>a1[i];
|
||||
const elem2 = <any[]><any>a2[i];
|
||||
if (!compareArrays(elem1, elem2)) {
|
||||
return false;
|
||||
}
|
||||
} else if (a1[i] !== a2[i]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user