convert player to ts

This commit is contained in:
Olivier Gagnon 2021-09-23 18:47:43 -04:00
parent 8fd6b2e7da
commit b8faa9dc0b
34 changed files with 1052 additions and 1155 deletions

@ -1,2 +1,3 @@
export declare function isRepeatableAug(aug: Augmentation): boolean; export declare function isRepeatableAug(aug: Augmentation): boolean;
export declare function installAugmentations(): void; export declare function installAugmentations(): void;
export declare function applyAugmentation(aug: Augmentation, reapply?: boolean): void;

@ -6,13 +6,11 @@ import { AllPages } from "./AllPages";
import { use } from "../../ui/Context"; import { use } from "../../ui/Context";
import { IBladeburner } from "../IBladeburner"; import { IBladeburner } from "../IBladeburner";
interface IProps { export function BladeburnerRoot(): React.ReactElement {
bladeburner: IBladeburner;
}
export function BladeburnerRoot(props: IProps): React.ReactElement {
const player = use.Player(); const player = use.Player();
const router = use.Router(); const router = use.Router();
const bladeburner = player.bladeburner;
if (bladeburner === null) return <></>;
return ( return (
<div className="bladeburner-container"> <div className="bladeburner-container">
<div style={{ height: "60%", display: "block", position: "relative" }}> <div style={{ height: "60%", display: "block", position: "relative" }}>
@ -24,9 +22,9 @@ export function BladeburnerRoot(props: IProps): React.ReactElement {
border: "1px solid white", border: "1px solid white",
}} }}
> >
<Stats bladeburner={props.bladeburner} player={player} router={router} /> <Stats bladeburner={bladeburner} player={player} router={router} />
</div> </div>
<Console bladeburner={props.bladeburner} player={player} /> <Console bladeburner={bladeburner} player={player} />
</div> </div>
<div <div
style={{ style={{
@ -38,7 +36,7 @@ export function BladeburnerRoot(props: IProps): React.ReactElement {
position: "relative", position: "relative",
}} }}
> >
<AllPages bladeburner={props.bladeburner} player={player} /> <AllPages bladeburner={bladeburner} player={player} />
</div> </div>
</div> </div>
); );

@ -10,6 +10,7 @@ import { ICorporation } from "../ICorporation";
import { IPlayer } from "../../PersonObjects/IPlayer"; import { IPlayer } from "../../PersonObjects/IPlayer";
import { MainPanel } from "./MainPanel"; import { MainPanel } from "./MainPanel";
import { Industries } from "../IndustryData"; import { Industries } from "../IndustryData";
import { use } from "../../ui/Context";
interface IExpandButtonProps { interface IExpandButtonProps {
corp: ICorporation; corp: ICorporation;
@ -38,12 +39,10 @@ function ExpandButton(props: IExpandButtonProps): React.ReactElement {
return <HeaderTab current={false} onClick={openNewIndustryPopup} text={"Expand into new Industry"} />; return <HeaderTab current={false} onClick={openNewIndustryPopup} text={"Expand into new Industry"} />;
} }
interface IProps { export function CorporationRoot(): React.ReactElement {
corp: ICorporation; const player = use.Player();
player: IPlayer; const corporation = player.corporation;
} if (corporation === null) return <></>;
export function CorporationRoot(props: IProps): React.ReactElement {
const setRerender = useState(false)[1]; const setRerender = useState(false)[1];
function rerender(): void { function rerender(): void {
setRerender((old) => !old); setRerender((old) => !old);
@ -62,9 +61,9 @@ export function CorporationRoot(props: IProps): React.ReactElement {
current={divisionName === "Overview"} current={divisionName === "Overview"}
key={"overview"} key={"overview"}
onClick={() => setDivisionName("Overview")} onClick={() => setDivisionName("Overview")}
text={props.corp.name} text={corporation.name}
/> />
{props.corp.divisions.map((division: IIndustry) => ( {corporation.divisions.map((division: IIndustry) => (
<HeaderTab <HeaderTab
current={division.name === divisionName} current={division.name === divisionName}
key={division.name} key={division.name}
@ -72,9 +71,9 @@ export function CorporationRoot(props: IProps): React.ReactElement {
text={division.name} text={division.name}
/> />
))} ))}
<ExpandButton corp={props.corp} setDivisionName={setDivisionName} /> <ExpandButton corp={corporation} setDivisionName={setDivisionName} />
</div> </div>
<MainPanel rerender={rerender} corp={props.corp} divisionName={divisionName} player={props.player} /> <MainPanel rerender={rerender} corp={corporation} divisionName={divisionName} player={player} />
</div> </div>
); );
} }

@ -2,6 +2,7 @@ import { CONSTANTS } from "../Constants";
import { IPlayer } from "../PersonObjects/IPlayer"; import { IPlayer } from "../PersonObjects/IPlayer";
import { IPlayerOrSleeve } from "../PersonObjects/IPlayerOrSleeve"; import { IPlayerOrSleeve } from "../PersonObjects/IPlayerOrSleeve";
import { IRouter } from "../ui/Router"; import { IRouter } from "../ui/Router";
import { WorkerScript } from "../Netscript/WorkerScript";
export interface IConstructorParams { export interface IConstructorParams {
hacking_success_weight?: number; hacking_success_weight?: number;
@ -86,7 +87,7 @@ export class Crime {
this.kills = params.kills ? params.kills : 0; 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) { if (div <= 0) {
div = 1; div = 1;
} }
@ -101,7 +102,7 @@ export class Crime {
this.charisma_exp / div, this.charisma_exp / div,
this.money / div, this.money / div,
this.time, this.time,
singParams, workerScript,
); );
return this.time; return this.time;

@ -14,7 +14,8 @@ export function checkIfConnectedToDarkweb(): void {
if (!isValidIPAddress(darkwebIp)) { if (!isValidIPAddress(darkwebIp)) {
return; return;
} }
if (darkwebIp == Player.getCurrentServer().ip) { const server = Player.getCurrentServer();
if (server !== null && darkwebIp == server.ip) {
Terminal.print( Terminal.print(
"You are now connected to the dark web. From the dark web you can purchase illegal items. " + "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] " + "Use the 'buy -l' command to display a list of all the items you can buy. Use 'buy [item-name] " +

@ -15,43 +15,42 @@ interface IProps {
} }
export function Bladeburner(props: IProps): React.ReactElement { export function Bladeburner(props: IProps): React.ReactElement {
const bladeburner = props.player.bladeburner;
if (bladeburner === null) return <></>;
function modifyBladeburnerRank(modify: number): (x: number) => void { function modifyBladeburnerRank(modify: number): (x: number) => void {
return function (rank: number): void { return function (rank: number): void {
if (props.player.bladeburner) { if (!bladeburner) return;
props.player.bladeburner.changeRank(props.player, rank * modify); bladeburner.changeRank(props.player, rank * modify);
}
}; };
} }
function resetBladeburnerRank(): void { function resetBladeburnerRank(): void {
props.player.bladeburner.rank = 0; if (!bladeburner) return;
props.player.bladeburner.maxRank = 0; bladeburner.rank = 0;
bladeburner.maxRank = 0;
} }
function addTonsBladeburnerRank(): void { function addTonsBladeburnerRank(): void {
if (props.player.bladeburner) { if (!bladeburner) return;
props.player.bladeburner.changeRank(props.player, bigNumber);
} bladeburner.changeRank(props.player, bigNumber);
} }
function modifyBladeburnerCycles(modify: number): (x: number) => void { function modifyBladeburnerCycles(modify: number): (x: number) => void {
return function (cycles: number): void { return function (cycles: number): void {
if (props.player.bladeburner) { if (!bladeburner) return;
props.player.bladeburner.storedCycles += cycles * modify; bladeburner.storedCycles += cycles * modify;
}
}; };
} }
function resetBladeburnerCycles(): void { function resetBladeburnerCycles(): void {
if (props.player.bladeburner) { if (!bladeburner) return;
props.player.bladeburner.storedCycles = 0; bladeburner.storedCycles = 0;
}
} }
function addTonsBladeburnerCycles(): void { function addTonsBladeburnerCycles(): void {
if (props.player.bladeburner) { if (!bladeburner) return;
props.player.bladeburner.storedCycles += bigNumber; bladeburner.storedCycles += bigNumber;
}
} }
return ( return (

@ -35,6 +35,6 @@ export function ExploitName(exploit: string): string {
return names[exploit]; return names[exploit];
} }
export function sanitizeExploits(exploits: string[]): string[] { export function sanitizeExploits(exploits: Exploit[]): Exploit[] {
return exploits.filter((e: string) => Object.keys(Exploit).includes(e)); return exploits.filter((e: Exploit) => Object.keys(Exploit).includes(e));
} }

@ -1,2 +0,0 @@
export declare function parseFconfSettings(config: string): void;
export declare function createFconf(): string;

@ -1,268 +0,0 @@
import { FconfSettings } from "./FconfSettings";
import { parse, Node } from "acorn";
import { dialogBoxCreate } from "../../utils/DialogBox";
var FconfComments = {
ENABLE_BASH_HOTKEYS:
"Improved Bash emulation mode. Setting this to 1 enables several\n" +
"new Terminal shortcuts and features that more closely resemble\n" +
"a real Bash-style shell. Note that when this mode is enabled,\n" +
"the default browser shortcuts are overriden by the new Bash\n" +
"shortcuts.\n\n" +
"To see a full list of the Terminal shortcuts that this enables, see:\n" +
"http://bitburner.readthedocs.io/en/latest/shortcuts.html",
ENABLE_TIMESTAMPS:
"Terminal commands and log entries will be timestamped. The timestamp\n" + "will have the format: M/D h:m",
MAIN_MENU_STYLE:
"Customize the main navigation menu on the left-hand side. Current options:\n\n" + "default, classic, compact",
THEME_BACKGROUND_COLOR:
"Sets the background color for not only the Terminal, but also for\n" +
"most of the game's UI.\n\n" +
"The color must be specified as a pound sign (#) followed by a \n" +
"3-digit or 6-digit hex color code (e.g. #123456). Default color: #000000",
THEME_FONT_COLOR:
"Sets the font color for not only the Terminal, but also for\n" +
"most of the game's UI.\n\n" +
"The color must be specified as a pound sign (#) followed by a \n" +
"3-digit or 6-digit hex color code (e.g. #123456). Default color: #66ff33",
THEME_HIGHLIGHT_COLOR:
"Sets the highlight color for not only the Terminal, but also for \n" +
"most of the game's UI.\n\n" +
"The color must be specified as a pound sign (#) followed by a \n" +
"3-digit or 6-digit hex color code (e.g. #123456). Default color: #ffffff",
THEME_PROMPT_COLOR:
"Sets the prompt color in the Terminal\n\n" +
"The color must be specified as a pound sign (#) followed by a \n" +
"3-digit or 6-digit hex color code (e.g. #123456). Default color: #f92672",
WRAP_INPUT:
"Wrap Terminal Input. If this is enabled, then when a Terminal command is\n" +
"too long and overflows, then it will wrap to the next line instead of\n" +
"side-scrolling\n\n" +
"Note that after you enable/disable this, you'll have to run a command\n" +
"before its effect takes place.",
};
const MainMenuStyleOptions = ["default", "classic", "compact"];
//Parse Fconf settings from the config text
//Throws an exception if parsing fails
function parseFconfSettings(config) {
var ast = parse(config, { sourceType: "module" });
var queue = [];
queue.push(ast);
while (queue.length != 0) {
var exp = queue.shift();
switch (exp.type) {
case "BlockStatement":
case "Program":
for (var i = 0; i < exp.body.length; ++i) {
if (exp.body[i] instanceof Node) {
queue.push(exp.body[i]);
}
}
break;
case "AssignmentExpression":
var setting, value;
if (exp.left != null && exp.left.name != null) {
setting = exp.left.name;
} else {
break;
}
if (exp.right != null && exp.right.raw != null) {
value = exp.right.raw;
} else {
break;
}
parseFconfSetting(setting, value);
break;
default:
break;
}
for (var prop in exp) {
if (exp.hasOwnProperty(prop)) {
if (exp[prop] instanceof Node) {
queue.push(exp[prop]);
}
}
}
}
setTheme();
setMainMenuStyle();
}
function parseFconfSetting(setting, value) {
setting = String(setting);
value = String(value);
if (setting == null || value == null || FconfSettings[setting] == null) {
console.warn(`Invalid .fconf setting: ${setting}`);
return;
}
function sanitizeString(value) {
value = value.toLowerCase();
if (value.startsWith('"')) {
value = value.slice(1);
}
if (value.endsWith('"')) {
value = value.slice(0, -1);
}
return value;
}
switch (setting) {
case "ENABLE_BASH_HOTKEYS":
case "ENABLE_TIMESTAMPS":
case "WRAP_INPUT":
// Need to convert entered value to boolean/strings accordingly
var value = value.toLowerCase();
if (value === "1" || value === "true" || value === "y") {
value = true;
} else {
value = false;
}
FconfSettings[setting] = value;
break;
case "MAIN_MENU_STYLE":
var value = sanitizeString(value);
if (MainMenuStyleOptions.includes(value)) {
FconfSettings[setting] = value;
} else {
dialogBoxCreate(`Invalid option specified for ${setting}. Options: ${MainMenuStyleOptions.toString()}`);
}
break;
case "THEME_BACKGROUND_COLOR":
case "THEME_FONT_COLOR":
case "THEME_HIGHLIGHT_COLOR":
case "THEME_PROMPT_COLOR":
var value = sanitizeString(value);
if (/(^#[0-9A-F]{6}$)|(^#[0-9A-F]{3}$)/i.test(value)) {
FconfSettings[setting] = value;
} else {
dialogBoxCreate(`Invalid color specified for ${setting}. Must be a hex color code preceded by a pound (#)`);
}
break;
default:
break;
}
}
//Create the .fconf file text from the settings
function createFconf() {
var res = "";
for (var setting in FconfSettings) {
if (FconfSettings.hasOwnProperty(setting)) {
//Setting comments (description)
var comment = FconfComments[setting];
if (comment == null) {
continue;
}
var comment = comment.split("\n");
for (var i = 0; i < comment.length; ++i) {
res += "//" + comment[i] + "\n";
}
var value = 0;
if (FconfSettings[setting] === true) {
value = "1";
} else if (FconfSettings[setting] === false) {
value = "0";
} else {
value = '"' + String(FconfSettings[setting]) + '"';
}
res += `${setting} = ${value}\n\n`;
}
}
return res;
}
function loadFconf(saveString) {
let tempFconfSettings = JSON.parse(saveString);
for (var setting in tempFconfSettings) {
if (tempFconfSettings.hasOwnProperty(setting)) {
FconfSettings[setting] = tempFconfSettings[setting];
}
}
// Initialize themes/styles after loading
setTheme();
setMainMenuStyle();
}
function setTheme() {
if (
FconfSettings.THEME_HIGHLIGHT_COLOR == null ||
FconfSettings.THEME_FONT_COLOR == null ||
FconfSettings.THEME_BACKGROUND_COLOR == null ||
FconfSettings.THEME_PROMPT_COLOR == null
) {
console.error("Cannot find Theme Settings");
return;
}
if (
/^#[0-9a-f]{3}(?:[0-9a-f]{3})?$/i.test(FconfSettings.THEME_HIGHLIGHT_COLOR) &&
/^#[0-9a-f]{3}(?:[0-9a-f]{3})?$/i.test(FconfSettings.THEME_FONT_COLOR) &&
/^#[0-9a-f]{3}(?:[0-9a-f]{3})?$/i.test(FconfSettings.THEME_BACKGROUND_COLOR) &&
/^#[0-9a-f]{3}(?:[0-9a-f]{3})?$/i.test(FconfSettings.THEME_PROMPT_COLOR)
) {
// document.body.style.setProperty("--my-highlight-color", FconfSettings.THEME_HIGHLIGHT_COLOR);
// document.body.style.setProperty("--my-font-color", FconfSettings.THEME_FONT_COLOR);
// document.body.style.setProperty("--my-background-color", FconfSettings.THEME_BACKGROUND_COLOR);
// document.body.style.setProperty("--my-prompt-color", FconfSettings.THEME_PROMPT_COLOR);
}
}
function setMainMenuStyle() {
const mainMenu = document.getElementById("mainmenu");
const hackingMenuHdr = document.getElementById("hacking-menu-header");
const characterMenuHdr = document.getElementById("character-menu-header");
const worldMenuHdr = document.getElementById("world-menu-header");
const helpMenuHdr = document.getElementById("help-menu-header");
function removeAllAccordionHeaderClasses() {
hackingMenuHdr.classList.remove("mainmenu-accordion-header", "mainmenu-accordion-header-classic");
characterMenuHdr.classList.remove("mainmenu-accordion-header", "mainmenu-accordion-header-classic");
worldMenuHdr.classList.remove("mainmenu-accordion-header", "mainmenu-accordion-header-classic");
helpMenuHdr.classList.remove("mainmenu-accordion-header", "mainmenu-accordion-header-classic");
}
function addClassToAllAccordionHeaders(clsName) {
hackingMenuHdr.classList.add(clsName);
characterMenuHdr.classList.add(clsName);
worldMenuHdr.classList.add(clsName);
helpMenuHdr.classList.add(clsName);
}
if (FconfSettings["MAIN_MENU_STYLE"] === "default") {
removeAllAccordionHeaderClasses();
mainMenu.classList.remove("classic");
mainMenu.classList.remove("compact");
addClassToAllAccordionHeaders("mainmenu-accordion-header");
} else if (FconfSettings["MAIN_MENU_STYLE"] === "classic") {
removeAllAccordionHeaderClasses();
mainMenu.classList.remove("compact");
mainMenu.classList.add("classic");
addClassToAllAccordionHeaders("mainmenu-accordion-header-classic");
} else if (FconfSettings["MAIN_MENU_STYLE"] === "compact") {
removeAllAccordionHeaderClasses();
mainMenu.classList.remove("classic");
mainMenu.classList.add("compact");
addClassToAllAccordionHeaders("mainmenu-accordion-header-compact");
} else {
return;
}
// Click each header twice to reset lol
hackingMenuHdr.click();
hackingMenuHdr.click();
characterMenuHdr.click();
characterMenuHdr.click();
worldMenuHdr.click();
worldMenuHdr.click();
helpMenuHdr.click();
helpMenuHdr.click();
}
export { FconfSettings, createFconf, parseFconfSettings, loadFconf };

@ -1,10 +0,0 @@
export const FconfSettings = {
ENABLE_BASH_HOTKEYS: false,
ENABLE_TIMESTAMPS: false,
MAIN_MENU_STYLE: "default",
THEME_BACKGROUND_COLOR: "#000000",
THEME_FONT_COLOR: "#66ff33",
THEME_HIGHLIGHT_COLOR: "#ffffff",
THEME_PROMPT_COLOR: "#f92672",
WRAP_INPUT: false,
};

@ -8,13 +8,13 @@ import { use } from "../../ui/Context";
import { Factions } from "../../Faction/Factions"; import { Factions } from "../../Faction/Factions";
import { Gang } from "../Gang"; import { Gang } from "../Gang";
interface IProps { export function GangRoot(): React.ReactElement {
gang: Gang;
}
export function GangRoot(props: IProps): React.ReactElement {
const player = use.Player(); const player = use.Player();
const router = use.Router(); 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 [management, setManagement] = useState(true);
const setRerender = useState(false)[1]; const setRerender = useState(false)[1];
@ -24,7 +24,7 @@ export function GangRoot(props: IProps): React.ReactElement {
}, []); }, []);
function back(): void { function back(): void {
router.toFaction(Factions[props.gang.facName]); router.toFaction(Factions[gang.facName]);
} }
return ( return (
@ -46,7 +46,7 @@ export function GangRoot(props: IProps): React.ReactElement {
> >
Gang Territory Gang Territory
</a> </a>
{management ? <ManagementSubpage gang={props.gang} player={player} /> : <TerritorySubpage gang={props.gang} />} {management ? <ManagementSubpage gang={gang} player={player} /> : <TerritorySubpage gang={gang} />}
</div> </div>
); );
} }

@ -479,13 +479,12 @@ export function purchaseHashUpgrade(player: IPlayer, upgName: string, upgTarget:
break; break;
} }
case "Sell for Corporation Funds": { case "Sell for Corporation Funds": {
// This will throw if player doesn't have a corporation const corp = player.corporation;
try { if (corp === null) {
player.corporation.funds = player.corporation.funds.plus(upg.value);
} catch (e) {
player.hashManager.refundUpgrade(upgName); player.hashManager.refundUpgrade(upgName);
return false; return false;
} }
corp.funds = corp.funds.plus(upg.value);
break; break;
} }
case "Reduce Minimum Security": { case "Reduce Minimum Security": {
@ -530,36 +529,35 @@ export function purchaseHashUpgrade(player: IPlayer, upgName: string, upgTarget:
} }
case "Exchange for Corporation Research": { case "Exchange for Corporation Research": {
// This will throw if player doesn't have a corporation // This will throw if player doesn't have a corporation
try { const corp = player.corporation;
for (const division of player.corporation.divisions) { if (corp === null) {
division.sciResearch.qty += upg.value;
}
} catch (e) {
player.hashManager.refundUpgrade(upgName); player.hashManager.refundUpgrade(upgName);
return false; return false;
} }
for (const division of corp.divisions) {
division.sciResearch.qty += upg.value;
}
break; break;
} }
case "Exchange for Bladeburner Rank": { case "Exchange for Bladeburner Rank": {
// This will throw if player isnt in Bladeburner // This will throw if player isnt in Bladeburner
try { const bladeburner = player.bladeburner;
player.bladeburner.changeRank(player, upg.value); if (bladeburner === null) {
} catch (e) {
player.hashManager.refundUpgrade(upgName); player.hashManager.refundUpgrade(upgName);
return false; return false;
} }
bladeburner.changeRank(player, upg.value);
break; break;
} }
case "Exchange for Bladeburner SP": { case "Exchange for Bladeburner SP": {
// This will throw if player isn't in Bladeburner // This will throw if player isnt in Bladeburner
try { const bladeburner = player.bladeburner;
// As long as we don't change `Bladeburner.totalSkillPoints`, this if (bladeburner === null) {
// shouldn't affect anything else
player.bladeburner.skillPoints += upg.value;
} catch (e) {
player.hashManager.refundUpgrade(upgName); player.hashManager.refundUpgrade(upgName);
return false; return false;
} }
bladeburner.skillPoints += upg.value;
break; break;
} }
case "Generate Coding Contract": { case "Generate Coding Contract": {

@ -3808,7 +3808,7 @@ function NetscriptFunctions(workerScript) {
throw makeRuntimeErrorMsg("commitCrime", `Invalid crime: '${crimeRoughName}'`); throw makeRuntimeErrorMsg("commitCrime", `Invalid crime: '${crimeRoughName}'`);
} }
workerScript.log("commitCrime", `Attempting to commit ${crime.name}...`); 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) { getCrimeChance: function (crimeRoughName) {
updateDynamicRam("getCrimeChance", getRamCost("getCrimeChance")); updateDynamicRam("getCrimeChance", getRamCost("getCrimeChance"));

@ -26,6 +26,8 @@ import { IGang } from "../Gang/IGang";
import { IBladeburner } from "../Bladeburner/IBladeburner"; import { IBladeburner } from "../Bladeburner/IBladeburner";
import { ICodingContractReward } from "../CodingContracts"; import { ICodingContractReward } from "../CodingContracts";
import { IRouter } from "../ui/Router"; import { IRouter } from "../ui/Router";
import { WorkerScript } from "../Netscript/WorkerScript";
import { HacknetServer } from "../Hacknet/HacknetServer";
export interface IPlayer { export interface IPlayer {
// Class members // Class members
@ -33,14 +35,12 @@ export interface IPlayer {
bitNodeN: number; bitNodeN: number;
city: CityName; city: CityName;
companyName: string; companyName: string;
corporation: ICorporation; corporation: ICorporation | null;
gang: IGang; gang: IGang | null;
bladeburner: IBladeburner; bladeburner: IBladeburner | null;
currentServer: string; currentServer: string;
factions: string[]; factions: string[];
factionInvitations: string[]; factionInvitations: string[];
firstProgramAvailable: boolean;
firstTimeTraveled: boolean;
hacknetNodes: (HacknetNode | string)[]; // HacknetNode object or IP of Hacknet Server hacknetNodes: (HacknetNode | string)[]; // HacknetNode object or IP of Hacknet Server
has4SData: boolean; has4SData: boolean;
has4SDataTixApi: boolean; has4SDataTixApi: boolean;
@ -122,9 +122,13 @@ export interface IPlayer {
bladeburner_analysis_mult: number; bladeburner_analysis_mult: number;
bladeburner_success_chance_mult: number; bladeburner_success_chance_mult: number;
createProgramReqLvl: number;
factionWorkType: string;
createProgramName: string; createProgramName: string;
timeWorkedCreateProgram: number; timeWorkedCreateProgram: number;
crimeType: string; crimeType: string;
committingCrimeThruSingFn: boolean;
singFnCrimeWorkerScript: WorkerScript | null;
timeNeededToCompleteWork: number; timeNeededToCompleteWork: number;
focus: boolean; focus: boolean;
className: string; className: string;
@ -151,20 +155,23 @@ export interface IPlayer {
workMoneyLossRate: number; workMoneyLossRate: number;
// Methods // Methods
applyForAgentJob(sing?: boolean): boolean | void; work(numCycles: number): boolean;
applyForBusinessConsultantJob(sing?: boolean): boolean | void; workPartTime(numCycles: number): boolean;
applyForBusinessJob(sing?: boolean): boolean | void; workForFaction(numCycles: number): boolean;
applyForEmployeeJob(sing?: boolean): boolean | void; applyForAgentJob(sing?: boolean): boolean;
applyForItJob(sing?: boolean): boolean | void; applyForBusinessConsultantJob(sing?: boolean): boolean;
applyForJob(entryPosType: CompanyPosition, sing?: boolean): boolean | void; applyForBusinessJob(sing?: boolean): boolean;
applyForNetworkEngineerJob(sing?: boolean): boolean | void; applyForEmployeeJob(sing?: boolean): boolean;
applyForPartTimeEmployeeJob(sing?: boolean): boolean | void; applyForItJob(sing?: boolean): boolean;
applyForPartTimeWaiterJob(sing?: boolean): boolean | void; applyForJob(entryPosType: CompanyPosition, sing?: boolean): boolean;
applyForSecurityEngineerJob(sing?: boolean): boolean | void; applyForNetworkEngineerJob(sing?: boolean): boolean;
applyForSecurityJob(sing?: boolean): boolean | void; applyForPartTimeEmployeeJob(sing?: boolean): boolean;
applyForSoftwareConsultantJob(sing?: boolean): boolean | void; applyForPartTimeWaiterJob(sing?: boolean): boolean;
applyForSoftwareJob(sing?: boolean): boolean | void; applyForSecurityEngineerJob(sing?: boolean): boolean;
applyForWaiterJob(sing?: boolean): boolean | void; applyForSecurityJob(sing?: boolean): boolean;
applyForSoftwareConsultantJob(sing?: boolean): boolean;
applyForSoftwareJob(sing?: boolean): boolean;
applyForWaiterJob(sing?: boolean): boolean;
canAccessBladeburner(): boolean; canAccessBladeburner(): boolean;
canAccessCorporation(): boolean; canAccessCorporation(): boolean;
canAccessGang(): boolean; canAccessGang(): boolean;
@ -178,11 +185,11 @@ export interface IPlayer {
gainCharismaExp(exp: number): void; gainCharismaExp(exp: number): void;
gainIntelligenceExp(exp: number): void; gainIntelligenceExp(exp: number): void;
gainMoney(money: number): void; gainMoney(money: number): void;
getCurrentServer(): Server; getCurrentServer(): Server | HacknetServer;
getGangFaction(): Faction; getGangFaction(): Faction;
getGangName(): string; getGangName(): string;
getHomeComputer(): Server; getHomeComputer(): Server;
getNextCompanyPosition(company: Company, entryPosType: CompanyPosition): CompanyPosition; getNextCompanyPosition(company: Company, entryPosType: CompanyPosition): CompanyPosition | null;
getUpgradeHomeRamCost(): number; getUpgradeHomeRamCost(): number;
gotoLocation(to: LocationName): boolean; gotoLocation(to: LocationName): boolean;
hasAugmentation(aug: Augmentation): boolean; hasAugmentation(aug: Augmentation): boolean;
@ -201,6 +208,7 @@ export interface IPlayer {
setMoney(amt: number): void; setMoney(amt: number): void;
singularityStopWork(): void; singularityStopWork(): void;
startBladeburner(p: any): void; startBladeburner(p: any): void;
startFactionWork(router: IRouter, faction: Faction): void;
startClass(router: IRouter, costMult: number, expMult: number, className: string): void; startClass(router: IRouter, costMult: number, expMult: number, className: string): void;
startCorporation(corpName: string, additionalShares?: number): void; startCorporation(corpName: string, additionalShares?: number): void;
startCrime( startCrime(
@ -237,11 +245,31 @@ export interface IPlayer {
updateSkillLevels(): void; updateSkillLevels(): void;
gainCodingContractReward(reward: ICodingContractReward, difficulty?: number): string; gainCodingContractReward(reward: ICodingContractReward, difficulty?: number): string;
stopFocusing(): void; stopFocusing(): void;
finishFactionWork(cancelled: boolean, sing?: boolean): void; finishFactionWork(cancelled: boolean, sing?: boolean): string;
finishClass(sing?: boolean): void; finishClass(sing?: boolean): string;
finishWork(cancelled: boolean, sing?: boolean): void; finishWork(cancelled: boolean, sing?: boolean): string;
cancelationPenalty(): number; cancelationPenalty(): number;
finishWorkPartTime(sing?: boolean): void; finishWorkPartTime(sing?: boolean): string;
finishCrime(cancelled: boolean): void; finishCrime(cancelled: boolean): string;
finishCreateProgramWork(cancelled: boolean): void; 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;
} }

@ -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;

@ -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<string>;
init: () => void;
isWorking: boolean;
karma: number;
numPeopleKilled: number;
location: LocationName;
max_hp: number;
money: any;
moneySourceA: MoneySourceTracker;
moneySourceB: MoneySourceTracker;
playtimeSinceLastAug: number;
playtimeSinceLastBitnode: number;
purchasedServers: any[];
queuedAugmentations: IPlayerOwnedAugmentation[];
resleeves: Resleeve[];
scriptProdSinceLastAug: number;
sleeves: Sleeve[];
sleevesFromCovenant: number;
sourceFiles: IPlayerOwnedSourceFile[];
exploits: Exploit[];
lastUpdate: number;
totalPlaytime: number;
// Stats
hacking_skill: number;
strength: number;
defense: number;
dexterity: number;
agility: number;
charisma: number;
intelligence: number;
// Experience
hacking_exp: number;
strength_exp: number;
defense_exp: number;
dexterity_exp: number;
agility_exp: number;
charisma_exp: number;
intelligence_exp: number;
// Multipliers
hacking_chance_mult: number;
hacking_speed_mult: number;
hacking_money_mult: number;
hacking_grow_mult: number;
hacking_mult: number;
hacking_exp_mult: number;
strength_mult: number;
strength_exp_mult: number;
defense_mult: number;
defense_exp_mult: number;
dexterity_mult: number;
dexterity_exp_mult: number;
agility_mult: number;
agility_exp_mult: number;
charisma_mult: number;
charisma_exp_mult: number;
hacknet_node_money_mult: number;
hacknet_node_purchase_cost_mult: number;
hacknet_node_ram_cost_mult: number;
hacknet_node_core_cost_mult: number;
hacknet_node_level_cost_mult: number;
company_rep_mult: number;
faction_rep_mult: number;
work_money_mult: number;
crime_success_mult: number;
crime_money_mult: number;
bladeburner_max_stamina_mult: number;
bladeburner_stamina_gain_mult: number;
bladeburner_analysis_mult: number;
bladeburner_success_chance_mult: number;
createProgramReqLvl: number;
factionWorkType: string;
createProgramName: string;
timeWorkedCreateProgram: number;
crimeType: string;
committingCrimeThruSingFn: boolean;
singFnCrimeWorkerScript: WorkerScript | null;
timeNeededToCompleteWork: number;
focus: boolean;
className: string;
currentWorkFactionName: string;
workType: string;
currentWorkFactionDescription: string;
timeWorked: number;
workMoneyGained: number;
workMoneyGainRate: number;
workRepGained: number;
workRepGainRate: number;
workHackExpGained: number;
workHackExpGainRate: number;
workStrExpGained: number;
workStrExpGainRate: number;
workDefExpGained: number;
workDefExpGainRate: number;
workDexExpGained: number;
workDexExpGainRate: number;
workAgiExpGained: number;
workAgiExpGainRate: number;
workChaExpGained: number;
workChaExpGainRate: number;
workMoneyLossRate: number;
// Methods
work: (numCycles: number) => boolean;
workPartTime: (numCycles: number) => boolean;
workForFaction: (numCycles: number) => boolean;
applyForAgentJob: (sing?: boolean) => boolean;
applyForBusinessConsultantJob: (sing?: boolean) => boolean;
applyForBusinessJob: (sing?: boolean) => boolean;
applyForEmployeeJob: (sing?: boolean) => boolean;
applyForItJob: (sing?: boolean) => boolean;
applyForJob: (entryPosType: CompanyPosition, sing?: boolean) => boolean;
applyForNetworkEngineerJob: (sing?: boolean) => boolean;
applyForPartTimeEmployeeJob: (sing?: boolean) => boolean;
applyForPartTimeWaiterJob: (sing?: boolean) => boolean;
applyForSecurityEngineerJob: (sing?: boolean) => boolean;
applyForSecurityJob: (sing?: boolean) => boolean;
applyForSoftwareConsultantJob: (sing?: boolean) => boolean;
applyForSoftwareJob: (sing?: boolean) => boolean;
applyForWaiterJob: (sing?: boolean) => boolean;
canAccessBladeburner: () => boolean;
canAccessCorporation: () => boolean;
canAccessGang: () => boolean;
canAccessResleeving: () => boolean;
canAfford: (cost: number) => boolean;
gainHackingExp: (exp: number) => void;
gainStrengthExp: (exp: number) => void;
gainDefenseExp: (exp: number) => void;
gainDexterityExp: (exp: number) => void;
gainAgilityExp: (exp: number) => void;
gainCharismaExp: (exp: number) => void;
gainIntelligenceExp: (exp: number) => void;
gainMoney: (money: number) => void;
getCurrentServer: () => Server | HacknetServer;
getGangFaction: () => Faction;
getGangName: () => string;
getHomeComputer: () => Server;
getNextCompanyPosition: (company: Company, entryPosType: CompanyPosition) => CompanyPosition | null;
getUpgradeHomeRamCost: () => number;
gotoLocation: (to: LocationName) => boolean;
hasAugmentation: (aug: Augmentation) => boolean;
hasCorporation: () => boolean;
hasGangWith: (facName: string) => boolean;
hasTorRouter: () => boolean;
hasProgram: (program: string) => boolean;
inBladeburner: () => boolean;
inGang: () => boolean;
isQualified: (company: Company, position: CompanyPosition) => boolean;
loseMoney: (money: number) => void;
reapplyAllAugmentations: (resetMultipliers: boolean) => void;
reapplyAllSourceFiles: () => void;
regenerateHp: (amt: number) => void;
recordMoneySource: (amt: number, source: string) => void;
setMoney: (amt: number) => void;
singularityStopWork: () => void;
startBladeburner: (p: any) => void;
startFactionWork: (router: IRouter, faction: Faction) => void;
startClass: (router: IRouter, costMult: number, expMult: number, className: string) => void;
startCorporation: (corpName: string, additionalShares?: number) => void;
startCrime: (
router: IRouter,
crimeType: string,
hackExp: number,
strExp: number,
defExp: number,
dexExp: number,
agiExp: number,
chaExp: number,
money: number,
time: number,
singParams: any,
) => void;
startFactionFieldWork: (router: IRouter, faction: Faction) => void;
startFactionHackWork: (router: IRouter, faction: Faction) => void;
startFactionSecurityWork: (router: IRouter, faction: Faction) => void;
startFocusing: () => void;
startGang: (facName: string, isHacking: boolean) => void;
startWork: (router: IRouter, companyName: string) => void;
startWorkPartTime: (router: IRouter, companyName: string) => void;
takeDamage: (amt: number) => boolean;
travel: (to: CityName) => boolean;
giveExploit: (exploit: Exploit) => void;
queryStatFromString: (str: string) => number;
getIntelligenceBonus: (weight: number) => number;
getCasinoWinnings: () => number;
quitJob: (company: string) => void;
createHacknetServer: () => 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;

@ -20,20 +20,34 @@ export function canAccessGang(this: IPlayer): boolean {
} }
export function getGangFaction(this: IPlayer): Faction { 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) { 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; return fac;
} }
export function getGangName(this: IPlayer): string { 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 { 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 { export function inGang(this: IPlayer): boolean {

@ -15,12 +15,16 @@ export function hasTorRouter(this: IPlayer): boolean {
return SpecialServerIps.hasOwnProperty("Darkweb Server"); return SpecialServerIps.hasOwnProperty("Darkweb Server");
} }
export function getCurrentServer(this: IPlayer): Server | HacknetServer | null { export function getCurrentServer(this: IPlayer): Server | HacknetServer {
return AllServers[this.currentServer]; 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 { export function getHomeComputer(this: IPlayer): Server {
return AllServers[this.homeComputer]; 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 { export function getUpgradeHomeRamCost(this: IPlayer): number {

3
src/Player.d.ts vendored

@ -1,3 +0,0 @@
import { IPlayer } from "./PersonObjects/IPlayer";
export declare let Player: IPlayer;

@ -8,7 +8,7 @@ import Decimal from "decimal.js";
export let Player = new PlayerObject(); export let Player = new PlayerObject();
export function loadPlayer(saveString) { export function loadPlayer(saveString: string): void {
Player = JSON.parse(saveString, Reviver); Player = JSON.parse(saveString, Reviver);
// Parse Decimal.js objects // Parse Decimal.js objects
@ -19,8 +19,8 @@ export function loadPlayer(saveString) {
Player.corporation.revenue = new Decimal(Player.corporation.revenue); Player.corporation.revenue = new Decimal(Player.corporation.revenue);
Player.corporation.expenses = new Decimal(Player.corporation.expenses); Player.corporation.expenses = new Decimal(Player.corporation.expenses);
for (var i = 0; i < Player.corporation.divisions.length; ++i) { for (let i = 0; i < Player.corporation.divisions.length; ++i) {
var ind = Player.corporation.divisions[i]; const ind = Player.corporation.divisions[i];
ind.lastCycleRevenue = new Decimal(ind.lastCycleRevenue); ind.lastCycleRevenue = new Decimal(ind.lastCycleRevenue);
ind.lastCycleExpenses = new Decimal(ind.lastCycleExpenses); ind.lastCycleExpenses = new Decimal(ind.lastCycleExpenses);
ind.thisCycleRevenue = new Decimal(ind.thisCycleRevenue); ind.thisCycleRevenue = new Decimal(ind.thisCycleRevenue);

@ -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"); terminal.print("You already have root access to this computer. There is no reason to run NUKE.exe");
return; return;
} }
if (server.openPortCount >= server.numOpenPortsRequired) {
if (server.openPortCount >= player.getCurrentServer().numOpenPortsRequired) {
server.hasAdminRights = true; 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 // TODO: Make this take time rather than be instant
return; return;
} }

@ -3,7 +3,6 @@
* A Script can have multiple active instances * A Script can have multiple active instances
*/ */
import { Script } from "./Script"; import { Script } from "./Script";
import { FconfSettings } from "../Fconf/FconfSettings";
import { Settings } from "../Settings/Settings"; import { Settings } from "../Settings/Settings";
import { IMap } from "../types"; import { IMap } from "../types";
import { Terminal } from "../Terminal"; import { Terminal } from "../Terminal";

@ -11,7 +11,6 @@ import { isValidFilePath } from "../../Terminal/DirectoryHelpers";
import { IPlayer } from "../../PersonObjects/IPlayer"; import { IPlayer } from "../../PersonObjects/IPlayer";
import { IRouter } from "../../ui/Router"; import { IRouter } from "../../ui/Router";
import { dialogBoxCreate } from "../../../utils/DialogBox"; import { dialogBoxCreate } from "../../../utils/DialogBox";
import { parseFconfSettings } from "../../Fconf/Fconf";
import { isScriptFilename } from "../../Script/ScriptHelpersTS"; import { isScriptFilename } from "../../Script/ScriptHelpersTS";
import { Script } from "../../Script/Script"; import { Script } from "../../Script/Script";
import { TextFile } from "../../TextFile"; import { TextFile } from "../../TextFile";
@ -144,7 +143,7 @@ export function Root(props: IProps): React.ReactElement {
return; return;
} }
if (filename !== ".fconf" && !isValidFilePath(filename)) { if (!isValidFilePath(filename)) {
dialogBoxCreate( dialogBoxCreate(
"Script filename can contain only alphanumerics, hyphens, and underscores, and must end with an extension.", "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(); const server = props.player.getCurrentServer();
if (server === null) throw new Error("Server should not be null but it is."); if (server === null) throw new Error("Server should not be null but it is.");
if (filename === ".fconf") { if (isScriptFilename(filename)) {
try {
parseFconfSettings(code);
} catch (e) {
dialogBoxCreate(`Invalid .fconf file: ${e}`);
return;
}
} else if (isScriptFilename(filename)) {
//If the current script already exists on the server, overwrite it //If the current script already exists on the server, overwrite it
for (let i = 0; i < server.scripts.length; i++) { for (let i = 0; i < server.scripts.length; i++) {
if (filename == server.scripts[i].filename) { if (filename == server.scripts[i].filename) {

@ -295,7 +295,6 @@ export function SidebarRoot(props: IProps): React.ReactElement {
event.preventDefault(); event.preventDefault();
clickCreateProgram(); clickCreateProgram();
} else if (event.keyCode === KEY.F && event.altKey) { } else if (event.keyCode === KEY.F && event.altKey) {
// Overriden by Fconf
if (props.page == Page.Terminal && Settings.EnableBashHotkeys) { if (props.page == Page.Terminal && Settings.EnableBashHotkeys) {
return; return;
} }

1
src/Terminal.d.ts vendored

@ -1 +0,0 @@
export declare const Terminal: ITerminal;

@ -3,6 +3,7 @@ import { IRouter } from "../ui/Router";
import { IPlayer } from "../PersonObjects/IPlayer"; import { IPlayer } from "../PersonObjects/IPlayer";
import { HacknetServer } from "../Hacknet/HacknetServer"; import { HacknetServer } from "../Hacknet/HacknetServer";
import { BaseServer } from "../Server/BaseServer"; import { BaseServer } from "../Server/BaseServer";
import { Server } from "../Server/Server";
import { Programs } from "../Programs/Programs"; import { Programs } from "../Programs/Programs";
import { CodingContractResult } from "../CodingContracts"; import { CodingContractResult } from "../CodingContracts";
import { TerminalEvents, TerminalClearEvents } from "./TerminalEvents"; import { TerminalEvents, TerminalClearEvents } from "./TerminalEvents";
@ -106,12 +107,22 @@ export class Terminal implements ITerminal {
startHack(player: IPlayer): void { startHack(player: IPlayer): void {
// Hacking through Terminal should be faster than hacking through a script // 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 { startBackdoor(player: IPlayer): void {
// Backdoor should take the same amount of time as hack // 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 { startAnalyze(): void {
@ -127,6 +138,10 @@ export class Terminal implements ITerminal {
finishHack(router: IRouter, player: IPlayer, cancelled = false): void { finishHack(router: IRouter, player: IPlayer, cancelled = false): void {
if (cancelled) return; if (cancelled) return;
const server = player.getCurrentServer(); const server = player.getCurrentServer();
if (server instanceof HacknetServer) {
this.error("Cannot hack this kind of server");
return;
}
// Calculate whether hack was successful // Calculate whether hack was successful
const hackChance = calculateHackingChance(server, player); const hackChance = calculateHackingChance(server, player);
@ -179,6 +194,10 @@ export class Terminal implements ITerminal {
finishBackdoor(router: IRouter, player: IPlayer, cancelled = false): void { finishBackdoor(router: IRouter, player: IPlayer, cancelled = false): void {
if (!cancelled) { if (!cancelled) {
const server = player.getCurrentServer(); const server = player.getCurrentServer();
if (server instanceof HacknetServer) {
this.error("Cannot hack this kind of server");
return;
}
if ( if (
SpecialServerIps[SpecialServerNames.WorldDaemon] && SpecialServerIps[SpecialServerNames.WorldDaemon] &&
SpecialServerIps[SpecialServerNames.WorldDaemon] == server.ip SpecialServerIps[SpecialServerNames.WorldDaemon] == server.ip
@ -203,24 +222,30 @@ export class Terminal implements ITerminal {
this.print("Organization name: " + (!isHacknet ? org : "player")); this.print("Organization name: " + (!isHacknet ? org : "player"));
const hasAdminRights = (!isHacknet && currServ.hasAdminRights) || isHacknet; const hasAdminRights = (!isHacknet && currServ.hasAdminRights) || isHacknet;
this.print("Root Access: " + (hasAdminRights ? "YES" : "NO")); this.print("Root Access: " + (hasAdminRights ? "YES" : "NO"));
const hackingSkill = currServ.requiredHackingSkill; if (currServ instanceof Server) {
this.print("Required hacking skill: " + (!isHacknet ? hackingSkill : "N/A")); const hackingSkill = currServ.requiredHackingSkill;
const security = currServ.hackDifficulty; this.print("Required hacking skill: " + (!isHacknet ? hackingSkill : "N/A"));
this.print("Server security level: " + (!isHacknet ? numeralWrapper.formatServerSecurity(security) : "N/A")); const security = currServ.hackDifficulty;
const hackingChance = calculateHackingChance(currServ, player); this.print("Server security level: " + (!isHacknet ? numeralWrapper.formatServerSecurity(security) : "N/A"));
this.print("Chance to hack: " + (!isHacknet ? numeralWrapper.formatPercentage(hackingChance) : "N/A")); const hackingChance = calculateHackingChance(currServ, player);
const hackingTime = calculateHackingTime(currServ, player) * 1000; this.print("Chance to hack: " + (!isHacknet ? numeralWrapper.formatPercentage(hackingChance) : "N/A"));
this.print("Time to hack: " + (!isHacknet ? convertTimeMsToTimeElapsedString(hackingTime, true) : "N/A")); const hackingTime = calculateHackingTime(currServ, player) * 1000;
this.print("Time to hack: " + (!isHacknet ? convertTimeMsToTimeElapsedString(hackingTime, true) : "N/A"));
}
this.print( 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; if (currServ instanceof Server) {
this.print("Required number of open ports for NUKE: " + (!isHacknet ? numPort : "N/A")); const numPort = currServ.numOpenPortsRequired;
this.print("SSH port: " + (currServ.sshPortOpen ? "Open" : "Closed")); this.print("Required number of open ports for NUKE: " + (!isHacknet ? numPort : "N/A"));
this.print("FTP port: " + (currServ.ftpPortOpen ? "Open" : "Closed")); this.print("SSH port: " + (currServ.sshPortOpen ? "Open" : "Closed"));
this.print("SMTP port: " + (currServ.smtpPortOpen ? "Open" : "Closed")); this.print("FTP port: " + (currServ.ftpPortOpen ? "Open" : "Closed"));
this.print("HTTP port: " + (currServ.httpPortOpen ? "Open" : "Closed")); this.print("SMTP port: " + (currServ.smtpPortOpen ? "Open" : "Closed"));
this.print("SQL port: " + (currServ.sqlPortOpen ? "Open" : "Closed")); this.print("HTTP port: " + (currServ.httpPortOpen ? "Open" : "Closed"));
this.print("SQL port: " + (currServ.sqlPortOpen ? "Open" : "Closed"));
}
} }
} }

@ -3,7 +3,6 @@ import { IRouter } from "../../ui/Router";
import { IPlayer } from "../../PersonObjects/IPlayer"; import { IPlayer } from "../../PersonObjects/IPlayer";
import { BaseServer } from "../../Server/BaseServer"; import { BaseServer } from "../../Server/BaseServer";
import { isScriptFilename } from "../../Script/ScriptHelpersTS"; import { isScriptFilename } from "../../Script/ScriptHelpersTS";
import { createFconf } from "../../Fconf/Fconf";
export function nano( export function nano(
terminal: ITerminal, terminal: ITerminal,
@ -19,11 +18,7 @@ export function nano(
try { try {
const filename = args[0] + ""; const filename = args[0] + "";
if (filename === ".fconf") { if (isScriptFilename(filename)) {
const text = createFconf();
router.toScriptEditor(filename, text);
return;
} else if (isScriptFilename(filename)) {
const filepath = terminal.getFilepath(filename); const filepath = terminal.getFilepath(filename);
const script = terminal.getScript(player, filename); const script = terminal.getScript(player, filename);
if (script == null) { if (script == null) {

@ -12,6 +12,7 @@ import { IRouter } from "../../ui/Router";
import { IPlayer } from "../../PersonObjects/IPlayer"; import { IPlayer } from "../../PersonObjects/IPlayer";
import { TerminalInput } from "./TerminalInput"; import { TerminalInput } from "./TerminalInput";
import { TerminalEvents, TerminalClearEvents } from "../TerminalEvents"; import { TerminalEvents, TerminalClearEvents } from "../TerminalEvents";
import _ from "lodash";
interface IActionTimerProps { interface IActionTimerProps {
terminal: ITerminal; terminal: ITerminal;
@ -60,8 +61,8 @@ export function TerminalRoot({ terminal, router, player }: IProps): React.ReactE
setKey((key) => key + 1); setKey((key) => key + 1);
} }
useEffect(() => TerminalEvents.subscribe(rerender), []); useEffect(() => TerminalEvents.subscribe(_.debounce(rerender, 50, { maxWait: 50 })), []);
useEffect(() => TerminalClearEvents.subscribe(clear), []); useEffect(() => TerminalClearEvents.subscribe(_.debounce(clear, 50, { maxWait: 50 })), []);
function doScroll(): void { function doScroll(): void {
const hook = scrollHook.current; const hook = scrollHook.current;

@ -326,11 +326,11 @@ export function GameRoot({ player, engine, terminal }: IProps): React.ReactEleme
) : page === Page.DevMenu ? ( ) : page === Page.DevMenu ? (
<DevMenuRoot player={player} engine={engine} router={Router} /> <DevMenuRoot player={player} engine={engine} router={Router} />
) : page === Page.Gang ? ( ) : page === Page.Gang ? (
<GangRoot gang={player.gang} /> <GangRoot />
) : page === Page.Corporation ? ( ) : page === Page.Corporation ? (
<CorporationRoot corp={player.corporation} player={player} /> <CorporationRoot />
) : page === Page.Bladeburner ? ( ) : page === Page.Bladeburner ? (
<BladeburnerRoot bladeburner={player.bladeburner} /> <BladeburnerRoot />
) : page === Page.Resleeves ? ( ) : page === Page.Resleeves ? (
<ResleeveRoot player={player} /> <ResleeveRoot player={player} />
) : page === Page.Travel ? ( ) : page === Page.Travel ? (

@ -1,177 +0,0 @@
// Implement the collapsible main menu headers
import { MainMenuLinks } from "./Links";
import { IPlayer } from "../../PersonObjects/IPlayer";
interface IMainMenuHeaders {
Hacking: HTMLElement | null;
Character: HTMLElement | null;
World: HTMLElement | null;
Help: HTMLElement | null;
}
export const MainMenuHeaders: IMainMenuHeaders = {
Hacking: null,
Character: null,
World: null,
Help: null,
};
// Implements collapsible toggle feature when a header is clicked
function toggleHeader(open: boolean, elems: HTMLElement[], links: HTMLElement[]): void {
for (let i = 0; i < elems.length; ++i) {
if (open) {
elems[i].style.opacity = "1";
elems[i].style.maxHeight = elems[i].scrollHeight + "px";
} else {
elems[i].style.opacity = "0";
elems[i].style.maxHeight = "";
}
}
for (let i = 0; i < links.length; ++i) {
if (open) {
links[i].style.opacity = "1";
links[i].style.maxHeight = links[i].scrollHeight + "px";
links[i].style.pointerEvents = "auto";
} else {
links[i].style.opacity = "0";
links[i].style.maxHeight = "";
links[i].style.pointerEvents = "none";
}
}
}
export function initializeMainMenuHeaders(p: IPlayer, dev = false): boolean {
function safeGetElement(id: string): HTMLElement {
const elem: HTMLElement | null = document.getElementById(id);
if (elem == null) {
throw new Error(`Failed to find element with id ${id} in initializeMainMenuHeaders()`);
}
return elem;
}
try {
// Get references to the DOM elements
MainMenuHeaders.Hacking = safeGetElement("hacking-menu-header");
MainMenuHeaders.Character = safeGetElement("character-menu-header");
MainMenuHeaders.World = safeGetElement("world-menu-header");
MainMenuHeaders.Help = safeGetElement("help-menu-header");
// Set click handlers to turn the headers into collapsibles
MainMenuHeaders.Hacking.onclick = function () {
const terminal: HTMLElement = safeGetElement("terminal-tab");
const createScript: HTMLElement = safeGetElement("create-script-tab");
const activeScripts: HTMLElement = safeGetElement("active-scripts-tab");
const createProgram: HTMLElement = safeGetElement("create-program-tab");
const createProgramNot: HTMLElement = safeGetElement("create-program-notification");
createProgram.style.display = p.firstProgramAvailable ? "list-item" : "none";
(this as any).classList.toggle("opened");
const elems: HTMLElement[] = [terminal, createScript, activeScripts, createProgram];
const links: HTMLElement[] = [
MainMenuLinks.Terminal,
MainMenuLinks.ScriptEditor,
MainMenuLinks.ActiveScripts,
MainMenuLinks.CreateProgram,
];
if (terminal.style.maxHeight) {
toggleHeader(false, elems, links);
createProgramNot.style.display = "none";
} else {
toggleHeader(true, elems, links);
createProgramNot.style.display = "block";
}
};
MainMenuHeaders.Character.onclick = function () {
const stats: HTMLElement = safeGetElement("stats-tab");
const factions: HTMLElement = safeGetElement("factions-tab");
const augmentations: HTMLElement = safeGetElement("augmentations-tab");
const hacknetnodes: HTMLElement = safeGetElement("hacknet-nodes-tab");
const sleeves: HTMLElement = safeGetElement("sleeves-tab");
sleeves.style.display = p.sleeves.length > 0 ? "list-item" : "none";
(this as any).classList.toggle("opened");
const elems: HTMLElement[] = [stats, factions, augmentations, hacknetnodes, sleeves];
const links: HTMLElement[] = [
MainMenuLinks.Stats,
MainMenuLinks.Factions,
MainMenuLinks.Augmentations,
MainMenuLinks.HacknetNodes,
MainMenuLinks.Sleeves,
];
if (stats.style.maxHeight) {
toggleHeader(false, elems, links);
} else {
toggleHeader(true, elems, links);
}
};
MainMenuHeaders.World.onclick = function () {
const city: HTMLElement = safeGetElement("city-tab");
const travel: HTMLElement = safeGetElement("travel-tab");
const job: HTMLElement = safeGetElement("job-tab");
const stockmarket: HTMLElement = safeGetElement("stock-market-tab");
const bladeburner: HTMLElement = safeGetElement("bladeburner-tab");
const corporation: HTMLElement = safeGetElement("corporation-tab");
const gang: HTMLElement = safeGetElement("gang-tab");
// Determine whether certain links should show up
job.style.display = p.companyName !== "" ? "list-item" : "none";
stockmarket.style.display = p.hasWseAccount ? "list-item" : "none";
bladeburner.style.display = p.inBladeburner() ? "list-item" : "none";
corporation.style.display = p.hasCorporation() ? "list-item" : "none";
gang.style.display = p.inGang() ? "list-item" : "none";
(this as any).classList.toggle("opened");
const elems: HTMLElement[] = [city, travel, job, stockmarket, bladeburner, corporation, gang];
const links: HTMLElement[] = [
MainMenuLinks.City,
MainMenuLinks.Travel,
MainMenuLinks.Job,
MainMenuLinks.StockMarket,
MainMenuLinks.Bladeburner,
MainMenuLinks.Corporation,
MainMenuLinks.Gang,
];
if (city.style.maxHeight) {
toggleHeader(false, elems, links);
} else {
toggleHeader(true, elems, links);
}
};
MainMenuHeaders.Help.onclick = function () {
const milestones: HTMLElement = safeGetElement("milestones-tab");
const tutorial: HTMLElement = safeGetElement("tutorial-tab");
const options: HTMLElement = safeGetElement("options-tab");
(this as any).classList.toggle("opened");
const elems: HTMLElement[] = [milestones, tutorial, options];
const links: HTMLElement[] = [MainMenuLinks.Milestones, MainMenuLinks.Tutorial, MainMenuLinks.Options];
if (dev) {
elems.push(safeGetElement("dev-tab"));
links.push(safeGetElement("dev-menu-link"));
}
if (tutorial.style.maxHeight) {
toggleHeader(false, elems, links);
} else {
toggleHeader(true, elems, links);
}
};
return true;
} catch (e) {
console.error(`Failed to initialize Main Menu Headers: ${e}`);
return false;
}
}

@ -1,98 +0,0 @@
// Get references to the Main Menu link DOM elements
// Does NOT include collapsible headers for the links
import { clearEventListeners } from "../../../utils/uiHelpers/clearEventListeners";
interface IMainMenuLinks {
[key: string]: HTMLElement | undefined;
Terminal: HTMLElement;
ScriptEditor: HTMLElement;
ActiveScripts: HTMLElement;
CreateProgram: HTMLElement;
Stats: HTMLElement;
Factions: HTMLElement;
Augmentations: HTMLElement;
HacknetNodes: HTMLElement;
Sleeves: HTMLElement;
City: HTMLElement;
Travel: HTMLElement;
Job: HTMLElement;
StockMarket: HTMLElement;
Bladeburner: HTMLElement;
Corporation: HTMLElement;
Gang: HTMLElement;
Milestones: HTMLElement;
Tutorial: HTMLElement;
Options: HTMLElement;
DevMenu: HTMLElement;
}
const emptyElement: HTMLElement = ((): HTMLElement => {
const elem = document.createElement("div");
if (elem === null) throw new Error("unable to create empty div element");
return elem;
})();
export const MainMenuLinks: IMainMenuLinks = {
Terminal: emptyElement,
ScriptEditor: emptyElement,
ActiveScripts: emptyElement,
CreateProgram: emptyElement,
Stats: emptyElement,
Factions: emptyElement,
Augmentations: emptyElement,
HacknetNodes: emptyElement,
Sleeves: emptyElement,
City: emptyElement,
Travel: emptyElement,
Job: emptyElement,
StockMarket: emptyElement,
Bladeburner: emptyElement,
Corporation: emptyElement,
Gang: emptyElement,
Milestones: emptyElement,
Tutorial: emptyElement,
Options: emptyElement,
DevMenu: emptyElement,
};
export function initializeMainMenuLinks(): boolean {
return true;
try {
function safeGetLink(id: string): HTMLElement {
const elem: HTMLElement | null = clearEventListeners(id);
if (elem == null) {
throw new Error(`clearEventListeners() failed for element with id: ${id}`);
}
return elem;
}
MainMenuLinks.Terminal = safeGetLink("terminal-menu-link");
MainMenuLinks.ScriptEditor = safeGetLink("create-script-menu-link");
MainMenuLinks.ActiveScripts = safeGetLink("active-scripts-menu-link");
MainMenuLinks.CreateProgram = safeGetLink("create-program-menu-link");
MainMenuLinks.Stats = safeGetLink("stats-menu-link");
MainMenuLinks.Factions = safeGetLink("factions-menu-link");
MainMenuLinks.Augmentations = safeGetLink("augmentations-menu-link");
MainMenuLinks.HacknetNodes = safeGetLink("hacknet-nodes-menu-link");
MainMenuLinks.Sleeves = safeGetLink("sleeves-menu-link");
MainMenuLinks.City = safeGetLink("city-menu-link");
MainMenuLinks.Travel = safeGetLink("travel-menu-link");
MainMenuLinks.Job = safeGetLink("job-menu-link");
MainMenuLinks.StockMarket = safeGetLink("stock-market-menu-link");
MainMenuLinks.Bladeburner = safeGetLink("bladeburner-menu-link");
MainMenuLinks.Corporation = safeGetLink("corporation-menu-link");
MainMenuLinks.Gang = safeGetLink("gang-menu-link");
MainMenuLinks.Milestones = safeGetLink("milestones-menu-link");
MainMenuLinks.Tutorial = safeGetLink("tutorial-menu-link");
// const op: HTMLElement | null = document.getElementById("options-menu-link");
// if (op === null) throw new Error(`Could not find element with id: "options-menu-link"`);
// MainMenuLinks.Options = op; // This click listener is already set, so don't clear it
MainMenuLinks.DevMenu = safeGetLink("dev-menu-link");
return true;
} catch (e) {
console.error(`Failed to initialize Main Menu Links: ${e}`);
return false;
}
}

@ -195,7 +195,7 @@ export function GameOptionsRoot(props: IProps): React.ReactElement {
return; return;
} }
const contents = result; const contents = result;
save(contents).then(() => location.reload()); save(contents).then(() => setTimeout(() => location.reload(), 1000));
}; };
reader.readAsText(file); reader.readAsText(file);
} }
@ -628,7 +628,7 @@ export function GameOptionsRoot(props: IProps): React.ReactElement {
onConfirm={() => { onConfirm={() => {
setDeleteOpen(false); setDeleteOpen(false);
deleteGame() deleteGame()
.then(() => location.reload()) .then(() => setTimeout(() => location.reload(), 1000))
.catch((r) => console.error(`Could not delete game: ${r}`)); .catch((r) => console.error(`Could not delete game: ${r}`));
}} }}
open={deleteGameOpen} open={deleteGameOpen}