mirror of
https://github.com/bitburner-official/bitburner-src.git
synced 2025-01-01 10:57:33 +01:00
commit
4e82293afb
54
dist/vendor.bundle.js
vendored
54
dist/vendor.bundle.js
vendored
File diff suppressed because one or more lines are too long
@ -28,6 +28,8 @@ grow() Netscript Function
|
|||||||
server, but there is no required hacking level to run the command. It also
|
server, but there is no required hacking level to run the command. It also
|
||||||
raises the security level of the target server by 0.004 per thread.
|
raises the security level of the target server by 0.004 per thread.
|
||||||
|
|
||||||
|
Action time is calculated at the start, effect is calculated at the end.
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
|
|
||||||
.. code-block:: javascript
|
.. code-block:: javascript
|
||||||
|
@ -27,6 +27,8 @@ hack() Netscript Function
|
|||||||
A successful :doc:`hack<hack>` on a server will raise that server's security
|
A successful :doc:`hack<hack>` on a server will raise that server's security
|
||||||
level by 0.002.
|
level by 0.002.
|
||||||
|
|
||||||
|
Action time is calculated at the start, effect is calculated at the end.
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
|
|
||||||
.. code-block:: javascript
|
.. code-block:: javascript
|
||||||
|
@ -3,7 +3,9 @@ getAugmentationCost() Netscript Function
|
|||||||
|
|
||||||
.. js:function:: getAugmentationCost(augName)
|
.. js:function:: getAugmentationCost(augName)
|
||||||
|
|
||||||
.. warning:: This function is deprecated.
|
.. warning:: This function is deprecated. It still functions, but new
|
||||||
|
scripts should prefer :doc:`getAugmentationPrice<getAugmentationPrice>`
|
||||||
|
and :doc:`getAugmentationRepReq<getAugmentationRepReq>` instead.
|
||||||
|
|
||||||
:RAM cost: 5 GB
|
:RAM cost: 5 GB
|
||||||
|
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
const { app, BrowserWindow, Menu } = require("electron");
|
const { app, BrowserWindow, Menu, globalShortcut, shell } = require("electron");
|
||||||
|
|
||||||
Menu.setApplicationMenu(false);
|
Menu.setApplicationMenu(false);
|
||||||
function createWindow() {
|
function createWindow() {
|
||||||
const win = new BrowserWindow({
|
const win = new BrowserWindow({
|
||||||
@ -12,6 +13,24 @@ function createWindow() {
|
|||||||
win.maximize();
|
win.maximize();
|
||||||
win.loadFile("index.html");
|
win.loadFile("index.html");
|
||||||
win.show();
|
win.show();
|
||||||
|
// win.webContents.openDevTools();
|
||||||
|
globalShortcut.register("f5", function () {
|
||||||
|
win.loadFile("index.html");
|
||||||
|
});
|
||||||
|
globalShortcut.register("f8", function () {
|
||||||
|
win.loadFile("index.html", { query: { noScripts: "true" } });
|
||||||
|
});
|
||||||
|
|
||||||
|
win.webContents.on("new-window", function (e, url) {
|
||||||
|
// make sure local urls stay in electron perimeter
|
||||||
|
if ("file://" === url.substr(0, "file://".length)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// and open every other protocols on the browser
|
||||||
|
e.preventDefault();
|
||||||
|
shell.openExternal(url);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
app.whenReady().then(() => {
|
app.whenReady().then(() => {
|
||||||
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
1357
package-lock.json
generated
1357
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -58,7 +58,8 @@
|
|||||||
"treant-js": "^1.0.1",
|
"treant-js": "^1.0.1",
|
||||||
"unused-webpack-plugin": "^2.4.0",
|
"unused-webpack-plugin": "^2.4.0",
|
||||||
"uuid": "^3.2.1",
|
"uuid": "^3.2.1",
|
||||||
"w3c-blob": "0.0.1"
|
"w3c-blob": "0.0.1",
|
||||||
|
"webpack-deadcode-plugin": "^0.1.15"
|
||||||
},
|
},
|
||||||
"description": "A cyberpunk-themed incremental game",
|
"description": "A cyberpunk-themed incremental game",
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
15
package.sh
15
package.sh
@ -1,14 +1,19 @@
|
|||||||
# npm install electron --save-dev
|
# npm install electron --save-dev
|
||||||
# npm install electron-packager --save-dev
|
# npm install electron-packager --save-dev
|
||||||
|
|
||||||
mkdir -p .package/dist || true
|
mkdir -p .package/dist/src/ThirdParty || true
|
||||||
|
mkdir -p .package/src/ThirdParty || true
|
||||||
|
|
||||||
cp index.html .package
|
cp index.html .package
|
||||||
cp electron/* .package
|
cp electron/* .package
|
||||||
cp dist/engine.bundle.js .package/dist
|
# The css files
|
||||||
cp dist/engineStyle.css .package/dist
|
|
||||||
cp dist/vendor.css .package/dist
|
cp dist/vendor.css .package/dist
|
||||||
cp dist/engineStyle.bundle.js .package/dist
|
cp main.css .package/main.css
|
||||||
cp dist/vendor.bundle.js .package/dist
|
|
||||||
|
# The js files.
|
||||||
|
cp dist/vendor.bundle.js .package/dist/vendor.bundle.js
|
||||||
|
cp main.bundle.js .package/main.bundle.js
|
||||||
|
|
||||||
|
cp src/ThirdParty/raphael.min.js .package/src/ThirdParty/raphael.min.js
|
||||||
|
|
||||||
npm run package-electron
|
npm run package-electron
|
@ -211,7 +211,7 @@ function initAugmentations() {
|
|||||||
name: AugmentationNames.Targeting3,
|
name: AugmentationNames.Targeting3,
|
||||||
moneyCost: 1.15e8,
|
moneyCost: 1.15e8,
|
||||||
repCost: 2.75e4,
|
repCost: 2.75e4,
|
||||||
info: "The latest version of the 'Augmented Targeting' implant adds the ability to " + "lock-on and track threats.",
|
info: "The latest version of the 'Augmented Targeting' implant adds the ability to lock-on and track threats.",
|
||||||
prereqs: [AugmentationNames.Targeting2],
|
prereqs: [AugmentationNames.Targeting2],
|
||||||
dexterity_mult: 1.3,
|
dexterity_mult: 1.3,
|
||||||
});
|
});
|
||||||
|
@ -16,8 +16,11 @@ class BitNode {
|
|||||||
// BitNode number
|
// BitNode number
|
||||||
number: number;
|
number: number;
|
||||||
|
|
||||||
constructor(n: number, name: string, desc = "", info: JSX.Element = <></>) {
|
difficulty: 0 | 1 | 2;
|
||||||
|
|
||||||
|
constructor(n: number, difficulty: 0 | 1 | 2, name: string, desc = "", info: JSX.Element = <></>) {
|
||||||
this.number = n;
|
this.number = n;
|
||||||
|
this.difficulty = difficulty;
|
||||||
this.name = name;
|
this.name = name;
|
||||||
this.desc = desc;
|
this.desc = desc;
|
||||||
this.info = info;
|
this.info = info;
|
||||||
@ -28,6 +31,7 @@ export const BitNodes: IMap<BitNode> = {};
|
|||||||
|
|
||||||
BitNodes["BitNode1"] = new BitNode(
|
BitNodes["BitNode1"] = new BitNode(
|
||||||
1,
|
1,
|
||||||
|
0,
|
||||||
"Source Genesis",
|
"Source Genesis",
|
||||||
"The original BitNode",
|
"The original BitNode",
|
||||||
(
|
(
|
||||||
@ -54,6 +58,7 @@ BitNodes["BitNode1"] = new BitNode(
|
|||||||
);
|
);
|
||||||
BitNodes["BitNode2"] = new BitNode(
|
BitNodes["BitNode2"] = new BitNode(
|
||||||
2,
|
2,
|
||||||
|
0,
|
||||||
"Rise of the Underworld",
|
"Rise of the Underworld",
|
||||||
"From the shadows, they rose", //Gangs
|
"From the shadows, they rose", //Gangs
|
||||||
(
|
(
|
||||||
@ -101,6 +106,7 @@ BitNodes["BitNode2"] = new BitNode(
|
|||||||
);
|
);
|
||||||
BitNodes["BitNode3"] = new BitNode(
|
BitNodes["BitNode3"] = new BitNode(
|
||||||
3,
|
3,
|
||||||
|
0,
|
||||||
"Corporatocracy",
|
"Corporatocracy",
|
||||||
"The Price of Civilization",
|
"The Price of Civilization",
|
||||||
(
|
(
|
||||||
@ -140,6 +146,7 @@ BitNodes["BitNode3"] = new BitNode(
|
|||||||
);
|
);
|
||||||
BitNodes["BitNode4"] = new BitNode(
|
BitNodes["BitNode4"] = new BitNode(
|
||||||
4,
|
4,
|
||||||
|
1,
|
||||||
"The Singularity",
|
"The Singularity",
|
||||||
"The Man and the Machine",
|
"The Man and the Machine",
|
||||||
(
|
(
|
||||||
@ -164,6 +171,7 @@ BitNodes["BitNode4"] = new BitNode(
|
|||||||
);
|
);
|
||||||
BitNodes["BitNode5"] = new BitNode(
|
BitNodes["BitNode5"] = new BitNode(
|
||||||
5,
|
5,
|
||||||
|
1,
|
||||||
"Artificial Intelligence",
|
"Artificial Intelligence",
|
||||||
"Posthuman",
|
"Posthuman",
|
||||||
(
|
(
|
||||||
@ -211,6 +219,7 @@ BitNodes["BitNode5"] = new BitNode(
|
|||||||
);
|
);
|
||||||
BitNodes["BitNode6"] = new BitNode(
|
BitNodes["BitNode6"] = new BitNode(
|
||||||
6,
|
6,
|
||||||
|
1,
|
||||||
"Bladeburners",
|
"Bladeburners",
|
||||||
"Like Tears in Rain",
|
"Like Tears in Rain",
|
||||||
(
|
(
|
||||||
@ -255,6 +264,7 @@ BitNodes["BitNode6"] = new BitNode(
|
|||||||
);
|
);
|
||||||
BitNodes["BitNode7"] = new BitNode(
|
BitNodes["BitNode7"] = new BitNode(
|
||||||
7,
|
7,
|
||||||
|
2,
|
||||||
"Bladeburners 2079",
|
"Bladeburners 2079",
|
||||||
"More human than humans",
|
"More human than humans",
|
||||||
(
|
(
|
||||||
@ -303,6 +313,7 @@ BitNodes["BitNode7"] = new BitNode(
|
|||||||
);
|
);
|
||||||
BitNodes["BitNode8"] = new BitNode(
|
BitNodes["BitNode8"] = new BitNode(
|
||||||
8,
|
8,
|
||||||
|
2,
|
||||||
"Ghost of Wall Street",
|
"Ghost of Wall Street",
|
||||||
"Money never sleeps",
|
"Money never sleeps",
|
||||||
(
|
(
|
||||||
@ -347,6 +358,7 @@ BitNodes["BitNode8"] = new BitNode(
|
|||||||
);
|
);
|
||||||
BitNodes["BitNode9"] = new BitNode(
|
BitNodes["BitNode9"] = new BitNode(
|
||||||
9,
|
9,
|
||||||
|
2,
|
||||||
"Hacktocracy",
|
"Hacktocracy",
|
||||||
"Hacknet Unleashed",
|
"Hacknet Unleashed",
|
||||||
(
|
(
|
||||||
@ -389,6 +401,7 @@ BitNodes["BitNode9"] = new BitNode(
|
|||||||
);
|
);
|
||||||
BitNodes["BitNode10"] = new BitNode(
|
BitNodes["BitNode10"] = new BitNode(
|
||||||
10,
|
10,
|
||||||
|
2,
|
||||||
"Digital Carbon",
|
"Digital Carbon",
|
||||||
"Your body is not who you are",
|
"Your body is not who you are",
|
||||||
(
|
(
|
||||||
@ -428,6 +441,7 @@ BitNodes["BitNode10"] = new BitNode(
|
|||||||
);
|
);
|
||||||
BitNodes["BitNode11"] = new BitNode(
|
BitNodes["BitNode11"] = new BitNode(
|
||||||
11,
|
11,
|
||||||
|
1,
|
||||||
"The Big Crash",
|
"The Big Crash",
|
||||||
"Okay. Sell it all.",
|
"Okay. Sell it all.",
|
||||||
(
|
(
|
||||||
@ -492,6 +506,7 @@ BitNodes["BitNode11"] = new BitNode(
|
|||||||
);
|
);
|
||||||
BitNodes["BitNode12"] = new BitNode(
|
BitNodes["BitNode12"] = new BitNode(
|
||||||
12,
|
12,
|
||||||
|
0,
|
||||||
"The Recursion",
|
"The Recursion",
|
||||||
"Repeat.",
|
"Repeat.",
|
||||||
(
|
(
|
||||||
@ -507,18 +522,18 @@ BitNodes["BitNode12"] = new BitNode(
|
|||||||
),
|
),
|
||||||
);
|
);
|
||||||
// Books: Frontera, Shiner
|
// Books: Frontera, Shiner
|
||||||
BitNodes["BitNode13"] = new BitNode(13, "fOS", "COMING SOON"); //Unlocks the new game mode and the rest of the BitNodes
|
BitNodes["BitNode13"] = new BitNode(13, 2, "fOS", "COMING SOON"); //Unlocks the new game mode and the rest of the BitNodes
|
||||||
BitNodes["BitNode14"] = new BitNode(14, "", "COMING SOON");
|
BitNodes["BitNode14"] = new BitNode(14, 2, "", "COMING SOON");
|
||||||
BitNodes["BitNode15"] = new BitNode(15, "", "COMING SOON");
|
BitNodes["BitNode15"] = new BitNode(15, 2, "", "COMING SOON");
|
||||||
BitNodes["BitNode16"] = new BitNode(16, "", "COMING SOON");
|
BitNodes["BitNode16"] = new BitNode(16, 2, "", "COMING SOON");
|
||||||
BitNodes["BitNode17"] = new BitNode(17, "", "COMING SOON");
|
BitNodes["BitNode17"] = new BitNode(17, 2, "", "COMING SOON");
|
||||||
BitNodes["BitNode18"] = new BitNode(18, "", "COMING SOON");
|
BitNodes["BitNode18"] = new BitNode(18, 2, "", "COMING SOON");
|
||||||
BitNodes["BitNode19"] = new BitNode(19, "", "COMING SOON");
|
BitNodes["BitNode19"] = new BitNode(19, 2, "", "COMING SOON");
|
||||||
BitNodes["BitNode20"] = new BitNode(20, "", "COMING SOON");
|
BitNodes["BitNode20"] = new BitNode(20, 2, "", "COMING SOON");
|
||||||
BitNodes["BitNode21"] = new BitNode(21, "", "COMING SOON");
|
BitNodes["BitNode21"] = new BitNode(21, 2, "", "COMING SOON");
|
||||||
BitNodes["BitNode22"] = new BitNode(22, "", "COMING SOON");
|
BitNodes["BitNode22"] = new BitNode(22, 2, "", "COMING SOON");
|
||||||
BitNodes["BitNode23"] = new BitNode(23, "", "COMING SOON");
|
BitNodes["BitNode23"] = new BitNode(23, 2, "", "COMING SOON");
|
||||||
BitNodes["BitNode24"] = new BitNode(24, "", "COMING SOON");
|
BitNodes["BitNode24"] = new BitNode(24, 2, "", "COMING SOON");
|
||||||
|
|
||||||
export function initBitNodeMultipliers(p: IPlayer): void {
|
export function initBitNodeMultipliers(p: IPlayer): void {
|
||||||
if (p.bitNodeN == null) {
|
if (p.bitNodeN == null) {
|
||||||
|
@ -29,6 +29,9 @@ export function PortalPopup(props: IProps): React.ReactElement {
|
|||||||
Source-File Level: {props.level} / {maxSourceFileLevel}
|
Source-File Level: {props.level} / {maxSourceFileLevel}
|
||||||
<br />
|
<br />
|
||||||
<br />
|
<br />
|
||||||
|
Difficulty: {["easy", "normal", "hard"][bitNode.difficulty]}
|
||||||
|
<br />
|
||||||
|
<br />
|
||||||
{bitNode.info}
|
{bitNode.info}
|
||||||
<br />
|
<br />
|
||||||
<br />
|
<br />
|
||||||
|
@ -3,6 +3,7 @@ import { removePopup } from "../../ui/React/createPopup";
|
|||||||
import { IBladeburner } from "../IBladeburner";
|
import { IBladeburner } from "../IBladeburner";
|
||||||
import { WorldMap } from "../../ui/React/WorldMap";
|
import { WorldMap } from "../../ui/React/WorldMap";
|
||||||
import { CityName } from "../../Locations/data/CityNames";
|
import { CityName } from "../../Locations/data/CityNames";
|
||||||
|
import { Settings } from "../../Settings/Settings";
|
||||||
|
|
||||||
interface IProps {
|
interface IProps {
|
||||||
bladeburner: IBladeburner;
|
bladeburner: IBladeburner;
|
||||||
@ -21,7 +22,15 @@ export function TravelPopup(props: IProps): React.ReactElement {
|
|||||||
Travel to a different city for your Bladeburner activities. This does not cost any money. The city you are in
|
Travel to a different city for your Bladeburner activities. This does not cost any money. The city you are in
|
||||||
for your Bladeburner duties does not affect your location in the game otherwise.
|
for your Bladeburner duties does not affect your location in the game otherwise.
|
||||||
</p>
|
</p>
|
||||||
<WorldMap currentCity={props.bladeburner.city as CityName} onTravel={(city: CityName) => travel(city)} />
|
{Settings.DisableASCIIArt ? (
|
||||||
|
Object.values(CityName).map((city: CityName) => (
|
||||||
|
<button key={city} className="std-button" onClick={() => travel(city)}>
|
||||||
|
{city}
|
||||||
|
</button>
|
||||||
|
))
|
||||||
|
) : (
|
||||||
|
<WorldMap currentCity={props.bladeburner.city as CityName} onTravel={(city: CityName) => travel(city)} />
|
||||||
|
)}
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -196,7 +196,7 @@ export class Roulette extends Game<IProps, IState> {
|
|||||||
if (playerWin && Math.random() > 0.9) {
|
if (playerWin && Math.random() > 0.9) {
|
||||||
playerWin = false;
|
playerWin = false;
|
||||||
while (this.state.strategy.match(n)) {
|
while (this.state.strategy.match(n)) {
|
||||||
n++;
|
n = (n + 1) % 36;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (playerWin) {
|
if (playerWin) {
|
||||||
|
1
src/CinematicText.d.ts
vendored
1
src/CinematicText.d.ts
vendored
@ -1 +0,0 @@
|
|||||||
export declare let cinematicTextFlag: boolean;
|
|
@ -1,119 +0,0 @@
|
|||||||
import { Engine } from "./engine";
|
|
||||||
import { setTimeoutRef } from "./utils/SetTimeoutRef";
|
|
||||||
|
|
||||||
import { removeChildrenFromElement } from "../utils/uiHelpers/removeChildrenFromElement";
|
|
||||||
import { createElement } from "../utils/uiHelpers/createElement";
|
|
||||||
import { exceptionAlert } from "../utils/helpers/exceptionAlert";
|
|
||||||
import { isString } from "../utils/helpers/isString";
|
|
||||||
|
|
||||||
export let cinematicTextFlag = false;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Print a message using a hacking-style "typing" effect.
|
|
||||||
* Note that this clears the UI so that the text from this is the only thing visible.
|
|
||||||
*
|
|
||||||
* @param lines {string[]} Array of strings to print, where each element is a separate line
|
|
||||||
*/
|
|
||||||
export function writeCinematicText(lines) {
|
|
||||||
cinematicTextFlag = true;
|
|
||||||
|
|
||||||
if (lines.constructor !== Array) {
|
|
||||||
throw new Error("Invalid non-array argument passed into writeCinematicText()");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Reuse the 'Red Pill' content
|
|
||||||
Engine.loadCinematicTextContent();
|
|
||||||
const container = document.getElementById("cinematic-text-container");
|
|
||||||
container.style.width = "75%";
|
|
||||||
if (container == null) {
|
|
||||||
throw new Error("Could not find cinematic-text-container for writeCinematicText()");
|
|
||||||
}
|
|
||||||
removeChildrenFromElement(container);
|
|
||||||
|
|
||||||
for (let i = 0; i < lines.length; ++i) {
|
|
||||||
if (!isString(lines[i])) {
|
|
||||||
throw new Error("Invalid non-string element in 'lines' argument. writeCinematicText() failed");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return writeCinematicTextRecurse(lines)
|
|
||||||
.then(function () {
|
|
||||||
return cinematicTextEnd(); //Puts the continue button
|
|
||||||
})
|
|
||||||
.catch(function (e) {
|
|
||||||
exceptionAlert(e);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function writeCinematicTextRecurse(lines, lineNumber = 0) {
|
|
||||||
if (lineNumber >= lines.length) {
|
|
||||||
return Promise.resolve(true);
|
|
||||||
}
|
|
||||||
return writeCinematicTextLine(lines[lineNumber]).then(function () {
|
|
||||||
return writeCinematicTextRecurse(lines, lineNumber + 1);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function writeCinematicTextLine(line) {
|
|
||||||
return new Promise(function (resolve, reject) {
|
|
||||||
const container = document.getElementById("cinematic-text-container");
|
|
||||||
const pElem = document.createElement("p");
|
|
||||||
container.appendChild(pElem);
|
|
||||||
|
|
||||||
const promise = writeCinematicTextLetter(pElem, line, 0);
|
|
||||||
promise.then(
|
|
||||||
function (res) {
|
|
||||||
resolve(res);
|
|
||||||
},
|
|
||||||
function (e) {
|
|
||||||
reject(e);
|
|
||||||
},
|
|
||||||
);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function writeCinematicTextLetter(pElem, line, i = 0) {
|
|
||||||
return new Promise(function (resolve, reject) {
|
|
||||||
setTimeoutRef(function () {
|
|
||||||
const textToShow = line.substring(0, i);
|
|
||||||
|
|
||||||
if (i >= line.length) {
|
|
||||||
pElem.innerHTML = textToShow;
|
|
||||||
return resolve(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
pElem.innerHTML = textToShow + "<span class='typed-cursor'> █ </span>";
|
|
||||||
const promise = writeCinematicTextLetter(pElem, line, i + 1);
|
|
||||||
promise.then(
|
|
||||||
function (res) {
|
|
||||||
resolve(res);
|
|
||||||
},
|
|
||||||
function (e) {
|
|
||||||
reject(e);
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}, 15);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function cinematicTextEnd() {
|
|
||||||
var container = document.getElementById("cinematic-text-container");
|
|
||||||
var mainMenu = document.getElementById("mainmenu-container");
|
|
||||||
container.appendChild(createElement("br"));
|
|
||||||
|
|
||||||
return new Promise(function (resolve) {
|
|
||||||
container.appendChild(
|
|
||||||
createElement("a", {
|
|
||||||
class: "a-link-button",
|
|
||||||
innerText: "Continue...",
|
|
||||||
clickListener: () => {
|
|
||||||
removeChildrenFromElement(container);
|
|
||||||
Engine.loadTerminalContent();
|
|
||||||
mainMenu.style.visibility = "visible";
|
|
||||||
cinematicTextFlag = false;
|
|
||||||
resolve();
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
});
|
|
||||||
}
|
|
@ -1,7 +1,7 @@
|
|||||||
import { Generic_fromJSON, Generic_toJSON, Reviver } from "../../utils/JSONReviver";
|
import { Generic_fromJSON, Generic_toJSON, Reviver } from "../../utils/JSONReviver";
|
||||||
|
|
||||||
// Array of all valid states
|
// Array of all valid states
|
||||||
export const AllCorporationStates: string[] = ["START", "PURCHASE", "PRODUCTION", "SALE", "EXPORT"];
|
const AllCorporationStates: string[] = ["START", "PURCHASE", "PRODUCTION", "SALE", "EXPORT"];
|
||||||
|
|
||||||
export class CorporationState {
|
export class CorporationState {
|
||||||
// Number representing what state the Corporation is in. The number
|
// Number representing what state the Corporation is in. The number
|
||||||
|
@ -4,10 +4,12 @@ import { IPlayer } from "../../PersonObjects/IPlayer";
|
|||||||
import { removePopup } from "../../ui/React/createPopup";
|
import { removePopup } from "../../ui/React/createPopup";
|
||||||
import { Money } from "../../ui/React/Money";
|
import { Money } from "../../ui/React/Money";
|
||||||
import { dialogBoxCreate } from "../../../utils/DialogBox";
|
import { dialogBoxCreate } from "../../../utils/DialogBox";
|
||||||
|
import { IRouter } from "../../ui/Router";
|
||||||
|
|
||||||
interface IProps {
|
interface IProps {
|
||||||
player: IPlayer;
|
player: IPlayer;
|
||||||
popupId: string;
|
popupId: string;
|
||||||
|
router: IRouter;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function CreateCorporationPopup(props: IProps): React.ReactElement {
|
export function CreateCorporationPopup(props: IProps): React.ReactElement {
|
||||||
@ -40,6 +42,7 @@ export function CreateCorporationPopup(props: IProps): React.ReactElement {
|
|||||||
"and manage your company in the City.",
|
"and manage your company in the City.",
|
||||||
);
|
);
|
||||||
removePopup(props.popupId);
|
removePopup(props.popupId);
|
||||||
|
props.router.toCorporation();
|
||||||
}
|
}
|
||||||
|
|
||||||
function seed(): void {
|
function seed(): void {
|
||||||
@ -55,6 +58,7 @@ export function CreateCorporationPopup(props: IProps): React.ReactElement {
|
|||||||
"You can visit and manage your company in the City.",
|
"You can visit and manage your company in the City.",
|
||||||
);
|
);
|
||||||
removePopup(props.popupId);
|
removePopup(props.popupId);
|
||||||
|
props.router.toCorporation();
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
@ -95,7 +95,7 @@ function BulkPurchase(props: IProps): React.ReactElement {
|
|||||||
style={{ margin: "5px" }}
|
style={{ margin: "5px" }}
|
||||||
onKeyDown={onKeyDown}
|
onKeyDown={onKeyDown}
|
||||||
/>
|
/>
|
||||||
<button className="std-button">Confirm Bulk Purchase</button>
|
<button className="std-button" onClick={bulkPurchase}>Confirm Bulk Purchase</button>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -62,6 +62,7 @@ export function ResearchPopup(props: IProps): React.ReactElement {
|
|||||||
Research(props.industry, allResearch[i]);
|
Research(props.industry, allResearch[i]);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
dialogBoxCreate(err + "");
|
dialogBoxCreate(err + "");
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
dialogBoxCreate(
|
dialogBoxCreate(
|
||||||
|
@ -24,35 +24,6 @@ export function checkIfConnectedToDarkweb(): void {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//Handler for dark web commands. The terminal's executeCommand() function will pass
|
|
||||||
//dark web-specific commands into this. It will pass in the raw split command array
|
|
||||||
//rather than the command string
|
|
||||||
export function executeDarkwebTerminalCommand(commandArray: string[]): void {
|
|
||||||
if (commandArray.length == 0) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
switch (commandArray[0]) {
|
|
||||||
case "buy": {
|
|
||||||
if (commandArray.length != 2) {
|
|
||||||
Terminal.error("Incorrect number of arguments. Usage: ");
|
|
||||||
Terminal.print("buy -l");
|
|
||||||
Terminal.print("buy [item name]");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const arg = commandArray[1];
|
|
||||||
if (arg == "-l" || arg == "-1" || arg == "--list") {
|
|
||||||
listAllDarkwebItems();
|
|
||||||
} else {
|
|
||||||
buyDarkwebItem(arg);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
Terminal.error("Command not found");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export function listAllDarkwebItems(): void {
|
export function listAllDarkwebItems(): void {
|
||||||
for (const key in DarkWebItems) {
|
for (const key in DarkWebItems) {
|
||||||
const item = DarkWebItems[key];
|
const item = DarkWebItems[key];
|
||||||
|
@ -22,7 +22,7 @@ export function TimeSkip(props: IProps): React.ReactElement {
|
|||||||
return () => {
|
return () => {
|
||||||
props.player.lastUpdate -= time;
|
props.player.lastUpdate -= time;
|
||||||
props.engine._lastUpdate -= time;
|
props.engine._lastUpdate -= time;
|
||||||
saveObject.saveGame(props.engine.indexedDb);
|
saveObject.saveGame();
|
||||||
setTimeout(() => location.reload(), 1000);
|
setTimeout(() => location.reload(), 1000);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -20,7 +20,7 @@ interface IServerProps {
|
|||||||
ip: string;
|
ip: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function ServerAccordion(props: IServerProps): React.ReactElement {
|
function ServerAccordion(props: IServerProps): React.ReactElement {
|
||||||
const server = AllServers[props.ip];
|
const server = AllServers[props.ip];
|
||||||
let totalSize = 0;
|
let totalSize = 0;
|
||||||
for (const f of server.scripts) {
|
for (const f of server.scripts) {
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
import { Player } from "../Player";
|
import { Player } from "../Player";
|
||||||
import { Exploit } from "./Exploit";
|
import { Exploit } from "./Exploit";
|
||||||
|
|
||||||
(function () {
|
export function startTampering(): void {
|
||||||
const a = 55;
|
const a = 55;
|
||||||
setInterval(function () {
|
setInterval(function () {
|
||||||
if (a.toExponential() !== "5.5e+1") {
|
if (a.toExponential() !== "5.5e+1") {
|
||||||
Player.giveExploit(Exploit.PrototypeTampering);
|
Player.giveExploit(Exploit.PrototypeTampering);
|
||||||
}
|
}
|
||||||
}, 15 * 60 * 1000); // 15 minutes
|
}, 15 * 60 * 1000); // 15 minutes
|
||||||
})();
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import { Player } from "../Player";
|
import { Player } from "../Player";
|
||||||
import { Exploit } from "./Exploit";
|
import { Exploit } from "./Exploit";
|
||||||
|
|
||||||
(function () {
|
export function startUnclickable(): void {
|
||||||
function clickTheUnclickable(event: MouseEvent): void {
|
function clickTheUnclickable(event: MouseEvent): void {
|
||||||
if (!event.target || !(event.target instanceof Element)) return;
|
if (!event.target || !(event.target instanceof Element)) return;
|
||||||
const display = window.getComputedStyle(event.target as Element).display;
|
const display = window.getComputedStyle(event.target as Element).display;
|
||||||
@ -19,4 +19,4 @@ import { Exploit } from "./Exploit";
|
|||||||
}
|
}
|
||||||
|
|
||||||
document.addEventListener("DOMContentLoaded", targetElement);
|
document.addEventListener("DOMContentLoaded", targetElement);
|
||||||
})();
|
}
|
||||||
|
@ -1,360 +0,0 @@
|
|||||||
import { IMap } from "../types";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Contains the "information" property for all the Factions, which is just a description of each faction
|
|
||||||
*/
|
|
||||||
export class FactionInfo {
|
|
||||||
/**
|
|
||||||
* The multiplier to apply to augmentation base purchase price.
|
|
||||||
*/
|
|
||||||
augmentationPriceMult: number;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The multiplier to apply to augmentation reputation base requirement.
|
|
||||||
*/
|
|
||||||
augmentationRepRequirementMult: number;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The names of all other factions considered to be enemies to this faction.
|
|
||||||
*/
|
|
||||||
enemies: string[];
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The descriptive text to show on the faction's page.
|
|
||||||
*/
|
|
||||||
infoText: string;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A flag indicating if the faction supports field work to earn reputation.
|
|
||||||
*/
|
|
||||||
offerFieldWork: boolean;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A flag indicating if the faction supports hacking missions to earn reputation.
|
|
||||||
*/
|
|
||||||
offerHackingMission: boolean;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A flag indicating if the faction supports hacking work to earn reputation.
|
|
||||||
*/
|
|
||||||
offerHackingWork: boolean;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A flag indicating if the faction supports security work to earn reputation.
|
|
||||||
*/
|
|
||||||
offerSecurityWork: boolean;
|
|
||||||
|
|
||||||
constructor(
|
|
||||||
infoText: string,
|
|
||||||
enemies: string[],
|
|
||||||
offerHackingMission: boolean,
|
|
||||||
offerHackingWork: boolean,
|
|
||||||
offerFieldWork: boolean,
|
|
||||||
offerSecurityWork: boolean,
|
|
||||||
) {
|
|
||||||
this.infoText = infoText;
|
|
||||||
this.enemies = enemies;
|
|
||||||
this.offerHackingMission = offerHackingMission;
|
|
||||||
this.offerHackingWork = offerHackingWork;
|
|
||||||
this.offerFieldWork = offerFieldWork;
|
|
||||||
this.offerSecurityWork = offerSecurityWork;
|
|
||||||
|
|
||||||
// These are always all 1 for now.
|
|
||||||
this.augmentationPriceMult = 1;
|
|
||||||
this.augmentationRepRequirementMult = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
offersWork(): boolean {
|
|
||||||
return this.offerFieldWork || this.offerHackingMission || this.offerHackingWork || this.offerSecurityWork;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A map of all factions and associated info to them.
|
|
||||||
*/
|
|
||||||
// tslint:disable-next-line:variable-name
|
|
||||||
export const FactionInfos: IMap<FactionInfo> = {
|
|
||||||
// Endgame
|
|
||||||
Illuminati: new FactionInfo(
|
|
||||||
"Humanity never changes. No matter how civilized society becomes, it will eventually fall back into chaos. " +
|
|
||||||
"And from this chaos, we are the invisible hand that guides them to order. ",
|
|
||||||
[],
|
|
||||||
true,
|
|
||||||
true,
|
|
||||||
true,
|
|
||||||
false,
|
|
||||||
),
|
|
||||||
|
|
||||||
Daedalus: new FactionInfo(
|
|
||||||
"Yesterday we obeyed kings and bent our necks to emperors. Today we kneel only to truth.",
|
|
||||||
[],
|
|
||||||
true,
|
|
||||||
true,
|
|
||||||
true,
|
|
||||||
false,
|
|
||||||
),
|
|
||||||
|
|
||||||
"The Covenant": new FactionInfo(
|
|
||||||
"Surrender yourself. Give up your empty individuality to become part of something great, something eternal. " +
|
|
||||||
"Become a slave. Submit your mind, body, and soul. Only then can you set yourself free.<br>" +
|
|
||||||
"<br>" +
|
|
||||||
"Only then can you discover immortality.",
|
|
||||||
[],
|
|
||||||
true,
|
|
||||||
true,
|
|
||||||
true,
|
|
||||||
false,
|
|
||||||
),
|
|
||||||
|
|
||||||
// Megacorporations, each forms its own faction
|
|
||||||
ECorp: new FactionInfo(
|
|
||||||
"ECorp's mission is simple: to connect the world of today with the technology of tomorrow. With our wide " +
|
|
||||||
"range of Internet-related software and commercial hardware, ECorp makes the world's information " +
|
|
||||||
"universally accessible.",
|
|
||||||
[],
|
|
||||||
true,
|
|
||||||
true,
|
|
||||||
true,
|
|
||||||
true,
|
|
||||||
),
|
|
||||||
|
|
||||||
MegaCorp: new FactionInfo(
|
|
||||||
"MegaCorp does what no other dares to do. We imagine. We create. We invent. We create what others have " +
|
|
||||||
"never even dreamed of. Our work fills the world's needs for food, water, power, and transporation on an " +
|
|
||||||
"unprecendented scale, in ways that no other company can.<br>" +
|
|
||||||
"<br>" +
|
|
||||||
"In our labs and factories and on the ground with customers, MegaCorp is ushering in a new era for the world.",
|
|
||||||
[],
|
|
||||||
true,
|
|
||||||
true,
|
|
||||||
true,
|
|
||||||
true,
|
|
||||||
),
|
|
||||||
|
|
||||||
"Bachman & Associates": new FactionInfo(
|
|
||||||
"Where Law and Business meet - thats where we are.<br>" +
|
|
||||||
"<br>" +
|
|
||||||
"Legal Insight - Business Instinct - Innovative Experience.",
|
|
||||||
[],
|
|
||||||
true,
|
|
||||||
true,
|
|
||||||
true,
|
|
||||||
true,
|
|
||||||
),
|
|
||||||
|
|
||||||
"Blade Industries": new FactionInfo("Augmentation is Salvation.", [], true, true, true, true),
|
|
||||||
|
|
||||||
NWO: new FactionInfo(
|
|
||||||
"Humans don't truly desire freedom. They want to be observed, understood, and judged. They want to " +
|
|
||||||
"be given purpose and direction in life. That is why they created God. And that is why they created " +
|
|
||||||
"civilization - not because of willingness, but because of a need to be incorporated into higher orders of " +
|
|
||||||
"structure and meaning.",
|
|
||||||
[],
|
|
||||||
true,
|
|
||||||
true,
|
|
||||||
true,
|
|
||||||
true,
|
|
||||||
),
|
|
||||||
|
|
||||||
"Clarke Incorporated": new FactionInfo("The Power of the Genome - Unlocked.", [], true, true, true, true),
|
|
||||||
|
|
||||||
"OmniTek Incorporated": new FactionInfo(
|
|
||||||
"Simply put, our mission is to design and build robots that make a difference.",
|
|
||||||
[],
|
|
||||||
true,
|
|
||||||
true,
|
|
||||||
true,
|
|
||||||
true,
|
|
||||||
),
|
|
||||||
|
|
||||||
"Four Sigma": new FactionInfo(
|
|
||||||
"The scientific method is the best way to approach investing. Big strategies backed up with big data. Driven " +
|
|
||||||
"by deep learning and innovative ideas. And improved by iteration. That's Four Sigma.",
|
|
||||||
[],
|
|
||||||
true,
|
|
||||||
true,
|
|
||||||
true,
|
|
||||||
true,
|
|
||||||
),
|
|
||||||
|
|
||||||
"KuaiGong International": new FactionInfo("Dream big. Work hard. Make history.", [], true, true, true, true),
|
|
||||||
|
|
||||||
// Other Corporations
|
|
||||||
"Fulcrum Secret Technologies": new FactionInfo(
|
|
||||||
"The human organism has an innate desire to worship. That is why they created gods. If there were no gods, it " +
|
|
||||||
"would be necessary to create them. And now we can.",
|
|
||||||
[],
|
|
||||||
true,
|
|
||||||
true,
|
|
||||||
false,
|
|
||||||
true,
|
|
||||||
),
|
|
||||||
|
|
||||||
// Hacker groups
|
|
||||||
BitRunners: new FactionInfo(
|
|
||||||
"Our entire lives are controlled by bits. All of our actions, our thoughts, our personal information. It's " +
|
|
||||||
"all transformed into bits, stored in bits, communicated through bits. It’s impossible for any person to move, " +
|
|
||||||
"to live, to operate at any level without the use of bits. And when a person moves, lives, and operates, they " +
|
|
||||||
"leave behind their bits, mere traces of seemingly meaningless fragments of information. But these bits can be " +
|
|
||||||
"reconstructed. Transformed. Used.<br>" +
|
|
||||||
"<br>" +
|
|
||||||
"Those who run the bits, run the world.",
|
|
||||||
[],
|
|
||||||
true,
|
|
||||||
true,
|
|
||||||
false,
|
|
||||||
false,
|
|
||||||
),
|
|
||||||
|
|
||||||
"The Black Hand": new FactionInfo(
|
|
||||||
"The world, so afraid of strong government, now has no government. Only power - Digital power. Financial " +
|
|
||||||
"power. Technological power. And those at the top rule with an invisible hand. They built a society where the " +
|
|
||||||
"rich get richer, and everyone else suffers.<br>" +
|
|
||||||
"<br>" +
|
|
||||||
"So much pain. So many lives. Their darkness must end.",
|
|
||||||
[],
|
|
||||||
true,
|
|
||||||
true,
|
|
||||||
true,
|
|
||||||
false,
|
|
||||||
),
|
|
||||||
|
|
||||||
NiteSec: new FactionInfo(
|
|
||||||
" __..__ <br>" +
|
|
||||||
" _.nITESECNIt. <br>" +
|
|
||||||
" .-'NITESECNITESEc. <br>" +
|
|
||||||
" .' NITESECNITESECn <br>" +
|
|
||||||
" / NITESECNITESEC; <br>" +
|
|
||||||
" : :NITESECNITESEC; <br>" +
|
|
||||||
" ; $ NITESECNITESECN <br>" +
|
|
||||||
" : _, ,N'ITESECNITESEC <br>" +
|
|
||||||
" : .+^^`, : `NITESECNIT <br>" +
|
|
||||||
" ) /), `-,-=,NITESECNI <br>" +
|
|
||||||
" / ^ ,-;|NITESECN; <br>" +
|
|
||||||
" / _.' '-';NITESECN <br>" +
|
|
||||||
" ( , ,-''`^NITE' <br>" +
|
|
||||||
" )` :`. .' <br>" +
|
|
||||||
" )-- ; `- / <br>" +
|
|
||||||
" ' _.-' : <br>" +
|
|
||||||
" ( _.-' . <br>" +
|
|
||||||
" ------. <br>" +
|
|
||||||
" . <br>" +
|
|
||||||
" _.nIt <br>" +
|
|
||||||
" _.nITESECNi <br>" +
|
|
||||||
" nITESECNIT^' <br>" +
|
|
||||||
" NITE^' ___ <br>" +
|
|
||||||
" / .gP''''Tp. <br>" +
|
|
||||||
" : d' . `b <br>" +
|
|
||||||
" ; d' o `b ; <br>" +
|
|
||||||
" / d; `b| <br>" +
|
|
||||||
" /, $; @ `: <br>" +
|
|
||||||
" /' $$ ; <br>" +
|
|
||||||
" .' $$b o | <br>" +
|
|
||||||
" .' d$$$; : <br>" +
|
|
||||||
" / .d$$$$; , ; <br>" +
|
|
||||||
" d .dNITESEC $ | <br>" +
|
|
||||||
" :bp.__.gNITESEC$$ :$ ; <br>" +
|
|
||||||
" NITESECNITESECNIT $$b : <br>",
|
|
||||||
[],
|
|
||||||
true,
|
|
||||||
true,
|
|
||||||
false,
|
|
||||||
false,
|
|
||||||
),
|
|
||||||
|
|
||||||
// City factions, essentially governments
|
|
||||||
Aevum: new FactionInfo("The Silicon City.", ["Chongqing", "New Tokyo", "Ishima", "Volhaven"], true, true, true, true),
|
|
||||||
Chongqing: new FactionInfo("Serve the People.", ["Sector-12", "Aevum", "Volhaven"], true, true, true, true),
|
|
||||||
Ishima: new FactionInfo(
|
|
||||||
"The East Asian Order of the Future.",
|
|
||||||
["Sector-12", "Aevum", "Volhaven"],
|
|
||||||
true,
|
|
||||||
true,
|
|
||||||
true,
|
|
||||||
true,
|
|
||||||
),
|
|
||||||
"New Tokyo": new FactionInfo("Asia's World City.", ["Sector-12", "Aevum", "Volhaven"], true, true, true, true),
|
|
||||||
"Sector-12": new FactionInfo(
|
|
||||||
"The City of the Future.",
|
|
||||||
["Chongqing", "New Tokyo", "Ishima", "Volhaven"],
|
|
||||||
true,
|
|
||||||
true,
|
|
||||||
true,
|
|
||||||
true,
|
|
||||||
),
|
|
||||||
Volhaven: new FactionInfo(
|
|
||||||
"Benefit, Honor, and Glory.",
|
|
||||||
["Chongqing", "Sector-12", "New Tokyo", "Aevum", "Ishima"],
|
|
||||||
true,
|
|
||||||
true,
|
|
||||||
true,
|
|
||||||
true,
|
|
||||||
),
|
|
||||||
|
|
||||||
// Criminal Organizations/Gangs
|
|
||||||
"Speakers for the Dead": new FactionInfo(
|
|
||||||
"It is better to reign in Hell than to serve in Heaven.",
|
|
||||||
[],
|
|
||||||
true,
|
|
||||||
true,
|
|
||||||
true,
|
|
||||||
true,
|
|
||||||
),
|
|
||||||
|
|
||||||
"The Dark Army": new FactionInfo(
|
|
||||||
"The World doesn't care about right or wrong. It only cares about power.",
|
|
||||||
[],
|
|
||||||
true,
|
|
||||||
true,
|
|
||||||
true,
|
|
||||||
false,
|
|
||||||
),
|
|
||||||
|
|
||||||
"The Syndicate": new FactionInfo("Honor holds you back.", [], true, true, true, true),
|
|
||||||
|
|
||||||
Silhouette: new FactionInfo(
|
|
||||||
"Corporations have filled the void of power left behind by the collapse of Western government. The issue is " +
|
|
||||||
"they've become so big that you don't know who they're working for. And if you're employed at one of these " +
|
|
||||||
"corporations, you don't even know who you're working for.<br>" +
|
|
||||||
"<br>" +
|
|
||||||
"That's terror. Terror, fear, and corruption. All born into the system, all propagated by the system.",
|
|
||||||
[],
|
|
||||||
true,
|
|
||||||
true,
|
|
||||||
true,
|
|
||||||
false,
|
|
||||||
),
|
|
||||||
|
|
||||||
Tetrads: new FactionInfo("Following the mandate of Heaven and carrying out the way.", [], false, false, true, true),
|
|
||||||
|
|
||||||
"Slum Snakes": new FactionInfo("Slum Snakes rule!", [], false, false, true, true),
|
|
||||||
|
|
||||||
// Earlygame factions - factions the player will prestige with early on that don't belong in other categories.
|
|
||||||
Netburners: new FactionInfo("~~//*>H4CK||3T 8URN3R5**>?>\\~~", [], true, true, false, false),
|
|
||||||
|
|
||||||
"Tian Di Hui": new FactionInfo("Obey Heaven and work righteously.", [], true, true, false, true),
|
|
||||||
|
|
||||||
CyberSec: new FactionInfo(
|
|
||||||
"The Internet is the first thing that was built that we don't fully understand, the largest " +
|
|
||||||
"experiment in anarchy that we have ever had. And as the world becomes increasingly dominated by it, " +
|
|
||||||
"society approaches the brink of total chaos. We serve only to protect society, to protect humanity, to " +
|
|
||||||
"protect the world from imminent collapse.",
|
|
||||||
[],
|
|
||||||
true,
|
|
||||||
true,
|
|
||||||
false,
|
|
||||||
false,
|
|
||||||
),
|
|
||||||
|
|
||||||
// Special Factions
|
|
||||||
Bladeburners: new FactionInfo(
|
|
||||||
"It's too bad they won't live. But then again, who does?<br><br>Note that for this faction, reputation can " +
|
|
||||||
"only be gained through Bladeburner actions. Completing Bladeburner contracts/operations will increase your " +
|
|
||||||
"reputation.",
|
|
||||||
[],
|
|
||||||
false,
|
|
||||||
false,
|
|
||||||
false,
|
|
||||||
false,
|
|
||||||
),
|
|
||||||
};
|
|
433
src/Faction/FactionInfo.tsx
Normal file
433
src/Faction/FactionInfo.tsx
Normal file
@ -0,0 +1,433 @@
|
|||||||
|
import React from "react";
|
||||||
|
import { IMap } from "../types";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Contains the "information" property for all the Factions, which is just a description of each faction
|
||||||
|
*/
|
||||||
|
export class FactionInfo {
|
||||||
|
/**
|
||||||
|
* The multiplier to apply to augmentation base purchase price.
|
||||||
|
*/
|
||||||
|
augmentationPriceMult: number;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The multiplier to apply to augmentation reputation base requirement.
|
||||||
|
*/
|
||||||
|
augmentationRepRequirementMult: number;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The names of all other factions considered to be enemies to this faction.
|
||||||
|
*/
|
||||||
|
enemies: string[];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The descriptive text to show on the faction's page.
|
||||||
|
*/
|
||||||
|
infoText: JSX.Element;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A flag indicating if the faction supports field work to earn reputation.
|
||||||
|
*/
|
||||||
|
offerFieldWork: boolean;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A flag indicating if the faction supports hacking missions to earn reputation.
|
||||||
|
*/
|
||||||
|
offerHackingMission: boolean;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A flag indicating if the faction supports hacking work to earn reputation.
|
||||||
|
*/
|
||||||
|
offerHackingWork: boolean;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A flag indicating if the faction supports security work to earn reputation.
|
||||||
|
*/
|
||||||
|
offerSecurityWork: boolean;
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
infoText: JSX.Element,
|
||||||
|
enemies: string[],
|
||||||
|
offerHackingMission: boolean,
|
||||||
|
offerHackingWork: boolean,
|
||||||
|
offerFieldWork: boolean,
|
||||||
|
offerSecurityWork: boolean,
|
||||||
|
) {
|
||||||
|
this.infoText = infoText;
|
||||||
|
this.enemies = enemies;
|
||||||
|
this.offerHackingMission = offerHackingMission;
|
||||||
|
this.offerHackingWork = offerHackingWork;
|
||||||
|
this.offerFieldWork = offerFieldWork;
|
||||||
|
this.offerSecurityWork = offerSecurityWork;
|
||||||
|
|
||||||
|
// These are always all 1 for now.
|
||||||
|
this.augmentationPriceMult = 1;
|
||||||
|
this.augmentationRepRequirementMult = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
offersWork(): boolean {
|
||||||
|
return this.offerFieldWork || this.offerHackingMission || this.offerHackingWork || this.offerSecurityWork;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A map of all factions and associated info to them.
|
||||||
|
*/
|
||||||
|
// tslint:disable-next-line:variable-name
|
||||||
|
export const FactionInfos: IMap<FactionInfo> = {
|
||||||
|
// Endgame
|
||||||
|
Illuminati: new FactionInfo(
|
||||||
|
(
|
||||||
|
<>
|
||||||
|
Humanity never changes. No matter how civilized society becomes, it will eventually fall back into chaos. And
|
||||||
|
from this chaos, we are the invisible hand that guides them to order.{" "}
|
||||||
|
</>
|
||||||
|
),
|
||||||
|
[],
|
||||||
|
true,
|
||||||
|
true,
|
||||||
|
true,
|
||||||
|
false,
|
||||||
|
),
|
||||||
|
|
||||||
|
Daedalus: new FactionInfo(
|
||||||
|
<>Yesterday we obeyed kings and bent our necks to emperors. Today we kneel only to truth.</>,
|
||||||
|
[],
|
||||||
|
true,
|
||||||
|
true,
|
||||||
|
true,
|
||||||
|
false,
|
||||||
|
),
|
||||||
|
|
||||||
|
"The Covenant": new FactionInfo(
|
||||||
|
(
|
||||||
|
<>
|
||||||
|
Surrender yourself. Give up your empty individuality to become part of something great, something eternal.
|
||||||
|
Become a slave. Submit your mind, body, and soul. Only then can you set yourself free.
|
||||||
|
<br />
|
||||||
|
<br />
|
||||||
|
Only then can you discover immortality.
|
||||||
|
</>
|
||||||
|
),
|
||||||
|
[],
|
||||||
|
true,
|
||||||
|
true,
|
||||||
|
true,
|
||||||
|
false,
|
||||||
|
),
|
||||||
|
|
||||||
|
// Megacorporations, each forms its own faction
|
||||||
|
ECorp: new FactionInfo(
|
||||||
|
(
|
||||||
|
<>
|
||||||
|
ECorp's mission is simple: to connect the world of today with the technology of tomorrow. With our wide range of
|
||||||
|
Internet-related software and commercial hardware, ECorp makes the world's information universally accessible.
|
||||||
|
</>
|
||||||
|
),
|
||||||
|
[],
|
||||||
|
true,
|
||||||
|
true,
|
||||||
|
true,
|
||||||
|
true,
|
||||||
|
),
|
||||||
|
|
||||||
|
MegaCorp: new FactionInfo(
|
||||||
|
(
|
||||||
|
<>
|
||||||
|
MegaCorp does what no other dares to do. We imagine. We create. We invent. We create what others have never even
|
||||||
|
dreamed of. Our work fills the world's needs for food, water, power, and transporation on an unprecendented
|
||||||
|
scale, in ways that no other company can.
|
||||||
|
<br />
|
||||||
|
<br />
|
||||||
|
In our labs and factories and on the ground with customers, MegaCorp is ushering in a new era for the world.
|
||||||
|
</>
|
||||||
|
),
|
||||||
|
[],
|
||||||
|
true,
|
||||||
|
true,
|
||||||
|
true,
|
||||||
|
true,
|
||||||
|
),
|
||||||
|
|
||||||
|
"Bachman & Associates": new FactionInfo(
|
||||||
|
(
|
||||||
|
<>
|
||||||
|
Where Law and Business meet - thats where we are.
|
||||||
|
<br />
|
||||||
|
<br />
|
||||||
|
Legal Insight - Business Instinct - Innovative Experience.
|
||||||
|
</>
|
||||||
|
),
|
||||||
|
[],
|
||||||
|
true,
|
||||||
|
true,
|
||||||
|
true,
|
||||||
|
true,
|
||||||
|
),
|
||||||
|
|
||||||
|
"Blade Industries": new FactionInfo(<>Augmentation is Salvation.</>, [], true, true, true, true),
|
||||||
|
|
||||||
|
NWO: new FactionInfo(
|
||||||
|
(
|
||||||
|
<>
|
||||||
|
Humans don't truly desire freedom. They want to be observed, understood, and judged. They want to be given
|
||||||
|
purpose and direction in life. That is why they created God. And that is why they created civilization - not
|
||||||
|
because of willingness, but because of a need to be incorporated into higher orders of structure and meaning.
|
||||||
|
</>
|
||||||
|
),
|
||||||
|
[],
|
||||||
|
true,
|
||||||
|
true,
|
||||||
|
true,
|
||||||
|
true,
|
||||||
|
),
|
||||||
|
|
||||||
|
"Clarke Incorporated": new FactionInfo(<>The Power of the Genome - Unlocked.</>, [], true, true, true, true),
|
||||||
|
|
||||||
|
"OmniTek Incorporated": new FactionInfo(
|
||||||
|
<>Simply put, our mission is to design and build robots that make a difference.</>,
|
||||||
|
[],
|
||||||
|
true,
|
||||||
|
true,
|
||||||
|
true,
|
||||||
|
true,
|
||||||
|
),
|
||||||
|
|
||||||
|
"Four Sigma": new FactionInfo(
|
||||||
|
(
|
||||||
|
<>
|
||||||
|
The scientific method is the best way to approach investing. Big strategies backed up with big data. Driven by
|
||||||
|
deep learning and innovative ideas. And improved by iteration. That's Four Sigma.
|
||||||
|
</>
|
||||||
|
),
|
||||||
|
[],
|
||||||
|
true,
|
||||||
|
true,
|
||||||
|
true,
|
||||||
|
true,
|
||||||
|
),
|
||||||
|
|
||||||
|
"KuaiGong International": new FactionInfo(<>Dream big. Work hard. Make history.</>, [], true, true, true, true),
|
||||||
|
|
||||||
|
// Other Corporations
|
||||||
|
"Fulcrum Secret Technologies": new FactionInfo(
|
||||||
|
(
|
||||||
|
<>
|
||||||
|
The human organism has an innate desire to worship. That is why they created gods. If there were no gods, it
|
||||||
|
would be necessary to create them. And now we can.
|
||||||
|
</>
|
||||||
|
),
|
||||||
|
[],
|
||||||
|
true,
|
||||||
|
true,
|
||||||
|
false,
|
||||||
|
true,
|
||||||
|
),
|
||||||
|
|
||||||
|
// Hacker groups
|
||||||
|
BitRunners: new FactionInfo(
|
||||||
|
(
|
||||||
|
<>
|
||||||
|
Our entire lives are controlled by bits. All of our actions, our thoughts, our personal information. It's all
|
||||||
|
transformed into bits, stored in bits, communicated through bits. It’s impossible for any person to move, to
|
||||||
|
live, to operate at any level without the use of bits. And when a person moves, lives, and operates, they leave
|
||||||
|
behind their bits, mere traces of seemingly meaningless fragments of information. But these bits can be
|
||||||
|
reconstructed. Transformed. Used.
|
||||||
|
<br />
|
||||||
|
<br />
|
||||||
|
Those who run the bits, run the world.
|
||||||
|
</>
|
||||||
|
),
|
||||||
|
[],
|
||||||
|
true,
|
||||||
|
true,
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
),
|
||||||
|
|
||||||
|
"The Black Hand": new FactionInfo(
|
||||||
|
(
|
||||||
|
<>
|
||||||
|
The world, so afraid of strong government, now has no government. Only power - Digital power. Financial power.
|
||||||
|
Technological power. And those at the top rule with an invisible hand. They built a society where the rich get
|
||||||
|
richer, and everyone else suffers.
|
||||||
|
<br />
|
||||||
|
<br />
|
||||||
|
So much pain. So many lives. Their darkness must end.
|
||||||
|
</>
|
||||||
|
),
|
||||||
|
[],
|
||||||
|
true,
|
||||||
|
true,
|
||||||
|
true,
|
||||||
|
false,
|
||||||
|
),
|
||||||
|
|
||||||
|
// prettier-ignore
|
||||||
|
NiteSec: new FactionInfo(<>
|
||||||
|
{" __..__ "}<br />
|
||||||
|
{" _.nITESECNIt. "}<br />
|
||||||
|
{" .-'NITESECNITESEc. "}<br />
|
||||||
|
{" .' NITESECNITESECn "}<br />
|
||||||
|
{" / NITESECNITESEC; "}<br />
|
||||||
|
{" : :NITESECNITESEC; "}<br />
|
||||||
|
{" ; $ NITESECNITESECN "}<br />
|
||||||
|
{" : _, ,N'ITESECNITESEC "}<br />
|
||||||
|
{" : .+^^`, : `NITESECNIT "}<br />
|
||||||
|
{" ) /), `-,-=,NITESECNI "}<br />
|
||||||
|
{" / ^ ,-;|NITESECN; "}<br />
|
||||||
|
{" / _.' '-';NITESECN "}<br />
|
||||||
|
{" ( , ,-''`^NITE' "}<br />
|
||||||
|
{" )` :`. .' "}<br />
|
||||||
|
{" )-- ; `- / "}<br />
|
||||||
|
{" ' _.-' : "}<br />
|
||||||
|
{" ( _.-' . "}<br />
|
||||||
|
{" ------. "}<br />
|
||||||
|
{" . "}<br />
|
||||||
|
{" _.nIt "}<br />
|
||||||
|
{" _.nITESECNi "}<br />
|
||||||
|
{" nITESECNIT^' "}<br />
|
||||||
|
{" NITE^' ___ "}<br />
|
||||||
|
{" / .gP''''Tp. "}<br />
|
||||||
|
{" : d' . `b "}<br />
|
||||||
|
{" ; d' o `b ; "}<br />
|
||||||
|
{" / d; `b| "}<br />
|
||||||
|
{" /, $; @ `: "}<br />
|
||||||
|
{" /' $$ ; "}<br />
|
||||||
|
{" .' $$b o | "}<br />
|
||||||
|
{" .' d$$$; : "}<br />
|
||||||
|
{" / .d$$$$; , ; "}<br />
|
||||||
|
{" d .dNITESEC $ | "}<br />
|
||||||
|
{" :bp.__.gNITESEC$$ :$ ; "}<br />
|
||||||
|
{" NITESECNITESECNIT $$b : "}<br /></>,
|
||||||
|
[],
|
||||||
|
true,
|
||||||
|
true,
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
),
|
||||||
|
|
||||||
|
// City factions, essentially governments
|
||||||
|
Aevum: new FactionInfo(
|
||||||
|
<>The Silicon City.</>,
|
||||||
|
["Chongqing", "New Tokyo", "Ishima", "Volhaven"],
|
||||||
|
true,
|
||||||
|
true,
|
||||||
|
true,
|
||||||
|
true,
|
||||||
|
),
|
||||||
|
Chongqing: new FactionInfo(<>Serve the People.</>, ["Sector-12", "Aevum", "Volhaven"], true, true, true, true),
|
||||||
|
Ishima: new FactionInfo(
|
||||||
|
<>The East Asian Order of the Future.</>,
|
||||||
|
["Sector-12", "Aevum", "Volhaven"],
|
||||||
|
true,
|
||||||
|
true,
|
||||||
|
true,
|
||||||
|
true,
|
||||||
|
),
|
||||||
|
"New Tokyo": new FactionInfo(<>Asia's World City.</>, ["Sector-12", "Aevum", "Volhaven"], true, true, true, true),
|
||||||
|
"Sector-12": new FactionInfo(
|
||||||
|
<>The City of the Future.</>,
|
||||||
|
["Chongqing", "New Tokyo", "Ishima", "Volhaven"],
|
||||||
|
true,
|
||||||
|
true,
|
||||||
|
true,
|
||||||
|
true,
|
||||||
|
),
|
||||||
|
Volhaven: new FactionInfo(
|
||||||
|
<>Benefit, Honor, and Glory.</>,
|
||||||
|
["Chongqing", "Sector-12", "New Tokyo", "Aevum", "Ishima"],
|
||||||
|
true,
|
||||||
|
true,
|
||||||
|
true,
|
||||||
|
true,
|
||||||
|
),
|
||||||
|
|
||||||
|
// Criminal Organizations/Gangs
|
||||||
|
"Speakers for the Dead": new FactionInfo(
|
||||||
|
<>It is better to reign in Hell than to serve in Heaven.</>,
|
||||||
|
[],
|
||||||
|
true,
|
||||||
|
true,
|
||||||
|
true,
|
||||||
|
true,
|
||||||
|
),
|
||||||
|
|
||||||
|
"The Dark Army": new FactionInfo(
|
||||||
|
<>The World doesn't care about right or wrong. It only cares about power.</>,
|
||||||
|
[],
|
||||||
|
true,
|
||||||
|
true,
|
||||||
|
true,
|
||||||
|
false,
|
||||||
|
),
|
||||||
|
|
||||||
|
"The Syndicate": new FactionInfo(<>Honor holds you back.</>, [], true, true, true, true),
|
||||||
|
|
||||||
|
Silhouette: new FactionInfo(
|
||||||
|
(
|
||||||
|
<>
|
||||||
|
Corporations have filled the void of power left behind by the collapse of Western government. The issue is
|
||||||
|
they've become so big that you don't know who they're working for. And if you're employed at one of these
|
||||||
|
corporations, you don't even know who you're working for.
|
||||||
|
<br />
|
||||||
|
<br />
|
||||||
|
That's terror. Terror, fear, and corruption. All born into the system, all propagated by the system.
|
||||||
|
</>
|
||||||
|
),
|
||||||
|
[],
|
||||||
|
true,
|
||||||
|
true,
|
||||||
|
true,
|
||||||
|
false,
|
||||||
|
),
|
||||||
|
|
||||||
|
Tetrads: new FactionInfo(
|
||||||
|
<>Following the mandate of Heaven and carrying out the way.</>,
|
||||||
|
[],
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
true,
|
||||||
|
true,
|
||||||
|
),
|
||||||
|
|
||||||
|
"Slum Snakes": new FactionInfo(<>Slum Snakes rule!</>, [], false, false, true, true),
|
||||||
|
|
||||||
|
// Earlygame factions - factions the player will prestige with early on that don't belong in other categories.
|
||||||
|
Netburners: new FactionInfo(<>{"~~//*>H4CK||3T 8URN3R5**>?>\\~~"}</>, [], true, true, false, false),
|
||||||
|
|
||||||
|
"Tian Di Hui": new FactionInfo(<>Obey Heaven and work righteously.</>, [], true, true, false, true),
|
||||||
|
|
||||||
|
CyberSec: new FactionInfo(
|
||||||
|
(
|
||||||
|
<>
|
||||||
|
The Internet is the first thing that was built that we don't fully understand, the largest experiment in anarchy
|
||||||
|
that we have ever had. And as the world becomes increasingly dominated by it, society approaches the brink of
|
||||||
|
total chaos. We serve only to protect society, to protect humanity, to protect the world from imminent collapse.
|
||||||
|
</>
|
||||||
|
),
|
||||||
|
[],
|
||||||
|
true,
|
||||||
|
true,
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
),
|
||||||
|
|
||||||
|
// Special Factions
|
||||||
|
Bladeburners: new FactionInfo(
|
||||||
|
(
|
||||||
|
<>
|
||||||
|
It's too bad they won't live. But then again, who does?
|
||||||
|
<br />
|
||||||
|
<br />
|
||||||
|
Note that for this faction, reputation can only be gained through Bladeburner actions. Completing Bladeburner
|
||||||
|
contracts/operations will increase your reputation.
|
||||||
|
</>
|
||||||
|
),
|
||||||
|
[],
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
),
|
||||||
|
};
|
@ -14,6 +14,11 @@ import { Settings } from "../../Settings/Settings";
|
|||||||
import { StdButton } from "../../ui/React/StdButton";
|
import { StdButton } from "../../ui/React/StdButton";
|
||||||
import { use } from "../../ui/Context";
|
import { use } from "../../ui/Context";
|
||||||
|
|
||||||
|
import Button from "@mui/material/Button";
|
||||||
|
import Typography from "@mui/material/Typography";
|
||||||
|
import TableBody from "@mui/material/TableBody";
|
||||||
|
import Table from "@mui/material/Table";
|
||||||
|
|
||||||
type IProps = {
|
type IProps = {
|
||||||
faction: Faction;
|
faction: Faction;
|
||||||
routeToMainPage: () => void;
|
routeToMainPage: () => void;
|
||||||
@ -104,8 +109,17 @@ export function AugmentationsPage(props: IProps): React.ReactElement {
|
|||||||
(!player.augmentations.some((a) => a.name === aug) && !player.queuedAugmentations.some((a) => a.name === aug)),
|
(!player.augmentations.some((a) => a.name === aug) && !player.queuedAugmentations.some((a) => a.name === aug)),
|
||||||
);
|
);
|
||||||
|
|
||||||
const purchaseableAugmentation = (aug: string): React.ReactNode => {
|
const purchaseableAugmentation = (aug: string, owned = false): React.ReactNode => {
|
||||||
return <PurchaseableAugmentation augName={aug} faction={props.faction} key={aug} p={player} rerender={rerender} />;
|
return (
|
||||||
|
<PurchaseableAugmentation
|
||||||
|
augName={aug}
|
||||||
|
faction={props.faction}
|
||||||
|
key={aug}
|
||||||
|
p={player}
|
||||||
|
rerender={rerender}
|
||||||
|
owned={owned}
|
||||||
|
/>
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const augListElems = purchasable.map((aug) => purchaseableAugmentation(aug));
|
const augListElems = purchasable.map((aug) => purchaseableAugmentation(aug));
|
||||||
@ -116,42 +130,33 @@ export function AugmentationsPage(props: IProps): React.ReactElement {
|
|||||||
ownedElem = (
|
ownedElem = (
|
||||||
<>
|
<>
|
||||||
<br />
|
<br />
|
||||||
<h2>Purchased Augmentations</h2>
|
<Typography variant="h4">Purchased Augmentations</Typography>
|
||||||
<p>This factions also offers these augmentations but you already own them.</p>
|
<Typography>This factions also offers these augmentations but you already own them.</Typography>
|
||||||
{owned.map((aug) => purchaseableAugmentation(aug))}
|
{owned.map((aug) => purchaseableAugmentation(aug, true))}
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<StdButton onClick={props.routeToMainPage} text={"Back"} />
|
<Button onClick={props.routeToMainPage}>Back</Button>
|
||||||
<h1>Faction Augmentations</h1>
|
<Typography variant="h4">Faction Augmentations</Typography>
|
||||||
<p>
|
<Typography>
|
||||||
These are all of the Augmentations that are available to purchase from {props.faction.name}. Augmentations are
|
These are all of the Augmentations that are available to purchase from {props.faction.name}. Augmentations are
|
||||||
powerful upgrades that will enhance your abilities.
|
powerful upgrades that will enhance your abilities.
|
||||||
</p>
|
</Typography>
|
||||||
<StdButton onClick={() => switchSortOrder(PurchaseAugmentationsOrderSetting.Cost)} text={"Sort by Cost"} />
|
<Button onClick={() => switchSortOrder(PurchaseAugmentationsOrderSetting.Cost)}>Sort by Cost</Button>
|
||||||
<StdButton
|
<Button onClick={() => switchSortOrder(PurchaseAugmentationsOrderSetting.Reputation)}>Sort by Reputation</Button>
|
||||||
onClick={() => switchSortOrder(PurchaseAugmentationsOrderSetting.Reputation)}
|
<Button onClick={() => switchSortOrder(PurchaseAugmentationsOrderSetting.Default)}>Sort by Default Order</Button>
|
||||||
text={"Sort by Reputation"}
|
|
||||||
/>
|
|
||||||
<StdButton
|
|
||||||
onClick={() => switchSortOrder(PurchaseAugmentationsOrderSetting.Default)}
|
|
||||||
text={"Sort by Default Order"}
|
|
||||||
/>
|
|
||||||
<br />
|
|
||||||
{augListElems}
|
|
||||||
{ownedElem}
|
|
||||||
<br />
|
|
||||||
<br />
|
|
||||||
<br />
|
|
||||||
<br />
|
|
||||||
<br />
|
|
||||||
<br />
|
|
||||||
<br />
|
|
||||||
<br />
|
|
||||||
<br />
|
<br />
|
||||||
|
|
||||||
|
<Table size="small" padding="none">
|
||||||
|
<TableBody>{augListElems}</TableBody>
|
||||||
|
</Table>
|
||||||
|
|
||||||
|
<Table size="small" padding="none">
|
||||||
|
<TableBody>{ownedElem}</TableBody>
|
||||||
|
</Table>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -7,6 +7,7 @@ import { CONSTANTS } from "../../Constants";
|
|||||||
import { Faction } from "../../Faction/Faction";
|
import { Faction } from "../../Faction/Faction";
|
||||||
import { IPlayer } from "../../PersonObjects/IPlayer";
|
import { IPlayer } from "../../PersonObjects/IPlayer";
|
||||||
import { repFromDonation } from "../formulas/donation";
|
import { repFromDonation } from "../formulas/donation";
|
||||||
|
import { Favor } from "../../ui/React/Favor";
|
||||||
|
|
||||||
import { Money } from "../../ui/React/Money";
|
import { Money } from "../../ui/React/Money";
|
||||||
import { Reputation } from "../../ui/React/Reputation";
|
import { Reputation } from "../../ui/React/Reputation";
|
||||||
@ -18,6 +19,11 @@ import { numeralWrapper } from "../../ui/numeralFormat";
|
|||||||
import { dialogBoxCreate } from "../../../utils/DialogBox";
|
import { dialogBoxCreate } from "../../../utils/DialogBox";
|
||||||
import { MathComponent } from "mathjax-react";
|
import { MathComponent } from "mathjax-react";
|
||||||
|
|
||||||
|
import Typography from "@mui/material/Typography";
|
||||||
|
import Paper from "@mui/material/Paper";
|
||||||
|
import Button from "@mui/material/Button";
|
||||||
|
import TextField from "@mui/material/TextField";
|
||||||
|
|
||||||
type IProps = {
|
type IProps = {
|
||||||
faction: Faction;
|
faction: Faction;
|
||||||
disabled: boolean;
|
disabled: boolean;
|
||||||
@ -67,36 +73,45 @@ export function DonateOption(props: IProps): React.ReactElement {
|
|||||||
function Status(): React.ReactElement {
|
function Status(): React.ReactElement {
|
||||||
if (donateAmt === null) return <></>;
|
if (donateAmt === null) return <></>;
|
||||||
if (!canDonate()) {
|
if (!canDonate()) {
|
||||||
if (props.p.money.lt(donateAmt)) return <p>Insufficient funds</p>;
|
if (props.p.money.lt(donateAmt)) return <Typography>Insufficient funds</Typography>;
|
||||||
return <p>Invalid donate amount entered!</p>;
|
return <Typography>Invalid donate amount entered!</Typography>;
|
||||||
}
|
}
|
||||||
return <p>This donation will result in {Reputation(repFromDonation(donateAmt, props.p))} reputation gain</p>;
|
return (
|
||||||
|
<Typography>
|
||||||
|
This donation will result in {Reputation(repFromDonation(donateAmt, props.p))} reputation gain
|
||||||
|
</Typography>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={"faction-work-div"}>
|
<Paper sx={{ my: 1, p: 1, width: "100%" }}>
|
||||||
<div className={"faction-work-div-wrapper"}>
|
<Status />
|
||||||
<input
|
{props.disabled ? (
|
||||||
className="text-input"
|
<Typography>
|
||||||
onChange={onChange}
|
Unlock donations at {Favor(props.favorToDonate)} favor with {props.faction.name}
|
||||||
placeholder={"Donation amount"}
|
</Typography>
|
||||||
style={inputStyleMarkup}
|
) : (
|
||||||
disabled={props.disabled}
|
<>
|
||||||
/>
|
<TextField
|
||||||
<StdButton onClick={donate} text={"Donate Money"} disabled={props.disabled || !canDonate()} />
|
variant="standard"
|
||||||
<Status />
|
onChange={onChange}
|
||||||
{props.disabled ? (
|
placeholder={"Donation amount"}
|
||||||
<p>
|
disabled={props.disabled}
|
||||||
Unlocked at {props.favorToDonate} favor with {props.faction.name}
|
InputProps={{
|
||||||
</p>
|
endAdornment: (
|
||||||
) : (
|
<Button onClick={donate} disabled={props.disabled || !canDonate()}>
|
||||||
<div className="text">
|
donate
|
||||||
|
</Button>
|
||||||
|
),
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<Typography>
|
||||||
<MathComponent
|
<MathComponent
|
||||||
tex={String.raw`reputation = \frac{\text{donation amount} \times \text{reputation multiplier}}{10^{${digits}}}`}
|
tex={String.raw`reputation = \frac{\text{donation amount} \times \text{reputation multiplier}}{10^{${digits}}}`}
|
||||||
/>
|
/>
|
||||||
</div>
|
</Typography>
|
||||||
)}
|
</>
|
||||||
</div>
|
)}
|
||||||
</div>
|
</Paper>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -21,6 +21,9 @@ import { createPopup } from "../../ui/React/createPopup";
|
|||||||
import { use } from "../../ui/Context";
|
import { use } from "../../ui/Context";
|
||||||
import { CreateGangPopup } from "./CreateGangPopup";
|
import { CreateGangPopup } from "./CreateGangPopup";
|
||||||
|
|
||||||
|
import Typography from "@mui/material/Typography";
|
||||||
|
import Button from "@mui/material/Button";
|
||||||
|
|
||||||
type IProps = {
|
type IProps = {
|
||||||
faction: Faction;
|
faction: Faction;
|
||||||
};
|
};
|
||||||
@ -145,8 +148,11 @@ export function FactionRoot(props: IProps): React.ReactElement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="faction-container">
|
<>
|
||||||
<h1>{faction.name}</h1>
|
<Button onClick={() => router.toFactions()}>Back</Button>
|
||||||
|
<Typography variant="h4" color="primary">
|
||||||
|
{faction.name}
|
||||||
|
</Typography>
|
||||||
<Info faction={faction} factionInfo={factionInfo} />
|
<Info faction={faction} factionInfo={factionInfo} />
|
||||||
{canAccessGang && <Option buttonText={"Manage Gang"} infoText={gangInfo} onClick={() => manageGang(faction)} />}
|
{canAccessGang && <Option buttonText={"Manage Gang"} infoText={gangInfo} onClick={() => manageGang(faction)} />}
|
||||||
{!isPlayersGang && factionInfo.offerHackingMission && (
|
{!isPlayersGang && factionInfo.offerHackingMission && (
|
||||||
@ -186,7 +192,7 @@ export function FactionRoot(props: IProps): React.ReactElement {
|
|||||||
onClick={sleevePurchases}
|
onClick={sleevePurchases}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</div>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -13,85 +13,79 @@ import { Reputation } from "../../ui/React/Reputation";
|
|||||||
import { Favor } from "../../ui/React/Favor";
|
import { Favor } from "../../ui/React/Favor";
|
||||||
import { MathComponent } from "mathjax-react";
|
import { MathComponent } from "mathjax-react";
|
||||||
|
|
||||||
|
import { Theme } from "@mui/material/styles";
|
||||||
|
import makeStyles from "@mui/styles/makeStyles";
|
||||||
|
import createStyles from "@mui/styles/createStyles";
|
||||||
|
import Typography from "@mui/material/Typography";
|
||||||
|
import Tooltip from "@mui/material/Tooltip";
|
||||||
|
import Box from "@mui/material/Box";
|
||||||
|
|
||||||
type IProps = {
|
type IProps = {
|
||||||
faction: Faction;
|
faction: Faction;
|
||||||
factionInfo: FactionInfo;
|
factionInfo: FactionInfo;
|
||||||
};
|
};
|
||||||
|
|
||||||
type IInnerHTMLMarkup = {
|
const useStyles = makeStyles((theme: Theme) =>
|
||||||
__html: string;
|
createStyles({
|
||||||
};
|
noformat: {
|
||||||
|
whiteSpace: "pre-wrap",
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
const blockStyleMarkup = {
|
export function Info(props: IProps): React.ReactElement {
|
||||||
display: "block",
|
const classes = useStyles();
|
||||||
};
|
|
||||||
|
|
||||||
const infoStyleMarkup = {
|
const favorGain = props.faction.getFavorGain()[0];
|
||||||
display: "block",
|
return (
|
||||||
width: "70%",
|
<>
|
||||||
};
|
<Typography classes={{ root: classes.noformat }}>{props.factionInfo.infoText}</Typography>
|
||||||
|
<Typography>-------------------------</Typography>
|
||||||
|
<Box display="flex">
|
||||||
|
<Tooltip
|
||||||
|
title={
|
||||||
|
<>
|
||||||
|
<Typography>
|
||||||
|
You will have {Favor(props.faction.favor + favorGain)} faction favor after installing an Augmentation.
|
||||||
|
</Typography>
|
||||||
|
<MathComponent tex={String.raw`\large{r = \text{total faction reputation}}`} />
|
||||||
|
<MathComponent
|
||||||
|
tex={String.raw`\large{favor=\left\lfloor\log_{1.02}\left(\frac{r+25000}{25500}\right)\right\rfloor}`}
|
||||||
|
/>
|
||||||
|
</>
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<Typography>Reputation: {Reputation(props.faction.playerReputation)}</Typography>
|
||||||
|
</Tooltip>
|
||||||
|
</Box>
|
||||||
|
|
||||||
export class Info extends React.Component<IProps, any> {
|
<Typography>-------------------------</Typography>
|
||||||
constructor(props: IProps) {
|
|
||||||
super(props);
|
|
||||||
|
|
||||||
this.getFavorGainContent = this.getFavorGainContent.bind(this);
|
<Box display="flex">
|
||||||
this.getReputationContent = this.getReputationContent.bind(this);
|
<Tooltip
|
||||||
}
|
title={
|
||||||
|
<>
|
||||||
|
<Typography>
|
||||||
|
Faction favor increases the rate at which you earn reputation for this faction by 1% per favor. Faction
|
||||||
|
favor is gained whenever you install an Augmentation. The amount of favor you gain depends on the total
|
||||||
|
amount of reputation you earned with this faction. Across all resets.
|
||||||
|
</Typography>
|
||||||
|
<MathComponent tex={String.raw`\large{r = reputation}`} />
|
||||||
|
<MathComponent tex={String.raw`\large{\Delta r = \Delta r \times \frac{100+favor}{100}}`} />
|
||||||
|
</>
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<Typography>Faction Favor: {Favor(props.faction.favor)}</Typography>
|
||||||
|
</Tooltip>
|
||||||
|
</Box>
|
||||||
|
|
||||||
getFavorGainContent(): JSX.Element {
|
<Typography>-------------------------</Typography>
|
||||||
const favorGain = this.props.faction.getFavorGain()[0];
|
<Typography>
|
||||||
return (
|
Perform work/carry out assignments for your faction to help further its cause! By doing so you will earn
|
||||||
<>
|
reputation for your faction. You will also gain reputation passively over time, although at a very slow rate.
|
||||||
You will have {Favor(this.props.faction.favor + favorGain)} faction favor after installing an Augmentation.
|
Earning reputation will allow you to purchase Augmentations through this faction, which are powerful upgrades
|
||||||
<MathComponent tex={String.raw`\large{r = \text{total faction reputation}}`} />
|
that enhance your abilities.
|
||||||
<MathComponent
|
</Typography>
|
||||||
tex={String.raw`\large{favor=\left\lfloor\log_{1.02}\left(\frac{r+25000}{25500}\right)\right\rfloor}`}
|
</>
|
||||||
/>
|
);
|
||||||
</>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
getReputationContent(): JSX.Element {
|
|
||||||
return <>Reputation: {Reputation(this.props.faction.playerReputation)}</>;
|
|
||||||
}
|
|
||||||
|
|
||||||
render(): React.ReactNode {
|
|
||||||
const favorTooltip = (
|
|
||||||
<>
|
|
||||||
Faction favor increases the rate at which you earn reputation for this faction by 1% per favor. Faction favor is
|
|
||||||
gained whenever you install an Augmentation. The amount of favor you gain depends on the total amount of
|
|
||||||
reputation you earned with this faction. Across all resets.
|
|
||||||
<MathComponent tex={String.raw`\large{r = reputation}`} />
|
|
||||||
<MathComponent tex={String.raw`\large{\Delta r = \Delta r \times \frac{100+favor}{100}}`} />
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
|
|
||||||
const infoText: IInnerHTMLMarkup = {
|
|
||||||
__html: this.props.factionInfo.infoText,
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div>
|
|
||||||
<pre>
|
|
||||||
<i className={"text"} dangerouslySetInnerHTML={infoText}></i>
|
|
||||||
</pre>
|
|
||||||
<p style={blockStyleMarkup}>-------------------------</p>
|
|
||||||
<AutoupdatingParagraph
|
|
||||||
intervalTime={5e3}
|
|
||||||
getContent={this.getReputationContent}
|
|
||||||
getTooltip={this.getFavorGainContent}
|
|
||||||
/>
|
|
||||||
<p style={blockStyleMarkup}>-------------------------</p>
|
|
||||||
<ParagraphWithTooltip content={<>Faction Favor: {Favor(this.props.faction.favor)}</>} tooltip={favorTooltip} />
|
|
||||||
<p style={blockStyleMarkup}>-------------------------</p>
|
|
||||||
<p style={infoStyleMarkup}>
|
|
||||||
Perform work/carry out assignments for your faction to help further its cause! By doing so you will earn
|
|
||||||
reputation for your faction. You will also gain reputation passively over time, although at a very slow rate.
|
|
||||||
Earning reputation will allow you to purchase Augmentations through this faction, which are powerful upgrades
|
|
||||||
that enhance your abilities.
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -7,21 +7,24 @@ import * as React from "react";
|
|||||||
|
|
||||||
import { StdButton } from "../../ui/React/StdButton";
|
import { StdButton } from "../../ui/React/StdButton";
|
||||||
|
|
||||||
|
import Typography from "@mui/material/Typography";
|
||||||
|
import Button from "@mui/material/Button";
|
||||||
|
import Paper from "@mui/material/Paper";
|
||||||
|
import Box from "@mui/material/Box";
|
||||||
|
|
||||||
type IProps = {
|
type IProps = {
|
||||||
buttonText: string;
|
buttonText: string;
|
||||||
infoText: string;
|
infoText: string;
|
||||||
onClick: (e: React.MouseEvent<HTMLElement>) => void;
|
onClick: (e: React.MouseEvent<HTMLElement>) => void;
|
||||||
};
|
};
|
||||||
|
|
||||||
export class Option extends React.Component<IProps, any> {
|
export function Option(props: IProps): React.ReactElement {
|
||||||
render(): React.ReactNode {
|
return (
|
||||||
return (
|
<Box>
|
||||||
<div className={"faction-work-div"}>
|
<Paper sx={{ my: 1, p: 1, width: "100%" }}>
|
||||||
<div className={"faction-work-div-wrapper"}>
|
<Button onClick={props.onClick}>{props.buttonText}</Button>
|
||||||
<StdButton onClick={this.props.onClick} text={this.props.buttonText} />
|
<Typography>{props.infoText}</Typography>
|
||||||
<p>{this.props.infoText}</p>
|
</Paper>
|
||||||
</div>
|
</Box>
|
||||||
</div>
|
);
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -19,13 +19,60 @@ import { IMap } from "../../types";
|
|||||||
|
|
||||||
import { StdButton } from "../../ui/React/StdButton";
|
import { StdButton } from "../../ui/React/StdButton";
|
||||||
import { Augmentation as AugFormat } from "../../ui/React/Augmentation";
|
import { Augmentation as AugFormat } from "../../ui/React/Augmentation";
|
||||||
|
import Button from "@mui/material/Button";
|
||||||
|
import Typography from "@mui/material/Typography";
|
||||||
|
import Tooltip from "@mui/material/Tooltip";
|
||||||
|
import Box from "@mui/material/Box";
|
||||||
|
import { TableCell } from "../../ui/React/Table";
|
||||||
|
import TableRow from "@mui/material/TableRow";
|
||||||
|
|
||||||
type IProps = {
|
interface IReqProps {
|
||||||
|
augName: string;
|
||||||
|
p: IPlayer;
|
||||||
|
hasReq: boolean;
|
||||||
|
rep: number;
|
||||||
|
hasRep: boolean;
|
||||||
|
cost: number;
|
||||||
|
hasCost: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
function Requirements(props: IReqProps): React.ReactElement {
|
||||||
|
const aug = Augmentations[props.augName];
|
||||||
|
if (!props.hasReq) {
|
||||||
|
return (
|
||||||
|
<TableCell key={1} colSpan={2}>
|
||||||
|
<Typography color="error">
|
||||||
|
Requires{" "}
|
||||||
|
{aug.prereqs.map((aug, i) => (
|
||||||
|
<AugFormat key={i} name={aug} />
|
||||||
|
))}
|
||||||
|
</Typography>
|
||||||
|
</TableCell>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
let color = !props.hasRep || !props.hasCost ? "error" : "primary";
|
||||||
|
return (
|
||||||
|
<React.Fragment key="f">
|
||||||
|
<TableCell key={1}>
|
||||||
|
<Typography color={color}>
|
||||||
|
<Money money={props.cost} player={props.p} />
|
||||||
|
</Typography>
|
||||||
|
</TableCell>
|
||||||
|
<TableCell key={2}>
|
||||||
|
<Typography color={color}>Requires {Reputation(props.rep)} faction reputation</Typography>
|
||||||
|
</TableCell>
|
||||||
|
</React.Fragment>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
interface IProps {
|
||||||
augName: string;
|
augName: string;
|
||||||
faction: Faction;
|
faction: Faction;
|
||||||
p: IPlayer;
|
p: IPlayer;
|
||||||
rerender: () => void;
|
rerender: () => void;
|
||||||
};
|
owned?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
export function PurchaseableAugmentation(props: IProps): React.ReactElement {
|
export function PurchaseableAugmentation(props: IProps): React.ReactElement {
|
||||||
const aug = Augmentations[props.augName];
|
const aug = Augmentations[props.augName];
|
||||||
@ -39,22 +86,6 @@ export function PurchaseableAugmentation(props: IProps): React.ReactElement {
|
|||||||
return aug.baseRepRequirement * props.faction.getInfo().augmentationRepRequirementMult;
|
return aug.baseRepRequirement * props.faction.getInfo().augmentationRepRequirementMult;
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleClick(): void {
|
|
||||||
if (!Settings.SuppressBuyAugmentationConfirmation) {
|
|
||||||
const popupId = "purchase-augmentation-popup";
|
|
||||||
createPopup(popupId, PurchaseAugmentationPopup, {
|
|
||||||
aug: aug,
|
|
||||||
faction: props.faction,
|
|
||||||
player: props.p,
|
|
||||||
rerender: props.rerender,
|
|
||||||
popupId: popupId,
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
purchaseAugmentation(aug, props.faction);
|
|
||||||
props.rerender();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Whether the player has the prerequisite Augmentations
|
// Whether the player has the prerequisite Augmentations
|
||||||
function hasPrereqs(): boolean {
|
function hasPrereqs(): boolean {
|
||||||
return hasAugmentationPrereqs(aug);
|
return hasAugmentationPrereqs(aug);
|
||||||
@ -94,39 +125,12 @@ export function PurchaseableAugmentation(props: IProps): React.ReactElement {
|
|||||||
|
|
||||||
const moneyCost = getMoneyCost();
|
const moneyCost = getMoneyCost();
|
||||||
const repCost = getRepCost();
|
const repCost = getRepCost();
|
||||||
|
const hasReq = hasPrereqs();
|
||||||
|
const hasRep = hasReputation();
|
||||||
|
const hasCost = aug.baseCost !== 0 && props.p.money.gt(aug.baseCost * props.faction.getInfo().augmentationPriceMult);
|
||||||
|
|
||||||
// Determine UI properties
|
// Determine UI properties
|
||||||
let disabled = false;
|
const color: "error" | "primary" = !hasReq || !hasRep || !hasCost ? "error" : "primary";
|
||||||
let status: JSX.Element = <></>;
|
|
||||||
let color = "";
|
|
||||||
if (!hasPrereqs()) {
|
|
||||||
disabled = true;
|
|
||||||
status = <>LOCKED (Requires {aug.prereqs.map((aug) => AugFormat(aug))} as prerequisite)</>;
|
|
||||||
color = "red";
|
|
||||||
} else if (aug.name !== AugmentationNames.NeuroFluxGovernor && (aug.owned || owned())) {
|
|
||||||
disabled = true;
|
|
||||||
} else if (hasReputation()) {
|
|
||||||
status = (
|
|
||||||
<>
|
|
||||||
UNLOCKED (at {Reputation(repCost)} faction reputation) - <Money money={moneyCost} player={props.p} />
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
disabled = true;
|
|
||||||
status = (
|
|
||||||
<>
|
|
||||||
LOCKED (Requires {Reputation(repCost)} faction reputation - <Money money={moneyCost} player={props.p} />)
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
color = "red";
|
|
||||||
}
|
|
||||||
|
|
||||||
const txtStyle: IMap<string> = {
|
|
||||||
display: "inline-block",
|
|
||||||
};
|
|
||||||
if (color !== "") {
|
|
||||||
txtStyle.color = color;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Determine button txt
|
// Determine button txt
|
||||||
let btnTxt = aug.name;
|
let btnTxt = aug.name;
|
||||||
@ -135,16 +139,16 @@ export function PurchaseableAugmentation(props: IProps): React.ReactElement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let tooltip = <></>;
|
let tooltip = <></>;
|
||||||
if (typeof aug.info === "string")
|
if (typeof aug.info === "string") {
|
||||||
tooltip = (
|
tooltip = (
|
||||||
<>
|
<>
|
||||||
<span dangerouslySetInnerHTML={{ __html: aug.info }} />
|
<span>{aug.info}</span>
|
||||||
<br />
|
<br />
|
||||||
<br />
|
<br />
|
||||||
{aug.stats}
|
{aug.stats}
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
else
|
} else
|
||||||
tooltip = (
|
tooltip = (
|
||||||
<>
|
<>
|
||||||
{aug.info}
|
{aug.info}
|
||||||
@ -154,25 +158,60 @@ export function PurchaseableAugmentation(props: IProps): React.ReactElement {
|
|||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
|
||||||
|
function handleClick(): void {
|
||||||
|
if (color === "error") return;
|
||||||
|
if (!Settings.SuppressBuyAugmentationConfirmation) {
|
||||||
|
const popupId = "purchase-augmentation-popup";
|
||||||
|
createPopup(popupId, PurchaseAugmentationPopup, {
|
||||||
|
aug: aug,
|
||||||
|
faction: props.faction,
|
||||||
|
player: props.p,
|
||||||
|
rerender: props.rerender,
|
||||||
|
popupId: popupId,
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
purchaseAugmentation(aug, props.faction);
|
||||||
|
props.rerender();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<li key={aug.name}>
|
<TableRow>
|
||||||
<span
|
{!props.owned && (
|
||||||
style={{
|
<TableCell key={0}>
|
||||||
margin: "4px",
|
<Button onClick={handleClick} color={color}>
|
||||||
padding: "4px",
|
Buy
|
||||||
}}
|
</Button>
|
||||||
>
|
</TableCell>
|
||||||
<StdButton
|
)}
|
||||||
disabled={disabled}
|
<TableCell key={1}>
|
||||||
onClick={handleClick}
|
<Box display="flex">
|
||||||
style={{
|
<Tooltip
|
||||||
display: "inline-block",
|
title={<Typography>{tooltip}</Typography>}
|
||||||
}}
|
placement="top"
|
||||||
text={btnTxt}
|
disableFocusListener
|
||||||
tooltip={tooltip}
|
disableTouchListener
|
||||||
|
enterNextDelay={1000}
|
||||||
|
enterDelay={500}
|
||||||
|
leaveDelay={0}
|
||||||
|
leaveTouchDelay={0}
|
||||||
|
>
|
||||||
|
<Typography>{btnTxt}</Typography>
|
||||||
|
</Tooltip>
|
||||||
|
</Box>
|
||||||
|
</TableCell>
|
||||||
|
{!props.owned && (
|
||||||
|
<Requirements
|
||||||
|
key={2}
|
||||||
|
augName={props.augName}
|
||||||
|
p={props.p}
|
||||||
|
cost={moneyCost}
|
||||||
|
rep={repCost}
|
||||||
|
hasReq={hasReq}
|
||||||
|
hasRep={hasRep}
|
||||||
|
hasCost={hasCost}
|
||||||
/>
|
/>
|
||||||
<p style={txtStyle}>{status}</p>
|
)}
|
||||||
</span>
|
</TableRow>
|
||||||
</li>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -218,28 +218,41 @@ export class GangMember {
|
|||||||
return points.hack > 0 || points.str > 0 || points.def > 0 || points.dex > 0 || points.agi > 0 || points.cha > 0;
|
return points.hack > 0 || points.str > 0 || points.def > 0 || points.dex > 0 || points.agi > 0 || points.cha > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
getAscensionResults(): IMults {
|
getCurrentAscensionMults(): IMults {
|
||||||
|
return {
|
||||||
|
hack: this.calculateAscensionMult(this.hack_asc_points),
|
||||||
|
str: this.calculateAscensionMult(this.str_asc_points),
|
||||||
|
def: this.calculateAscensionMult(this.def_asc_points),
|
||||||
|
dex: this.calculateAscensionMult(this.dex_asc_points),
|
||||||
|
agi: this.calculateAscensionMult(this.agi_asc_points),
|
||||||
|
cha: this.calculateAscensionMult(this.cha_asc_points)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
getAscensionMultsAfterAscend(): IMults {
|
||||||
const points = this.getGainedAscensionPoints();
|
const points = this.getGainedAscensionPoints();
|
||||||
return {
|
return {
|
||||||
hack:
|
hack: this.calculateAscensionMult(this.hack_asc_points + points.hack),
|
||||||
this.calculateAscensionMult(this.hack_asc_points + points.hack) /
|
str: this.calculateAscensionMult(this.str_asc_points + points.str),
|
||||||
this.calculateAscensionMult(this.hack_asc_points),
|
def: this.calculateAscensionMult(this.def_asc_points + points.def),
|
||||||
str:
|
dex: this.calculateAscensionMult(this.dex_asc_points + points.dex),
|
||||||
this.calculateAscensionMult(this.str_asc_points + points.str) /
|
agi: this.calculateAscensionMult(this.agi_asc_points + points.agi),
|
||||||
this.calculateAscensionMult(this.str_asc_points),
|
cha: this.calculateAscensionMult(this.cha_asc_points + points.cha),
|
||||||
def:
|
}
|
||||||
this.calculateAscensionMult(this.def_asc_points + points.def) /
|
}
|
||||||
this.calculateAscensionMult(this.def_asc_points),
|
|
||||||
dex:
|
getAscensionResults(): IMults {
|
||||||
this.calculateAscensionMult(this.dex_asc_points + points.dex) /
|
const postAscend = this.getAscensionMultsAfterAscend();
|
||||||
this.calculateAscensionMult(this.dex_asc_points),
|
const preAscend = this.getCurrentAscensionMults();
|
||||||
agi:
|
|
||||||
this.calculateAscensionMult(this.agi_asc_points + points.agi) /
|
return {
|
||||||
this.calculateAscensionMult(this.agi_asc_points),
|
hack: postAscend.hack / preAscend.hack,
|
||||||
cha:
|
str: postAscend.str / preAscend.str,
|
||||||
this.calculateAscensionMult(this.cha_asc_points + points.cha) /
|
def: postAscend.def / preAscend.def,
|
||||||
this.calculateAscensionMult(this.cha_asc_points),
|
dex: postAscend.dex / preAscend.dex,
|
||||||
};
|
agi: postAscend.agi / preAscend.agi,
|
||||||
|
cha: postAscend.cha / preAscend.cha,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ascend(): IAscensionResult {
|
ascend(): IAscensionResult {
|
||||||
|
@ -57,7 +57,9 @@ export function AscensionPopup(props: IProps): React.ReactElement {
|
|||||||
removePopup(props.popupId);
|
removePopup(props.popupId);
|
||||||
}
|
}
|
||||||
|
|
||||||
const ascendBenefits = props.member.getAscensionResults();
|
// const ascendBenefits = props.member.getAscensionResults();
|
||||||
|
const preAscend = props.member.getCurrentAscensionMults();
|
||||||
|
const postAscend = props.member.getAscensionMultsAfterAscend();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
@ -72,17 +74,17 @@ export function AscensionPopup(props: IProps): React.ReactElement {
|
|||||||
<br />
|
<br />
|
||||||
In return, they will gain the following permanent boost to stat multipliers:
|
In return, they will gain the following permanent boost to stat multipliers:
|
||||||
<br />
|
<br />
|
||||||
Hacking: x{numeralWrapper.format(ascendBenefits.hack, "0.000")}
|
Hacking: x{numeralWrapper.format(preAscend.hack, "0.000")} => x{numeralWrapper.format(postAscend.hack, "0.000")}
|
||||||
<br />
|
<br />
|
||||||
Strength: x{numeralWrapper.format(ascendBenefits.str, "0.000")}
|
Strength: x{numeralWrapper.format(preAscend.str, "0.000")} => x{numeralWrapper.format(postAscend.str, "0.000")}
|
||||||
<br />
|
<br />
|
||||||
Defense: x{numeralWrapper.format(ascendBenefits.def, "0.000")}
|
Defense: x{numeralWrapper.format(preAscend.def, "0.000")} => x{numeralWrapper.format(postAscend.def, "0.000")}
|
||||||
<br />
|
<br />
|
||||||
Dexterity: x{numeralWrapper.format(ascendBenefits.dex, "0.000")}
|
Dexterity: x{numeralWrapper.format(preAscend.dex, "0.000")} => x{numeralWrapper.format(postAscend.dex, "0.000")}
|
||||||
<br />
|
<br />
|
||||||
Agility: x{numeralWrapper.format(ascendBenefits.agi, "0.000")}
|
Agility: x{numeralWrapper.format(preAscend.agi, "0.000")} => x{numeralWrapper.format(postAscend.agi, "0.000")}
|
||||||
<br />
|
<br />
|
||||||
Charisma: x{numeralWrapper.format(ascendBenefits.cha, "0.000")}
|
Charisma: x{numeralWrapper.format(preAscend.cha, "0.000")} => x{numeralWrapper.format(postAscend.cha, "0.000")}
|
||||||
<br />
|
<br />
|
||||||
</pre>
|
</pre>
|
||||||
<button className="std-button" onClick={confirm}>
|
<button className="std-button" onClick={confirm}>
|
||||||
|
@ -41,6 +41,7 @@ export function SpecialLocation(props: IProps): React.ReactElement {
|
|||||||
createPopup(popupId, CreateCorporationPopup, {
|
createPopup(popupId, CreateCorporationPopup, {
|
||||||
player: player,
|
player: player,
|
||||||
popupId: popupId,
|
popupId: popupId,
|
||||||
|
router: router,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2,7 +2,7 @@ import { makeRuntimeRejectMsg } from "./NetscriptEvaluator";
|
|||||||
import { ScriptUrl } from "./Script/ScriptUrl";
|
import { ScriptUrl } from "./Script/ScriptUrl";
|
||||||
|
|
||||||
// Makes a blob that contains the code of a given script.
|
// Makes a blob that contains the code of a given script.
|
||||||
export function makeScriptBlob(code) {
|
function makeScriptBlob(code) {
|
||||||
return new Blob([code], { type: "text/javascript" });
|
return new Blob([code], { type: "text/javascript" });
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -93,7 +93,7 @@ function shouldCompile(script, scripts) {
|
|||||||
* the script parameter.
|
* the script parameter.
|
||||||
*/
|
*/
|
||||||
// BUG: apparently seen is never consulted. Oops.
|
// BUG: apparently seen is never consulted. Oops.
|
||||||
export function _getScriptUrls(script, scripts, seen) {
|
function _getScriptUrls(script, scripts, seen) {
|
||||||
// Inspired by: https://stackoverflow.com/a/43834063/91401
|
// Inspired by: https://stackoverflow.com/a/43834063/91401
|
||||||
/** @type {ScriptUrl[]} */
|
/** @type {ScriptUrl[]} */
|
||||||
const urlStack = [];
|
const urlStack = [];
|
||||||
|
@ -70,16 +70,20 @@ export function CovenantPurchasesRoot(props: IProps): React.ReactElement {
|
|||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<PopupCloseButton popup={PopupId} text={"Close"} />
|
<PopupCloseButton popup={PopupId} text={"Close"} />
|
||||||
<p>
|
{props.p.sleevesFromCovenant < MaxSleevesFromCovenant && (
|
||||||
Would you like to purchase an additional Duplicate Sleeve from The Covenant for{" "}
|
<>
|
||||||
<Money money={purchaseCost()} player={props.p} />?
|
<p>
|
||||||
</p>
|
Would you like to purchase an additional Duplicate Sleeve from The Covenant for{" "}
|
||||||
<br />
|
<Money money={purchaseCost()} player={props.p} />?
|
||||||
<p>
|
</p>
|
||||||
These Duplicate Sleeves are permanent (they persist through BitNodes). You can purchase a total of{" "}
|
<br />
|
||||||
{MaxSleevesFromCovenant} from The Covenant.
|
<p>
|
||||||
</p>
|
These Duplicate Sleeves are permanent (they persist through BitNodes). You can purchase a total of{" "}
|
||||||
<StdButton disabled={purchaseDisabled} onClick={purchaseOnClick} text={"Purchase"} />
|
{MaxSleevesFromCovenant} from The Covenant.
|
||||||
|
</p>
|
||||||
|
<StdButton disabled={purchaseDisabled} onClick={purchaseOnClick} text={"Purchase"} />
|
||||||
|
</>
|
||||||
|
)}
|
||||||
<br />
|
<br />
|
||||||
<br />
|
<br />
|
||||||
<p>
|
<p>
|
||||||
|
@ -6,6 +6,7 @@ import { removePopup } from "../../../ui/React/createPopup";
|
|||||||
import { Money } from "../../../ui/React/Money";
|
import { Money } from "../../../ui/React/Money";
|
||||||
import { WorldMap } from "../../../ui/React/WorldMap";
|
import { WorldMap } from "../../../ui/React/WorldMap";
|
||||||
import { CityName } from "../../../Locations/data/CityNames";
|
import { CityName } from "../../../Locations/data/CityNames";
|
||||||
|
import { Settings } from "../../../Settings/Settings";
|
||||||
import { dialogBoxCreate } from "../../../../utils/DialogBox";
|
import { dialogBoxCreate } from "../../../../utils/DialogBox";
|
||||||
|
|
||||||
interface IProps {
|
interface IProps {
|
||||||
@ -34,7 +35,15 @@ export function TravelPopup(props: IProps): React.ReactElement {
|
|||||||
study. Traveling to a different city costs <Money money={CONSTANTS.TravelCost} player={props.player} />. It will
|
study. Traveling to a different city costs <Money money={CONSTANTS.TravelCost} player={props.player} />. It will
|
||||||
also set your current sleeve task to idle.
|
also set your current sleeve task to idle.
|
||||||
</p>
|
</p>
|
||||||
<WorldMap currentCity={props.sleeve.city} onTravel={(city: CityName) => travel(city)} />
|
{Settings.DisableASCIIArt ? (
|
||||||
|
Object.values(CityName).map((city: CityName) => (
|
||||||
|
<button key={city} className="std-button" onClick={() => travel(city)}>
|
||||||
|
{city}
|
||||||
|
</button>
|
||||||
|
))
|
||||||
|
) : (
|
||||||
|
<WorldMap currentCity={props.sleeve.city} onTravel={(city: CityName) => travel(city)} />
|
||||||
|
)}
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -10,10 +10,6 @@ import { SourceFiles } from "./SourceFile/SourceFiles";
|
|||||||
import { dialogBoxCreate } from "../utils/DialogBox";
|
import { dialogBoxCreate } from "../utils/DialogBox";
|
||||||
|
|
||||||
let redPillFlag = false;
|
let redPillFlag = false;
|
||||||
function hackWorldDaemon(router, flume = false, quick = false) {
|
|
||||||
router.toBitVerse(flume, quick);
|
|
||||||
redPillFlag = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
function giveSourceFile(bitNodeNumber) {
|
function giveSourceFile(bitNodeNumber) {
|
||||||
var sourceFileKey = "SourceFile" + bitNodeNumber.toString();
|
var sourceFileKey = "SourceFile" + bitNodeNumber.toString();
|
||||||
@ -86,4 +82,4 @@ export function enterBitNode(router, flume, destroyedBitNode, newBitNode) {
|
|||||||
prestigeSourceFile(flume);
|
prestigeSourceFile(flume);
|
||||||
}
|
}
|
||||||
|
|
||||||
export { redPillFlag, hackWorldDaemon };
|
export { redPillFlag };
|
||||||
|
8
src/SaveObject.d.ts
vendored
8
src/SaveObject.d.ts
vendored
@ -1,2 +1,6 @@
|
|||||||
export declare const saveObject: any;
|
export declare const saveObject: {
|
||||||
export declare function openImportFileHandler(evt: any): void;
|
getSaveString: () => string;
|
||||||
|
saveGame: () => void;
|
||||||
|
exportGame: () => void;
|
||||||
|
};
|
||||||
|
export declare function loadGame(s: string): boolean;
|
||||||
|
@ -22,6 +22,7 @@ import * as ExportBonus from "./ExportBonus";
|
|||||||
import { dialogBoxCreate } from "../utils/DialogBox";
|
import { dialogBoxCreate } from "../utils/DialogBox";
|
||||||
import { clearEventListeners } from "../utils/uiHelpers/clearEventListeners";
|
import { clearEventListeners } from "../utils/uiHelpers/clearEventListeners";
|
||||||
import { Reviver, Generic_toJSON, Generic_fromJSON } from "../utils/JSONReviver";
|
import { Reviver, Generic_toJSON, Generic_fromJSON } from "../utils/JSONReviver";
|
||||||
|
import { save } from "./db";
|
||||||
|
|
||||||
import Decimal from "decimal.js";
|
import Decimal from "decimal.js";
|
||||||
|
|
||||||
@ -84,33 +85,12 @@ BitburnerSaveObject.prototype.getSaveString = function () {
|
|||||||
return saveString;
|
return saveString;
|
||||||
};
|
};
|
||||||
|
|
||||||
BitburnerSaveObject.prototype.saveGame = function (db) {
|
BitburnerSaveObject.prototype.saveGame = function () {
|
||||||
var saveString = this.getSaveString();
|
const saveString = this.getSaveString();
|
||||||
|
|
||||||
// We'll save to both localstorage and indexedDb
|
save(saveString)
|
||||||
var objectStore = db.transaction(["savestring"], "readwrite").objectStore("savestring");
|
.then(() => createStatusText("Game saved!"))
|
||||||
var request = objectStore.put(saveString, "save");
|
.catch((err) => console.error(err));
|
||||||
|
|
||||||
request.onerror = function (e) {
|
|
||||||
console.error("Error saving game to IndexedDB: " + e);
|
|
||||||
};
|
|
||||||
|
|
||||||
try {
|
|
||||||
window.localStorage.setItem("bitburnerSave", saveString);
|
|
||||||
} catch (e) {
|
|
||||||
if (e.code == 22) {
|
|
||||||
createStatusText("Save failed for localStorage! Check console(F12)");
|
|
||||||
console.error(
|
|
||||||
"Failed to save game to localStorage because the size of the save file " +
|
|
||||||
"is too large. However, the game will still be saved to IndexedDb if your browser " +
|
|
||||||
"supports it. If you would like to save to localStorage as well, then " +
|
|
||||||
"consider killing several of your scripts to " +
|
|
||||||
"fix this, or increasing the size of your browsers localStorage",
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
createStatusText("Game saved!");
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// Makes necessary changes to the loaded/imported data to ensure
|
// Makes necessary changes to the loaded/imported data to ensure
|
||||||
@ -155,16 +135,10 @@ function evaluateVersionCompatibility(ver) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function loadGame(saveString) {
|
function loadGame(saveString) {
|
||||||
if (saveString === "" || saveString == null || saveString === undefined) {
|
if (!saveString) return false;
|
||||||
if (!window.localStorage.getItem("bitburnerSave")) {
|
saveString = decodeURIComponent(escape(atob(saveString)));
|
||||||
return false;
|
|
||||||
}
|
|
||||||
saveString = decodeURIComponent(escape(atob(window.localStorage.getItem("bitburnerSave"))));
|
|
||||||
} else {
|
|
||||||
saveString = decodeURIComponent(escape(atob(saveString)));
|
|
||||||
}
|
|
||||||
|
|
||||||
var saveObj = JSON.parse(saveString, Reviver);
|
const saveObj = JSON.parse(saveString, Reviver);
|
||||||
|
|
||||||
loadPlayer(saveObj.PlayerSave);
|
loadPlayer(saveObj.PlayerSave);
|
||||||
loadAllServers(saveObj.AllServersSave);
|
loadAllServers(saveObj.AllServersSave);
|
||||||
@ -224,19 +198,12 @@ function loadGame(saveString) {
|
|||||||
} else {
|
} else {
|
||||||
Settings.init();
|
Settings.init();
|
||||||
}
|
}
|
||||||
if (saveObj.hasOwnProperty("FconfSettingsSave")) {
|
|
||||||
try {
|
|
||||||
loadFconf(saveObj.FconfSettingsSave);
|
|
||||||
} catch (e) {
|
|
||||||
console.error("ERROR: Failed to parse .fconf Settings.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (saveObj.hasOwnProperty("LastExportBonus")) {
|
if (saveObj.hasOwnProperty("LastExportBonus")) {
|
||||||
try {
|
try {
|
||||||
ExportBonus.setLastExportBonus(JSON.parse(saveObj.LastExportBonus));
|
ExportBonus.setLastExportBonus(JSON.parse(saveObj.LastExportBonus));
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
ExportBonus.setLastExportBonus(new Date().getTime());
|
ExportBonus.setLastExportBonus(new Date().getTime());
|
||||||
console.error("ERROR: Failed to parse .fconf Settings " + err);
|
console.error("ERROR: Failed to parse last export bonus Settings " + err);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (saveObj.hasOwnProperty("VersionSave")) {
|
if (saveObj.hasOwnProperty("VersionSave")) {
|
||||||
@ -267,173 +234,6 @@ function loadGame(saveString) {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
function loadImportedGame(saveObj, saveString) {
|
|
||||||
var tempSaveObj = null;
|
|
||||||
var tempPlayer = null;
|
|
||||||
|
|
||||||
// Check to see if the imported save file can be parsed. If any
|
|
||||||
// errors are caught it will fail
|
|
||||||
try {
|
|
||||||
var decodedSaveString = decodeURIComponent(escape(atob(saveString)));
|
|
||||||
tempSaveObj = JSON.parse(decodedSaveString, Reviver);
|
|
||||||
|
|
||||||
tempPlayer = JSON.parse(tempSaveObj.PlayerSave, Reviver);
|
|
||||||
|
|
||||||
// Parse Decimal.js objects
|
|
||||||
tempPlayer.money = new Decimal(tempPlayer.money);
|
|
||||||
|
|
||||||
JSON.parse(tempSaveObj.AllServersSave, Reviver);
|
|
||||||
JSON.parse(tempSaveObj.CompaniesSave, Reviver);
|
|
||||||
JSON.parse(tempSaveObj.FactionsSave, Reviver);
|
|
||||||
JSON.parse(tempSaveObj.SpecialServerIpsSave, Reviver);
|
|
||||||
if (tempSaveObj.hasOwnProperty("AliasesSave")) {
|
|
||||||
try {
|
|
||||||
JSON.parse(tempSaveObj.AliasesSave, Reviver);
|
|
||||||
} catch (e) {
|
|
||||||
console.error(`Parsing Aliases save failed: ${e}`);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (tempSaveObj.hasOwnProperty("GlobalAliases")) {
|
|
||||||
try {
|
|
||||||
JSON.parse(tempSaveObj.AliasesSave, Reviver);
|
|
||||||
} catch (e) {
|
|
||||||
console.error(`Parsing Global Aliases save failed: ${e}`);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (tempSaveObj.hasOwnProperty("MessagesSave")) {
|
|
||||||
try {
|
|
||||||
JSON.parse(tempSaveObj.MessagesSave, Reviver);
|
|
||||||
} catch (e) {
|
|
||||||
console.error(`Parsing Messages save failed: ${e}`);
|
|
||||||
initMessages();
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
initMessages();
|
|
||||||
}
|
|
||||||
if (saveObj.hasOwnProperty("StockMarketSave")) {
|
|
||||||
try {
|
|
||||||
JSON.parse(tempSaveObj.StockMarketSave, Reviver);
|
|
||||||
} catch (e) {
|
|
||||||
console.error(`Parsing StockMarket save failed: ${e}`);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (saveObj.hasOwnProperty("LastExportBonus")) {
|
|
||||||
try {
|
|
||||||
ExportBonus.setLastExportBonus(JSON.parse(saveObj.LastExportBonus));
|
|
||||||
} catch (err) {
|
|
||||||
ExportBonus.setLastExportBonus(new Date().getTime());
|
|
||||||
console.error("ERROR: Failed to parse .fconf Settings " + err);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (tempSaveObj.hasOwnProperty("VersionSave")) {
|
|
||||||
try {
|
|
||||||
var ver = JSON.parse(tempSaveObj.VersionSave, Reviver);
|
|
||||||
evaluateVersionCompatibility(ver);
|
|
||||||
} catch (e) {
|
|
||||||
console.error("Parsing Version save failed: " + e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (tempPlayer.inGang() && tempSaveObj.hasOwnProperty("AllGangsSave")) {
|
|
||||||
try {
|
|
||||||
loadAllGangs(tempSaveObj.AllGangsSave);
|
|
||||||
} catch (e) {
|
|
||||||
console.error(`Failed to parse AllGangsSave: {e}`);
|
|
||||||
throw e;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (e) {
|
|
||||||
dialogBoxCreate("Error importing game: " + e.toString());
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Since the save file is valid, load everything for real
|
|
||||||
saveString = decodeURIComponent(escape(atob(saveString)));
|
|
||||||
saveObj = JSON.parse(saveString, Reviver);
|
|
||||||
|
|
||||||
loadPlayer(saveObj.PlayerSave);
|
|
||||||
loadAllServers(saveObj.AllServersSave);
|
|
||||||
loadCompanies(saveObj.CompaniesSave);
|
|
||||||
loadFactions(saveObj.FactionsSave);
|
|
||||||
loadSpecialServerIps(saveObj.SpecialServerIpsSave);
|
|
||||||
|
|
||||||
if (saveObj.hasOwnProperty("AliasesSave")) {
|
|
||||||
try {
|
|
||||||
loadAliases(saveObj.AliasesSave);
|
|
||||||
} catch (e) {
|
|
||||||
loadAliases("");
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
loadAliases("");
|
|
||||||
}
|
|
||||||
if (saveObj.hasOwnProperty("GlobalAliasesSave")) {
|
|
||||||
try {
|
|
||||||
loadGlobalAliases(saveObj.GlobalAliasesSave);
|
|
||||||
} catch (e) {
|
|
||||||
loadGlobalAliases("");
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
loadGlobalAliases("");
|
|
||||||
}
|
|
||||||
if (saveObj.hasOwnProperty("MessagesSave")) {
|
|
||||||
try {
|
|
||||||
loadMessages(saveObj.MessagesSave);
|
|
||||||
} catch (e) {
|
|
||||||
initMessages();
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
initMessages();
|
|
||||||
}
|
|
||||||
if (saveObj.hasOwnProperty("StockMarketSave")) {
|
|
||||||
try {
|
|
||||||
loadStockMarket(saveObj.StockMarketSave);
|
|
||||||
} catch (e) {
|
|
||||||
loadStockMarket("");
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
loadStockMarket("");
|
|
||||||
}
|
|
||||||
if (saveObj.hasOwnProperty("SettingsSave")) {
|
|
||||||
try {
|
|
||||||
Settings.load(saveObj.SettingsSave);
|
|
||||||
} catch (e) {
|
|
||||||
Settings.init();
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
Settings.init();
|
|
||||||
}
|
|
||||||
if (saveObj.hasOwnProperty("FconfSettingsSave")) {
|
|
||||||
try {
|
|
||||||
loadFconf(saveObj.FconfSettingsSave);
|
|
||||||
} catch (e) {
|
|
||||||
console.error("ERROR: Failed to load .fconf settings when importing");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (saveObj.hasOwnProperty("VersionSave")) {
|
|
||||||
try {
|
|
||||||
var ver = JSON.parse(saveObj.VersionSave, Reviver);
|
|
||||||
evaluateVersionCompatibility(ver);
|
|
||||||
|
|
||||||
if (ver != CONSTANTS.Version) {
|
|
||||||
createNewUpdateText();
|
|
||||||
}
|
|
||||||
} catch (e) {
|
|
||||||
createNewUpdateText();
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
createNewUpdateText();
|
|
||||||
}
|
|
||||||
if (Player.inGang() && saveObj.hasOwnProperty("AllGangsSave")) {
|
|
||||||
try {
|
|
||||||
loadAllGangs(saveObj.AllGangsSave);
|
|
||||||
} catch (e) {
|
|
||||||
console.error("ERROR: Failed to parse AllGangsSave: " + e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
saveObject.saveGame(Engine.indexedDb);
|
|
||||||
location.reload();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
BitburnerSaveObject.prototype.exportGame = function () {
|
BitburnerSaveObject.prototype.exportGame = function () {
|
||||||
const saveString = this.getSaveString();
|
const saveString = this.getSaveString();
|
||||||
|
|
||||||
@ -460,31 +260,6 @@ BitburnerSaveObject.prototype.exportGame = function () {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
BitburnerSaveObject.prototype.importGame = function () {
|
|
||||||
if (window.File && window.FileReader && window.FileList && window.Blob) {
|
|
||||||
var fileSelector = clearEventListeners("import-game-file-selector");
|
|
||||||
fileSelector.addEventListener("change", openImportFileHandler, false);
|
|
||||||
$("#import-game-file-selector").click();
|
|
||||||
} else {
|
|
||||||
dialogBoxCreate("ERR: Your browser does not support HTML5 File API. Cannot import.");
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
BitburnerSaveObject.prototype.deleteGame = function (db) {
|
|
||||||
// Delete from local storage
|
|
||||||
if (window.localStorage.getItem("bitburnerSave")) {
|
|
||||||
window.localStorage.removeItem("bitburnerSave");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Delete from indexedDB
|
|
||||||
var request = db.transaction(["savestring"], "readwrite").objectStore("savestring").delete("save");
|
|
||||||
request.onsuccess = function () {};
|
|
||||||
request.onerror = function (e) {
|
|
||||||
console.error(`Failed to delete save from indexedDb: ${e}`);
|
|
||||||
};
|
|
||||||
createStatusText("Game deleted!");
|
|
||||||
};
|
|
||||||
|
|
||||||
function createNewUpdateText() {
|
function createNewUpdateText() {
|
||||||
dialogBoxCreate(
|
dialogBoxCreate(
|
||||||
"New update!<br>" +
|
"New update!<br>" +
|
||||||
@ -514,19 +289,4 @@ BitburnerSaveObject.fromJSON = function (value) {
|
|||||||
|
|
||||||
Reviver.constructors.BitburnerSaveObject = BitburnerSaveObject;
|
Reviver.constructors.BitburnerSaveObject = BitburnerSaveObject;
|
||||||
|
|
||||||
function openImportFileHandler(evt) {
|
export { saveObject, loadGame };
|
||||||
var file = evt.target.files[0];
|
|
||||||
if (!file) {
|
|
||||||
dialogBoxCreate("Invalid file selected");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
var reader = new FileReader();
|
|
||||||
reader.onload = function (e) {
|
|
||||||
var contents = e.target.result;
|
|
||||||
loadImportedGame(saveObject, contents);
|
|
||||||
};
|
|
||||||
reader.readAsText(file);
|
|
||||||
}
|
|
||||||
|
|
||||||
export { saveObject, loadGame, openImportFileHandler };
|
|
||||||
|
@ -3,7 +3,7 @@ export type Position = {
|
|||||||
column: number;
|
column: number;
|
||||||
};
|
};
|
||||||
|
|
||||||
export class PositionTracker {
|
class PositionTracker {
|
||||||
positions: Map<string, Position>;
|
positions: Map<string, Position>;
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
|
@ -5,6 +5,14 @@ import { OwnedAugmentationsOrderSetting, PurchaseAugmentationsOrderSetting } fro
|
|||||||
* Represents the default settings the player could customize.
|
* Represents the default settings the player could customize.
|
||||||
*/
|
*/
|
||||||
interface IDefaultSettings {
|
interface IDefaultSettings {
|
||||||
|
/**
|
||||||
|
* How many servers per page
|
||||||
|
*/
|
||||||
|
ActiveScriptsServerPageSize: number;
|
||||||
|
/**
|
||||||
|
* How many scripts per page
|
||||||
|
*/
|
||||||
|
ActiveScriptsScriptPageSize: number;
|
||||||
/**
|
/**
|
||||||
* How often the game should autosave the player's progress, in seconds.
|
* How often the game should autosave the player's progress, in seconds.
|
||||||
*/
|
*/
|
||||||
@ -101,6 +109,8 @@ interface ISettings extends IDefaultSettings {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const defaultSettings: IDefaultSettings = {
|
const defaultSettings: IDefaultSettings = {
|
||||||
|
ActiveScriptsServerPageSize: 10,
|
||||||
|
ActiveScriptsScriptPageSize: 10,
|
||||||
AutosaveInterval: 60,
|
AutosaveInterval: 60,
|
||||||
CodeInstructionRunTime: 50,
|
CodeInstructionRunTime: 50,
|
||||||
DisableASCIIArt: false,
|
DisableASCIIArt: false,
|
||||||
@ -123,6 +133,8 @@ const defaultSettings: IDefaultSettings = {
|
|||||||
*/
|
*/
|
||||||
// tslint:disable-next-line:variable-name
|
// tslint:disable-next-line:variable-name
|
||||||
export const Settings: ISettings & ISelfInitializer & ISelfLoading = {
|
export const Settings: ISettings & ISelfInitializer & ISelfLoading = {
|
||||||
|
ActiveScriptsServerPageSize: defaultSettings.ActiveScriptsServerPageSize,
|
||||||
|
ActiveScriptsScriptPageSize: defaultSettings.ActiveScriptsScriptPageSize,
|
||||||
AutosaveInterval: defaultSettings.AutosaveInterval,
|
AutosaveInterval: defaultSettings.AutosaveInterval,
|
||||||
CodeInstructionRunTime: 25,
|
CodeInstructionRunTime: 25,
|
||||||
DisableASCIIArt: defaultSettings.DisableASCIIArt,
|
DisableASCIIArt: defaultSettings.DisableASCIIArt,
|
||||||
|
@ -51,7 +51,6 @@ import { Settings } from "../../Settings/Settings";
|
|||||||
import { redPillFlag } from "../../RedPill";
|
import { redPillFlag } from "../../RedPill";
|
||||||
|
|
||||||
import { inMission } from "../../Missions";
|
import { inMission } from "../../Missions";
|
||||||
import { cinematicTextFlag } from "../../CinematicText";
|
|
||||||
import { KEY } from "../../../utils/helpers/keyCodes";
|
import { KEY } from "../../../utils/helpers/keyCodes";
|
||||||
import { FconfSettings } from "../../Fconf/FconfSettings";
|
import { FconfSettings } from "../../Fconf/FconfSettings";
|
||||||
|
|
||||||
@ -268,7 +267,7 @@ export function SidebarRoot(props: IProps): React.ReactElement {
|
|||||||
// Alt-o - Options
|
// Alt-o - Options
|
||||||
function handleShortcuts(this: Document, event: KeyboardEvent): any {
|
function handleShortcuts(this: Document, event: KeyboardEvent): any {
|
||||||
if (Settings.DisableHotkeys) return;
|
if (Settings.DisableHotkeys) return;
|
||||||
if (props.player.isWorking || redPillFlag || inMission || cinematicTextFlag) return;
|
if (props.player.isWorking || redPillFlag || inMission) return;
|
||||||
if (event.keyCode == KEY.T && event.altKey) {
|
if (event.keyCode == KEY.T && event.altKey) {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
clickTerminal();
|
clickTerminal();
|
||||||
|
@ -4,43 +4,42 @@ import { IMap } from "../types";
|
|||||||
export const TerminalHelpText: string[] = [
|
export const TerminalHelpText: string[] = [
|
||||||
"Type 'help name' to learn more about the command ",
|
"Type 'help name' to learn more about the command ",
|
||||||
"",
|
"",
|
||||||
'alias [-g] [name="value"] Create or display Terminal aliases',
|
'alias [-g] [name="value"] Create or display Terminal aliases',
|
||||||
"analyze Get information about the current machine ",
|
"analyze Get information about the current machine ",
|
||||||
"backdoor Install a backdoor on the current machine ",
|
"backdoor Install a backdoor on the current machine ",
|
||||||
"buy [-l/program] Purchase a program through the Dark Web",
|
"buy [-l/program] Purchase a program through the Dark Web",
|
||||||
"cat [file] Display a .msg, .lit, or .txt file",
|
"cat [file] Display a .msg, .lit, or .txt file",
|
||||||
"cd [dir] Change to a new directory",
|
"cd [dir] Change to a new directory",
|
||||||
"check [script] [args...] Print a script's logs to Terminal",
|
"check [script] [args...] Print a script's logs to Terminal",
|
||||||
"clear Clear all text on the terminal ",
|
"clear Clear all text on the terminal ",
|
||||||
"cls See 'clear' command ",
|
"cls See 'clear' command ",
|
||||||
"connect [ip/hostname] Connects to a remote server",
|
"connect [ip/hostname] Connects to a remote server",
|
||||||
"download [script/text file] Downloads scripts or text files to your computer",
|
"download [script/text file] Downloads scripts or text files to your computer",
|
||||||
"expr [math expression] Evaluate a mathematical expression",
|
"expr [math expression] Evaluate a mathematical expression",
|
||||||
"free Check the machine's memory (RAM) usage",
|
"free Check the machine's memory (RAM) usage",
|
||||||
"hack Hack the current machine",
|
"hack Hack the current machine",
|
||||||
"help [command] Display this help text, or the help text for a command",
|
"help [command] Display this help text, or the help text for a command",
|
||||||
"home Connect to home computer",
|
"home Connect to home computer",
|
||||||
"hostname Displays the hostname of the machine",
|
"hostname Displays the hostname of the machine",
|
||||||
"ifconfig Displays the IP address of the machine",
|
"ifconfig Displays the IP address of the machine",
|
||||||
"kill [script/pid] [args...] Stops the specified script on the current server ",
|
"kill [script/pid] [args...] Stops the specified script on the current server ",
|
||||||
"killall Stops all running scripts on the current machine",
|
"killall Stops all running scripts on the current machine",
|
||||||
"ls [dir] [| grep pattern] Displays all files on the machine",
|
"ls [dir] [| grep pattern] Displays all files on the machine",
|
||||||
"lscpu Displays the number of CPU cores on the machine",
|
"lscpu Displays the number of CPU cores on the machine",
|
||||||
"mem [script] [-t] [n] Displays the amount of RAM required to run the script",
|
"mem [script] [-t] [n] Displays the amount of RAM required to run the script",
|
||||||
"mv [src] [dest] Move/rename a text or script file",
|
"mv [src] [dest] Move/rename a text or script file",
|
||||||
"nano [file] Text editor - Open up and edit a script or text file",
|
"nano [file] Text editor - Open up and edit a script or text file",
|
||||||
"ps Display all scripts that are currently running",
|
"ps Display all scripts that are currently running",
|
||||||
"rm [file] Delete a file from the server",
|
"rm [file] Delete a file from the server",
|
||||||
"run [name] [-t] [n] [args...] Execute a program or script",
|
"run [name] [-t n] [--tail] [args...] Execute a program or script",
|
||||||
"scan Prints all immediately-available network connections",
|
"scan Prints all immediately-available network connections",
|
||||||
"scan-analyze [d] [-a] Prints info for all servers up to <i>d</i> nodes away",
|
"scan-analyze [d] [-a] Prints info for all servers up to <i>d</i> nodes away",
|
||||||
"scp [file] [server] Copies a file to a destination server",
|
"scp [file] [server] Copies a file to a destination server",
|
||||||
"sudov Shows whether you have root access on this computer",
|
"sudov Shows whether you have root access on this computer",
|
||||||
"tail [script] [args...] Displays dynamic logs for the specified script",
|
"tail [script] [args...] Displays dynamic logs for the specified script",
|
||||||
"theme [preset] | bg txt hlgt Change the color scheme of the UI",
|
"top Displays all running scripts and their RAM usage",
|
||||||
"top Displays all running scripts and their RAM usage",
|
"unalias [alias name] Deletes the specified alias",
|
||||||
"unalias [alias name] Deletes the specified alias",
|
"wget [url] [target file] Retrieves code/text from a web server",
|
||||||
"wget [url] [target file] Retrieves code/text from a web server",
|
|
||||||
];
|
];
|
||||||
|
|
||||||
export const HelpTexts: IMap<string[]> = {
|
export const HelpTexts: IMap<string[]> = {
|
||||||
@ -268,7 +267,7 @@ export const HelpTexts: IMap<string[]> = {
|
|||||||
lscpu: ["lscpu", " ", "Prints the number of CPU Cores the current server has"],
|
lscpu: ["lscpu", " ", "Prints the number of CPU Cores the current server has"],
|
||||||
|
|
||||||
mem: [
|
mem: [
|
||||||
"mem [script name] [-t] [num threads]",
|
"mem [script name] [-t num_threads]",
|
||||||
" ",
|
" ",
|
||||||
"Displays the amount of RAM needed to run the specified script with a single thread. The command can also be used to print ",
|
"Displays the amount of RAM needed to run the specified script with a single thread. The command can also be used to print ",
|
||||||
"the amount of RAM needed to run a script with multiple threads using the '-t' flag. If the '-t' flag is specified, then ",
|
"the amount of RAM needed to run a script with multiple threads using the '-t' flag. If the '-t' flag is specified, then ",
|
||||||
@ -374,24 +373,6 @@ export const HelpTexts: IMap<string[]> = {
|
|||||||
" ",
|
" ",
|
||||||
"tail foo.script 10 50000",
|
"tail foo.script 10 50000",
|
||||||
],
|
],
|
||||||
theme: [
|
|
||||||
"theme [preset] | [#background #text #highlight]",
|
|
||||||
" ",
|
|
||||||
"Change the color of the game's user interface",
|
|
||||||
" ",
|
|
||||||
"This command can be called with a preset theme. Currently, the supported presets are 'default', 'muted', and 'solarized'. ",
|
|
||||||
"However, you can also specify your own color scheme using hex values. To do so, you must specify three hex color values ",
|
|
||||||
"for the background color, the text color, and the highlight color. These hex values must be preceded by a pound sign (#) and ",
|
|
||||||
"must be either 3 or 6 digits. Example:",
|
|
||||||
" ",
|
|
||||||
"theme #ffffff #385 #235012",
|
|
||||||
" ",
|
|
||||||
"A color picker such as ",
|
|
||||||
"<a href='https://www.google.com/search?q=color+picker&oq=color+picker&aqs=chrome.0.0l6.951j0j1&sourceid=chrome&ie=UTF-8' target='_blank'>Google's</a> ",
|
|
||||||
"can be used to get your desired hex color values",
|
|
||||||
" ",
|
|
||||||
"Themes are not saved, so when the game is closed and then re-opened or reloaded then it will revert back to the default theme.",
|
|
||||||
],
|
|
||||||
top: [
|
top: [
|
||||||
"top",
|
"top",
|
||||||
" ",
|
" ",
|
||||||
|
@ -61,7 +61,6 @@ import { scananalyze } from "./commands/scananalyze";
|
|||||||
import { scp } from "./commands/scp";
|
import { scp } from "./commands/scp";
|
||||||
import { sudov } from "./commands/sudov";
|
import { sudov } from "./commands/sudov";
|
||||||
import { tail } from "./commands/tail";
|
import { tail } from "./commands/tail";
|
||||||
import { theme } from "./commands/theme";
|
|
||||||
import { top } from "./commands/top";
|
import { top } from "./commands/top";
|
||||||
import { unalias } from "./commands/unalias";
|
import { unalias } from "./commands/unalias";
|
||||||
import { wget } from "./commands/wget";
|
import { wget } from "./commands/wget";
|
||||||
@ -345,14 +344,10 @@ export class Terminal implements ITerminal {
|
|||||||
case CodingContractResult.Failure:
|
case CodingContractResult.Failure:
|
||||||
++contract.tries;
|
++contract.tries;
|
||||||
if (contract.tries >= contract.getMaxNumTries()) {
|
if (contract.tries >= contract.getMaxNumTries()) {
|
||||||
this.print("Contract <p style='color:red;display:inline'>FAILED</p> - Contract is now self-destructing");
|
this.print("Contract FAILED - Contract is now self-destructing");
|
||||||
serv.removeContract(contract);
|
serv.removeContract(contract);
|
||||||
} else {
|
} else {
|
||||||
this.print(
|
this.print(`Contract FAILED - ${contract.getMaxNumTries() - contract.tries} tries remaining`);
|
||||||
`Contract <p style='color:red;display:inline'>FAILED</p> - ${
|
|
||||||
contract.getMaxNumTries() - contract.tries
|
|
||||||
} tries remaining`,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case CodingContractResult.Cancelled:
|
case CodingContractResult.Cancelled:
|
||||||
@ -683,7 +678,6 @@ export class Terminal implements ITerminal {
|
|||||||
scp: scp,
|
scp: scp,
|
||||||
sudov: sudov,
|
sudov: sudov,
|
||||||
tail: tail,
|
tail: tail,
|
||||||
theme: theme,
|
|
||||||
top: top,
|
top: top,
|
||||||
unalias: unalias,
|
unalias: unalias,
|
||||||
wget: wget,
|
wget: wget,
|
||||||
|
@ -1,60 +0,0 @@
|
|||||||
import { ITerminal } from "../ITerminal";
|
|
||||||
import { IRouter } from "../../ui/Router";
|
|
||||||
import { IPlayer } from "../../PersonObjects/IPlayer";
|
|
||||||
import { BaseServer } from "../../Server/BaseServer";
|
|
||||||
import { FconfSettings } from "../../Fconf/FconfSettings";
|
|
||||||
|
|
||||||
export function theme(
|
|
||||||
terminal: ITerminal,
|
|
||||||
router: IRouter,
|
|
||||||
player: IPlayer,
|
|
||||||
server: BaseServer,
|
|
||||||
args: (string | number)[],
|
|
||||||
): void {
|
|
||||||
if (args.length !== 1 && args.length !== 3) {
|
|
||||||
terminal.error("Incorrect number of arguments.");
|
|
||||||
terminal.error(
|
|
||||||
"Usage: theme [default|muted|solarized] | #[background color hex] #[text color hex] #[highlight color hex]",
|
|
||||||
);
|
|
||||||
} else if (args.length === 1) {
|
|
||||||
const themeName = args[0];
|
|
||||||
if (themeName == "default") {
|
|
||||||
document.body.style.setProperty("--my-highlight-color", "#ffffff");
|
|
||||||
document.body.style.setProperty("--my-font-color", "#66ff33");
|
|
||||||
document.body.style.setProperty("--my-background-color", "#000000");
|
|
||||||
document.body.style.setProperty("--my-prompt-color", "#f92672");
|
|
||||||
} else if (themeName == "muted") {
|
|
||||||
document.body.style.setProperty("--my-highlight-color", "#ffffff");
|
|
||||||
document.body.style.setProperty("--my-font-color", "#66ff33");
|
|
||||||
document.body.style.setProperty("--my-background-color", "#252527");
|
|
||||||
} else if (themeName == "solarized") {
|
|
||||||
document.body.style.setProperty("--my-highlight-color", "#6c71c4");
|
|
||||||
document.body.style.setProperty("--my-font-color", "#839496");
|
|
||||||
document.body.style.setProperty("--my-background-color", "#002b36");
|
|
||||||
} else {
|
|
||||||
return terminal.error("Theme not found");
|
|
||||||
}
|
|
||||||
FconfSettings.THEME_HIGHLIGHT_COLOR = document.body.style.getPropertyValue("--my-highlight-color");
|
|
||||||
FconfSettings.THEME_FONT_COLOR = document.body.style.getPropertyValue("--my-font-color");
|
|
||||||
FconfSettings.THEME_BACKGROUND_COLOR = document.body.style.getPropertyValue("--my-background-color");
|
|
||||||
FconfSettings.THEME_PROMPT_COLOR = document.body.style.getPropertyValue("--my-prompt-color");
|
|
||||||
} else {
|
|
||||||
const inputBackgroundHex = args[0] + "";
|
|
||||||
const inputTextHex = args[1] + "";
|
|
||||||
const inputHighlightHex = args[2] + "";
|
|
||||||
if (
|
|
||||||
/(^#[0-9A-F]{6}$)|(^#[0-9A-F]{3}$)/i.test(inputBackgroundHex) &&
|
|
||||||
/(^#[0-9A-F]{6}$)|(^#[0-9A-F]{3}$)/i.test(inputTextHex) &&
|
|
||||||
/(^#[0-9A-F]{6}$)|(^#[0-9A-F]{3}$)/i.test(inputHighlightHex)
|
|
||||||
) {
|
|
||||||
document.body.style.setProperty("--my-highlight-color", inputHighlightHex);
|
|
||||||
document.body.style.setProperty("--my-font-color", inputTextHex);
|
|
||||||
document.body.style.setProperty("--my-background-color", inputBackgroundHex);
|
|
||||||
FconfSettings.THEME_HIGHLIGHT_COLOR = document.body.style.getPropertyValue("--my-highlight-color");
|
|
||||||
FconfSettings.THEME_FONT_COLOR = document.body.style.getPropertyValue("--my-font-color");
|
|
||||||
FconfSettings.THEME_BACKGROUND_COLOR = document.body.style.getPropertyValue("--my-background-color");
|
|
||||||
} else {
|
|
||||||
return terminal.error("Invalid Hex Input for theme");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
86
src/db.tsx
Normal file
86
src/db.tsx
Normal file
@ -0,0 +1,86 @@
|
|||||||
|
import { Engine } from "./engine";
|
||||||
|
import { createStatusText } from "./ui/createStatusText";
|
||||||
|
|
||||||
|
function getDB(): Promise<IDBObjectStore> {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
if (!window.indexedDB) {
|
||||||
|
reject("Indexed DB does not exists");
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* DB is called bitburnerSave
|
||||||
|
* Object store is called savestring
|
||||||
|
* key for the Object store is called save
|
||||||
|
* Version `1` is important
|
||||||
|
*/
|
||||||
|
const indexedDbRequest: IDBOpenDBRequest = window.indexedDB.open("bitburnerSave", 1);
|
||||||
|
|
||||||
|
// This is called when there's no db to begin with. It's important, don't remove it.
|
||||||
|
indexedDbRequest.onupgradeneeded = function (this: IDBRequest<IDBDatabase>) {
|
||||||
|
const db = this.result;
|
||||||
|
db.createObjectStore("savestring");
|
||||||
|
};
|
||||||
|
|
||||||
|
indexedDbRequest.onerror = function (this: IDBRequest<IDBDatabase>, ev: Event) {
|
||||||
|
reject(`Failed to get IDB ${ev}`);
|
||||||
|
};
|
||||||
|
|
||||||
|
indexedDbRequest.onsuccess = function (this: IDBRequest<IDBDatabase>, ev: Event) {
|
||||||
|
const db = this.result;
|
||||||
|
if (!db) {
|
||||||
|
reject("database loadign result was undefined");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
resolve(db.transaction(["savestring"], "readwrite").objectStore("savestring"));
|
||||||
|
};
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ILoadCallback {
|
||||||
|
success: (s: string) => void;
|
||||||
|
error?: () => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function load(): Promise<string> {
|
||||||
|
return new Promise(async (resolve, reject) => {
|
||||||
|
await getDB()
|
||||||
|
.then((db) => {
|
||||||
|
return new Promise<string>((resolve, reject) => {
|
||||||
|
const request: IDBRequest<string> = db.get("save");
|
||||||
|
request.onerror = function (this: IDBRequest<string>, ev: Event) {
|
||||||
|
reject("Error in Database request to get savestring: " + ev);
|
||||||
|
};
|
||||||
|
|
||||||
|
request.onsuccess = function (this: IDBRequest<string>) {
|
||||||
|
resolve(this.result);
|
||||||
|
};
|
||||||
|
}).then((saveString) => resolve(saveString));
|
||||||
|
})
|
||||||
|
.catch((r) => reject(r));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ISaveCallback {
|
||||||
|
success: () => void;
|
||||||
|
error?: () => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function save(saveString: string): Promise<void> {
|
||||||
|
return getDB().then((db) => {
|
||||||
|
return new Promise<void>((resolve, reject) => {
|
||||||
|
// We'll save to both localstorage and indexedDb
|
||||||
|
const request = db.put(saveString, "save");
|
||||||
|
|
||||||
|
request.onerror = function (e) {
|
||||||
|
reject("Error saving game to IndexedDB: " + e);
|
||||||
|
};
|
||||||
|
|
||||||
|
request.onsuccess = () => resolve();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export function deleteGame(): Promise<void> {
|
||||||
|
return getDB().then((db) => {
|
||||||
|
db.delete("save");
|
||||||
|
});
|
||||||
|
}
|
2
src/engine.d.ts
vendored
2
src/engine.d.ts
vendored
@ -1,3 +1 @@
|
|||||||
export declare function load(cb: () => void): void;
|
|
||||||
|
|
||||||
export declare const Engine: IEngine;
|
export declare const Engine: IEngine;
|
||||||
|
@ -44,14 +44,12 @@ import { Reputation } from "./ui/React/Reputation";
|
|||||||
import { dialogBoxCreate } from "../utils/DialogBox";
|
import { dialogBoxCreate } from "../utils/DialogBox";
|
||||||
import { exceptionAlert } from "../utils/helpers/exceptionAlert";
|
import { exceptionAlert } from "../utils/helpers/exceptionAlert";
|
||||||
|
|
||||||
import "./Exploits/tampering";
|
import { startTampering } from "./Exploits/tampering";
|
||||||
import "./Exploits/unclickable";
|
import { startUnclickable } from "./Exploits/unclickable";
|
||||||
|
|
||||||
import React from "react";
|
import React from "react";
|
||||||
|
|
||||||
const Engine = {
|
const Engine = {
|
||||||
indexedDb: undefined,
|
|
||||||
|
|
||||||
// Time variables (milliseconds unix epoch time)
|
// Time variables (milliseconds unix epoch time)
|
||||||
_lastUpdate: new Date().getTime(),
|
_lastUpdate: new Date().getTime(),
|
||||||
|
|
||||||
@ -196,7 +194,7 @@ const Engine = {
|
|||||||
Engine.Counters.autoSaveCounter = Infinity;
|
Engine.Counters.autoSaveCounter = Infinity;
|
||||||
} else {
|
} else {
|
||||||
Engine.Counters.autoSaveCounter = Settings.AutosaveInterval * 5;
|
Engine.Counters.autoSaveCounter = Settings.AutosaveInterval * 5;
|
||||||
saveObject.saveGame(Engine.indexedDb);
|
saveObject.saveGame();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -248,6 +246,8 @@ const Engine = {
|
|||||||
},
|
},
|
||||||
|
|
||||||
load: function (saveString) {
|
load: function (saveString) {
|
||||||
|
startTampering();
|
||||||
|
startUnclickable();
|
||||||
// Load game from save or create new game
|
// Load game from save or create new game
|
||||||
if (loadGame(saveString)) {
|
if (loadGame(saveString)) {
|
||||||
initBitNodeMultipliers(Player);
|
initBitNodeMultipliers(Player);
|
||||||
@ -420,48 +420,4 @@ const Engine = {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
function load(cb) {
|
export { Engine };
|
||||||
if (!window.indexedDB) {
|
|
||||||
return Engine.load(null); // Will try to load from localstorage
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* DB is called bitburnerSave
|
|
||||||
* Object store is called savestring
|
|
||||||
* key for the Object store is called save
|
|
||||||
*/
|
|
||||||
indexedDbRequest = window.indexedDB.open("bitburnerSave", 1);
|
|
||||||
|
|
||||||
indexedDbRequest.onerror = function (e) {
|
|
||||||
console.error("Error opening indexedDB: ");
|
|
||||||
console.error(e);
|
|
||||||
Engine.load(null); // Try to load from localstorage
|
|
||||||
cb();
|
|
||||||
};
|
|
||||||
|
|
||||||
indexedDbRequest.onsuccess = function (e) {
|
|
||||||
Engine.indexedDb = e.target.result;
|
|
||||||
var transaction = Engine.indexedDb.transaction(["savestring"]);
|
|
||||||
var objectStore = transaction.objectStore("savestring");
|
|
||||||
var request = objectStore.get("save");
|
|
||||||
request.onerror = function (e) {
|
|
||||||
console.error("Error in Database request to get savestring: " + e);
|
|
||||||
Engine.load(null); // Try to load from localstorage
|
|
||||||
cb();
|
|
||||||
};
|
|
||||||
|
|
||||||
request.onsuccess = function () {
|
|
||||||
Engine.load(request.result);
|
|
||||||
cb();
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
indexedDbRequest.onupgradeneeded = function (e) {
|
|
||||||
const db = e.target.result;
|
|
||||||
db.createObjectStore("savestring");
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
var indexedDbRequest;
|
|
||||||
|
|
||||||
export { Engine, load };
|
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
import ReactDOM from "react-dom";
|
import ReactDOM from "react-dom";
|
||||||
|
|
||||||
import { TTheme as Theme } from "./ui/React/Theme";
|
import { TTheme as Theme, colors } from "./ui/React/Theme";
|
||||||
import { LoadingScreen } from "./ui/LoadingScreen";
|
import { LoadingScreen } from "./ui/LoadingScreen";
|
||||||
import "./engineStyle";
|
import "./engineStyle";
|
||||||
|
|
||||||
@ -11,3 +11,14 @@ ReactDOM.render(
|
|||||||
</Theme>,
|
</Theme>,
|
||||||
document.getElementById("mainmenu-container"),
|
document.getElementById("mainmenu-container"),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// setTimeout(() => {
|
||||||
|
// colors.primary = "#fff";
|
||||||
|
// refreshTheme();
|
||||||
|
// ReactDOM.render(
|
||||||
|
// <Theme>
|
||||||
|
// <LoadingScreen />
|
||||||
|
// </Theme>,
|
||||||
|
// document.getElementById("mainmenu-container"),
|
||||||
|
// );
|
||||||
|
// }, 5000);
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
*/
|
*/
|
||||||
import * as React from "react";
|
import * as React from "react";
|
||||||
|
|
||||||
|
import { Money } from "../React/Money";
|
||||||
import { MoneyRate } from "../React/MoneyRate";
|
import { MoneyRate } from "../React/MoneyRate";
|
||||||
import { use } from "../Context";
|
import { use } from "../Context";
|
||||||
|
|
||||||
@ -40,18 +41,13 @@ export function ScriptProduction(): React.ReactElement {
|
|||||||
<TableBody>
|
<TableBody>
|
||||||
<TableRow>
|
<TableRow>
|
||||||
<TableCell component="th" scope="row" classes={{ root: classes.cell }}>
|
<TableCell component="th" scope="row" classes={{ root: classes.cell }}>
|
||||||
<Typography variant="body2">Total online production of Active scripts:</Typography>
|
<Typography variant="body2">Total production:</Typography>
|
||||||
</TableCell>
|
</TableCell>
|
||||||
<TableCell align="left" classes={{ root: classes.cell }}>
|
<TableCell align="left" classes={{ root: classes.cell }}>
|
||||||
<Typography variant="body2">
|
<Typography variant="body2">
|
||||||
<MoneyRate money={player.scriptProdSinceLastAug} />
|
<Money money={player.scriptProdSinceLastAug} />
|
||||||
</Typography>
|
</Typography>
|
||||||
</TableCell>
|
</TableCell>
|
||||||
</TableRow>
|
|
||||||
<TableRow style={{ width: "1px" }}>
|
|
||||||
<TableCell component="th" scope="row" classes={{ root: classes.cell }}>
|
|
||||||
<Typography variant="body2">Total online production since last Aug installation:</Typography>
|
|
||||||
</TableCell>
|
|
||||||
<TableCell align="left" classes={{ root: classes.cell }}>
|
<TableCell align="left" classes={{ root: classes.cell }}>
|
||||||
<Typography variant="body2">
|
<Typography variant="body2">
|
||||||
(<MoneyRate money={prodRateSinceLastAug} />)
|
(<MoneyRate money={prodRateSinceLastAug} />)
|
||||||
|
@ -4,6 +4,7 @@ import { WorkerScriptAccordion } from "./WorkerScriptAccordion";
|
|||||||
import List from "@mui/material/List";
|
import List from "@mui/material/List";
|
||||||
import TablePagination from "@mui/material/TablePagination";
|
import TablePagination from "@mui/material/TablePagination";
|
||||||
import { TablePaginationActionsAll } from "../React/TablePaginationActionsAll";
|
import { TablePaginationActionsAll } from "../React/TablePaginationActionsAll";
|
||||||
|
import { Settings } from "../../Settings/Settings";
|
||||||
|
|
||||||
interface IProps {
|
interface IProps {
|
||||||
workerScripts: WorkerScript[];
|
workerScripts: WorkerScript[];
|
||||||
@ -11,36 +12,30 @@ interface IProps {
|
|||||||
|
|
||||||
export function ServerAccordionContent(props: IProps): React.ReactElement {
|
export function ServerAccordionContent(props: IProps): React.ReactElement {
|
||||||
const [page, setPage] = useState(0);
|
const [page, setPage] = useState(0);
|
||||||
const [rowsPerPage, setRowsPerPage] = useState(10);
|
const [rowsPerPage, setRowsPerPage] = useState(Settings.ActiveScriptsScriptPageSize);
|
||||||
const handleChangePage = (event: unknown, newPage: number): void => {
|
const handleChangePage = (event: unknown, newPage: number): void => {
|
||||||
setPage(newPage);
|
setPage(newPage);
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleChangeRowsPerPage = (event: React.ChangeEvent<HTMLInputElement>): void => {
|
const handleChangeRowsPerPage = (event: React.ChangeEvent<HTMLInputElement>): void => {
|
||||||
|
Settings.ActiveScriptsScriptPageSize = parseInt(event.target.value, 10);
|
||||||
setRowsPerPage(parseInt(event.target.value, 10));
|
setRowsPerPage(parseInt(event.target.value, 10));
|
||||||
setPage(0);
|
setPage(0);
|
||||||
};
|
};
|
||||||
|
|
||||||
let safePage = page;
|
|
||||||
while (safePage * rowsPerPage + 1 > props.workerScripts.length) {
|
|
||||||
safePage--;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (safePage != page) setPage(safePage);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<List dense disablePadding>
|
<List dense disablePadding>
|
||||||
{props.workerScripts.slice(safePage * rowsPerPage, safePage * rowsPerPage + rowsPerPage).map((ws) => (
|
{props.workerScripts.slice(page * rowsPerPage, page * rowsPerPage + rowsPerPage).map((ws) => (
|
||||||
<WorkerScriptAccordion key={`${ws.name}_${ws.args}`} workerScript={ws} />
|
<WorkerScriptAccordion key={`${ws.name}_${ws.args}`} workerScript={ws} />
|
||||||
))}
|
))}
|
||||||
</List>
|
</List>
|
||||||
<TablePagination
|
<TablePagination
|
||||||
rowsPerPageOptions={[10, 15, 20]}
|
rowsPerPageOptions={[10, 15, 20, 100]}
|
||||||
component="div"
|
component="div"
|
||||||
count={props.workerScripts.length}
|
count={props.workerScripts.length}
|
||||||
rowsPerPage={rowsPerPage}
|
rowsPerPage={rowsPerPage}
|
||||||
page={safePage}
|
page={page}
|
||||||
onPageChange={handleChangePage}
|
onPageChange={handleChangePage}
|
||||||
onRowsPerPageChange={handleChangeRowsPerPage}
|
onRowsPerPageChange={handleChangeRowsPerPage}
|
||||||
ActionsComponent={TablePaginationActionsAll}
|
ActionsComponent={TablePaginationActionsAll}
|
||||||
|
@ -13,6 +13,7 @@ import { WorkerScript } from "../../Netscript/WorkerScript";
|
|||||||
import { WorkerScriptStartStopEventEmitter } from "../../Netscript/WorkerScriptStartStopEventEmitter";
|
import { WorkerScriptStartStopEventEmitter } from "../../Netscript/WorkerScriptStartStopEventEmitter";
|
||||||
import { getServer } from "../../Server/ServerHelpers";
|
import { getServer } from "../../Server/ServerHelpers";
|
||||||
import { BaseServer } from "../../Server/BaseServer";
|
import { BaseServer } from "../../Server/BaseServer";
|
||||||
|
import { Settings } from "../../Settings/Settings";
|
||||||
import { TablePaginationActionsAll } from "../React/TablePaginationActionsAll";
|
import { TablePaginationActionsAll } from "../React/TablePaginationActionsAll";
|
||||||
import SearchIcon from "@mui/icons-material/Search";
|
import SearchIcon from "@mui/icons-material/Search";
|
||||||
|
|
||||||
@ -33,7 +34,7 @@ type IProps = {
|
|||||||
export function ServerAccordions(props: IProps): React.ReactElement {
|
export function ServerAccordions(props: IProps): React.ReactElement {
|
||||||
const [filter, setFilter] = useState("");
|
const [filter, setFilter] = useState("");
|
||||||
const [page, setPage] = useState(0);
|
const [page, setPage] = useState(0);
|
||||||
const [rowsPerPage, setRowsPerPage] = useState(10);
|
const [rowsPerPage, setRowsPerPage] = useState(Settings.ActiveScriptsServerPageSize);
|
||||||
const setRerender = useState(false)[1];
|
const setRerender = useState(false)[1];
|
||||||
|
|
||||||
const handleChangePage = (event: unknown, newPage: number): void => {
|
const handleChangePage = (event: unknown, newPage: number): void => {
|
||||||
@ -41,6 +42,7 @@ export function ServerAccordions(props: IProps): React.ReactElement {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const handleChangeRowsPerPage = (event: React.ChangeEvent<HTMLInputElement>): void => {
|
const handleChangeRowsPerPage = (event: React.ChangeEvent<HTMLInputElement>): void => {
|
||||||
|
Settings.ActiveScriptsServerPageSize = parseInt(event.target.value, 10);
|
||||||
setRowsPerPage(parseInt(event.target.value, 10));
|
setRowsPerPage(parseInt(event.target.value, 10));
|
||||||
setPage(0);
|
setPage(0);
|
||||||
};
|
};
|
||||||
@ -74,13 +76,6 @@ export function ServerAccordions(props: IProps): React.ReactElement {
|
|||||||
|
|
||||||
function rerender(): void {
|
function rerender(): void {
|
||||||
setRerender((old) => !old);
|
setRerender((old) => !old);
|
||||||
|
|
||||||
let safePage = page;
|
|
||||||
while (safePage * rowsPerPage + 1 >= filtered.length) {
|
|
||||||
safePage--;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (safePage != page) setPage(safePage);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
useEffect(() => WorkerScriptStartStopEventEmitter.subscribe(rerender));
|
useEffect(() => WorkerScriptStartStopEventEmitter.subscribe(rerender));
|
||||||
@ -108,7 +103,7 @@ export function ServerAccordions(props: IProps): React.ReactElement {
|
|||||||
})}
|
})}
|
||||||
</List>
|
</List>
|
||||||
<TablePagination
|
<TablePagination
|
||||||
rowsPerPageOptions={[10, 15, 20]}
|
rowsPerPageOptions={[10, 15, 20, 100]}
|
||||||
component="div"
|
component="div"
|
||||||
count={filtered.length}
|
count={filtered.length}
|
||||||
rowsPerPage={rowsPerPage}
|
rowsPerPage={rowsPerPage}
|
||||||
|
@ -4,7 +4,7 @@ import { IPlayer } from "../PersonObjects/IPlayer";
|
|||||||
import { IEngine } from "../IEngine";
|
import { IEngine } from "../IEngine";
|
||||||
import { ITerminal } from "../Terminal/ITerminal";
|
import { ITerminal } from "../Terminal/ITerminal";
|
||||||
import { installAugmentations } from "../Augmentation/AugmentationHelpers";
|
import { installAugmentations } from "../Augmentation/AugmentationHelpers";
|
||||||
import { saveObject, openImportFileHandler } from "../SaveObject";
|
import { saveObject } from "../SaveObject";
|
||||||
import { onExport } from "../ExportBonus";
|
import { onExport } from "../ExportBonus";
|
||||||
import { LocationName } from "../Locations/data/LocationNames";
|
import { LocationName } from "../Locations/data/LocationNames";
|
||||||
import { Location } from "../Locations/Location";
|
import { Location } from "../Locations/Location";
|
||||||
@ -282,7 +282,7 @@ export function GameRoot({ player, engine, terminal }: IProps): React.ReactEleme
|
|||||||
<Context.Router.Provider value={Router}>
|
<Context.Router.Provider value={Router}>
|
||||||
<Overview>
|
<Overview>
|
||||||
{!ITutorial.isRunning ? (
|
{!ITutorial.isRunning ? (
|
||||||
<CharacterOverview save={() => saveObject.saveGame(engine.indexedDb)} />
|
<CharacterOverview save={() => saveObject.saveGame()} />
|
||||||
) : (
|
) : (
|
||||||
<InteractiveTutorialRoot />
|
<InteractiveTutorialRoot />
|
||||||
)}
|
)}
|
||||||
@ -300,7 +300,7 @@ export function GameRoot({ player, engine, terminal }: IProps): React.ReactEleme
|
|||||||
) : (
|
) : (
|
||||||
<Box display="flex" flexDirection="row" width="100%">
|
<Box display="flex" flexDirection="row" width="100%">
|
||||||
<SidebarRoot player={player} router={Router} page={page} />
|
<SidebarRoot player={player} router={Router} page={page} />
|
||||||
<Box className={classes.root} flexGrow={1} display="block" width="100%" px={1} height="100vh">
|
<Box className={classes.root} flexGrow={1} display="block" px={1} height="100vh">
|
||||||
{page === Page.Terminal ? (
|
{page === Page.Terminal ? (
|
||||||
<TerminalRoot terminal={terminal} router={Router} player={player} />
|
<TerminalRoot terminal={terminal} router={Router} player={player} />
|
||||||
) : page === Page.Sleeves ? (
|
) : page === Page.Sleeves ? (
|
||||||
@ -357,10 +357,8 @@ export function GameRoot({ player, engine, terminal }: IProps): React.ReactEleme
|
|||||||
) : page === Page.Options ? (
|
) : page === Page.Options ? (
|
||||||
<GameOptionsRoot
|
<GameOptionsRoot
|
||||||
player={player}
|
player={player}
|
||||||
save={() => saveObject.saveGame(engine.indexedDb)}
|
save={() => saveObject.saveGame()}
|
||||||
delete={() => saveObject.deleteGame(engine.indexedDb)}
|
|
||||||
export={() => saveObject.exportGame()}
|
export={() => saveObject.exportGame()}
|
||||||
import={openImportFileHandler}
|
|
||||||
forceKill={() => {
|
forceKill={() => {
|
||||||
for (const hostname of Object.keys(AllServers)) {
|
for (const hostname of Object.keys(AllServers)) {
|
||||||
AllServers[hostname].runningScripts = [];
|
AllServers[hostname].runningScripts = [];
|
||||||
|
@ -535,7 +535,7 @@ export function InteractiveTutorialRoot(): React.ReactElement {
|
|||||||
const content = contents[step];
|
const content = contents[step];
|
||||||
if (content === undefined) throw new Error("error in the tutorial");
|
if (content === undefined) throw new Error("error in the tutorial");
|
||||||
return (
|
return (
|
||||||
<Paper square sx={{ maxWidth: "35vh", p: 2 }}>
|
<Paper square sx={{ maxWidth: "70vw", p: 2 }}>
|
||||||
{content.content}
|
{content.content}
|
||||||
{step !== iTutorialSteps.TutorialPageInfo && (
|
{step !== iTutorialSteps.TutorialPageInfo && (
|
||||||
<>
|
<>
|
||||||
|
@ -4,56 +4,13 @@ import Typography from "@mui/material/Typography";
|
|||||||
import Grid from "@mui/material/Grid";
|
import Grid from "@mui/material/Grid";
|
||||||
|
|
||||||
import { Terminal } from "../Terminal";
|
import { Terminal } from "../Terminal";
|
||||||
import { Engine } from "../engine";
|
import { load } from "../db";
|
||||||
import { Player } from "../Player";
|
import { Player } from "../Player";
|
||||||
|
import { Engine } from "../engine";
|
||||||
import { GameRoot } from "./GameRoot";
|
import { GameRoot } from "./GameRoot";
|
||||||
|
|
||||||
import { CONSTANTS } from "../Constants";
|
import { CONSTANTS } from "../Constants";
|
||||||
|
|
||||||
function load(cb: () => void): void {
|
|
||||||
if (!window.indexedDB) {
|
|
||||||
return Engine.load(""); // Will try to load from localstorage
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* DB is called bitburnerSave
|
|
||||||
* Object store is called savestring
|
|
||||||
* key for the Object store is called save
|
|
||||||
*/
|
|
||||||
// Version 1 is important
|
|
||||||
const indexedDbRequest: IDBOpenDBRequest = window.indexedDB.open("bitburnerSave", 1);
|
|
||||||
|
|
||||||
indexedDbRequest.onerror = function (this: IDBRequest<IDBDatabase>, ev: Event) {
|
|
||||||
console.error("Error opening indexedDB: ");
|
|
||||||
console.error(ev);
|
|
||||||
Engine.load(""); // Try to load from localstorage
|
|
||||||
cb();
|
|
||||||
};
|
|
||||||
|
|
||||||
indexedDbRequest.onsuccess = function (this: IDBRequest<IDBDatabase>) {
|
|
||||||
Engine.indexedDb = this.result;
|
|
||||||
const transaction = Engine.indexedDb.transaction(["savestring"]);
|
|
||||||
const objectStore = transaction.objectStore("savestring");
|
|
||||||
const request: IDBRequest<string> = objectStore.get("save");
|
|
||||||
request.onerror = function (this: IDBRequest<string>, ev: Event) {
|
|
||||||
console.error("Error in Database request to get savestring: " + ev);
|
|
||||||
Engine.load(""); // Try to load from localstorage
|
|
||||||
cb();
|
|
||||||
};
|
|
||||||
|
|
||||||
request.onsuccess = function (this: IDBRequest<string>) {
|
|
||||||
Engine.load(this.result);
|
|
||||||
cb();
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
// This is called when there's no db to begin with. It's important.
|
|
||||||
indexedDbRequest.onupgradeneeded = function (this: IDBRequest<IDBDatabase>) {
|
|
||||||
const db = this.result;
|
|
||||||
db.createObjectStore("savestring");
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function LoadingScreen(): React.ReactElement {
|
export function LoadingScreen(): React.ReactElement {
|
||||||
const [show, setShow] = useState(false);
|
const [show, setShow] = useState(false);
|
||||||
const [loaded, setLoaded] = useState(false);
|
const [loaded, setLoaded] = useState(false);
|
||||||
@ -66,9 +23,19 @@ export function LoadingScreen(): React.ReactElement {
|
|||||||
});
|
});
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
load(() => {
|
async function doLoad() {
|
||||||
setLoaded(true);
|
await load()
|
||||||
});
|
.then((saveString) => {
|
||||||
|
Engine.load(saveString);
|
||||||
|
setLoaded(true);
|
||||||
|
})
|
||||||
|
.catch((reason) => {
|
||||||
|
console.error(reason);
|
||||||
|
Engine.load("");
|
||||||
|
setLoaded(true);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
doLoad();
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
if (loaded) {
|
if (loaded) {
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import * as React from "react";
|
import * as React from "react";
|
||||||
|
|
||||||
export function Augmentation(name: string): JSX.Element {
|
export function Augmentation({ name }: { name: string }): JSX.Element {
|
||||||
return (
|
return (
|
||||||
<span className={"samefont"} style={{ color: "white" }}>
|
<span className={"samefont"} style={{ color: "white" }}>
|
||||||
{name}
|
{name}
|
||||||
|
@ -1,7 +1,9 @@
|
|||||||
// Root React Component for the Corporation UI
|
// Root React Component for the Corporation UI
|
||||||
import React, { useState, useEffect } from "react";
|
import React, { useState, useEffect } from "react";
|
||||||
|
|
||||||
|
import { Theme } from "@mui/material/styles";
|
||||||
import makeStyles from "@mui/styles/makeStyles";
|
import makeStyles from "@mui/styles/makeStyles";
|
||||||
|
import createStyles from "@mui/styles/createStyles";
|
||||||
import { numeralWrapper } from "../../ui/numeralFormat";
|
import { numeralWrapper } from "../../ui/numeralFormat";
|
||||||
import { Reputation } from "./Reputation";
|
import { Reputation } from "./Reputation";
|
||||||
|
|
||||||
@ -78,35 +80,37 @@ function Work(): React.ReactElement {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const useStyles = makeStyles({
|
const useStyles = makeStyles((theme: Theme) =>
|
||||||
cellNone: {
|
createStyles({
|
||||||
borderBottom: "none",
|
cellNone: {
|
||||||
padding: 0,
|
borderBottom: "none",
|
||||||
margin: 0,
|
padding: 0,
|
||||||
},
|
margin: 0,
|
||||||
cell: {
|
},
|
||||||
padding: 0,
|
cell: {
|
||||||
margin: 0,
|
padding: 0,
|
||||||
},
|
margin: 0,
|
||||||
hp: {
|
},
|
||||||
color: colors.hp,
|
hp: {
|
||||||
},
|
color: theme.colors.hp,
|
||||||
money: {
|
},
|
||||||
color: colors.money,
|
money: {
|
||||||
},
|
color: theme.colors.money,
|
||||||
hack: {
|
},
|
||||||
color: colors.hack,
|
hack: {
|
||||||
},
|
color: theme.colors.hack,
|
||||||
combat: {
|
},
|
||||||
color: colors.combat,
|
combat: {
|
||||||
},
|
color: theme.colors.combat,
|
||||||
cha: {
|
},
|
||||||
color: colors.cha,
|
cha: {
|
||||||
},
|
color: theme.colors.cha,
|
||||||
int: {
|
},
|
||||||
color: colors.int,
|
int: {
|
||||||
},
|
color: theme.colors.int,
|
||||||
});
|
},
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
export function CharacterOverview({ save }: IProps): React.ReactElement {
|
export function CharacterOverview({ save }: IProps): React.ReactElement {
|
||||||
const player = use.Player();
|
const player = use.Player();
|
||||||
|
@ -28,6 +28,7 @@ import { dialogBoxCreate } from "../../../utils/DialogBox";
|
|||||||
import { ConfirmationModal } from "./ConfirmationModal";
|
import { ConfirmationModal } from "./ConfirmationModal";
|
||||||
|
|
||||||
import { Settings } from "../../Settings/Settings";
|
import { Settings } from "../../Settings/Settings";
|
||||||
|
import { save, deleteGame } from "../../db";
|
||||||
|
|
||||||
const useStyles = makeStyles((theme: Theme) =>
|
const useStyles = makeStyles((theme: Theme) =>
|
||||||
createStyles({
|
createStyles({
|
||||||
@ -42,9 +43,7 @@ const useStyles = makeStyles((theme: Theme) =>
|
|||||||
interface IProps {
|
interface IProps {
|
||||||
player: IPlayer;
|
player: IPlayer;
|
||||||
save: () => void;
|
save: () => void;
|
||||||
delete: () => void;
|
|
||||||
export: () => void;
|
export: () => void;
|
||||||
import: (evt: any) => void;
|
|
||||||
forceKill: () => void;
|
forceKill: () => void;
|
||||||
softReset: () => void;
|
softReset: () => void;
|
||||||
}
|
}
|
||||||
@ -153,20 +152,38 @@ export function GameOptionsRoot(props: IProps): React.ReactElement {
|
|||||||
Settings.Locale = event.target.value as string;
|
Settings.Locale = event.target.value as string;
|
||||||
}
|
}
|
||||||
|
|
||||||
function importSave(): void {
|
function startImport(): void {
|
||||||
if (window.File && window.FileReader && window.FileList && window.Blob) {
|
if (!window.File || !window.FileReader || !window.FileList || !window.Blob) return;
|
||||||
// var fileSelector = clearEventListeners("import-game-file-selector");
|
const ii = importInput.current;
|
||||||
// fileSelector.addEventListener("change", openImportFileHandler, false);
|
if (ii === null) throw new Error("import input should not be null");
|
||||||
const ii = importInput.current;
|
ii.click();
|
||||||
if (ii === null) throw new Error("import input should not be null");
|
|
||||||
ii.click();
|
|
||||||
} else {
|
|
||||||
dialogBoxCreate("ERR: Your browser does not support HTML5 File API. Cannot import.");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function onImport(event: React.ChangeEvent<HTMLInputElement>): void {
|
function onImport(event: React.ChangeEvent<HTMLInputElement>): void {
|
||||||
props.import(event);
|
const files = event.target.files;
|
||||||
|
if (files === null) return;
|
||||||
|
const file = files[0];
|
||||||
|
if (!file) {
|
||||||
|
dialogBoxCreate("Invalid file selected");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const reader = new FileReader();
|
||||||
|
reader.onload = function (this: FileReader, e: ProgressEvent<FileReader>) {
|
||||||
|
const target = e.target;
|
||||||
|
if (target === null) {
|
||||||
|
console.error("error importing file");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const result = target.result;
|
||||||
|
if (typeof result !== "string" || result === null) {
|
||||||
|
console.error("FileReader event was not type string");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const contents = result;
|
||||||
|
save(contents).then(() => location.reload());
|
||||||
|
};
|
||||||
|
reader.readAsText(file);
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@ -490,7 +507,7 @@ export function GameOptionsRoot(props: IProps): React.ReactElement {
|
|||||||
</Button>
|
</Button>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
<Tooltip title={<Typography>import</Typography>}>
|
<Tooltip title={<Typography>import</Typography>}>
|
||||||
<Button onClick={importSave}>
|
<Button onClick={startImport}>
|
||||||
<UploadIcon color="primary" />
|
<UploadIcon color="primary" />
|
||||||
Import
|
Import
|
||||||
<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} />
|
||||||
@ -536,6 +553,9 @@ export function GameOptionsRoot(props: IProps): React.ReactElement {
|
|||||||
</Tooltip>
|
</Tooltip>
|
||||||
</Box>
|
</Box>
|
||||||
<Box>
|
<Box>
|
||||||
|
<Link href="https://github.com/danielyxie/bitburner/issues/new" target="_blank">
|
||||||
|
<Typography>Report bug</Typography>
|
||||||
|
</Link>
|
||||||
<Link href="https://bitburner.readthedocs.io/en/latest/changelog.html" target="_blank">
|
<Link href="https://bitburner.readthedocs.io/en/latest/changelog.html" target="_blank">
|
||||||
<Typography>Changelog</Typography>
|
<Typography>Changelog</Typography>
|
||||||
</Link>
|
</Link>
|
||||||
@ -554,8 +574,10 @@ export function GameOptionsRoot(props: IProps): React.ReactElement {
|
|||||||
<FileDiagnosticModal open={diagnosticOpen} onClose={() => setDiagnosticOpen(false)} />
|
<FileDiagnosticModal open={diagnosticOpen} onClose={() => setDiagnosticOpen(false)} />
|
||||||
<ConfirmationModal
|
<ConfirmationModal
|
||||||
onConfirm={() => {
|
onConfirm={() => {
|
||||||
props.delete();
|
|
||||||
setDeleteOpen(false);
|
setDeleteOpen(false);
|
||||||
|
deleteGame()
|
||||||
|
.then(() => location.reload())
|
||||||
|
.catch((r) => console.error(`Could not delete game: ${r}`));
|
||||||
}}
|
}}
|
||||||
open={deleteGameOpen}
|
open={deleteGameOpen}
|
||||||
onClose={() => setDeleteOpen(false)}
|
onClose={() => setDeleteOpen(false)}
|
||||||
|
@ -5,6 +5,7 @@ import Box from "@mui/material/Box";
|
|||||||
import Collapse from "@mui/material/Collapse";
|
import Collapse from "@mui/material/Collapse";
|
||||||
import Fab from "@mui/material/Fab";
|
import Fab from "@mui/material/Fab";
|
||||||
import VisibilityOffIcon from "@mui/icons-material/VisibilityOff";
|
import VisibilityOffIcon from "@mui/icons-material/VisibilityOff";
|
||||||
|
import VisibilityIcon from "@mui/icons-material/Visibility";
|
||||||
import { use } from "../Context";
|
import { use } from "../Context";
|
||||||
import { Page } from "../Router";
|
import { Page } from "../Router";
|
||||||
|
|
||||||
@ -24,13 +25,19 @@ export function Overview({ children }: IProps): React.ReactElement {
|
|||||||
const router = use.Router();
|
const router = use.Router();
|
||||||
if (router.page() === Page.BitVerse || router.page() === Page.HackingMission || router.page() === Page.Loading)
|
if (router.page() === Page.BitVerse || router.page() === Page.HackingMission || router.page() === Page.Loading)
|
||||||
return <></>;
|
return <></>;
|
||||||
|
let icon;
|
||||||
|
if (open){
|
||||||
|
icon = <VisibilityOffIcon color="primary" />;
|
||||||
|
} else {
|
||||||
|
icon = <VisibilityIcon color="primary" />;
|
||||||
|
}
|
||||||
return (
|
return (
|
||||||
<div style={{ position: "fixed", top: 0, right: 0, zIndex: 1500 }}>
|
<div style={{ position: "fixed", top: 0, right: 0, zIndex: 1500 }}>
|
||||||
<Box display="flex" justifyContent="flex-end" flexDirection={"column"}>
|
<Box display="flex" justifyContent="flex-end" flexDirection={"column"}>
|
||||||
<Collapse in={open}>{children}</Collapse>
|
<Collapse in={open}>{children}</Collapse>
|
||||||
<Box display="flex" justifyContent="flex-end">
|
<Box display="flex" justifyContent="flex-end">
|
||||||
<Fab classes={{ root: classes.nobackground }} onClick={() => setOpen((old) => !old)}>
|
<Fab classes={{ root: classes.nobackground }} onClick={() => setOpen((old) => !old)}>
|
||||||
<VisibilityOffIcon color="primary" />
|
{icon}
|
||||||
</Fab>
|
</Fab>
|
||||||
</Box>
|
</Box>
|
||||||
</Box>
|
</Box>
|
||||||
|
@ -1,12 +1,31 @@
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
import { createTheme, ThemeProvider, Theme, StyledEngineProvider } from "@mui/material/styles";
|
import { createTheme, ThemeProvider, Theme, StyledEngineProvider } from "@mui/material/styles";
|
||||||
|
|
||||||
declare module "@mui/styles/defaultTheme" {
|
declare module "@mui/material/styles" {
|
||||||
// eslint-disable-next-line @typescript-eslint/no-empty-interface
|
interface Theme {
|
||||||
interface DefaultTheme extends Theme {}
|
colors: {
|
||||||
|
hp: React.CSSProperties["color"];
|
||||||
|
money: React.CSSProperties["color"];
|
||||||
|
hack: React.CSSProperties["color"];
|
||||||
|
combat: React.CSSProperties["color"];
|
||||||
|
cha: React.CSSProperties["color"];
|
||||||
|
int: React.CSSProperties["color"];
|
||||||
|
rep: React.CSSProperties["color"];
|
||||||
|
};
|
||||||
|
}
|
||||||
|
interface ThemeOptions {
|
||||||
|
colors: {
|
||||||
|
hp: React.CSSProperties["color"];
|
||||||
|
money: React.CSSProperties["color"];
|
||||||
|
hack: React.CSSProperties["color"];
|
||||||
|
combat: React.CSSProperties["color"];
|
||||||
|
cha: React.CSSProperties["color"];
|
||||||
|
int: React.CSSProperties["color"];
|
||||||
|
rep: React.CSSProperties["color"];
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
export let colors = {
|
||||||
export const colors = {
|
|
||||||
primarylight: "#0f0",
|
primarylight: "#0f0",
|
||||||
primary: "#0c0",
|
primary: "#0c0",
|
||||||
primarydark: "#090",
|
primarydark: "#090",
|
||||||
@ -38,227 +57,242 @@ export const colors = {
|
|||||||
combat: "#faffdf",
|
combat: "#faffdf",
|
||||||
cha: "#a671d1",
|
cha: "#a671d1",
|
||||||
int: "#6495ed",
|
int: "#6495ed",
|
||||||
|
rep: "#faffdf",
|
||||||
};
|
};
|
||||||
|
|
||||||
export const theme = createTheme({
|
let theme: Theme;
|
||||||
palette: {
|
|
||||||
primary: {
|
function refreshTheme() {
|
||||||
light: colors.primarylight,
|
theme = createTheme({
|
||||||
main: colors.primary,
|
colors: {
|
||||||
dark: colors.primarydark,
|
hp: "#dd3434",
|
||||||
|
money: "#ffd700",
|
||||||
|
hack: "#adff2f",
|
||||||
|
combat: "#faffdf",
|
||||||
|
cha: "#a671d1",
|
||||||
|
int: "#6495ed",
|
||||||
|
rep: "#faffdf",
|
||||||
},
|
},
|
||||||
secondary: {
|
palette: {
|
||||||
light: colors.secondarylight,
|
primary: {
|
||||||
main: colors.secondary,
|
light: colors.primarylight,
|
||||||
dark: colors.secondarydark,
|
main: colors.primary,
|
||||||
|
dark: colors.primarydark,
|
||||||
|
},
|
||||||
|
secondary: {
|
||||||
|
light: colors.secondarylight,
|
||||||
|
main: colors.secondary,
|
||||||
|
dark: colors.secondarydark,
|
||||||
|
},
|
||||||
|
error: {
|
||||||
|
light: colors.errorlight,
|
||||||
|
main: colors.error,
|
||||||
|
dark: colors.errordark,
|
||||||
|
},
|
||||||
|
info: {
|
||||||
|
light: colors.infolight,
|
||||||
|
main: colors.info,
|
||||||
|
dark: colors.infodark,
|
||||||
|
},
|
||||||
|
warning: {
|
||||||
|
light: colors.warninglight,
|
||||||
|
main: colors.warning,
|
||||||
|
dark: colors.warningdark,
|
||||||
|
},
|
||||||
|
background: {
|
||||||
|
default: colors.black,
|
||||||
|
paper: colors.well,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
error: {
|
typography: {
|
||||||
light: colors.errorlight,
|
fontFamily: "monospace",
|
||||||
main: colors.error,
|
button: {
|
||||||
dark: colors.errordark,
|
textTransform: "none",
|
||||||
|
},
|
||||||
},
|
},
|
||||||
info: {
|
components: {
|
||||||
light: colors.infolight,
|
MuiInputBase: {
|
||||||
main: colors.info,
|
styleOverrides: {
|
||||||
dark: colors.infodark,
|
root: {
|
||||||
},
|
backgroundColor: colors.well,
|
||||||
warning: {
|
color: colors.primary,
|
||||||
light: colors.warninglight,
|
},
|
||||||
main: colors.warning,
|
input: {
|
||||||
dark: colors.warningdark,
|
"&::placeholder": {
|
||||||
},
|
userSelect: "none",
|
||||||
background: {
|
color: colors.primarydark,
|
||||||
default: colors.black,
|
},
|
||||||
paper: colors.well,
|
},
|
||||||
},
|
|
||||||
},
|
|
||||||
typography: {
|
|
||||||
fontFamily: "monospace",
|
|
||||||
button: {
|
|
||||||
textTransform: "none",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
components: {
|
|
||||||
MuiInputBase: {
|
|
||||||
styleOverrides: {
|
|
||||||
root: {
|
|
||||||
backgroundColor: colors.well,
|
|
||||||
color: colors.primary,
|
|
||||||
},
|
},
|
||||||
input: {
|
},
|
||||||
"&::placeholder": {
|
|
||||||
|
MuiInput: {
|
||||||
|
styleOverrides: {
|
||||||
|
root: {
|
||||||
|
backgroundColor: colors.well,
|
||||||
|
borderBottomColor: "#fff",
|
||||||
|
},
|
||||||
|
underline: {
|
||||||
|
"&:hover": {
|
||||||
|
borderBottomColor: colors.primarydark,
|
||||||
|
},
|
||||||
|
"&:before": {
|
||||||
|
borderBottomColor: colors.primary,
|
||||||
|
},
|
||||||
|
"&:after": {
|
||||||
|
borderBottomColor: colors.primarylight,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
MuiInputLabel: {
|
||||||
|
styleOverrides: {
|
||||||
|
root: {
|
||||||
|
color: colors.primarydark, // why is this switched?
|
||||||
userSelect: "none",
|
userSelect: "none",
|
||||||
color: colors.primarydark,
|
"&:before": {
|
||||||
|
color: colors.primarylight,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
MuiButton: {
|
||||||
|
styleOverrides: {
|
||||||
|
root: {
|
||||||
|
backgroundColor: "#333",
|
||||||
|
border: "1px solid " + colors.well,
|
||||||
|
// color: colors.primary,
|
||||||
|
"&:hover": {
|
||||||
|
backgroundColor: colors.black,
|
||||||
|
},
|
||||||
|
|
||||||
MuiInput: {
|
borderRadius: 0,
|
||||||
styleOverrides: {
|
|
||||||
root: {
|
|
||||||
backgroundColor: colors.well,
|
|
||||||
borderBottomColor: "#fff",
|
|
||||||
},
|
|
||||||
underline: {
|
|
||||||
"&:hover": {
|
|
||||||
borderBottomColor: colors.primarydark,
|
|
||||||
},
|
|
||||||
"&:before": {
|
|
||||||
borderBottomColor: colors.primary,
|
|
||||||
},
|
|
||||||
"&:after": {
|
|
||||||
borderBottomColor: colors.primarylight,
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
MuiSelect: {
|
||||||
|
styleOverrides: {
|
||||||
MuiInputLabel: {
|
icon: {
|
||||||
styleOverrides: {
|
color: colors.primary,
|
||||||
root: {
|
|
||||||
color: colors.primarydark, // why is this switched?
|
|
||||||
userSelect: "none",
|
|
||||||
"&:before": {
|
|
||||||
color: colors.primarylight,
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
MuiMenu: {
|
||||||
MuiButton: {
|
styleOverrides: {
|
||||||
styleOverrides: {
|
list: {
|
||||||
root: {
|
backgroundColor: colors.well,
|
||||||
backgroundColor: "#333",
|
},
|
||||||
border: "1px solid " + colors.well,
|
},
|
||||||
// color: colors.primary,
|
},
|
||||||
margin: "5px",
|
MuiMenuItem: {
|
||||||
padding: "3px 5px",
|
styleOverrides: {
|
||||||
"&:hover": {
|
root: {
|
||||||
|
color: colors.primary,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
MuiAccordionSummary: {
|
||||||
|
styleOverrides: {
|
||||||
|
root: {
|
||||||
|
backgroundColor: "#111",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
MuiAccordionDetails: {
|
||||||
|
styleOverrides: {
|
||||||
|
root: {
|
||||||
backgroundColor: colors.black,
|
backgroundColor: colors.black,
|
||||||
},
|
},
|
||||||
|
|
||||||
borderRadius: 0,
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
MuiIconButton: {
|
||||||
MuiSelect: {
|
styleOverrides: {
|
||||||
styleOverrides: {
|
root: {
|
||||||
icon: {
|
color: colors.primary,
|
||||||
color: colors.primary,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
MuiMenu: {
|
|
||||||
styleOverrides: {
|
|
||||||
list: {
|
|
||||||
backgroundColor: colors.well,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
MuiMenuItem: {
|
|
||||||
styleOverrides: {
|
|
||||||
root: {
|
|
||||||
color: colors.primary,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
MuiAccordionSummary: {
|
|
||||||
styleOverrides: {
|
|
||||||
root: {
|
|
||||||
backgroundColor: "#111",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
MuiAccordionDetails: {
|
|
||||||
styleOverrides: {
|
|
||||||
root: {
|
|
||||||
backgroundColor: colors.black,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
MuiIconButton: {
|
|
||||||
styleOverrides: {
|
|
||||||
root: {
|
|
||||||
color: colors.primary,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
MuiTooltip: {
|
|
||||||
styleOverrides: {
|
|
||||||
tooltip: {
|
|
||||||
fontSize: "1em",
|
|
||||||
color: colors.primary,
|
|
||||||
backgroundColor: colors.well,
|
|
||||||
borderRadius: 0,
|
|
||||||
border: "2px solid white",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
MuiSlider: {
|
|
||||||
styleOverrides: {
|
|
||||||
valueLabel: {
|
|
||||||
color: colors.primary,
|
|
||||||
backgroundColor: colors.well,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
MuiDrawer: {
|
|
||||||
styleOverrides: {
|
|
||||||
paper: {
|
|
||||||
"&::-webkit-scrollbar": {
|
|
||||||
// webkit
|
|
||||||
display: "none",
|
|
||||||
},
|
},
|
||||||
scrollbarWidth: "none", // firefox
|
|
||||||
backgroundColor: colors.black,
|
|
||||||
},
|
},
|
||||||
paperAnchorDockedLeft: {
|
},
|
||||||
borderRight: "1px solid " + colors.welllight,
|
MuiTooltip: {
|
||||||
|
styleOverrides: {
|
||||||
|
tooltip: {
|
||||||
|
fontSize: "1em",
|
||||||
|
color: colors.primary,
|
||||||
|
backgroundColor: colors.well,
|
||||||
|
borderRadius: 0,
|
||||||
|
border: "2px solid white",
|
||||||
|
maxWidth: "100vh",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
MuiSlider: {
|
||||||
|
styleOverrides: {
|
||||||
|
valueLabel: {
|
||||||
|
color: colors.primary,
|
||||||
|
backgroundColor: colors.well,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
MuiDrawer: {
|
||||||
|
styleOverrides: {
|
||||||
|
paper: {
|
||||||
|
"&::-webkit-scrollbar": {
|
||||||
|
// webkit
|
||||||
|
display: "none",
|
||||||
|
},
|
||||||
|
scrollbarWidth: "none", // firefox
|
||||||
|
backgroundColor: colors.black,
|
||||||
|
},
|
||||||
|
paperAnchorDockedLeft: {
|
||||||
|
borderRight: "1px solid " + colors.welllight,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
MuiDivider: {
|
||||||
|
styleOverrides: {
|
||||||
|
root: {
|
||||||
|
backgroundColor: colors.welllight,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
MuiFormControlLabel: {
|
||||||
|
styleOverrides: {
|
||||||
|
root: {
|
||||||
|
color: colors.primary,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
MuiSwitch: {
|
||||||
|
styleOverrides: {
|
||||||
|
switchBase: {
|
||||||
|
color: colors.primarydark,
|
||||||
|
},
|
||||||
|
track: {
|
||||||
|
backgroundColor: colors.welllight,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
MuiPaper: {
|
||||||
|
styleOverrides: {
|
||||||
|
root: {
|
||||||
|
borderRadius: 0,
|
||||||
|
backgroundColor: colors.black,
|
||||||
|
border: "1px solid " + colors.welllight,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
MuiTablePagination: {
|
||||||
|
styleOverrides: {
|
||||||
|
select: {
|
||||||
|
color: colors.primary,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
MuiDivider: {
|
});
|
||||||
styleOverrides: {
|
console.log("refreshed");
|
||||||
root: {
|
}
|
||||||
backgroundColor: colors.welllight,
|
refreshTheme();
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
MuiFormControlLabel: {
|
|
||||||
styleOverrides: {
|
|
||||||
root: {
|
|
||||||
color: colors.primary,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
MuiSwitch: {
|
|
||||||
styleOverrides: {
|
|
||||||
switchBase: {
|
|
||||||
color: colors.primarydark,
|
|
||||||
},
|
|
||||||
track: {
|
|
||||||
backgroundColor: colors.welllight,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
MuiPaper: {
|
|
||||||
styleOverrides: {
|
|
||||||
root: {
|
|
||||||
borderRadius: 0,
|
|
||||||
backgroundColor: colors.black,
|
|
||||||
border: "1px solid " + colors.welllight,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
MuiTablePagination: {
|
|
||||||
styleOverrides: {
|
|
||||||
select: {
|
|
||||||
color: colors.primary,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
interface IProps {
|
interface IProps {
|
||||||
children: JSX.Element[] | JSX.Element;
|
children: JSX.Element[] | JSX.Element;
|
||||||
|
@ -32,11 +32,11 @@ export function WorkInProgressRoot(): React.ReactElement {
|
|||||||
const faction = Factions[player.currentWorkFactionName];
|
const faction = Factions[player.currentWorkFactionName];
|
||||||
if (player.workType == CONSTANTS.WorkTypeFaction) {
|
if (player.workType == CONSTANTS.WorkTypeFaction) {
|
||||||
function cancel(): void {
|
function cancel(): void {
|
||||||
router.toFaction();
|
router.toFaction(faction);
|
||||||
player.finishFactionWork(true);
|
player.finishFactionWork(true);
|
||||||
}
|
}
|
||||||
function unfocus(): void {
|
function unfocus(): void {
|
||||||
router.toFaction();
|
router.toFaction(faction);
|
||||||
player.stopFocusing();
|
player.stopFocusing();
|
||||||
}
|
}
|
||||||
return (
|
return (
|
||||||
|
@ -11,10 +11,6 @@
|
|||||||
* This formula ensures that the effects of the statistic that is being processed
|
* This formula ensures that the effects of the statistic that is being processed
|
||||||
* has diminishing returns, but never loses its effectiveness as you continue
|
* has diminishing returns, but never loses its effectiveness as you continue
|
||||||
* to raise it.
|
* to raise it.
|
||||||
*
|
|
||||||
* There are two implementations of this component. One is simply a function that
|
|
||||||
* can be called with the stat and the exponential/linear factors. The other is a
|
|
||||||
* class where the exponential and linear factors are defined upon construction.
|
|
||||||
*/
|
*/
|
||||||
export function calculateEffectWithFactors(n: number, expFac: number, linearFac: number): number {
|
export function calculateEffectWithFactors(n: number, expFac: number, linearFac: number): number {
|
||||||
if (expFac <= 0 || expFac >= 1) {
|
if (expFac <= 0 || expFac >= 1) {
|
||||||
@ -26,20 +22,3 @@ export function calculateEffectWithFactors(n: number, expFac: number, linearFac:
|
|||||||
|
|
||||||
return Math.pow(n, expFac) + n / linearFac;
|
return Math.pow(n, expFac) + n / linearFac;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class EffectWithFactors {
|
|
||||||
// Exponential factor
|
|
||||||
private expFac: number;
|
|
||||||
|
|
||||||
// Linear Factor
|
|
||||||
private linearFac: number;
|
|
||||||
|
|
||||||
constructor(expFac: number, linearFac: number) {
|
|
||||||
this.expFac = expFac;
|
|
||||||
this.linearFac = linearFac;
|
|
||||||
}
|
|
||||||
|
|
||||||
calculate(n: number): number {
|
|
||||||
return calculateEffectWithFactors(n, this.expFac, this.linearFac);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -6,6 +6,7 @@ const HtmlWebpackPlugin = require("html-webpack-plugin");
|
|||||||
const ForkTsCheckerWebpackPlugin = require("fork-ts-checker-webpack-plugin");
|
const ForkTsCheckerWebpackPlugin = require("fork-ts-checker-webpack-plugin");
|
||||||
const UnusedWebpackPlugin = require("unused-webpack-plugin");
|
const UnusedWebpackPlugin = require("unused-webpack-plugin");
|
||||||
const ReactRefreshWebpackPlugin = require("@pmmmwh/react-refresh-webpack-plugin");
|
const ReactRefreshWebpackPlugin = require("@pmmmwh/react-refresh-webpack-plugin");
|
||||||
|
const DeadCodePlugin = require("webpack-deadcode-plugin");
|
||||||
|
|
||||||
module.exports = (env, argv) => {
|
module.exports = (env, argv) => {
|
||||||
const isDevServer = (env || {}).devServer === true;
|
const isDevServer = (env || {}).devServer === true;
|
||||||
@ -130,6 +131,10 @@ module.exports = (env, argv) => {
|
|||||||
module: true,
|
module: true,
|
||||||
}),
|
}),
|
||||||
isDevelopment && new ReactRefreshWebpackPlugin(),
|
isDevelopment && new ReactRefreshWebpackPlugin(),
|
||||||
|
new DeadCodePlugin({
|
||||||
|
patterns: ["src/**/*.(js|jsx|css|ts|tsx)"],
|
||||||
|
exclude: ["**/*.(stories|spec).(js|jsx)"],
|
||||||
|
}),
|
||||||
].filter(Boolean),
|
].filter(Boolean),
|
||||||
target: "web",
|
target: "web",
|
||||||
entry: entry,
|
entry: entry,
|
||||||
|
Loading…
Reference in New Issue
Block a user