merge dev and added purchased server softcap

This commit is contained in:
Olivier Gagnon 2021-10-16 22:39:56 -04:00
commit 75caf77231
16 changed files with 148 additions and 124 deletions

26
dist/vendor.bundle.js vendored

File diff suppressed because one or more lines are too long

@ -3,6 +3,57 @@
Changelog Changelog
========= =========
v0.57.0 - 2021-10-16 It was too cheap! (hydroflame & community)
-------------------------------------------
** BREAKING (kindof) **
* purchased server cost now scales exponentially past 2^10.
I'm going to actually explain this one: Currently the cost of a 2^20GB server is 57b
Most players can get that before their first install. In an effort to nerf good players
a softcap was added. This softcap is different for every BN.
** Script Editor **
* Added a theme that is close to monokai. Unfortunately a full monokai is impossible because
Monaco doesn't have a very good tokenizer.
* Opening a file and connecting to a new server will still save the file on the server that the file
was opened.
** Netscript **
* New function: alert, which creates a textbox.
* New function: toast, creates a notification in the bottom right.
* New function: upgradeHomeCores (@Saynt_Garmo)
* New function: atExit, allows you to set a callback for when the script closes.
* New kindof function: autocomplete, this allows you to tell the game what it should
autocomplete on the terminal.
** Augmentation **
* ENM Core (the Augmentation from The Black Hand with the highest rep cost) rep cost
reduced from 250 to 175. This will help new players transition from TBH to BitRunners more easily.
** Bladeburner **
* New general action: Incite Violence. This action adds other action counts but increases chaos.
** Misc. **
* Current bladeburner action is shown on the character overview.
* Fix blackop being #000 on #000.
* The last clicked Tail Box goes in front of the others.
* Fixed an issue where some values were loaded as 0 when they should be null.
* Implemented toasts.
* .msg are no longer saved in the text file.
* Tail boxes no longer display all the args, they use "..." after 30 characters.
* Fixed cancelation penalty bonus not being properly applied after the IP <-> hostname switch.
* Fixed an exploit where you could send non-strings or numbers to other scripts.
* Fixed issue when trying to work for a faction with a work type that doesn't exist while
already working for that faction.
* Fixed not being able to work for the CIA. (Don't ask)
* nerf noodle bar
v0.56.0 - 2021-10-11 Trimming the backlog (hydroflame & community) v0.56.0 - 2021-10-11 Trimming the backlog (hydroflame & community)
------------------------------------------- -------------------------------------------

@ -64,9 +64,9 @@ documentation_title = '{0} Documentation'.format(project)
# built documents. # built documents.
# #
# The short X.Y version. # The short X.Y version.
version = '0.56' version = '0.57'
# The full version, including alpha/beta/rc tags. # The full version, including alpha/beta/rc tags.
release = '0.56.0' release = '0.57.0'
# The language for content autogenerated by Sphinx. Refer to documentation # The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages. # for a list of supported languages.

@ -1,13 +1,13 @@
autocomplete() Netscript Function autocomplete() Netscript Function
============================ ============================
.. warning:: This feature is not officially supported yet and the API might change. .. warning:: This feature is not officially supported yet and the API might change. It is also only supported in ns2
.. js:function:: autocomplete(data, args) .. js:function:: autocomplete(data, args)
:RAM cost: 0 GB :RAM cost: 0 GB
:param Object data: general data about the game you might want to autocomplete. :param Object data: general data about the game you might want to autocomplete.
:param string[] args: current arguments. :param string[] args: current arguments. Minus `run script.ns`
data is an object with the following properties:: data is an object with the following properties::
@ -15,8 +15,11 @@ autocomplete() Netscript Function
servers: list of all servers in the game. servers: list of all servers in the game.
txts: list of all text files on the current server. txts: list of all text files on the current server.
scripts: list of all scripts on the current server. scripts: list of all scripts on the current server.
flags: the same flags function as passed with ns. Calling this function adds all the flags as autocomplete arguments
} }
This function is special as it must be declared as a top level function like `main`.
Example: Example:
.. code-block:: javascript .. code-block:: javascript

@ -7,7 +7,7 @@ toast() Netscript Function
:param string message: message to display :param string message: message to display
:param success|info|warning|error variant: color of the toast :param success|info|warning|error variant: color of the toast
Spawns a toast (those bottom left notifications). Spawns a toast (those bottom right notifications).
Example: Example:

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

@ -599,6 +599,7 @@ export function initBitNodeMultipliers(p: IPlayer): void {
BitNodeMultipliers.FactionWorkRepGain = 0.5; BitNodeMultipliers.FactionWorkRepGain = 0.5;
BitNodeMultipliers.FactionPassiveRepGain = 0; BitNodeMultipliers.FactionPassiveRepGain = 0;
BitNodeMultipliers.GangKarmaRequirement = 0; BitNodeMultipliers.GangKarmaRequirement = 0;
BitNodeMultipliers.PurchasedServerSoftcap = 1.4;
break; break;
case 3: // Corporatocracy case 3: // Corporatocracy
BitNodeMultipliers.HackingLevelMultiplier = 0.8; BitNodeMultipliers.HackingLevelMultiplier = 0.8;
@ -615,6 +616,7 @@ export function initBitNodeMultipliers(p: IPlayer): void {
BitNodeMultipliers.HomeComputerRamCost = 1.5; BitNodeMultipliers.HomeComputerRamCost = 1.5;
BitNodeMultipliers.PurchasedServerCost = 2; BitNodeMultipliers.PurchasedServerCost = 2;
BitNodeMultipliers.GangKarmaRequirement = 3; BitNodeMultipliers.GangKarmaRequirement = 3;
BitNodeMultipliers.PurchasedServerSoftcap = 1.4;
break; break;
case 4: // The Singularity case 4: // The Singularity
BitNodeMultipliers.ServerMaxMoney = 0.15; BitNodeMultipliers.ServerMaxMoney = 0.15;
@ -629,6 +631,7 @@ export function initBitNodeMultipliers(p: IPlayer): void {
BitNodeMultipliers.HackExpGain = 0.4; BitNodeMultipliers.HackExpGain = 0.4;
BitNodeMultipliers.CrimeExpGain = 0.5; BitNodeMultipliers.CrimeExpGain = 0.5;
BitNodeMultipliers.FactionWorkRepGain = 0.75; BitNodeMultipliers.FactionWorkRepGain = 0.75;
BitNodeMultipliers.PurchasedServerSoftcap = 1.3;
break; break;
case 5: // Artificial intelligence case 5: // Artificial intelligence
BitNodeMultipliers.ServerMaxMoney = 2; BitNodeMultipliers.ServerMaxMoney = 2;
@ -642,6 +645,7 @@ export function initBitNodeMultipliers(p: IPlayer): void {
BitNodeMultipliers.AugmentationMoneyCost = 2; BitNodeMultipliers.AugmentationMoneyCost = 2;
BitNodeMultipliers.HackExpGain = 0.5; BitNodeMultipliers.HackExpGain = 0.5;
BitNodeMultipliers.CorporationValuation = 0.5; BitNodeMultipliers.CorporationValuation = 0.5;
BitNodeMultipliers.PurchasedServerSoftcap = 1.3;
break; break;
case 6: // Bladeburner case 6: // Bladeburner
BitNodeMultipliers.HackingLevelMultiplier = 0.35; BitNodeMultipliers.HackingLevelMultiplier = 0.35;
@ -658,6 +662,7 @@ export function initBitNodeMultipliers(p: IPlayer): void {
BitNodeMultipliers.HackExpGain = 0.25; BitNodeMultipliers.HackExpGain = 0.25;
BitNodeMultipliers.DaedalusAugsRequirement = 1.166; // Results in 35 Augs needed BitNodeMultipliers.DaedalusAugsRequirement = 1.166; // Results in 35 Augs needed
BitNodeMultipliers.GangKarmaRequirement = 5; BitNodeMultipliers.GangKarmaRequirement = 5;
BitNodeMultipliers.PurchasedServerSoftcap = 2;
break; break;
case 7: // Bladeburner 2079 case 7: // Bladeburner 2079
BitNodeMultipliers.BladeburnerRank = 0.6; BitNodeMultipliers.BladeburnerRank = 0.6;
@ -679,6 +684,7 @@ export function initBitNodeMultipliers(p: IPlayer): void {
BitNodeMultipliers.FourSigmaMarketDataApiCost = 2; BitNodeMultipliers.FourSigmaMarketDataApiCost = 2;
BitNodeMultipliers.DaedalusAugsRequirement = 1.166; // Results in 35 Augs needed BitNodeMultipliers.DaedalusAugsRequirement = 1.166; // Results in 35 Augs needed
BitNodeMultipliers.GangKarmaRequirement = 5; BitNodeMultipliers.GangKarmaRequirement = 5;
BitNodeMultipliers.PurchasedServerSoftcap = 2;
break; break;
case 8: // Ghost of Wall Street case 8: // Ghost of Wall Street
BitNodeMultipliers.ScriptHackMoney = 0.3; BitNodeMultipliers.ScriptHackMoney = 0.3;
@ -692,6 +698,7 @@ export function initBitNodeMultipliers(p: IPlayer): void {
BitNodeMultipliers.CorporationValuation = 0; BitNodeMultipliers.CorporationValuation = 0;
BitNodeMultipliers.CodingContractMoney = 0; BitNodeMultipliers.CodingContractMoney = 0;
BitNodeMultipliers.GangKarmaRequirement = 10; BitNodeMultipliers.GangKarmaRequirement = 10;
BitNodeMultipliers.PurchasedServerSoftcap = 5;
break; break;
case 9: // Hacktocracy case 9: // Hacktocracy
BitNodeMultipliers.HackingLevelMultiplier = 0.4; BitNodeMultipliers.HackingLevelMultiplier = 0.4;
@ -738,6 +745,7 @@ export function initBitNodeMultipliers(p: IPlayer): void {
BitNodeMultipliers.PurchasedServerMaxRam = 0.5; BitNodeMultipliers.PurchasedServerMaxRam = 0.5;
BitNodeMultipliers.BladeburnerRank = 0.8; BitNodeMultipliers.BladeburnerRank = 0.8;
BitNodeMultipliers.GangKarmaRequirement = 3; BitNodeMultipliers.GangKarmaRequirement = 3;
BitNodeMultipliers.PurchasedServerSoftcap = 1.2;
break; break;
case 11: //The Big Crash case 11: //The Big Crash
BitNodeMultipliers.HackingLevelMultiplier = 0.5; BitNodeMultipliers.HackingLevelMultiplier = 0.5;
@ -756,6 +764,7 @@ export function initBitNodeMultipliers(p: IPlayer): void {
BitNodeMultipliers.CodingContractMoney = 0.25; BitNodeMultipliers.CodingContractMoney = 0.25;
BitNodeMultipliers.FourSigmaMarketDataCost = 4; BitNodeMultipliers.FourSigmaMarketDataCost = 4;
BitNodeMultipliers.FourSigmaMarketDataApiCost = 4; BitNodeMultipliers.FourSigmaMarketDataApiCost = 4;
BitNodeMultipliers.PurchasedServerSoftcap = 2.2;
break; break;
case 12: { case 12: {
//The Recursion //The Recursion
@ -792,6 +801,7 @@ export function initBitNodeMultipliers(p: IPlayer): void {
BitNodeMultipliers.PurchasedServerCost = inc; BitNodeMultipliers.PurchasedServerCost = inc;
BitNodeMultipliers.PurchasedServerLimit = dec; BitNodeMultipliers.PurchasedServerLimit = dec;
BitNodeMultipliers.PurchasedServerMaxRam = dec; BitNodeMultipliers.PurchasedServerMaxRam = dec;
BitNodeMultipliers.PurchasedServerSoftcap = inc;
BitNodeMultipliers.ManualHackMoney = dec; BitNodeMultipliers.ManualHackMoney = dec;
BitNodeMultipliers.ScriptHackMoney = dec; BitNodeMultipliers.ScriptHackMoney = dec;
@ -828,6 +838,8 @@ export function initBitNodeMultipliers(p: IPlayer): void {
case 13: { case 13: {
BitNodeMultipliers.DaedalusAugsRequirement = 100; BitNodeMultipliers.DaedalusAugsRequirement = 100;
BitNodeMultipliers.PurchasedServerSoftcap = 2.2;
BitNodeMultipliers.HackingLevelMultiplier = 0.2; BitNodeMultipliers.HackingLevelMultiplier = 0.2;
BitNodeMultipliers.StrengthLevelMultiplier = 0.2; BitNodeMultipliers.StrengthLevelMultiplier = 0.2;
BitNodeMultipliers.DefenseLevelMultiplier = 0.2; BitNodeMultipliers.DefenseLevelMultiplier = 0.2;

@ -156,6 +156,11 @@ interface IBitNodeMultipliers {
*/ */
PurchasedServerCost: number; PurchasedServerCost: number;
/**
* Influence how much it costs to purchase a server
*/
PurchasedServerSoftcap: number;
/** /**
* Influences the maximum number of purchased servers you can have * Influences the maximum number of purchased servers you can have
*/ */
@ -247,6 +252,7 @@ export const BitNodeMultipliers: IBitNodeMultipliers = {
HomeComputerRamCost: 1, HomeComputerRamCost: 1,
PurchasedServerCost: 1, PurchasedServerCost: 1,
PurchasedServerSoftcap: 1,
PurchasedServerLimit: 1, PurchasedServerLimit: 1,
PurchasedServerMaxRam: 1, PurchasedServerMaxRam: 1,

@ -1503,18 +1503,18 @@ export class Bladeburner implements IBladeburner {
for (const contract of Object.keys(this.contracts)) { for (const contract of Object.keys(this.contracts)) {
const growthF = Growths[contract]; const growthF = Growths[contract];
if (!growthF) throw new Error("trying to generate count for action that doesn't exist? " + contract); if (!growthF) throw new Error("trying to generate count for action that doesn't exist? " + contract);
this.contracts[contract].count += (60 * 3 * growthF()) / BladeburnerConstants.ActionCountGrowthPeriod; this.contracts[contract].count += (60 * 6 * growthF()) / BladeburnerConstants.ActionCountGrowthPeriod;
} }
for (const operation of Object.keys(this.operations)) { for (const operation of Object.keys(this.operations)) {
const growthF = Growths[operation]; const growthF = Growths[operation];
if (!growthF) throw new Error("trying to generate count for action that doesn't exist? " + operation); if (!growthF) throw new Error("trying to generate count for action that doesn't exist? " + operation);
this.operations[operation].count += (60 * 3 * growthF()) / BladeburnerConstants.ActionCountGrowthPeriod; this.operations[operation].count += (60 * 6 * growthF()) / BladeburnerConstants.ActionCountGrowthPeriod;
} }
if (this.logging.general) { if (this.logging.general) {
this.log(`Incited violence in the synthoid communities.`); this.log(`Incited violence in the synthoid communities.`);
} }
const city = this.cities[this.city]; const city = this.cities[this.city];
city.chaos *= 2; city.chaos *= (city.chaos + 100) * 2;
this.startAction(player, this.action); this.startAction(player, this.action);
break; break;
} }

@ -12,13 +12,13 @@ export const Growths: {
["Stealth Retirement Operation"]: () => number; ["Stealth Retirement Operation"]: () => number;
["Assassination"]: () => number; ["Assassination"]: () => number;
} = { } = {
Tracking: () => getRandomInt(5, 75) / 10, Tracking: () => getRandomInt(5, 75) / 20,
"Bounty Hunter": () => getRandomInt(5, 75) / 10, "Bounty Hunter": () => getRandomInt(5, 75) / 20,
Retirement: () => getRandomInt(5, 75) / 10, Retirement: () => getRandomInt(5, 75) / 20,
Investigation: () => getRandomInt(10, 40) / 10, Investigation: () => getRandomInt(10, 40) / 20,
"Undercover Operation": () => getRandomInt(10, 40) / 10, "Undercover Operation": () => getRandomInt(10, 40) / 20,
"Sting Operation": () => getRandomInt(3, 40) / 10, "Sting Operation": () => getRandomInt(3, 40) / 20,
Raid: () => getRandomInt(2, 40) / 10, Raid: () => getRandomInt(2, 40) / 20,
"Stealth Retirement Operation": () => getRandomInt(1, 20) / 10, "Stealth Retirement Operation": () => getRandomInt(1, 20) / 20,
Assassination: () => getRandomInt(1, 20) / 10, Assassination: () => getRandomInt(1, 20) / 20,
}; };

@ -114,7 +114,7 @@ export const CONSTANTS: {
TotalNumBitNodes: number; TotalNumBitNodes: number;
LatestUpdate: string; LatestUpdate: string;
} = { } = {
Version: "0.56.0", Version: "0.57.0",
// Speed (in ms) at which the main loop is updated // Speed (in ms) at which the main loop is updated
_idleSpeed: 200, _idleSpeed: 200,
@ -281,107 +281,55 @@ export const CONSTANTS: {
TotalNumBitNodes: 24, TotalNumBitNodes: 24,
LatestUpdate: ` LatestUpdate: `
v0.56.0 - 2021-10-11 Trimming the backlog (hydroflame & community) v0.57.0 - 2021-10-16 It was too cheap! (hydroflame & community)
------------------------------------------- -------------------------------------------
** BREAKING ** ** BREAKING (kindof) **
* The 'write' function is now async. This helps when making scripts that write scripts. * purchased server cost now scales exponentially past 2^10.
I'm going to actually explain this one: Currently the cost of a 2^20GB server is 57b
** Terminal ** Most players can get that before their first install. In an effort to nerf good players
a softcap was added. This softcap is different for every BN.
* 'grow' and 'weaken' have been added as terminal command. This should help player transition
from commands to scripts. The tutorial also talks about it.
* 'cp' command added
* Improved performance by rate limiting refresh.
** IP vs Hostname **
* The game now uses hostname as primary key for it's servers (yeah believe it or not IPs were
used until then). This has caused some issues with purchased servers (they couldn't be sold).
You might need to soft reset for the game to fully convert itself.
** Sleeve **
* Fixed bug where they couldn't train at Volhaven.
* No longer consume all bonus time at once, making it look buggy.
** SF9 **
* Now boosts hacknet production by 8/12/14%
** Hacknet Servers **
* production nerfed by 10%
* Max money increase gets weaker above 10t max money
** Corporation **
* Warehouse tooltip now also displays the amount of space taken by products.
* Changed research box completely to avoid dependency on Treant (Treant is a pita)
* All textbox should accept MAX/MP case insensitive.
* Fixed export popup not refreshing dropdowns correctly.
* Fixed product mku becoming zero
* Increased scaling of Wilson to avoid feedback loop.
* Can no longer get in debt by buying real estate
* Bonus time is consumed faster.
** Netscript **
* isBusy takes bitverse and infiltration into account
* hospitalize can't be called when in infiltration.
* setToCommitCrime now accepts crime rough name instead of perfect name.
* disableLog All now works for bladeburner functions.
* Fixed netscript port for ns1.
** Augmentation **
* Added augmentation to Ti Di Hui that removes penalty for being unfocused.
* Neuroflux no longer appears in special factions.
** Script Editor ** ** Script Editor **
* Ram check is debounced instead of refreshed every second. * Added a theme that is close to monokai. Unfortunately a full monokai is impossible because
* Added the vscode extension documentation to the game (it doesn't work well, thought) Monaco doesn't have a very good tokenizer.
* Fixed issue where autocomplete list would grow forever * Opening a file and connecting to a new server will still save the file on the server that the file
* Added semi-monokai as theme. was opened.
* Fixed issue where modifying filename would mess it up.
* Font size can be changed now.
** Infiltration ** ** Netscript **
* Fixed issue where game controls would become unfocused. * New function: alert, which creates a textbox.
* New function: toast, creates a notification in the bottom right.
* New function: upgradeHomeCores (@Saynt_Garmo)
* New function: atExit, allows you to set a callback for when the script closes.
* New kindof function: autocomplete, this allows you to tell the game what it should
autocomplete on the terminal.
** Augmentation **
* ENM Core (the Augmentation from The Black Hand with the highest rep cost) rep cost
reduced from 250 to 175. This will help new players transition from TBH to BitRunners more easily.
** Bladeburner **
* New general action: Incite Violence. This action adds other action counts but increases chaos.
** Misc. ** ** Misc. **
* Fixed loader incorrectly assuming some null values are incorrect. * Current bladeburner action is shown on the character overview.
* installBackdoor trigger Bitverse sequence * Fix blackop being #000 on #000.
* Some improvements to the theme editor * The last clicked Tail Box goes in front of the others.
* Improved documentation about where to learn javascript. * Fixed an issue where some values were loaded as 0 when they should be null.
* Added some instructions for contributors. * Implemented toasts.
* Fixed typo in corporation sell shares modal (@Saynt_Garmo) * .msg are no longer saved in the text file.
* Fixed pagination being black on black in Active Scripts * Tail boxes no longer display all the args, they use "..." after 30 characters.
* Create Script tab renamed to Script Editor * Fixed cancelation penalty bonus not being properly applied after the IP <-> hostname switch.
* Fixed an issue where corp some textbox wouldn't update when changing city. * Fixed an exploit where you could send non-strings or numbers to other scripts.
* Fixed an issue where hacknet online time was always 0. * Fixed issue when trying to work for a faction with a work type that doesn't exist while
* Netscript function prompt fixed. already working for that faction.
* Fixed miscalculation in growth. * Fixed not being able to work for the CIA. (Don't ask)
* Script with syntax errors will try to be a tad more helpful.
* Corporations can no longer bribe bladeburners.
* Augmentation Graphene Branchiblade renamed to Brachi, like the rest of them.
* All ram is displayed in GB/TB/PB now.
* Game now saves when saving a file, this can be turned off.
* Several improvement to log window.
* Bladeburner current action returns General type instead of the name of the action.
* Bladeburner travel and Sleeve travel respect disable ASCII.
* Tutorial fits on small screens.
* Import is much slower but more consistent now.
* Fix intelligence not updating properly.
* Added SF -1: Time Compression
* ReadTheDoc theme now matches the game.
* Logbox should wrap text better
* Logbox behavior should feel better.
* Fix font for AutoLink.exe
* nerf noodle bar * nerf noodle bar
`, `,
}; };

@ -2956,7 +2956,6 @@ function NetscriptFunctions(workerScript: WorkerScript): NS {
return true; return true;
}, },
workForFaction: function (name: any, type: any): any { workForFaction: function (name: any, type: any): any {
console.log(`${name} ${type}`);
updateDynamicRam("workForFaction", getRamCost("workForFaction")); updateDynamicRam("workForFaction", getRamCost("workForFaction"));
checkSingularityAccess("workForFaction", 2); checkSingularityAccess("workForFaction", 2);
getFaction("workForFaction", name); getFaction("workForFaction", name);

@ -884,7 +884,6 @@ export function startFactionFieldWork(this: IPlayer, router: IRouter, faction: F
} }
export function startFactionSecurityWork(this: IPlayer, router: IRouter, faction: Faction): void { export function startFactionSecurityWork(this: IPlayer, router: IRouter, faction: Faction): void {
console.log(faction);
this.resetWorkStatus(CONSTANTS.WorkTypeFaction, faction.name, CONSTANTS.FactionWorkSecurity); this.resetWorkStatus(CONSTANTS.WorkTypeFaction, faction.name, CONSTANTS.FactionWorkSecurity);
this.workHackExpGainRate = 0.05 * this.hacking_exp_mult * BitNodeMultipliers.FactionWorkExpGain; this.workHackExpGainRate = 0.05 * this.hacking_exp_mult * BitNodeMultipliers.FactionWorkExpGain;

@ -331,7 +331,6 @@ export function Root(props: IProps): React.ReactElement {
otherKeywords.forEach((k) => l.language.tokenizer.root.unshift([k, { token: "otherkeywords" }])); otherKeywords.forEach((k) => l.language.tokenizer.root.unshift([k, { token: "otherkeywords" }]));
otherKeyvars.forEach((k) => l.language.tokenizer.root.unshift([k, { token: "otherkeyvars" }])); otherKeyvars.forEach((k) => l.language.tokenizer.root.unshift([k, { token: "otherkeyvars" }]));
l.language.tokenizer.root.unshift(["this", { token: "this" }]); l.language.tokenizer.root.unshift(["this", { token: "this" }]);
console.log(l);
})(); })();
monaco.languages.typescript.javascriptDefaults.addExtraLib(libSource, "netscript.d.ts"); monaco.languages.typescript.javascriptDefaults.addExtraLib(libSource, "netscript.d.ts");

@ -28,7 +28,14 @@ export function getPurchaseServerCost(ram: number): number {
return Infinity; return Infinity;
} }
return sanitizedRam * CONSTANTS.BaseCostFor1GBOfRamServer * BitNodeMultipliers.PurchasedServerCost; const upg = Math.max(0, Math.log(sanitizedRam) / Math.log(2) - 9);
return (
sanitizedRam *
CONSTANTS.BaseCostFor1GBOfRamServer *
BitNodeMultipliers.PurchasedServerCost *
Math.pow(BitNodeMultipliers.PurchasedServerSoftcap, upg)
);
} }
export function getPurchaseServerLimit(): number { export function getPurchaseServerLimit(): number {