mirror of
https://github.com/bitburner-official/bitburner-src.git
synced 2025-02-16 18:12:24 +01:00
Merge branch 'dev' into feature/alert-close-browser
This commit is contained in:
@ -121,7 +121,29 @@ Inside the root of the repo run
|
|||||||
After that you can open any browser and navigate to `localhost:8000` and play the game.
|
After that you can open any browser and navigate to `localhost:8000` and play the game.
|
||||||
Saving a file will reload the game automatically.
|
Saving a file will reload the game automatically.
|
||||||
|
|
||||||
#### Submitting a Pull Request
|
|
||||||
|
### How to build the electron app
|
||||||
|
|
||||||
|
Tested on Node v16.13.1 (LTS) on Windows
|
||||||
|
These steps only work in a bash-like environment, like MinGW for Windows.
|
||||||
|
|
||||||
|
```sh
|
||||||
|
# Install the main game dependencies & build the app in debug mode
|
||||||
|
npm install
|
||||||
|
npm run build:dev
|
||||||
|
|
||||||
|
# Use electron-packager to build the app to the .build/ folder
|
||||||
|
npm run electron
|
||||||
|
|
||||||
|
# When launching the .exe directly, you'll need the steam_appid.txt file in the root
|
||||||
|
# If not using windows, change this line accordingly
|
||||||
|
cp .build/bitburner-win32-x64/resources/app/steam_appid.txt .build/bitburner-win32-x64/steam_appid.txt
|
||||||
|
|
||||||
|
# And run the game...
|
||||||
|
.build/bitburner-win32-x64/bitburner.exe
|
||||||
|
```
|
||||||
|
|
||||||
|
### Submitting a Pull Request
|
||||||
|
|
||||||
When submitting a pull request with your code contributions, please abide by
|
When submitting a pull request with your code contributions, please abide by
|
||||||
the following rules:
|
the following rules:
|
||||||
|
2
dist/bitburner.d.ts
vendored
2
dist/bitburner.d.ts
vendored
@ -3498,7 +3498,7 @@ export declare interface NS extends Singularity {
|
|||||||
* Returns 0 if the script does not exist.
|
* Returns 0 if the script does not exist.
|
||||||
*
|
*
|
||||||
* @param script - Filename of script. This is case-sensitive.
|
* @param script - Filename of script. This is case-sensitive.
|
||||||
* @param host - Host of target server the script is located on. This is optional, If it is not specified then the function will se the current server as the target server.
|
* @param host - Host of target server the script is located on. This is optional, If it is not specified then the function will use the current server as the target server.
|
||||||
* @returns Amount of RAM required to run the specified script on the target server, and 0 if the script does not exist.
|
* @returns Amount of RAM required to run the specified script on the target server, and 0 if the script does not exist.
|
||||||
*/
|
*/
|
||||||
getScriptRam(script: string, host?: string): number;
|
getScriptRam(script: string, host?: string): number;
|
||||||
|
30
electron/export.html
Normal file
30
electron/export.html
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8"/>
|
||||||
|
<title>Bitburner</title>
|
||||||
|
<link rel="stylesheet" href="main.css" />
|
||||||
|
<style>
|
||||||
|
body {
|
||||||
|
background-color: black;
|
||||||
|
color: #0c0;
|
||||||
|
}
|
||||||
|
|
||||||
|
div {
|
||||||
|
height: 100vh;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
h1 {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div>
|
||||||
|
<h1>Close me when operation is completed.</h1>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
@ -1,11 +1,12 @@
|
|||||||
/* eslint-disable no-process-exit */
|
/* eslint-disable no-process-exit */
|
||||||
/* eslint-disable @typescript-eslint/no-var-requires */
|
/* eslint-disable @typescript-eslint/no-var-requires */
|
||||||
const { app, dialog } = require("electron");
|
const { app, dialog, BrowserWindow } = require("electron");
|
||||||
const log = require("electron-log");
|
const log = require("electron-log");
|
||||||
const greenworks = require("./greenworks");
|
const greenworks = require("./greenworks");
|
||||||
const api = require("./api-server");
|
const api = require("./api-server");
|
||||||
const gameWindow = require("./gameWindow");
|
const gameWindow = require("./gameWindow");
|
||||||
const achievements = require("./achievements");
|
const achievements = require("./achievements");
|
||||||
|
const utils = require("./utils");
|
||||||
|
|
||||||
log.catchErrors();
|
log.catchErrors();
|
||||||
log.info(`Started app: ${JSON.stringify(process.argv)}`);
|
log.info(`Started app: ${JSON.stringify(process.argv)}`);
|
||||||
@ -100,7 +101,16 @@ global.app_handlers = {
|
|||||||
createWindow: startWindow,
|
createWindow: startWindow,
|
||||||
}
|
}
|
||||||
|
|
||||||
app.whenReady().then(() => {
|
app.whenReady().then(async () => {
|
||||||
log.info('Application is ready!');
|
log.info('Application is ready!');
|
||||||
startWindow(process.argv.includes("--no-scripts"));
|
|
||||||
|
if (process.argv.includes("--export-save")) {
|
||||||
|
const window = new BrowserWindow({ show: false });
|
||||||
|
await window.loadFile("export.html", false);
|
||||||
|
window.show();
|
||||||
|
setStopProcessHandler(app, window, true);
|
||||||
|
await utils.exportSave(window);
|
||||||
|
} else {
|
||||||
|
startWindow(process.argv.includes("--no-scripts"));
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
@ -62,7 +62,38 @@ function showErrorBox(title, error) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function exportSaveFromIndexedDb() {
|
||||||
|
return new Promise((resolve) => {
|
||||||
|
const dbRequest = indexedDB.open("bitburnerSave");
|
||||||
|
dbRequest.onsuccess = () => {
|
||||||
|
const db = dbRequest.result;
|
||||||
|
const transaction = db.transaction(['savestring'], "readonly");
|
||||||
|
const store = transaction.objectStore('savestring');
|
||||||
|
const request = store.get('save');
|
||||||
|
request.onsuccess = () => {
|
||||||
|
const file = new Blob([request.result], {type: 'text/plain'});
|
||||||
|
const a = document.createElement("a");
|
||||||
|
const url = URL.createObjectURL(file);
|
||||||
|
a.href = url;
|
||||||
|
a.download = 'save.json';
|
||||||
|
document.body.appendChild(a);
|
||||||
|
a.click();
|
||||||
|
setTimeout(function () {
|
||||||
|
document.body.removeChild(a);
|
||||||
|
window.URL.revokeObjectURL(url);
|
||||||
|
resolve();
|
||||||
|
}, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async function exportSave(window) {
|
||||||
|
await window.webContents
|
||||||
|
.executeJavaScript(`${exportSaveFromIndexedDb.toString()}; exportSaveFromIndexedDb();`, true);
|
||||||
|
}
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
reloadAndKill, showErrorBox,
|
reloadAndKill, showErrorBox, exportSave,
|
||||||
attachUnresponsiveAppHandler, detachUnresponsiveAppHandler,
|
attachUnresponsiveAppHandler, detachUnresponsiveAppHandler,
|
||||||
}
|
}
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
|
|
||||||
## NS.hackAnalyze() method
|
## NS.hackAnalyze() method
|
||||||
|
|
||||||
Get the percent of money stolen with a single thread.
|
Get the part of money stolen with a single thread.
|
||||||
|
|
||||||
<b>Signature:</b>
|
<b>Signature:</b>
|
||||||
|
|
||||||
@ -22,13 +22,13 @@ hackAnalyze(host: string): number;
|
|||||||
|
|
||||||
number
|
number
|
||||||
|
|
||||||
The percentage of money you will steal from the target server with a single hack.
|
The part of money you will steal from the target server with a single thread hack.
|
||||||
|
|
||||||
## Remarks
|
## Remarks
|
||||||
|
|
||||||
RAM cost: 1 GB
|
RAM cost: 1 GB
|
||||||
|
|
||||||
Returns the percentage of the specified server’s money you will steal with a single hack. This value is returned in percentage form, not decimal (Netscript functions typically return in decimal form, but not this one).
|
Returns the part of the specified server’s money you will steal with a single thread hack.
|
||||||
|
|
||||||
## Example
|
## Example
|
||||||
|
|
||||||
@ -36,6 +36,6 @@ Returns the percentage of the specified server’s money you will steal with a s
|
|||||||
```ts
|
```ts
|
||||||
//For example, assume the following returns 0.01:
|
//For example, assume the following returns 0.01:
|
||||||
hackAnalyze("foodnstuff");
|
hackAnalyze("foodnstuff");
|
||||||
//This means that if hack the foodnstuff server, then you will steal 1% of its total money. If you hack using N threads, then you will steal N*0.01 times its total money.
|
//This means that if hack the foodnstuff server using a single thread, then you will steal 1%, or 0.01 of its total money. If you hack using N threads, then you will steal N*0.01 times its total money.
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -111,7 +111,7 @@ export async function main(ns) {
|
|||||||
| [growthAnalyze(host, growthAmount, cores)](./bitburner.ns.growthanalyze.md) | Calculate the number of grow thread needed to grow a server by a certain multiplier. |
|
| [growthAnalyze(host, growthAmount, cores)](./bitburner.ns.growthanalyze.md) | Calculate the number of grow thread needed to grow a server by a certain multiplier. |
|
||||||
| [growthAnalyzeSecurity(threads)](./bitburner.ns.growthanalyzesecurity.md) | Calculate the security increase for a number of thread. |
|
| [growthAnalyzeSecurity(threads)](./bitburner.ns.growthanalyzesecurity.md) | Calculate the security increase for a number of thread. |
|
||||||
| [hack(host, opts)](./bitburner.ns.hack.md) | Steal a servers money. |
|
| [hack(host, opts)](./bitburner.ns.hack.md) | Steal a servers money. |
|
||||||
| [hackAnalyze(host)](./bitburner.ns.hackanalyze.md) | Get the percent of money stolen with a single thread. |
|
| [hackAnalyze(host)](./bitburner.ns.hackanalyze.md) | Get the part of money stolen with a single thread. |
|
||||||
| [hackAnalyzeChance(host)](./bitburner.ns.hackanalyzechance.md) | Get the chance of successfully hacking a server. |
|
| [hackAnalyzeChance(host)](./bitburner.ns.hackanalyzechance.md) | Get the chance of successfully hacking a server. |
|
||||||
| [hackAnalyzeSecurity(threads)](./bitburner.ns.hackanalyzesecurity.md) | Get the security increase for a number of thread. |
|
| [hackAnalyzeSecurity(threads)](./bitburner.ns.hackanalyzesecurity.md) | Get the security increase for a number of thread. |
|
||||||
| [hackAnalyzeThreads(host, hackAmount)](./bitburner.ns.hackanalyzethreads.md) | Predict the effect of hack. |
|
| [hackAnalyzeThreads(host, hackAmount)](./bitburner.ns.hackanalyzethreads.md) | Predict the effect of hack. |
|
||||||
|
@ -30,7 +30,7 @@ RAM cost: 5 GB
|
|||||||
|
|
||||||
This function is used to automatically attempt to commit crimes. If you are already in the middle of some ‘working’ action (such as working for a company or training at a gym), then running this function will automatically cancel that action and give you your earnings.
|
This function is used to automatically attempt to commit crimes. If you are already in the middle of some ‘working’ action (such as working for a company or training at a gym), then running this function will automatically cancel that action and give you your earnings.
|
||||||
|
|
||||||
This function returns the number of seconds it takes to attempt the specified crime (e.g It takes 60 seconds to attempt the ‘Rob Store’ crime, so running `commitCrime('rob store')` will return 60).
|
This function returns the number of milliseconds it takes to attempt the specified crime (e.g It takes 60 seconds to attempt the ‘Rob Store’ crime, so running `commitCrime('rob store')` will return 60,000).
|
||||||
|
|
||||||
Warning: I do not recommend using the time returned from this function to try and schedule your crime attempts. Instead, I would use the isBusy Singularity function to check whether you have finished attempting a crime. This is because although the game sets a certain crime to be X amount of seconds, there is no guarantee that your browser will follow that time limit.
|
Warning: I do not recommend using the time returned from this function to try and schedule your crime attempts. Instead, I would use the isBusy Singularity function to check whether you have finished attempting a crime. This is because although the game sets a certain crime to be X amount of seconds, there is no guarantee that your browser will follow that time limit.
|
||||||
|
|
||||||
|
@ -16,4 +16,10 @@ cp main.css .package/main.css
|
|||||||
cp dist/vendor.bundle.js .package/dist/vendor.bundle.js
|
cp dist/vendor.bundle.js .package/dist/vendor.bundle.js
|
||||||
cp main.bundle.js .package/main.bundle.js
|
cp main.bundle.js .package/main.bundle.js
|
||||||
|
|
||||||
|
# Install electron sub-dependencies
|
||||||
|
cd electron
|
||||||
|
npm install
|
||||||
|
cd ..
|
||||||
|
|
||||||
|
# And finally build the app.
|
||||||
npm run electron:packager
|
npm run electron:packager
|
||||||
|
@ -38,13 +38,14 @@ export function printAliases(): void {
|
|||||||
export function parseAliasDeclaration(dec: string, global = false): boolean {
|
export function parseAliasDeclaration(dec: string, global = false): boolean {
|
||||||
const re = /^([\w|!|%|,|@|-]+)=(("(.+)")|('(.+)'))$/;
|
const re = /^([\w|!|%|,|@|-]+)=(("(.+)")|('(.+)'))$/;
|
||||||
const matches = dec.match(re);
|
const matches = dec.match(re);
|
||||||
if (matches == null || matches.length != 3) {
|
if (matches == null || matches.length != 7) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (global) {
|
if (global) {
|
||||||
addGlobalAlias(matches[1], matches[2]);
|
addGlobalAlias(matches[1], matches[4] || matches[6]);
|
||||||
} else {
|
} else {
|
||||||
addAlias(matches[1], matches[2]);
|
addAlias(matches[1], matches[4] || matches[6]);
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -1925,7 +1925,7 @@ function initAugmentations(): void {
|
|||||||
repCost: 7.5e3,
|
repCost: 7.5e3,
|
||||||
moneyCost: 3e7,
|
moneyCost: 3e7,
|
||||||
info:
|
info:
|
||||||
"A tiny chip that sits behind the retinae. This implant lets the" + "user visually detect infrared radiation.",
|
"A tiny chip that sits behind the retinae. This implant lets the user visually detect infrared radiation.",
|
||||||
crime_success_mult: 1.25,
|
crime_success_mult: 1.25,
|
||||||
crime_money_mult: 1.1,
|
crime_money_mult: 1.1,
|
||||||
dexterity_mult: 1.1,
|
dexterity_mult: 1.1,
|
||||||
|
@ -108,31 +108,22 @@ function WarehouseRoot(props: IProps): React.ReactElement {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let breakdown = <></>;
|
const breakdownItems: string[] = [];
|
||||||
for (const matName in props.warehouse.materials) {
|
for (const matName in props.warehouse.materials) {
|
||||||
const mat = props.warehouse.materials[matName];
|
const mat = props.warehouse.materials[matName];
|
||||||
if (!MaterialSizes.hasOwnProperty(matName)) continue;
|
if (!MaterialSizes.hasOwnProperty(matName)) continue;
|
||||||
if (mat.qty === 0) continue;
|
if (mat.qty === 0) continue;
|
||||||
breakdown = (
|
breakdownItems.push(`${matName}: ${numeralWrapper.format(mat.qty * MaterialSizes[matName], "0,0.0")}`);
|
||||||
<>
|
|
||||||
{breakdown}
|
|
||||||
{matName}: {numeralWrapper.format(mat.qty * MaterialSizes[matName], "0,0.0")}
|
|
||||||
<br />
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const prodName in division.products) {
|
for (const prodName in division.products) {
|
||||||
const prod = division.products[prodName];
|
const prod = division.products[prodName];
|
||||||
if (prod === undefined) continue;
|
if (prod === undefined) continue;
|
||||||
breakdown = (
|
breakdownItems.push(`${prodName}: ${numeralWrapper.format(prod.data[props.warehouse.loc][0] * prod.siz, "0,0.0")}`);
|
||||||
<>
|
|
||||||
{breakdown}
|
|
||||||
{prodName}: {numeralWrapper.format(prod.data[props.warehouse.loc][0] * prod.siz, "0,0.0")}
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const breakdown = <>{breakdownItems.join('<br />')}</>
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Paper>
|
<Paper>
|
||||||
<Box display="flex" alignItems="center">
|
<Box display="flex" alignItems="center">
|
||||||
|
@ -29,6 +29,7 @@ import { GetServer } from "../../Server/AllServers";
|
|||||||
import { CorruptableText } from "../../ui/React/CorruptableText";
|
import { CorruptableText } from "../../ui/React/CorruptableText";
|
||||||
import { use } from "../../ui/Context";
|
import { use } from "../../ui/Context";
|
||||||
import { serverMetadata } from "../../Server/data/servers";
|
import { serverMetadata } from "../../Server/data/servers";
|
||||||
|
import { Tooltip } from "@mui/material";
|
||||||
|
|
||||||
type IProps = {
|
type IProps = {
|
||||||
loc: Location;
|
loc: Location;
|
||||||
@ -92,8 +93,11 @@ export function GenericLocation({ loc }: IProps): React.ReactElement {
|
|||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Button onClick={() => router.toCity()}>Return to World</Button>
|
<Button onClick={() => router.toCity()}>Return to World</Button>
|
||||||
<Typography variant="h4">
|
<Typography variant="h4" sx={{ mt: 1 }}>
|
||||||
{backdoorInstalled && !Settings.DisableTextEffects ? <CorruptableText content={loc.name} /> : loc.name}
|
{backdoorInstalled && !Settings.DisableTextEffects ? (
|
||||||
|
<Tooltip title={`Backdoor installed on ${loc.name}.`}>
|
||||||
|
<span><CorruptableText content={loc.name} /></span>
|
||||||
|
</Tooltip>) : loc.name}
|
||||||
</Typography>
|
</Typography>
|
||||||
{locContent}
|
{locContent}
|
||||||
</>
|
</>
|
||||||
|
@ -1009,7 +1009,7 @@ export function NetscriptFunctions(workerScript: WorkerScript): NS {
|
|||||||
workerScript.log("spawn", () => "Exiting...");
|
workerScript.log("spawn", () => "Exiting...");
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
kill: function (filename: any, hostname: any, ...scriptArgs: any): any {
|
kill: function (filename: any, hostname?: any, ...scriptArgs: any): any {
|
||||||
updateDynamicRam("kill", getRamCost("kill"));
|
updateDynamicRam("kill", getRamCost("kill"));
|
||||||
|
|
||||||
let res;
|
let res;
|
||||||
@ -2025,7 +2025,7 @@ export function NetscriptFunctions(workerScript: WorkerScript): NS {
|
|||||||
|
|
||||||
return calculateWeakenTime(server, Player) * 1000;
|
return calculateWeakenTime(server, Player) * 1000;
|
||||||
},
|
},
|
||||||
getScriptIncome: function (scriptname: any, hostname: any, ...args: any[]): any {
|
getScriptIncome: function (scriptname?: any, hostname?: any, ...args: any[]): any {
|
||||||
updateDynamicRam("getScriptIncome", getRamCost("getScriptIncome"));
|
updateDynamicRam("getScriptIncome", getRamCost("getScriptIncome"));
|
||||||
if (arguments.length === 0) {
|
if (arguments.length === 0) {
|
||||||
const res = [];
|
const res = [];
|
||||||
@ -2054,7 +2054,7 @@ export function NetscriptFunctions(workerScript: WorkerScript): NS {
|
|||||||
return runningScriptObj.onlineMoneyMade / runningScriptObj.onlineRunningTime;
|
return runningScriptObj.onlineMoneyMade / runningScriptObj.onlineRunningTime;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
getScriptExpGain: function (scriptname: any, hostname: any, ...args: any[]): any {
|
getScriptExpGain: function (scriptname?: any, hostname?: any, ...args: any[]): any {
|
||||||
updateDynamicRam("getScriptExpGain", getRamCost("getScriptExpGain"));
|
updateDynamicRam("getScriptExpGain", getRamCost("getScriptExpGain"));
|
||||||
if (arguments.length === 0) {
|
if (arguments.length === 0) {
|
||||||
let total = 0;
|
let total = 0;
|
||||||
|
@ -1690,6 +1690,11 @@ export function applyForJob(this: IPlayer, entryPosType: CompanyPosition, sing =
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check if this company has the position
|
||||||
|
if (!company.hasPosition(pos)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
const newPos = getNextCompanyPositionHelper(pos);
|
const newPos = getNextCompanyPositionHelper(pos);
|
||||||
if (newPos == null) {
|
if (newPos == null) {
|
||||||
@ -1863,9 +1868,14 @@ export function applyForAgentJob(this: IPlayer, sing = false): boolean {
|
|||||||
|
|
||||||
export function applyForEmployeeJob(this: IPlayer, sing = false): boolean {
|
export function applyForEmployeeJob(this: IPlayer, sing = false): boolean {
|
||||||
const company = Companies[this.location]; //Company being applied to
|
const company = Companies[this.location]; //Company being applied to
|
||||||
if (this.isQualified(company, CompanyPositions[posNames.MiscCompanyPositions[1]])) {
|
const position = posNames.MiscCompanyPositions[1];
|
||||||
|
// Check if this company has the position
|
||||||
|
if (!company.hasPosition(position)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (this.isQualified(company, CompanyPositions[position])) {
|
||||||
this.companyName = company.name;
|
this.companyName = company.name;
|
||||||
this.jobs[company.name] = posNames.MiscCompanyPositions[1];
|
this.jobs[company.name] = position;
|
||||||
if (!sing) {
|
if (!sing) {
|
||||||
dialogBoxCreate("Congratulations, you are now employed at " + this.location);
|
dialogBoxCreate("Congratulations, you are now employed at " + this.location);
|
||||||
}
|
}
|
||||||
@ -1882,8 +1892,13 @@ export function applyForEmployeeJob(this: IPlayer, sing = false): boolean {
|
|||||||
|
|
||||||
export function applyForPartTimeEmployeeJob(this: IPlayer, sing = false): boolean {
|
export function applyForPartTimeEmployeeJob(this: IPlayer, sing = false): boolean {
|
||||||
const company = Companies[this.location]; //Company being applied to
|
const company = Companies[this.location]; //Company being applied to
|
||||||
if (this.isQualified(company, CompanyPositions[posNames.PartTimeCompanyPositions[1]])) {
|
const position = posNames.PartTimeCompanyPositions[1];
|
||||||
this.jobs[company.name] = posNames.PartTimeCompanyPositions[1];
|
// Check if this company has the position
|
||||||
|
if (!company.hasPosition(position)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (this.isQualified(company, CompanyPositions[position])) {
|
||||||
|
this.jobs[company.name] = position;
|
||||||
if (!sing) {
|
if (!sing) {
|
||||||
dialogBoxCreate("Congratulations, you are now employed part-time at " + this.location);
|
dialogBoxCreate("Congratulations, you are now employed part-time at " + this.location);
|
||||||
}
|
}
|
||||||
@ -1900,9 +1915,14 @@ export function applyForPartTimeEmployeeJob(this: IPlayer, sing = false): boolea
|
|||||||
|
|
||||||
export function applyForWaiterJob(this: IPlayer, sing = false): boolean {
|
export function applyForWaiterJob(this: IPlayer, sing = false): boolean {
|
||||||
const company = Companies[this.location]; //Company being applied to
|
const company = Companies[this.location]; //Company being applied to
|
||||||
if (this.isQualified(company, CompanyPositions[posNames.MiscCompanyPositions[0]])) {
|
const position = posNames.MiscCompanyPositions[0];
|
||||||
|
// Check if this company has the position
|
||||||
|
if (!company.hasPosition(position)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (this.isQualified(company, CompanyPositions[position])) {
|
||||||
this.companyName = company.name;
|
this.companyName = company.name;
|
||||||
this.jobs[company.name] = posNames.MiscCompanyPositions[0];
|
this.jobs[company.name] = position;
|
||||||
if (!sing) {
|
if (!sing) {
|
||||||
dialogBoxCreate("Congratulations, you are now employed as a waiter at " + this.location);
|
dialogBoxCreate("Congratulations, you are now employed as a waiter at " + this.location);
|
||||||
}
|
}
|
||||||
@ -1917,9 +1937,14 @@ export function applyForWaiterJob(this: IPlayer, sing = false): boolean {
|
|||||||
|
|
||||||
export function applyForPartTimeWaiterJob(this: IPlayer, sing = false): boolean {
|
export function applyForPartTimeWaiterJob(this: IPlayer, sing = false): boolean {
|
||||||
const company = Companies[this.location]; //Company being applied to
|
const company = Companies[this.location]; //Company being applied to
|
||||||
if (this.isQualified(company, CompanyPositions[posNames.PartTimeCompanyPositions[0]])) {
|
const position = posNames.PartTimeCompanyPositions[0];
|
||||||
|
// Check if this company has the position
|
||||||
|
if (!company.hasPosition(position)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (this.isQualified(company, CompanyPositions[position])) {
|
||||||
this.companyName = company.name;
|
this.companyName = company.name;
|
||||||
this.jobs[company.name] = posNames.PartTimeCompanyPositions[0];
|
this.jobs[company.name] = position;
|
||||||
if (!sing) {
|
if (!sing) {
|
||||||
dialogBoxCreate("Congratulations, you are now employed as a part-time waiter at " + this.location);
|
dialogBoxCreate("Congratulations, you are now employed as a part-time waiter at " + this.location);
|
||||||
}
|
}
|
||||||
|
11
src/ScriptEditor/NetscriptDefinitions.d.ts
vendored
11
src/ScriptEditor/NetscriptDefinitions.d.ts
vendored
@ -1767,7 +1767,7 @@ export interface Singularity {
|
|||||||
*
|
*
|
||||||
* This function returns the number of milliseconds it takes to attempt the
|
* This function returns the number of milliseconds it takes to attempt the
|
||||||
* specified crime (e.g It takes 60 seconds to attempt the ‘Rob Store’ crime,
|
* specified crime (e.g It takes 60 seconds to attempt the ‘Rob Store’ crime,
|
||||||
* so running `commitCrime('rob store')` will return 60000).
|
* so running `commitCrime('rob store')` will return 60,000).
|
||||||
*
|
*
|
||||||
* Warning: I do not recommend using the time returned from this function to try
|
* Warning: I do not recommend using the time returned from this function to try
|
||||||
* and schedule your crime attempts. Instead, I would use the isBusy Singularity
|
* and schedule your crime attempts. Instead, I would use the isBusy Singularity
|
||||||
@ -4680,8 +4680,9 @@ export interface NS extends Singularity {
|
|||||||
* @param args - Arguments to identify which script to kill.
|
* @param args - Arguments to identify which script to kill.
|
||||||
* @returns True if the script is successfully killed, and false otherwise.
|
* @returns True if the script is successfully killed, and false otherwise.
|
||||||
*/
|
*/
|
||||||
kill(script: string | number, host: string, ...args: string[]): boolean;
|
kill(script: number): boolean;
|
||||||
|
kill(script: string, host: string, ...args: string[]): boolean;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Terminate all scripts on a server.
|
* Terminate all scripts on a server.
|
||||||
* @remarks
|
* @remarks
|
||||||
@ -5543,7 +5544,8 @@ export interface NS extends Singularity {
|
|||||||
* @param args - Arguments that the script is running with.
|
* @param args - Arguments that the script is running with.
|
||||||
* @returns Amount of income the specified script generates while online.
|
* @returns Amount of income the specified script generates while online.
|
||||||
*/
|
*/
|
||||||
getScriptIncome(script: string, host: string, ...args: string[]): number | [number, number];
|
getScriptIncome(): [number, number];
|
||||||
|
getScriptIncome(script: string, host: string, ...args: string[]): number;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the exp gain of a script.
|
* Get the exp gain of a script.
|
||||||
@ -5562,6 +5564,7 @@ export interface NS extends Singularity {
|
|||||||
* @param args - Arguments that the script is running with.
|
* @param args - Arguments that the script is running with.
|
||||||
* @returns Amount of hacking experience the specified script generates while online.
|
* @returns Amount of hacking experience the specified script generates while online.
|
||||||
*/
|
*/
|
||||||
|
getScriptExpGain(): number;
|
||||||
getScriptExpGain(script: string, host: string, ...args: string[]): number;
|
getScriptExpGain(script: string, host: string, ...args: string[]): number;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -178,7 +178,12 @@ export function Root(props: IProps): React.ReactElement {
|
|||||||
save();
|
save();
|
||||||
});
|
});
|
||||||
MonacoVim.VimMode.Vim.defineEx("quit", "q", function () {
|
MonacoVim.VimMode.Vim.defineEx("quit", "q", function () {
|
||||||
|
props.router.toTerminal();
|
||||||
|
});
|
||||||
|
// "wqriteandquit" is not a typo, prefix must be found in full string
|
||||||
|
MonacoVim.VimMode.Vim.defineEx("wqriteandquit", "wq", function () {
|
||||||
save();
|
save();
|
||||||
|
props.router.toTerminal();
|
||||||
});
|
});
|
||||||
editor.focus();
|
editor.focus();
|
||||||
});
|
});
|
||||||
|
@ -113,6 +113,11 @@ interface IDefaultSettings {
|
|||||||
* Theme colors
|
* Theme colors
|
||||||
*/
|
*/
|
||||||
theme: ITheme;
|
theme: ITheme;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Use GiB instead of GB
|
||||||
|
*/
|
||||||
|
UseIEC60027_2: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -160,6 +165,7 @@ export const defaultSettings: IDefaultSettings = {
|
|||||||
SuppressBladeburnerPopup: false,
|
SuppressBladeburnerPopup: false,
|
||||||
SuppressTIXPopup: false,
|
SuppressTIXPopup: false,
|
||||||
SuppressSavedGameToast: false,
|
SuppressSavedGameToast: false,
|
||||||
|
UseIEC60027_2: false,
|
||||||
|
|
||||||
theme: defaultTheme,
|
theme: defaultTheme,
|
||||||
};
|
};
|
||||||
@ -192,6 +198,7 @@ export const Settings: ISettings & ISelfInitializer & ISelfLoading = {
|
|||||||
SuppressBladeburnerPopup: defaultSettings.SuppressBladeburnerPopup,
|
SuppressBladeburnerPopup: defaultSettings.SuppressBladeburnerPopup,
|
||||||
SuppressTIXPopup: defaultSettings.SuppressTIXPopup,
|
SuppressTIXPopup: defaultSettings.SuppressTIXPopup,
|
||||||
SuppressSavedGameToast: defaultSettings.SuppressSavedGameToast,
|
SuppressSavedGameToast: defaultSettings.SuppressSavedGameToast,
|
||||||
|
UseIEC60027_2: defaultSettings.UseIEC60027_2,
|
||||||
MonacoTheme: "monokai",
|
MonacoTheme: "monokai",
|
||||||
MonacoInsertSpaces: false,
|
MonacoInsertSpaces: false,
|
||||||
MonacoFontSize: 20,
|
MonacoFontSize: 20,
|
||||||
|
@ -408,4 +408,206 @@ export const getPredefinedThemes = (): IMap<IPredefinedTheme> => ({
|
|||||||
button: "#000000",
|
button: "#000000",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
|
Discord: {
|
||||||
|
credit: "Thermite",
|
||||||
|
description: "Discord inspired theme",
|
||||||
|
reference: "https://discord.com/channels/415207508303544321/921991895230611466/924305252017143818",
|
||||||
|
colors: {
|
||||||
|
primarylight: "#7389DC",
|
||||||
|
primary: "#7389DC",
|
||||||
|
primarydark: "#5964F1",
|
||||||
|
successlight: "#00CC00",
|
||||||
|
success: "#20DF20",
|
||||||
|
successdark: "#0CB80C",
|
||||||
|
errorlight: "#EA5558",
|
||||||
|
error: "#EC4145",
|
||||||
|
errordark: "#E82528",
|
||||||
|
secondarylight: "#C3C3C3",
|
||||||
|
secondary: "#9C9C9C",
|
||||||
|
secondarydark: "#4E4E4E",
|
||||||
|
warninglight: "#ff0",
|
||||||
|
warning: "#cc0",
|
||||||
|
warningdark: "#990",
|
||||||
|
infolight: "#69f",
|
||||||
|
info: "#36c",
|
||||||
|
infodark: "#1C4FB3",
|
||||||
|
welllight: "#999999",
|
||||||
|
well: "#35383C",
|
||||||
|
white: "#FFFFFF",
|
||||||
|
black: "#202225",
|
||||||
|
hp: "#FF5656",
|
||||||
|
money: "#43FF43",
|
||||||
|
hack: "#FFAB3D",
|
||||||
|
combat: "#8A90FD",
|
||||||
|
cha: "#FF51D9",
|
||||||
|
int: "#6495ed",
|
||||||
|
rep: "#FFFF30",
|
||||||
|
disabled: "#474B51",
|
||||||
|
backgroundprimary: "#2F3136",
|
||||||
|
backgroundsecondary: "#35393E",
|
||||||
|
button: "#333",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
"One Dark": {
|
||||||
|
credit: "Dexalt142",
|
||||||
|
reference: "https://discord.com/channels/415207508303544321/921991895230611466/924650660694208512",
|
||||||
|
colors: {
|
||||||
|
primarylight: "#98C379",
|
||||||
|
primary: "#98C379",
|
||||||
|
primarydark: "#98C379",
|
||||||
|
successlight: "#98C379",
|
||||||
|
success: "#98C379",
|
||||||
|
successdark: "#98C379",
|
||||||
|
errorlight: "#E06C75",
|
||||||
|
error: "#BE5046",
|
||||||
|
errordark: "#BE5046",
|
||||||
|
secondarylight: "#AAA",
|
||||||
|
secondary: "#888",
|
||||||
|
secondarydark: "#666",
|
||||||
|
warninglight: "#E5C07B",
|
||||||
|
warning: "#E5C07B",
|
||||||
|
warningdark: "#D19A66",
|
||||||
|
infolight: "#61AFEF",
|
||||||
|
info: "#61AFEF",
|
||||||
|
infodark: "#61AFEF",
|
||||||
|
welllight: "#4B5263",
|
||||||
|
well: "#282C34",
|
||||||
|
white: "#ABB2BF",
|
||||||
|
black: "#282C34",
|
||||||
|
hp: "#E06C75",
|
||||||
|
money: "#E5C07B",
|
||||||
|
hack: "#98C379",
|
||||||
|
combat: "#ABB2BF",
|
||||||
|
cha: "#C678DD",
|
||||||
|
int: "#61AFEF",
|
||||||
|
rep: "#ABB2BF",
|
||||||
|
disabled: "#56B6C2",
|
||||||
|
backgroundprimary: "#282C34",
|
||||||
|
backgroundsecondary: "#21252B",
|
||||||
|
button: "#4B5263",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
"Muted Gold & Blue": {
|
||||||
|
credit: "Sloth",
|
||||||
|
reference: "https://discord.com/channels/415207508303544321/921991895230611466/924672660758208563",
|
||||||
|
colors: {
|
||||||
|
primarylight: "#E3B54A",
|
||||||
|
primary: "#CAA243",
|
||||||
|
primarydark: "#7E6937",
|
||||||
|
successlight: "#82FF82",
|
||||||
|
success: "#6FDA6F",
|
||||||
|
successdark: "#64C364",
|
||||||
|
errorlight: "#FD5555",
|
||||||
|
error: "#D84A4A",
|
||||||
|
errordark: "#AC3939",
|
||||||
|
secondarylight: "#D8D0B8",
|
||||||
|
secondary: "#B1AA95",
|
||||||
|
secondarydark: "#736E5E",
|
||||||
|
warninglight: "#ff0",
|
||||||
|
warning: "#cc0",
|
||||||
|
warningdark: "#990",
|
||||||
|
infolight: "#69f",
|
||||||
|
info: "#36c",
|
||||||
|
infodark: "#039",
|
||||||
|
welllight: "#444",
|
||||||
|
well: "#111111",
|
||||||
|
white: "#fff",
|
||||||
|
black: "#070300",
|
||||||
|
hp: "#dd3434",
|
||||||
|
money: "#ffd700",
|
||||||
|
hack: "#adff2f",
|
||||||
|
combat: "#faffdf",
|
||||||
|
cha: "#a671d1",
|
||||||
|
int: "#6495ed",
|
||||||
|
rep: "#faffdf",
|
||||||
|
disabled: "#66cfbc",
|
||||||
|
backgroundprimary: "#0A0A0E",
|
||||||
|
backgroundsecondary: "#0E0E10",
|
||||||
|
button: "#222222",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
"Default Lite": {
|
||||||
|
credit: "NmuGmu",
|
||||||
|
description: "Less eye-straining default theme",
|
||||||
|
reference: "https://discord.com/channels/415207508303544321/921991895230611466/925263801564151888",
|
||||||
|
colors: {
|
||||||
|
primarylight: "#28CF28",
|
||||||
|
primary: "#21A821",
|
||||||
|
primarydark: "#177317",
|
||||||
|
successlight: "#1CFF1C",
|
||||||
|
success: "#16CA16",
|
||||||
|
successdark: "#0D910D",
|
||||||
|
errorlight: "#FF3B3B",
|
||||||
|
error: "#C32D2D",
|
||||||
|
errordark: "#8E2121",
|
||||||
|
secondarylight: "#B3B3B3",
|
||||||
|
secondary: "#838383",
|
||||||
|
secondarydark: "#676767",
|
||||||
|
warninglight: "#FFFF3A",
|
||||||
|
warning: "#C3C32A",
|
||||||
|
warningdark: "#8C8C1E",
|
||||||
|
infolight: "#64CBFF",
|
||||||
|
info: "#3399CC",
|
||||||
|
infodark: "#246D91",
|
||||||
|
welllight: "#404040",
|
||||||
|
well: "#1C1C1C",
|
||||||
|
white: "#C3C3C3",
|
||||||
|
black: "#0A0B0B",
|
||||||
|
hp: "#C62E2E",
|
||||||
|
money: "#D6BB27",
|
||||||
|
hack: "#ADFF2F",
|
||||||
|
combat: "#E8EDCD",
|
||||||
|
cha: "#8B5FAF",
|
||||||
|
int: "#537CC8",
|
||||||
|
rep: "#E8EDCD",
|
||||||
|
disabled: "#5AB5A5",
|
||||||
|
backgroundprimary: "#0C0D0E",
|
||||||
|
backgroundsecondary: "#121415",
|
||||||
|
button: "#252829",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
Light: {
|
||||||
|
credit: "matt",
|
||||||
|
reference: "https://discord.com/channels/415207508303544321/921991895230611466/926114005456658432",
|
||||||
|
colors: {
|
||||||
|
primarylight: "#535353",
|
||||||
|
primary: "#1A1A1A",
|
||||||
|
primarydark: "#0d0d0d",
|
||||||
|
successlight: "#63c439",
|
||||||
|
success: "#428226",
|
||||||
|
successdark: "#2E5A1B",
|
||||||
|
errorlight: "#df7051",
|
||||||
|
error: "#C94824",
|
||||||
|
errordark: "#91341B",
|
||||||
|
secondarylight: "#b3b3b3",
|
||||||
|
secondary: "#9B9B9B",
|
||||||
|
secondarydark: "#7A7979",
|
||||||
|
warninglight: "#e8d464",
|
||||||
|
warning: "#C6AD20",
|
||||||
|
warningdark: "#9F8A16",
|
||||||
|
infolight: "#6299cf",
|
||||||
|
info: "#3778B7",
|
||||||
|
infodark: "#30689C",
|
||||||
|
welllight: "#f9f9f9",
|
||||||
|
well: "#eaeaea",
|
||||||
|
white: "#F7F7F7",
|
||||||
|
black: "#F7F7F7",
|
||||||
|
hp: "#BF5C41",
|
||||||
|
money: "#E1B121",
|
||||||
|
hack: "#47BC38",
|
||||||
|
combat: "#656262",
|
||||||
|
cha: "#A568AC",
|
||||||
|
int: "#889BCF",
|
||||||
|
rep: "#656262",
|
||||||
|
disabled: "#70B4BF",
|
||||||
|
backgroundprimary: "#F7F7F7",
|
||||||
|
backgroundsecondary: "#f9f9f9",
|
||||||
|
button: "#eaeaea",
|
||||||
|
},
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
@ -32,10 +32,10 @@ StockSymbols[LocationName.VolhavenCompuTek] = "CTK";
|
|||||||
StockSymbols[LocationName.AevumNetLinkTechnologies] = "NTLK";
|
StockSymbols[LocationName.AevumNetLinkTechnologies] = "NTLK";
|
||||||
StockSymbols[LocationName.IshimaOmegaSoftware] = "OMGA";
|
StockSymbols[LocationName.IshimaOmegaSoftware] = "OMGA";
|
||||||
StockSymbols[LocationName.Sector12FoodNStuff] = "FNS";
|
StockSymbols[LocationName.Sector12FoodNStuff] = "FNS";
|
||||||
|
StockSymbols[LocationName.Sector12JoesGuns] = "JGN";
|
||||||
|
|
||||||
// Stocks for other companies
|
// Stocks for other companies
|
||||||
StockSymbols["Sigma Cosmetics"] = "SGC";
|
StockSymbols["Sigma Cosmetics"] = "SGC";
|
||||||
StockSymbols["Joes Guns"] = "JGN";
|
|
||||||
StockSymbols["Catalyst Ventures"] = "CTYS";
|
StockSymbols["Catalyst Ventures"] = "CTYS";
|
||||||
StockSymbols["Microdyne Technologies"] = "MDYN";
|
StockSymbols["Microdyne Technologies"] = "MDYN";
|
||||||
StockSymbols["Titan Laboratories"] = "TITN";
|
StockSymbols["Titan Laboratories"] = "TITN";
|
||||||
|
@ -176,7 +176,7 @@ export function InfoAndPurchases(props: IProps): React.ReactElement {
|
|||||||
<>
|
<>
|
||||||
<Typography>Welcome to the World Stock Exchange (WSE)!</Typography>
|
<Typography>Welcome to the World Stock Exchange (WSE)!</Typography>
|
||||||
<Link href={documentationLink} target={"_blank"}>
|
<Link href={documentationLink} target={"_blank"}>
|
||||||
Investopedia
|
<Typography>Investopedia</Typography>
|
||||||
</Link>
|
</Link>
|
||||||
<br />
|
<br />
|
||||||
<PurchaseWseAccountButton {...props} />
|
<PurchaseWseAccountButton {...props} />
|
||||||
|
@ -28,6 +28,7 @@ import { FileDiagnosticModal } from "../../Diagnostic/FileDiagnosticModal";
|
|||||||
import { dialogBoxCreate } from "./DialogBox";
|
import { dialogBoxCreate } from "./DialogBox";
|
||||||
import { ConfirmationModal } from "./ConfirmationModal";
|
import { ConfirmationModal } from "./ConfirmationModal";
|
||||||
import { ThemeEditorModal } from "./ThemeEditorModal";
|
import { ThemeEditorModal } from "./ThemeEditorModal";
|
||||||
|
import { SnackbarEvents } from "./Snackbar";
|
||||||
|
|
||||||
import { Settings } from "../../Settings/Settings";
|
import { Settings } from "../../Settings/Settings";
|
||||||
import { save, deleteGame } from "../../db";
|
import { save, deleteGame } from "../../db";
|
||||||
@ -51,6 +52,12 @@ interface IProps {
|
|||||||
softReset: () => void;
|
softReset: () => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface ImportData {
|
||||||
|
base64: string;
|
||||||
|
parsed: any;
|
||||||
|
exportDate?: Date;
|
||||||
|
}
|
||||||
|
|
||||||
export function GameOptionsRoot(props: IProps): React.ReactElement {
|
export function GameOptionsRoot(props: IProps): React.ReactElement {
|
||||||
const classes = useStyles();
|
const classes = useStyles();
|
||||||
const importInput = useRef<HTMLInputElement>(null);
|
const importInput = useRef<HTMLInputElement>(null);
|
||||||
@ -78,12 +85,15 @@ export function GameOptionsRoot(props: IProps): React.ReactElement {
|
|||||||
const [enableBashHotkeys, setEnableBashHotkeys] = useState(Settings.EnableBashHotkeys);
|
const [enableBashHotkeys, setEnableBashHotkeys] = useState(Settings.EnableBashHotkeys);
|
||||||
const [timestampFormat, setTimestampFormat] = useState(Settings.TimestampsFormat);
|
const [timestampFormat, setTimestampFormat] = useState(Settings.TimestampsFormat);
|
||||||
const [saveGameOnFileSave, setSaveGameOnFileSave] = useState(Settings.SaveGameOnFileSave);
|
const [saveGameOnFileSave, setSaveGameOnFileSave] = useState(Settings.SaveGameOnFileSave);
|
||||||
|
const [useIEC60027_2, setUseIEC60027_2] = useState(Settings.UseIEC60027_2);
|
||||||
|
|
||||||
const [locale, setLocale] = useState(Settings.Locale);
|
const [locale, setLocale] = useState(Settings.Locale);
|
||||||
const [diagnosticOpen, setDiagnosticOpen] = useState(false);
|
const [diagnosticOpen, setDiagnosticOpen] = useState(false);
|
||||||
const [deleteGameOpen, setDeleteOpen] = useState(false);
|
const [deleteGameOpen, setDeleteOpen] = useState(false);
|
||||||
const [themeEditorOpen, setThemeEditorOpen] = useState(false);
|
const [themeEditorOpen, setThemeEditorOpen] = useState(false);
|
||||||
const [softResetOpen, setSoftResetOpen] = useState(false);
|
const [softResetOpen, setSoftResetOpen] = useState(false);
|
||||||
|
const [importSaveOpen, setImportSaveOpen] = useState(false);
|
||||||
|
const [importData, setImportData] = useState<ImportData | null>(null);
|
||||||
|
|
||||||
function handleExecTimeChange(event: any, newValue: number | number[]): void {
|
function handleExecTimeChange(event: any, newValue: number | number[]): void {
|
||||||
setExecTime(newValue as number);
|
setExecTime(newValue as number);
|
||||||
@ -154,6 +164,10 @@ export function GameOptionsRoot(props: IProps): React.ReactElement {
|
|||||||
setDisableASCIIArt(event.target.checked);
|
setDisableASCIIArt(event.target.checked);
|
||||||
Settings.DisableASCIIArt = event.target.checked;
|
Settings.DisableASCIIArt = event.target.checked;
|
||||||
}
|
}
|
||||||
|
function handleUseIEC60027_2Change(event: React.ChangeEvent<HTMLInputElement>): void {
|
||||||
|
setUseIEC60027_2(event.target.checked);
|
||||||
|
Settings.UseIEC60027_2 = event.target.checked;
|
||||||
|
}
|
||||||
|
|
||||||
function handleDisableTextEffectsChange(event: React.ChangeEvent<HTMLInputElement>): void {
|
function handleDisableTextEffectsChange(event: React.ChangeEvent<HTMLInputElement>): void {
|
||||||
setDisableTextEffects(event.target.checked);
|
setDisableTextEffects(event.target.checked);
|
||||||
@ -206,11 +220,67 @@ export function GameOptionsRoot(props: IProps): React.ReactElement {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const contents = result;
|
const contents = result;
|
||||||
save(contents).then(() => setTimeout(() => location.reload(), 1000));
|
|
||||||
|
// https://stackoverflow.com/a/35002237
|
||||||
|
const base64regex = /^([0-9a-zA-Z+/]{4})*(([0-9a-zA-Z+/]{2}==)|([0-9a-zA-Z+/]{3}=))?$/;
|
||||||
|
if (!base64regex.test(contents)) {
|
||||||
|
SnackbarEvents.emit("Save game was not a base64 string", "error", 5000);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let newSave;
|
||||||
|
try {
|
||||||
|
newSave = window.atob(contents);
|
||||||
|
newSave = newSave.trim();
|
||||||
|
} catch (error) {
|
||||||
|
console.log(error); // We'll handle below
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!newSave || newSave === '') {
|
||||||
|
SnackbarEvents.emit("Save game had not content", "error", 5000);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let parsedSave;
|
||||||
|
try {
|
||||||
|
parsedSave = JSON.parse(newSave);
|
||||||
|
} catch (error) {
|
||||||
|
console.log(error); // We'll handle below
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!parsedSave || parsedSave.ctor !== 'BitburnerSaveObject' || !parsedSave.data) {
|
||||||
|
SnackbarEvents.emit("Save game did not seem valid", "error", 5000);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const data: ImportData = {
|
||||||
|
base64: contents,
|
||||||
|
parsed: parsedSave,
|
||||||
|
}
|
||||||
|
|
||||||
|
// We don't always seem to have this value in the save file. Exporting from the option menu does not set the bonus I think.
|
||||||
|
const exportTimestamp = parsedSave.data.LastExportBonus;
|
||||||
|
if (exportTimestamp && exportTimestamp !== '0') {
|
||||||
|
data.exportDate = new Date(parseInt(exportTimestamp, 10))
|
||||||
|
}
|
||||||
|
|
||||||
|
setImportData(data)
|
||||||
|
setImportSaveOpen(true);
|
||||||
};
|
};
|
||||||
reader.readAsText(file);
|
reader.readAsText(file);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function confirmedImportGame(): void {
|
||||||
|
if (!importData) return;
|
||||||
|
|
||||||
|
setImportSaveOpen(false);
|
||||||
|
save(importData.base64).then(() => {
|
||||||
|
setImportData(null);
|
||||||
|
setTimeout(() => location.reload(), 1000)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
function doSoftReset(): void {
|
function doSoftReset(): void {
|
||||||
if (!Settings.SuppressBuyAugmentationConfirmation) {
|
if (!Settings.SuppressBuyAugmentationConfirmation) {
|
||||||
setSoftResetOpen(true);
|
setSoftResetOpen(true);
|
||||||
@ -513,6 +583,16 @@ export function GameOptionsRoot(props: IProps): React.ReactElement {
|
|||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
</ListItem>
|
</ListItem>
|
||||||
|
<ListItem>
|
||||||
|
<FormControlLabel
|
||||||
|
control={<Switch checked={useIEC60027_2} onChange={handleUseIEC60027_2Change} />}
|
||||||
|
label={
|
||||||
|
<Tooltip title={<Typography>If this is set all references to memory will use GiB instead of GB, in accordance with IEC 60027-2.</Typography>}>
|
||||||
|
<Typography>Use GiB instead of GB</Typography>
|
||||||
|
</Tooltip>
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</ListItem>
|
||||||
<ListItem>
|
<ListItem>
|
||||||
<Tooltip
|
<Tooltip
|
||||||
title={
|
title={
|
||||||
@ -618,19 +698,41 @@ export function GameOptionsRoot(props: IProps): React.ReactElement {
|
|||||||
<Button onClick={() => setDeleteOpen(true)}>Delete Game</Button>
|
<Button onClick={() => setDeleteOpen(true)}>Delete Game</Button>
|
||||||
</Box>
|
</Box>
|
||||||
<Box>
|
<Box>
|
||||||
<Tooltip title={<Typography>export</Typography>}>
|
<Tooltip title={<Typography>Export your game to a text file.</Typography>}>
|
||||||
<Button onClick={() => props.export()}>
|
<Button onClick={() => props.export()}>
|
||||||
<DownloadIcon color="primary" />
|
<DownloadIcon color="primary" />
|
||||||
Export
|
Export Game
|
||||||
</Button>
|
</Button>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
<Tooltip title={<Typography>import</Typography>}>
|
<Tooltip title={<Typography>Import your game from a text file.<br/>This will <strong>overwrite</strong> your current game. Back it up first!</Typography>}>
|
||||||
<Button onClick={startImport}>
|
<Button onClick={startImport}>
|
||||||
<UploadIcon color="primary" />
|
<UploadIcon color="primary" />
|
||||||
Import
|
Import Game
|
||||||
<input ref={importInput} id="import-game-file-selector" type="file" hidden onChange={onImport} />
|
<input ref={importInput} id="import-game-file-selector" type="file" hidden onChange={onImport} />
|
||||||
</Button>
|
</Button>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
|
<ConfirmationModal
|
||||||
|
open={importSaveOpen}
|
||||||
|
onClose={() => setImportSaveOpen(false)}
|
||||||
|
onConfirm={() => confirmedImportGame()}
|
||||||
|
confirmationText={
|
||||||
|
<>
|
||||||
|
Importing a new game will <strong>completely wipe</strong> the current data!
|
||||||
|
<br />
|
||||||
|
<br />
|
||||||
|
Make sure to have a backup of your current save file before importing.
|
||||||
|
<br />
|
||||||
|
The file you are attempting to import seems valid.
|
||||||
|
<br />
|
||||||
|
<br />
|
||||||
|
{importData?.exportDate && (<>
|
||||||
|
The export date of the save file is <strong>{importData?.exportDate.toString()}</strong>
|
||||||
|
<br />
|
||||||
|
<br />
|
||||||
|
</>)}
|
||||||
|
</>
|
||||||
|
}
|
||||||
|
/>
|
||||||
</Box>
|
</Box>
|
||||||
<Box>
|
<Box>
|
||||||
<Tooltip
|
<Tooltip
|
||||||
|
@ -46,6 +46,7 @@ function ColorEditor({ name, onColorChange, color, defaultColor }: IColorEditorP
|
|||||||
deferred
|
deferred
|
||||||
value={color}
|
value={color}
|
||||||
onChange={(newColor: Color) => onColorChange(name, "#" + newColor.hex)}
|
onChange={(newColor: Color) => onColorChange(name, "#" + newColor.hex)}
|
||||||
|
disableAlpha
|
||||||
/>
|
/>
|
||||||
</>
|
</>
|
||||||
),
|
),
|
||||||
|
@ -14,10 +14,13 @@ import "numeral/locales/no";
|
|||||||
import "numeral/locales/pl";
|
import "numeral/locales/pl";
|
||||||
import "numeral/locales/ru";
|
import "numeral/locales/ru";
|
||||||
|
|
||||||
|
import { Settings } from "../Settings/Settings";
|
||||||
|
|
||||||
/* eslint-disable class-methods-use-this */
|
/* eslint-disable class-methods-use-this */
|
||||||
|
|
||||||
const extraFormats = [1e15, 1e18, 1e21, 1e24, 1e27, 1e30];
|
const extraFormats = [1e15, 1e18, 1e21, 1e24, 1e27, 1e30];
|
||||||
const extraNotations = ["q", "Q", "s", "S", "o", "n"];
|
const extraNotations = ["q", "Q", "s", "S", "o", "n"];
|
||||||
|
const gigaMultiplier = { standard: 1e9, iec60027_2: 2 ** 30 };
|
||||||
|
|
||||||
class NumeralFormatter {
|
class NumeralFormatter {
|
||||||
// Default Locale
|
// Default Locale
|
||||||
@ -110,11 +113,11 @@ class NumeralFormatter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
formatRAM(n: number): string {
|
formatRAM(n: number): string {
|
||||||
if (n < 1e3) return this.format(n, "0.00") + "GB";
|
if(Settings.UseIEC60027_2)
|
||||||
if (n < 1e6) return this.format(n / 1e3, "0.00") + "TB";
|
{
|
||||||
if (n < 1e9) return this.format(n / 1e6, "0.00") + "PB";
|
return this.format(n * gigaMultiplier.iec60027_2, "0.00ib");
|
||||||
if (n < 1e12) return this.format(n / 1e9, "0.00") + "EB";
|
}
|
||||||
return this.format(n, "0.00") + "GB";
|
return this.format(n * gigaMultiplier.standard, "0.00b");
|
||||||
}
|
}
|
||||||
|
|
||||||
formatPercentage(n: number, decimalPlaces = 2): string {
|
formatPercentage(n: number, decimalPlaces = 2): string {
|
||||||
|
Reference in New Issue
Block a user