VERSION: Update game version to 2.2 (#240)

Includes some bug fixes:
* Fix sleeve shock internal/display discrepancy (0-100 vs 0-100)
* Special error message if ns function called without a this
* Change whitespace to pre-wrap for dialog box.
* Fix bug where idle sleeves do not consume cycles but still recover shock from those cycles. Now they do not recover during idle.
* attempted to tag commit as v2.2.0
This commit is contained in:
Snarling
2022-12-01 16:07:46 -05:00
committed by GitHub
parent 6034e1c3fa
commit 5ff2cd5357
14 changed files with 441 additions and 505 deletions

View File

@@ -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 = '2.1' version = '2.2'
# The full version, including alpha/beta/rc tags. # The full version, including alpha/beta/rc tags.
release = '2.1.0' release = '2.2.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.

View File

@@ -1,10 +1,10 @@
{ {
"name": "bitburner", "name": "bitburner",
"license": "SEE LICENSE IN license.txt", "license": "SEE LICENSE IN license.txt",
"version": "2.1.0", "version": "2.2.0",
"main": "electron-main.js", "main": "electron-main.js",
"author": { "author": {
"name": "Daniel Xie & Olivier Gagnon" "name": "Daniel Xie, Olivier Gagnon, et al."
}, },
"bugs": { "bugs": {
"url": "https://github.com/bitburner-official/bitburner-src/issues" "url": "https://github.com/bitburner-official/bitburner-src/issues"

View File

@@ -88,8 +88,8 @@ export const CONSTANTS: {
Donations: number; // number of blood/plasma/palette donation the dev have verified., boosts NFG Donations: number; // number of blood/plasma/palette donation the dev have verified., boosts NFG
LatestUpdate: string; LatestUpdate: string;
} = { } = {
VersionString: "2.1.0", VersionString: "2.2.0",
VersionNumber: 26, VersionNumber: 27,
// Speed (in ms) at which the main loop is updated // Speed (in ms) at which the main loop is updated
_idleSpeed: 200, _idleSpeed: 200,
@@ -232,186 +232,102 @@ export const CONSTANTS: {
Donations: 30, Donations: 30,
LatestUpdate: ` LatestUpdate: `
v2.1.0 - 2022-09-23 Remote File API v2.2.0 - 2022-12-01
-----------------------------------
BREAKING CHANGES:
Dev notes * ns.codingcontract.attempt no longer returns a boolean, it returns empty string on failure or the reward string
* The most important change about this update is the introduction of the remote file api. on success, so comparing the result directly to true/false will no longer work. The result can still be used as
With this we also deprecate the HTTP file api and the visual studio extension. Those things a condition directly.
were made during the rush of Steam and aren't well thought out. This new process works with * (NS2 only) ns functions use the this value from ns: if you move the function to its own variable off of ns, it
both the web and Steam version of the game and every text editor. Moving forward we also needs to be bound to ns. e.g.:
won't be doing much, if any, upgrades to the in-game editor. We think it's good enough for const tprint = ns.tprint.bind(ns);
now and if you need more we recommend you hook up your favorite external editor. * ns.formulas.work.classGains removed, replaced with ns.formulas.work.universityGains and ns.formulas.work.gymGains
* Added functions to resize, move, and close tail windows * ns.sleeve.getSleeveStats and ns.sleeve.getSleeveInformation removed, ns.sleeve.getSleeve added and the returned
* Added a new Augmentation, Z.O.Ë., which allows Sleeves to benefit from Stanek. sleeve can be used with formulas API the same way the getPlayer return can be.
API DEVELOPMENT
* Remove incorrectly placed 's' in ns.tFormat() (by @LJNeon) * Development repo moved to https://github.com/bitburner-official/bitburner-src
* More ports (previously max 20, now practically unlimited) (by @Hoekstraa) * Dev version available on web at https://bitburner-official.github.io/bitburner-src/
* Corp functions now return copy of constant arrays instead of the original (by @Mughur) * Development is active again for non-bugfix.
* All the player sub-objects need to be copied for 'getPlayer'. (by @MageKing17) * A bunch of fixes and setup related to moving to a new repo (@hydroflame)
* add corp get<constant> functions, UI (by @Mughur)
* FIX #3860 destroyW0r1dD43m0n now properly gives achievements and FIX #3890 favor now properly syncs across pages and the Donate achievement is now given correctly (by @Aerophia) NETSCRIPT
* Faster API wrapping on script launch. (by @d0sboots & @Snarling)
CONTRIBUTIONS * Expose more enums for player use under ns.enums (by @Snarling)
* Modify PR template (by @Hoekstraa) * tFormat: Fix display for negative time (by @Snarling)
CODING CONTRACT
CCT * ns.codingcontract.attempt always returns a string (by @Snarling)
* inconsistent probability for generation between online and offline (by @quacksouls) FORMULAS
* ns.formulas.work.classGains removed, replaced with ns.formulas.work.universityGains and
DOC ns.formulas.work.gymGains (@Snarling)
* Some typo fixes in Netscript functions (by @quacksouls) * Add ns.formulas.work.companyGains function (by @AlexeyKozhemiakin)
* Fix #4033 Why use Coding Contract API (by @quacksouls) PORTS
* typo fix in description of Caesar cipher (by @quacksouls) * added portHandle.nextWrite() (by @LJNeon)
* FIX DOCS TYPO IN terminal.rst (by @BugiDev) * Make ns.writePort synchronous (by @Snarling)
* Update bitburner.sleeve.settobladeburneraction.md (by @borisflagell)
CORPORATION
* FIX #3880, #3876, #3322 and #3138 Bunch of corporation fixes (by @Mughur)
* Gave investors some economics classes (by @Mughur)
* Limit shareholder priority on newly issued shares (by @Undeemiss)
UI
* FIX #2962 Add a setting to display middle time unit in Time Elapsed String (by @hydroflame)
* FIX #4106 Fix incorrect experience display in Crime UI. (by @SilverNexus)
* Bitnode stats now show if BB/Corporation are disabled (by @Kelenius)
* Removed three empty lines from BB status screen (by @Kelenius)
* Add missing space to BN7 description (by @hex7cd)
* Improvements to crime work UI (by @Kelenius)
* FIX #3975, #3882 Script Editor more responsive on resize, and fix dirty file indicator (by @Snarling)
API FIX
* getCrimeStats use bitnode multipliers in the output of crime stats (by @phyzical)
SLEEVES
* FIX #3819 Allow using the regeneration chamber with sleeves to heal them. (by @coderanger)
* FIX #4063 fix crash when player tries to assign more than 3 sleeves to Bladeburner contracts (by @Snarling)
* FIX #4051 Sleeves no longer crash when player quits company sleeve was working (by @Snarling)
API BACKUP
* add singularity function for exporting game save back (by @phyzical)
CORPORATION API
* FIX #3655 Expose exports from Material (by @Rasmoh)
SCRIPTS
* FIX #4081 Rerunning a script from tail window recalculates ram usage (by @Snarling)
* FIX #3962 The correct script will be closed even if the player modifies args (v2.0) (by @Snarling)
DOCUMENTATION
* Fixed Argument order for scp() (by @njalooo)
CORP API
* Fix up param order for limitProductProduction to match docs (by @phyzical)
NETSCRIPT
* FIX #2376 ns.exit now exits immediately (by @Snarling)
* FIX #4055 Fix dynamic ram check (by @Snarling)
* FIX #4037 ns1 wraps deeper layers correctly. (by @Snarling)
* FIX #3963 Prevent bladeburner.setActionLevel from setting invalid action levels (by @MPJ-K)
* Typo fixes in CodingContract, Hacknet, Singularity APIs (by @quacksouls)
* Fix a typo in doc of Singularity.travelToCity() (by @quacksouls)
* Update netscript definition file for scp, write, read, and flags (by @Snarling)
* Correct missing ! for boolean coercion in Corporation.createCorporation(). (by @Risenafis)
* Normalized Stock API logging (by @Snarling)
* fix #3992 allow null duration in toast ns function (by @RollerKnobster)
* Correct missing '!' for boolean coercion in 'singularity.workForCompany()'. (by @MageKing17)
* ns.scp and ns.write are now synchronous + fix exec race condition (by @Snarling)
* FIX #2931 atExit now allows synchronous ns functions (by @Snarling)
* Improve real life CPU and memory performance of scripts. (by @Snarling)
INFILTRATION
* Corrected ns formula for infiltration rewards (by @ezylot)
RFA
* NetscriptDefinitions retains export strings (by @Hoekstraa)
* Fix type of RFAMessages with non-String results (by @Hoekstraa)
* New Remote File API addition for transmitting files to the game (by @Hoekstraa)
SLEEVE SLEEVE
* FIX #4022, #4024, #4025, #3998 (by @Mughur) * ns.sleeve.getSleeve added. getPlayer and getSleeve can both be used for formulas. (by @Snarling)
STOCK
DOCS, UI * ns.stock.getOrganization added for getting org from stock symbol (by @SamuraiNinjaGuy)
* update docs a bit more, amending some BN and SF texts (by @Mughur)
SCRIPTS
GANG * Fixed bug where zombie scripts could be created after a soft reset (by @Snarling)
* Added weight to GangMemberTask construction call (by @ezylot)
SCRIPT LOGS
Coding Contracts * Add ctrl-a support for selecting all text in tail window (by @Snarling)
* Don't stringify answer if already a string (by @alainbryden)
CORPORATION
TERMINAL * Remove corp employees as objects (by @Kelenius)
* Fix ansi display bugs (by @Snarling) * Happiness/Energy/Morale trend down even for productive corps (by @Snarling)
* Typo fixes in modals to sell materials and products (by @quacksouls)
SCRIPT EDITOR * Reworked MP formula validation to prevent possible save corruption on invalid entry (by @Snarling)
* Debounce updateRAM calls. (by @Snarling) * Internal reorganization of Industry data (by @Snarling)
* Added check to material buy amount (by @G4mingJon4s)
WORK * Check there is room to make a new product before opening popup. (by @G4mingJon4s)
* Add singularity check for finishing company work (by @Snarling) * Fix typos in research descriptions (by @quacksouls)
DOCS SLEEVE
* Correct documentation for 'run()' with 0 threads. (by @MageKing17) * Fixed inconsistencies in how sleeve work rewards are handled. (by @Snarling)
* Some doc updates (by @Mughur) * Fix bug that prevented selecting some crimes from UI. (by @Snarling)
* Internally shock starts at 100 and lowers to 0. Previously this was backwards.
FILES
* FIX #3979 Allow characters & and ' in filenames (by @Snarling) STOCKMARKET
* Fix broken initializer when manually buying WSE access (by @Snarling)
CORP FIX
* dont take research points for something already researched via api (by @phyzical) TERMINAL
* Connect command will connect to player owned servers from anywhere. (by @Snarling)
FIX
* Prompt Add user friendly message to avoid throwing recovery screen for invalid choices (by @phyzical) UI
* Fix keyboard shortcuts for other keyboard layouts (by @d0sboots)
TUTORIAL * Fixed spacing of text in Trade for reputation button after Infiltration (by @PyroGenesis)
* Fix #3965 Corrected tutorial text (by @mihilt) * Fix spacing on ANSI background escape codes (by @Snarling)
* Fix several instances where newlines were not being displayed properly (by @quacksouls)
CONTRACTS * SoftResetButton.tsx Tooltip changed to make more sense (by @rai68)
* FIX #3755 change input handling for contract attempts (by @Snarling) * GANG: Fix Gang UI to correctly report the bonus time multiplier as 25x (by @TheMas3212)
HOTFIX DOC
* Fix infil definitions.d.ts (by @phyzical) * Fix incorrect examples for grow (by @quacksouls)
* Updated limitMaterialProduction() and limitProductProduction() documentation to mention removing limits. (by @PyroGenesis)
MISC * Add ns documentation for possible sleeve tasks (by @Snarling)
* crime gains, sleeve gang augs and faq (by @Mughur) * Update documentation for workForFaction and workForCompany (by @quacksouls)
* FIX #3649 Preventing server starting security level from going above 100 (by @Shiiyu) * Improve CCT documentation for HammingCodes (by @quacksouls)
* Adds Shadows of Anarchy (by @Lagicrus) * cleanup in doc of Netscript functions (by @quacksouls)
* Added intormation about hacking managers to hacking algorithms page (by @Kelenius) * Various other doc fixes (by @quacksouls)
* Fix Jest CI Error (by @geggleto) * Update documentation for ns.args (by @Snarling)
* multiple hasAugmentation checks didn't check if the augment was installed (by @Mughur) * De-uglify ns.print examples (by @LJNeon)
* Fix for #2442 and #2795. (by @G4mingJon4s)
* Adds info regarding augments and focus (by @Lagicrus) MISC
* Removed console.log line (by @dhosborne) * Some error handling streamlining (by @Snarling)
* Update some doc (by @hydroflame) * fix: check both ts and js source now (by @Tanimodori)
* Sleeve crime gain bitnode multiplier fix (by @Mughur) * chore: sync version in package-lock.json (by @Tanimodori)
* trying to fix int problems (by @hydroflame) * Better safety when loading game for multiple save corruption issues (by @Snarling)
* Fix broken ns filesnames (by @hydroflame) * Nerf Noodle bar
* new formula functions (by @hydroflame)
* v2.0.0 (by @hydroflame) STATS
* test fixes/md updates (by @phyzical) * Fix logic for increasing HP based on defense skill levels (by @mattgarretson)
* Remove "based" from positive adjectives in infil (by @faangbait)
* minor fix in instance calculation (by @hydroflame) TUTORIAL
* fix dynamic ram miscalc not triggering (by @hydroflame) * Fix Ram Text (by @jaculler)
* Refactor game options into separate components (by @hydroflame)
* fix documentation for remote api (by @hydroflame) INFILTRATION
* fix settings unfocusing on every key stroke (by @hydroflame) * Fix SlashGame scaling. (by @Snarling)`,
* fix some stuff with the timestamp settings (by @hydroflame)
* fix some stuff with the timestamp settings (by @hydroflame)
* Fix unique key problem with ascii elements (by @hydroflame)
* Improve wrong arg user message and add ui.windowSize (by @hydroflame)
* fix stack trace missing in some errors (by @hydroflame)
* Fix scp and write in ns1 (by @hydroflame)
* Did some changes of the remote api and added documentation (by @hydroflame)
* Add dummy function to generate a mock server or player for formulas stuff (by @hydroflame)
* fix compile error (by @hydroflame)
* regen doc (by @hydroflame)
* rm console log (by @hydroflame)
* regen doc (by @hydroflame)
* Added more info about blood program, change some aug descriptions (by @hydroflame)
* use triple equal (by @hydroflame)
* Minor improvements to Netscript Port loading and unloading (by @hydroflame)
* Fix hostname generation being weird about dash 0 added (by @hydroflame)
* upgrade version number. (by @hydroflame)
* Nerf Noodle bar
`,
}; };

View File

@@ -13,13 +13,13 @@ import { Adjuster } from "./Adjuster";
export function Sleeves(): React.ReactElement { export function Sleeves(): React.ReactElement {
function sleeveMaxAllShock(): void { function sleeveMaxAllShock(): void {
for (let i = 0; i < Player.sleeves.length; ++i) { for (let i = 0; i < Player.sleeves.length; ++i) {
Player.sleeves[i].shock = 0; Player.sleeves[i].shock = 100;
} }
} }
function sleeveClearAllShock(): void { function sleeveClearAllShock(): void {
for (let i = 0; i < Player.sleeves.length; ++i) { for (let i = 0; i < Player.sleeves.length; ++i) {
Player.sleeves[i].shock = 100; Player.sleeves[i].shock = 0;
} }
} }

View File

@@ -46,6 +46,14 @@ export class StampedLayer {
const arrayPath = [...tree, key]; const arrayPath = [...tree, key];
const functionPath = arrayPath.join("."); const functionPath = arrayPath.join(".");
function wrappedFunction(this: StampedLayer, ...args: unknown[]): unknown { function wrappedFunction(this: StampedLayer, ...args: unknown[]): unknown {
if (!this)
throw new Error(`
ns.${functionPath} called with no this value.
ns functions must be bound to ns if placed in a new
variable. e.g.
const ${key} = ns.${functionPath}.bind(ns);
${key}(${JSON.stringify(args).replace(/^\[|\]$/g, "")});\n\n`);
const ctx = { workerScript: this.#workerScript, function: key, functionPath }; const ctx = { workerScript: this.#workerScript, function: key, functionPath };
helpers.checkEnvFlags(ctx); helpers.checkEnvFlags(ctx);
helpers.updateDynamicRam(ctx, getRamCost(...tree, key)); helpers.updateDynamicRam(ctx, getRamCost(...tree, key));

View File

@@ -105,7 +105,7 @@ export function prestigeAugmentation(this: PlayerObject): void {
this.sleeves.push(new Sleeve()); this.sleeves.push(new Sleeve());
} }
this.sleeves.forEach((sleeve) => (sleeve.shock >= 100 ? sleeve.synchronize() : sleeve.shockRecovery())); this.sleeves.forEach((sleeve) => (sleeve.shock <= 0 ? sleeve.synchronize() : sleeve.shockRecovery()));
this.lastUpdate = new Date().getTime(); this.lastUpdate = new Date().getTime();

View File

@@ -55,7 +55,7 @@ export class Sleeve extends Person implements SleevePerson {
* *
* Reputation earned is also multiplied by shock% * Reputation earned is also multiplied by shock%
*/ */
shock = 1; shock = 100;
/** Stored number of game "loop" cycles */ /** Stored number of game "loop" cycles */
storedCycles = 0; storedCycles = 0;
@@ -76,7 +76,7 @@ export class Sleeve extends Person implements SleevePerson {
findPurchasableAugs = sleeveMethods.findPurchasableAugs; findPurchasableAugs = sleeveMethods.findPurchasableAugs;
shockBonus(): number { shockBonus(): number {
return this.shock / 100; return (100 - this.shock) / 100;
} }
syncBonus(): number { syncBonus(): number {
@@ -159,7 +159,7 @@ export class Sleeve extends Person implements SleevePerson {
this.city = CityName.Sector12; this.city = CityName.Sector12;
// Reset sleeve-related stats // Reset sleeve-related stats
this.shock = 1; this.shock = 100;
this.storedCycles = 0; this.storedCycles = 0;
this.sync = Math.max(this.memory, 1); this.sync = Math.max(this.memory, 1);
} }
@@ -173,12 +173,9 @@ export class Sleeve extends Person implements SleevePerson {
// Only process once every second (5 cycles) // Only process once every second (5 cycles)
const CyclesPerSecond = 1000 / CONSTANTS.MilliPerCycle; const CyclesPerSecond = 1000 / CONSTANTS.MilliPerCycle;
this.storedCycles += numCycles; this.storedCycles += numCycles;
if (this.storedCycles < CyclesPerSecond) return; if (this.storedCycles < CyclesPerSecond || !this.currentWork) return;
const cyclesUsed = Math.min(this.storedCycles, 15);
let cyclesUsed = this.storedCycles; this.shock = Math.max(0, this.shock - 0.0001 * cyclesUsed);
cyclesUsed = Math.min(cyclesUsed, 15);
this.shock = Math.min(100, this.shock + 0.0001 * cyclesUsed);
if (!this.currentWork) return;
this.currentWork.process(this, cyclesUsed); this.currentWork.process(this, cyclesUsed);
this.storedCycles -= cyclesUsed; this.storedCycles -= cyclesUsed;
} }
@@ -457,7 +454,7 @@ export class Sleeve extends Person implements SleevePerson {
this.hp.current -= amt; this.hp.current -= amt;
if (this.hp.current <= 0) { if (this.hp.current <= 0) {
this.shock = Math.max(0, this.shock - 0.5); this.shock = Math.min(100, this.shock + 0.5);
this.hp.current = this.hp.max; this.hp.current = this.hp.max;
return true; return true;
} else { } else {

View File

@@ -11,8 +11,8 @@ export class SleeveRecoveryWork extends Work {
} }
process(sleeve: Sleeve, cycles: number) { process(sleeve: Sleeve, cycles: number) {
sleeve.shock = Math.min(100, sleeve.shock + 0.0002 * cycles); sleeve.shock = Math.max(0, sleeve.shock - 0.0002 * cycles);
if (sleeve.shock >= 100) sleeve.stopWork(); if (sleeve.shock <= 0) sleeve.stopWork();
} }
APICopy() { APICopy() {

View File

@@ -169,12 +169,12 @@ export function SleeveElem(props: IProps): React.ReactElement {
</span> </span>
</Tooltip> </Tooltip>
<Tooltip <Tooltip
title={props.sleeve.shock < 100 ? <Typography>Unlocked when sleeve has fully recovered</Typography> : ""} title={props.sleeve.shock > 0 ? <Typography>Unlocked when sleeve has fully recovered</Typography> : ""}
> >
<span> <span>
<Button <Button
onClick={() => setAugmentationsOpen(true)} onClick={() => setAugmentationsOpen(true)}
disabled={props.sleeve.shock < 100} disabled={props.sleeve.shock > 0}
sx={{ width: "100%", height: "100%" }} sx={{ width: "100%", height: "100%" }}
> >
Manage Augmentations Manage Augmentations

View File

@@ -78,7 +78,7 @@ export function StatsElement(props: IProps): React.ReactElement {
<StatsRow <StatsRow
name="Shock" name="Shock"
color={Settings.theme.primary} color={Settings.theme.primary}
data={{ content: numeralWrapper.formatSleeveShock(100 - props.sleeve.shock) }} data={{ content: numeralWrapper.formatSleeveShock(props.sleeve.shock) }}
/> />
<StatsRow <StatsRow
name="Sync" name="Sync"

View File

@@ -245,7 +245,7 @@ const canDo: {
[CityName.Aevum, CityName.Sector12, CityName.Volhaven].includes(sleeve.city), [CityName.Aevum, CityName.Sector12, CityName.Volhaven].includes(sleeve.city),
"Workout at Gym": (sleeve: Sleeve) => [CityName.Aevum, CityName.Sector12, CityName.Volhaven].includes(sleeve.city), "Workout at Gym": (sleeve: Sleeve) => [CityName.Aevum, CityName.Sector12, CityName.Volhaven].includes(sleeve.city),
"Perform Bladeburner Actions": () => !!Player.bladeburner, "Perform Bladeburner Actions": () => !!Player.bladeburner,
"Shock Recovery": (sleeve: Sleeve) => sleeve.shock < 100, "Shock Recovery": (sleeve: Sleeve) => sleeve.shock > 0,
Synchronize: (sleeve: Sleeve) => sleeve.sync < 100, Synchronize: (sleeve: Sleeve) => sleeve.sync < 100,
}; };

View File

@@ -354,306 +354,309 @@ function evaluateVersionCompatibility(ver: string | number): void {
v1APIBreak(); v1APIBreak();
ver = 1; ver = 1;
} }
if (typeof ver === "number") { if (typeof ver !== "number") return;
if (ver < 2) { if (ver < 2) {
AwardNFG(10); AwardNFG(10);
Player.reapplyAllAugmentations(true); Player.reapplyAllAugmentations(true);
Player.reapplyAllSourceFiles(); Player.reapplyAllSourceFiles();
} }
if (ver < 3) { if (ver < 3) {
anyPlayer.money = parseFloat(anyPlayer.money); anyPlayer.money = parseFloat(anyPlayer.money);
if (anyPlayer.corporation) { if (anyPlayer.corporation) {
anyPlayer.corporation.funds = parseFloat(anyPlayer.corporation.funds); anyPlayer.corporation.funds = parseFloat(anyPlayer.corporation.funds);
anyPlayer.corporation.revenue = parseFloat(anyPlayer.corporation.revenue); anyPlayer.corporation.revenue = parseFloat(anyPlayer.corporation.revenue);
anyPlayer.corporation.expenses = parseFloat(anyPlayer.corporation.expenses); anyPlayer.corporation.expenses = parseFloat(anyPlayer.corporation.expenses);
for (let i = 0; i < anyPlayer.corporation.divisions.length; ++i) { for (let i = 0; i < anyPlayer.corporation.divisions.length; ++i) {
const ind = anyPlayer.corporation.divisions[i]; const ind = anyPlayer.corporation.divisions[i];
ind.lastCycleRevenue = parseFloat(ind.lastCycleRevenue); ind.lastCycleRevenue = parseFloat(ind.lastCycleRevenue);
ind.lastCycleExpenses = parseFloat(ind.lastCycleExpenses); ind.lastCycleExpenses = parseFloat(ind.lastCycleExpenses);
ind.thisCycleRevenue = parseFloat(ind.thisCycleRevenue); ind.thisCycleRevenue = parseFloat(ind.thisCycleRevenue);
ind.thisCycleExpenses = parseFloat(ind.thisCycleExpenses); ind.thisCycleExpenses = parseFloat(ind.thisCycleExpenses);
}
} }
} }
if (ver < 9) { }
if (StockMarket.hasOwnProperty("Joes Guns")) { if (ver < 9) {
const s = StockMarket["Joes Guns"]; if (StockMarket.hasOwnProperty("Joes Guns")) {
delete StockMarket["Joes Guns"]; const s = StockMarket["Joes Guns"];
StockMarket[LocationName.Sector12JoesGuns] = s; delete StockMarket["Joes Guns"];
} StockMarket[LocationName.Sector12JoesGuns] = s;
} }
if (ver < 10) { }
// Augmentation name was changed in 0.56.0 but sleeves aug list was missed. if (ver < 10) {
if (anyPlayer.sleeves && anyPlayer.sleeves.length > 0) { // Augmentation name was changed in 0.56.0 but sleeves aug list was missed.
for (const sleeve of anyPlayer.sleeves) { if (anyPlayer.sleeves && anyPlayer.sleeves.length > 0) {
if (!sleeve.augmentations || sleeve.augmentations.length === 0) continue;
for (const augmentation of sleeve.augmentations) {
if (augmentation.name !== "Graphene BranchiBlades Upgrade") continue;
augmentation.name = "Graphene BrachiBlades Upgrade";
}
}
}
}
if (ver < 12) {
if (anyPlayer.resleeves !== undefined) {
delete anyPlayer.resleeves;
}
}
if (ver < 15) {
Settings.EditorTheme = { ...defaultMonacoTheme };
}
//Fix contract names
if (ver < 16) {
Factions[FactionNames.ShadowsOfAnarchy] = new Faction(FactionNames.ShadowsOfAnarchy);
//Iterate over all contracts on all servers
for (const server of GetAllServers()) {
for (const contract of server.contracts) {
//Rename old "HammingCodes: Integer to encoded Binary" contracts
//to "HammingCodes: Integer to Encoded Binary"
if (contract.type == "HammingCodes: Integer to encoded Binary") {
contract.type = "HammingCodes: Integer to Encoded Binary";
}
}
}
}
const v22PlayerBreak = () => {
// reset HP correctly to avoid crash
anyPlayer.hp = { current: 1, max: 1 };
for (const sleeve of anyPlayer.sleeves) { for (const sleeve of anyPlayer.sleeves) {
sleeve.hp = { current: 1, max: 1 }; if (!sleeve.augmentations || sleeve.augmentations.length === 0) continue;
} for (const augmentation of sleeve.augmentations) {
if (augmentation.name !== "Graphene BranchiBlades Upgrade") continue;
// transfer over old exp to new struct augmentation.name = "Graphene BrachiBlades Upgrade";
anyPlayer.exp.hacking = anyPlayer.hacking_exp; }
anyPlayer.exp.strength = anyPlayer.strength_exp;
anyPlayer.exp.defense = anyPlayer.defense_exp;
anyPlayer.exp.dexterity = anyPlayer.dexterity_exp;
anyPlayer.exp.agility = anyPlayer.agility_exp;
anyPlayer.exp.charisma = anyPlayer.charisma_exp;
anyPlayer.exp.intelligence = anyPlayer.intelligence_exp;
};
// Fix bugged NFG accumulation in owned augmentations
if (ver < 17) {
let ownedNFGs = [...Player.augmentations];
ownedNFGs = ownedNFGs.filter((aug) => aug.name === AugmentationNames.NeuroFluxGovernor);
const newNFG = new PlayerOwnedAugmentation(AugmentationNames.NeuroFluxGovernor);
newNFG.level = 0;
for (const nfg of ownedNFGs) {
newNFG.level += nfg.level;
}
Player.augmentations = [
...Player.augmentations.filter((aug) => aug.name !== AugmentationNames.NeuroFluxGovernor),
newNFG,
];
v22PlayerBreak();
Player.reapplyAllAugmentations(true);
Player.reapplyAllSourceFiles();
}
if (ver < 20) {
// Create the darkweb for everyone but it won't be linked
const dw = GetServer(SpecialServers.DarkWeb);
if (!dw) {
const darkweb = safelyCreateUniqueServer({
ip: createUniqueRandomIp(),
hostname: SpecialServers.DarkWeb,
organizationName: "",
isConnectedTo: false,
adminRights: false,
purchasedByPlayer: false,
maxRam: 1,
});
AddToAllServers(darkweb);
} }
} }
if (ver < 21) { }
// 2.0.0 work rework if (ver < 12) {
AwardNFG(10); if (anyPlayer.resleeves !== undefined) {
const create = anyPlayer["createProgramName"]; delete anyPlayer.resleeves;
if (create) Player.getHomeComputer().pushProgram(create);
const graft = anyPlayer["graftAugmentationName"];
if (graft) Player.augmentations.push({ name: graft, level: 1 });
} }
if (ver < 22) { }
v22PlayerBreak();
v2APIBreak(); if (ver < 15) {
Settings.EditorTheme = { ...defaultMonacoTheme };
}
//Fix contract names
if (ver < 16) {
Factions[FactionNames.ShadowsOfAnarchy] = new Faction(FactionNames.ShadowsOfAnarchy);
//Iterate over all contracts on all servers
for (const server of GetAllServers()) {
for (const contract of server.contracts) {
//Rename old "HammingCodes: Integer to encoded Binary" contracts
//to "HammingCodes: Integer to Encoded Binary"
if (contract.type == "HammingCodes: Integer to encoded Binary") {
contract.type = "HammingCodes: Integer to Encoded Binary";
}
}
} }
if (ver < 23) { }
anyPlayer.currentWork = null;
const v22PlayerBreak = () => {
// reset HP correctly to avoid crash
anyPlayer.hp = { current: 1, max: 1 };
for (const sleeve of anyPlayer.sleeves) {
sleeve.hp = { current: 1, max: 1 };
} }
if (ver < 24) {
Player.getHomeComputer().scripts.forEach((s) => s.filename.endsWith(".ns") && (s.filename += ".js")); // transfer over old exp to new struct
anyPlayer.exp.hacking = anyPlayer.hacking_exp;
anyPlayer.exp.strength = anyPlayer.strength_exp;
anyPlayer.exp.defense = anyPlayer.defense_exp;
anyPlayer.exp.dexterity = anyPlayer.dexterity_exp;
anyPlayer.exp.agility = anyPlayer.agility_exp;
anyPlayer.exp.charisma = anyPlayer.charisma_exp;
anyPlayer.exp.intelligence = anyPlayer.intelligence_exp;
};
// Fix bugged NFG accumulation in owned augmentations
if (ver < 17) {
let ownedNFGs = [...Player.augmentations];
ownedNFGs = ownedNFGs.filter((aug) => aug.name === AugmentationNames.NeuroFluxGovernor);
const newNFG = new PlayerOwnedAugmentation(AugmentationNames.NeuroFluxGovernor);
newNFG.level = 0;
for (const nfg of ownedNFGs) {
newNFG.level += nfg.level;
} }
if (ver < 25) {
const removePlayerFields = [ Player.augmentations = [
"hacking_chance_mult", ...Player.augmentations.filter((aug) => aug.name !== AugmentationNames.NeuroFluxGovernor),
"hacking_speed_mult", newNFG,
"hacking_money_mult", ];
"hacking_grow_mult",
"hacking_mult", v22PlayerBreak();
"strength_mult", Player.reapplyAllAugmentations(true);
"defense_mult", Player.reapplyAllSourceFiles();
"dexterity_mult", }
"agility_mult",
"charisma_mult", if (ver < 20) {
"hacking_exp_mult", // Create the darkweb for everyone but it won't be linked
"strength_exp_mult", const dw = GetServer(SpecialServers.DarkWeb);
"defense_exp_mult", if (!dw) {
"dexterity_exp_mult", const darkweb = safelyCreateUniqueServer({
"agility_exp_mult", ip: createUniqueRandomIp(),
"charisma_exp_mult", hostname: SpecialServers.DarkWeb,
"company_rep_mult", organizationName: "",
"faction_rep_mult", isConnectedTo: false,
"crime_money_mult", adminRights: false,
"crime_success_mult", purchasedByPlayer: false,
"work_money_mult", maxRam: 1,
"hacknet_node_money_mult", });
"hacknet_node_purchase_cost_mult", AddToAllServers(darkweb);
"hacknet_node_ram_cost_mult", }
"hacknet_node_core_cost_mult", }
"hacknet_node_level_cost_mult", if (ver < 21) {
"bladeburner_max_stamina_mult", // 2.0.0 work rework
"bladeburner_stamina_gain_mult", AwardNFG(10);
"bladeburner_analysis_mult", const create = anyPlayer["createProgramName"];
"bladeburner_success_chance_mult", if (create) Player.getHomeComputer().pushProgram(create);
"hacking_exp", const graft = anyPlayer["graftAugmentationName"];
"strength_exp", if (graft) Player.augmentations.push({ name: graft, level: 1 });
"defense_exp", }
"dexterity_exp", if (ver < 22) {
"agility_exp", v22PlayerBreak();
"charisma_exp", v2APIBreak();
"intelligence_exp", }
"companyName", if (ver < 23) {
"isWorking", anyPlayer.currentWork = null;
"workType", }
"workCostMult", if (ver < 24) {
"workExpMult", Player.getHomeComputer().scripts.forEach((s) => s.filename.endsWith(".ns") && (s.filename += ".js"));
"currentWorkFactionName", }
"currentWorkFactionDescription", if (ver < 25) {
"workHackExpGainRate", const removePlayerFields = [
"workStrExpGainRate", "hacking_chance_mult",
"workDefExpGainRate", "hacking_speed_mult",
"workDexExpGainRate", "hacking_money_mult",
"workAgiExpGainRate", "hacking_grow_mult",
"workChaExpGainRate", "hacking_mult",
"workRepGainRate", "strength_mult",
"workMoneyGainRate", "defense_mult",
"workMoneyLossRate", "dexterity_mult",
"workHackExpGained", "agility_mult",
"workStrExpGained", "charisma_mult",
"workDefExpGained", "hacking_exp_mult",
"workDexExpGained", "strength_exp_mult",
"workAgiExpGained", "defense_exp_mult",
"workChaExpGained", "dexterity_exp_mult",
"workRepGained", "agility_exp_mult",
"workMoneyGained", "charisma_exp_mult",
"createProgramName", "company_rep_mult",
"createProgramReqLvl", "faction_rep_mult",
"graftAugmentationName", "crime_money_mult",
"timeWorkedGraftAugmentation", "crime_success_mult",
"className", "work_money_mult",
"crimeType", "hacknet_node_money_mult",
"timeWorked", "hacknet_node_purchase_cost_mult",
"timeWorkedCreateProgram", "hacknet_node_ram_cost_mult",
"timeNeededToCompleteWork", "hacknet_node_core_cost_mult",
"factionWorkType", "hacknet_node_level_cost_mult",
"committingCrimeThruSingFn", "bladeburner_max_stamina_mult",
"singFnCrimeWorkerScript", "bladeburner_stamina_gain_mult",
"hacking", "bladeburner_analysis_mult",
"max_hp", "bladeburner_success_chance_mult",
"strength", "hacking_exp",
"defense", "strength_exp",
"dexterity", "defense_exp",
"agility", "dexterity_exp",
"charisma", "agility_exp",
"intelligence", "charisma_exp",
]; "intelligence_exp",
const removeSleeveFields = [ "companyName",
"gymStatType", "isWorking",
"bbAction", "workType",
"bbContract", "workCostMult",
"hacking", "workExpMult",
"strength", "currentWorkFactionName",
"defense", "currentWorkFactionDescription",
"dexterity", "workHackExpGainRate",
"agility", "workStrExpGainRate",
"charisma", "workDefExpGainRate",
"intelligence", "workDexExpGainRate",
"max_hp", "workAgiExpGainRate",
"hacking_exp", "workChaExpGainRate",
"strength_exp", "workRepGainRate",
"defense_exp", "workMoneyGainRate",
"dexterity_exp", "workMoneyLossRate",
"agility_exp", "workHackExpGained",
"charisma_exp", "workStrExpGained",
"intelligence_exp", "workDefExpGained",
"hacking_mult", "workDexExpGained",
"strength_mult", "workAgiExpGained",
"defense_mult", "workChaExpGained",
"dexterity_mult", "workRepGained",
"agility_mult", "workMoneyGained",
"charisma_mult", "createProgramName",
"hacking_exp_mult", "createProgramReqLvl",
"strength_exp_mult", "graftAugmentationName",
"defense_exp_mult", "timeWorkedGraftAugmentation",
"dexterity_exp_mult", "className",
"agility_exp_mult", "crimeType",
"charisma_exp_mult", "timeWorked",
"hacking_chance_mult", "timeWorkedCreateProgram",
"hacking_speed_mult", "timeNeededToCompleteWork",
"hacking_money_mult", "factionWorkType",
"hacking_grow_mult", "committingCrimeThruSingFn",
"company_rep_mult", "singFnCrimeWorkerScript",
"faction_rep_mult", "hacking",
"crime_money_mult", "max_hp",
"crime_success_mult", "strength",
"work_money_mult", "defense",
"hacknet_node_money_mult", "dexterity",
"hacknet_node_purchase_cost_mult", "agility",
"hacknet_node_ram_cost_mult", "charisma",
"hacknet_node_core_cost_mult", "intelligence",
"hacknet_node_level_cost_mult", ];
"bladeburner_max_stamina_mult", const removeSleeveFields = [
"bladeburner_stamina_gain_mult", "gymStatType",
"bladeburner_analysis_mult", "bbAction",
"bladeburner_success_chance_mult", "bbContract",
"className", "hacking",
"crimeType", "strength",
"currentTask", "defense",
"currentTaskLocation", "dexterity",
"currentTaskMaxTime", "agility",
"currentTaskTime", "charisma",
"earningsForSleeves", "intelligence",
"earningsForPlayer", "max_hp",
"earningsForTask", "hacking_exp",
"factionWorkType", "strength_exp",
"gainRatesForTask", "defense_exp",
"logs", "dexterity_exp",
]; "agility_exp",
let intExp = Number(anyPlayer.intelligence_exp); "charisma_exp",
"intelligence_exp",
"hacking_mult",
"strength_mult",
"defense_mult",
"dexterity_mult",
"agility_mult",
"charisma_mult",
"hacking_exp_mult",
"strength_exp_mult",
"defense_exp_mult",
"dexterity_exp_mult",
"agility_exp_mult",
"charisma_exp_mult",
"hacking_chance_mult",
"hacking_speed_mult",
"hacking_money_mult",
"hacking_grow_mult",
"company_rep_mult",
"faction_rep_mult",
"crime_money_mult",
"crime_success_mult",
"work_money_mult",
"hacknet_node_money_mult",
"hacknet_node_purchase_cost_mult",
"hacknet_node_ram_cost_mult",
"hacknet_node_core_cost_mult",
"hacknet_node_level_cost_mult",
"bladeburner_max_stamina_mult",
"bladeburner_stamina_gain_mult",
"bladeburner_analysis_mult",
"bladeburner_success_chance_mult",
"className",
"crimeType",
"currentTask",
"currentTaskLocation",
"currentTaskMaxTime",
"currentTaskTime",
"earningsForSleeves",
"earningsForPlayer",
"earningsForTask",
"factionWorkType",
"gainRatesForTask",
"logs",
];
let intExp = Number(anyPlayer.intelligence_exp);
if (isNaN(intExp)) intExp = 0;
anyPlayer.exp.intelligence += intExp;
for (const field of removePlayerFields) {
delete anyPlayer[field];
}
for (const sleeve of anyPlayer.sleeves) {
const anySleeve = sleeve as any;
let intExp = Number(anySleeve.intelligence_exp);
if (isNaN(intExp)) intExp = 0; if (isNaN(intExp)) intExp = 0;
anyPlayer.exp.intelligence += intExp; anySleeve.exp.intelligence += intExp;
for (const field of removePlayerFields) { for (const field of removeSleeveFields) {
delete anyPlayer[field]; delete sleeve[field];
}
for (const sleeve of anyPlayer.sleeves) {
const anySleeve = sleeve as any;
let intExp = Number(anySleeve.intelligence_exp);
if (isNaN(intExp)) intExp = 0;
anySleeve.exp.intelligence += intExp;
for (const field of removeSleeveFields) {
delete sleeve[field];
}
} }
} }
} }
if (ver < 27) {
// Prior to v2.2.0, sleeve shock was 0 to 100 internally but displayed as 100 to 0. This unifies them as 100 to 0.
for (const sleeve of Player.sleeves) sleeve.shock = 100 - sleeve.shock;
}
} }
function loadGame(saveString: string): boolean { function loadGame(saveString: string): boolean {
@@ -730,7 +733,7 @@ function loadGame(saveString: string): boolean {
try { try {
const ver = JSON.parse(saveObj.VersionSave, Reviver); const ver = JSON.parse(saveObj.VersionSave, Reviver);
evaluateVersionCompatibility(ver); evaluateVersionCompatibility(ver);
if (window.location.href.toLowerCase().includes("bitburner-beta")) { if (window.location.href.toLowerCase().includes("bitburner-src")) {
// Beta branch, always show changes // Beta branch, always show changes
createBetaUpdateText(); createBetaUpdateText();
} else if (ver !== CONSTANTS.VersionNumber) { } else if (ver !== CONSTANTS.VersionNumber) {

View File

@@ -10,7 +10,9 @@ export function dialogBoxCreate(txt: string | JSX.Element, html = false): void {
) : html ? ( ) : html ? (
<div dangerouslySetInnerHTML={{ __html: txt }}></div> <div dangerouslySetInnerHTML={{ __html: txt }}></div>
) : ( ) : (
<Typography component="span">{txt}</Typography> <Typography component="span" style={{ whiteSpace: "pre-wrap" }}>
{txt}
</Typography>
), ),
); );
} }

View File

@@ -2,12 +2,12 @@
import { Octokit } from "@octokit/rest"; import { Octokit } from "@octokit/rest";
import commandLineArgs from "command-line-args"; import commandLineArgs from "command-line-args";
const owner = "danielyxie"; const owner = "bitburner-official";
const repo = "bitburner"; const repo = "bitburner-src";
const cliArgs = commandLineArgs([ const cliArgs = commandLineArgs([
{ name: "from", alias: "f", type: String }, { name: "from", alias: "f", type: String },
{ name: "to", alias: "t", type: String }, { name: "to", alias: "t", type: String, defaultValue: undefined },
]); ]);
class MergeChangelog { class MergeChangelog {
@@ -75,18 +75,22 @@ class MergeChangelog {
const pulls = []; const pulls = [];
for (const entry of searchResults) { for (const entry of searchResults) {
const r = await this.octokit.rest.pulls await this.octokit.rest.pulls
.get({ .get({
owner, owner,
repo, repo,
pull_number: entry.number, pull_number: entry.number,
}) })
.then((response) => ({ .then((response) =>
...entry, pulls.push({
merge_commit_sha: response.data.merge_commit_sha, ...entry,
head_commit_sha: response.data.head.sha, merge_commit_sha: response.data.merge_commit_sha,
})); head_commit_sha: response.data.head.sha,
pulls.push(r); }),
)
.catch((e) => {
console.warn(`Encountered error retrieving pull: ${e}`);
});
await sleep(1000); await sleep(1000);
} }
return pulls; return pulls;
@@ -234,11 +238,17 @@ const sleep = async (wait) => {
}); });
}; };
const token = process.env.GITHUB_API_TOKEN;
if (!token) {
console.log("You need to set the env var GITHUB_API_TOKEN.");
process.exit(1);
}
const api = new MergeChangelog({ auth: process.env.GITHUB_API_TOKEN }); const api = new MergeChangelog({ auth: process.env.GITHUB_API_TOKEN });
if (!cliArgs.from || !cliArgs.to) { if (!cliArgs.from) {
console.error("USAGE: node index.js --from hash --to hash"); console.error("USAGE: node index.js --from hash [--to hash]");
process.exit(); process.exit();
} }
cliArgs.to ??= await api.getLastCommitByBranch("dev");
api.getChangelog(cliArgs.from, cliArgs.to).then((data) => { api.getChangelog(cliArgs.from, cliArgs.to).then((data) => {
console.log(data.log); console.log(data.log);
}); });