mirror of
https://github.com/bitburner-official/bitburner-src.git
synced 2024-11-27 18:13:52 +01:00
Merge pull request #1376 from danielyxie/dev
Almost everything in typescript.
This commit is contained in:
commit
b5c105b6fe
38
dist/vendor.bundle.js
vendored
38
dist/vendor.bundle.js
vendored
File diff suppressed because one or more lines are too long
@ -5,7 +5,7 @@ function createWindow() {
|
||||
const win = new BrowserWindow({
|
||||
show: false,
|
||||
webPreferences: {
|
||||
devTools: false,
|
||||
devTools: true,
|
||||
},
|
||||
});
|
||||
|
||||
@ -13,7 +13,7 @@ function createWindow() {
|
||||
win.maximize();
|
||||
win.loadFile("index.html");
|
||||
win.show();
|
||||
// win.webContents.openDevTools();
|
||||
win.webContents.openDevTools();
|
||||
globalShortcut.register("f5", function () {
|
||||
win.loadFile("index.html");
|
||||
});
|
||||
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
11
package-lock.json
generated
11
package-lock.json
generated
@ -16,6 +16,7 @@
|
||||
"@mui/lab": "^5.0.0-alpha.46",
|
||||
"@mui/material": "^5.0.0-rc.1",
|
||||
"@mui/styles": "^5.0.0-rc.1",
|
||||
"@types/escodegen": "^0.0.7",
|
||||
"@types/js-beautify": "^1.13.2",
|
||||
"@types/numeral": "0.0.25",
|
||||
"@types/react": "^17.0.21",
|
||||
@ -4522,6 +4523,11 @@
|
||||
"@babel/types": "^7.3.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/escodegen": {
|
||||
"version": "0.0.7",
|
||||
"resolved": "https://registry.npmjs.org/@types/escodegen/-/escodegen-0.0.7.tgz",
|
||||
"integrity": "sha512-46oENdSRNEJXCNrPJoC3vRolZJpfeEm7yvATkd2bCncKFG0PUEyfBCaoacfpcXH4Y5RRuqdVj3J7TI+wwn2SbQ=="
|
||||
},
|
||||
"node_modules/@types/file-saver": {
|
||||
"version": "2.0.3",
|
||||
"resolved": "https://registry.npmjs.org/@types/file-saver/-/file-saver-2.0.3.tgz",
|
||||
@ -31410,6 +31416,11 @@
|
||||
"@babel/types": "^7.3.0"
|
||||
}
|
||||
},
|
||||
"@types/escodegen": {
|
||||
"version": "0.0.7",
|
||||
"resolved": "https://registry.npmjs.org/@types/escodegen/-/escodegen-0.0.7.tgz",
|
||||
"integrity": "sha512-46oENdSRNEJXCNrPJoC3vRolZJpfeEm7yvATkd2bCncKFG0PUEyfBCaoacfpcXH4Y5RRuqdVj3J7TI+wwn2SbQ=="
|
||||
},
|
||||
"@types/file-saver": {
|
||||
"version": "2.0.3",
|
||||
"resolved": "https://registry.npmjs.org/@types/file-saver/-/file-saver-2.0.3.tgz",
|
||||
|
@ -17,6 +17,7 @@
|
||||
"@mui/lab": "^5.0.0-alpha.46",
|
||||
"@mui/material": "^5.0.0-rc.1",
|
||||
"@mui/styles": "^5.0.0-rc.1",
|
||||
"@types/escodegen": "^0.0.7",
|
||||
"@types/js-beautify": "^1.13.2",
|
||||
"@types/numeral": "0.0.25",
|
||||
"@types/react": "^17.0.21",
|
||||
|
@ -10,7 +10,7 @@ import { Money } from "../ui/React/Money";
|
||||
|
||||
import { Generic_fromJSON, Generic_toJSON, Reviver } from "../../utils/JSONReviver";
|
||||
|
||||
interface IConstructorParams {
|
||||
export interface IConstructorParams {
|
||||
info: string | JSX.Element;
|
||||
stats?: JSX.Element;
|
||||
isSpecial?: boolean;
|
||||
|
2
src/Augmentation/AugmentationHelpers.d.ts
vendored
2
src/Augmentation/AugmentationHelpers.d.ts
vendored
@ -1,2 +0,0 @@
|
||||
export declare function isRepeatableAug(aug: Augmentation): boolean;
|
||||
export declare function installAugmentations(): void;
|
@ -1,6 +1,6 @@
|
||||
import { Augmentation } from "./Augmentation";
|
||||
import { Augmentation, IConstructorParams } from "./Augmentation";
|
||||
import { Augmentations } from "./Augmentations";
|
||||
import { PlayerOwnedAugmentation } from "./PlayerOwnedAugmentation";
|
||||
import { PlayerOwnedAugmentation, IPlayerOwnedAugmentation } from "./PlayerOwnedAugmentation";
|
||||
import { AugmentationNames } from "./data/AugmentationNames";
|
||||
|
||||
import { BitNodeMultipliers } from "../BitNode/BitNodeMultipliers";
|
||||
@ -18,13 +18,13 @@ import { WHRNG } from "../Casino/RNG";
|
||||
|
||||
import React from "react";
|
||||
|
||||
function AddToAugmentations(aug) {
|
||||
var name = aug.name;
|
||||
function AddToAugmentations(aug: Augmentation): void {
|
||||
const name = aug.name;
|
||||
Augmentations[name] = aug;
|
||||
}
|
||||
|
||||
function getRandomBonus() {
|
||||
var bonuses = [
|
||||
function getRandomBonus(): any {
|
||||
const bonuses = [
|
||||
{
|
||||
bonuses: {
|
||||
hacking_chance_mult: 1.25,
|
||||
@ -124,7 +124,7 @@ function initAugmentations() {
|
||||
//Time-Based Augment Test
|
||||
const randomBonuses = getRandomBonus();
|
||||
|
||||
const UnstableCircadianModulatorParams = {
|
||||
const UnstableCircadianModulatorParams: IConstructorParams = {
|
||||
name: AugmentationNames.UnstableCircadianModulator,
|
||||
moneyCost: 5e9,
|
||||
repCost: 3.625e5,
|
||||
@ -133,7 +133,7 @@ function initAugmentations() {
|
||||
"unpredictable results based on your circadian rhythm.",
|
||||
};
|
||||
Object.keys(randomBonuses.bonuses).forEach(
|
||||
(key) => (UnstableCircadianModulatorParams[key] = randomBonuses.bonuses[key]),
|
||||
(key) => ((UnstableCircadianModulatorParams as any)[key] = randomBonuses.bonuses[key]),
|
||||
);
|
||||
const UnstableCircadianModulator = new Augmentation(UnstableCircadianModulatorParams);
|
||||
|
||||
@ -2359,7 +2359,7 @@ function initAugmentations() {
|
||||
}
|
||||
|
||||
//Resets an Augmentation during (re-initizliation)
|
||||
function resetAugmentation(newAugObject) {
|
||||
function resetAugmentation(newAugObject: Augmentation): void {
|
||||
if (!(newAugObject instanceof Augmentation)) {
|
||||
throw new Error("Invalid argument 'newAugObject' passed into resetAugmentation");
|
||||
}
|
||||
@ -2370,18 +2370,15 @@ function resetAugmentation(newAugObject) {
|
||||
AddToAugmentations(newAugObject);
|
||||
}
|
||||
|
||||
function applyAugmentation(aug, reapply = false) {
|
||||
function applyAugmentation(aug: IPlayerOwnedAugmentation, reapply = false): void {
|
||||
Augmentations[aug.name].owned = true;
|
||||
|
||||
const augObj = Augmentations[aug.name];
|
||||
|
||||
// Apply multipliers
|
||||
for (const mult in augObj.mults) {
|
||||
if (Player[mult] == null) {
|
||||
console.warn(`Augmentation has unrecognized multiplier property: ${mult}`);
|
||||
} else {
|
||||
Player[mult] *= augObj.mults[mult];
|
||||
}
|
||||
const v = Player.getMult(mult) * augObj.mults[mult];
|
||||
Player.setMult(mult, v);
|
||||
}
|
||||
|
||||
// Special logic for NeuroFlux Governor
|
||||
@ -2445,11 +2442,11 @@ function installAugmentations() {
|
||||
prestigeAugmentation();
|
||||
}
|
||||
|
||||
function augmentationExists(name) {
|
||||
function augmentationExists(name: string) {
|
||||
return Augmentations.hasOwnProperty(name);
|
||||
}
|
||||
|
||||
export function isRepeatableAug(aug) {
|
||||
export function isRepeatableAug(aug: Augmentation): boolean {
|
||||
const augName = aug instanceof Augmentation ? aug.name : aug;
|
||||
|
||||
if (augName === AugmentationNames.NeuroFluxGovernor) {
|
@ -6,13 +6,11 @@ import { AllPages } from "./AllPages";
|
||||
import { use } from "../../ui/Context";
|
||||
import { IBladeburner } from "../IBladeburner";
|
||||
|
||||
interface IProps {
|
||||
bladeburner: IBladeburner;
|
||||
}
|
||||
|
||||
export function BladeburnerRoot(props: IProps): React.ReactElement {
|
||||
export function BladeburnerRoot(): React.ReactElement {
|
||||
const player = use.Player();
|
||||
const router = use.Router();
|
||||
const bladeburner = player.bladeburner;
|
||||
if (bladeburner === null) return <></>;
|
||||
return (
|
||||
<div className="bladeburner-container">
|
||||
<div style={{ height: "60%", display: "block", position: "relative" }}>
|
||||
@ -24,9 +22,9 @@ export function BladeburnerRoot(props: IProps): React.ReactElement {
|
||||
border: "1px solid white",
|
||||
}}
|
||||
>
|
||||
<Stats bladeburner={props.bladeburner} player={player} router={router} />
|
||||
<Stats bladeburner={bladeburner} player={player} router={router} />
|
||||
</div>
|
||||
<Console bladeburner={props.bladeburner} player={player} />
|
||||
<Console bladeburner={bladeburner} player={player} />
|
||||
</div>
|
||||
<div
|
||||
style={{
|
||||
@ -38,7 +36,7 @@ export function BladeburnerRoot(props: IProps): React.ReactElement {
|
||||
position: "relative",
|
||||
}}
|
||||
>
|
||||
<AllPages bladeburner={props.bladeburner} player={player} />
|
||||
<AllPages bladeburner={bladeburner} player={player} />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
@ -10,6 +10,7 @@ import { ICorporation } from "../ICorporation";
|
||||
import { IPlayer } from "../../PersonObjects/IPlayer";
|
||||
import { MainPanel } from "./MainPanel";
|
||||
import { Industries } from "../IndustryData";
|
||||
import { use } from "../../ui/Context";
|
||||
|
||||
interface IExpandButtonProps {
|
||||
corp: ICorporation;
|
||||
@ -38,12 +39,10 @@ function ExpandButton(props: IExpandButtonProps): React.ReactElement {
|
||||
return <HeaderTab current={false} onClick={openNewIndustryPopup} text={"Expand into new Industry"} />;
|
||||
}
|
||||
|
||||
interface IProps {
|
||||
corp: ICorporation;
|
||||
player: IPlayer;
|
||||
}
|
||||
|
||||
export function CorporationRoot(props: IProps): React.ReactElement {
|
||||
export function CorporationRoot(): React.ReactElement {
|
||||
const player = use.Player();
|
||||
const corporation = player.corporation;
|
||||
if (corporation === null) return <></>;
|
||||
const setRerender = useState(false)[1];
|
||||
function rerender(): void {
|
||||
setRerender((old) => !old);
|
||||
@ -62,9 +61,9 @@ export function CorporationRoot(props: IProps): React.ReactElement {
|
||||
current={divisionName === "Overview"}
|
||||
key={"overview"}
|
||||
onClick={() => setDivisionName("Overview")}
|
||||
text={props.corp.name}
|
||||
text={corporation.name}
|
||||
/>
|
||||
{props.corp.divisions.map((division: IIndustry) => (
|
||||
{corporation.divisions.map((division: IIndustry) => (
|
||||
<HeaderTab
|
||||
current={division.name === divisionName}
|
||||
key={division.name}
|
||||
@ -72,9 +71,9 @@ export function CorporationRoot(props: IProps): React.ReactElement {
|
||||
text={division.name}
|
||||
/>
|
||||
))}
|
||||
<ExpandButton corp={props.corp} setDivisionName={setDivisionName} />
|
||||
<ExpandButton corp={corporation} setDivisionName={setDivisionName} />
|
||||
</div>
|
||||
<MainPanel rerender={rerender} corp={props.corp} divisionName={divisionName} player={props.player} />
|
||||
<MainPanel rerender={rerender} corp={corporation} divisionName={divisionName} player={player} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
@ -2,6 +2,7 @@ import { CONSTANTS } from "../Constants";
|
||||
import { IPlayer } from "../PersonObjects/IPlayer";
|
||||
import { IPlayerOrSleeve } from "../PersonObjects/IPlayerOrSleeve";
|
||||
import { IRouter } from "../ui/Router";
|
||||
import { WorkerScript } from "../Netscript/WorkerScript";
|
||||
|
||||
export interface IConstructorParams {
|
||||
hacking_success_weight?: number;
|
||||
@ -86,7 +87,7 @@ export class Crime {
|
||||
this.kills = params.kills ? params.kills : 0;
|
||||
}
|
||||
|
||||
commit(router: IRouter, p: IPlayer, div = 1, singParams: any = null): number {
|
||||
commit(router: IRouter, p: IPlayer, div = 1, workerScript: WorkerScript | null = null): number {
|
||||
if (div <= 0) {
|
||||
div = 1;
|
||||
}
|
||||
@ -101,7 +102,7 @@ export class Crime {
|
||||
this.charisma_exp / div,
|
||||
this.money / div,
|
||||
this.time,
|
||||
singParams,
|
||||
workerScript,
|
||||
);
|
||||
|
||||
return this.time;
|
||||
|
@ -14,7 +14,8 @@ export function checkIfConnectedToDarkweb(): void {
|
||||
if (!isValidIPAddress(darkwebIp)) {
|
||||
return;
|
||||
}
|
||||
if (darkwebIp == Player.getCurrentServer().ip) {
|
||||
const server = Player.getCurrentServer();
|
||||
if (server !== null && darkwebIp == server.ip) {
|
||||
Terminal.print(
|
||||
"You are now connected to the dark web. From the dark web you can purchase illegal items. " +
|
||||
"Use the 'buy -l' command to display a list of all the items you can buy. Use 'buy [item-name] " +
|
||||
|
@ -15,43 +15,42 @@ interface IProps {
|
||||
}
|
||||
|
||||
export function Bladeburner(props: IProps): React.ReactElement {
|
||||
const bladeburner = props.player.bladeburner;
|
||||
if (bladeburner === null) return <></>;
|
||||
function modifyBladeburnerRank(modify: number): (x: number) => void {
|
||||
return function (rank: number): void {
|
||||
if (props.player.bladeburner) {
|
||||
props.player.bladeburner.changeRank(props.player, rank * modify);
|
||||
}
|
||||
if (!bladeburner) return;
|
||||
bladeburner.changeRank(props.player, rank * modify);
|
||||
};
|
||||
}
|
||||
|
||||
function resetBladeburnerRank(): void {
|
||||
props.player.bladeburner.rank = 0;
|
||||
props.player.bladeburner.maxRank = 0;
|
||||
if (!bladeburner) return;
|
||||
bladeburner.rank = 0;
|
||||
bladeburner.maxRank = 0;
|
||||
}
|
||||
|
||||
function addTonsBladeburnerRank(): void {
|
||||
if (props.player.bladeburner) {
|
||||
props.player.bladeburner.changeRank(props.player, bigNumber);
|
||||
}
|
||||
if (!bladeburner) return;
|
||||
|
||||
bladeburner.changeRank(props.player, bigNumber);
|
||||
}
|
||||
|
||||
function modifyBladeburnerCycles(modify: number): (x: number) => void {
|
||||
return function (cycles: number): void {
|
||||
if (props.player.bladeburner) {
|
||||
props.player.bladeburner.storedCycles += cycles * modify;
|
||||
}
|
||||
if (!bladeburner) return;
|
||||
bladeburner.storedCycles += cycles * modify;
|
||||
};
|
||||
}
|
||||
|
||||
function resetBladeburnerCycles(): void {
|
||||
if (props.player.bladeburner) {
|
||||
props.player.bladeburner.storedCycles = 0;
|
||||
}
|
||||
if (!bladeburner) return;
|
||||
bladeburner.storedCycles = 0;
|
||||
}
|
||||
|
||||
function addTonsBladeburnerCycles(): void {
|
||||
if (props.player.bladeburner) {
|
||||
props.player.bladeburner.storedCycles += bigNumber;
|
||||
}
|
||||
if (!bladeburner) return;
|
||||
bladeburner.storedCycles += bigNumber;
|
||||
}
|
||||
|
||||
return (
|
||||
|
@ -35,6 +35,6 @@ export function ExploitName(exploit: string): string {
|
||||
return names[exploit];
|
||||
}
|
||||
|
||||
export function sanitizeExploits(exploits: string[]): string[] {
|
||||
return exploits.filter((e: string) => Object.keys(Exploit).includes(e));
|
||||
export function sanitizeExploits(exploits: Exploit[]): Exploit[] {
|
||||
return exploits.filter((e: Exploit) => Object.keys(Exploit).includes(e));
|
||||
}
|
||||
|
8
src/Faction/FactionHelpers.d.ts
vendored
8
src/Faction/FactionHelpers.d.ts
vendored
@ -1,8 +0,0 @@
|
||||
import { Augmentation } from "../Augmentation/Augmentation";
|
||||
import { Faction } from "../Faction/Faction";
|
||||
|
||||
export declare function getNextNeurofluxLevel(): number;
|
||||
export declare function hasAugmentationPrereqs(aug: Augmentation): boolean;
|
||||
export declare function purchaseAugmentation(aug: Augmentation, fac: Faction, sing?: boolean): void;
|
||||
export declare function joinFaction(faction: Faction): void;
|
||||
export declare function startHackingMission(faction: Faction): void;
|
@ -1,4 +1,5 @@
|
||||
import { Augmentations } from "../Augmentation/Augmentations";
|
||||
import { Augmentation } from "../Augmentation/Augmentation";
|
||||
import { PlayerOwnedAugmentation } from "../Augmentation/PlayerOwnedAugmentation";
|
||||
import { AugmentationNames } from "../Augmentation/data/AugmentationNames";
|
||||
import { BitNodeMultipliers } from "../BitNode/BitNodeMultipliers";
|
||||
@ -20,7 +21,7 @@ import { dialogBoxCreate } from "../../utils/DialogBox";
|
||||
import { createPopup } from "../ui/React/createPopup";
|
||||
import { InvitationPopup } from "./ui/InvitationPopup";
|
||||
|
||||
export function inviteToFaction(faction) {
|
||||
export function inviteToFaction(faction: Faction): void {
|
||||
Player.factionInvitations.push(faction.name);
|
||||
faction.alreadyInvited = true;
|
||||
if (!Settings.SuppressFactionInvites) {
|
||||
@ -33,7 +34,7 @@ export function inviteToFaction(faction) {
|
||||
}
|
||||
}
|
||||
|
||||
export function joinFaction(faction) {
|
||||
export function joinFaction(faction: Faction): void {
|
||||
if (faction.isMember) return;
|
||||
faction.isMember = true;
|
||||
Player.factions.push(faction.name);
|
||||
@ -54,7 +55,7 @@ export function joinFaction(faction) {
|
||||
}
|
||||
}
|
||||
|
||||
export function startHackingMission(faction) {
|
||||
export function startHackingMission(faction: Faction): void {
|
||||
const mission = new HackingMission(faction.playerReputation, faction);
|
||||
setInMission(true, mission); //Sets inMission flag to true
|
||||
mission.init();
|
||||
@ -62,7 +63,7 @@ export function startHackingMission(faction) {
|
||||
|
||||
//Returns a boolean indicating whether the player has the prerequisites for the
|
||||
//specified Augmentation
|
||||
export function hasAugmentationPrereqs(aug) {
|
||||
export function hasAugmentationPrereqs(aug: Augmentation): boolean {
|
||||
let hasPrereqs = true;
|
||||
if (aug.prereqs && aug.prereqs.length > 0) {
|
||||
for (let i = 0; i < aug.prereqs.length; ++i) {
|
||||
@ -88,7 +89,7 @@ export function hasAugmentationPrereqs(aug) {
|
||||
return hasPrereqs;
|
||||
}
|
||||
|
||||
export function purchaseAugmentation(aug, fac, sing = false) {
|
||||
export function purchaseAugmentation(aug: Augmentation, fac: Faction, sing = false): string {
|
||||
const factionInfo = fac.getInfo();
|
||||
var hasPrereqs = hasAugmentationPrereqs(aug);
|
||||
if (!hasPrereqs) {
|
||||
@ -111,13 +112,6 @@ export function purchaseAugmentation(aug, fac, sing = false) {
|
||||
}
|
||||
dialogBoxCreate(txt);
|
||||
} else if (aug.baseCost === 0 || Player.money.gte(aug.baseCost * factionInfo.augmentationPriceMult)) {
|
||||
if (Player.firstAugPurchased === false) {
|
||||
Player.firstAugPurchased = true;
|
||||
document.getElementById("augmentations-tab").style.display = "list-item";
|
||||
document.getElementById("character-menu-header").click();
|
||||
document.getElementById("character-menu-header").click();
|
||||
}
|
||||
|
||||
var queuedAugmentation = new PlayerOwnedAugmentation(aug.name);
|
||||
if (aug.name == AugmentationNames.NeuroFluxGovernor) {
|
||||
queuedAugmentation.level = getNextNeurofluxLevel();
|
||||
@ -166,9 +160,10 @@ export function purchaseAugmentation(aug, fac, sing = false) {
|
||||
"reproduce this.",
|
||||
);
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
export function getNextNeurofluxLevel() {
|
||||
export function getNextNeurofluxLevel(): number {
|
||||
// Get current Neuroflux level based on Player's augmentations
|
||||
let currLevel = 0;
|
||||
for (var i = 0; i < Player.augmentations.length; ++i) {
|
||||
@ -186,7 +181,7 @@ export function getNextNeurofluxLevel() {
|
||||
return currLevel + 1;
|
||||
}
|
||||
|
||||
export function processPassiveFactionRepGain(numCycles) {
|
||||
export function processPassiveFactionRepGain(numCycles: number): void {
|
||||
for (const name in Factions) {
|
||||
if (name === Player.currentWorkFactionName) continue;
|
||||
if (!Factions.hasOwnProperty(name)) continue;
|
2
src/Fconf/Fconf.d.ts
vendored
2
src/Fconf/Fconf.d.ts
vendored
@ -1,2 +0,0 @@
|
||||
export declare function parseFconfSettings(config: string): void;
|
||||
export declare function createFconf(): string;
|
@ -1,268 +0,0 @@
|
||||
import { FconfSettings } from "./FconfSettings";
|
||||
|
||||
import { parse, Node } from "acorn";
|
||||
import { dialogBoxCreate } from "../../utils/DialogBox";
|
||||
|
||||
var FconfComments = {
|
||||
ENABLE_BASH_HOTKEYS:
|
||||
"Improved Bash emulation mode. Setting this to 1 enables several\n" +
|
||||
"new Terminal shortcuts and features that more closely resemble\n" +
|
||||
"a real Bash-style shell. Note that when this mode is enabled,\n" +
|
||||
"the default browser shortcuts are overriden by the new Bash\n" +
|
||||
"shortcuts.\n\n" +
|
||||
"To see a full list of the Terminal shortcuts that this enables, see:\n" +
|
||||
"http://bitburner.readthedocs.io/en/latest/shortcuts.html",
|
||||
ENABLE_TIMESTAMPS:
|
||||
"Terminal commands and log entries will be timestamped. The timestamp\n" + "will have the format: M/D h:m",
|
||||
MAIN_MENU_STYLE:
|
||||
"Customize the main navigation menu on the left-hand side. Current options:\n\n" + "default, classic, compact",
|
||||
THEME_BACKGROUND_COLOR:
|
||||
"Sets the background color for not only the Terminal, but also for\n" +
|
||||
"most of the game's UI.\n\n" +
|
||||
"The color must be specified as a pound sign (#) followed by a \n" +
|
||||
"3-digit or 6-digit hex color code (e.g. #123456). Default color: #000000",
|
||||
THEME_FONT_COLOR:
|
||||
"Sets the font color for not only the Terminal, but also for\n" +
|
||||
"most of the game's UI.\n\n" +
|
||||
"The color must be specified as a pound sign (#) followed by a \n" +
|
||||
"3-digit or 6-digit hex color code (e.g. #123456). Default color: #66ff33",
|
||||
THEME_HIGHLIGHT_COLOR:
|
||||
"Sets the highlight color for not only the Terminal, but also for \n" +
|
||||
"most of the game's UI.\n\n" +
|
||||
"The color must be specified as a pound sign (#) followed by a \n" +
|
||||
"3-digit or 6-digit hex color code (e.g. #123456). Default color: #ffffff",
|
||||
THEME_PROMPT_COLOR:
|
||||
"Sets the prompt color in the Terminal\n\n" +
|
||||
"The color must be specified as a pound sign (#) followed by a \n" +
|
||||
"3-digit or 6-digit hex color code (e.g. #123456). Default color: #f92672",
|
||||
WRAP_INPUT:
|
||||
"Wrap Terminal Input. If this is enabled, then when a Terminal command is\n" +
|
||||
"too long and overflows, then it will wrap to the next line instead of\n" +
|
||||
"side-scrolling\n\n" +
|
||||
"Note that after you enable/disable this, you'll have to run a command\n" +
|
||||
"before its effect takes place.",
|
||||
};
|
||||
|
||||
const MainMenuStyleOptions = ["default", "classic", "compact"];
|
||||
|
||||
//Parse Fconf settings from the config text
|
||||
//Throws an exception if parsing fails
|
||||
function parseFconfSettings(config) {
|
||||
var ast = parse(config, { sourceType: "module" });
|
||||
var queue = [];
|
||||
queue.push(ast);
|
||||
while (queue.length != 0) {
|
||||
var exp = queue.shift();
|
||||
switch (exp.type) {
|
||||
case "BlockStatement":
|
||||
case "Program":
|
||||
for (var i = 0; i < exp.body.length; ++i) {
|
||||
if (exp.body[i] instanceof Node) {
|
||||
queue.push(exp.body[i]);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case "AssignmentExpression":
|
||||
var setting, value;
|
||||
if (exp.left != null && exp.left.name != null) {
|
||||
setting = exp.left.name;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
if (exp.right != null && exp.right.raw != null) {
|
||||
value = exp.right.raw;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
parseFconfSetting(setting, value);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
for (var prop in exp) {
|
||||
if (exp.hasOwnProperty(prop)) {
|
||||
if (exp[prop] instanceof Node) {
|
||||
queue.push(exp[prop]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
setTheme();
|
||||
setMainMenuStyle();
|
||||
}
|
||||
|
||||
function parseFconfSetting(setting, value) {
|
||||
setting = String(setting);
|
||||
value = String(value);
|
||||
if (setting == null || value == null || FconfSettings[setting] == null) {
|
||||
console.warn(`Invalid .fconf setting: ${setting}`);
|
||||
return;
|
||||
}
|
||||
|
||||
function sanitizeString(value) {
|
||||
value = value.toLowerCase();
|
||||
if (value.startsWith('"')) {
|
||||
value = value.slice(1);
|
||||
}
|
||||
if (value.endsWith('"')) {
|
||||
value = value.slice(0, -1);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
switch (setting) {
|
||||
case "ENABLE_BASH_HOTKEYS":
|
||||
case "ENABLE_TIMESTAMPS":
|
||||
case "WRAP_INPUT":
|
||||
// Need to convert entered value to boolean/strings accordingly
|
||||
var value = value.toLowerCase();
|
||||
if (value === "1" || value === "true" || value === "y") {
|
||||
value = true;
|
||||
} else {
|
||||
value = false;
|
||||
}
|
||||
FconfSettings[setting] = value;
|
||||
break;
|
||||
case "MAIN_MENU_STYLE":
|
||||
var value = sanitizeString(value);
|
||||
if (MainMenuStyleOptions.includes(value)) {
|
||||
FconfSettings[setting] = value;
|
||||
} else {
|
||||
dialogBoxCreate(`Invalid option specified for ${setting}. Options: ${MainMenuStyleOptions.toString()}`);
|
||||
}
|
||||
break;
|
||||
case "THEME_BACKGROUND_COLOR":
|
||||
case "THEME_FONT_COLOR":
|
||||
case "THEME_HIGHLIGHT_COLOR":
|
||||
case "THEME_PROMPT_COLOR":
|
||||
var value = sanitizeString(value);
|
||||
if (/(^#[0-9A-F]{6}$)|(^#[0-9A-F]{3}$)/i.test(value)) {
|
||||
FconfSettings[setting] = value;
|
||||
} else {
|
||||
dialogBoxCreate(`Invalid color specified for ${setting}. Must be a hex color code preceded by a pound (#)`);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//Create the .fconf file text from the settings
|
||||
function createFconf() {
|
||||
var res = "";
|
||||
for (var setting in FconfSettings) {
|
||||
if (FconfSettings.hasOwnProperty(setting)) {
|
||||
//Setting comments (description)
|
||||
var comment = FconfComments[setting];
|
||||
if (comment == null) {
|
||||
continue;
|
||||
}
|
||||
var comment = comment.split("\n");
|
||||
for (var i = 0; i < comment.length; ++i) {
|
||||
res += "//" + comment[i] + "\n";
|
||||
}
|
||||
|
||||
var value = 0;
|
||||
if (FconfSettings[setting] === true) {
|
||||
value = "1";
|
||||
} else if (FconfSettings[setting] === false) {
|
||||
value = "0";
|
||||
} else {
|
||||
value = '"' + String(FconfSettings[setting]) + '"';
|
||||
}
|
||||
res += `${setting} = ${value}\n\n`;
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
function loadFconf(saveString) {
|
||||
let tempFconfSettings = JSON.parse(saveString);
|
||||
for (var setting in tempFconfSettings) {
|
||||
if (tempFconfSettings.hasOwnProperty(setting)) {
|
||||
FconfSettings[setting] = tempFconfSettings[setting];
|
||||
}
|
||||
}
|
||||
|
||||
// Initialize themes/styles after loading
|
||||
setTheme();
|
||||
setMainMenuStyle();
|
||||
}
|
||||
|
||||
function setTheme() {
|
||||
if (
|
||||
FconfSettings.THEME_HIGHLIGHT_COLOR == null ||
|
||||
FconfSettings.THEME_FONT_COLOR == null ||
|
||||
FconfSettings.THEME_BACKGROUND_COLOR == null ||
|
||||
FconfSettings.THEME_PROMPT_COLOR == null
|
||||
) {
|
||||
console.error("Cannot find Theme Settings");
|
||||
return;
|
||||
}
|
||||
if (
|
||||
/^#[0-9a-f]{3}(?:[0-9a-f]{3})?$/i.test(FconfSettings.THEME_HIGHLIGHT_COLOR) &&
|
||||
/^#[0-9a-f]{3}(?:[0-9a-f]{3})?$/i.test(FconfSettings.THEME_FONT_COLOR) &&
|
||||
/^#[0-9a-f]{3}(?:[0-9a-f]{3})?$/i.test(FconfSettings.THEME_BACKGROUND_COLOR) &&
|
||||
/^#[0-9a-f]{3}(?:[0-9a-f]{3})?$/i.test(FconfSettings.THEME_PROMPT_COLOR)
|
||||
) {
|
||||
// document.body.style.setProperty("--my-highlight-color", FconfSettings.THEME_HIGHLIGHT_COLOR);
|
||||
// document.body.style.setProperty("--my-font-color", FconfSettings.THEME_FONT_COLOR);
|
||||
// document.body.style.setProperty("--my-background-color", FconfSettings.THEME_BACKGROUND_COLOR);
|
||||
// document.body.style.setProperty("--my-prompt-color", FconfSettings.THEME_PROMPT_COLOR);
|
||||
}
|
||||
}
|
||||
|
||||
function setMainMenuStyle() {
|
||||
const mainMenu = document.getElementById("mainmenu");
|
||||
const hackingMenuHdr = document.getElementById("hacking-menu-header");
|
||||
const characterMenuHdr = document.getElementById("character-menu-header");
|
||||
const worldMenuHdr = document.getElementById("world-menu-header");
|
||||
const helpMenuHdr = document.getElementById("help-menu-header");
|
||||
|
||||
function removeAllAccordionHeaderClasses() {
|
||||
hackingMenuHdr.classList.remove("mainmenu-accordion-header", "mainmenu-accordion-header-classic");
|
||||
characterMenuHdr.classList.remove("mainmenu-accordion-header", "mainmenu-accordion-header-classic");
|
||||
worldMenuHdr.classList.remove("mainmenu-accordion-header", "mainmenu-accordion-header-classic");
|
||||
helpMenuHdr.classList.remove("mainmenu-accordion-header", "mainmenu-accordion-header-classic");
|
||||
}
|
||||
|
||||
function addClassToAllAccordionHeaders(clsName) {
|
||||
hackingMenuHdr.classList.add(clsName);
|
||||
characterMenuHdr.classList.add(clsName);
|
||||
worldMenuHdr.classList.add(clsName);
|
||||
helpMenuHdr.classList.add(clsName);
|
||||
}
|
||||
|
||||
if (FconfSettings["MAIN_MENU_STYLE"] === "default") {
|
||||
removeAllAccordionHeaderClasses();
|
||||
mainMenu.classList.remove("classic");
|
||||
mainMenu.classList.remove("compact");
|
||||
addClassToAllAccordionHeaders("mainmenu-accordion-header");
|
||||
} else if (FconfSettings["MAIN_MENU_STYLE"] === "classic") {
|
||||
removeAllAccordionHeaderClasses();
|
||||
mainMenu.classList.remove("compact");
|
||||
mainMenu.classList.add("classic");
|
||||
addClassToAllAccordionHeaders("mainmenu-accordion-header-classic");
|
||||
} else if (FconfSettings["MAIN_MENU_STYLE"] === "compact") {
|
||||
removeAllAccordionHeaderClasses();
|
||||
mainMenu.classList.remove("classic");
|
||||
mainMenu.classList.add("compact");
|
||||
addClassToAllAccordionHeaders("mainmenu-accordion-header-compact");
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
|
||||
// Click each header twice to reset lol
|
||||
hackingMenuHdr.click();
|
||||
hackingMenuHdr.click();
|
||||
characterMenuHdr.click();
|
||||
characterMenuHdr.click();
|
||||
worldMenuHdr.click();
|
||||
worldMenuHdr.click();
|
||||
helpMenuHdr.click();
|
||||
helpMenuHdr.click();
|
||||
}
|
||||
|
||||
export { FconfSettings, createFconf, parseFconfSettings, loadFconf };
|
@ -1,10 +0,0 @@
|
||||
export const FconfSettings = {
|
||||
ENABLE_BASH_HOTKEYS: false,
|
||||
ENABLE_TIMESTAMPS: false,
|
||||
MAIN_MENU_STYLE: "default",
|
||||
THEME_BACKGROUND_COLOR: "#000000",
|
||||
THEME_FONT_COLOR: "#66ff33",
|
||||
THEME_HIGHLIGHT_COLOR: "#ffffff",
|
||||
THEME_PROMPT_COLOR: "#f92672",
|
||||
WRAP_INPUT: false,
|
||||
};
|
@ -8,13 +8,13 @@ import { use } from "../../ui/Context";
|
||||
import { Factions } from "../../Faction/Factions";
|
||||
import { Gang } from "../Gang";
|
||||
|
||||
interface IProps {
|
||||
gang: Gang;
|
||||
}
|
||||
|
||||
export function GangRoot(props: IProps): React.ReactElement {
|
||||
export function GangRoot(): React.ReactElement {
|
||||
const player = use.Player();
|
||||
const router = use.Router();
|
||||
const gang = (function () {
|
||||
if (player.gang === null) throw new Error("Gang should not be null");
|
||||
return player.gang;
|
||||
})();
|
||||
const [management, setManagement] = useState(true);
|
||||
const setRerender = useState(false)[1];
|
||||
|
||||
@ -24,7 +24,7 @@ export function GangRoot(props: IProps): React.ReactElement {
|
||||
}, []);
|
||||
|
||||
function back(): void {
|
||||
router.toFaction(Factions[props.gang.facName]);
|
||||
router.toFaction(Factions[gang.facName]);
|
||||
}
|
||||
|
||||
return (
|
||||
@ -46,7 +46,7 @@ export function GangRoot(props: IProps): React.ReactElement {
|
||||
>
|
||||
Gang Territory
|
||||
</a>
|
||||
{management ? <ManagementSubpage gang={props.gang} player={player} /> : <TerritorySubpage gang={props.gang} />}
|
||||
{management ? <ManagementSubpage gang={gang} player={player} /> : <TerritorySubpage gang={gang} />}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
@ -479,13 +479,12 @@ export function purchaseHashUpgrade(player: IPlayer, upgName: string, upgTarget:
|
||||
break;
|
||||
}
|
||||
case "Sell for Corporation Funds": {
|
||||
// This will throw if player doesn't have a corporation
|
||||
try {
|
||||
player.corporation.funds = player.corporation.funds.plus(upg.value);
|
||||
} catch (e) {
|
||||
const corp = player.corporation;
|
||||
if (corp === null) {
|
||||
player.hashManager.refundUpgrade(upgName);
|
||||
return false;
|
||||
}
|
||||
corp.funds = corp.funds.plus(upg.value);
|
||||
break;
|
||||
}
|
||||
case "Reduce Minimum Security": {
|
||||
@ -530,36 +529,35 @@ export function purchaseHashUpgrade(player: IPlayer, upgName: string, upgTarget:
|
||||
}
|
||||
case "Exchange for Corporation Research": {
|
||||
// This will throw if player doesn't have a corporation
|
||||
try {
|
||||
for (const division of player.corporation.divisions) {
|
||||
division.sciResearch.qty += upg.value;
|
||||
}
|
||||
} catch (e) {
|
||||
const corp = player.corporation;
|
||||
if (corp === null) {
|
||||
player.hashManager.refundUpgrade(upgName);
|
||||
return false;
|
||||
}
|
||||
for (const division of corp.divisions) {
|
||||
division.sciResearch.qty += upg.value;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case "Exchange for Bladeburner Rank": {
|
||||
// This will throw if player isnt in Bladeburner
|
||||
try {
|
||||
player.bladeburner.changeRank(player, upg.value);
|
||||
} catch (e) {
|
||||
const bladeburner = player.bladeburner;
|
||||
if (bladeburner === null) {
|
||||
player.hashManager.refundUpgrade(upgName);
|
||||
return false;
|
||||
}
|
||||
bladeburner.changeRank(player, upg.value);
|
||||
break;
|
||||
}
|
||||
case "Exchange for Bladeburner SP": {
|
||||
// This will throw if player isn't in Bladeburner
|
||||
try {
|
||||
// As long as we don't change `Bladeburner.totalSkillPoints`, this
|
||||
// shouldn't affect anything else
|
||||
player.bladeburner.skillPoints += upg.value;
|
||||
} catch (e) {
|
||||
// This will throw if player isnt in Bladeburner
|
||||
const bladeburner = player.bladeburner;
|
||||
if (bladeburner === null) {
|
||||
player.hashManager.refundUpgrade(upgName);
|
||||
return false;
|
||||
}
|
||||
|
||||
bladeburner.skillPoints += upg.value;
|
||||
break;
|
||||
}
|
||||
case "Generate Coding Contract": {
|
||||
|
@ -3,32 +3,25 @@
|
||||
* to TypeScript at the moment
|
||||
*/
|
||||
export interface IEngine {
|
||||
indexedDb: any;
|
||||
_lastUpdate: number;
|
||||
hideAllContent: () => void;
|
||||
loadTerminalContent: () => void;
|
||||
loadScriptEditorContent: (filename?: string, code?: string) => void;
|
||||
loadActiveScriptsContent: () => void;
|
||||
loadCreateProgramContent: () => void;
|
||||
loadCharacterContent: () => void;
|
||||
loadFactionsContent: () => void;
|
||||
loadAugmentationsContent: () => void;
|
||||
loadHacknetNodesContent: () => void;
|
||||
loadSleevesContent: () => void;
|
||||
loadLocationContent: () => void;
|
||||
loadTravelContent: () => void;
|
||||
loadJobContent: () => void;
|
||||
loadStockMarketContent: () => void;
|
||||
loadBladeburnerContent: () => void;
|
||||
loadCorporationContent: () => void;
|
||||
loadGangContent: () => void;
|
||||
loadMilestonesContent: () => void;
|
||||
loadTutorialContent: () => void;
|
||||
loadDevMenuContent: () => void;
|
||||
loadFactionContent: () => void;
|
||||
loadInfiltrationContent: (name: string, difficulty: number, maxLevel: number) => void;
|
||||
loadMissionContent: () => void;
|
||||
loadResleevingContent: () => void;
|
||||
loadGameOptionsContent: () => void;
|
||||
load: (save: string) => void;
|
||||
updateGame: (numCycles?: number) => void;
|
||||
Counters: {
|
||||
[key: string]: number | undefined;
|
||||
autoSaveCounter: number;
|
||||
updateSkillLevelsCounter: number;
|
||||
updateDisplays: number;
|
||||
updateDisplaysLong: number;
|
||||
updateActiveScriptsDisplay: number;
|
||||
createProgramNotifications: number;
|
||||
augmentationsNotifications: number;
|
||||
checkFactionInvitations: number;
|
||||
passiveFactionGrowth: number;
|
||||
messages: number;
|
||||
mechanicProcess: number;
|
||||
contractGeneration: number;
|
||||
};
|
||||
decrementAllCounters: (numCycles?: number) => void;
|
||||
checkCounters: () => void;
|
||||
load: (saveString: string) => void;
|
||||
start: () => void;
|
||||
}
|
||||
|
1
src/Message/MessageHelpers.d.ts
vendored
1
src/Message/MessageHelpers.d.ts
vendored
@ -1 +0,0 @@
|
||||
export declare function showMessage(msg: Message): void;
|
@ -11,7 +11,7 @@ import { dialogBoxCreate } from "../../utils/DialogBox";
|
||||
import { Reviver } from "../../utils/JSONReviver";
|
||||
|
||||
//Sends message to player, including a pop up
|
||||
function sendMessage(msg, forced = false) {
|
||||
function sendMessage(msg: Message, forced = false): void {
|
||||
msg.recvd = true;
|
||||
if (forced || !Settings.SuppressMessages) {
|
||||
showMessage(msg);
|
||||
@ -19,7 +19,7 @@ function sendMessage(msg, forced = false) {
|
||||
addMessageToServer(msg, "home");
|
||||
}
|
||||
|
||||
function showMessage(msg) {
|
||||
function showMessage(msg: Message): void {
|
||||
var txt =
|
||||
"Message received from unknown sender: <br><br>" +
|
||||
"<i>" +
|
||||
@ -32,14 +32,16 @@ function showMessage(msg) {
|
||||
}
|
||||
|
||||
//Adds a message to a server
|
||||
function addMessageToServer(msg, serverHostname) {
|
||||
function addMessageToServer(msg: Message, serverHostname: string): void {
|
||||
var server = GetServerByHostname(serverHostname);
|
||||
if (server == null) {
|
||||
console.warn(`Could not find server ${serverHostname}`);
|
||||
return;
|
||||
}
|
||||
for (var i = 0; i < server.messages.length; ++i) {
|
||||
if (server.messages[i].filename === msg.filename) {
|
||||
const msg = server.messages[i];
|
||||
if (typeof msg === "string") continue;
|
||||
if (msg.filename === msg.filename) {
|
||||
return; //Already exists
|
||||
}
|
||||
}
|
||||
@ -95,13 +97,13 @@ function checkForMessagesToSend() {
|
||||
}
|
||||
}
|
||||
|
||||
function AddToAllMessages(msg) {
|
||||
function AddToAllMessages(msg: Message): void {
|
||||
Messages[msg.filename] = msg;
|
||||
}
|
||||
|
||||
let Messages = {};
|
||||
let Messages: { [key: string]: Message | undefined } = {};
|
||||
|
||||
function loadMessages(saveString) {
|
||||
function loadMessages(saveString: string): void {
|
||||
Messages = JSON.parse(saveString, Reviver);
|
||||
}
|
||||
|
7
src/Missions.d.ts
vendored
7
src/Missions.d.ts
vendored
@ -1 +1,8 @@
|
||||
export declare let inMission: boolean;
|
||||
export declare class HackingMission {
|
||||
constructor(reputation: number, faction: Faction);
|
||||
init(): void;
|
||||
process(numCycles: number): void;
|
||||
}
|
||||
export declare function setInMission(inMission: boolean, mission: HackingMission): void;
|
||||
export declare let currMission: HackingMission;
|
||||
|
@ -68,7 +68,7 @@ export class WorkerScript {
|
||||
* Used for static RAM calculation. Stores names of all functions that have
|
||||
* already been checked by this script
|
||||
*/
|
||||
loadedFns: IMap<string> = {};
|
||||
loadedFns: IMap<boolean> = {};
|
||||
|
||||
/**
|
||||
* Filename of script
|
||||
|
@ -2,8 +2,9 @@ import { setTimeoutRef } from "./utils/SetTimeoutRef";
|
||||
|
||||
import { isString } from "../utils/helpers/isString";
|
||||
import { AllServers } from "./Server/AllServers";
|
||||
import { WorkerScript } from "./Netscript/WorkerScript";
|
||||
|
||||
export function netscriptDelay(time, workerScript) {
|
||||
export function netscriptDelay(time: number, workerScript: WorkerScript): Promise<void> {
|
||||
return new Promise(function (resolve) {
|
||||
workerScript.delay = setTimeoutRef(() => {
|
||||
workerScript.delay = null;
|
||||
@ -13,7 +14,7 @@ export function netscriptDelay(time, workerScript) {
|
||||
});
|
||||
}
|
||||
|
||||
export function makeRuntimeRejectMsg(workerScript, msg, exp = null) {
|
||||
export function makeRuntimeRejectMsg(workerScript: WorkerScript, msg: string, exp: any = null) {
|
||||
var lineNum = "";
|
||||
if (exp != null) {
|
||||
var num = getErrorLineNumber(exp, workerScript);
|
||||
@ -21,13 +22,17 @@ export function makeRuntimeRejectMsg(workerScript, msg, exp = null) {
|
||||
}
|
||||
const server = AllServers[workerScript.serverIp];
|
||||
if (server == null) {
|
||||
throw new Error(`WorkerScript constructed with invalid server ip: ${this.serverIp}`);
|
||||
throw new Error(`WorkerScript constructed with invalid server ip: ${workerScript.serverIp}`);
|
||||
}
|
||||
|
||||
return "|" + server.hostname + "|" + workerScript.name + "|" + msg + lineNum;
|
||||
}
|
||||
|
||||
export function resolveNetscriptRequestedThreads(workerScript, functionName, requestedThreads) {
|
||||
export function resolveNetscriptRequestedThreads(
|
||||
workerScript: WorkerScript,
|
||||
functionName: string,
|
||||
requestedThreads: number,
|
||||
) {
|
||||
const threads = workerScript.scriptRef.threads;
|
||||
if (!requestedThreads) {
|
||||
return isNaN(threads) || threads < 1 ? 1 : threads;
|
||||
@ -48,19 +53,22 @@ export function resolveNetscriptRequestedThreads(workerScript, functionName, req
|
||||
return requestedThreadsAsInt;
|
||||
}
|
||||
|
||||
export function getErrorLineNumber(exp, workerScript) {
|
||||
var code = workerScript.scriptRef.codeCode();
|
||||
export function getErrorLineNumber(exp: any, workerScript: WorkerScript): number {
|
||||
return -1;
|
||||
// TODO wtf is codeCode?
|
||||
|
||||
//Split code up to the start of the node
|
||||
try {
|
||||
code = code.substring(0, exp.start);
|
||||
return (code.match(/\n/g) || []).length + 1;
|
||||
} catch (e) {
|
||||
return -1;
|
||||
}
|
||||
// var code = workerScript.scriptRef.codeCode();
|
||||
|
||||
// //Split code up to the start of the node
|
||||
// try {
|
||||
// code = code.substring(0, exp.start);
|
||||
// return (code.match(/\n/g) || []).length + 1;
|
||||
// } catch (e) {
|
||||
// return -1;
|
||||
// }
|
||||
}
|
||||
|
||||
export function isScriptErrorMessage(msg) {
|
||||
export function isScriptErrorMessage(msg: string): boolean {
|
||||
if (!isString(msg)) {
|
||||
return false;
|
||||
}
|
@ -103,7 +103,8 @@ import { Player } from "./Player";
|
||||
import { Programs } from "./Programs/Programs";
|
||||
import { Script } from "./Script/Script";
|
||||
import { findRunningScript, findRunningScriptByPid } from "./Script/ScriptHelpers";
|
||||
import { isScriptFilename } from "./Script/ScriptHelpersTS";
|
||||
import { isScriptFilename } from "./Script/isScriptFilename";
|
||||
|
||||
import { AllServers, AddToAllServers, createUniqueRandomIp } from "./Server/AllServers";
|
||||
import { RunningScript } from "./Script/RunningScript";
|
||||
import {
|
||||
@ -132,7 +133,7 @@ import { NetscriptPorts, runScriptFromScript, startWorkerScript } from "./Netscr
|
||||
import { killWorkerScript } from "./Netscript/killWorkerScript";
|
||||
import { workerScripts } from "./Netscript/WorkerScripts";
|
||||
import { makeRuntimeRejectMsg, netscriptDelay, resolveNetscriptRequestedThreads } from "./NetscriptEvaluator";
|
||||
import { Interpreter } from "./JSInterpreter";
|
||||
import { Interpreter } from "./ThirdParty/JSInterpreter";
|
||||
import { NetscriptPort } from "./NetscriptPort";
|
||||
import { SleeveTaskType } from "./PersonObjects/Sleeve/SleeveTaskTypesEnum";
|
||||
import { findSleevePurchasableAugs } from "./PersonObjects/Sleeve/SleeveHelpers";
|
||||
@ -3808,7 +3809,7 @@ function NetscriptFunctions(workerScript) {
|
||||
throw makeRuntimeErrorMsg("commitCrime", `Invalid crime: '${crimeRoughName}'`);
|
||||
}
|
||||
workerScript.log("commitCrime", `Attempting to commit ${crime.name}...`);
|
||||
return crime.commit(Router, Player, 1, { workerscript: workerScript });
|
||||
return crime.commit(Router, Player, 1, workerScript);
|
||||
},
|
||||
getCrimeChance: function (crimeRoughName) {
|
||||
updateDynamicRam("getCrimeChance", getRamCost("getCrimeChance"));
|
||||
|
@ -1,8 +1,10 @@
|
||||
import { makeRuntimeRejectMsg } from "./NetscriptEvaluator";
|
||||
import { ScriptUrl } from "./Script/ScriptUrl";
|
||||
import { WorkerScript } from "./Netscript/WorkerScript";
|
||||
import { Script } from "./Script/Script";
|
||||
|
||||
// Makes a blob that contains the code of a given script.
|
||||
function makeScriptBlob(code) {
|
||||
function makeScriptBlob(code: string): Blob {
|
||||
return new Blob([code], { type: "text/javascript" });
|
||||
}
|
||||
|
||||
@ -14,10 +16,11 @@ function makeScriptBlob(code) {
|
||||
// (i.e. hack, grow, etc.).
|
||||
// When the promise returned by this resolves, we'll have finished
|
||||
// running the main function of the script.
|
||||
export async function executeJSScript(scripts = [], workerScript) {
|
||||
export async function executeJSScript(scripts: Script[] = [], workerScript: WorkerScript) {
|
||||
let loadedModule;
|
||||
let urls = null;
|
||||
let uurls: ScriptUrl[] = [];
|
||||
let script = workerScript.getScript();
|
||||
if (script === null) throw new Error("script is null");
|
||||
if (shouldCompile(script, scripts)) {
|
||||
// The URL at the top is the one we want to import. It will
|
||||
// recursively import all the other modules in the urlStack.
|
||||
@ -27,31 +30,24 @@ export async function executeJSScript(scripts = [], workerScript) {
|
||||
// load fully dynamic content. So we hide the import from webpack
|
||||
// by placing it inside an eval call.
|
||||
script.markUpdated();
|
||||
urls = _getScriptUrls(script, scripts, []);
|
||||
script.url = urls[urls.length - 1].url;
|
||||
script.module = new Promise((resolve) => resolve(eval("import(urls[urls.length - 1].url)")));
|
||||
script.dependencies = urls;
|
||||
uurls = _getScriptUrls(script, scripts, []);
|
||||
script.url = uurls[uurls.length - 1].url;
|
||||
script.module = new Promise((resolve) => resolve(eval("import(uurls[uurls.length - 1].url)")));
|
||||
script.dependencies = uurls;
|
||||
}
|
||||
loadedModule = await script.module;
|
||||
|
||||
let ns = workerScript.env.vars;
|
||||
|
||||
try {
|
||||
// TODO: putting await in a non-async function yields unhelpful
|
||||
// "SyntaxError: unexpected reserved word" with no line number information.
|
||||
if (!loadedModule.main) {
|
||||
throw makeRuntimeRejectMsg(
|
||||
workerScript,
|
||||
`${script.filename} cannot be run because it does not have a main function.`,
|
||||
);
|
||||
}
|
||||
return loadedModule.main(ns);
|
||||
} finally {
|
||||
// Revoke the generated URLs
|
||||
if (urls != null) {
|
||||
for (const b in urls) URL.revokeObjectURL(b.url);
|
||||
}
|
||||
// TODO: putting await in a non-async function yields unhelpful
|
||||
// "SyntaxError: unexpected reserved word" with no line number information.
|
||||
if (!loadedModule.main) {
|
||||
throw makeRuntimeRejectMsg(
|
||||
workerScript,
|
||||
`${script.filename} cannot be run because it does not have a main function.`,
|
||||
);
|
||||
}
|
||||
return loadedModule.main(ns);
|
||||
}
|
||||
|
||||
/** Returns whether we should compile the script parameter.
|
||||
@ -59,7 +55,7 @@ export async function executeJSScript(scripts = [], workerScript) {
|
||||
* @param {Script} script
|
||||
* @param {Script[]} scripts
|
||||
*/
|
||||
function shouldCompile(script, scripts) {
|
||||
function shouldCompile(script: Script, scripts: Script[]): boolean {
|
||||
if (script.module === "") return true;
|
||||
return script.dependencies.some((dep) => {
|
||||
const depScript = scripts.find((s) => s.filename == dep.filename);
|
||||
@ -93,7 +89,7 @@ function shouldCompile(script, scripts) {
|
||||
* the script parameter.
|
||||
*/
|
||||
// BUG: apparently seen is never consulted. Oops.
|
||||
function _getScriptUrls(script, scripts, seen) {
|
||||
function _getScriptUrls(script: Script, scripts: Script[], seen: Script[]): ScriptUrl[] {
|
||||
// Inspired by: https://stackoverflow.com/a/43834063/91401
|
||||
/** @type {ScriptUrl[]} */
|
||||
const urlStack = [];
|
@ -1,6 +1,14 @@
|
||||
import { Settings } from "./Settings/Settings";
|
||||
|
||||
interface IPort {}
|
||||
export interface IPort {
|
||||
write: (value: any) => any;
|
||||
tryWrite: (value: any) => boolean;
|
||||
read: () => any;
|
||||
peek: () => any;
|
||||
full: () => boolean;
|
||||
empty: () => boolean;
|
||||
clear: () => void;
|
||||
}
|
||||
|
||||
export function NetscriptPort(): IPort {
|
||||
const data: any[] = [];
|
||||
|
1
src/NetscriptWorker.d.ts
vendored
1
src/NetscriptWorker.d.ts
vendored
@ -1 +0,0 @@
|
||||
export declare function startWorkerScript(script: RunningScript, server: BaseServer): boolean;
|
@ -9,16 +9,19 @@ import { WorkerScriptStartStopEventEmitter } from "./Netscript/WorkerScriptStart
|
||||
import { generateNextPid } from "./Netscript/Pid";
|
||||
|
||||
import { CONSTANTS } from "./Constants";
|
||||
import { Interpreter } from "./JSInterpreter";
|
||||
import { Interpreter } from "./ThirdParty/JSInterpreter";
|
||||
import { isScriptErrorMessage, makeRuntimeRejectMsg } from "./NetscriptEvaluator";
|
||||
import { NetscriptFunctions } from "./NetscriptFunctions";
|
||||
import { executeJSScript } from "./NetscriptJSEvaluator";
|
||||
import { NetscriptPort } from "./NetscriptPort";
|
||||
import { NetscriptPort, IPort } from "./NetscriptPort";
|
||||
import { Player } from "./Player";
|
||||
import { RunningScript } from "./Script/RunningScript";
|
||||
import { getRamUsageFromRunningScript } from "./Script/RunningScriptHelpers";
|
||||
import { scriptCalculateOfflineProduction } from "./Script/ScriptHelpers";
|
||||
import { Script } from "./Script/Script";
|
||||
import { AllServers } from "./Server/AllServers";
|
||||
import { Server } from "./Server/Server";
|
||||
import { BaseServer } from "./Server/BaseServer";
|
||||
import { Settings } from "./Settings/Settings";
|
||||
import { setTimeoutRef } from "./utils/SetTimeoutRef";
|
||||
|
||||
@ -28,12 +31,13 @@ import { dialogBoxCreate } from "../utils/DialogBox";
|
||||
import { arrayToString } from "../utils/helpers/arrayToString";
|
||||
import { roundToTwo } from "../utils/helpers/roundToTwo";
|
||||
import { isString } from "../utils/helpers/isString";
|
||||
import { sprintf } from "sprintf-js";
|
||||
|
||||
import { parse } from "acorn";
|
||||
import { simple as walksimple } from "acorn-walk";
|
||||
|
||||
// Netscript Ports are instantiated here
|
||||
export const NetscriptPorts = [];
|
||||
export const NetscriptPorts: IPort[] = [];
|
||||
for (var i = 0; i < CONSTANTS.NumNetscriptPorts; ++i) {
|
||||
NetscriptPorts.push(NetscriptPort());
|
||||
}
|
||||
@ -51,20 +55,20 @@ export function prestigeWorkerScripts() {
|
||||
// JS script promises need a little massaging to have the same guarantees as netscript
|
||||
// promises. This does said massaging and kicks the script off. It returns a promise
|
||||
// that resolves or rejects when the corresponding worker script is done.
|
||||
function startNetscript2Script(workerScript) {
|
||||
function startNetscript2Script(workerScript: WorkerScript): Promise<WorkerScript> {
|
||||
workerScript.running = true;
|
||||
|
||||
// The name of the currently running netscript function, to prevent concurrent
|
||||
// calls to hack, grow, etc.
|
||||
let runningFn = null;
|
||||
let runningFn: string | null = null;
|
||||
|
||||
// We need to go through the environment and wrap each function in such a way that it
|
||||
// can be called at most once at a time. This will prevent situations where multiple
|
||||
// hack promises are outstanding, for example.
|
||||
function wrap(propName, f) {
|
||||
function wrap(propName: string, f: Function): Function {
|
||||
// This function unfortunately cannot be an async function, because we don't
|
||||
// know if the original one was, and there's no way to tell.
|
||||
return function (...args) {
|
||||
return function (...args: any[]) {
|
||||
// Wrap every netscript function with a check for the stop flag.
|
||||
// This prevents cases where we never stop because we are only calling
|
||||
// netscript functions that don't check this.
|
||||
@ -115,27 +119,28 @@ function startNetscript2Script(workerScript) {
|
||||
|
||||
// Note: the environment that we pass to the JS script only needs to contain the functions visible
|
||||
// to that script, which env.vars does at this point.
|
||||
return executeJSScript(workerScript.getServer().scripts, workerScript)
|
||||
.then(function (mainReturnValue) {
|
||||
if (mainReturnValue === undefined) return workerScript;
|
||||
return [mainReturnValue, workerScript];
|
||||
})
|
||||
.catch((e) => {
|
||||
if (e instanceof Error) {
|
||||
workerScript.errorMessage = makeRuntimeRejectMsg(
|
||||
workerScript,
|
||||
e.message + ((e.stack && "\nstack:\n" + e.stack.toString()) || ""),
|
||||
);
|
||||
throw workerScript;
|
||||
} else if (isScriptErrorMessage(e)) {
|
||||
workerScript.errorMessage = e;
|
||||
throw workerScript;
|
||||
}
|
||||
throw e; // Don't know what to do with it, let's rethrow.
|
||||
});
|
||||
return new Promise<WorkerScript>((resolve, reject) => {
|
||||
executeJSScript(workerScript.getServer().scripts, workerScript)
|
||||
.then(() => {
|
||||
resolve(workerScript);
|
||||
})
|
||||
.catch((e) => reject(e));
|
||||
}).catch((e) => {
|
||||
if (e instanceof Error) {
|
||||
workerScript.errorMessage = makeRuntimeRejectMsg(
|
||||
workerScript,
|
||||
e.message + ((e.stack && "\nstack:\n" + e.stack.toString()) || ""),
|
||||
);
|
||||
throw workerScript;
|
||||
} else if (isScriptErrorMessage(e)) {
|
||||
workerScript.errorMessage = e;
|
||||
throw workerScript;
|
||||
}
|
||||
throw e; // Don't know what to do with it, let's rethrow.
|
||||
});
|
||||
}
|
||||
|
||||
function startNetscript1Script(workerScript) {
|
||||
function startNetscript1Script(workerScript: WorkerScript): Promise<WorkerScript> {
|
||||
const code = workerScript.code;
|
||||
workerScript.running = true;
|
||||
|
||||
@ -150,10 +155,10 @@ function startNetscript1Script(workerScript) {
|
||||
workerScript.env.stopFlag = true;
|
||||
workerScript.running = false;
|
||||
killWorkerScript(workerScript);
|
||||
return;
|
||||
return Promise.resolve(workerScript);
|
||||
}
|
||||
|
||||
var interpreterInitialization = function (int, scope) {
|
||||
var interpreterInitialization = function (int: any, scope: any) {
|
||||
//Add the Netscript environment
|
||||
var ns = NetscriptFunctions(workerScript);
|
||||
for (let name in ns) {
|
||||
@ -183,10 +188,10 @@ function startNetscript1Script(workerScript) {
|
||||
let cb = arguments[arguments.length - 1];
|
||||
let fnPromise = entry.apply(null, fnArgs);
|
||||
fnPromise
|
||||
.then(function (res) {
|
||||
.then(function (res: any) {
|
||||
cb(res);
|
||||
})
|
||||
.catch(function (err) {
|
||||
.catch(function (err: any) {
|
||||
console.error(err);
|
||||
});
|
||||
};
|
||||
@ -242,7 +247,7 @@ function startNetscript1Script(workerScript) {
|
||||
int.setProperty(scope, "args", int.nativeToPseudo(workerScript.args));
|
||||
};
|
||||
|
||||
var interpreter;
|
||||
var interpreter: any;
|
||||
try {
|
||||
interpreter = new Interpreter(codeWithImports, interpreterInitialization, codeLineOffset);
|
||||
} catch (e) {
|
||||
@ -250,7 +255,7 @@ function startNetscript1Script(workerScript) {
|
||||
workerScript.env.stopFlag = true;
|
||||
workerScript.running = false;
|
||||
killWorkerScript(workerScript);
|
||||
return;
|
||||
return Promise.resolve(workerScript);
|
||||
}
|
||||
|
||||
return new Promise(function (resolve, reject) {
|
||||
@ -301,9 +306,9 @@ function startNetscript1Script(workerScript) {
|
||||
Should typically be positive
|
||||
}
|
||||
*/
|
||||
function processNetscript1Imports(code, workerScript) {
|
||||
function processNetscript1Imports(code: string, workerScript: WorkerScript): any {
|
||||
//allowReserved prevents 'import' from throwing error in ES5
|
||||
const ast = parse(code, {
|
||||
const ast: any = parse(code, {
|
||||
ecmaVersion: 9,
|
||||
allowReserved: true,
|
||||
sourceType: "module",
|
||||
@ -314,7 +319,7 @@ function processNetscript1Imports(code, workerScript) {
|
||||
throw new Error("Failed to find underlying Server object for script");
|
||||
}
|
||||
|
||||
function getScript(scriptName) {
|
||||
function getScript(scriptName: string): Script | null {
|
||||
for (let i = 0; i < server.scripts.length; ++i) {
|
||||
if (server.scripts[i].filename === scriptName) {
|
||||
return server.scripts[i];
|
||||
@ -328,7 +333,7 @@ function processNetscript1Imports(code, workerScript) {
|
||||
|
||||
// Walk over the tree and process ImportDeclaration nodes
|
||||
walksimple(ast, {
|
||||
ImportDeclaration: (node) => {
|
||||
ImportDeclaration: (node: any) => {
|
||||
hasImports = true;
|
||||
let scriptName = node.source.value;
|
||||
if (scriptName.startsWith("./")) {
|
||||
@ -347,10 +352,10 @@ function processNetscript1Imports(code, workerScript) {
|
||||
if (node.specifiers.length === 1 && node.specifiers[0].type === "ImportNamespaceSpecifier") {
|
||||
// import * as namespace from script
|
||||
let namespace = node.specifiers[0].local.name;
|
||||
let fnNames = []; //Names only
|
||||
let fnDeclarations = []; //FunctionDeclaration Node objects
|
||||
let fnNames: string[] = []; //Names only
|
||||
let fnDeclarations: any[] = []; //FunctionDeclaration Node objects
|
||||
walksimple(scriptAst, {
|
||||
FunctionDeclaration: (node) => {
|
||||
FunctionDeclaration: (node: any) => {
|
||||
fnNames.push(node.id.name);
|
||||
fnDeclarations.push(node);
|
||||
},
|
||||
@ -360,7 +365,7 @@ function processNetscript1Imports(code, workerScript) {
|
||||
generatedCode += "var " + namespace + ";\n" + "(function (namespace) {\n";
|
||||
|
||||
//Add the function declarations
|
||||
fnDeclarations.forEach((fn) => {
|
||||
fnDeclarations.forEach((fn: any) => {
|
||||
generatedCode += generate(fn);
|
||||
generatedCode += "\n";
|
||||
});
|
||||
@ -377,15 +382,15 @@ function processNetscript1Imports(code, workerScript) {
|
||||
//import {...} from script
|
||||
|
||||
//Get array of all fns to import
|
||||
let fnsToImport = [];
|
||||
node.specifiers.forEach((e) => {
|
||||
let fnsToImport: string[] = [];
|
||||
node.specifiers.forEach((e: any) => {
|
||||
fnsToImport.push(e.local.name);
|
||||
});
|
||||
|
||||
//Walk through script and get FunctionDeclaration code for all specified fns
|
||||
let fnDeclarations = [];
|
||||
let fnDeclarations: any[] = [];
|
||||
walksimple(scriptAst, {
|
||||
FunctionDeclaration: (node) => {
|
||||
FunctionDeclaration: (node: any) => {
|
||||
if (fnsToImport.includes(node.id.name)) {
|
||||
fnDeclarations.push(node);
|
||||
}
|
||||
@ -393,7 +398,7 @@ function processNetscript1Imports(code, workerScript) {
|
||||
});
|
||||
|
||||
//Convert FunctionDeclarations into code
|
||||
fnDeclarations.forEach((fn) => {
|
||||
fnDeclarations.forEach((fn: any) => {
|
||||
generatedCode += generate(fn);
|
||||
generatedCode += "\n";
|
||||
});
|
||||
@ -442,11 +447,11 @@ function processNetscript1Imports(code, workerScript) {
|
||||
* @param {Server} server - Server on which the script is to be run
|
||||
* @returns {number} pid of started script
|
||||
*/
|
||||
export function startWorkerScript(runningScript, server, parent) {
|
||||
export function startWorkerScript(runningScript: RunningScript, server: BaseServer, parent?: WorkerScript): number {
|
||||
if (createAndAddWorkerScript(runningScript, server, parent)) {
|
||||
// Push onto runningScripts.
|
||||
// This has to come after createAndAddWorkerScript() because that fn updates RAM usage
|
||||
server.runScript(runningScript, Player.hacknet_node_money_mult);
|
||||
server.runScript(runningScript);
|
||||
|
||||
// Once the WorkerScript is constructed in createAndAddWorkerScript(), the RunningScript
|
||||
// object should have a PID assigned to it, so we return that
|
||||
@ -463,7 +468,11 @@ export function startWorkerScript(runningScript, server, parent) {
|
||||
* @param {Server} server - Server on which the script is to be run
|
||||
* returns {boolean} indicating whether or not the workerScript was successfully added
|
||||
*/
|
||||
export function createAndAddWorkerScript(runningScriptObj, server, parent) {
|
||||
export function createAndAddWorkerScript(
|
||||
runningScriptObj: RunningScript,
|
||||
server: BaseServer,
|
||||
parent?: WorkerScript,
|
||||
): boolean {
|
||||
// Update server's ram usage
|
||||
let threads = 1;
|
||||
if (runningScriptObj.threads && !isNaN(runningScriptObj.threads)) {
|
||||
@ -503,7 +512,7 @@ export function createAndAddWorkerScript(runningScriptObj, server, parent) {
|
||||
WorkerScriptStartStopEventEmitter.emit();
|
||||
|
||||
// Start the script's execution
|
||||
let p = null; // Script's resulting promise
|
||||
let p: Promise<WorkerScript> | null = null; // Script's resulting promise
|
||||
if (s.name.endsWith(".js") || s.name.endsWith(".ns")) {
|
||||
p = startNetscript2Script(s);
|
||||
} else {
|
||||
@ -515,17 +524,19 @@ export function createAndAddWorkerScript(runningScriptObj, server, parent) {
|
||||
|
||||
// Once the code finishes (either resolved or rejected, doesnt matter), set its
|
||||
// running status to false
|
||||
p.then(function (w) {
|
||||
p.then(function (w: WorkerScript) {
|
||||
// On natural death, the earnings are transfered to the parent if it still exists.
|
||||
if (parent && parent.running) {
|
||||
parent.scriptRef.onlineExpGained += runningScriptObj.onlineExpGained;
|
||||
parent.scriptRef.onlineMoneyMade += runningScriptObj.onlineMoneyMade;
|
||||
if (parent !== undefined) {
|
||||
if (parent.running) {
|
||||
parent.scriptRef.onlineExpGained += runningScriptObj.onlineExpGained;
|
||||
parent.scriptRef.onlineMoneyMade += runningScriptObj.onlineMoneyMade;
|
||||
}
|
||||
}
|
||||
|
||||
// If the WorkerScript is no longer "running", then this means its execution was
|
||||
// already stopped somewhere else (maybe by something like exit()). This prevents
|
||||
// the script from being cleaned up twice
|
||||
if (!w.running) {
|
||||
if (w === undefined || !w.running) {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -541,7 +552,7 @@ export function createAndAddWorkerScript(runningScriptObj, server, parent) {
|
||||
const errorTextArray = w.errorMessage.split("|");
|
||||
if (errorTextArray.length != 4) {
|
||||
console.error("ERROR: Something wrong with Error text in evaluator...");
|
||||
console.error("Error text: " + errorText);
|
||||
console.error("Error text: " + w.errorMessage);
|
||||
return;
|
||||
}
|
||||
const serverIp = errorTextArray[1];
|
||||
@ -630,14 +641,21 @@ export function loadAllRunningScripts() {
|
||||
/**
|
||||
* Run a script from inside another script (run(), exec(), spawn(), etc.)
|
||||
*/
|
||||
export function runScriptFromScript(caller, server, scriptname, args, workerScript, threads = 1) {
|
||||
export function runScriptFromScript(
|
||||
caller: string,
|
||||
server: BaseServer,
|
||||
scriptname: string,
|
||||
args: any[],
|
||||
workerScript: WorkerScript,
|
||||
threads = 1,
|
||||
): number {
|
||||
// Sanitize arguments
|
||||
if (!(workerScript instanceof WorkerScript)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (typeof scriptname !== "string" || !Array.isArray(args)) {
|
||||
workerScript.log(caller, `Invalid arguments: scriptname='${scriptname} args='${ags}'`);
|
||||
workerScript.log(caller, `Invalid arguments: scriptname='${scriptname} args='${args}'`);
|
||||
console.error(`runScriptFromScript() failed due to invalid arguments`);
|
||||
return 0;
|
||||
}
|
@ -26,6 +26,8 @@ import { IGang } from "../Gang/IGang";
|
||||
import { IBladeburner } from "../Bladeburner/IBladeburner";
|
||||
import { ICodingContractReward } from "../CodingContracts";
|
||||
import { IRouter } from "../ui/Router";
|
||||
import { WorkerScript } from "../Netscript/WorkerScript";
|
||||
import { HacknetServer } from "../Hacknet/HacknetServer";
|
||||
|
||||
export interface IPlayer {
|
||||
// Class members
|
||||
@ -33,14 +35,12 @@ export interface IPlayer {
|
||||
bitNodeN: number;
|
||||
city: CityName;
|
||||
companyName: string;
|
||||
corporation: ICorporation;
|
||||
gang: IGang;
|
||||
bladeburner: IBladeburner;
|
||||
corporation: ICorporation | null;
|
||||
gang: IGang | null;
|
||||
bladeburner: IBladeburner | null;
|
||||
currentServer: string;
|
||||
factions: string[];
|
||||
factionInvitations: string[];
|
||||
firstProgramAvailable: boolean;
|
||||
firstTimeTraveled: boolean;
|
||||
hacknetNodes: (HacknetNode | string)[]; // HacknetNode object or IP of Hacknet Server
|
||||
has4SData: boolean;
|
||||
has4SDataTixApi: boolean;
|
||||
@ -122,9 +122,13 @@ export interface IPlayer {
|
||||
bladeburner_analysis_mult: number;
|
||||
bladeburner_success_chance_mult: number;
|
||||
|
||||
createProgramReqLvl: number;
|
||||
factionWorkType: string;
|
||||
createProgramName: string;
|
||||
timeWorkedCreateProgram: number;
|
||||
crimeType: string;
|
||||
committingCrimeThruSingFn: boolean;
|
||||
singFnCrimeWorkerScript: WorkerScript | null;
|
||||
timeNeededToCompleteWork: number;
|
||||
focus: boolean;
|
||||
className: string;
|
||||
@ -151,20 +155,23 @@ export interface IPlayer {
|
||||
workMoneyLossRate: number;
|
||||
|
||||
// Methods
|
||||
applyForAgentJob(sing?: boolean): boolean | void;
|
||||
applyForBusinessConsultantJob(sing?: boolean): boolean | void;
|
||||
applyForBusinessJob(sing?: boolean): boolean | void;
|
||||
applyForEmployeeJob(sing?: boolean): boolean | void;
|
||||
applyForItJob(sing?: boolean): boolean | void;
|
||||
applyForJob(entryPosType: CompanyPosition, sing?: boolean): boolean | void;
|
||||
applyForNetworkEngineerJob(sing?: boolean): boolean | void;
|
||||
applyForPartTimeEmployeeJob(sing?: boolean): boolean | void;
|
||||
applyForPartTimeWaiterJob(sing?: boolean): boolean | void;
|
||||
applyForSecurityEngineerJob(sing?: boolean): boolean | void;
|
||||
applyForSecurityJob(sing?: boolean): boolean | void;
|
||||
applyForSoftwareConsultantJob(sing?: boolean): boolean | void;
|
||||
applyForSoftwareJob(sing?: boolean): boolean | void;
|
||||
applyForWaiterJob(sing?: boolean): boolean | void;
|
||||
work(numCycles: number): boolean;
|
||||
workPartTime(numCycles: number): boolean;
|
||||
workForFaction(numCycles: number): boolean;
|
||||
applyForAgentJob(sing?: boolean): boolean;
|
||||
applyForBusinessConsultantJob(sing?: boolean): boolean;
|
||||
applyForBusinessJob(sing?: boolean): boolean;
|
||||
applyForEmployeeJob(sing?: boolean): boolean;
|
||||
applyForItJob(sing?: boolean): boolean;
|
||||
applyForJob(entryPosType: CompanyPosition, sing?: boolean): boolean;
|
||||
applyForNetworkEngineerJob(sing?: boolean): boolean;
|
||||
applyForPartTimeEmployeeJob(sing?: boolean): boolean;
|
||||
applyForPartTimeWaiterJob(sing?: boolean): boolean;
|
||||
applyForSecurityEngineerJob(sing?: boolean): boolean;
|
||||
applyForSecurityJob(sing?: boolean): boolean;
|
||||
applyForSoftwareConsultantJob(sing?: boolean): boolean;
|
||||
applyForSoftwareJob(sing?: boolean): boolean;
|
||||
applyForWaiterJob(sing?: boolean): boolean;
|
||||
canAccessBladeburner(): boolean;
|
||||
canAccessCorporation(): boolean;
|
||||
canAccessGang(): boolean;
|
||||
@ -178,11 +185,11 @@ export interface IPlayer {
|
||||
gainCharismaExp(exp: number): void;
|
||||
gainIntelligenceExp(exp: number): void;
|
||||
gainMoney(money: number): void;
|
||||
getCurrentServer(): Server;
|
||||
getCurrentServer(): Server | HacknetServer;
|
||||
getGangFaction(): Faction;
|
||||
getGangName(): string;
|
||||
getHomeComputer(): Server;
|
||||
getNextCompanyPosition(company: Company, entryPosType: CompanyPosition): CompanyPosition;
|
||||
getNextCompanyPosition(company: Company, entryPosType: CompanyPosition): CompanyPosition | null;
|
||||
getUpgradeHomeRamCost(): number;
|
||||
gotoLocation(to: LocationName): boolean;
|
||||
hasAugmentation(aug: Augmentation): boolean;
|
||||
@ -194,13 +201,14 @@ export interface IPlayer {
|
||||
inGang(): boolean;
|
||||
isQualified(company: Company, position: CompanyPosition): boolean;
|
||||
loseMoney(money: number): void;
|
||||
reapplyAllAugmentations(resetMultipliers: boolean): void;
|
||||
reapplyAllAugmentations(resetMultipliers?: boolean): void;
|
||||
reapplyAllSourceFiles(): void;
|
||||
regenerateHp(amt: number): void;
|
||||
recordMoneySource(amt: number, source: string): void;
|
||||
setMoney(amt: number): void;
|
||||
singularityStopWork(): void;
|
||||
startBladeburner(p: any): void;
|
||||
startFactionWork(router: IRouter, faction: Faction): void;
|
||||
startClass(router: IRouter, costMult: number, expMult: number, className: string): void;
|
||||
startCorporation(corpName: string, additionalShares?: number): void;
|
||||
startCrime(
|
||||
@ -230,18 +238,40 @@ export interface IPlayer {
|
||||
getIntelligenceBonus(weight: number): number;
|
||||
getCasinoWinnings(): number;
|
||||
quitJob(company: string): void;
|
||||
createHacknetServer(): void;
|
||||
createHacknetServer(): HacknetServer;
|
||||
startCreateProgramWork(router: IRouter, programName: string, time: number, reqLevel: number): void;
|
||||
queueAugmentation(augmentationName: string): void;
|
||||
receiveInvite(factionName: string): void;
|
||||
updateSkillLevels(): void;
|
||||
gainCodingContractReward(reward: ICodingContractReward, difficulty?: number): string;
|
||||
stopFocusing(): void;
|
||||
finishFactionWork(cancelled: boolean, sing?: boolean): void;
|
||||
finishClass(sing?: boolean): void;
|
||||
finishWork(cancelled: boolean, sing?: boolean): void;
|
||||
finishFactionWork(cancelled: boolean, sing?: boolean): string;
|
||||
finishClass(sing?: boolean): string;
|
||||
finishWork(cancelled: boolean, sing?: boolean): string;
|
||||
cancelationPenalty(): number;
|
||||
finishWorkPartTime(sing?: boolean): void;
|
||||
finishCrime(cancelled: boolean): void;
|
||||
finishCreateProgramWork(cancelled: boolean): void;
|
||||
finishWorkPartTime(sing?: boolean): string;
|
||||
finishCrime(cancelled: boolean): string;
|
||||
finishCreateProgramWork(cancelled: boolean): string;
|
||||
resetMultipliers(): void;
|
||||
prestigeAugmentation(): void;
|
||||
prestigeSourceFile(): void;
|
||||
calculateSkill(exp: number, mult?: number): number;
|
||||
resetWorkStatus(generalType?: string, group?: string, workType?: string): void;
|
||||
getWorkHackExpGain(): number;
|
||||
getWorkStrExpGain(): number;
|
||||
getWorkDefExpGain(): number;
|
||||
getWorkDexExpGain(): number;
|
||||
getWorkAgiExpGain(): number;
|
||||
getWorkChaExpGain(): number;
|
||||
getWorkRepGain(): number;
|
||||
getWorkMoneyGain(): number;
|
||||
processWorkEarnings(cycles: number): void;
|
||||
hospitalize(): void;
|
||||
createProgramWork(numCycles: number): boolean;
|
||||
takeClass(numCycles: number): boolean;
|
||||
commitCrime(numCycles: number): boolean;
|
||||
checkForFactionInvitations(): Faction[];
|
||||
setBitNodeNumber(n: number): void;
|
||||
getMult(name: string): number;
|
||||
setMult(name: string, mult: number): void;
|
||||
}
|
||||
|
@ -1,224 +0,0 @@
|
||||
import * as augmentationMethods from "./PlayerObjectAugmentationMethods";
|
||||
import * as bladeburnerMethods from "./PlayerObjectBladeburnerMethods";
|
||||
import * as corporationMethods from "./PlayerObjectCorporationMethods";
|
||||
import * as gangMethods from "./PlayerObjectGangMethods";
|
||||
import * as generalMethods from "./PlayerObjectGeneralMethods";
|
||||
import * as serverMethods from "./PlayerObjectServerMethods";
|
||||
|
||||
import { HashManager } from "../../Hacknet/HashManager";
|
||||
import { CityName } from "../../Locations/data/CityNames";
|
||||
|
||||
import { MoneySourceTracker } from "../../utils/MoneySourceTracker";
|
||||
import { Reviver, Generic_toJSON, Generic_fromJSON } from "../../../utils/JSONReviver";
|
||||
|
||||
import Decimal from "decimal.js";
|
||||
|
||||
export function PlayerObject() {
|
||||
//Skills and stats
|
||||
this.hacking_skill = 1;
|
||||
|
||||
//Combat stats
|
||||
this.hp = 10;
|
||||
this.max_hp = 10;
|
||||
this.strength = 1;
|
||||
this.defense = 1;
|
||||
this.dexterity = 1;
|
||||
this.agility = 1;
|
||||
|
||||
//Labor stats
|
||||
this.charisma = 1;
|
||||
|
||||
//Special stats
|
||||
this.intelligence = 0;
|
||||
|
||||
//Hacking multipliers
|
||||
this.hacking_chance_mult = 1;
|
||||
this.hacking_speed_mult = 1;
|
||||
this.hacking_money_mult = 1;
|
||||
this.hacking_grow_mult = 1;
|
||||
|
||||
//Experience and multipliers
|
||||
this.hacking_exp = 0;
|
||||
this.strength_exp = 0;
|
||||
this.defense_exp = 0;
|
||||
this.dexterity_exp = 0;
|
||||
this.agility_exp = 0;
|
||||
this.charisma_exp = 0;
|
||||
this.intelligence_exp = 0;
|
||||
|
||||
this.hacking_mult = 1;
|
||||
this.strength_mult = 1;
|
||||
this.defense_mult = 1;
|
||||
this.dexterity_mult = 1;
|
||||
this.agility_mult = 1;
|
||||
this.charisma_mult = 1;
|
||||
|
||||
this.hacking_exp_mult = 1;
|
||||
this.strength_exp_mult = 1;
|
||||
this.defense_exp_mult = 1;
|
||||
this.dexterity_exp_mult = 1;
|
||||
this.agility_exp_mult = 1;
|
||||
this.charisma_exp_mult = 1;
|
||||
|
||||
this.company_rep_mult = 1;
|
||||
this.faction_rep_mult = 1;
|
||||
|
||||
//Money
|
||||
this.money = new Decimal(1000);
|
||||
|
||||
//IP Address of Starting (home) computer
|
||||
this.homeComputer = "";
|
||||
|
||||
//Location information
|
||||
this.city = CityName.Sector12;
|
||||
this.location = "";
|
||||
|
||||
// Jobs that the player holds
|
||||
// Map of company name (key) -> name of company position (value. Just the name, not the CompanyPosition object)
|
||||
// The CompanyPosition name must match a key value in CompanyPositions
|
||||
this.jobs = {};
|
||||
|
||||
// Company at which player is CURRENTLY working (only valid when the player is actively working)
|
||||
this.companyName = ""; // Name of Company. Must match a key value in Companies map
|
||||
|
||||
// Servers
|
||||
this.currentServer = ""; //IP address of Server currently being accessed through terminal
|
||||
this.purchasedServers = []; //IP Addresses of purchased servers
|
||||
|
||||
// Hacknet Nodes/Servers
|
||||
this.hacknetNodes = []; // Note: For Hacknet Servers, this array holds the IP addresses of the servers
|
||||
this.hashManager = new HashManager();
|
||||
|
||||
//Factions
|
||||
this.factions = []; //Names of all factions player has joined
|
||||
this.factionInvitations = []; //Outstanding faction invitations
|
||||
|
||||
//Augmentations
|
||||
this.queuedAugmentations = [];
|
||||
this.augmentations = [];
|
||||
|
||||
this.sourceFiles = [];
|
||||
|
||||
//Crime statistics
|
||||
this.numPeopleKilled = 0;
|
||||
this.karma = 0;
|
||||
|
||||
this.crime_money_mult = 1;
|
||||
this.crime_success_mult = 1;
|
||||
|
||||
//Flags/variables for working (Company, Faction, Creating Program, Taking Class)
|
||||
this.isWorking = false;
|
||||
this.focus = false;
|
||||
this.workType = "";
|
||||
|
||||
this.currentWorkFactionName = "";
|
||||
this.currentWorkFactionDescription = "";
|
||||
|
||||
this.workHackExpGainRate = 0;
|
||||
this.workStrExpGainRate = 0;
|
||||
this.workDefExpGainRate = 0;
|
||||
this.workDexExpGainRate = 0;
|
||||
this.workAgiExpGainRate = 0;
|
||||
this.workChaExpGainRate = 0;
|
||||
this.workRepGainRate = 0;
|
||||
this.workMoneyGainRate = 0;
|
||||
this.workMoneyLossRate = 0;
|
||||
|
||||
this.workHackExpGained = 0;
|
||||
this.workStrExpGained = 0;
|
||||
this.workDefExpGained = 0;
|
||||
this.workDexExpGained = 0;
|
||||
this.workAgiExpGained = 0;
|
||||
this.workChaExpGained = 0;
|
||||
this.workRepGained = 0;
|
||||
this.workMoneyGained = 0;
|
||||
|
||||
this.createProgramName = "";
|
||||
this.createProgramReqLvl = 0;
|
||||
|
||||
this.className = "";
|
||||
|
||||
this.crimeType = "";
|
||||
|
||||
this.timeWorked = 0; //in ms
|
||||
this.timeWorkedCreateProgram = 0;
|
||||
this.timeNeededToCompleteWork = 0;
|
||||
|
||||
this.work_money_mult = 1;
|
||||
|
||||
//Hacknet Node multipliers
|
||||
this.hacknet_node_money_mult = 1;
|
||||
this.hacknet_node_purchase_cost_mult = 1;
|
||||
this.hacknet_node_ram_cost_mult = 1;
|
||||
this.hacknet_node_core_cost_mult = 1;
|
||||
this.hacknet_node_level_cost_mult = 1;
|
||||
|
||||
//Stock Market
|
||||
this.hasWseAccount = false;
|
||||
this.hasTixApiAccess = false;
|
||||
this.has4SData = false;
|
||||
this.has4SDataTixApi = false;
|
||||
|
||||
//Gang
|
||||
this.gang = null;
|
||||
|
||||
//Corporation
|
||||
this.corporation = null;
|
||||
|
||||
//Bladeburner
|
||||
this.bladeburner = null;
|
||||
this.bladeburner_max_stamina_mult = 1;
|
||||
this.bladeburner_stamina_gain_mult = 1;
|
||||
this.bladeburner_analysis_mult = 1; //Field Analysis Only
|
||||
this.bladeburner_success_chance_mult = 1;
|
||||
|
||||
// Sleeves & Re-sleeving
|
||||
this.sleeves = [];
|
||||
this.resleeves = [];
|
||||
this.sleevesFromCovenant = 0; // # of Duplicate sleeves purchased from the covenant
|
||||
|
||||
//bitnode
|
||||
this.bitNodeN = 1;
|
||||
|
||||
//Flags for determining whether certain "thresholds" have been achieved
|
||||
this.firstFacInvRecvd = false;
|
||||
this.firstAugPurchased = false;
|
||||
this.firstTimeTraveled = false;
|
||||
this.firstProgramAvailable = false;
|
||||
|
||||
//Used to store the last update time.
|
||||
this.lastUpdate = 0;
|
||||
this.totalPlaytime = 0;
|
||||
this.playtimeSinceLastAug = 0;
|
||||
this.playtimeSinceLastBitnode = 0;
|
||||
|
||||
// Keep track of where money comes from
|
||||
this.moneySourceA = new MoneySourceTracker(); // Where money comes from since last-installed Augmentation
|
||||
this.moneySourceB = new MoneySourceTracker(); // Where money comes from for this entire BitNode run
|
||||
|
||||
// Production since last Augmentation installation
|
||||
this.scriptProdSinceLastAug = 0;
|
||||
|
||||
this.exploits = [];
|
||||
}
|
||||
|
||||
// Apply player methods to the prototype using Object.assign()
|
||||
Object.assign(
|
||||
PlayerObject.prototype,
|
||||
generalMethods,
|
||||
serverMethods,
|
||||
bladeburnerMethods,
|
||||
corporationMethods,
|
||||
gangMethods,
|
||||
augmentationMethods,
|
||||
);
|
||||
|
||||
PlayerObject.prototype.toJSON = function () {
|
||||
return Generic_toJSON("PlayerObject", this);
|
||||
};
|
||||
|
||||
PlayerObject.fromJSON = function (value) {
|
||||
return Generic_fromJSON(PlayerObject, value.data);
|
||||
};
|
||||
|
||||
Reviver.constructors.PlayerObject = PlayerObject;
|
596
src/PersonObjects/Player/PlayerObject.ts
Normal file
596
src/PersonObjects/Player/PlayerObject.ts
Normal file
@ -0,0 +1,596 @@
|
||||
import * as augmentationMethods from "./PlayerObjectAugmentationMethods";
|
||||
import * as bladeburnerMethods from "./PlayerObjectBladeburnerMethods";
|
||||
import * as corporationMethods from "./PlayerObjectCorporationMethods";
|
||||
import * as gangMethods from "./PlayerObjectGangMethods";
|
||||
import * as generalMethods from "./PlayerObjectGeneralMethods";
|
||||
import * as serverMethods from "./PlayerObjectServerMethods";
|
||||
|
||||
import { IMap } from "../../types";
|
||||
import { Resleeve } from "../Resleeving/Resleeve";
|
||||
import { Sleeve } from "../Sleeve/Sleeve";
|
||||
import { IPlayerOwnedSourceFile } from "../../SourceFile/PlayerOwnedSourceFile";
|
||||
import { Exploit } from "../../Exploits/Exploit";
|
||||
import { WorkerScript } from "../../Netscript/WorkerScript";
|
||||
import { CompanyPosition } from "../../Company/CompanyPosition";
|
||||
import { Server } from "../../Server/Server";
|
||||
import { HacknetServer } from "../../Hacknet/HacknetServer";
|
||||
import { Faction } from "../../Faction/Faction";
|
||||
import { Company } from "../../Company/Company";
|
||||
import { Augmentation } from "../../Augmentation/Augmentation";
|
||||
import { IRouter } from "../../ui/Router";
|
||||
import { ICodingContractReward } from "../../CodingContracts";
|
||||
|
||||
import { IPlayer } from "../IPlayer";
|
||||
import { LocationName } from "../../Locations/data/LocationNames";
|
||||
import { IPlayerOwnedAugmentation } from "../../Augmentation/PlayerOwnedAugmentation";
|
||||
import { ICorporation } from "../../Corporation/ICorporation";
|
||||
import { IGang } from "../../Gang/IGang";
|
||||
import { IBladeburner } from "../../Bladeburner/IBladeburner";
|
||||
import { HacknetNode } from "../../Hacknet/HacknetNode";
|
||||
|
||||
import { HashManager } from "../../Hacknet/HashManager";
|
||||
import { CityName } from "../../Locations/data/CityNames";
|
||||
|
||||
import { MoneySourceTracker } from "../../utils/MoneySourceTracker";
|
||||
import { Reviver, Generic_toJSON, Generic_fromJSON } from "../../../utils/JSONReviver";
|
||||
|
||||
import Decimal from "decimal.js";
|
||||
|
||||
export class PlayerObject implements IPlayer {
|
||||
// Class members
|
||||
augmentations: IPlayerOwnedAugmentation[];
|
||||
bitNodeN: number;
|
||||
city: CityName;
|
||||
companyName: string;
|
||||
corporation: ICorporation | null;
|
||||
gang: IGang | null;
|
||||
bladeburner: IBladeburner | null;
|
||||
currentServer: string;
|
||||
factions: string[];
|
||||
factionInvitations: string[];
|
||||
hacknetNodes: (HacknetNode | string)[]; // HacknetNode object or IP of Hacknet Server
|
||||
has4SData: boolean;
|
||||
has4SDataTixApi: boolean;
|
||||
hashManager: HashManager;
|
||||
hasTixApiAccess: boolean;
|
||||
hasWseAccount: boolean;
|
||||
homeComputer: string;
|
||||
hp: number;
|
||||
jobs: IMap<string>;
|
||||
init: () => void;
|
||||
isWorking: boolean;
|
||||
karma: number;
|
||||
numPeopleKilled: number;
|
||||
location: LocationName;
|
||||
max_hp: number;
|
||||
money: any;
|
||||
moneySourceA: MoneySourceTracker;
|
||||
moneySourceB: MoneySourceTracker;
|
||||
playtimeSinceLastAug: number;
|
||||
playtimeSinceLastBitnode: number;
|
||||
purchasedServers: any[];
|
||||
queuedAugmentations: IPlayerOwnedAugmentation[];
|
||||
resleeves: Resleeve[];
|
||||
scriptProdSinceLastAug: number;
|
||||
sleeves: Sleeve[];
|
||||
sleevesFromCovenant: number;
|
||||
sourceFiles: IPlayerOwnedSourceFile[];
|
||||
exploits: Exploit[];
|
||||
lastUpdate: number;
|
||||
totalPlaytime: number;
|
||||
|
||||
// Stats
|
||||
hacking_skill: number;
|
||||
strength: number;
|
||||
defense: number;
|
||||
dexterity: number;
|
||||
agility: number;
|
||||
charisma: number;
|
||||
intelligence: number;
|
||||
|
||||
// Experience
|
||||
hacking_exp: number;
|
||||
strength_exp: number;
|
||||
defense_exp: number;
|
||||
dexterity_exp: number;
|
||||
agility_exp: number;
|
||||
charisma_exp: number;
|
||||
intelligence_exp: number;
|
||||
|
||||
// Multipliers
|
||||
hacking_chance_mult: number;
|
||||
hacking_speed_mult: number;
|
||||
hacking_money_mult: number;
|
||||
hacking_grow_mult: number;
|
||||
hacking_mult: number;
|
||||
hacking_exp_mult: number;
|
||||
strength_mult: number;
|
||||
strength_exp_mult: number;
|
||||
defense_mult: number;
|
||||
defense_exp_mult: number;
|
||||
dexterity_mult: number;
|
||||
dexterity_exp_mult: number;
|
||||
agility_mult: number;
|
||||
agility_exp_mult: number;
|
||||
charisma_mult: number;
|
||||
charisma_exp_mult: number;
|
||||
hacknet_node_money_mult: number;
|
||||
hacknet_node_purchase_cost_mult: number;
|
||||
hacknet_node_ram_cost_mult: number;
|
||||
hacknet_node_core_cost_mult: number;
|
||||
hacknet_node_level_cost_mult: number;
|
||||
company_rep_mult: number;
|
||||
faction_rep_mult: number;
|
||||
work_money_mult: number;
|
||||
crime_success_mult: number;
|
||||
crime_money_mult: number;
|
||||
bladeburner_max_stamina_mult: number;
|
||||
bladeburner_stamina_gain_mult: number;
|
||||
bladeburner_analysis_mult: number;
|
||||
bladeburner_success_chance_mult: number;
|
||||
|
||||
createProgramReqLvl: number;
|
||||
factionWorkType: string;
|
||||
createProgramName: string;
|
||||
timeWorkedCreateProgram: number;
|
||||
crimeType: string;
|
||||
committingCrimeThruSingFn: boolean;
|
||||
singFnCrimeWorkerScript: WorkerScript | null;
|
||||
timeNeededToCompleteWork: number;
|
||||
focus: boolean;
|
||||
className: string;
|
||||
currentWorkFactionName: string;
|
||||
workType: string;
|
||||
currentWorkFactionDescription: string;
|
||||
timeWorked: number;
|
||||
workMoneyGained: number;
|
||||
workMoneyGainRate: number;
|
||||
workRepGained: number;
|
||||
workRepGainRate: number;
|
||||
workHackExpGained: number;
|
||||
workHackExpGainRate: number;
|
||||
workStrExpGained: number;
|
||||
workStrExpGainRate: number;
|
||||
workDefExpGained: number;
|
||||
workDefExpGainRate: number;
|
||||
workDexExpGained: number;
|
||||
workDexExpGainRate: number;
|
||||
workAgiExpGained: number;
|
||||
workAgiExpGainRate: number;
|
||||
workChaExpGained: number;
|
||||
workChaExpGainRate: number;
|
||||
workMoneyLossRate: number;
|
||||
|
||||
// Methods
|
||||
work: (numCycles: number) => boolean;
|
||||
workPartTime: (numCycles: number) => boolean;
|
||||
workForFaction: (numCycles: number) => boolean;
|
||||
applyForAgentJob: (sing?: boolean) => boolean;
|
||||
applyForBusinessConsultantJob: (sing?: boolean) => boolean;
|
||||
applyForBusinessJob: (sing?: boolean) => boolean;
|
||||
applyForEmployeeJob: (sing?: boolean) => boolean;
|
||||
applyForItJob: (sing?: boolean) => boolean;
|
||||
applyForJob: (entryPosType: CompanyPosition, sing?: boolean) => boolean;
|
||||
applyForNetworkEngineerJob: (sing?: boolean) => boolean;
|
||||
applyForPartTimeEmployeeJob: (sing?: boolean) => boolean;
|
||||
applyForPartTimeWaiterJob: (sing?: boolean) => boolean;
|
||||
applyForSecurityEngineerJob: (sing?: boolean) => boolean;
|
||||
applyForSecurityJob: (sing?: boolean) => boolean;
|
||||
applyForSoftwareConsultantJob: (sing?: boolean) => boolean;
|
||||
applyForSoftwareJob: (sing?: boolean) => boolean;
|
||||
applyForWaiterJob: (sing?: boolean) => boolean;
|
||||
canAccessBladeburner: () => boolean;
|
||||
canAccessCorporation: () => boolean;
|
||||
canAccessGang: () => boolean;
|
||||
canAccessResleeving: () => boolean;
|
||||
canAfford: (cost: number) => boolean;
|
||||
gainHackingExp: (exp: number) => void;
|
||||
gainStrengthExp: (exp: number) => void;
|
||||
gainDefenseExp: (exp: number) => void;
|
||||
gainDexterityExp: (exp: number) => void;
|
||||
gainAgilityExp: (exp: number) => void;
|
||||
gainCharismaExp: (exp: number) => void;
|
||||
gainIntelligenceExp: (exp: number) => void;
|
||||
gainMoney: (money: number) => void;
|
||||
getCurrentServer: () => Server | HacknetServer;
|
||||
getGangFaction: () => Faction;
|
||||
getGangName: () => string;
|
||||
getHomeComputer: () => Server;
|
||||
getNextCompanyPosition: (company: Company, entryPosType: CompanyPosition) => CompanyPosition | null;
|
||||
getUpgradeHomeRamCost: () => number;
|
||||
gotoLocation: (to: LocationName) => boolean;
|
||||
hasAugmentation: (aug: Augmentation) => boolean;
|
||||
hasCorporation: () => boolean;
|
||||
hasGangWith: (facName: string) => boolean;
|
||||
hasTorRouter: () => boolean;
|
||||
hasProgram: (program: string) => boolean;
|
||||
inBladeburner: () => boolean;
|
||||
inGang: () => boolean;
|
||||
isQualified: (company: Company, position: CompanyPosition) => boolean;
|
||||
loseMoney: (money: number) => void;
|
||||
reapplyAllAugmentations: (resetMultipliers?: boolean) => void;
|
||||
reapplyAllSourceFiles: () => void;
|
||||
regenerateHp: (amt: number) => void;
|
||||
recordMoneySource: (amt: number, source: string) => void;
|
||||
setMoney: (amt: number) => void;
|
||||
singularityStopWork: () => void;
|
||||
startBladeburner: (p: any) => void;
|
||||
startFactionWork: (router: IRouter, faction: Faction) => void;
|
||||
startClass: (router: IRouter, costMult: number, expMult: number, className: string) => void;
|
||||
startCorporation: (corpName: string, additionalShares?: number) => void;
|
||||
startCrime: (
|
||||
router: IRouter,
|
||||
crimeType: string,
|
||||
hackExp: number,
|
||||
strExp: number,
|
||||
defExp: number,
|
||||
dexExp: number,
|
||||
agiExp: number,
|
||||
chaExp: number,
|
||||
money: number,
|
||||
time: number,
|
||||
singParams: any,
|
||||
) => void;
|
||||
startFactionFieldWork: (router: IRouter, faction: Faction) => void;
|
||||
startFactionHackWork: (router: IRouter, faction: Faction) => void;
|
||||
startFactionSecurityWork: (router: IRouter, faction: Faction) => void;
|
||||
startFocusing: () => void;
|
||||
startGang: (facName: string, isHacking: boolean) => void;
|
||||
startWork: (router: IRouter, companyName: string) => void;
|
||||
startWorkPartTime: (router: IRouter, companyName: string) => void;
|
||||
takeDamage: (amt: number) => boolean;
|
||||
travel: (to: CityName) => boolean;
|
||||
giveExploit: (exploit: Exploit) => void;
|
||||
queryStatFromString: (str: string) => number;
|
||||
getIntelligenceBonus: (weight: number) => number;
|
||||
getCasinoWinnings: () => number;
|
||||
quitJob: (company: string) => void;
|
||||
createHacknetServer: () => HacknetServer;
|
||||
startCreateProgramWork: (router: IRouter, programName: string, time: number, reqLevel: number) => void;
|
||||
queueAugmentation: (augmentationName: string) => void;
|
||||
receiveInvite: (factionName: string) => void;
|
||||
updateSkillLevels: () => void;
|
||||
gainCodingContractReward: (reward: ICodingContractReward, difficulty?: number) => string;
|
||||
stopFocusing: () => void;
|
||||
finishFactionWork: (cancelled: boolean, sing?: boolean) => string;
|
||||
finishClass: (sing?: boolean) => string;
|
||||
finishWork: (cancelled: boolean, sing?: boolean) => string;
|
||||
cancelationPenalty: () => number;
|
||||
finishWorkPartTime: (sing?: boolean) => string;
|
||||
finishCrime: (cancelled: boolean) => string;
|
||||
finishCreateProgramWork: (cancelled: boolean) => string;
|
||||
resetMultipliers: () => void;
|
||||
prestigeAugmentation: () => void;
|
||||
prestigeSourceFile: () => void;
|
||||
calculateSkill: (exp: number, mult?: number) => number;
|
||||
resetWorkStatus: (generalType?: string, group?: string, workType?: string) => void;
|
||||
getWorkHackExpGain: () => number;
|
||||
getWorkStrExpGain: () => number;
|
||||
getWorkDefExpGain: () => number;
|
||||
getWorkDexExpGain: () => number;
|
||||
getWorkAgiExpGain: () => number;
|
||||
getWorkChaExpGain: () => number;
|
||||
getWorkRepGain: () => number;
|
||||
getWorkMoneyGain: () => number;
|
||||
processWorkEarnings: (cycles: number) => void;
|
||||
hospitalize: () => void;
|
||||
createProgramWork: (numCycles: number) => boolean;
|
||||
takeClass: (numCycles: number) => boolean;
|
||||
commitCrime: (numCycles: number) => boolean;
|
||||
checkForFactionInvitations: () => Faction[];
|
||||
setBitNodeNumber: (n: number) => void;
|
||||
getMult: (name: string) => number;
|
||||
setMult: (name: string, mult: number) => void;
|
||||
|
||||
constructor() {
|
||||
//Skills and stats
|
||||
this.hacking_skill = 1;
|
||||
|
||||
//Combat stats
|
||||
this.hp = 10;
|
||||
this.max_hp = 10;
|
||||
this.strength = 1;
|
||||
this.defense = 1;
|
||||
this.dexterity = 1;
|
||||
this.agility = 1;
|
||||
|
||||
//Labor stats
|
||||
this.charisma = 1;
|
||||
|
||||
//Special stats
|
||||
this.intelligence = 0;
|
||||
|
||||
//Hacking multipliers
|
||||
this.hacking_chance_mult = 1;
|
||||
this.hacking_speed_mult = 1;
|
||||
this.hacking_money_mult = 1;
|
||||
this.hacking_grow_mult = 1;
|
||||
|
||||
//Experience and multipliers
|
||||
this.hacking_exp = 0;
|
||||
this.strength_exp = 0;
|
||||
this.defense_exp = 0;
|
||||
this.dexterity_exp = 0;
|
||||
this.agility_exp = 0;
|
||||
this.charisma_exp = 0;
|
||||
this.intelligence_exp = 0;
|
||||
|
||||
this.hacking_mult = 1;
|
||||
this.strength_mult = 1;
|
||||
this.defense_mult = 1;
|
||||
this.dexterity_mult = 1;
|
||||
this.agility_mult = 1;
|
||||
this.charisma_mult = 1;
|
||||
|
||||
this.hacking_exp_mult = 1;
|
||||
this.strength_exp_mult = 1;
|
||||
this.defense_exp_mult = 1;
|
||||
this.dexterity_exp_mult = 1;
|
||||
this.agility_exp_mult = 1;
|
||||
this.charisma_exp_mult = 1;
|
||||
|
||||
this.company_rep_mult = 1;
|
||||
this.faction_rep_mult = 1;
|
||||
|
||||
//Money
|
||||
this.money = new Decimal(1000);
|
||||
|
||||
//IP Address of Starting (home) computer
|
||||
this.homeComputer = "";
|
||||
|
||||
//Location information
|
||||
this.city = CityName.Sector12;
|
||||
this.location = LocationName.TravelAgency;
|
||||
|
||||
// Jobs that the player holds
|
||||
// Map of company name (key) -> name of company position (value. Just the name, not the CompanyPosition object)
|
||||
// The CompanyPosition name must match a key value in CompanyPositions
|
||||
this.jobs = {};
|
||||
|
||||
// Company at which player is CURRENTLY working (only valid when the player is actively working)
|
||||
this.companyName = ""; // Name of Company. Must match a key value in Companies ma;
|
||||
|
||||
// Servers
|
||||
this.currentServer = ""; //IP address of Server currently being accessed through termina;
|
||||
this.purchasedServers = []; //IP Addresses of purchased server;
|
||||
|
||||
// Hacknet Nodes/Servers
|
||||
this.hacknetNodes = []; // Note= For Hacknet Servers, this array holds the IP addresses of the server;
|
||||
this.hashManager = new HashManager();
|
||||
|
||||
//Factions
|
||||
this.factions = []; //Names of all factions player has joine;
|
||||
this.factionInvitations = []; //Outstanding faction invitation;
|
||||
|
||||
//Augmentations
|
||||
this.queuedAugmentations = [];
|
||||
this.augmentations = [];
|
||||
|
||||
this.sourceFiles = [];
|
||||
|
||||
//Crime statistics
|
||||
this.numPeopleKilled = 0;
|
||||
this.karma = 0;
|
||||
|
||||
this.crime_money_mult = 1;
|
||||
this.crime_success_mult = 1;
|
||||
|
||||
//Flags/variables for working (Company, Faction, Creating Program, Taking Class)
|
||||
this.isWorking = false;
|
||||
this.focus = false;
|
||||
this.workType = "";
|
||||
|
||||
this.currentWorkFactionName = "";
|
||||
this.currentWorkFactionDescription = "";
|
||||
|
||||
this.workHackExpGainRate = 0;
|
||||
this.workStrExpGainRate = 0;
|
||||
this.workDefExpGainRate = 0;
|
||||
this.workDexExpGainRate = 0;
|
||||
this.workAgiExpGainRate = 0;
|
||||
this.workChaExpGainRate = 0;
|
||||
this.workRepGainRate = 0;
|
||||
this.workMoneyGainRate = 0;
|
||||
this.workMoneyLossRate = 0;
|
||||
|
||||
this.workHackExpGained = 0;
|
||||
this.workStrExpGained = 0;
|
||||
this.workDefExpGained = 0;
|
||||
this.workDexExpGained = 0;
|
||||
this.workAgiExpGained = 0;
|
||||
this.workChaExpGained = 0;
|
||||
this.workRepGained = 0;
|
||||
this.workMoneyGained = 0;
|
||||
|
||||
this.createProgramName = "";
|
||||
this.createProgramReqLvl = 0;
|
||||
|
||||
this.className = "";
|
||||
|
||||
this.crimeType = "";
|
||||
|
||||
(this.timeWorked = 0), //in m;
|
||||
(this.timeWorkedCreateProgram = 0);
|
||||
this.timeNeededToCompleteWork = 0;
|
||||
|
||||
this.work_money_mult = 1;
|
||||
|
||||
//Hacknet Node multipliers
|
||||
this.hacknet_node_money_mult = 1;
|
||||
this.hacknet_node_purchase_cost_mult = 1;
|
||||
this.hacknet_node_ram_cost_mult = 1;
|
||||
this.hacknet_node_core_cost_mult = 1;
|
||||
this.hacknet_node_level_cost_mult = 1;
|
||||
|
||||
//Stock Market
|
||||
this.hasWseAccount = false;
|
||||
this.hasTixApiAccess = false;
|
||||
this.has4SData = false;
|
||||
this.has4SDataTixApi = false;
|
||||
|
||||
//Gang
|
||||
this.gang = null;
|
||||
|
||||
//Corporation
|
||||
this.corporation = null;
|
||||
|
||||
//Bladeburner
|
||||
this.bladeburner = null;
|
||||
this.bladeburner_max_stamina_mult = 1;
|
||||
this.bladeburner_stamina_gain_mult = 1;
|
||||
(this.bladeburner_analysis_mult = 1), //Field Analysis Onl;
|
||||
(this.bladeburner_success_chance_mult = 1);
|
||||
|
||||
// Sleeves & Re-sleeving
|
||||
this.sleeves = [];
|
||||
this.resleeves = [];
|
||||
(this.sleevesFromCovenant = 0), // # of Duplicate sleeves purchased from the covenan;
|
||||
//bitnode
|
||||
(this.bitNodeN = 1);
|
||||
|
||||
//Used to store the last update time.
|
||||
this.lastUpdate = 0;
|
||||
this.totalPlaytime = 0;
|
||||
this.playtimeSinceLastAug = 0;
|
||||
this.playtimeSinceLastBitnode = 0;
|
||||
|
||||
// Keep track of where money comes from
|
||||
(this.moneySourceA = new MoneySourceTracker()), // Where money comes from since last-installed Augmentatio;
|
||||
(this.moneySourceB = new MoneySourceTracker()), // Where money comes from for this entire BitNode ru;
|
||||
// Production since last Augmentation installation
|
||||
(this.scriptProdSinceLastAug = 0);
|
||||
|
||||
this.exploits = [];
|
||||
|
||||
this.init = generalMethods.init;
|
||||
this.prestigeAugmentation = generalMethods.prestigeAugmentation;
|
||||
this.prestigeSourceFile = generalMethods.prestigeSourceFile;
|
||||
this.receiveInvite = generalMethods.receiveInvite;
|
||||
this.calculateSkill = generalMethods.calculateSkill;
|
||||
this.updateSkillLevels = generalMethods.updateSkillLevels;
|
||||
this.resetMultipliers = generalMethods.resetMultipliers;
|
||||
this.hasProgram = generalMethods.hasProgram;
|
||||
this.setMoney = generalMethods.setMoney;
|
||||
this.gainMoney = generalMethods.gainMoney;
|
||||
this.loseMoney = generalMethods.loseMoney;
|
||||
this.canAfford = generalMethods.canAfford;
|
||||
this.recordMoneySource = generalMethods.recordMoneySource;
|
||||
this.gainHackingExp = generalMethods.gainHackingExp;
|
||||
this.gainStrengthExp = generalMethods.gainStrengthExp;
|
||||
this.gainDefenseExp = generalMethods.gainDefenseExp;
|
||||
this.gainDexterityExp = generalMethods.gainDexterityExp;
|
||||
this.gainAgilityExp = generalMethods.gainAgilityExp;
|
||||
this.gainCharismaExp = generalMethods.gainCharismaExp;
|
||||
this.gainIntelligenceExp = generalMethods.gainIntelligenceExp;
|
||||
this.queryStatFromString = generalMethods.queryStatFromString;
|
||||
this.resetWorkStatus = generalMethods.resetWorkStatus;
|
||||
this.processWorkEarnings = generalMethods.processWorkEarnings;
|
||||
this.startWork = generalMethods.startWork;
|
||||
this.cancelationPenalty = generalMethods.cancelationPenalty;
|
||||
this.work = generalMethods.work;
|
||||
this.finishWork = generalMethods.finishWork;
|
||||
this.startWorkPartTime = generalMethods.startWorkPartTime;
|
||||
this.workPartTime = generalMethods.workPartTime;
|
||||
this.finishWorkPartTime = generalMethods.finishWorkPartTime;
|
||||
this.startFocusing = generalMethods.startFocusing;
|
||||
this.stopFocusing = generalMethods.stopFocusing;
|
||||
this.startFactionWork = generalMethods.startFactionWork;
|
||||
this.startFactionHackWork = generalMethods.startFactionHackWork;
|
||||
this.startFactionFieldWork = generalMethods.startFactionFieldWork;
|
||||
this.startFactionSecurityWork = generalMethods.startFactionSecurityWork;
|
||||
this.workForFaction = generalMethods.workForFaction;
|
||||
this.finishFactionWork = generalMethods.finishFactionWork;
|
||||
this.getWorkMoneyGain = generalMethods.getWorkMoneyGain;
|
||||
this.getWorkHackExpGain = generalMethods.getWorkHackExpGain;
|
||||
this.getWorkStrExpGain = generalMethods.getWorkStrExpGain;
|
||||
this.getWorkDefExpGain = generalMethods.getWorkDefExpGain;
|
||||
this.getWorkDexExpGain = generalMethods.getWorkDexExpGain;
|
||||
this.getWorkAgiExpGain = generalMethods.getWorkAgiExpGain;
|
||||
this.getWorkChaExpGain = generalMethods.getWorkChaExpGain;
|
||||
this.getWorkRepGain = generalMethods.getWorkRepGain;
|
||||
this.startCreateProgramWork = generalMethods.startCreateProgramWork;
|
||||
this.createProgramWork = generalMethods.createProgramWork;
|
||||
this.finishCreateProgramWork = generalMethods.finishCreateProgramWork;
|
||||
this.startClass = generalMethods.startClass;
|
||||
this.takeClass = generalMethods.takeClass;
|
||||
this.finishClass = generalMethods.finishClass;
|
||||
this.startCrime = generalMethods.startCrime;
|
||||
this.commitCrime = generalMethods.commitCrime;
|
||||
this.finishCrime = generalMethods.finishCrime;
|
||||
this.singularityStopWork = generalMethods.singularityStopWork;
|
||||
this.takeDamage = generalMethods.takeDamage;
|
||||
this.regenerateHp = generalMethods.regenerateHp;
|
||||
this.hospitalize = generalMethods.hospitalize;
|
||||
this.applyForJob = generalMethods.applyForJob;
|
||||
this.getNextCompanyPosition = generalMethods.getNextCompanyPosition;
|
||||
this.quitJob = generalMethods.quitJob;
|
||||
this.applyForSoftwareJob = generalMethods.applyForSoftwareJob;
|
||||
this.applyForSoftwareConsultantJob = generalMethods.applyForSoftwareConsultantJob;
|
||||
this.applyForItJob = generalMethods.applyForItJob;
|
||||
this.applyForSecurityEngineerJob = generalMethods.applyForSecurityEngineerJob;
|
||||
this.applyForNetworkEngineerJob = generalMethods.applyForNetworkEngineerJob;
|
||||
this.applyForBusinessJob = generalMethods.applyForBusinessJob;
|
||||
this.applyForBusinessConsultantJob = generalMethods.applyForBusinessConsultantJob;
|
||||
this.applyForSecurityJob = generalMethods.applyForSecurityJob;
|
||||
this.applyForAgentJob = generalMethods.applyForAgentJob;
|
||||
this.applyForEmployeeJob = generalMethods.applyForEmployeeJob;
|
||||
this.applyForPartTimeEmployeeJob = generalMethods.applyForPartTimeEmployeeJob;
|
||||
this.applyForWaiterJob = generalMethods.applyForWaiterJob;
|
||||
this.applyForPartTimeWaiterJob = generalMethods.applyForPartTimeWaiterJob;
|
||||
this.isQualified = generalMethods.isQualified;
|
||||
this.reapplyAllAugmentations = generalMethods.reapplyAllAugmentations;
|
||||
this.reapplyAllSourceFiles = generalMethods.reapplyAllSourceFiles;
|
||||
this.checkForFactionInvitations = generalMethods.checkForFactionInvitations;
|
||||
this.setBitNodeNumber = generalMethods.setBitNodeNumber;
|
||||
this.queueAugmentation = generalMethods.queueAugmentation;
|
||||
this.gainCodingContractReward = generalMethods.gainCodingContractReward;
|
||||
this.travel = generalMethods.travel;
|
||||
this.gotoLocation = generalMethods.gotoLocation;
|
||||
this.canAccessResleeving = generalMethods.canAccessResleeving;
|
||||
this.giveExploit = generalMethods.giveExploit;
|
||||
this.getIntelligenceBonus = generalMethods.getIntelligenceBonus;
|
||||
this.getCasinoWinnings = generalMethods.getCasinoWinnings;
|
||||
this.hasAugmentation = augmentationMethods.hasAugmentation;
|
||||
this.canAccessBladeburner = bladeburnerMethods.canAccessBladeburner;
|
||||
this.inBladeburner = bladeburnerMethods.inBladeburner;
|
||||
this.startBladeburner = bladeburnerMethods.startBladeburner;
|
||||
this.canAccessCorporation = corporationMethods.canAccessCorporation;
|
||||
this.hasCorporation = corporationMethods.hasCorporation;
|
||||
this.startCorporation = corporationMethods.startCorporation;
|
||||
this.canAccessGang = gangMethods.canAccessGang;
|
||||
this.getGangFaction = gangMethods.getGangFaction;
|
||||
this.getGangName = gangMethods.getGangName;
|
||||
this.hasGangWith = gangMethods.hasGangWith;
|
||||
this.inGang = gangMethods.inGang;
|
||||
this.startGang = gangMethods.startGang;
|
||||
|
||||
this.hasTorRouter = serverMethods.hasTorRouter;
|
||||
this.getCurrentServer = serverMethods.getCurrentServer;
|
||||
this.getHomeComputer = serverMethods.getHomeComputer;
|
||||
this.getUpgradeHomeRamCost = serverMethods.getUpgradeHomeRamCost;
|
||||
this.createHacknetServer = serverMethods.createHacknetServer;
|
||||
this.factionWorkType = "";
|
||||
this.committingCrimeThruSingFn = false;
|
||||
this.singFnCrimeWorkerScript = null;
|
||||
|
||||
this.getMult = generalMethods.getMult;
|
||||
this.setMult = generalMethods.setMult;
|
||||
}
|
||||
|
||||
/**
|
||||
* Serialize the current object to a JSON save state.
|
||||
*/
|
||||
toJSON(): any {
|
||||
return Generic_toJSON("PlayerObject", this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initiatizes a PlayerObject object from a JSON save state.
|
||||
*/
|
||||
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
|
||||
static fromJSON(value: any): PlayerObject {
|
||||
return Generic_fromJSON(PlayerObject, value.data);
|
||||
}
|
||||
}
|
||||
|
||||
Reviver.constructors.PlayerObject = PlayerObject;
|
@ -1,7 +1,8 @@
|
||||
import { Bladeburner } from "../../Bladeburner/Bladeburner";
|
||||
import { SourceFileFlags } from "../../SourceFile/SourceFileFlags";
|
||||
import { IPlayer } from "../IPlayer";
|
||||
|
||||
export function canAccessBladeburner() {
|
||||
export function canAccessBladeburner(this: IPlayer) {
|
||||
if (this.bitNodeN === 8) {
|
||||
return false;
|
||||
}
|
||||
@ -9,13 +10,13 @@ export function canAccessBladeburner() {
|
||||
return this.bitNodeN === 6 || this.bitNodeN === 7 || SourceFileFlags[6] > 0 || SourceFileFlags[7] > 0;
|
||||
}
|
||||
|
||||
export function inBladeburner() {
|
||||
export function inBladeburner(this: IPlayer): boolean {
|
||||
if (this.bladeburner == null) {
|
||||
return false;
|
||||
}
|
||||
return this.bladeburner instanceof Bladeburner;
|
||||
}
|
||||
|
||||
export function startBladeburner() {
|
||||
export function startBladeburner(this: IPlayer): void {
|
||||
this.bladeburner = new Bladeburner(this);
|
||||
}
|
@ -1,18 +1,19 @@
|
||||
import { Corporation } from "../../Corporation/Corporation";
|
||||
import { SourceFileFlags } from "../../SourceFile/SourceFileFlags";
|
||||
import { IPlayer } from "../IPlayer";
|
||||
|
||||
export function canAccessCorporation() {
|
||||
export function canAccessCorporation(this: IPlayer): boolean {
|
||||
return this.bitNodeN === 3 || SourceFileFlags[3] > 0;
|
||||
}
|
||||
|
||||
export function hasCorporation() {
|
||||
export function hasCorporation(this: IPlayer): boolean {
|
||||
if (this.corporation == null) {
|
||||
return false;
|
||||
}
|
||||
return this.corporation instanceof Corporation;
|
||||
}
|
||||
|
||||
export function startCorporation(corpName, additionalShares = 0) {
|
||||
export function startCorporation(this: IPlayer, corpName: string, additionalShares = 0): void {
|
||||
this.corporation = new Corporation({
|
||||
name: corpName,
|
||||
});
|
@ -1,53 +0,0 @@
|
||||
import { Factions } from "../../Faction/Factions";
|
||||
import { Gang } from "../../Gang/Gang";
|
||||
import { SourceFileFlags } from "../../SourceFile/SourceFileFlags";
|
||||
import { BitNodeMultipliers } from "../../BitNode/BitNodeMultipliers";
|
||||
|
||||
// Amount of negative karma needed to manage a gang in BitNodes other than 2
|
||||
const GangKarmaRequirement = -54000;
|
||||
|
||||
export function canAccessGang() {
|
||||
if (this.bitNodeN === 2) {
|
||||
return true;
|
||||
}
|
||||
if (SourceFileFlags[2] <= 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return this.karma <= BitNodeMultipliers.GangKarmaRequirement * GangKarmaRequirement;
|
||||
}
|
||||
|
||||
export function getGangFaction() {
|
||||
const fac = Factions[this.gang.facName];
|
||||
if (fac == null) {
|
||||
throw new Error(`Gang has invalid faction name: ${this.gang.facName}`);
|
||||
}
|
||||
|
||||
return fac;
|
||||
}
|
||||
|
||||
export function getGangName() {
|
||||
return this.inGang() ? this.gang.facName : "";
|
||||
}
|
||||
|
||||
export function hasGangWith(facName) {
|
||||
return this.inGang() && this.gang.facName === facName;
|
||||
}
|
||||
|
||||
export function inGang() {
|
||||
if (this.gang == null || this.gang == undefined) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return this.gang instanceof Gang;
|
||||
}
|
||||
|
||||
export function startGang(factionName, hacking) {
|
||||
this.gang = new Gang(factionName, hacking);
|
||||
|
||||
const fac = Factions[factionName];
|
||||
if (fac == null) {
|
||||
throw new Error(`Invalid faction name when creating gang: ${factionName}`);
|
||||
}
|
||||
fac.playerReputation = 0;
|
||||
}
|
69
src/PersonObjects/Player/PlayerObjectGangMethods.ts
Normal file
69
src/PersonObjects/Player/PlayerObjectGangMethods.ts
Normal file
@ -0,0 +1,69 @@
|
||||
import { Factions } from "../../Faction/Factions";
|
||||
import { Faction } from "../../Faction/Faction";
|
||||
import { Gang } from "../../Gang/Gang";
|
||||
import { SourceFileFlags } from "../../SourceFile/SourceFileFlags";
|
||||
import { BitNodeMultipliers } from "../../BitNode/BitNodeMultipliers";
|
||||
import { IPlayer } from "../IPlayer";
|
||||
|
||||
// Amount of negative karma needed to manage a gang in BitNodes other than 2
|
||||
const GangKarmaRequirement = -54000;
|
||||
|
||||
export function canAccessGang(this: IPlayer): boolean {
|
||||
if (this.bitNodeN === 2) {
|
||||
return true;
|
||||
}
|
||||
if (SourceFileFlags[2] <= 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return this.karma <= BitNodeMultipliers.GangKarmaRequirement * GangKarmaRequirement;
|
||||
}
|
||||
|
||||
export function getGangFaction(this: IPlayer): Faction {
|
||||
const gang = this.gang;
|
||||
if (gang === null) {
|
||||
throw new Error("Cannot get gang faction because player is not in a gang.");
|
||||
}
|
||||
const fac = Factions[gang.facName];
|
||||
if (fac == null) {
|
||||
throw new Error(`Gang has invalid faction name: ${gang.facName}`);
|
||||
}
|
||||
|
||||
return fac;
|
||||
}
|
||||
|
||||
export function getGangName(this: IPlayer): string {
|
||||
if (!this.inGang()) return "";
|
||||
const gang = this.gang;
|
||||
if (gang === null) {
|
||||
throw new Error("Cannot get gang faction because player is not in a gang.");
|
||||
}
|
||||
return gang.facName;
|
||||
}
|
||||
|
||||
export function hasGangWith(this: IPlayer, facName: string): boolean {
|
||||
if (!this.inGang()) return false;
|
||||
const gang = this.gang;
|
||||
if (gang === null) {
|
||||
throw new Error("Cannot get gang faction because player is not in a gang.");
|
||||
}
|
||||
return gang.facName === facName;
|
||||
}
|
||||
|
||||
export function inGang(this: IPlayer): boolean {
|
||||
if (this.gang == null || this.gang == undefined) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return this.gang instanceof Gang;
|
||||
}
|
||||
|
||||
export function startGang(this: IPlayer, factionName: string, hacking: boolean): void {
|
||||
this.gang = new Gang(factionName, hacking);
|
||||
|
||||
const fac = Factions[factionName];
|
||||
if (fac == null) {
|
||||
throw new Error(`Invalid faction name when creating gang: ${factionName}`);
|
||||
}
|
||||
fac.playerReputation = 0;
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -15,12 +15,16 @@ export function hasTorRouter(this: IPlayer): boolean {
|
||||
return SpecialServerIps.hasOwnProperty("Darkweb Server");
|
||||
}
|
||||
|
||||
export function getCurrentServer(this: IPlayer): Server | HacknetServer | null {
|
||||
return AllServers[this.currentServer];
|
||||
export function getCurrentServer(this: IPlayer): Server | HacknetServer {
|
||||
const server = AllServers[this.currentServer];
|
||||
if (server === null) throw new Error("somehow connected to a server that does not exist.");
|
||||
return server;
|
||||
}
|
||||
|
||||
export function getHomeComputer(this: IPlayer): Server | HacknetServer | null {
|
||||
return AllServers[this.homeComputer];
|
||||
export function getHomeComputer(this: IPlayer): Server {
|
||||
const home = AllServers[this.homeComputer];
|
||||
if (home instanceof Server) return home;
|
||||
throw new Error("home computer was not a normal server");
|
||||
}
|
||||
|
||||
export function getUpgradeHomeRamCost(this: IPlayer): number {
|
||||
|
3
src/Player.d.ts
vendored
3
src/Player.d.ts
vendored
@ -1,3 +0,0 @@
|
||||
import { IPlayer } from "./PersonObjects/IPlayer";
|
||||
|
||||
export declare let Player: IPlayer;
|
@ -8,7 +8,7 @@ import Decimal from "decimal.js";
|
||||
|
||||
export let Player = new PlayerObject();
|
||||
|
||||
export function loadPlayer(saveString) {
|
||||
export function loadPlayer(saveString: string): void {
|
||||
Player = JSON.parse(saveString, Reviver);
|
||||
|
||||
// Parse Decimal.js objects
|
||||
@ -19,8 +19,8 @@ export function loadPlayer(saveString) {
|
||||
Player.corporation.revenue = new Decimal(Player.corporation.revenue);
|
||||
Player.corporation.expenses = new Decimal(Player.corporation.expenses);
|
||||
|
||||
for (var i = 0; i < Player.corporation.divisions.length; ++i) {
|
||||
var ind = Player.corporation.divisions[i];
|
||||
for (let i = 0; i < Player.corporation.divisions.length; ++i) {
|
||||
const ind = Player.corporation.divisions[i];
|
||||
ind.lastCycleRevenue = new Decimal(ind.lastCycleRevenue);
|
||||
ind.lastCycleExpenses = new Decimal(ind.lastCycleExpenses);
|
||||
ind.thisCycleRevenue = new Decimal(ind.thisCycleRevenue);
|
2
src/Prestige.d.ts
vendored
2
src/Prestige.d.ts
vendored
@ -1,2 +0,0 @@
|
||||
export declare function prestigeAugmentation(): void;
|
||||
export declare function prestigeSourceFile(flume: boolean): void;
|
@ -14,6 +14,7 @@ import { updateHashManagerCapacity } from "./Hacknet/HacknetHelpers";
|
||||
import { initMessages } from "./Message/MessageHelpers";
|
||||
import { prestigeWorkerScripts } from "./NetscriptWorker";
|
||||
import { Player } from "./Player";
|
||||
import { Router } from "./ui/GameRoot";
|
||||
import { resetPidCounter } from "./Netscript/Pid";
|
||||
import { LiteratureNames } from "./Literature/data/LiteratureNames";
|
||||
|
||||
@ -31,7 +32,7 @@ import Decimal from "decimal.js";
|
||||
const BitNode8StartingMoney = 250e6;
|
||||
|
||||
// Prestige by purchasing augmentation
|
||||
function prestigeAugmentation() {
|
||||
function prestigeAugmentation(): void {
|
||||
initBitNodeMultipliers(Player);
|
||||
|
||||
const maintainMembership = Player.factions.filter(function (faction) {
|
||||
@ -42,7 +43,7 @@ function prestigeAugmentation() {
|
||||
// Delete all Worker Scripts objects
|
||||
prestigeWorkerScripts();
|
||||
|
||||
var homeComp = Player.getHomeComputer();
|
||||
const homeComp = Player.getHomeComputer();
|
||||
// Delete all servers except home computer
|
||||
prestigeAllServers();
|
||||
|
||||
@ -70,23 +71,22 @@ function prestigeAugmentation() {
|
||||
initForeignServers(Player.getHomeComputer());
|
||||
|
||||
// Gain favor for Companies
|
||||
for (var member in Companies) {
|
||||
for (const member in Companies) {
|
||||
if (Companies.hasOwnProperty(member)) {
|
||||
Companies[member].gainFavor();
|
||||
}
|
||||
}
|
||||
|
||||
// Gain favor for factions
|
||||
for (var member in Factions) {
|
||||
for (const member in Factions) {
|
||||
if (Factions.hasOwnProperty(member)) {
|
||||
Factions[member].gainFavor();
|
||||
}
|
||||
}
|
||||
|
||||
// Stop a Terminal action if there is onerror
|
||||
if (Engine._actionInProgress) {
|
||||
Engine._actionInProgress = false;
|
||||
Terminal.finishAction(true);
|
||||
if (Terminal.action !== null) {
|
||||
Terminal.finishAction(Router, Player, true);
|
||||
}
|
||||
|
||||
// Re-initialize things - This will update any changes
|
||||
@ -102,8 +102,9 @@ function prestigeAugmentation() {
|
||||
initMessages();
|
||||
|
||||
// Gang
|
||||
if (Player.inGang()) {
|
||||
const faction = Factions[Player.gang.facName];
|
||||
const gang = Player.gang;
|
||||
if (Player.inGang() && gang !== null) {
|
||||
const faction = Factions[gang.facName];
|
||||
if (faction instanceof Faction) {
|
||||
joinFaction(faction);
|
||||
}
|
||||
@ -131,8 +132,12 @@ function prestigeAugmentation() {
|
||||
|
||||
// Red Pill
|
||||
if (augmentationExists(AugmentationNames.TheRedPill) && Augmentations[AugmentationNames.TheRedPill].owned) {
|
||||
var WorldDaemon = AllServers[SpecialServerIps[SpecialServerNames.WorldDaemon]];
|
||||
var DaedalusServer = AllServers[SpecialServerIps[SpecialServerNames.DaedalusServer]];
|
||||
const WorldDaemonIP = SpecialServerIps[SpecialServerNames.WorldDaemon];
|
||||
if (typeof WorldDaemonIP !== "string") throw new Error("WorldDaemonIP should be string");
|
||||
const WorldDaemon = AllServers[WorldDaemonIP];
|
||||
const DaedalusServerIP = SpecialServerIps[SpecialServerNames.DaedalusServer];
|
||||
if (typeof DaedalusServerIP !== "string") throw new Error("DaedalusServerIP should be string");
|
||||
const DaedalusServer = AllServers[DaedalusServerIP];
|
||||
if (WorldDaemon && DaedalusServer) {
|
||||
WorldDaemon.serversOnNetwork.push(DaedalusServer.ip);
|
||||
DaedalusServer.serversOnNetwork.push(WorldDaemon.ip);
|
||||
@ -143,7 +148,7 @@ function prestigeAugmentation() {
|
||||
}
|
||||
|
||||
// Prestige by destroying Bit Node and gaining a Source File
|
||||
function prestigeSourceFile(flume) {
|
||||
function prestigeSourceFile(flume: boolean): void {
|
||||
initBitNodeMultipliers(Player);
|
||||
updateSourceFileFlags(Player);
|
||||
|
||||
@ -189,9 +194,8 @@ function prestigeSourceFile(flume) {
|
||||
}
|
||||
|
||||
// Stop a Terminal action if there is one
|
||||
if (Engine._actionInProgress) {
|
||||
Engine._actionInProgress = false;
|
||||
Terminal.finishAction(true);
|
||||
if (Terminal.action !== null) {
|
||||
Terminal.finishAction(Router, Player, true);
|
||||
}
|
||||
|
||||
// Delete all Augmentations
|
||||
@ -249,7 +253,6 @@ function prestigeSourceFile(flume) {
|
||||
deleteStockMarket();
|
||||
}
|
||||
|
||||
if (Player.inGang()) clearGangUI();
|
||||
Player.gang = null;
|
||||
Player.corporation = null;
|
||||
resetIndustryResearchTrees();
|
@ -53,10 +53,9 @@ export const programsMetadata: IProgramCreationParams[] = [
|
||||
terminal.print("You already have root access to this computer. There is no reason to run NUKE.exe");
|
||||
return;
|
||||
}
|
||||
|
||||
if (server.openPortCount >= player.getCurrentServer().numOpenPortsRequired) {
|
||||
if (server.openPortCount >= server.numOpenPortsRequired) {
|
||||
server.hasAdminRights = true;
|
||||
terminal.print("NUKE successful! Gained root access to " + player.getCurrentServer().hostname);
|
||||
terminal.print("NUKE successful! Gained root access to " + server.hostname);
|
||||
// TODO: Make this take time rather than be instant
|
||||
return;
|
||||
}
|
||||
|
3
src/RedPill.d.ts
vendored
3
src/RedPill.d.ts
vendored
@ -1,3 +0,0 @@
|
||||
export declare let redPillFlag: boolean;
|
||||
export declare function enterBitNode(router: IRouter, flume: boolean, destroyedBitNode: number, newBitNode: number);
|
||||
export declare function setRedPillFlag(b: boolean): void;
|
@ -8,14 +8,15 @@ import { SourceFileFlags } from "./SourceFile/SourceFileFlags";
|
||||
import { SourceFiles } from "./SourceFile/SourceFiles";
|
||||
|
||||
import { dialogBoxCreate } from "../utils/DialogBox";
|
||||
import { IRouter } from "./ui/Router";
|
||||
|
||||
export let redPillFlag = false;
|
||||
|
||||
export function setRedPillFlag(b) {
|
||||
export function setRedPillFlag(b: boolean): void {
|
||||
redPillFlag = b;
|
||||
}
|
||||
|
||||
function giveSourceFile(bitNodeNumber) {
|
||||
function giveSourceFile(bitNodeNumber: number): void {
|
||||
var sourceFileKey = "SourceFile" + bitNodeNumber.toString();
|
||||
var sourceFile = SourceFiles[sourceFileKey];
|
||||
if (sourceFile == null) {
|
||||
@ -62,7 +63,7 @@ function giveSourceFile(bitNodeNumber) {
|
||||
}
|
||||
}
|
||||
|
||||
export function enterBitNode(router, flume, destroyedBitNode, newBitNode) {
|
||||
export function enterBitNode(router: IRouter, flume: boolean, destroyedBitNode: number, newBitNode: number): void {
|
||||
if (!flume) {
|
||||
giveSourceFile(destroyedBitNode);
|
||||
} else {
|
@ -27,90 +27,125 @@ import Decimal from "decimal.js";
|
||||
/* SaveObject.js
|
||||
* Defines the object used to save/load games
|
||||
*/
|
||||
let saveObject = new BitburnerSaveObject();
|
||||
|
||||
function BitburnerSaveObject() {
|
||||
this.PlayerSave = "";
|
||||
this.AllServersSave = "";
|
||||
this.CompaniesSave = "";
|
||||
this.FactionsSave = "";
|
||||
this.SpecialServerIpsSave = "";
|
||||
this.AliasesSave = "";
|
||||
this.GlobalAliasesSave = "";
|
||||
this.MessagesSave = "";
|
||||
this.StockMarketSave = "";
|
||||
this.SettingsSave = "";
|
||||
this.VersionSave = "";
|
||||
this.AllGangsSave = "";
|
||||
this.LastExportBonus = "";
|
||||
class BitburnerSaveObject {
|
||||
PlayerSave = "";
|
||||
AllServersSave = "";
|
||||
CompaniesSave = "";
|
||||
FactionsSave = "";
|
||||
SpecialServerIpsSave = "";
|
||||
AliasesSave = "";
|
||||
GlobalAliasesSave = "";
|
||||
MessagesSave = "";
|
||||
StockMarketSave = "";
|
||||
SettingsSave = "";
|
||||
VersionSave = "";
|
||||
AllGangsSave = "";
|
||||
LastExportBonus = "";
|
||||
|
||||
getSaveString(): string {
|
||||
this.PlayerSave = JSON.stringify(Player);
|
||||
|
||||
// Delete all logs from all running scripts
|
||||
var TempAllServers = JSON.parse(JSON.stringify(AllServers), Reviver);
|
||||
for (var ip in TempAllServers) {
|
||||
var server = TempAllServers[ip];
|
||||
if (server == null) {
|
||||
continue;
|
||||
}
|
||||
for (var i = 0; i < server.runningScripts.length; ++i) {
|
||||
var runningScriptObj = server.runningScripts[i];
|
||||
runningScriptObj.logs.length = 0;
|
||||
runningScriptObj.logs = [];
|
||||
}
|
||||
}
|
||||
|
||||
this.AllServersSave = JSON.stringify(TempAllServers);
|
||||
this.CompaniesSave = JSON.stringify(Companies);
|
||||
this.FactionsSave = JSON.stringify(Factions);
|
||||
this.SpecialServerIpsSave = JSON.stringify(SpecialServerIps);
|
||||
this.AliasesSave = JSON.stringify(Aliases);
|
||||
this.GlobalAliasesSave = JSON.stringify(GlobalAliases);
|
||||
this.MessagesSave = JSON.stringify(Messages);
|
||||
this.StockMarketSave = JSON.stringify(StockMarket);
|
||||
this.SettingsSave = JSON.stringify(Settings);
|
||||
this.VersionSave = JSON.stringify(CONSTANTS.Version);
|
||||
this.LastExportBonus = JSON.stringify(ExportBonus.LastExportBonus);
|
||||
if (Player.inGang()) {
|
||||
this.AllGangsSave = JSON.stringify(AllGangs);
|
||||
}
|
||||
var saveString = btoa(unescape(encodeURIComponent(JSON.stringify(this))));
|
||||
|
||||
return saveString;
|
||||
}
|
||||
|
||||
saveGame(): void {
|
||||
const saveString = this.getSaveString();
|
||||
|
||||
save(saveString)
|
||||
.then(() => createStatusText("Game saved!"))
|
||||
.catch((err) => console.error(err));
|
||||
}
|
||||
|
||||
exportGame(): void {
|
||||
const saveString = this.getSaveString();
|
||||
|
||||
// Save file name is based on current timestamp and BitNode
|
||||
const epochTime = Math.round(Date.now() / 1000);
|
||||
const bn = Player.bitNodeN;
|
||||
const filename = `bitburnerSave_BN${bn}x${SourceFileFlags[bn]}_${epochTime}.json`;
|
||||
var file = new Blob([saveString], { type: "text/plain" });
|
||||
if (window.navigator.msSaveOrOpenBlob) {
|
||||
// IE10+
|
||||
window.navigator.msSaveOrOpenBlob(file, filename);
|
||||
} else {
|
||||
// Others
|
||||
var a = document.createElement("a"),
|
||||
url = URL.createObjectURL(file);
|
||||
a.href = url;
|
||||
a.download = filename;
|
||||
document.body.appendChild(a);
|
||||
a.click();
|
||||
setTimeoutRef(function () {
|
||||
document.body.removeChild(a);
|
||||
window.URL.revokeObjectURL(url);
|
||||
}, 0);
|
||||
}
|
||||
}
|
||||
|
||||
toJSON(): any {
|
||||
return Generic_toJSON("BitburnerSaveObject", this);
|
||||
}
|
||||
|
||||
static fromJSON(value: { data: any }): BitburnerSaveObject {
|
||||
return Generic_fromJSON(BitburnerSaveObject, value.data);
|
||||
}
|
||||
}
|
||||
|
||||
BitburnerSaveObject.prototype.getSaveString = function () {
|
||||
this.PlayerSave = JSON.stringify(Player);
|
||||
|
||||
// Delete all logs from all running scripts
|
||||
var TempAllServers = JSON.parse(JSON.stringify(AllServers), Reviver);
|
||||
for (var ip in TempAllServers) {
|
||||
var server = TempAllServers[ip];
|
||||
if (server == null) {
|
||||
continue;
|
||||
}
|
||||
for (var i = 0; i < server.runningScripts.length; ++i) {
|
||||
var runningScriptObj = server.runningScripts[i];
|
||||
runningScriptObj.logs.length = 0;
|
||||
runningScriptObj.logs = [];
|
||||
}
|
||||
}
|
||||
|
||||
this.AllServersSave = JSON.stringify(TempAllServers);
|
||||
this.CompaniesSave = JSON.stringify(Companies);
|
||||
this.FactionsSave = JSON.stringify(Factions);
|
||||
this.SpecialServerIpsSave = JSON.stringify(SpecialServerIps);
|
||||
this.AliasesSave = JSON.stringify(Aliases);
|
||||
this.GlobalAliasesSave = JSON.stringify(GlobalAliases);
|
||||
this.MessagesSave = JSON.stringify(Messages);
|
||||
this.StockMarketSave = JSON.stringify(StockMarket);
|
||||
this.SettingsSave = JSON.stringify(Settings);
|
||||
this.VersionSave = JSON.stringify(CONSTANTS.Version);
|
||||
this.LastExportBonus = JSON.stringify(ExportBonus.LastExportBonus);
|
||||
if (Player.inGang()) {
|
||||
this.AllGangsSave = JSON.stringify(AllGangs);
|
||||
}
|
||||
var saveString = btoa(unescape(encodeURIComponent(JSON.stringify(this))));
|
||||
|
||||
return saveString;
|
||||
};
|
||||
|
||||
BitburnerSaveObject.prototype.saveGame = function () {
|
||||
const saveString = this.getSaveString();
|
||||
|
||||
save(saveString)
|
||||
.then(() => createStatusText("Game saved!"))
|
||||
.catch((err) => console.error(err));
|
||||
};
|
||||
|
||||
// Makes necessary changes to the loaded/imported data to ensure
|
||||
// the game stills works with new versions
|
||||
function evaluateVersionCompatibility(ver) {
|
||||
function evaluateVersionCompatibility(ver: string) {
|
||||
// We have to do this because ts won't let us otherwise
|
||||
const anyPlayer = Player as any;
|
||||
// This version refactored the Company/job-related code
|
||||
if (ver <= "0.41.2") {
|
||||
// Player's company position is now a string
|
||||
if (Player.companyPosition != null && typeof Player.companyPosition !== "string") {
|
||||
Player.companyPosition = Player.companyPosition.data.positionName;
|
||||
if (Player.companyPosition == null) {
|
||||
Player.companyPosition = "";
|
||||
if (anyPlayer.companyPosition != null && typeof anyPlayer.companyPosition !== "string") {
|
||||
anyPlayer.companyPosition = anyPlayer.companyPosition.data.positionName;
|
||||
if (anyPlayer.companyPosition == null) {
|
||||
anyPlayer.companyPosition = "";
|
||||
}
|
||||
}
|
||||
|
||||
// The "companyName" property of all Companies is renamed to "name"
|
||||
for (var companyName in Companies) {
|
||||
const company = Companies[companyName];
|
||||
if ((company.name == null || company.name === 0 || company.name === "") && company.companyName != null) {
|
||||
for (const companyName in Companies) {
|
||||
const company: any = Companies[companyName];
|
||||
if (company.name == 0 && company.companyName != null) {
|
||||
company.name = company.companyName;
|
||||
}
|
||||
|
||||
if (company.companyPositions instanceof Array) {
|
||||
const pos = {};
|
||||
const pos: any = {};
|
||||
|
||||
for (let i = 0; i < company.companyPositions.length; ++i) {
|
||||
pos[company.companyPositions[i]] = true;
|
||||
@ -122,15 +157,15 @@ function evaluateVersionCompatibility(ver) {
|
||||
|
||||
// This version allowed players to hold multiple jobs
|
||||
if (ver < "0.43.0") {
|
||||
if (Player.companyName !== "" && Player.companyPosition != null && Player.companyPosition !== "") {
|
||||
Player.jobs[Player.companyName] = Player.companyPosition;
|
||||
if (anyPlayer.companyName !== "" && anyPlayer.companyPosition != null && anyPlayer.companyPosition !== "") {
|
||||
anyPlayer.jobs[anyPlayer.companyName] = anyPlayer.companyPosition;
|
||||
}
|
||||
|
||||
delete Player.companyPosition;
|
||||
delete anyPlayer.companyPosition;
|
||||
}
|
||||
}
|
||||
|
||||
function loadGame(saveString) {
|
||||
function loadGame(saveString: string): boolean {
|
||||
if (!saveString) return false;
|
||||
saveString = decodeURIComponent(escape(atob(saveString)));
|
||||
|
||||
@ -230,32 +265,6 @@ function loadGame(saveString) {
|
||||
return true;
|
||||
}
|
||||
|
||||
BitburnerSaveObject.prototype.exportGame = function () {
|
||||
const saveString = this.getSaveString();
|
||||
|
||||
// Save file name is based on current timestamp and BitNode
|
||||
const epochTime = Math.round(Date.now() / 1000);
|
||||
const bn = Player.bitNodeN;
|
||||
const filename = `bitburnerSave_BN${bn}x${SourceFileFlags[bn]}_${epochTime}.json`;
|
||||
var file = new Blob([saveString], { type: "text/plain" });
|
||||
if (window.navigator.msSaveOrOpenBlob) {
|
||||
// IE10+
|
||||
window.navigator.msSaveOrOpenBlob(file, filename);
|
||||
} else {
|
||||
// Others
|
||||
var a = document.createElement("a"),
|
||||
url = URL.createObjectURL(file);
|
||||
a.href = url;
|
||||
a.download = filename;
|
||||
document.body.appendChild(a);
|
||||
a.click();
|
||||
setTimeoutRef(function () {
|
||||
document.body.removeChild(a);
|
||||
window.URL.revokeObjectURL(url);
|
||||
}, 0);
|
||||
}
|
||||
};
|
||||
|
||||
function createNewUpdateText() {
|
||||
dialogBoxCreate(
|
||||
"New update!<br>" +
|
||||
@ -275,14 +284,8 @@ function createBetaUpdateText() {
|
||||
);
|
||||
}
|
||||
|
||||
BitburnerSaveObject.prototype.toJSON = function () {
|
||||
return Generic_toJSON("BitburnerSaveObject", this);
|
||||
};
|
||||
|
||||
BitburnerSaveObject.fromJSON = function (value) {
|
||||
return Generic_fromJSON(BitburnerSaveObject, value.data);
|
||||
};
|
||||
|
||||
Reviver.constructors.BitburnerSaveObject = BitburnerSaveObject;
|
||||
|
||||
export { saveObject, loadGame };
|
||||
|
||||
let saveObject = new BitburnerSaveObject();
|
3
src/Script/RamCalculations.d.ts
vendored
3
src/Script/RamCalculations.d.ts
vendored
@ -1,3 +0,0 @@
|
||||
import { Script } from "./Script";
|
||||
|
||||
export declare function calculateRamUsage(codeCopy: string, otherScripts: Script[]): number;
|
@ -11,6 +11,8 @@ import { parse } from "acorn";
|
||||
import { RamCalculationErrorCode } from "./RamCalculationErrorCodes";
|
||||
|
||||
import { RamCosts, RamCostConstants } from "../Netscript/RamCostGenerator";
|
||||
import { Script } from "../Script/Script";
|
||||
import { WorkerScript } from "../Netscript/WorkerScript";
|
||||
|
||||
// These special strings are used to reference the presence of a given logical
|
||||
// construct within a user script.
|
||||
@ -29,7 +31,11 @@ const memCheckGlobalKey = ".__GLOBAL__";
|
||||
* @param {WorkerScript} workerScript - Object containing RAM costs of Netscript functions. Also used to
|
||||
* keep track of what functions have/havent been accounted for
|
||||
*/
|
||||
async function parseOnlyRamCalculate(otherScripts, code, workerScript) {
|
||||
async function parseOnlyRamCalculate(
|
||||
otherScripts: Script[],
|
||||
code: string,
|
||||
workerScript: WorkerScript,
|
||||
): Promise<number | RamCalculationErrorCode> {
|
||||
try {
|
||||
/**
|
||||
* Maps dependent identifiers to their dependencies.
|
||||
@ -41,16 +47,16 @@ async function parseOnlyRamCalculate(otherScripts, code, workerScript) {
|
||||
* We walk the dependency graph to calculate RAM usage, given that some identifiers
|
||||
* reference Netscript functions which have a RAM cost.
|
||||
*/
|
||||
let dependencyMap = {};
|
||||
let dependencyMap: { [key: string]: string[] } = {};
|
||||
|
||||
// Scripts we've parsed.
|
||||
const completedParses = new Set();
|
||||
|
||||
// Scripts we've discovered that need to be parsed.
|
||||
const parseQueue = [];
|
||||
const parseQueue: string[] = [];
|
||||
|
||||
// Parses a chunk of code with a given module name, and updates parseQueue and dependencyMap.
|
||||
function parseCode(code, moduleName) {
|
||||
function parseCode(code: string, moduleName: string): void {
|
||||
const result = parseOnlyCalculateDeps(code, moduleName);
|
||||
completedParses.add(moduleName);
|
||||
|
||||
@ -72,6 +78,7 @@ async function parseOnlyRamCalculate(otherScripts, code, workerScript) {
|
||||
// Process additional modules, which occurs if the "main" script has any imports
|
||||
while (parseQueue.length > 0) {
|
||||
const nextModule = parseQueue.shift();
|
||||
if (nextModule === undefined) throw new Error("nextModule should not be undefined");
|
||||
|
||||
// Additional modules can either be imported from the web (in which case we use
|
||||
// a dynamic import), or from other in-game scripts
|
||||
@ -122,6 +129,7 @@ async function parseOnlyRamCalculate(otherScripts, code, workerScript) {
|
||||
const resolvedRefs = new Set();
|
||||
while (unresolvedRefs.length > 0) {
|
||||
const ref = unresolvedRefs.shift();
|
||||
if (ref === undefined) throw new Error("ref should not be undefined");
|
||||
|
||||
// Check if this is one of the special keys, and add the appropriate ram cost if so.
|
||||
if (ref === "hacknet" && !resolvedRefs.has("hacknet")) {
|
||||
@ -154,7 +162,7 @@ async function parseOnlyRamCalculate(otherScripts, code, workerScript) {
|
||||
// Check if this identifier is a function in the workerScript environment.
|
||||
// If it is, then we need to get its RAM cost.
|
||||
try {
|
||||
function applyFuncRam(func) {
|
||||
function applyFuncRam(func: any) {
|
||||
if (typeof func === "function") {
|
||||
try {
|
||||
let res;
|
||||
@ -216,27 +224,28 @@ async function parseOnlyRamCalculate(otherScripts, code, workerScript) {
|
||||
* for RAM usage calculations. It also returns an array of additional modules
|
||||
* that need to be parsed (i.e. are 'import'ed scripts).
|
||||
*/
|
||||
function parseOnlyCalculateDeps(code, currentModule) {
|
||||
function parseOnlyCalculateDeps(code: string, currentModule: string): any {
|
||||
const ast = parse(code, { sourceType: "module", ecmaVersion: "latest" });
|
||||
|
||||
// Everything from the global scope goes in ".". Everything else goes in ".function", where only
|
||||
// the outermost layer of functions counts.
|
||||
const globalKey = currentModule + memCheckGlobalKey;
|
||||
const dependencyMap = {};
|
||||
dependencyMap[globalKey] = new Set();
|
||||
const dependencyMap: { [key: string]: Set<string> | undefined } = {};
|
||||
dependencyMap[globalKey] = new Set<string>();
|
||||
|
||||
// If we reference this internal name, we're really referencing that external name.
|
||||
// Filled when we import names from other modules.
|
||||
let internalToExternal = {};
|
||||
let internalToExternal: { [key: string]: string | undefined } = {};
|
||||
|
||||
var additionalModules = [];
|
||||
let additionalModules: string[] = [];
|
||||
|
||||
// References get added pessimistically. They are added for thisModule.name, name, and for
|
||||
// any aliases.
|
||||
function addRef(key, name) {
|
||||
function addRef(key: string, name: string): void {
|
||||
const s = dependencyMap[key] || (dependencyMap[key] = new Set());
|
||||
if (name in internalToExternal) {
|
||||
s.add(internalToExternal[name]);
|
||||
const external = internalToExternal[name];
|
||||
if (external !== undefined) {
|
||||
s.add(external);
|
||||
}
|
||||
s.add(currentModule + "." + name);
|
||||
s.add(name); // For builtins like hack.
|
||||
@ -249,36 +258,36 @@ function parseOnlyCalculateDeps(code, currentModule) {
|
||||
// walkDeeper is for doing recursive walks of expressions in composites that we handle.
|
||||
function commonVisitors() {
|
||||
return {
|
||||
Identifier: (node, st) => {
|
||||
Identifier: (node: any, st: any) => {
|
||||
if (objectPrototypeProperties.includes(node.name)) {
|
||||
return;
|
||||
}
|
||||
addRef(st.key, node.name);
|
||||
},
|
||||
WhileStatement: (node, st, walkDeeper) => {
|
||||
WhileStatement: (node: any, st: any, walkDeeper: any) => {
|
||||
addRef(st.key, specialReferenceWHILE);
|
||||
node.test && walkDeeper(node.test, st);
|
||||
node.body && walkDeeper(node.body, st);
|
||||
},
|
||||
DoWhileStatement: (node, st, walkDeeper) => {
|
||||
DoWhileStatement: (node: any, st: any, walkDeeper: any) => {
|
||||
addRef(st.key, specialReferenceWHILE);
|
||||
node.test && walkDeeper(node.test, st);
|
||||
node.body && walkDeeper(node.body, st);
|
||||
},
|
||||
ForStatement: (node, st, walkDeeper) => {
|
||||
ForStatement: (node: any, st: any, walkDeeper: any) => {
|
||||
addRef(st.key, specialReferenceFOR);
|
||||
node.init && walkDeeper(node.init, st);
|
||||
node.test && walkDeeper(node.test, st);
|
||||
node.update && walkDeeper(node.update, st);
|
||||
node.body && walkDeeper(node.body, st);
|
||||
},
|
||||
IfStatement: (node, st, walkDeeper) => {
|
||||
IfStatement: (node: any, st: any, walkDeeper: any) => {
|
||||
addRef(st.key, specialReferenceIF);
|
||||
node.test && walkDeeper(node.test, st);
|
||||
node.consequent && walkDeeper(node.consequent, st);
|
||||
node.alternate && walkDeeper(node.alternate, st);
|
||||
},
|
||||
MemberExpression: (node, st, walkDeeper) => {
|
||||
MemberExpression: (node: any, st: any, walkDeeper: any) => {
|
||||
node.object && walkDeeper(node.object, st);
|
||||
node.property && walkDeeper(node.property, st);
|
||||
},
|
||||
@ -290,13 +299,15 @@ function parseOnlyCalculateDeps(code, currentModule) {
|
||||
{ key: globalKey },
|
||||
Object.assign(
|
||||
{
|
||||
ImportDeclaration: (node, st) => {
|
||||
ImportDeclaration: (node: any, st: any) => {
|
||||
const importModuleName = node.source.value;
|
||||
additionalModules.push(importModuleName);
|
||||
|
||||
// This module's global scope refers to that module's global scope, no matter how we
|
||||
// import it.
|
||||
dependencyMap[st.key].add(importModuleName + memCheckGlobalKey);
|
||||
const set = dependencyMap[st.key];
|
||||
if (set === undefined) throw new Error("set should not be undefined");
|
||||
set.add(importModuleName + memCheckGlobalKey);
|
||||
|
||||
for (let i = 0; i < node.specifiers.length; ++i) {
|
||||
const spec = node.specifiers[i];
|
||||
@ -305,11 +316,13 @@ function parseOnlyCalculateDeps(code, currentModule) {
|
||||
internalToExternal[spec.local.name] = importModuleName + "." + spec.imported.name;
|
||||
} else {
|
||||
// We depend on everything.
|
||||
dependencyMap[st.key].add(importModuleName + ".*");
|
||||
const set = dependencyMap[st.key];
|
||||
if (set === undefined) throw new Error("set should not be undefined");
|
||||
set.add(importModuleName + ".*");
|
||||
}
|
||||
}
|
||||
},
|
||||
FunctionDeclaration: (node) => {
|
||||
FunctionDeclaration: (node: any) => {
|
||||
const key = currentModule + "." + node.id.name;
|
||||
walk.recursive(node, { key: key }, commonVisitors());
|
||||
},
|
||||
@ -327,7 +340,10 @@ function parseOnlyCalculateDeps(code, currentModule) {
|
||||
* @param {Script[]} otherScripts - All other scripts on the server.
|
||||
* Used to account for imported scripts
|
||||
*/
|
||||
export async function calculateRamUsage(codeCopy, otherScripts) {
|
||||
export async function calculateRamUsage(
|
||||
codeCopy: string,
|
||||
otherScripts: Script[],
|
||||
): Promise<RamCalculationErrorCode | number> {
|
||||
// We don't need a real WorkerScript for this. Just an object that keeps
|
||||
// track of whatever's needed for RAM calculations
|
||||
const workerScript = {
|
||||
@ -335,7 +351,7 @@ export async function calculateRamUsage(codeCopy, otherScripts) {
|
||||
env: {
|
||||
vars: RamCosts,
|
||||
},
|
||||
};
|
||||
} as WorkerScript;
|
||||
|
||||
try {
|
||||
return await parseOnlyRamCalculate(otherScripts, codeCopy, workerScript);
|
@ -3,7 +3,6 @@
|
||||
* A Script can have multiple active instances
|
||||
*/
|
||||
import { Script } from "./Script";
|
||||
import { FconfSettings } from "../Fconf/FconfSettings";
|
||||
import { Settings } from "../Settings/Settings";
|
||||
import { IMap } from "../types";
|
||||
import { Terminal } from "../Terminal";
|
||||
|
6
src/Script/ScriptHelpers.d.ts
vendored
6
src/Script/ScriptHelpers.d.ts
vendored
@ -1,6 +0,0 @@
|
||||
export declare function findRunningScript(
|
||||
filename: string,
|
||||
args: (string | number)[],
|
||||
server: BaseServer,
|
||||
): RunningScript | null;
|
||||
export declare function findRunningScriptByPid(pid: number, server: BaseServer): RunningScript | null;
|
@ -1,13 +1,16 @@
|
||||
import { CONSTANTS } from "../Constants";
|
||||
import { Player } from "../Player";
|
||||
import { AllServers } from "../Server/AllServers";
|
||||
import { BaseServer } from "../Server/BaseServer";
|
||||
import { Server } from "../Server/Server";
|
||||
import { RunningScript } from "../Script/RunningScript";
|
||||
import { processSingleServerGrowth } from "../Server/ServerHelpers";
|
||||
|
||||
import { numeralWrapper } from "../ui/numeralFormat";
|
||||
|
||||
import { compareArrays } from "../../utils/helpers/compareArrays";
|
||||
|
||||
export function scriptCalculateOfflineProduction(runningScriptObj) {
|
||||
export function scriptCalculateOfflineProduction(runningScript: RunningScript) {
|
||||
//The Player object stores the last update time from when we were online
|
||||
const thisUpdate = new Date().getTime();
|
||||
const lastUpdate = Player.lastUpdate;
|
||||
@ -16,7 +19,7 @@ export function scriptCalculateOfflineProduction(runningScriptObj) {
|
||||
//Calculate the "confidence" rating of the script's true production. This is based
|
||||
//entirely off of time. We will arbitrarily say that if a script has been running for
|
||||
//4 hours (14400 sec) then we are completely confident in its ability
|
||||
let confidence = runningScriptObj.onlineRunningTime / 14400;
|
||||
let confidence = runningScript.onlineRunningTime / 14400;
|
||||
if (confidence >= 1) {
|
||||
confidence = 1;
|
||||
}
|
||||
@ -24,9 +27,9 @@ export function scriptCalculateOfflineProduction(runningScriptObj) {
|
||||
//Data map: [MoneyStolen, NumTimesHacked, NumTimesGrown, NumTimesWeaken]
|
||||
|
||||
// Grow
|
||||
for (const ip in runningScriptObj.dataMap) {
|
||||
if (runningScriptObj.dataMap.hasOwnProperty(ip)) {
|
||||
if (runningScriptObj.dataMap[ip][2] == 0 || runningScriptObj.dataMap[ip][2] == null) {
|
||||
for (const ip in runningScript.dataMap) {
|
||||
if (runningScript.dataMap.hasOwnProperty(ip)) {
|
||||
if (runningScript.dataMap[ip][2] == 0 || runningScript.dataMap[ip][2] == null) {
|
||||
continue;
|
||||
}
|
||||
const serv = AllServers[ip];
|
||||
@ -34,12 +37,13 @@ export function scriptCalculateOfflineProduction(runningScriptObj) {
|
||||
continue;
|
||||
}
|
||||
const timesGrown = Math.round(
|
||||
((0.5 * runningScriptObj.dataMap[ip][2]) / runningScriptObj.onlineRunningTime) * timePassed,
|
||||
((0.5 * runningScript.dataMap[ip][2]) / runningScript.onlineRunningTime) * timePassed,
|
||||
);
|
||||
runningScriptObj.log(`Called on ${serv.hostname} ${timesGrown} times while offline`);
|
||||
const host = AllServers[runningScriptObj.server];
|
||||
runningScript.log(`Called on ${serv.hostname} ${timesGrown} times while offline`);
|
||||
const host = AllServers[runningScript.server];
|
||||
if (!(serv instanceof Server)) throw new Error("trying to grow a non-normal server");
|
||||
const growth = processSingleServerGrowth(serv, timesGrown, Player, host.cpuCores);
|
||||
runningScriptObj.log(
|
||||
runningScript.log(
|
||||
`'${serv.hostname}' grown by ${numeralWrapper.format(growth * 100 - 100, "0.000000%")} while offline`,
|
||||
);
|
||||
}
|
||||
@ -47,28 +51,30 @@ export function scriptCalculateOfflineProduction(runningScriptObj) {
|
||||
|
||||
// Offline EXP gain
|
||||
// A script's offline production will always be at most half of its online production.
|
||||
const expGain = confidence * (runningScriptObj.onlineExpGained / runningScriptObj.onlineRunningTime) * timePassed;
|
||||
const expGain = confidence * (runningScript.onlineExpGained / runningScript.onlineRunningTime) * timePassed;
|
||||
Player.gainHackingExp(expGain);
|
||||
|
||||
// Update script stats
|
||||
runningScriptObj.offlineRunningTime += timePassed;
|
||||
runningScriptObj.offlineExpGained += expGain;
|
||||
runningScript.offlineRunningTime += timePassed;
|
||||
runningScript.offlineExpGained += expGain;
|
||||
|
||||
// Weaken
|
||||
for (const ip in runningScriptObj.dataMap) {
|
||||
if (runningScriptObj.dataMap.hasOwnProperty(ip)) {
|
||||
if (runningScriptObj.dataMap[ip][3] == 0 || runningScriptObj.dataMap[ip][3] == null) {
|
||||
for (const ip in runningScript.dataMap) {
|
||||
if (runningScript.dataMap.hasOwnProperty(ip)) {
|
||||
if (runningScript.dataMap[ip][3] == 0 || runningScript.dataMap[ip][3] == null) {
|
||||
continue;
|
||||
}
|
||||
const serv = AllServers[ip];
|
||||
if (serv == null) {
|
||||
continue;
|
||||
}
|
||||
const host = AllServers[runningScriptObj.server];
|
||||
|
||||
if (!(serv instanceof Server)) throw new Error("trying to weaken a non-normal server");
|
||||
const host = AllServers[runningScript.server];
|
||||
const timesWeakened = Math.round(
|
||||
((0.5 * runningScriptObj.dataMap[ip][3]) / runningScriptObj.onlineRunningTime) * timePassed,
|
||||
((0.5 * runningScript.dataMap[ip][3]) / runningScript.onlineRunningTime) * timePassed,
|
||||
);
|
||||
runningScriptObj.log(`Called weaken() on ${serv.hostname} ${timesWeakened} times while offline`);
|
||||
runningScript.log(`Called weaken() on ${serv.hostname} ${timesWeakened} times while offline`);
|
||||
const coreBonus = 1 + (host.cpuCores - 1) / 16;
|
||||
serv.weaken(CONSTANTS.ServerWeakenAmount * timesWeakened * coreBonus);
|
||||
}
|
||||
@ -77,7 +83,7 @@ export function scriptCalculateOfflineProduction(runningScriptObj) {
|
||||
|
||||
//Returns a RunningScript object matching the filename and arguments on the
|
||||
//designated server, and false otherwise
|
||||
export function findRunningScript(filename, args, server) {
|
||||
export function findRunningScript(filename: string, args: (string | number)[], server: BaseServer) {
|
||||
for (var i = 0; i < server.runningScripts.length; ++i) {
|
||||
if (server.runningScripts[i].filename === filename && compareArrays(server.runningScripts[i].args, args)) {
|
||||
return server.runningScripts[i];
|
||||
@ -88,7 +94,7 @@ export function findRunningScript(filename, args, server) {
|
||||
|
||||
//Returns a RunningScript object matching the pid on the
|
||||
//designated server, and false otherwise
|
||||
export function findRunningScriptByPid(pid, server) {
|
||||
export function findRunningScriptByPid(pid: number, server: BaseServer) {
|
||||
for (var i = 0; i < server.runningScripts.length; ++i) {
|
||||
if (server.runningScripts[i].pid === pid) {
|
||||
return server.runningScripts[i];
|
@ -1,4 +1,3 @@
|
||||
// Script helper functions
|
||||
export function isScriptFilename(f: string): boolean {
|
||||
return f.endsWith(".js") || f.endsWith(".script") || f.endsWith(".ns");
|
||||
}
|
@ -11,8 +11,7 @@ import { isValidFilePath } from "../../Terminal/DirectoryHelpers";
|
||||
import { IPlayer } from "../../PersonObjects/IPlayer";
|
||||
import { IRouter } from "../../ui/Router";
|
||||
import { dialogBoxCreate } from "../../../utils/DialogBox";
|
||||
import { parseFconfSettings } from "../../Fconf/Fconf";
|
||||
import { isScriptFilename } from "../../Script/ScriptHelpersTS";
|
||||
import { isScriptFilename } from "../../Script/isScriptFilename";
|
||||
import { Script } from "../../Script/Script";
|
||||
import { TextFile } from "../../TextFile";
|
||||
import { calculateRamUsage } from "../../Script/RamCalculations";
|
||||
@ -144,7 +143,7 @@ export function Root(props: IProps): React.ReactElement {
|
||||
return;
|
||||
}
|
||||
|
||||
if (filename !== ".fconf" && !isValidFilePath(filename)) {
|
||||
if (!isValidFilePath(filename)) {
|
||||
dialogBoxCreate(
|
||||
"Script filename can contain only alphanumerics, hyphens, and underscores, and must end with an extension.",
|
||||
);
|
||||
@ -153,14 +152,7 @@ export function Root(props: IProps): React.ReactElement {
|
||||
|
||||
const server = props.player.getCurrentServer();
|
||||
if (server === null) throw new Error("Server should not be null but it is.");
|
||||
if (filename === ".fconf") {
|
||||
try {
|
||||
parseFconfSettings(code);
|
||||
} catch (e) {
|
||||
dialogBoxCreate(`Invalid .fconf file: ${e}`);
|
||||
return;
|
||||
}
|
||||
} else if (isScriptFilename(filename)) {
|
||||
if (isScriptFilename(filename)) {
|
||||
//If the current script already exists on the server, overwrite it
|
||||
for (let i = 0; i < server.scripts.length; i++) {
|
||||
if (filename == server.scripts[i].filename) {
|
||||
|
@ -9,7 +9,7 @@ import { isValidFilePath } from "../Terminal/DirectoryHelpers";
|
||||
import { TextFile } from "../TextFile";
|
||||
import { IReturnStatus } from "../types";
|
||||
|
||||
import { isScriptFilename } from "../Script/ScriptHelpersTS";
|
||||
import { isScriptFilename } from "../Script/isScriptFilename";
|
||||
|
||||
import { createRandomIp } from "../../utils/IPAddress";
|
||||
import { compareArrays } from "../../utils/helpers/compareArrays";
|
||||
|
@ -295,7 +295,6 @@ export function SidebarRoot(props: IProps): React.ReactElement {
|
||||
event.preventDefault();
|
||||
clickCreateProgram();
|
||||
} else if (event.keyCode === KEY.F && event.altKey) {
|
||||
// Overriden by Fconf
|
||||
if (props.page == Page.Terminal && Settings.EnableBashHotkeys) {
|
||||
return;
|
||||
}
|
||||
|
1
src/Terminal.d.ts
vendored
1
src/Terminal.d.ts
vendored
@ -1 +0,0 @@
|
||||
export declare const Terminal: ITerminal;
|
@ -3,13 +3,14 @@ import { IRouter } from "../ui/Router";
|
||||
import { IPlayer } from "../PersonObjects/IPlayer";
|
||||
import { HacknetServer } from "../Hacknet/HacknetServer";
|
||||
import { BaseServer } from "../Server/BaseServer";
|
||||
import { Server } from "../Server/Server";
|
||||
import { Programs } from "../Programs/Programs";
|
||||
import { CodingContractResult } from "../CodingContracts";
|
||||
import { TerminalEvents, TerminalClearEvents } from "./TerminalEvents";
|
||||
|
||||
import { TextFile } from "../TextFile";
|
||||
import { Script } from "../Script/Script";
|
||||
import { isScriptFilename } from "../Script/ScriptHelpersTS";
|
||||
import { isScriptFilename } from "../Script/isScriptFilename";
|
||||
import { CONSTANTS } from "../Constants";
|
||||
import { AllServers } from "../Server/AllServers";
|
||||
|
||||
@ -91,7 +92,7 @@ export class Terminal implements ITerminal {
|
||||
append(item: Output | Link): void {
|
||||
this.outputHistory.push(item);
|
||||
if (this.outputHistory.length > Settings.MaxTerminalCapacity) {
|
||||
this.outputHistory.slice(this.outputHistory.length - Settings.MaxTerminalCapacity);
|
||||
this.outputHistory.splice(0, this.outputHistory.length - Settings.MaxTerminalCapacity);
|
||||
}
|
||||
TerminalEvents.emit();
|
||||
}
|
||||
@ -106,12 +107,22 @@ export class Terminal implements ITerminal {
|
||||
|
||||
startHack(player: IPlayer): void {
|
||||
// Hacking through Terminal should be faster than hacking through a script
|
||||
this.startAction(calculateHackingTime(player.getCurrentServer(), player) / 4, "h");
|
||||
const server = player.getCurrentServer();
|
||||
if (server instanceof HacknetServer) {
|
||||
this.error("Cannot hack this kind of server");
|
||||
return;
|
||||
}
|
||||
this.startAction(calculateHackingTime(server, player) / 4, "h");
|
||||
}
|
||||
|
||||
startBackdoor(player: IPlayer): void {
|
||||
// Backdoor should take the same amount of time as hack
|
||||
this.startAction(calculateHackingTime(player.getCurrentServer(), player) / 4, "b");
|
||||
const server = player.getCurrentServer();
|
||||
if (server instanceof HacknetServer) {
|
||||
this.error("Cannot backdoor this kind of server");
|
||||
return;
|
||||
}
|
||||
this.startAction(calculateHackingTime(server, player) / 4, "b");
|
||||
}
|
||||
|
||||
startAnalyze(): void {
|
||||
@ -127,6 +138,10 @@ export class Terminal implements ITerminal {
|
||||
finishHack(router: IRouter, player: IPlayer, cancelled = false): void {
|
||||
if (cancelled) return;
|
||||
const server = player.getCurrentServer();
|
||||
if (server instanceof HacknetServer) {
|
||||
this.error("Cannot hack this kind of server");
|
||||
return;
|
||||
}
|
||||
|
||||
// Calculate whether hack was successful
|
||||
const hackChance = calculateHackingChance(server, player);
|
||||
@ -179,6 +194,10 @@ export class Terminal implements ITerminal {
|
||||
finishBackdoor(router: IRouter, player: IPlayer, cancelled = false): void {
|
||||
if (!cancelled) {
|
||||
const server = player.getCurrentServer();
|
||||
if (server instanceof HacknetServer) {
|
||||
this.error("Cannot hack this kind of server");
|
||||
return;
|
||||
}
|
||||
if (
|
||||
SpecialServerIps[SpecialServerNames.WorldDaemon] &&
|
||||
SpecialServerIps[SpecialServerNames.WorldDaemon] == server.ip
|
||||
@ -203,24 +222,30 @@ export class Terminal implements ITerminal {
|
||||
this.print("Organization name: " + (!isHacknet ? org : "player"));
|
||||
const hasAdminRights = (!isHacknet && currServ.hasAdminRights) || isHacknet;
|
||||
this.print("Root Access: " + (hasAdminRights ? "YES" : "NO"));
|
||||
const hackingSkill = currServ.requiredHackingSkill;
|
||||
this.print("Required hacking skill: " + (!isHacknet ? hackingSkill : "N/A"));
|
||||
const security = currServ.hackDifficulty;
|
||||
this.print("Server security level: " + (!isHacknet ? numeralWrapper.formatServerSecurity(security) : "N/A"));
|
||||
const hackingChance = calculateHackingChance(currServ, player);
|
||||
this.print("Chance to hack: " + (!isHacknet ? numeralWrapper.formatPercentage(hackingChance) : "N/A"));
|
||||
const hackingTime = calculateHackingTime(currServ, player) * 1000;
|
||||
this.print("Time to hack: " + (!isHacknet ? convertTimeMsToTimeElapsedString(hackingTime, true) : "N/A"));
|
||||
if (currServ instanceof Server) {
|
||||
const hackingSkill = currServ.requiredHackingSkill;
|
||||
this.print("Required hacking skill: " + (!isHacknet ? hackingSkill : "N/A"));
|
||||
const security = currServ.hackDifficulty;
|
||||
this.print("Server security level: " + (!isHacknet ? numeralWrapper.formatServerSecurity(security) : "N/A"));
|
||||
const hackingChance = calculateHackingChance(currServ, player);
|
||||
this.print("Chance to hack: " + (!isHacknet ? numeralWrapper.formatPercentage(hackingChance) : "N/A"));
|
||||
const hackingTime = calculateHackingTime(currServ, player) * 1000;
|
||||
this.print("Time to hack: " + (!isHacknet ? convertTimeMsToTimeElapsedString(hackingTime, true) : "N/A"));
|
||||
}
|
||||
this.print(
|
||||
`Total money available on server: ${!isHacknet ? numeralWrapper.formatMoney(currServ.moneyAvailable) : "N/A"}`,
|
||||
`Total money available on server: ${
|
||||
!(currServ instanceof HacknetServer) ? numeralWrapper.formatMoney(currServ.moneyAvailable) : "N/A"
|
||||
}`,
|
||||
);
|
||||
const numPort = currServ.numOpenPortsRequired;
|
||||
this.print("Required number of open ports for NUKE: " + (!isHacknet ? numPort : "N/A"));
|
||||
this.print("SSH port: " + (currServ.sshPortOpen ? "Open" : "Closed"));
|
||||
this.print("FTP port: " + (currServ.ftpPortOpen ? "Open" : "Closed"));
|
||||
this.print("SMTP port: " + (currServ.smtpPortOpen ? "Open" : "Closed"));
|
||||
this.print("HTTP port: " + (currServ.httpPortOpen ? "Open" : "Closed"));
|
||||
this.print("SQL port: " + (currServ.sqlPortOpen ? "Open" : "Closed"));
|
||||
if (currServ instanceof Server) {
|
||||
const numPort = currServ.numOpenPortsRequired;
|
||||
this.print("Required number of open ports for NUKE: " + (!isHacknet ? numPort : "N/A"));
|
||||
this.print("SSH port: " + (currServ.sshPortOpen ? "Open" : "Closed"));
|
||||
this.print("FTP port: " + (currServ.ftpPortOpen ? "Open" : "Closed"));
|
||||
this.print("SMTP port: " + (currServ.smtpPortOpen ? "Open" : "Closed"));
|
||||
this.print("HTTP port: " + (currServ.httpPortOpen ? "Open" : "Closed"));
|
||||
this.print("SQL port: " + (currServ.sqlPortOpen ? "Open" : "Closed"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3,7 +3,7 @@ import { IRouter } from "../../ui/Router";
|
||||
import { IPlayer } from "../../PersonObjects/IPlayer";
|
||||
import { BaseServer } from "../../Server/BaseServer";
|
||||
import { findRunningScript } from "../../Script/ScriptHelpers";
|
||||
import { isScriptFilename } from "../../Script/ScriptHelpersTS";
|
||||
import { isScriptFilename } from "../../Script/isScriptFilename";
|
||||
|
||||
export function check(
|
||||
terminal: ITerminal,
|
||||
|
@ -2,7 +2,7 @@ import { ITerminal } from "../ITerminal";
|
||||
import { IRouter } from "../../ui/Router";
|
||||
import { IPlayer } from "../../PersonObjects/IPlayer";
|
||||
import { BaseServer } from "../../Server/BaseServer";
|
||||
import { isScriptFilename } from "../../Script/ScriptHelpersTS";
|
||||
import { isScriptFilename } from "../../Script/isScriptFilename";
|
||||
import FileSaver from "file-saver";
|
||||
import JSZip from "jszip";
|
||||
|
||||
|
@ -2,7 +2,7 @@ import { ITerminal } from "../ITerminal";
|
||||
import { IRouter } from "../../ui/Router";
|
||||
import { IPlayer } from "../../PersonObjects/IPlayer";
|
||||
import { BaseServer } from "../../Server/BaseServer";
|
||||
import { isScriptFilename } from "../../Script/ScriptHelpersTS";
|
||||
import { isScriptFilename } from "../../Script/isScriptFilename";
|
||||
import { TextFile } from "../../TextFile";
|
||||
import { Script } from "../../Script/Script";
|
||||
|
||||
|
@ -2,8 +2,7 @@ import { ITerminal } from "../ITerminal";
|
||||
import { IRouter } from "../../ui/Router";
|
||||
import { IPlayer } from "../../PersonObjects/IPlayer";
|
||||
import { BaseServer } from "../../Server/BaseServer";
|
||||
import { isScriptFilename } from "../../Script/ScriptHelpersTS";
|
||||
import { createFconf } from "../../Fconf/Fconf";
|
||||
import { isScriptFilename } from "../../Script/isScriptFilename";
|
||||
|
||||
export function nano(
|
||||
terminal: ITerminal,
|
||||
@ -19,11 +18,7 @@ export function nano(
|
||||
|
||||
try {
|
||||
const filename = args[0] + "";
|
||||
if (filename === ".fconf") {
|
||||
const text = createFconf();
|
||||
router.toScriptEditor(filename, text);
|
||||
return;
|
||||
} else if (isScriptFilename(filename)) {
|
||||
if (isScriptFilename(filename)) {
|
||||
const filepath = terminal.getFilepath(filename);
|
||||
const script = terminal.getScript(player, filename);
|
||||
if (script == null) {
|
||||
|
@ -2,7 +2,7 @@ import { ITerminal } from "../ITerminal";
|
||||
import { IRouter } from "../../ui/Router";
|
||||
import { IPlayer } from "../../PersonObjects/IPlayer";
|
||||
import { BaseServer } from "../../Server/BaseServer";
|
||||
import { isScriptFilename } from "../../Script/ScriptHelpersTS";
|
||||
import { isScriptFilename } from "../../Script/isScriptFilename";
|
||||
import { runScript } from "./runScript";
|
||||
import { runProgram } from "./runProgram";
|
||||
|
||||
|
@ -4,7 +4,7 @@ import { IPlayer } from "../../PersonObjects/IPlayer";
|
||||
import { BaseServer } from "../../Server/BaseServer";
|
||||
import { Message } from "../../Message/Message";
|
||||
import { getServer } from "../../Server/ServerHelpers";
|
||||
import { isScriptFilename } from "../../Script/ScriptHelpersTS";
|
||||
import { isScriptFilename } from "../../Script/isScriptFilename";
|
||||
|
||||
export function scp(
|
||||
terminal: ITerminal,
|
||||
|
@ -4,8 +4,8 @@ import { IPlayer } from "../../PersonObjects/IPlayer";
|
||||
import { BaseServer } from "../../Server/BaseServer";
|
||||
import { logBoxCreate } from "../../../utils/LogBox";
|
||||
import { findRunningScriptByPid } from "../../Script/ScriptHelpers";
|
||||
import { isScriptFilename } from "../../Script/isScriptFilename";
|
||||
import { compareArrays } from "../../../utils/helpers/compareArrays";
|
||||
import { isScriptFilename } from "../../Script/ScriptHelpersTS";
|
||||
|
||||
export function tail(
|
||||
terminal: ITerminal,
|
||||
|
@ -2,7 +2,7 @@ import { ITerminal } from "../ITerminal";
|
||||
import { IRouter } from "../../ui/Router";
|
||||
import { IPlayer } from "../../PersonObjects/IPlayer";
|
||||
import { BaseServer } from "../../Server/BaseServer";
|
||||
import { isScriptFilename } from "../../Script/ScriptHelpersTS";
|
||||
import { isScriptFilename } from "../../Script/isScriptFilename";
|
||||
|
||||
export function wget(
|
||||
terminal: ITerminal,
|
||||
|
@ -12,6 +12,7 @@ import { IRouter } from "../../ui/Router";
|
||||
import { IPlayer } from "../../PersonObjects/IPlayer";
|
||||
import { TerminalInput } from "./TerminalInput";
|
||||
import { TerminalEvents, TerminalClearEvents } from "../TerminalEvents";
|
||||
import _ from "lodash";
|
||||
|
||||
interface IActionTimerProps {
|
||||
terminal: ITerminal;
|
||||
|
1
src/ThirdParty/JSInterpreter.d.ts
vendored
Normal file
1
src/ThirdParty/JSInterpreter.d.ts
vendored
Normal file
@ -0,0 +1 @@
|
||||
export declare let Interpreter: any;
|
1
src/ThirdParty/sprintf-js.d.ts
vendored
Normal file
1
src/ThirdParty/sprintf-js.d.ts
vendored
Normal file
@ -0,0 +1 @@
|
||||
declare module "sprintf-js";
|
@ -50,7 +50,29 @@ import { startUnclickable } from "./Exploits/unclickable";
|
||||
|
||||
import React from "react";
|
||||
|
||||
const Engine = {
|
||||
const Engine: {
|
||||
_lastUpdate: number;
|
||||
updateGame: (numCycles?: number) => void;
|
||||
Counters: {
|
||||
[key: string]: number | undefined;
|
||||
autoSaveCounter: number;
|
||||
updateSkillLevelsCounter: number;
|
||||
updateDisplays: number;
|
||||
updateDisplaysLong: number;
|
||||
updateActiveScriptsDisplay: number;
|
||||
createProgramNotifications: number;
|
||||
augmentationsNotifications: number;
|
||||
checkFactionInvitations: number;
|
||||
passiveFactionGrowth: number;
|
||||
messages: number;
|
||||
mechanicProcess: number;
|
||||
contractGeneration: number;
|
||||
};
|
||||
decrementAllCounters: (numCycles?: number) => void;
|
||||
checkCounters: () => void;
|
||||
load: (saveString: string) => void;
|
||||
start: () => void;
|
||||
} = {
|
||||
// Time variables (milliseconds unix epoch time)
|
||||
_lastUpdate: new Date().getTime(),
|
||||
|
||||
@ -106,7 +128,7 @@ const Engine = {
|
||||
}
|
||||
|
||||
// Gang, if applicable
|
||||
if (Player.inGang()) {
|
||||
if (Player.inGang() && Player.gang !== null) {
|
||||
Player.gang.process(numCycles, Player);
|
||||
}
|
||||
|
||||
@ -175,10 +197,10 @@ const Engine = {
|
||||
},
|
||||
|
||||
decrementAllCounters: function (numCycles = 1) {
|
||||
for (var counter in Engine.Counters) {
|
||||
if (Engine.Counters.hasOwnProperty(counter)) {
|
||||
Engine.Counters[counter] = Engine.Counters[counter] - numCycles;
|
||||
}
|
||||
for (const counterName in Engine.Counters) {
|
||||
const counter = Engine.Counters[counterName];
|
||||
if (counter === undefined) throw new Error("counter should not be undefined");
|
||||
Engine.Counters[counterName] = counter - numCycles;
|
||||
}
|
||||
},
|
||||
|
||||
@ -328,8 +350,9 @@ const Engine = {
|
||||
}
|
||||
|
||||
// Gang progress for BitNode 2
|
||||
if (Player.inGang()) {
|
||||
Player.gang.process(numCyclesOffline, Player);
|
||||
const gang = Player.gang;
|
||||
if (Player.inGang() && gang !== null) {
|
||||
gang.process(numCyclesOffline, Player);
|
||||
}
|
||||
|
||||
// Corporation offline progress
|
@ -326,11 +326,11 @@ export function GameRoot({ player, engine, terminal }: IProps): React.ReactEleme
|
||||
) : page === Page.DevMenu ? (
|
||||
<DevMenuRoot player={player} engine={engine} router={Router} />
|
||||
) : page === Page.Gang ? (
|
||||
<GangRoot gang={player.gang} />
|
||||
<GangRoot />
|
||||
) : page === Page.Corporation ? (
|
||||
<CorporationRoot corp={player.corporation} player={player} />
|
||||
<CorporationRoot />
|
||||
) : page === Page.Bladeburner ? (
|
||||
<BladeburnerRoot bladeburner={player.bladeburner} />
|
||||
<BladeburnerRoot />
|
||||
) : page === Page.Resleeves ? (
|
||||
<ResleeveRoot player={player} />
|
||||
) : page === Page.Travel ? (
|
||||
|
@ -1,177 +0,0 @@
|
||||
// Implement the collapsible main menu headers
|
||||
import { MainMenuLinks } from "./Links";
|
||||
import { IPlayer } from "../../PersonObjects/IPlayer";
|
||||
|
||||
interface IMainMenuHeaders {
|
||||
Hacking: HTMLElement | null;
|
||||
Character: HTMLElement | null;
|
||||
World: HTMLElement | null;
|
||||
Help: HTMLElement | null;
|
||||
}
|
||||
|
||||
export const MainMenuHeaders: IMainMenuHeaders = {
|
||||
Hacking: null,
|
||||
Character: null,
|
||||
World: null,
|
||||
Help: null,
|
||||
};
|
||||
|
||||
// Implements collapsible toggle feature when a header is clicked
|
||||
function toggleHeader(open: boolean, elems: HTMLElement[], links: HTMLElement[]): void {
|
||||
for (let i = 0; i < elems.length; ++i) {
|
||||
if (open) {
|
||||
elems[i].style.opacity = "1";
|
||||
elems[i].style.maxHeight = elems[i].scrollHeight + "px";
|
||||
} else {
|
||||
elems[i].style.opacity = "0";
|
||||
elems[i].style.maxHeight = "";
|
||||
}
|
||||
}
|
||||
|
||||
for (let i = 0; i < links.length; ++i) {
|
||||
if (open) {
|
||||
links[i].style.opacity = "1";
|
||||
links[i].style.maxHeight = links[i].scrollHeight + "px";
|
||||
links[i].style.pointerEvents = "auto";
|
||||
} else {
|
||||
links[i].style.opacity = "0";
|
||||
links[i].style.maxHeight = "";
|
||||
links[i].style.pointerEvents = "none";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export function initializeMainMenuHeaders(p: IPlayer, dev = false): boolean {
|
||||
function safeGetElement(id: string): HTMLElement {
|
||||
const elem: HTMLElement | null = document.getElementById(id);
|
||||
if (elem == null) {
|
||||
throw new Error(`Failed to find element with id ${id} in initializeMainMenuHeaders()`);
|
||||
}
|
||||
|
||||
return elem;
|
||||
}
|
||||
|
||||
try {
|
||||
// Get references to the DOM elements
|
||||
MainMenuHeaders.Hacking = safeGetElement("hacking-menu-header");
|
||||
MainMenuHeaders.Character = safeGetElement("character-menu-header");
|
||||
MainMenuHeaders.World = safeGetElement("world-menu-header");
|
||||
MainMenuHeaders.Help = safeGetElement("help-menu-header");
|
||||
|
||||
// Set click handlers to turn the headers into collapsibles
|
||||
MainMenuHeaders.Hacking.onclick = function () {
|
||||
const terminal: HTMLElement = safeGetElement("terminal-tab");
|
||||
const createScript: HTMLElement = safeGetElement("create-script-tab");
|
||||
const activeScripts: HTMLElement = safeGetElement("active-scripts-tab");
|
||||
const createProgram: HTMLElement = safeGetElement("create-program-tab");
|
||||
const createProgramNot: HTMLElement = safeGetElement("create-program-notification");
|
||||
|
||||
createProgram.style.display = p.firstProgramAvailable ? "list-item" : "none";
|
||||
|
||||
(this as any).classList.toggle("opened");
|
||||
|
||||
const elems: HTMLElement[] = [terminal, createScript, activeScripts, createProgram];
|
||||
const links: HTMLElement[] = [
|
||||
MainMenuLinks.Terminal,
|
||||
MainMenuLinks.ScriptEditor,
|
||||
MainMenuLinks.ActiveScripts,
|
||||
MainMenuLinks.CreateProgram,
|
||||
];
|
||||
if (terminal.style.maxHeight) {
|
||||
toggleHeader(false, elems, links);
|
||||
createProgramNot.style.display = "none";
|
||||
} else {
|
||||
toggleHeader(true, elems, links);
|
||||
createProgramNot.style.display = "block";
|
||||
}
|
||||
};
|
||||
|
||||
MainMenuHeaders.Character.onclick = function () {
|
||||
const stats: HTMLElement = safeGetElement("stats-tab");
|
||||
const factions: HTMLElement = safeGetElement("factions-tab");
|
||||
const augmentations: HTMLElement = safeGetElement("augmentations-tab");
|
||||
const hacknetnodes: HTMLElement = safeGetElement("hacknet-nodes-tab");
|
||||
const sleeves: HTMLElement = safeGetElement("sleeves-tab");
|
||||
|
||||
sleeves.style.display = p.sleeves.length > 0 ? "list-item" : "none";
|
||||
|
||||
(this as any).classList.toggle("opened");
|
||||
|
||||
const elems: HTMLElement[] = [stats, factions, augmentations, hacknetnodes, sleeves];
|
||||
const links: HTMLElement[] = [
|
||||
MainMenuLinks.Stats,
|
||||
MainMenuLinks.Factions,
|
||||
MainMenuLinks.Augmentations,
|
||||
MainMenuLinks.HacknetNodes,
|
||||
MainMenuLinks.Sleeves,
|
||||
];
|
||||
if (stats.style.maxHeight) {
|
||||
toggleHeader(false, elems, links);
|
||||
} else {
|
||||
toggleHeader(true, elems, links);
|
||||
}
|
||||
};
|
||||
|
||||
MainMenuHeaders.World.onclick = function () {
|
||||
const city: HTMLElement = safeGetElement("city-tab");
|
||||
const travel: HTMLElement = safeGetElement("travel-tab");
|
||||
const job: HTMLElement = safeGetElement("job-tab");
|
||||
const stockmarket: HTMLElement = safeGetElement("stock-market-tab");
|
||||
const bladeburner: HTMLElement = safeGetElement("bladeburner-tab");
|
||||
const corporation: HTMLElement = safeGetElement("corporation-tab");
|
||||
const gang: HTMLElement = safeGetElement("gang-tab");
|
||||
|
||||
// Determine whether certain links should show up
|
||||
job.style.display = p.companyName !== "" ? "list-item" : "none";
|
||||
stockmarket.style.display = p.hasWseAccount ? "list-item" : "none";
|
||||
bladeburner.style.display = p.inBladeburner() ? "list-item" : "none";
|
||||
corporation.style.display = p.hasCorporation() ? "list-item" : "none";
|
||||
gang.style.display = p.inGang() ? "list-item" : "none";
|
||||
|
||||
(this as any).classList.toggle("opened");
|
||||
|
||||
const elems: HTMLElement[] = [city, travel, job, stockmarket, bladeburner, corporation, gang];
|
||||
const links: HTMLElement[] = [
|
||||
MainMenuLinks.City,
|
||||
MainMenuLinks.Travel,
|
||||
MainMenuLinks.Job,
|
||||
MainMenuLinks.StockMarket,
|
||||
MainMenuLinks.Bladeburner,
|
||||
MainMenuLinks.Corporation,
|
||||
MainMenuLinks.Gang,
|
||||
];
|
||||
if (city.style.maxHeight) {
|
||||
toggleHeader(false, elems, links);
|
||||
} else {
|
||||
toggleHeader(true, elems, links);
|
||||
}
|
||||
};
|
||||
|
||||
MainMenuHeaders.Help.onclick = function () {
|
||||
const milestones: HTMLElement = safeGetElement("milestones-tab");
|
||||
const tutorial: HTMLElement = safeGetElement("tutorial-tab");
|
||||
const options: HTMLElement = safeGetElement("options-tab");
|
||||
|
||||
(this as any).classList.toggle("opened");
|
||||
|
||||
const elems: HTMLElement[] = [milestones, tutorial, options];
|
||||
const links: HTMLElement[] = [MainMenuLinks.Milestones, MainMenuLinks.Tutorial, MainMenuLinks.Options];
|
||||
|
||||
if (dev) {
|
||||
elems.push(safeGetElement("dev-tab"));
|
||||
links.push(safeGetElement("dev-menu-link"));
|
||||
}
|
||||
|
||||
if (tutorial.style.maxHeight) {
|
||||
toggleHeader(false, elems, links);
|
||||
} else {
|
||||
toggleHeader(true, elems, links);
|
||||
}
|
||||
};
|
||||
|
||||
return true;
|
||||
} catch (e) {
|
||||
console.error(`Failed to initialize Main Menu Headers: ${e}`);
|
||||
return false;
|
||||
}
|
||||
}
|
@ -1,98 +0,0 @@
|
||||
// Get references to the Main Menu link DOM elements
|
||||
// Does NOT include collapsible headers for the links
|
||||
import { clearEventListeners } from "../../../utils/uiHelpers/clearEventListeners";
|
||||
|
||||
interface IMainMenuLinks {
|
||||
[key: string]: HTMLElement | undefined;
|
||||
Terminal: HTMLElement;
|
||||
ScriptEditor: HTMLElement;
|
||||
ActiveScripts: HTMLElement;
|
||||
CreateProgram: HTMLElement;
|
||||
Stats: HTMLElement;
|
||||
Factions: HTMLElement;
|
||||
Augmentations: HTMLElement;
|
||||
HacknetNodes: HTMLElement;
|
||||
Sleeves: HTMLElement;
|
||||
City: HTMLElement;
|
||||
Travel: HTMLElement;
|
||||
Job: HTMLElement;
|
||||
StockMarket: HTMLElement;
|
||||
Bladeburner: HTMLElement;
|
||||
Corporation: HTMLElement;
|
||||
Gang: HTMLElement;
|
||||
Milestones: HTMLElement;
|
||||
Tutorial: HTMLElement;
|
||||
Options: HTMLElement;
|
||||
DevMenu: HTMLElement;
|
||||
}
|
||||
|
||||
const emptyElement: HTMLElement = ((): HTMLElement => {
|
||||
const elem = document.createElement("div");
|
||||
if (elem === null) throw new Error("unable to create empty div element");
|
||||
return elem;
|
||||
})();
|
||||
|
||||
export const MainMenuLinks: IMainMenuLinks = {
|
||||
Terminal: emptyElement,
|
||||
ScriptEditor: emptyElement,
|
||||
ActiveScripts: emptyElement,
|
||||
CreateProgram: emptyElement,
|
||||
Stats: emptyElement,
|
||||
Factions: emptyElement,
|
||||
Augmentations: emptyElement,
|
||||
HacknetNodes: emptyElement,
|
||||
Sleeves: emptyElement,
|
||||
City: emptyElement,
|
||||
Travel: emptyElement,
|
||||
Job: emptyElement,
|
||||
StockMarket: emptyElement,
|
||||
Bladeburner: emptyElement,
|
||||
Corporation: emptyElement,
|
||||
Gang: emptyElement,
|
||||
Milestones: emptyElement,
|
||||
Tutorial: emptyElement,
|
||||
Options: emptyElement,
|
||||
DevMenu: emptyElement,
|
||||
};
|
||||
|
||||
export function initializeMainMenuLinks(): boolean {
|
||||
return true;
|
||||
try {
|
||||
function safeGetLink(id: string): HTMLElement {
|
||||
const elem: HTMLElement | null = clearEventListeners(id);
|
||||
if (elem == null) {
|
||||
throw new Error(`clearEventListeners() failed for element with id: ${id}`);
|
||||
}
|
||||
|
||||
return elem;
|
||||
}
|
||||
|
||||
MainMenuLinks.Terminal = safeGetLink("terminal-menu-link");
|
||||
MainMenuLinks.ScriptEditor = safeGetLink("create-script-menu-link");
|
||||
MainMenuLinks.ActiveScripts = safeGetLink("active-scripts-menu-link");
|
||||
MainMenuLinks.CreateProgram = safeGetLink("create-program-menu-link");
|
||||
MainMenuLinks.Stats = safeGetLink("stats-menu-link");
|
||||
MainMenuLinks.Factions = safeGetLink("factions-menu-link");
|
||||
MainMenuLinks.Augmentations = safeGetLink("augmentations-menu-link");
|
||||
MainMenuLinks.HacknetNodes = safeGetLink("hacknet-nodes-menu-link");
|
||||
MainMenuLinks.Sleeves = safeGetLink("sleeves-menu-link");
|
||||
MainMenuLinks.City = safeGetLink("city-menu-link");
|
||||
MainMenuLinks.Travel = safeGetLink("travel-menu-link");
|
||||
MainMenuLinks.Job = safeGetLink("job-menu-link");
|
||||
MainMenuLinks.StockMarket = safeGetLink("stock-market-menu-link");
|
||||
MainMenuLinks.Bladeburner = safeGetLink("bladeburner-menu-link");
|
||||
MainMenuLinks.Corporation = safeGetLink("corporation-menu-link");
|
||||
MainMenuLinks.Gang = safeGetLink("gang-menu-link");
|
||||
MainMenuLinks.Milestones = safeGetLink("milestones-menu-link");
|
||||
MainMenuLinks.Tutorial = safeGetLink("tutorial-menu-link");
|
||||
// const op: HTMLElement | null = document.getElementById("options-menu-link");
|
||||
// if (op === null) throw new Error(`Could not find element with id: "options-menu-link"`);
|
||||
// MainMenuLinks.Options = op; // This click listener is already set, so don't clear it
|
||||
MainMenuLinks.DevMenu = safeGetLink("dev-menu-link");
|
||||
|
||||
return true;
|
||||
} catch (e) {
|
||||
console.error(`Failed to initialize Main Menu Links: ${e}`);
|
||||
return false;
|
||||
}
|
||||
}
|
@ -195,7 +195,7 @@ export function GameOptionsRoot(props: IProps): React.ReactElement {
|
||||
return;
|
||||
}
|
||||
const contents = result;
|
||||
save(contents).then(() => location.reload());
|
||||
save(contents).then(() => setTimeout(() => location.reload(), 1000));
|
||||
};
|
||||
reader.readAsText(file);
|
||||
}
|
||||
@ -628,7 +628,7 @@ export function GameOptionsRoot(props: IProps): React.ReactElement {
|
||||
onConfirm={() => {
|
||||
setDeleteOpen(false);
|
||||
deleteGame()
|
||||
.then(() => location.reload())
|
||||
.then(() => setTimeout(() => location.reload(), 1000))
|
||||
.catch((r) => console.error(`Could not delete game: ${r}`));
|
||||
}}
|
||||
open={deleteGameOpen}
|
||||
|
@ -5,17 +5,17 @@ interface IError {
|
||||
lineNumber?: number;
|
||||
}
|
||||
|
||||
export function exceptionAlert(e: IError): void {
|
||||
export function exceptionAlert(e: IError | string): void {
|
||||
console.error(e);
|
||||
dialogBoxCreate(
|
||||
"Caught an exception: " +
|
||||
e +
|
||||
"<br><br>" +
|
||||
"Filename: " +
|
||||
(e.fileName || "UNKNOWN FILE NAME") +
|
||||
((e as any).fileName || "UNKNOWN FILE NAME") +
|
||||
"<br><br>" +
|
||||
"Line Number: " +
|
||||
(e.lineNumber || "UNKNOWN LINE NUMBER") +
|
||||
((e as any).lineNumber || "UNKNOWN LINE NUMBER") +
|
||||
"<br><br>" +
|
||||
"This is a bug, please report to game developer with this " +
|
||||
"message as well as details about how to reproduce the bug.<br><br>" +
|
||||
|
Loading…
Reference in New Issue
Block a user