diff --git a/src/Augmentation/AugmentationHelpers.d.ts b/src/Augmentation/AugmentationHelpers.d.ts
index c20c69364..80a1be9cc 100644
--- a/src/Augmentation/AugmentationHelpers.d.ts
+++ b/src/Augmentation/AugmentationHelpers.d.ts
@@ -1,2 +1,3 @@
export declare function isRepeatableAug(aug: Augmentation): boolean;
export declare function installAugmentations(): void;
+export declare function applyAugmentation(aug: Augmentation, reapply?: boolean): void;
diff --git a/src/Bladeburner/ui/BladeburnerRoot.tsx b/src/Bladeburner/ui/BladeburnerRoot.tsx
index 35af06174..e0c62747c 100644
--- a/src/Bladeburner/ui/BladeburnerRoot.tsx
+++ b/src/Bladeburner/ui/BladeburnerRoot.tsx
@@ -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 (
@@ -24,9 +22,9 @@ export function BladeburnerRoot(props: IProps): React.ReactElement {
border: "1px solid white",
}}
>
-
+
-
+
);
diff --git a/src/Corporation/ui/CorporationRoot.tsx b/src/Corporation/ui/CorporationRoot.tsx
index 8784a35a7..0ad51fd23 100644
--- a/src/Corporation/ui/CorporationRoot.tsx
+++ b/src/Corporation/ui/CorporationRoot.tsx
@@ -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 ;
}
-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) => (
))}
-
+
-
+
);
}
diff --git a/src/Crime/Crime.ts b/src/Crime/Crime.ts
index 798b8e262..75db4bb42 100644
--- a/src/Crime/Crime.ts
+++ b/src/Crime/Crime.ts
@@ -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;
diff --git a/src/DarkWeb/DarkWeb.tsx b/src/DarkWeb/DarkWeb.tsx
index 5473bf036..2e339946b 100644
--- a/src/DarkWeb/DarkWeb.tsx
+++ b/src/DarkWeb/DarkWeb.tsx
@@ -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] " +
diff --git a/src/DevMenu/ui/Bladeburner.tsx b/src/DevMenu/ui/Bladeburner.tsx
index 0a435dfa5..81082a8b9 100644
--- a/src/DevMenu/ui/Bladeburner.tsx
+++ b/src/DevMenu/ui/Bladeburner.tsx
@@ -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 (
diff --git a/src/Exploits/Exploit.ts b/src/Exploits/Exploit.ts
index 77da933c7..1d5f23482 100644
--- a/src/Exploits/Exploit.ts
+++ b/src/Exploits/Exploit.ts
@@ -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));
}
diff --git a/src/Fconf/Fconf.d.ts b/src/Fconf/Fconf.d.ts
deleted file mode 100644
index fcacfe3f8..000000000
--- a/src/Fconf/Fconf.d.ts
+++ /dev/null
@@ -1,2 +0,0 @@
-export declare function parseFconfSettings(config: string): void;
-export declare function createFconf(): string;
diff --git a/src/Fconf/Fconf.js b/src/Fconf/Fconf.js
deleted file mode 100644
index a31645858..000000000
--- a/src/Fconf/Fconf.js
+++ /dev/null
@@ -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 };
diff --git a/src/Fconf/FconfSettings.ts b/src/Fconf/FconfSettings.ts
deleted file mode 100644
index 12c5e8a0e..000000000
--- a/src/Fconf/FconfSettings.ts
+++ /dev/null
@@ -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,
-};
diff --git a/src/Gang/ui/GangRoot.tsx b/src/Gang/ui/GangRoot.tsx
index d746d7626..5ee45804f 100644
--- a/src/Gang/ui/GangRoot.tsx
+++ b/src/Gang/ui/GangRoot.tsx
@@ -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
- {management ? : }
+ {management ? : }
);
}
diff --git a/src/Hacknet/HacknetHelpers.tsx b/src/Hacknet/HacknetHelpers.tsx
index 38411fdba..d5fd1345a 100644
--- a/src/Hacknet/HacknetHelpers.tsx
+++ b/src/Hacknet/HacknetHelpers.tsx
@@ -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": {
diff --git a/src/NetscriptFunctions.js b/src/NetscriptFunctions.js
index 787e52c30..86627e160 100644
--- a/src/NetscriptFunctions.js
+++ b/src/NetscriptFunctions.js
@@ -3808,7 +3808,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"));
diff --git a/src/PersonObjects/IPlayer.ts b/src/PersonObjects/IPlayer.ts
index 993d8a064..393a8995b 100644
--- a/src/PersonObjects/IPlayer.ts
+++ b/src/PersonObjects/IPlayer.ts
@@ -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;
@@ -201,6 +208,7 @@ export interface IPlayer {
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(
@@ -237,11 +245,31 @@ export interface IPlayer {
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(): void;
+ setBitNodeNumber(n: number): void;
}
diff --git a/src/PersonObjects/Player/PlayerObject.js b/src/PersonObjects/Player/PlayerObject.js
deleted file mode 100644
index 32022fa3c..000000000
--- a/src/PersonObjects/Player/PlayerObject.js
+++ /dev/null
@@ -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;
diff --git a/src/PersonObjects/Player/PlayerObject.ts b/src/PersonObjects/Player/PlayerObject.ts
new file mode 100644
index 000000000..ad7da4a70
--- /dev/null
+++ b/src/PersonObjects/Player/PlayerObject.ts
@@ -0,0 +1,591 @@
+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;
+ 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: () => void;
+ 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: () => void;
+ setBitNodeNumber: (n: 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;
+ }
+
+ /**
+ * 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;
diff --git a/src/PersonObjects/Player/PlayerObjectGangMethods.ts b/src/PersonObjects/Player/PlayerObjectGangMethods.ts
index b8aea304f..c24783512 100644
--- a/src/PersonObjects/Player/PlayerObjectGangMethods.ts
+++ b/src/PersonObjects/Player/PlayerObjectGangMethods.ts
@@ -20,20 +20,34 @@ export function canAccessGang(this: IPlayer): boolean {
}
export function getGangFaction(this: IPlayer): Faction {
- const fac = Factions[this.gang.facName];
+ 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: ${this.gang.facName}`);
+ throw new Error(`Gang has invalid faction name: ${gang.facName}`);
}
return fac;
}
export function getGangName(this: IPlayer): string {
- return this.inGang() ? this.gang.facName : "";
+ 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 {
- return this.inGang() && this.gang.facName === facName;
+ 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 {
diff --git a/src/PersonObjects/Player/PlayerObjectGeneralMethods.jsx b/src/PersonObjects/Player/PlayerObjectGeneralMethods.tsx
similarity index 84%
rename from src/PersonObjects/Player/PlayerObjectGeneralMethods.jsx
rename to src/PersonObjects/Player/PlayerObjectGeneralMethods.tsx
index 872bb633b..b788202a7 100644
--- a/src/PersonObjects/Player/PlayerObjectGeneralMethods.jsx
+++ b/src/PersonObjects/Player/PlayerObjectGeneralMethods.tsx
@@ -1,3 +1,4 @@
+import { IPlayer } from "../IPlayer";
import { Augmentations } from "../../Augmentation/Augmentations";
import { applyAugmentation } from "../../Augmentation/AugmentationHelpers";
import { PlayerOwnedAugmentation } from "../../Augmentation/PlayerOwnedAugmentation";
@@ -9,11 +10,14 @@ import { Companies } from "../../Company/Companies";
import { getNextCompanyPositionHelper } from "../../Company/GetNextCompanyPosition";
import { getJobRequirementText } from "../../Company/GetJobRequirementText";
import { CompanyPositions } from "../../Company/CompanyPositions";
+import { CompanyPosition } from "../../Company/CompanyPosition";
import * as posNames from "../../Company/data/companypositionnames";
import { CONSTANTS } from "../../Constants";
import { Programs } from "../../Programs/Programs";
import { determineCrimeSuccess } from "../../Crime/CrimeHelpers";
+import { ICodingContractReward } from "../../CodingContracts";
import { Crimes } from "../../Crime/Crimes";
+import { Exploit } from "../../Exploits/Exploit";
import { Faction } from "../../Faction/Faction";
import { Factions } from "../../Faction/Factions";
import { resetGangs } from "../../Gang/AllGangs";
@@ -31,6 +35,7 @@ import {
getFactionFieldWorkRepGain,
} from "../formulas/reputation";
import { AllServers, AddToAllServers, createUniqueRandomIp } from "../../Server/AllServers";
+import { Server } from "../../Server/Server";
import { safetlyCreateUniqueServer } from "../../Server/ServerHelpers";
import { Settings } from "../../Settings/Settings";
import { SpecialServerIps, SpecialServerNames } from "../../Server/SpecialServerIps";
@@ -40,10 +45,12 @@ import { SourceFiles } from "../../SourceFile/SourceFiles";
import { SourceFileFlags } from "../../SourceFile/SourceFileFlags";
import { influenceStockThroughCompanyWork } from "../../StockMarket/PlayerInfluencing";
import { getHospitalizationCost } from "../../Hospital/Hospital";
+import { WorkerScript } from "../../Netscript/WorkerScript";
import Decimal from "decimal.js";
import { numeralWrapper } from "../../ui/numeralFormat";
+import { IRouter } from "../../ui/Router";
import { MoneySourceTracker } from "../../utils/MoneySourceTracker";
import { dialogBoxCreate } from "../../../utils/DialogBox";
import { convertTimeMsToTimeElapsedString } from "../../../utils/StringHelperFunctions";
@@ -53,7 +60,7 @@ import { Money } from "../../ui/React/Money";
import React from "react";
-export function init() {
+export function init(this: IPlayer) {
/* Initialize Player's home computer */
var t_homeComp = safetlyCreateUniqueServer({
adminRights: true,
@@ -71,7 +78,7 @@ export function init() {
this.getHomeComputer().programs.push(Programs.NukeProgram.name);
}
-export function prestigeAugmentation() {
+export function prestigeAugmentation(this: IPlayer) {
var homeComp = this.getHomeComputer();
this.currentServer = homeComp.ip;
this.homeComputer = homeComp.ip;
@@ -99,7 +106,7 @@ export function prestigeAugmentation() {
this.money = new Decimal(1000);
this.city = CityName.Sector12;
- this.location = "";
+ this.location = LocationName.TravelAgency;
this.companyName = "";
this.jobs = {};
@@ -113,7 +120,7 @@ export function prestigeAugmentation() {
this.resleeves = [];
- let numSleeves = Math.min(3, SourceFileFlags[10] + (this.bitNodeN === 10 ? 1 : 0)) + this.sleevesFromCovenant;
+ const numSleeves = Math.min(3, SourceFileFlags[10] + (this.bitNodeN === 10 ? 1 : 0)) + this.sleevesFromCovenant;
if (this.sleeves.length > numSleeves) this.sleeves.length = numSleeves;
for (let i = this.sleeves.length; i < numSleeves; i++) {
this.sleeves.push(new Sleeve(this));
@@ -171,7 +178,7 @@ export function prestigeAugmentation() {
this.hp = this.max_hp;
}
-export function prestigeSourceFile() {
+export function prestigeSourceFile(this: IPlayer) {
this.prestigeAugmentation();
// Duplicate sleeves are reset to level 1 every Bit Node (but the number of sleeves you have persists)
for (let i = 0; i < this.sleeves.length; ++i) {
@@ -202,27 +209,26 @@ export function prestigeSourceFile() {
this.has4SDataTixApi = false;
// BitNode 3: Corporatocracy
- this.corporation = 0;
+ this.corporation = null;
this.moneySourceB.reset();
this.playtimeSinceLastBitnode = 0;
this.augmentations = [];
}
-export function receiveInvite(factionName) {
+export function receiveInvite(this: IPlayer, factionName: string): void {
if (this.factionInvitations.includes(factionName) || this.factions.includes(factionName)) {
return;
}
- this.firstFacInvRecvd = true;
this.factionInvitations.push(factionName);
}
//Calculates skill level based on experience. The same formula will be used for every skill
-export function calculateSkill(exp, mult = 1) {
+export function calculateSkill(this: IPlayer, exp: number, mult = 1): number {
return calculateSkillF(exp, mult);
}
-export function updateSkillLevels() {
+export function updateSkillLevels(this: IPlayer): void {
this.hacking_skill = Math.max(
1,
Math.floor(this.calculateSkill(this.hacking_exp, this.hacking_mult * BitNodeMultipliers.HackingLevelMultiplier)),
@@ -261,7 +267,7 @@ export function updateSkillLevels() {
this.hp = Math.round(this.max_hp * ratio);
}
-export function resetMultipliers() {
+export function resetMultipliers(this: IPlayer): void {
this.hacking_chance_mult = 1;
this.hacking_speed_mult = 1;
this.hacking_money_mult = 1;
@@ -301,7 +307,7 @@ export function resetMultipliers() {
this.bladeburner_success_chance_mult = 1;
}
-export function hasProgram(programName) {
+export function hasProgram(this: IPlayer, programName: string): boolean {
const home = this.getHomeComputer();
if (home == null) {
return false;
@@ -315,7 +321,7 @@ export function hasProgram(programName) {
return false;
}
-export function setMoney(money) {
+export function setMoney(this: IPlayer, money: number): void {
if (isNaN(money)) {
console.error("NaN passed into Player.setMoney()");
return;
@@ -323,7 +329,7 @@ export function setMoney(money) {
this.money = new Decimal(money);
}
-export function gainMoney(money) {
+export function gainMoney(this: IPlayer, money: number): void {
if (isNaN(money)) {
console.error("NaN passed into Player.gainMoney()");
return;
@@ -331,7 +337,7 @@ export function gainMoney(money) {
this.money = this.money.plus(money);
}
-export function loseMoney(money) {
+export function loseMoney(this: IPlayer, money: number): void {
if (isNaN(money)) {
console.error("NaN passed into Player.loseMoney()");
return;
@@ -340,7 +346,7 @@ export function loseMoney(money) {
this.money = this.money.minus(money);
}
-export function canAfford(cost) {
+export function canAfford(this: IPlayer, cost: number): boolean {
if (isNaN(cost)) {
console.error(`NaN passed into Player.canAfford()`);
return false;
@@ -348,7 +354,7 @@ export function canAfford(cost) {
return this.money.gte(cost);
}
-export function recordMoneySource(amt, source) {
+export function recordMoneySource(this: IPlayer, amt: number, source: string) {
if (!(this.moneySourceA instanceof MoneySourceTracker)) {
console.warn(`Player.moneySourceA was not properly initialized. Resetting`);
this.moneySourceA = new MoneySourceTracker();
@@ -361,7 +367,7 @@ export function recordMoneySource(amt, source) {
this.moneySourceB.record(amt, source);
}
-export function gainHackingExp(exp) {
+export function gainHackingExp(this: IPlayer, exp: number) {
if (isNaN(exp)) {
console.error("ERR: NaN passed into Player.gainHackingExp()");
return;
@@ -374,7 +380,7 @@ export function gainHackingExp(exp) {
this.hacking_skill = calculateSkillF(this.hacking_exp, this.hacking_mult * BitNodeMultipliers.HackingLevelMultiplier);
}
-export function gainStrengthExp(exp) {
+export function gainStrengthExp(this: IPlayer, exp: number) {
if (isNaN(exp)) {
console.error("ERR: NaN passed into Player.gainStrengthExp()");
return;
@@ -387,7 +393,7 @@ export function gainStrengthExp(exp) {
this.strength = calculateSkillF(this.strength_exp, this.strength_mult * BitNodeMultipliers.StrengthLevelMultiplier);
}
-export function gainDefenseExp(exp) {
+export function gainDefenseExp(this: IPlayer, exp: number) {
if (isNaN(exp)) {
console.error("ERR: NaN passed into player.gainDefenseExp()");
return;
@@ -400,7 +406,7 @@ export function gainDefenseExp(exp) {
this.defense = calculateSkillF(this.defense_exp, this.defense_mult * BitNodeMultipliers.DefenseLevelMultiplier);
}
-export function gainDexterityExp(exp) {
+export function gainDexterityExp(this: IPlayer, exp: number) {
if (isNaN(exp)) {
console.error("ERR: NaN passed into Player.gainDexterityExp()");
return;
@@ -416,7 +422,7 @@ export function gainDexterityExp(exp) {
);
}
-export function gainAgilityExp(exp) {
+export function gainAgilityExp(this: IPlayer, exp: number): void {
if (isNaN(exp)) {
console.error("ERR: NaN passed into Player.gainAgilityExp()");
return;
@@ -429,7 +435,7 @@ export function gainAgilityExp(exp) {
this.agility = calculateSkillF(this.agility_exp, this.agility_mult * BitNodeMultipliers.AgilityLevelMultiplier);
}
-export function gainCharismaExp(exp) {
+export function gainCharismaExp(this: IPlayer, exp: number): void {
if (isNaN(exp)) {
console.error("ERR: NaN passed into Player.gainCharismaExp()");
return;
@@ -442,7 +448,7 @@ export function gainCharismaExp(exp) {
this.charisma = calculateSkillF(this.charisma_exp, this.charisma_mult * BitNodeMultipliers.CharismaLevelMultiplier);
}
-export function gainIntelligenceExp(exp) {
+export function gainIntelligenceExp(this: IPlayer, exp: number): void {
if (isNaN(exp)) {
console.error("ERROR: NaN passed into Player.gainIntelligenceExp()");
return;
@@ -453,7 +459,7 @@ export function gainIntelligenceExp(exp) {
}
//Given a string expression like "str" or "strength", returns the given stat
-export function queryStatFromString(str) {
+export function queryStatFromString(this: IPlayer, str: string): number {
const tempStr = str.toLowerCase();
if (tempStr.includes("hack")) {
return this.hacking_skill;
@@ -476,10 +482,11 @@ export function queryStatFromString(str) {
if (tempStr.includes("int")) {
return this.intelligence;
}
+ return 0;
}
/******* Working functions *******/
-export function resetWorkStatus(generalType, group, workType) {
+export function resetWorkStatus(this: IPlayer, generalType?: string, group?: string, workType?: string): void {
if (this.workType !== CONSTANTS.WorkTypeFaction && generalType === this.workType && group === this.companyName)
return;
if (generalType === this.workType && group === this.currentWorkFactionName && workType === this.factionWorkType)
@@ -513,7 +520,7 @@ export function resetWorkStatus(generalType, group, workType) {
this.className = "";
}
-export function processWorkEarnings(numCycles = 1) {
+export function processWorkEarnings(this: IPlayer, numCycles = 1) {
const focusBonus = this.focus ? 1 : 0.8;
const hackExpGain = focusBonus * this.workHackExpGainRate * numCycles;
const strExpGain = focusBonus * this.workStrExpGainRate * numCycles;
@@ -547,7 +554,7 @@ export function processWorkEarnings(numCycles = 1) {
}
/* Working for Company */
-export function startWork(router, companyName) {
+export function startWork(this: IPlayer, router: IRouter, companyName: string): void {
this.resetWorkStatus(CONSTANTS.WorkTypeCompany, companyName);
this.isWorking = true;
this.focus = true;
@@ -567,16 +574,18 @@ export function startWork(router, companyName) {
router.toWork();
}
-export function cancelationPenalty() {
+export function cancelationPenalty(this: IPlayer) {
const specialIp = SpecialServerIps[this.companyName];
- if (specialIp) {
+ if (typeof specialIp === "string" && specialIp !== "") {
const server = AllServers[specialIp];
- if (server && server.backdoorInstalled) return 0.75;
+ if (server instanceof Server) {
+ if (server && server.backdoorInstalled) return 0.75;
+ }
}
return 0.5;
}
-export function work(numCycles) {
+export function work(this: IPlayer, numCycles: number): boolean {
// Cap the number of cycles being processed to whatever would put you at
// the work time limit (8 hours)
var overMax = false;
@@ -594,13 +603,13 @@ export function work(numCycles) {
// If timeWorked == 8 hours, then finish. You can only gain 8 hours worth of exp and money
if (overMax || this.timeWorked >= CONSTANTS.MillisecondsPer8Hours) {
- return this.finishWork(false);
+ this.finishWork(false);
return true;
}
return false;
}
-export function finishWork(cancelled, sing = false) {
+export function finishWork(this: IPlayer, cancelled: boolean, sing = false): string {
//Since the work was cancelled early, player only gains half of what they've earned so far
if (cancelled) {
this.workRepGained *= this.cancelationPenalty();
@@ -652,8 +661,9 @@ export function finishWork(cancelled, sing = false) {
this.isWorking = false;
+ this.resetWorkStatus();
if (sing) {
- var res =
+ const res =
"You worked a short shift of " +
convertTimeMsToTimeElapsedString(this.timeWorked) +
" and " +
@@ -674,13 +684,14 @@ export function finishWork(cancelled, sing = false) {
" agility exp, and " +
numeralWrapper.formatExp(this.workChaExpGained) +
" charisma exp.";
- this.resetWorkStatus();
+
return res;
}
- this.resetWorkStatus();
+
+ return "";
}
-export function startWorkPartTime(router, companyName) {
+export function startWorkPartTime(this: IPlayer, router: IRouter, companyName: string): void {
this.resetWorkStatus(CONSTANTS.WorkTypeCompanyPartTime, companyName);
this.isWorking = true;
this.focus = true;
@@ -700,7 +711,7 @@ export function startWorkPartTime(router, companyName) {
router.toWork();
}
-export function workPartTime(numCycles) {
+export function workPartTime(this: IPlayer, numCycles: number): boolean {
//Cap the number of cycles being processed to whatever would put you at the
//work time limit (8 hours)
var overMax = false;
@@ -715,13 +726,13 @@ export function workPartTime(numCycles) {
//If timeWorked == 8 hours, then finish. You can only gain 8 hours worth of exp and money
if (overMax || this.timeWorked >= CONSTANTS.MillisecondsPer8Hours) {
- return this.finishWorkPartTime();
+ this.finishWorkPartTime();
return true;
}
return false;
}
-export function finishWorkPartTime(sing = false) {
+export function finishWorkPartTime(this: IPlayer, sing = false): string {
var company = Companies[this.companyName];
company.playerReputation += this.workRepGained;
@@ -750,6 +761,8 @@ export function finishWorkPartTime(sing = false) {
}
this.isWorking = false;
+ this.resetWorkStatus();
+
if (sing) {
var res =
"You worked for " +
@@ -773,22 +786,21 @@ export function finishWorkPartTime(sing = false) {
" agility exp, and " +
numeralWrapper.formatExp(this.workChaExpGained) +
" charisma exp";
- this.resetWorkStatus();
return res;
}
- this.resetWorkStatus();
+ return "";
}
-export function startFocusing() {
+export function startFocusing(this: IPlayer): void {
this.focus = true;
}
-export function stopFocusing() {
+export function stopFocusing(this: IPlayer): void {
this.focus = false;
}
/* Working for Faction */
-export function startFactionWork(router, faction) {
+export function startFactionWork(this: IPlayer, router: IRouter, faction: Faction): void {
//Update reputation gain rate to account for faction favor
var favorMult = 1 + faction.favor / 100;
if (isNaN(favorMult)) {
@@ -806,7 +818,7 @@ export function startFactionWork(router, faction) {
router.toWork();
}
-export function startFactionHackWork(router, faction) {
+export function startFactionHackWork(this: IPlayer, router: IRouter, faction: Faction) {
this.resetWorkStatus(CONSTANTS.WorkTypeFaction, faction.name, CONSTANTS.FactionWorkHacking);
this.workHackExpGainRate = 0.15 * this.hacking_exp_mult * BitNodeMultipliers.FactionWorkExpGain;
@@ -821,7 +833,7 @@ export function startFactionHackWork(router, faction) {
this.startFactionWork(router, faction);
}
-export function startFactionFieldWork(router, faction) {
+export function startFactionFieldWork(this: IPlayer, router: IRouter, faction: Faction) {
this.resetWorkStatus(CONSTANTS.WorkTypeFaction, faction.name, CONSTANTS.FactionWorkField);
this.workHackExpGainRate = 0.1 * this.hacking_exp_mult * BitNodeMultipliers.FactionWorkExpGain;
@@ -838,7 +850,7 @@ export function startFactionFieldWork(router, faction) {
this.startFactionWork(router, faction);
}
-export function startFactionSecurityWork(router, faction) {
+export function startFactionSecurityWork(this: IPlayer, router: IRouter, faction: Faction) {
this.resetWorkStatus(CONSTANTS.WorkTypeFaction, faction.name, CONSTANTS.FactionWorkSecurity);
this.workHackExpGainRate = 0.05 * this.hacking_exp_mult * BitNodeMultipliers.FactionWorkExpGain;
@@ -855,7 +867,7 @@ export function startFactionSecurityWork(router, faction) {
this.startFactionWork(router, faction);
}
-export function workForFaction(numCycles) {
+export function workForFaction(this: IPlayer, numCycles: number) {
const faction = Factions[this.currentWorkFactionName];
//Constantly update the rep gain rate
@@ -874,7 +886,7 @@ export function workForFaction(numCycles) {
}
//Cap the number of cycles being processed to whatever would put you at limit (20 hours)
- var overMax = false;
+ let overMax = false;
if (this.timeWorked + CONSTANTS._idleSpeed * numCycles >= CONSTANTS.MillisecondsPer20Hours) {
overMax = true;
numCycles = Math.round((CONSTANTS.MillisecondsPer20Hours - this.timeWorked) / CONSTANTS._idleSpeed);
@@ -891,8 +903,8 @@ export function workForFaction(numCycles) {
return false;
}
-export function finishFactionWork(cancelled, sing = false) {
- var faction = Factions[this.currentWorkFactionName];
+export function finishFactionWork(this: IPlayer, cancelled: boolean, sing = false): string {
+ const faction = Factions[this.currentWorkFactionName];
faction.playerReputation += this.workRepGained;
this.updateSkillLevels();
@@ -919,7 +931,7 @@ export function finishFactionWork(cancelled, sing = false) {
}
this.isWorking = false;
-
+ this.resetWorkStatus();
if (sing) {
var res =
"You worked for your faction " +
@@ -942,14 +954,14 @@ export function finishFactionWork(cancelled, sing = false) {
" agi exp, and " +
numeralWrapper.formatExp(this.workChaExpGained) +
" cha exp.";
- this.resetWorkStatus();
+
return res;
}
- this.resetWorkStatus();
+ return "";
}
//Money gained per game cycle
-export function getWorkMoneyGain() {
+export function getWorkMoneyGain(this: IPlayer): number {
// If player has SF-11, calculate salary multiplier from favor
let bn11Mult = 1;
const company = Companies[this.companyName];
@@ -975,7 +987,7 @@ export function getWorkMoneyGain() {
}
//Hack exp gained per game cycle
-export function getWorkHackExpGain() {
+export function getWorkHackExpGain(this: IPlayer): number {
const company = Companies[this.companyName];
const companyPositionName = this.jobs[this.companyName];
const companyPosition = CompanyPositions[companyPositionName];
@@ -999,7 +1011,7 @@ export function getWorkHackExpGain() {
}
//Str exp gained per game cycle
-export function getWorkStrExpGain() {
+export function getWorkStrExpGain(this: IPlayer): number {
const company = Companies[this.companyName];
const companyPositionName = this.jobs[this.companyName];
const companyPosition = CompanyPositions[companyPositionName];
@@ -1023,7 +1035,7 @@ export function getWorkStrExpGain() {
}
//Def exp gained per game cycle
-export function getWorkDefExpGain() {
+export function getWorkDefExpGain(this: IPlayer): number {
const company = Companies[this.companyName];
const companyPositionName = this.jobs[this.companyName];
const companyPosition = CompanyPositions[companyPositionName];
@@ -1047,7 +1059,7 @@ export function getWorkDefExpGain() {
}
//Dex exp gained per game cycle
-export function getWorkDexExpGain() {
+export function getWorkDexExpGain(this: IPlayer): number {
const company = Companies[this.companyName];
const companyPositionName = this.jobs[this.companyName];
const companyPosition = CompanyPositions[companyPositionName];
@@ -1071,7 +1083,7 @@ export function getWorkDexExpGain() {
}
//Agi exp gained per game cycle
-export function getWorkAgiExpGain() {
+export function getWorkAgiExpGain(this: IPlayer): number {
const company = Companies[this.companyName];
const companyPositionName = this.jobs[this.companyName];
const companyPosition = CompanyPositions[companyPositionName];
@@ -1095,7 +1107,7 @@ export function getWorkAgiExpGain() {
}
//Charisma exp gained per game cycle
-export function getWorkChaExpGain() {
+export function getWorkChaExpGain(this: IPlayer): number {
const company = Companies[this.companyName];
const companyPositionName = this.jobs[this.companyName];
const companyPosition = CompanyPositions[companyPositionName];
@@ -1119,7 +1131,7 @@ export function getWorkChaExpGain() {
}
//Reputation gained per game cycle
-export function getWorkRepGain() {
+export function getWorkRepGain(this: IPlayer): number {
const company = Companies[this.companyName];
const companyPositionName = this.jobs[this.companyName];
const companyPosition = CompanyPositions[companyPositionName];
@@ -1154,7 +1166,7 @@ export function getWorkRepGain() {
return jobPerformance * this.company_rep_mult * favorMult;
}
-// export function getFactionSecurityWorkRepGain() {
+// export function getFactionSecurityWorkRepGain(this: IPlayer) {
// var t = 0.9 * (this.hacking_skill / CONSTANTS.MaxSkillLevel +
// this.strength / CONSTANTS.MaxSkillLevel +
// this.defense / CONSTANTS.MaxSkillLevel +
@@ -1163,7 +1175,7 @@ export function getWorkRepGain() {
// return t * this.faction_rep_mult;
// }
-// export function getFactionFieldWorkRepGain() {
+// export function getFactionFieldWorkRepGain(this: IPlayer) {
// var t = 0.9 * (this.hacking_skill / CONSTANTS.MaxSkillLevel +
// this.strength / CONSTANTS.MaxSkillLevel +
// this.defense / CONSTANTS.MaxSkillLevel +
@@ -1175,7 +1187,13 @@ export function getWorkRepGain() {
// }
/* Creating a Program */
-export function startCreateProgramWork(router, programName, time, reqLevel) {
+export function startCreateProgramWork(
+ this: IPlayer,
+ router: IRouter,
+ programName: string,
+ time: number,
+ reqLevel: number,
+): void {
this.resetWorkStatus();
this.isWorking = true;
this.focus = true;
@@ -1210,7 +1228,7 @@ export function startCreateProgramWork(router, programName, time, reqLevel) {
router.toWork();
}
-export function createProgramWork(numCycles) {
+export function createProgramWork(this: IPlayer, numCycles: number): boolean {
//Higher hacking skill will allow you to create programs faster
var reqLvl = this.createProgramReqLvl;
var skillMult = (this.hacking_skill / reqLvl) * this.getIntelligenceBonus(3); //This should always be greater than 1;
@@ -1227,7 +1245,7 @@ export function createProgramWork(numCycles) {
return false;
}
-export function finishCreateProgramWork(cancelled) {
+export function finishCreateProgramWork(this: IPlayer, cancelled: boolean): string {
var programName = this.createProgramName;
if (cancelled === false) {
dialogBoxCreate(
@@ -1248,10 +1266,11 @@ export function finishCreateProgramWork(cancelled) {
this.isWorking = false;
this.resetWorkStatus();
+ return "You've finished creating " + programName + "! The new program can be found on your home computer.";
}
/* Studying/Taking Classes */
-export function startClass(router, costMult, expMult, className) {
+export function startClass(this: IPlayer, router: IRouter, costMult: number, expMult: number, className: string): void {
this.resetWorkStatus();
this.isWorking = true;
this.focus = true;
@@ -1325,7 +1344,7 @@ export function startClass(router, costMult, expMult, className) {
router.toWork();
}
-export function takeClass(numCycles) {
+export function takeClass(this: IPlayer, numCycles: number): boolean {
this.timeWorked += CONSTANTS._idleSpeed * numCycles;
this.processWorkEarnings(numCycles);
return false;
@@ -1333,7 +1352,7 @@ export function takeClass(numCycles) {
//The 'sing' argument defines whether or not this function was called
//through a Singularity Netscript function
-export function finishClass(sing = false) {
+export function finishClass(this: IPlayer, sing = false): string {
this.gainIntelligenceExp(CONSTANTS.IntelligenceClassBaseExpGain * Math.round(this.timeWorked / 1000));
if (this.workMoneyGained > 0) {
@@ -1388,22 +1407,24 @@ export function finishClass(sing = false) {
return res;
}
this.resetWorkStatus();
+ return "";
}
//The EXP and $ gains are hardcoded. Time is in ms
export function startCrime(
- router,
- crimeType,
- hackExp,
- strExp,
- defExp,
- dexExp,
- agiExp,
- chaExp,
- money,
- time,
- singParams = null,
-) {
+ this: IPlayer,
+ router: IRouter,
+ crimeType: string,
+ hackExp: number,
+ strExp: number,
+ defExp: number,
+ dexExp: number,
+ agiExp: number,
+ chaExp: number,
+ money: number,
+ time: number,
+ workerscript: WorkerScript | null = null,
+): void {
this.crimeType = crimeType;
this.resetWorkStatus();
@@ -1411,9 +1432,9 @@ export function startCrime(
this.focus = true;
this.workType = CONSTANTS.WorkTypeCrime;
- if (singParams && singParams.workerscript) {
+ if (workerscript !== null) {
this.committingCrimeThruSingFn = true;
- this.singFnCrimeWorkerScript = singParams.workerscript;
+ this.singFnCrimeWorkerScript = workerscript;
}
this.workHackExpGained = hackExp * this.hacking_exp_mult * BitNodeMultipliers.CrimeExpGain;
@@ -1428,7 +1449,7 @@ export function startCrime(
router.toWork();
}
-export function commitCrime(numCycles) {
+export function commitCrime(this: IPlayer, numCycles: number): boolean {
this.timeWorked += CONSTANTS._idleSpeed * numCycles;
if (this.timeWorked >= this.timeNeededToCompleteWork) {
@@ -1438,7 +1459,7 @@ export function commitCrime(numCycles) {
return false;
}
-export function finishCrime(cancelled) {
+export function finishCrime(this: IPlayer, cancelled: boolean): string {
//Determine crime success/failure
if (!cancelled) {
if (determineCrimeSuccess(this, this.crimeType)) {
@@ -1454,6 +1475,7 @@ export function finishCrime(cancelled) {
dialogBoxCreate(
`ERR: Unrecognized crime type (${this.crimeType}). This is probably a bug please contact the developer`,
);
+ return "";
}
this.gainMoney(this.workMoneyGained);
this.recordMoneySource(this.workMoneyGained, "crime");
@@ -1470,12 +1492,10 @@ export function finishCrime(cancelled) {
this.workDexExpGained *= 2;
this.workAgiExpGained *= 2;
this.workChaExpGained *= 2;
- if (this.committingCrimeThruSingFn) {
- if (
- this.singFnCrimeWorkerScript.disableLogs.ALL == null &&
- this.singFnCrimeWorkerScript.disableLogs.commitCrime == null
- ) {
- this.singFnCrimeWorkerScript.scriptRef.log(
+ const ws = this.singFnCrimeWorkerScript;
+ if (this.committingCrimeThruSingFn && ws !== null) {
+ if (ws.disableLogs.ALL == null && ws.disableLogs.commitCrime == null) {
+ ws.scriptRef.log(
"Crime successful! Gained " +
numeralWrapper.formatMoney(this.workMoneyGained) +
", " +
@@ -1524,12 +1544,10 @@ export function finishCrime(cancelled) {
this.workDexExpGained /= 2;
this.workAgiExpGained /= 2;
this.workChaExpGained /= 2;
- if (this.committingCrimeThruSingFn) {
- if (
- this.singFnCrimeWorkerScript.disableLogs.ALL == null &&
- this.singFnCrimeWorkerScript.disableLogs.commitCrime == null
- ) {
- this.singFnCrimeWorkerScript.scriptRef.log(
+ const ws = this.singFnCrimeWorkerScript;
+ if (this.committingCrimeThruSingFn && ws !== null) {
+ if (ws.disableLogs.ALL == null && ws.disableLogs.commitCrime == null) {
+ ws.scriptRef.log(
"Crime failed! Gained " +
numeralWrapper.formatExp(this.workHackExpGained) +
" hack exp, " +
@@ -1580,15 +1598,16 @@ export function finishCrime(cancelled) {
this.isWorking = false;
this.crimeType = "";
this.resetWorkStatus();
+ return "";
}
//Cancels the player's current "work" assignment and gives the proper rewards
//Used only for Singularity functions, so no popups are created
-export function singularityStopWork() {
+export function singularityStopWork(this: IPlayer): string {
if (!this.isWorking) {
return "";
}
- var res; //Earnings text for work
+ let res = ""; //Earnings text for work
switch (this.workType) {
case CONSTANTS.WorkTypeStudyClass:
res = this.finishClass(true);
@@ -1616,10 +1635,10 @@ export function singularityStopWork() {
}
// Returns true if hospitalized, false otherwise
-export function takeDamage(amt) {
+export function takeDamage(this: IPlayer, amt: number): boolean {
if (typeof amt !== "number") {
console.warn(`Player.takeDamage() called without a numeric argument: ${amt}`);
- return;
+ return false;
}
this.hp -= amt;
@@ -1631,7 +1650,7 @@ export function takeDamage(amt) {
}
}
-export function regenerateHp(amt) {
+export function regenerateHp(this: IPlayer, amt: number): void {
if (typeof amt !== "number") {
console.warn(`Player.regenerateHp() called without a numeric argument: ${amt}`);
return;
@@ -1642,7 +1661,7 @@ export function regenerateHp(amt) {
}
}
-export function hospitalize() {
+export function hospitalize(this: IPlayer): number {
const cost = getHospitalizationCost(this);
if (Settings.SuppressHospitalizationPopup === false) {
dialogBoxCreate(
@@ -1664,7 +1683,7 @@ export function hospitalize() {
//Determines the job that the Player should get (if any) at the current company
//The 'sing' argument designates whether or not this is being called from
//the applyToCompany() Netscript Singularity function
-export function applyForJob(entryPosType, sing = false) {
+export function applyForJob(this: IPlayer, entryPosType: CompanyPosition, sing = false): boolean {
// Get current company and job
let currCompany = null;
if (this.companyName !== "") {
@@ -1675,25 +1694,18 @@ export function applyForJob(entryPosType, sing = false) {
// Get company that's being applied to
const company = Companies[this.location]; //Company being applied to
if (!(company instanceof Company)) {
- if (sing) {
- return "ERROR: Invalid company name: " + this.location + ". applyToCompany() failed";
- } else {
- console.error(
- `Could not find company that matches the location: ${this.location}. Player.applyToCompany() failed`,
- );
- return;
- }
+ console.error(`Could not find company that matches the location: ${this.location}. Player.applyToCompany() failed`);
+ return false;
}
let pos = entryPosType;
if (!this.isQualified(company, pos)) {
- var reqText = getJobRequirementText(company, pos);
- if (sing) {
- return false;
+ const reqText = getJobRequirementText(company, pos);
+ if (!sing) {
+ dialogBoxCreate("Unforunately, you do not qualify for this position
" + reqText);
}
- dialogBoxCreate("Unforunately, you do not qualify for this position
" + reqText);
- return;
+ return false;
}
while (true) {
@@ -1717,40 +1729,43 @@ export function applyForJob(entryPosType, sing = false) {
//Check if the determined job is the same as the player's current job
if (currCompany != null) {
if (currCompany.name == company.name && pos.name == currPositionName) {
- var nextPos = getNextCompanyPositionHelper(pos);
+ const nextPos = getNextCompanyPositionHelper(pos);
if (nextPos == null) {
- if (sing) {
- return false;
+ if (!sing) {
+ dialogBoxCreate("You are already at the highest position for your field! No promotion available");
}
- dialogBoxCreate("You are already at the highest position for your field! No promotion available");
+ return false;
} else if (company.hasPosition(nextPos)) {
- if (sing) {
- return false;
+ if (!sing) {
+ var reqText = getJobRequirementText(company, nextPos);
+ dialogBoxCreate("Unfortunately, you do not qualify for a promotion
" + reqText);
}
- var reqText = getJobRequirementText(company, nextPos);
- dialogBoxCreate("Unfortunately, you do not qualify for a promotion
" + reqText);
+ return false;
} else {
- if (sing) {
- return false;
+ if (!sing) {
+ dialogBoxCreate("You are already at the highest position for your field! No promotion available");
}
- dialogBoxCreate("You are already at the highest position for your field! No promotion available");
+ return false;
}
- return; //Same job, do nothing
+ return false; //Same job, do nothing
}
}
this.jobs[company.name] = pos.name;
this.companyName = this.location;
- if (sing) {
- return true;
+ if (!sing) {
+ dialogBoxCreate("Congratulations! You were offered a new job at " + this.companyName + " as a " + pos.name + "!");
}
-
- dialogBoxCreate("Congratulations! You were offered a new job at " + this.companyName + " as a " + pos.name + "!");
+ return true;
}
//Returns your next position at a company given the field (software, business, etc.)
-export function getNextCompanyPosition(company, entryPosType) {
+export function getNextCompanyPosition(
+ this: IPlayer,
+ company: Company,
+ entryPosType: CompanyPosition,
+): CompanyPosition | null {
var currCompany = null;
if (this.companyName !== "") {
currCompany = Companies[this.companyName];
@@ -1784,143 +1799,149 @@ export function getNextCompanyPosition(company, entryPosType) {
return entryPosType;
}
-export function quitJob(company) {
+export function quitJob(this: IPlayer, company: string): void {
this.isWorking = false;
this.companyName = "";
delete this.jobs[company];
}
-export function applyForSoftwareJob(sing = false) {
+export function applyForSoftwareJob(this: IPlayer, sing = false): boolean {
return this.applyForJob(CompanyPositions[posNames.SoftwareCompanyPositions[0]], sing);
}
-export function applyForSoftwareConsultantJob(sing = false) {
+export function applyForSoftwareConsultantJob(this: IPlayer, sing = false): boolean {
return this.applyForJob(CompanyPositions[posNames.SoftwareConsultantCompanyPositions[0]], sing);
}
-export function applyForItJob(sing = false) {
+export function applyForItJob(this: IPlayer, sing = false): boolean {
return this.applyForJob(CompanyPositions[posNames.ITCompanyPositions[0]], sing);
}
-export function applyForSecurityEngineerJob(sing = false) {
+export function applyForSecurityEngineerJob(this: IPlayer, sing = false): boolean {
var company = Companies[this.location]; //Company being applied to
if (this.isQualified(company, CompanyPositions[posNames.SecurityEngineerCompanyPositions[0]])) {
return this.applyForJob(CompanyPositions[posNames.SecurityEngineerCompanyPositions[0]], sing);
} else {
- if (sing) {
- return false;
+ if (!sing) {
+ dialogBoxCreate("Unforunately, you do not qualify for this position");
}
- dialogBoxCreate("Unforunately, you do not qualify for this position");
+ return false;
}
}
-export function applyForNetworkEngineerJob(sing = false) {
+export function applyForNetworkEngineerJob(this: IPlayer, sing = false): boolean {
var company = Companies[this.location]; //Company being applied to
if (this.isQualified(company, CompanyPositions[posNames.NetworkEngineerCompanyPositions[0]])) {
- return this.applyForJob(CompanyPositions[posNames.NetworkEngineerCompanyPositions[0]], sing);
+ const pos = CompanyPositions[posNames.NetworkEngineerCompanyPositions[0]];
+ return this.applyForJob(pos, sing);
} else {
- if (sing) {
- return false;
+ if (!sing) {
+ dialogBoxCreate("Unforunately, you do not qualify for this position");
}
- dialogBoxCreate("Unforunately, you do not qualify for this position");
+ return false;
}
}
-export function applyForBusinessJob(sing = false) {
+export function applyForBusinessJob(this: IPlayer, sing = false): boolean {
return this.applyForJob(CompanyPositions[posNames.BusinessCompanyPositions[0]], sing);
}
-export function applyForBusinessConsultantJob(sing = false) {
+export function applyForBusinessConsultantJob(this: IPlayer, sing = false): boolean {
return this.applyForJob(CompanyPositions[posNames.BusinessConsultantCompanyPositions[0]], sing);
}
-export function applyForSecurityJob(sing = false) {
+export function applyForSecurityJob(this: IPlayer, sing = false): boolean {
// TODO Police Jobs
// Indexing starts at 2 because 0 is for police officer
return this.applyForJob(CompanyPositions[posNames.SecurityCompanyPositions[2]], sing);
}
-export function applyForAgentJob(sing = false) {
+export function applyForAgentJob(this: IPlayer, sing = false): boolean {
var company = Companies[this.location]; //Company being applied to
if (this.isQualified(company, CompanyPositions[posNames.AgentCompanyPositions[0]])) {
- return this.applyForJob(CompanyPositions[posNames.AgentCompanyPositions[0]], sing);
+ const pos = CompanyPositions[posNames.AgentCompanyPositions[0]];
+ return this.applyForJob(pos, sing);
} else {
- if (sing) {
- return false;
+ if (!sing) {
+ dialogBoxCreate("Unforunately, you do not qualify for this position");
}
- dialogBoxCreate("Unforunately, you do not qualify for this position");
+ return false;
}
}
-export function applyForEmployeeJob(sing = false) {
+export function applyForEmployeeJob(this: IPlayer, sing = false): boolean {
var company = Companies[this.location]; //Company being applied to
if (this.isQualified(company, CompanyPositions[posNames.MiscCompanyPositions[1]])) {
this.companyName = company.name;
this.jobs[company.name] = posNames.MiscCompanyPositions[1];
- if (sing) {
- return true;
+ if (!sing) {
+ dialogBoxCreate("Congratulations, you are now employed at " + this.companyName);
}
- dialogBoxCreate("Congratulations, you are now employed at " + this.companyName);
+
+ return true;
} else {
- if (sing) {
- return false;
+ if (!sing) {
+ dialogBoxCreate("Unforunately, you do not qualify for this position");
}
- dialogBoxCreate("Unforunately, you do not qualify for this position");
+
+ return false;
}
}
-export function applyForPartTimeEmployeeJob(sing = false) {
+export function applyForPartTimeEmployeeJob(this: IPlayer, sing = false): boolean {
var company = Companies[this.location]; //Company being applied to
if (this.isQualified(company, CompanyPositions[posNames.PartTimeCompanyPositions[1]])) {
this.jobs[company.name] = posNames.PartTimeCompanyPositions[1];
- if (sing) {
- return true;
+ if (!sing) {
+ dialogBoxCreate("Congratulations, you are now employed part-time at " + this.companyName);
}
- dialogBoxCreate("Congratulations, you are now employed part-time at " + this.companyName);
+
+ return true;
} else {
- if (sing) {
- return false;
+ if (!sing) {
+ dialogBoxCreate("Unforunately, you do not qualify for this position");
}
- dialogBoxCreate("Unforunately, you do not qualify for this position");
+
+ return false;
}
}
-export function applyForWaiterJob(sing = false) {
+export function applyForWaiterJob(this: IPlayer, sing = false): boolean {
var company = Companies[this.location]; //Company being applied to
if (this.isQualified(company, CompanyPositions[posNames.MiscCompanyPositions[0]])) {
this.companyName = company.name;
this.jobs[company.name] = posNames.MiscCompanyPositions[0];
- if (sing) {
- return true;
+ if (!sing) {
+ dialogBoxCreate("Congratulations, you are now employed as a waiter at " + this.companyName);
}
- dialogBoxCreate("Congratulations, you are now employed as a waiter at " + this.companyName);
+ return true;
} else {
- if (sing) {
- return false;
+ if (!sing) {
+ dialogBoxCreate("Unforunately, you do not qualify for this position");
}
- dialogBoxCreate("Unforunately, you do not qualify for this position");
+ return false;
}
}
-export function applyForPartTimeWaiterJob(sing = false) {
+export function applyForPartTimeWaiterJob(this: IPlayer, sing = false): boolean {
var company = Companies[this.location]; //Company being applied to
if (this.isQualified(company, CompanyPositions[posNames.PartTimeCompanyPositions[0]])) {
this.companyName = company.name;
this.jobs[company.name] = posNames.PartTimeCompanyPositions[0];
- if (sing) {
- return true;
+ if (!sing) {
+ dialogBoxCreate("Congratulations, you are now employed as a part-time waiter at " + this.companyName);
}
- dialogBoxCreate("Congratulations, you are now employed as a part-time waiter at " + this.companyName);
+ return true;
} else {
- if (sing) {
- return false;
+ if (!sing) {
+ dialogBoxCreate("Unforunately, you do not qualify for this position");
}
- dialogBoxCreate("Unforunately, you do not qualify for this position");
+ return false;
}
}
//Checks if the Player is qualified for a certain position
-export function isQualified(company, position) {
+export function isQualified(this: IPlayer, company: Company, position: CompanyPosition): boolean {
var offset = company.jobStatReqOffset;
var reqHacking = position.requiredHacking > 0 ? position.requiredHacking + offset : 0;
var reqStrength = position.requiredStrength > 0 ? position.requiredStrength + offset : 0;
@@ -1944,7 +1965,7 @@ export function isQualified(company, position) {
}
/********** Reapplying Augmentations and Source File ***********/
-export function reapplyAllAugmentations(resetMultipliers = true) {
+export function reapplyAllAugmentations(this: IPlayer, resetMultipliers = true): void {
if (resetMultipliers) {
this.resetMultipliers();
}
@@ -1974,7 +1995,7 @@ export function reapplyAllAugmentations(resetMultipliers = true) {
this.updateSkillLevels();
}
-export function reapplyAllSourceFiles() {
+export function reapplyAllSourceFiles(this: IPlayer): void {
//Will always be called after reapplyAllAugmentations() so multipliers do not have to be reset
//this.resetMultipliers();
@@ -1994,7 +2015,7 @@ export function reapplyAllSourceFiles() {
//This function sets the requirements to join a Faction. It checks whether the Player meets
//those requirements and will return an array of all factions that the Player should
//receive an invitation to
-export function checkForFactionInvitations() {
+export function checkForFactionInvitations(this: IPlayer) {
let invitedFactions = []; //Array which will hold all Factions the player should be invited to
var numAugmentations = this.augmentations.length;
@@ -2003,7 +2024,7 @@ export function checkForFactionInvitations() {
const allPositions = Object.values(this.jobs);
// Given a company name, safely returns the reputation (returns 0 if invalid company is specified)
- function getCompanyRep(companyName) {
+ function getCompanyRep(companyName: string): number {
const company = Companies[companyName];
if (company == null) {
return 0;
@@ -2016,7 +2037,7 @@ export function checkForFactionInvitations() {
// the requirements for the specified company. There are two requirements:
// 1. High enough reputation
// 2. Player is employed at the company
- function checkMegacorpRequirements(companyName, repNeeded = CONSTANTS.CorpFactionRepRequirement) {
+ function checkMegacorpRequirements(companyName: string, repNeeded = CONSTANTS.CorpFactionRepRequirement): boolean {
return allCompanies.includes(companyName) && getCompanyRep(companyName) > repNeeded;
}
@@ -2168,8 +2189,11 @@ export function checkForFactionInvitations() {
}
//Fulcrum Secret Technologies - If u've unlocked fulcrum secret technolgoies server and have a high rep with the company
- var fulcrumsecrettechonologiesFac = Factions["Fulcrum Secret Technologies"];
- var fulcrumSecretServer = AllServers[SpecialServerIps[SpecialServerNames.FulcrumSecretTechnologies]];
+ const fulcrumsecrettechonologiesFac = Factions["Fulcrum Secret Technologies"];
+ const fulcrumIP = SpecialServerIps[SpecialServerNames.BitRunnersServer];
+ if (typeof fulcrumIP !== "string") throw new Error("Fulcrum Secret Technologies should be string");
+ const fulcrumSecretServer = AllServers[fulcrumIP];
+ if (!(fulcrumSecretServer instanceof Server)) throw new Error("Fulcrum Secret Technologies should be normal server");
if (fulcrumSecretServer == null) {
console.error("Could not find Fulcrum Secret Technologies Server");
} else {
@@ -2185,8 +2209,11 @@ export function checkForFactionInvitations() {
}
//BitRunners
- var bitrunnersFac = Factions["BitRunners"];
- var bitrunnersServer = AllServers[SpecialServerIps[SpecialServerNames.BitRunnersServer]];
+ const bitrunnersFac = Factions["BitRunners"];
+ const bitrunnerIP = SpecialServerIps[SpecialServerNames.BitRunnersServer];
+ if (typeof bitrunnerIP !== "string") throw new Error("BitRunners should be string");
+ const bitrunnersServer = AllServers[bitrunnerIP];
+ if (!(bitrunnersServer instanceof Server)) throw new Error("BitRunners should be normal server");
if (bitrunnersServer == null) {
console.error("Could not find BitRunners Server");
} else if (
@@ -2199,8 +2226,12 @@ export function checkForFactionInvitations() {
}
//The Black Hand
- var theblackhandFac = Factions["The Black Hand"];
- var blackhandServer = AllServers[SpecialServerIps[SpecialServerNames.TheBlackHandServer]];
+
+ const theblackhandFac = Factions["The Black Hand"];
+ const tbhIP = SpecialServerIps[SpecialServerNames.TheBlackHandServer];
+ if (typeof tbhIP !== "string") throw new Error("TheBlackHand should be string");
+ const blackhandServer = AllServers[tbhIP];
+ if (!(blackhandServer instanceof Server)) throw new Error("TheBlackHand should be normal server");
if (blackhandServer == null) {
console.error("Could not find The Black Hand Server");
} else if (
@@ -2213,8 +2244,11 @@ export function checkForFactionInvitations() {
}
//NiteSec
- var nitesecFac = Factions["NiteSec"];
- var nitesecServer = AllServers[SpecialServerIps[SpecialServerNames.NiteSecServer]];
+ const nitesecFac = Factions["NiteSec"];
+ const nitesecIP = SpecialServerIps[SpecialServerNames.NiteSecServer];
+ if (typeof nitesecIP !== "string") throw new Error("NiteSec should be string");
+ const nitesecServer = AllServers[nitesecIP];
+ if (!(nitesecServer instanceof Server)) throw new Error("NiteSec should be normal server");
if (nitesecServer == null) {
console.error("Could not find NiteSec Server");
} else if (
@@ -2410,17 +2444,17 @@ export function checkForFactionInvitations() {
var totalHacknetCores = 0;
var totalHacknetLevels = 0;
for (let i = 0; i < this.hacknetNodes.length; ++i) {
- if (hasHacknetServers(this)) {
- const hserver = AllServers[this.hacknetNodes[i]];
- if (hserver) {
- totalHacknetLevels += hserver.level;
- totalHacknetRam += hserver.maxRam;
- totalHacknetCores += hserver.cores;
- }
+ const v = this.hacknetNodes[i];
+ if (typeof v === "string") {
+ const hserver = AllServers[v];
+ if (hserver instanceof Server) throw new Error("player hacknet server was not HacknetServer");
+ totalHacknetLevels += hserver.level;
+ totalHacknetRam += hserver.maxRam;
+ totalHacknetCores += hserver.cores;
} else {
- totalHacknetLevels += this.hacknetNodes[i].level;
- totalHacknetRam += this.hacknetNodes[i].ram;
- totalHacknetCores += this.hacknetNodes[i].cores;
+ totalHacknetLevels += v.level;
+ totalHacknetRam += v.ram;
+ totalHacknetCores += v.cores;
}
}
if (
@@ -2449,8 +2483,11 @@ export function checkForFactionInvitations() {
}
//CyberSec
- var cybersecFac = Factions["CyberSec"];
- var cybersecServer = AllServers[SpecialServerIps[SpecialServerNames.CyberSecServer]];
+ const cybersecFac = Factions["CyberSec"];
+ const cyberSecIP = SpecialServerIps[SpecialServerNames.CyberSecServer];
+ if (typeof cyberSecIP !== "string") throw new Error("cybersec should be string");
+ const cybersecServer = AllServers[cyberSecIP];
+ if (!(cybersecServer instanceof Server)) throw new Error("cybersec should be normal server");
if (cybersecServer == null) {
console.error("Could not find CyberSec Server");
} else if (
@@ -2466,11 +2503,11 @@ export function checkForFactionInvitations() {
}
/************* BitNodes **************/
-export function setBitNodeNumber(n) {
+export function setBitNodeNumber(this: IPlayer, n: number) {
this.bitNodeN = n;
}
-export function queueAugmentation(name) {
+export function queueAugmentation(this: IPlayer, name: string) {
for (const i in this.queuedAugmentations) {
if (this.queuedAugmentations[i].name == name) {
console.warn(`tried to queue ${name} twice, this may be a bug`);
@@ -2485,12 +2522,11 @@ export function queueAugmentation(name) {
}
}
- this.firstAugPurchased = true;
this.queuedAugmentations.push(new PlayerOwnedAugmentation(name));
}
/************* Coding Contracts **************/
-export function gainCodingContractReward(reward, difficulty = 1) {
+export function gainCodingContractReward(this: IPlayer, reward: ICodingContractReward, difficulty = 1) {
if (reward == null || reward.type == null || reward == null) {
return `No reward for this contract`;
}
@@ -2552,7 +2588,7 @@ export function gainCodingContractReward(reward, difficulty = 1) {
/* eslint-enable no-case-declarations */
}
-export function travel(to) {
+export function travel(this: IPlayer, to: CityName) {
if (Cities[to] == null) {
console.warn(`Player.travel() called with invalid city: ${to}`);
return false;
@@ -2562,7 +2598,7 @@ export function travel(to) {
return true;
}
-export function gotoLocation(to) {
+export function gotoLocation(this: IPlayer, to: LocationName) {
if (Locations[to] == null) {
console.warn(`Player.gotoLocation() called with invalid location: ${to}`);
return false;
@@ -2572,20 +2608,20 @@ export function gotoLocation(to) {
return true;
}
-export function canAccessResleeving() {
+export function canAccessResleeving(this: IPlayer) {
return this.bitNodeN === 10 || SourceFileFlags[10] > 0;
}
-export function giveExploit(exploit) {
+export function giveExploit(this: IPlayer, exploit: Exploit) {
if (!this.exploits.includes(exploit)) {
this.exploits.push(exploit);
}
}
-export function getIntelligenceBonus(weight) {
+export function getIntelligenceBonus(this: IPlayer, weight: number) {
return calculateIntelligenceBonus(this.intelligence, weight);
}
-export function getCasinoWinnings() {
+export function getCasinoWinnings(this: IPlayer) {
return this.moneySourceA.casino;
}
diff --git a/src/PersonObjects/Player/PlayerObjectServerMethods.ts b/src/PersonObjects/Player/PlayerObjectServerMethods.ts
index 2361fa6ef..b9bf0e60b 100644
--- a/src/PersonObjects/Player/PlayerObjectServerMethods.ts
+++ b/src/PersonObjects/Player/PlayerObjectServerMethods.ts
@@ -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 {
diff --git a/src/Player.d.ts b/src/Player.d.ts
deleted file mode 100644
index a4e5b3f7a..000000000
--- a/src/Player.d.ts
+++ /dev/null
@@ -1,3 +0,0 @@
-import { IPlayer } from "./PersonObjects/IPlayer";
-
-export declare let Player: IPlayer;
diff --git a/src/Player.js b/src/Player.ts
similarity index 85%
rename from src/Player.js
rename to src/Player.ts
index 79db73bfc..852d757c5 100644
--- a/src/Player.js
+++ b/src/Player.ts
@@ -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);
diff --git a/src/Programs/data/ProgramsMetadata.ts b/src/Programs/data/ProgramsMetadata.ts
index 45ca6b7dc..09ea12820 100644
--- a/src/Programs/data/ProgramsMetadata.ts
+++ b/src/Programs/data/ProgramsMetadata.ts
@@ -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;
}
diff --git a/src/Script/RunningScript.ts b/src/Script/RunningScript.ts
index 683b095be..acf9c0f52 100644
--- a/src/Script/RunningScript.ts
+++ b/src/Script/RunningScript.ts
@@ -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";
diff --git a/src/ScriptEditor/ui/Root.tsx b/src/ScriptEditor/ui/Root.tsx
index 5d6b0f53e..ec3fe83e9 100644
--- a/src/ScriptEditor/ui/Root.tsx
+++ b/src/ScriptEditor/ui/Root.tsx
@@ -11,7 +11,6 @@ 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 { Script } from "../../Script/Script";
import { TextFile } from "../../TextFile";
@@ -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) {
diff --git a/src/Sidebar/ui/SidebarRoot.tsx b/src/Sidebar/ui/SidebarRoot.tsx
index 4138a8522..af9986c05 100644
--- a/src/Sidebar/ui/SidebarRoot.tsx
+++ b/src/Sidebar/ui/SidebarRoot.tsx
@@ -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;
}
diff --git a/src/Terminal.d.ts b/src/Terminal.d.ts
deleted file mode 100644
index 80b9d17aa..000000000
--- a/src/Terminal.d.ts
+++ /dev/null
@@ -1 +0,0 @@
-export declare const Terminal: ITerminal;
diff --git a/src/Terminal.jsx b/src/Terminal.ts
similarity index 100%
rename from src/Terminal.jsx
rename to src/Terminal.ts
diff --git a/src/Terminal/Terminal.ts b/src/Terminal/Terminal.ts
index 77a4140b6..45fa46b75 100644
--- a/src/Terminal/Terminal.ts
+++ b/src/Terminal/Terminal.ts
@@ -3,6 +3,7 @@ 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";
@@ -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"));
+ }
}
}
diff --git a/src/Terminal/commands/nano.ts b/src/Terminal/commands/nano.ts
index ad93cf2f9..b028cf9ac 100644
--- a/src/Terminal/commands/nano.ts
+++ b/src/Terminal/commands/nano.ts
@@ -3,7 +3,6 @@ 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";
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) {
diff --git a/src/Terminal/ui/TerminalRoot.tsx b/src/Terminal/ui/TerminalRoot.tsx
index e4dc0caf9..1351d20ee 100644
--- a/src/Terminal/ui/TerminalRoot.tsx
+++ b/src/Terminal/ui/TerminalRoot.tsx
@@ -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;
@@ -60,8 +61,8 @@ export function TerminalRoot({ terminal, router, player }: IProps): React.ReactE
setKey((key) => key + 1);
}
- useEffect(() => TerminalEvents.subscribe(rerender), []);
- useEffect(() => TerminalClearEvents.subscribe(clear), []);
+ useEffect(() => TerminalEvents.subscribe(_.debounce(rerender, 50, { maxWait: 50 })), []);
+ useEffect(() => TerminalClearEvents.subscribe(_.debounce(clear, 50, { maxWait: 50 })), []);
function doScroll(): void {
const hook = scrollHook.current;
diff --git a/src/ui/GameRoot.tsx b/src/ui/GameRoot.tsx
index 66539c6df..41ccc8e57 100644
--- a/src/ui/GameRoot.tsx
+++ b/src/ui/GameRoot.tsx
@@ -326,11 +326,11 @@ export function GameRoot({ player, engine, terminal }: IProps): React.ReactEleme
) : page === Page.DevMenu ? (
) : page === Page.Gang ? (
-
+
) : page === Page.Corporation ? (
-
+
) : page === Page.Bladeburner ? (
-
+
) : page === Page.Resleeves ? (
) : page === Page.Travel ? (
diff --git a/src/ui/MainMenu/Headers.ts b/src/ui/MainMenu/Headers.ts
deleted file mode 100644
index 5ba3b971e..000000000
--- a/src/ui/MainMenu/Headers.ts
+++ /dev/null
@@ -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;
- }
-}
diff --git a/src/ui/MainMenu/Links.ts b/src/ui/MainMenu/Links.ts
deleted file mode 100644
index b89ce5757..000000000
--- a/src/ui/MainMenu/Links.ts
+++ /dev/null
@@ -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;
- }
-}
diff --git a/src/ui/React/GameOptionsRoot.tsx b/src/ui/React/GameOptionsRoot.tsx
index b557e22d4..e62d4e45b 100644
--- a/src/ui/React/GameOptionsRoot.tsx
+++ b/src/ui/React/GameOptionsRoot.tsx
@@ -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}