This commit is contained in:
Snarling 2022-10-03 12:12:16 -04:00
parent ab56d18e1e
commit 50f14b4f58
67 changed files with 307 additions and 599 deletions

@ -20,7 +20,6 @@ import { SpecialServers } from "../Server/data/SpecialServers";
import { Server } from "../Server/Server"; import { Server } from "../Server/Server";
import { Router } from "../ui/GameRoot"; import { Router } from "../ui/GameRoot";
import { Page } from "../ui/Router"; import { Page } from "../ui/Router";
import { IMap } from "../types";
import * as data from "./AchievementData.json"; import * as data from "./AchievementData.json";
import { FactionNames } from "../Faction/data/FactionNames"; import { FactionNames } from "../Faction/data/FactionNames";
import { BlackOperationNames } from "../Bladeburner/data/BlackOperationNames"; import { BlackOperationNames } from "../Bladeburner/data/BlackOperationNames";
@ -47,7 +46,7 @@ export interface PlayerAchievement {
} }
export interface AchievementDataJson { export interface AchievementDataJson {
achievements: IMap<AchievementData>; achievements: Record<string, AchievementData>;
} }
export interface AchievementData { export interface AchievementData {
@ -87,7 +86,7 @@ function sfAchievement(): Achievement[] {
return achs; return achs;
} }
export const achievements: IMap<Achievement> = { export const achievements: Record<string, Achievement> = {
[FactionNames.CyberSec.toUpperCase()]: { [FactionNames.CyberSec.toUpperCase()]: {
...achievementData[FactionNames.CyberSec.toUpperCase()], ...achievementData[FactionNames.CyberSec.toUpperCase()],
Icon: "CSEC", Icon: "CSEC",

@ -1,8 +1,7 @@
import { IMap } from "./types";
import { Terminal } from "./Terminal"; import { Terminal } from "./Terminal";
export let Aliases: IMap<string> = {}; export let Aliases: Record<string, string> = {};
export let GlobalAliases: IMap<string> = {}; export let GlobalAliases: Record<string, string> = {};
export function loadAliases(saveString: string): void { export function loadAliases(saveString: string): void {
if (saveString === "") { if (saveString === "") {

@ -1,4 +1,3 @@
import { Augmentation } from "./Augmentation"; import { Augmentation } from "./Augmentation";
import { IMap } from "../types";
export const StaticAugmentations: IMap<Augmentation> = {}; export const StaticAugmentations: Record<string, Augmentation> = {};

@ -1,7 +1,6 @@
import React from "react"; import React from "react";
import { Player } from "../Player"; import { Player } from "../Player";
import { BitNodeMultipliers, IBitNodeMultipliers } from "./BitNodeMultipliers"; import { BitNodeMultipliers, IBitNodeMultipliers } from "./BitNodeMultipliers";
import { IMap } from "../types";
import { FactionNames } from "../Faction/data/FactionNames"; import { FactionNames } from "../Faction/data/FactionNames";
import { CityName } from "../Locations/data/CityNames"; import { CityName } from "../Locations/data/CityNames";
@ -29,7 +28,7 @@ class BitNode {
} }
} }
export const BitNodes: IMap<BitNode> = {}; export const BitNodes: Record<string, BitNode> = {};
export function initBitNodes() { export function initBitNodes() {
BitNodes["BitNode1"] = new BitNode( BitNodes["BitNode1"] = new BitNode(
1, 1,

@ -1,8 +1,7 @@
import { BlackOperation } from "./BlackOperation"; import { BlackOperation } from "./BlackOperation";
import { IMap } from "../types";
import { BlackOperationNames } from "./data/BlackOperationNames"; import { BlackOperationNames } from "./data/BlackOperationNames";
export const BlackOperations: IMap<BlackOperation> = {}; export const BlackOperations: Record<string, BlackOperation> = {};
(function () { (function () {
BlackOperations[BlackOperationNames.OperationTyphoon] = new BlackOperation({ BlackOperations[BlackOperationNames.OperationTyphoon] = new BlackOperation({

@ -1,7 +1,6 @@
import { Action } from "./Action"; import { Action } from "./Action";
import { IMap } from "../types";
export const GeneralActions: IMap<Action> = {}; export const GeneralActions: Record<string, Action> = {};
const actionNames: Array<string> = [ const actionNames: Array<string> = [
"Training", "Training",

@ -1,8 +1,7 @@
import { Skill } from "./Skill"; import { Skill } from "./Skill";
import { SkillNames } from "./data/SkillNames"; import { SkillNames } from "./data/SkillNames";
import { IMap } from "../types";
export const Skills: IMap<Skill> = {}; export const Skills: Record<string, Skill> = {};
(function () { (function () {
Skills[SkillNames.BladesIntuition] = new Skill({ Skills[SkillNames.BladesIntuition] = new Skill({

@ -1,7 +1,5 @@
import { codingContractTypesMetadata, DescriptionFunc, GeneratorFunc, SolverFunc } from "./data/codingcontracttypes"; import { codingContractTypesMetadata, DescriptionFunc, GeneratorFunc, SolverFunc } from "./data/codingcontracttypes";
import { IMap } from "./types";
import { Generic_fromJSON, Generic_toJSON, IReviverValue, Reviver } from "./utils/JSONReviver"; import { Generic_fromJSON, Generic_toJSON, IReviverValue, Reviver } from "./utils/JSONReviver";
import { CodingContractEvent } from "./ui/React/CodingContractModal"; import { CodingContractEvent } from "./ui/React/CodingContractModal";
@ -58,7 +56,7 @@ class CodingContractType {
/* Contract Types */ /* Contract Types */
// tslint:disable-next-line // tslint:disable-next-line
export const CodingContractTypes: IMap<CodingContractType> = {}; export const CodingContractTypes: Record<string, CodingContractType> = {};
for (const md of codingContractTypesMetadata) { for (const md of codingContractTypesMetadata) {
// tslint:disable-next-line // tslint:disable-next-line

@ -1,10 +1,9 @@
// Constructs all CompanyPosition objects using the metadata in data/companypositions.ts // Constructs all CompanyPosition objects using the metadata in data/companypositions.ts
import { companiesMetadata } from "./data/CompaniesMetadata"; import { companiesMetadata } from "./data/CompaniesMetadata";
import { Company, IConstructorParams } from "./Company"; import { Company, IConstructorParams } from "./Company";
import { IMap } from "../types";
import { Reviver } from "../utils/JSONReviver"; import { Reviver } from "../utils/JSONReviver";
export let Companies: IMap<Company> = {}; export let Companies: Record<string, Company> = {};
function addCompany(params: IConstructorParams): void { function addCompany(params: IConstructorParams): void {
if (Companies[params.name] != null) { if (Companies[params.name] != null) {

@ -2,14 +2,12 @@ import { CompanyPosition } from "./CompanyPosition";
import * as posNames from "./data/companypositionnames"; import * as posNames from "./data/companypositionnames";
import { favorToRep, repToFavor } from "../Faction/formulas/favor"; import { favorToRep, repToFavor } from "../Faction/formulas/favor";
import { IMap } from "../types";
import { Generic_fromJSON, Generic_toJSON, IReviverValue, Reviver } from "../utils/JSONReviver"; import { Generic_fromJSON, Generic_toJSON, IReviverValue, Reviver } from "../utils/JSONReviver";
export interface IConstructorParams { export interface IConstructorParams {
name: string; name: string;
info: string; info: string;
companyPositions: IMap<boolean>; companyPositions: Record<string, boolean>;
expMultiplier: number; expMultiplier: number;
salaryMultiplier: number; salaryMultiplier: number;
jobStatReqOffset: number; jobStatReqOffset: number;
@ -48,7 +46,7 @@ export class Company {
* *
* Must match names of Company Positions, defined in data/companypositionnames.ts * Must match names of Company Positions, defined in data/companypositionnames.ts
*/ */
companyPositions: IMap<boolean>; companyPositions: Record<string, boolean>;
/** /**
* Company-specific multiplier for earnings * Company-specific multiplier for earnings

@ -1,9 +1,8 @@
// Constructs all CompanyPosition objects using the metadata in data/companypositions.ts // Constructs all CompanyPosition objects using the metadata in data/companypositions.ts
import { companyPositionMetadata } from "./data/CompanyPositionsMetadata"; import { companyPositionMetadata } from "./data/CompanyPositionsMetadata";
import { CompanyPosition, IConstructorParams } from "./CompanyPosition"; import { CompanyPosition, IConstructorParams } from "./CompanyPosition";
import { IMap } from "../types";
export const CompanyPositions: IMap<CompanyPosition> = {}; export const CompanyPositions: Record<string, CompanyPosition> = {};
function addCompanyPosition(params: IConstructorParams): void { function addCompanyPosition(params: IConstructorParams): void {
if (CompanyPositions[params.name] != null) { if (CompanyPositions[params.name] != null) {

@ -1,30 +1,29 @@
import * as posNames from "./companypositionnames"; import * as posNames from "./companypositionnames";
import { IConstructorParams } from "../Company"; import { IConstructorParams } from "../Company";
import { IMap } from "../../types";
import { LocationName } from "../../Locations/data/LocationNames"; import { LocationName } from "../../Locations/data/LocationNames";
// Create Objects containing Company Positions by category // Create Objects containing Company Positions by category
// Will help in metadata construction later // Will help in metadata construction later
const AllSoftwarePositions: IMap<boolean> = {}; const AllSoftwarePositions: Record<string, boolean> = {};
const AllITPositions: IMap<boolean> = {}; const AllITPositions: Record<string, boolean> = {};
const AllNetworkEngineerPositions: IMap<boolean> = {}; const AllNetworkEngineerPositions: Record<string, boolean> = {};
const SecurityEngineerPositions: IMap<boolean> = {}; const SecurityEngineerPositions: Record<string, boolean> = {};
const AllTechnologyPositions: IMap<boolean> = {}; const AllTechnologyPositions: Record<string, boolean> = {};
const AllBusinessPositions: IMap<boolean> = {}; const AllBusinessPositions: Record<string, boolean> = {};
const AllAgentPositions: IMap<boolean> = {}; const AllAgentPositions: Record<string, boolean> = {};
const AllSecurityPositions: IMap<boolean> = {}; const AllSecurityPositions: Record<string, boolean> = {};
const AllSoftwareConsultantPositions: IMap<boolean> = {}; const AllSoftwareConsultantPositions: Record<string, boolean> = {};
const AllBusinessConsultantPositions: IMap<boolean> = {}; const AllBusinessConsultantPositions: Record<string, boolean> = {};
const SoftwarePositionsUpToHeadOfEngineering: IMap<boolean> = {}; const SoftwarePositionsUpToHeadOfEngineering: Record<string, boolean> = {};
const SoftwarePositionsUpToLeadDeveloper: IMap<boolean> = {}; const SoftwarePositionsUpToLeadDeveloper: Record<string, boolean> = {};
const BusinessPositionsUpToOperationsManager: IMap<boolean> = {}; const BusinessPositionsUpToOperationsManager: Record<string, boolean> = {};
const WaiterOnly: IMap<boolean> = {}; const WaiterOnly: Record<string, boolean> = {};
const EmployeeOnly: IMap<boolean> = {}; const EmployeeOnly: Record<string, boolean> = {};
const PartTimeWaiterOnly: IMap<boolean> = {}; const PartTimeWaiterOnly: Record<string, boolean> = {};
const PartTimeEmployeeOnly: IMap<boolean> = {}; const PartTimeEmployeeOnly: Record<string, boolean> = {};
const OperationsManagerOnly: IMap<boolean> = {}; const OperationsManagerOnly: Record<string, boolean> = {};
const CEOOnly: IMap<boolean> = {}; const CEOOnly: Record<string, boolean> = {};
posNames.SoftwareCompanyPositions.forEach((e) => { posNames.SoftwareCompanyPositions.forEach((e) => {
AllSoftwarePositions[e] = true; AllSoftwarePositions[e] = true;

@ -14,6 +14,7 @@ import { Cities } from "../Locations/Cities";
import { EmployeePositions } from "./EmployeePositions"; import { EmployeePositions } from "./EmployeePositions";
import { ResearchMap } from "./ResearchMap"; import { ResearchMap } from "./ResearchMap";
import { isRelevantMaterial } from "./ui/Helpers"; import { isRelevantMaterial } from "./ui/Helpers";
import { checkObjContainsValue } from "../utils/helpers/checkObjContains";
export function NewIndustry(corporation: Corporation, industry: string, name: string): void { export function NewIndustry(corporation: Corporation, industry: string, name: string): void {
if (corporation.divisions.find(({ type }) => industry == type)) if (corporation.divisions.find(({ type }) => industry == type))
@ -303,16 +304,13 @@ export function BuyBackShares(corporation: Corporation, numShares: number): bool
export function AssignJob(office: OfficeSpace, employeeName: string, job: string): void { export function AssignJob(office: OfficeSpace, employeeName: string, job: string): void {
const employee = office.employees.find((e) => e.name === employeeName); const employee = office.employees.find((e) => e.name === employeeName);
if (!employee) throw new Error(`Could not find employee '${name}'.`); if (!employee) throw new Error(`Could not find employee '${name}'.`);
if (!Object.values(EmployeePositions).includes(job)) throw new Error(`'${job}' is not a valid job.`); if (!checkObjContainsValue(EmployeePositions, job)) throw new Error(`'${job}' is not a valid job.`)
office.assignSingleJob(employee, job); office.assignSingleJob(employee, job);
} }
export function AutoAssignJob(office: OfficeSpace, job: string, count: number): boolean { export function AutoAssignJob(office: OfficeSpace, job: string, count: number): boolean {
if (!Object.values(EmployeePositions).includes(job)) throw new Error(`'${job}' is not a valid job.`); if (!checkObjContainsValue(EmployeePositions, job)) throw new Error(`'${job}' is not a valid job.`)
return office.autoAssignJob(job, count); return office.autoAssignJob(job, count);
} }

@ -1,6 +1,4 @@
import { IMap } from "../types"; export const EmployeePositions = {
export const EmployeePositions: IMap<string> = {
Operations: "Operations", Operations: "Operations",
Engineer: "Engineer", Engineer: "Engineer",
Business: "Business", Business: "Business",
@ -8,4 +6,4 @@ export const EmployeePositions: IMap<string> = {
RandD: "Research & Development", RandD: "Research & Development",
Training: "Training", Training: "Training",
Unassigned: "Unassigned", Unassigned: "Unassigned",
}; } as const;

@ -1,7 +1,5 @@
import { IMap } from "../types";
// Map of material (by name) to their sizes (how much space it takes in warehouse) // Map of material (by name) to their sizes (how much space it takes in warehouse)
export const MaterialSizes: IMap<number> = { export const MaterialSizes: Record<string, number> = {
Water: 0.05, Water: 0.05,
Energy: 0.01, Energy: 0.01,
Food: 0.03, Food: 0.03,

@ -4,7 +4,6 @@ import { Industry } from "./Industry";
import { ProductRatingWeights, IProductRatingWeight } from "./ProductRatingWeights"; import { ProductRatingWeights, IProductRatingWeight } from "./ProductRatingWeights";
import { createCityMap } from "../Locations/createCityMap"; import { createCityMap } from "../Locations/createCityMap";
import { IMap } from "../types";
import { Generic_fromJSON, Generic_toJSON, IReviverValue, Reviver } from "../utils/JSONReviver"; import { Generic_fromJSON, Generic_toJSON, IReviverValue, Reviver } from "../utils/JSONReviver";
import { getRandomInt } from "../utils/helpers/getRandomInt"; import { getRandomInt } from "../utils/helpers/getRandomInt";
@ -25,7 +24,7 @@ interface IConstructorParams {
features?: number; features?: number;
loc?: string; loc?: string;
size?: number; size?: number;
req?: IMap<number>; req?: Record<string, number>;
} }
export class Product { export class Product {
@ -81,7 +80,7 @@ export class Product {
// Data refers to the production, sale, and quantity of the products // Data refers to the production, sale, and quantity of the products
// These values are specific to a city // These values are specific to a city
// For each city, the data is [qty, prod, sell] // For each city, the data is [qty, prod, sell]
data: IMap<number[]> = createCityMap<number[]>([0, 0, 0]); data: Record<string, number[]> = createCityMap<number[]>([0, 0, 0]);
// Location of this Product // Location of this Product
// Only applies for location-based products like restaurants/hospitals // Only applies for location-based products like restaurants/hospitals
@ -93,18 +92,18 @@ export class Product {
// Material requirements. An object that maps the name of a material to how much it requires // Material requirements. An object that maps the name of a material to how much it requires
// to make 1 unit of the product. // to make 1 unit of the product.
reqMats: IMap<number> = {}; reqMats: Record<string, number> = {};
// Data to keep track of whether production/sale of this Product is // Data to keep track of whether production/sale of this Product is
// manually limited. These values are specific to a city // manually limited. These values are specific to a city
// [Whether production/sale is limited, limit amount] // [Whether production/sale is limited, limit amount]
prdman: IMap<any[]> = createCityMap<any[]>([false, 0]); prdman: Record<string, any[]> = createCityMap<any[]>([false, 0]);
sllman: IMap<any[]> = createCityMap<any[]>([false, 0]); sllman: Record<string, any[]> = createCityMap<any[]>([false, 0]);
// Flags that signal whether automatic sale pricing through Market TA is enabled // Flags that signal whether automatic sale pricing through Market TA is enabled
marketTa1 = false; marketTa1 = false;
marketTa2 = false; marketTa2 = false;
marketTa2Price: IMap<number> = createCityMap<number>(0); marketTa2Price: Record<string, number> = createCityMap<number>(0);
// Determines the maximum amount of this product that can be sold in one market cycle // Determines the maximum amount of this product that can be sold in one market cycle
maxsll = 0; maxsll = 0;

@ -1,5 +1,4 @@
import { Industries } from "./IndustryData"; import { Industries } from "./IndustryData";
import { IMap } from "../types";
export interface IProductRatingWeight { export interface IProductRatingWeight {
Aesthetics?: number; Aesthetics?: number;
@ -10,7 +9,7 @@ export interface IProductRatingWeight {
Reliability?: number; Reliability?: number;
} }
export const ProductRatingWeights: IMap<any> = { export const ProductRatingWeights: Record<string, IProductRatingWeight> = {
[Industries.Food]: { [Industries.Food]: {
Quality: 0.7, Quality: 0.7,
Durability: 0.1, Durability: 0.1,

@ -2,9 +2,8 @@
// as values. They are identified by their names // as values. They are identified by their names
import { Research, IConstructorParams } from "./Research"; import { Research, IConstructorParams } from "./Research";
import { researchMetadata } from "./data/ResearchMetadata"; import { researchMetadata } from "./data/ResearchMetadata";
import { IMap } from "../types";
export const ResearchMap: IMap<Research> = {}; export const ResearchMap: Record<string, Research> = {};
function addResearch(p: IConstructorParams): void { function addResearch(p: IConstructorParams): void {
if (ResearchMap[p.name] != null) { if (ResearchMap[p.name] != null) {

@ -6,8 +6,6 @@
import { Research } from "./Research"; import { Research } from "./Research";
import { ResearchMap } from "./ResearchMap"; import { ResearchMap } from "./ResearchMap";
import { IMap } from "../types";
interface IConstructorParams { interface IConstructorParams {
children?: Node[]; children?: Node[];
cost: number; cost: number;
@ -86,7 +84,7 @@ export class Node {
// The root node in a Research Tree must always be the "Hi-Tech R&D Laboratory" // The root node in a Research Tree must always be the "Hi-Tech R&D Laboratory"
export class ResearchTree { export class ResearchTree {
// Object containing names of all acquired Research by name // Object containing names of all acquired Research by name
researched: IMap<boolean> = {}; researched: Record<string, boolean> = {};
// Root Node // Root Node
root: Node | null = null; root: Node | null = null;

@ -2,7 +2,6 @@ import { Material } from "./Material";
import { Corporation } from "./Corporation"; import { Corporation } from "./Corporation";
import { Industry } from "./Industry"; import { Industry } from "./Industry";
import { MaterialSizes } from "./MaterialSizes"; import { MaterialSizes } from "./MaterialSizes";
import { IMap } from "../types";
import { Generic_fromJSON, Generic_toJSON, IReviverValue, Reviver } from "../utils/JSONReviver"; import { Generic_fromJSON, Generic_toJSON, IReviverValue, Reviver } from "../utils/JSONReviver";
import { exceptionAlert } from "../utils/helpers/exceptionAlert"; import { exceptionAlert } from "../utils/helpers/exceptionAlert";
@ -21,7 +20,7 @@ export class Warehouse {
loc: string; loc: string;
// Map of Materials held by this Warehouse // Map of Materials held by this Warehouse
materials: IMap<Material>; materials: Record<string, Material>;
// Maximum amount warehouse can hold // Maximum amount warehouse can hold
size: number; size: number;

@ -1,11 +1,10 @@
import { Crime } from "./Crime"; import { Crime } from "./Crime";
import { CONSTANTS } from "../Constants"; import { CONSTANTS } from "../Constants";
import { IMap } from "../types";
import { CrimeType } from "../utils/WorkType"; import { CrimeType } from "../utils/WorkType";
export const Crimes: IMap<Crime> = { export const Crimes: Record<string, Crime> = {
Shoplift: new Crime("Shoplift", "to shoplift", CrimeType.SHOPLIFT, 2e3, 15e3, 1 / 20, 0.1, { Shoplift: new Crime("Shoplift", "to shoplift", CrimeType.SHOPLIFT, 2e3, 15e3, 1 / 20, 0.1, {
dexterity_success_weight: 1, dexterity_success_weight: 1,
agility_success_weight: 1, agility_success_weight: 1,

@ -1,8 +1,7 @@
import { DarkWebItem } from "./DarkWebItem"; import { DarkWebItem } from "./DarkWebItem";
import { IMap } from "../types";
import { Programs, initPrograms } from "../Programs/Programs"; import { Programs, initPrograms } from "../Programs/Programs";
export const DarkWebItems: IMap<DarkWebItem> = {}; export const DarkWebItems: Record<string, DarkWebItem> = {};
export function initDarkWebItems() { export function initDarkWebItems() {
initPrograms(); initPrograms();
Object.assign(DarkWebItems, { Object.assign(DarkWebItems, {

@ -7,7 +7,7 @@ import ExpandMoreIcon from "@mui/icons-material/ExpandMore";
import Typography from "@mui/material/Typography"; import Typography from "@mui/material/Typography";
import { saveObject } from "../../SaveObject"; import { saveObject } from "../../SaveObject";
import { SnackbarEvents, ToastVariant } from "../../ui/React/Snackbar"; import { SnackbarEvents } from "../../ui/React/Snackbar";
import { Upload } from "@mui/icons-material"; import { Upload } from "@mui/icons-material";
import { Button } from "@mui/material"; import { Button } from "@mui/material";
import { OptionSwitch } from "../../ui/React/OptionSwitch"; import { OptionSwitch } from "../../ui/React/OptionSwitch";
@ -25,7 +25,7 @@ export function SaveFile(): React.ReactElement {
const save = atob(base64Save); const save = atob(base64Save);
setSaveFile(save); setSaveFile(save);
} catch (e: unknown) { } catch (e: unknown) {
SnackbarEvents.emit(String(e), ToastVariant.ERROR, 5000); SnackbarEvents.emit(String(e), "error", 5000);
} }
} }

@ -3,7 +3,7 @@ import { Router } from "./ui/GameRoot";
import { removeLeadingSlash } from "./Terminal/DirectoryHelpers"; import { removeLeadingSlash } from "./Terminal/DirectoryHelpers";
import { Terminal } from "./Terminal"; import { Terminal } from "./Terminal";
import { SnackbarEvents, ToastVariant } from "./ui/React/Snackbar"; import { SnackbarEvents, ToastVariant } from "./ui/React/Snackbar";
import { IMap, IReturnStatus } from "./types"; import { IReturnStatus } from "./types";
import { GetServer } from "./Server/AllServers"; import { GetServer } from "./Server/AllServers";
import { ImportPlayerData, SaveData, saveObject } from "./SaveObject"; import { ImportPlayerData, SaveData, saveObject } from "./SaveObject";
import { Settings } from "./Settings/Settings"; import { Settings } from "./Settings/Settings";
@ -125,7 +125,7 @@ function initWebserver(): void {
function initAppNotifier(): void { function initAppNotifier(): void {
const funcs = { const funcs = {
terminal: (message: string, type?: string) => { terminal: (message: string, type?: string) => {
const typesFn: IMap<(s: string) => void> = { const typesFn: Record<string, (s: string) => void> = {
info: Terminal.info, info: Terminal.info,
warn: Terminal.warn, warn: Terminal.warn,
error: Terminal.error, error: Terminal.error,
@ -151,7 +151,7 @@ function initSaveFunctions(): void {
saveObject.exportGame(); saveObject.exportGame();
} catch (error) { } catch (error) {
console.error(error); console.error(error);
SnackbarEvents.emit("Could not export game.", ToastVariant.ERROR, 2000); SnackbarEvents.emit("Could not export game.", "error", 2000);
} }
}, },
triggerScriptsExport: (): void => exportScripts("*", Player.getHomeComputer()), triggerScriptsExport: (): void => exportScripts("*", Player.getHomeComputer()),
@ -203,7 +203,7 @@ function initElectronBridge(): void {
}) })
.catch((error: unknown) => { .catch((error: unknown) => {
console.error(error); console.error(error);
SnackbarEvents.emit("Could not save game.", ToastVariant.ERROR, 2000); SnackbarEvents.emit("Could not save game.", "error", 2000);
}); });
}); });
bridge.receive("trigger-game-export", () => { bridge.receive("trigger-game-export", () => {
@ -211,7 +211,7 @@ function initElectronBridge(): void {
window.appSaveFns.triggerGameExport(); window.appSaveFns.triggerGameExport();
} catch (error) { } catch (error) {
console.error(error); console.error(error);
SnackbarEvents.emit("Could not export game.", ToastVariant.ERROR, 2000); SnackbarEvents.emit("Could not export game.", "error", 2000);
} }
}); });
bridge.receive("trigger-scripts-export", () => { bridge.receive("trigger-scripts-export", () => {
@ -219,7 +219,7 @@ function initElectronBridge(): void {
window.appSaveFns.triggerScriptsExport(); window.appSaveFns.triggerScriptsExport();
} catch (error) { } catch (error) {
console.error(error); console.error(error);
SnackbarEvents.emit("Could not export scripts.", ToastVariant.ERROR, 2000); SnackbarEvents.emit("Could not export scripts.", "error", 2000);
} }
}); });
} }

@ -1,5 +1,4 @@
import React from "react"; import React from "react";
import { IMap } from "../types";
import { FactionNames } from "./data/FactionNames"; import { FactionNames } from "./data/FactionNames";
import { Router } from "../ui/GameRoot"; import { Router } from "../ui/GameRoot";
import { Option } from "./ui/Option"; import { Option } from "./ui/Option";
@ -81,7 +80,7 @@ export class FactionInfo {
* A map of all factions and associated info to them. * A map of all factions and associated info to them.
*/ */
// tslint:disable-next-line:variable-name // tslint:disable-next-line:variable-name
export const FactionInfos: IMap<FactionInfo> = { export const FactionInfos: Record<string, FactionInfo> = {
// Endgame // Endgame
[FactionNames.Illuminati]: new FactionInfo({ [FactionNames.Illuminati]: new FactionInfo({
infoText: ( infoText: (

@ -5,11 +5,9 @@
import { Faction } from "./Faction"; import { Faction } from "./Faction";
import { FactionInfos } from "./FactionInfo"; import { FactionInfos } from "./FactionInfo";
import { IMap } from "../types";
import { Reviver } from "../utils/JSONReviver"; import { Reviver } from "../utils/JSONReviver";
export let Factions: IMap<Faction> = {}; export let Factions: Record<string, Faction> = {};
export function loadFactions(saveString: string): void { export function loadFactions(saveString: string): void {
Factions = JSON.parse(saveString, Reviver); Factions = JSON.parse(saveString, Reviver);

@ -19,7 +19,7 @@ import { StyleEditorButton } from "../../Themes/ui/StyleEditorButton";
import { ThemeEditorButton } from "../../Themes/ui/ThemeEditorButton"; import { ThemeEditorButton } from "../../Themes/ui/ThemeEditorButton";
import { ConfirmationModal } from "../../ui/React/ConfirmationModal"; import { ConfirmationModal } from "../../ui/React/ConfirmationModal";
import { DeleteGameButton } from "../../ui/React/DeleteGameButton"; import { DeleteGameButton } from "../../ui/React/DeleteGameButton";
import { SnackbarEvents, ToastVariant } from "../../ui/React/Snackbar"; import { SnackbarEvents } from "../../ui/React/Snackbar";
import { SoftResetButton } from "../../ui/React/SoftResetButton"; import { SoftResetButton } from "../../ui/React/SoftResetButton";
import { Router } from "../../ui/GameRoot"; import { Router } from "../../ui/GameRoot";
import { convertTimeMsToTimeElapsedString } from "../../utils/StringHelperFunctions"; import { convertTimeMsToTimeElapsedString } from "../../utils/StringHelperFunctions";
@ -72,7 +72,7 @@ export const GameOptionsSidebar = (props: IProps): React.ReactElement => {
setImportData(data); setImportData(data);
setImportSaveOpen(true); setImportSaveOpen(true);
} catch (e: unknown) { } catch (e: unknown) {
SnackbarEvents.emit(String(e), ToastVariant.ERROR, 5000); SnackbarEvents.emit(String(e), "error", 5000);
} }
} }
@ -82,7 +82,7 @@ export const GameOptionsSidebar = (props: IProps): React.ReactElement => {
try { try {
await saveObject.importGame(importData.base64); await saveObject.importGame(importData.base64);
} catch (e: unknown) { } catch (e: unknown) {
SnackbarEvents.emit(String(e), ToastVariant.ERROR, 5000); SnackbarEvents.emit(String(e), "error", 5000);
} }
setImportSaveOpen(false); setImportSaveOpen(false);

@ -9,7 +9,6 @@
import { HashUpgrades } from "./HashUpgrades"; import { HashUpgrades } from "./HashUpgrades";
import { HashUpgrade } from "./HashUpgrade"; import { HashUpgrade } from "./HashUpgrade";
import { IMap } from "../types";
import { Generic_fromJSON, Generic_toJSON, IReviverValue, Reviver } from "../utils/JSONReviver"; import { Generic_fromJSON, Generic_toJSON, IReviverValue, Reviver } from "../utils/JSONReviver";
export class HashManager { export class HashManager {
@ -21,7 +20,7 @@ export class HashManager {
hashes = 0; hashes = 0;
// Map of Hash Upgrade Name -> levels in that upgrade // Map of Hash Upgrade Name -> levels in that upgrade
upgrades: IMap<number> = {}; upgrades: Record<string, number> = {};
constructor() { constructor() {
for (const name of Object.keys(HashUpgrades)) { for (const name of Object.keys(HashUpgrades)) {

@ -4,9 +4,8 @@
*/ */
import { HashUpgrade, IConstructorParams } from "./HashUpgrade"; import { HashUpgrade, IConstructorParams } from "./HashUpgrade";
import { HashUpgradesMetadata } from "./data/HashUpgradesMetadata"; import { HashUpgradesMetadata } from "./data/HashUpgradesMetadata";
import { IMap } from "../types";
export const HashUpgrades: IMap<HashUpgrade> = {}; export const HashUpgrades: Record<string, HashUpgrade> = {};
function createHashUpgrade(p: IConstructorParams): void { function createHashUpgrade(p: IConstructorParams): void {
HashUpgrades[p.name] = new HashUpgrade(p); HashUpgrades[p.name] = new HashUpgrade(p);

@ -1,10 +1,9 @@
import { CityName } from "./../Locations/data/CityNames"; import { CityName } from "./../Locations/data/CityNames";
import { Literature } from "./Literature"; import { Literature } from "./Literature";
import { LiteratureNames } from "./data/LiteratureNames"; import { LiteratureNames } from "./data/LiteratureNames";
import { IMap } from "../types";
import { FactionNames } from "../Faction/data/FactionNames"; import { FactionNames } from "../Faction/data/FactionNames";
export const Literatures: IMap<Literature> = {}; export const Literatures: Record<string, Literature> = {};
(function () { (function () {
let title, fn, txt; let title, fn, txt;

@ -1,6 +1,4 @@
import { IMap } from "../../types"; export const LiteratureNames = {
export const LiteratureNames: IMap<string> = {
HackersStartingHandbook: "hackers-starting-handbook.lit", HackersStartingHandbook: "hackers-starting-handbook.lit",
CorporationManagementHandbook: "corporation-management-handbook.lit", CorporationManagementHandbook: "corporation-management-handbook.lit",
HistoryOfSynthoids: "history-of-synthoids.lit", HistoryOfSynthoids: "history-of-synthoids.lit",
@ -22,4 +20,4 @@ export const LiteratureNames: IMap<string> = {
TheNewGod: "the-new-god.lit", TheNewGod: "the-new-god.lit",
NewTriads: "new-triads.lit", NewTriads: "new-triads.lit",
TheSecretWar: "the-secret-war.lit", TheSecretWar: "the-secret-war.lit",
}; } as const;

@ -3,6 +3,5 @@
* Key = City Name, Value = City object * Key = City Name, Value = City object
*/ */
import { City } from "./City"; import { City } from "./City";
import { IMap } from "../types";
export const Cities: IMap<City> = {}; export const Cities: Record<string, City> = {};

@ -8,9 +8,7 @@ import { Location, IConstructorParams } from "./Location";
import { CityName } from "./data/CityNames"; import { CityName } from "./data/CityNames";
import { LocationsMetadata } from "./data/LocationsMetadata"; import { LocationsMetadata } from "./data/LocationsMetadata";
import { IMap } from "../types"; export const Locations: Record<string, Location> = {};
export const Locations: IMap<Location> = {};
/** /**
* Here, we'll initialize both Locations and Cities data. These can both * Here, we'll initialize both Locations and Cities data. These can both

@ -5,10 +5,9 @@
* This map uses the official name of the city, NOT its key in the 'Cities' object * This map uses the official name of the city, NOT its key in the 'Cities' object
*/ */
import { Cities } from "./Cities"; import { Cities } from "./Cities";
import { IMap } from "../types";
export function createCityMap<T>(initValue: T): IMap<T> { export function createCityMap<T>(initValue: T): Record<string, T> {
const map: IMap<T> = {}; const map: Record<string, T> = {};
const cities = Object.keys(Cities); const cities = Object.keys(Cities);
for (let i = 0; i < cities.length; ++i) { for (let i = 0; i < cities.length; ++i) {
map[cities[i]] = initValue; map[cities[i]] = initValue;

@ -25,7 +25,7 @@ import { Router } from "../../ui/GameRoot";
import { Player } from "../../Player"; import { Player } from "../../Player";
import { dialogBoxCreate } from "../../ui/React/DialogBox"; import { dialogBoxCreate } from "../../ui/React/DialogBox";
import { SnackbarEvents, ToastVariant } from "../../ui/React/Snackbar"; import { SnackbarEvents } from "../../ui/React/Snackbar";
import { N00dles } from "../../utils/helpers/N00dles"; import { N00dles } from "../../utils/helpers/N00dles";
import { Exploit } from "../../Exploits/Exploit"; import { Exploit } from "../../Exploits/Exploit";
import { applyAugmentation } from "../../Augmentation/AugmentationHelpers"; import { applyAugmentation } from "../../Augmentation/AugmentationHelpers";
@ -95,7 +95,7 @@ export function SpecialLocation(props: IProps): React.ReactElement {
function renderNoodleBar(): React.ReactElement { function renderNoodleBar(): React.ReactElement {
function EatNoodles(): void { function EatNoodles(): void {
SnackbarEvents.emit("You ate some delicious noodles and feel refreshed", ToastVariant.SUCCESS, 2000); SnackbarEvents.emit("You ate some delicious noodles and feel refreshed", "success", 2000);
N00dles(); // This is the true power of the noodles. N00dles(); // This is the true power of the noodles.
if (Player.sourceFiles.length > 0) Player.giveExploit(Exploit.N00dles); if (Player.sourceFiles.length > 0) Player.giveExploit(Exploit.N00dles);
if (Player.sourceFileLvl(5) > 0 || Player.bitNodeN === 5) { if (Player.sourceFileLvl(5) > 0 || Player.bitNodeN === 5) {

@ -1,5 +1,4 @@
import { Player } from "../Player"; import { Player } from "../Player";
import { IMap } from "../types";
import { NS as INS } from "../ScriptEditor/NetscriptDefinitions"; import { NS as INS } from "../ScriptEditor/NetscriptDefinitions";
import { INetscriptExtra } from "../NetscriptFunctions/Extra"; import { INetscriptExtra } from "../NetscriptFunctions/Extra";
@ -15,7 +14,7 @@ type RamCostTree<API> = {
// TODO remember to update RamCalculations.js and WorkerScript.js // TODO remember to update RamCalculations.js and WorkerScript.js
// RAM costs for Netscript functions // RAM costs for Netscript functions
export const RamCostConstants: IMap<number> = { export const RamCostConstants: Record<string, number> = {
ScriptBaseRamCost: 1.6, ScriptBaseRamCost: 1.6,
ScriptDomRamCost: 25, ScriptDomRamCost: 25,
ScriptCorporationRamCost: 1024 - 1.6, ScriptCorporationRamCost: 1024 - 1.6,
@ -604,7 +603,7 @@ const SourceRamCosts = {
}, },
}; };
export const RamCosts: IMap<any> = SourceRamCosts; export const RamCosts: Record<string, any> = SourceRamCosts;
// This line in particular is there so typescript typechecks that we are not missing any static ram cost. // This line in particular is there so typescript typechecks that we are not missing any static ram cost.
// eslint-disable-next-line @typescript-eslint/no-unused-vars // eslint-disable-next-line @typescript-eslint/no-unused-vars

@ -13,7 +13,6 @@ import { RunningScript } from "../Script/RunningScript";
import { Script } from "../Script/Script"; import { Script } from "../Script/Script";
import { GetServer } from "../Server/AllServers"; import { GetServer } from "../Server/AllServers";
import { BaseServer } from "../Server/BaseServer"; import { BaseServer } from "../Server/BaseServer";
import { IMap } from "../types";
import { NS } from "../ScriptEditor/NetscriptDefinitions"; import { NS } from "../ScriptEditor/NetscriptDefinitions";
import { ScriptDeath } from "./ScriptDeath"; import { ScriptDeath } from "./ScriptDeath";
import { ScriptArg } from "./ScriptArg"; import { ScriptArg } from "./ScriptArg";
@ -43,14 +42,14 @@ export class WorkerScript {
/** /**
* Stores names of all functions that have logging disabled * Stores names of all functions that have logging disabled
*/ */
disableLogs: IMap<boolean> = {}; disableLogs: Record<string, boolean> = {};
/** /**
* Used for dynamic RAM calculation. Stores names of all functions that have * Used for dynamic RAM calculation. Stores names of all functions that have
* already been checked by this script. * already been checked by this script.
* TODO: Could probably just combine this with loadedFns? * TODO: Could probably just combine this with loadedFns?
*/ */
dynamicLoadedFns: IMap<boolean> = {}; dynamicLoadedFns: Record<string, boolean> = {};
/** /**
* Tracks dynamic RAM usage * Tracks dynamic RAM usage
@ -71,7 +70,7 @@ export class WorkerScript {
* Used for static RAM calculation. Stores names of all functions that have * Used for static RAM calculation. Stores names of all functions that have
* already been checked by this script * already been checked by this script
*/ */
loadedFns: IMap<boolean> = {}; loadedFns: Record<string, boolean> = {};
/** /**
* Filename of script * Filename of script

@ -71,7 +71,7 @@ import { NetscriptSingularity } from "./NetscriptFunctions/Singularity";
import { dialogBoxCreate } from "./ui/React/DialogBox"; import { dialogBoxCreate } from "./ui/React/DialogBox";
import { SnackbarEvents, ToastVariant } from "./ui/React/Snackbar"; import { SnackbarEvents, ToastVariant } from "./ui/React/Snackbar";
import { checkEnum } from "./utils/helpers/checkEnum"; import { checkObjContainsValue } from "./utils/helpers/checkObjContains";
import { Flags } from "./NetscriptFunctions/Flags"; import { Flags } from "./NetscriptFunctions/Flags";
import { calculateIntelligenceBonus } from "./PersonObjects/formulas/intelligence"; import { calculateIntelligenceBonus } from "./PersonObjects/formulas/intelligence";
@ -80,7 +80,17 @@ import { recentScripts } from "./Netscript/RecentScripts";
import { InternalAPI, NetscriptContext, wrapAPI } from "./Netscript/APIWrapper"; import { InternalAPI, NetscriptContext, wrapAPI } from "./Netscript/APIWrapper";
import { INetscriptExtra } from "./NetscriptFunctions/Extra"; import { INetscriptExtra } from "./NetscriptFunctions/Extra";
import { ScriptDeath } from "./Netscript/ScriptDeath"; import { ScriptDeath } from "./Netscript/ScriptDeath";
import { TypeEquality, ValuesFrom } from "./types";
// "Enums" as object
export const enums = {
toast: {
SUCCESS: "success",
WARNING: "warning",
ERROR: "error",
INFO: "info",
} as const,
};
export type NSFull = NS & INetscriptExtra; export type NSFull = NS & INetscriptExtra;
export function NetscriptFunctions(workerScript: WorkerScript): NSFull { export function NetscriptFunctions(workerScript: WorkerScript): NSFull {
@ -89,10 +99,8 @@ export function NetscriptFunctions(workerScript: WorkerScript): NSFull {
const base: InternalAPI<NS> = { const base: InternalAPI<NS> = {
args: [], args: [],
enums: { //The next line will error if enums does not match the definition in NetscriptDefinitions.d.ts
toast: ToastVariant, enums,
},
singularity: NetscriptSingularity(), singularity: NetscriptSingularity(),
gang: NetscriptGang(), gang: NetscriptGang(),
bladeburner: NetscriptBladeburner(), bladeburner: NetscriptBladeburner(),
@ -1782,12 +1790,12 @@ const base: InternalAPI<NS> = {
}, },
toast: toast:
(ctx: NetscriptContext) => (ctx: NetscriptContext) =>
(_message: unknown, _variant: unknown = ToastVariant.SUCCESS, _duration: unknown = 2000): void => { (_message: unknown, _variant: unknown = enums.toast.SUCCESS, _duration: unknown = 2000): void => {
const message = helpers.string(ctx, "message", _message); const message = helpers.string(ctx, "message", _message);
const variant = helpers.string(ctx, "variant", _variant); const variant = helpers.string(ctx, "variant", _variant);
const duration = _duration === null ? null : helpers.number(ctx, "duration", _duration); const duration = _duration === null ? null : helpers.number(ctx, "duration", _duration);
if (!checkEnum(ToastVariant, variant)) if (!checkObjContainsValue(enums.toast, variant))
throw new Error(`variant must be one of ${Object.values(ToastVariant).join(", ")}`); throw new Error(`variant must be one of ${Object.values(enums.toast).join(", ")}`);
SnackbarEvents.emit(message, variant, duration); SnackbarEvents.emit(message, variant, duration);
}, },
prompt: prompt:

@ -66,6 +66,7 @@ import { Factions } from "../Faction/Factions";
import { BitNodeMultipliers } from "../BitNode/BitNodeMultipliers"; import { BitNodeMultipliers } from "../BitNode/BitNodeMultipliers";
import { InternalAPI, NetscriptContext } from "../Netscript/APIWrapper"; import { InternalAPI, NetscriptContext } from "../Netscript/APIWrapper";
import { helpers } from "../Netscript/NetscriptHelpers"; import { helpers } from "../Netscript/NetscriptHelpers";
import { checkObjContainsValue } from "../utils/helpers/checkObjContains";
export function NetscriptCorporation(): InternalAPI<NSCorporation> { export function NetscriptCorporation(): InternalAPI<NSCorporation> {
function createCorporation(corporationName: string, selfFund = true): boolean { function createCorporation(corporationName: string, selfFund = true): boolean {
@ -711,7 +712,7 @@ export function NetscriptCorporation(): InternalAPI<NSCorporation> {
const employeeName = helpers.string(ctx, "employeeName", _employeeName); const employeeName = helpers.string(ctx, "employeeName", _employeeName);
const job = helpers.string(ctx, "job", _job); const job = helpers.string(ctx, "job", _job);
if (!Object.values(EmployeePositions).includes(job)) throw new Error(`'${job}' is not a valid job.`); if (!checkObjContainsValue(EmployeePositions, job)) throw new Error(`'${job}' is not a valid job.`);
const office = getOffice(divisionName, cityName); const office = getOffice(divisionName, cityName);
AssignJob(office, employeeName, job); AssignJob(office, employeeName, job);
@ -725,7 +726,7 @@ export function NetscriptCorporation(): InternalAPI<NSCorporation> {
const amount = helpers.number(ctx, "amount", _amount); const amount = helpers.number(ctx, "amount", _amount);
const job = helpers.string(ctx, "job", _job); const job = helpers.string(ctx, "job", _job);
if (!Object.values(EmployeePositions).includes(job)) throw new Error(`'${job}' is not a valid job.`); if (!checkObjContainsValue(EmployeePositions,job)) throw new Error(`'${job}' is not a valid job.`);
const office = getOffice(divisionName, cityName); const office = getOffice(divisionName, cityName);
return AutoAssignJob(office, job, amount); return AutoAssignJob(office, job, amount);

@ -14,7 +14,7 @@ import {
import { FactionNames } from "../Faction/data/FactionNames"; import { FactionNames } from "../Faction/data/FactionNames";
import { Factions } from "../Faction/Factions"; import { Factions } from "../Faction/Factions";
import { InternalAPI, NetscriptContext } from "../Netscript/APIWrapper"; import { InternalAPI, NetscriptContext } from "../Netscript/APIWrapper";
import { checkEnum } from "../utils/helpers/checkEnum"; import { checkObjContainsValue } from "../utils/helpers/checkObjContains";
import { LocationName } from "../Locations/data/LocationNames"; import { LocationName } from "../Locations/data/LocationNames";
import { helpers } from "../Netscript/NetscriptHelpers"; import { helpers } from "../Netscript/NetscriptHelpers";
@ -24,7 +24,7 @@ export function NetscriptInfiltration(): InternalAPI<IInfiltration> {
); );
const calculateInfiltrationData = (ctx: NetscriptContext, locationName: string): InfiltrationLocation => { const calculateInfiltrationData = (ctx: NetscriptContext, locationName: string): InfiltrationLocation => {
if (!checkEnum(LocationName, locationName)) throw new Error(`Location '${locationName}' does not exists.`); if (!checkObjContainsValue(LocationName, locationName)) throw new Error(`Location '${locationName}' does not exists.`);
const location = Locations[locationName]; const location = Locations[locationName];
if (location === undefined) throw helpers.makeRuntimeErrorMsg(ctx, `Location '${location}' does not exists.`); if (location === undefined) throw helpers.makeRuntimeErrorMsg(ctx, `Location '${location}' does not exists.`);
if (location.infiltrationData === undefined) if (location.infiltrationData === undefined)

@ -11,7 +11,7 @@ import {
SleeveSkills, SleeveSkills,
SleeveTask, SleeveTask,
} from "../ScriptEditor/NetscriptDefinitions"; } from "../ScriptEditor/NetscriptDefinitions";
import { checkEnum } from "../utils/helpers/checkEnum"; import { checkObjContainsValue } from "../utils/helpers/checkObjContains";
import { InternalAPI, NetscriptContext } from "../Netscript/APIWrapper"; import { InternalAPI, NetscriptContext } from "../Netscript/APIWrapper";
import { isSleeveBladeburnerWork } from "../PersonObjects/Sleeve/Work/SleeveBladeburnerWork"; import { isSleeveBladeburnerWork } from "../PersonObjects/Sleeve/Work/SleeveBladeburnerWork";
import { isSleeveFactionWork } from "../PersonObjects/Sleeve/Work/SleeveFactionWork"; import { isSleeveFactionWork } from "../PersonObjects/Sleeve/Work/SleeveFactionWork";
@ -102,7 +102,7 @@ export function NetscriptSleeve(): InternalAPI<ISleeve> {
const cityName = helpers.string(ctx, "cityName", _cityName); const cityName = helpers.string(ctx, "cityName", _cityName);
checkSleeveAPIAccess(ctx); checkSleeveAPIAccess(ctx);
checkSleeveNumber(ctx, sleeveNumber); checkSleeveNumber(ctx, sleeveNumber);
if (checkEnum(CityName, cityName)) { if (checkObjContainsValue(CityName, cityName)) {
return Player.sleeves[sleeveNumber].travel(cityName); return Player.sleeves[sleeveNumber].travel(cityName);
} else { } else {
throw helpers.makeRuntimeErrorMsg(ctx, `Invalid city name: '${cityName}'.`); throw helpers.makeRuntimeErrorMsg(ctx, `Invalid city name: '${cityName}'.`);

@ -6,7 +6,6 @@ import * as generalMethods from "./PlayerObjectGeneralMethods";
import * as serverMethods from "./PlayerObjectServerMethods"; import * as serverMethods from "./PlayerObjectServerMethods";
import * as workMethods from "./PlayerObjectWorkMethods"; import * as workMethods from "./PlayerObjectWorkMethods";
import { IMap } from "../../types";
import { Sleeve } from "../Sleeve/Sleeve"; import { Sleeve } from "../Sleeve/Sleeve";
import { PlayerOwnedSourceFile } from "../../SourceFile/PlayerOwnedSourceFile"; import { PlayerOwnedSourceFile } from "../../SourceFile/PlayerOwnedSourceFile";
import { Exploit } from "../../Exploits/Exploit"; import { Exploit } from "../../Exploits/Exploit";
@ -43,7 +42,7 @@ export class PlayerObject extends Person {
hashManager = new HashManager(); hashManager = new HashManager();
hasTixApiAccess = false; hasTixApiAccess = false;
hasWseAccount = false; hasWseAccount = false;
jobs: IMap<string> = {}; jobs: Record<string, string> = {};
karma = 0; karma = 0;
numPeopleKilled = 0; numPeopleKilled = 0;
location = LocationName.TravelAgency; location = LocationName.TravelAgency;

@ -39,7 +39,7 @@ import { numeralWrapper } from "../../ui/numeralFormat";
import { MoneySourceTracker } from "../../utils/MoneySourceTracker"; import { MoneySourceTracker } from "../../utils/MoneySourceTracker";
import { dialogBoxCreate } from "../../ui/React/DialogBox"; import { dialogBoxCreate } from "../../ui/React/DialogBox";
import { SnackbarEvents, ToastVariant } from "../../ui/React/Snackbar"; import { SnackbarEvents } from "../../ui/React/Snackbar";
import { achievements } from "../../Achievements/Achievements"; import { achievements } from "../../Achievements/Achievements";
import { FactionNames } from "../../Faction/data/FactionNames"; import { FactionNames } from "../../Faction/data/FactionNames";
@ -257,7 +257,7 @@ export function takeDamage(this: PlayerObject, amt: number): boolean {
export function hospitalize(this: PlayerObject): number { export function hospitalize(this: PlayerObject): number {
const cost = getHospitalizationCost(); const cost = getHospitalizationCost();
SnackbarEvents.emit(`You've been Hospitalized for ${numeralWrapper.formatMoney(cost)}`, ToastVariant.WARNING, 2000); SnackbarEvents.emit(`You've been Hospitalized for ${numeralWrapper.formatMoney(cost)}`, "warning", 2000);
this.loseMoney(cost, "hospitalization"); this.loseMoney(cost, "hospitalization");
this.hp.current = this.hp.max; this.hp.current = this.hp.max;
@ -1193,7 +1193,7 @@ export function canAccessGrafting(this: PlayerObject): boolean {
export function giveExploit(this: PlayerObject, exploit: Exploit): void { export function giveExploit(this: PlayerObject, exploit: Exploit): void {
if (!this.exploits.includes(exploit)) { if (!this.exploits.includes(exploit)) {
this.exploits.push(exploit); this.exploits.push(exploit);
SnackbarEvents.emit("SF -1 acquired!", ToastVariant.SUCCESS, 2000); SnackbarEvents.emit("SF -1 acquired!", "success", 2000);
} }
} }
@ -1202,7 +1202,7 @@ export function giveAchievement(this: PlayerObject, achievementId: string): void
if (!achievement) return; if (!achievement) return;
if (!this.achievements.map((a) => a.ID).includes(achievementId)) { if (!this.achievements.map((a) => a.ID).includes(achievementId)) {
this.achievements.push({ ID: achievementId, unlockedOn: new Date().getTime() }); this.achievements.push({ ID: achievementId, unlockedOn: new Date().getTime() });
SnackbarEvents.emit(`Unlocked Achievement: "${achievement.Name}"`, ToastVariant.SUCCESS, 2000); SnackbarEvents.emit(`Unlocked Achievement: "${achievement.Name}"`, "success", 2000);
} }
} }

@ -1,8 +1,7 @@
import { Program } from "./Program"; import { Program } from "./Program";
import { programsMetadata } from "./data/ProgramsMetadata"; import { programsMetadata } from "./data/ProgramsMetadata";
import { IMap } from "../types";
export const Programs: IMap<Program> = {}; export const Programs: Record<string, Program> = {};
export function initPrograms() { export function initPrograms() {
for (const params of programsMetadata) { for (const params of programsMetadata) {
Programs[params.key] = new Program(params.name, params.create, params.run); Programs[params.key] = new Program(params.name, params.create, params.run);

@ -1,6 +1,6 @@
import { RFAMessage } from "./MessageDefinitions"; import { RFAMessage } from "./MessageDefinitions";
import { RFARequestHandler } from "./MessageHandlers"; import { RFARequestHandler } from "./MessageHandlers";
import { SnackbarEvents, ToastVariant } from "../ui/React/Snackbar"; import { SnackbarEvents } from "../ui/React/Snackbar";
export class Remote { export class Remote {
connection?: WebSocket; connection?: WebSocket;
@ -22,18 +22,18 @@ export class Remote {
this.connection = new WebSocket(address); this.connection = new WebSocket(address);
this.connection.addEventListener("error", (e: Event) => this.connection.addEventListener("error", (e: Event) =>
SnackbarEvents.emit(`Error with websocket ${address}, details: ${JSON.stringify(e)}`, ToastVariant.ERROR, 5000), SnackbarEvents.emit(`Error with websocket ${address}, details: ${JSON.stringify(e)}`, "error", 5000),
); );
this.connection.addEventListener("message", handleMessageEvent); this.connection.addEventListener("message", handleMessageEvent);
this.connection.addEventListener("open", () => this.connection.addEventListener("open", () =>
SnackbarEvents.emit( SnackbarEvents.emit(
`Remote API connection established on ${this.ipaddr}:${this.port}`, `Remote API connection established on ${this.ipaddr}:${this.port}`,
ToastVariant.SUCCESS, "success",
2000, 2000,
), ),
); );
this.connection.addEventListener("close", () => this.connection.addEventListener("close", () =>
SnackbarEvents.emit("Remote API connection closed", ToastVariant.WARNING, 2000), SnackbarEvents.emit("Remote API connection closed", "warning", 2000),
); );
} }
} }

@ -16,7 +16,7 @@ import { Settings } from "./Settings/Settings";
import { loadStockMarket, StockMarket } from "./StockMarket/StockMarket"; import { loadStockMarket, StockMarket } from "./StockMarket/StockMarket";
import { staneksGift, loadStaneksGift } from "./CotMG/Helper"; import { staneksGift, loadStaneksGift } from "./CotMG/Helper";
import { SnackbarEvents, ToastVariant } from "./ui/React/Snackbar"; import { SnackbarEvents } from "./ui/React/Snackbar";
import * as ExportBonus from "./ExportBonus"; import * as ExportBonus from "./ExportBonus";
@ -120,7 +120,7 @@ class BitburnerSaveObject {
pushGameSaved(saveData); pushGameSaved(saveData);
if (emitToastEvent) { if (emitToastEvent) {
SnackbarEvents.emit("Game Saved!", ToastVariant.INFO, 2000); SnackbarEvents.emit("Game Saved!", "info", 2000);
} }
return resolve(); return resolve();
}) })
@ -707,13 +707,9 @@ function loadGame(saveString: string): boolean {
} }
if (saveObj.hasOwnProperty("SettingsSave")) { if (saveObj.hasOwnProperty("SettingsSave")) {
try { try {
// Try to set saved settings.
Settings.load(saveObj.SettingsSave); Settings.load(saveObj.SettingsSave);
} catch (e) { } catch (e) {}
console.error("ERROR: Failed to parse Settings. Re-initing default values");
Settings.init();
}
} else {
Settings.init();
} }
if (saveObj.hasOwnProperty("LastExportBonus")) { if (saveObj.hasOwnProperty("LastExportBonus")) {
try { try {

@ -5,7 +5,6 @@
import { Script } from "./Script"; import { Script } from "./Script";
import { ScriptUrl } from "./ScriptUrl"; import { ScriptUrl } from "./ScriptUrl";
import { Settings } from "../Settings/Settings"; import { Settings } from "../Settings/Settings";
import { IMap } from "../types";
import { Terminal } from "../Terminal"; import { Terminal } from "../Terminal";
import { Generic_fromJSON, Generic_toJSON, IReviverValue, Reviver } from "../utils/JSONReviver"; import { Generic_fromJSON, Generic_toJSON, IReviverValue, Reviver } from "../utils/JSONReviver";
@ -18,7 +17,7 @@ export class RunningScript {
// Map of [key: hostname] -> Hacking data. Used for offline progress calculations. // Map of [key: hostname] -> Hacking data. Used for offline progress calculations.
// Hacking data format: [MoneyStolen, NumTimesHacked, NumTimesGrown, NumTimesWeaken] // Hacking data format: [MoneyStolen, NumTimesHacked, NumTimesGrown, NumTimesWeaken]
dataMap: IMap<number[]> = {}; dataMap: Record<string, number[]> = {};
// Script filename // Script filename
filename = ""; filename = "";

@ -6573,22 +6573,16 @@ export interface NS {
enums: NSEnums; enums: NSEnums;
} }
/** @public */ export const enums = {
export enum ToastVariant { toast: {
SUCCESS = "success", SUCCESS: "success",
WARNING = "warning", WARNING: "warning",
ERROR = "error", ERROR: "error",
INFO = "info", INFO: "info",
} },
} as const;
/** @public */
export type ToastVariantValues = `${ToastVariant}`;
/** @public */
export interface NSEnums {
toast: typeof ToastVariant;
}
export type NSEnums = typeof enums;
/** /**
* Corporation Office API * Corporation Office API
* @remarks * @remarks

@ -4,7 +4,7 @@ import { serverMetadata } from "./data/servers";
import { HacknetServer } from "../Hacknet/HacknetServer"; import { HacknetServer } from "../Hacknet/HacknetServer";
import { IMap, IMinMaxRange } from "../types"; import { IMinMaxRange } from "../types";
import { createRandomIp } from "../utils/IPAddress"; import { createRandomIp } from "../utils/IPAddress";
import { getRandomInt } from "../utils/helpers/getRandomInt"; import { getRandomInt } from "../utils/helpers/getRandomInt";
import { Reviver } from "../utils/JSONReviver"; import { Reviver } from "../utils/JSONReviver";
@ -17,7 +17,7 @@ import { BitNodeMultipliers } from "../BitNode/BitNodeMultipliers";
* Key (string) = IP * Key (string) = IP
* Value = Server object * Value = Server object
*/ */
let AllServers: IMap<Server | HacknetServer> = {}; let AllServers: Record<string, Server | HacknetServer> = {};
function GetServerByIP(ip: string): BaseServer | undefined { function GetServerByIP(ip: string): BaseServer | undefined {
for (const key of Object.keys(AllServers)) { for (const key of Object.keys(AllServers)) {

@ -1,303 +1,98 @@
import { ISelfInitializer, ISelfLoading } from "../types";
import { OwnedAugmentationsOrderSetting, PurchaseAugmentationsOrderSetting } from "./SettingEnums"; import { OwnedAugmentationsOrderSetting, PurchaseAugmentationsOrderSetting } from "./SettingEnums";
import { defaultTheme, ITheme } from "../Themes/Themes"; import { defaultTheme } from "../Themes/Themes";
import { defaultStyles } from "../Themes/Styles"; import { defaultStyles } from "../Themes/Styles";
import { WordWrapOptions } from "../ScriptEditor/ui/Options"; import { WordWrapOptions } from "../ScriptEditor/ui/Options";
import { OverviewSettings } from "../ui/React/Overview"; import { defaultMonacoTheme } from "../ScriptEditor/ui/themes";
import { IStyleSettings } from "../ScriptEditor/NetscriptDefinitions";
import { defaultMonacoTheme, IScriptEditorTheme } from "../ScriptEditor/ui/themes";
/** /** The current options the player has customized to their play style. */
* Represents the default settings the player could customize. export const Settings = {
*/ /** How many servers per page */
interface IDefaultSettings {
/**
* How many servers per page
*/
ActiveScriptsServerPageSize: number;
/**
* How many scripts per page
*/
ActiveScriptsScriptPageSize: number;
/**
* How often the game should autosave the player's progress, in seconds.
*/
AutosaveInterval: number;
/**
* How many milliseconds between execution points for Netscript 1 statements.
*/
CodeInstructionRunTime: number;
/**
* Render city as list of buttons.
*/
DisableASCIIArt: boolean;
/**
* Whether global keyboard shortcuts should be recognized throughout the game.
*/
DisableHotkeys: boolean;
/**
* Whether text effects such as corruption should be visible.
*/
DisableTextEffects: boolean;
/**
* Whether overview progress bars should be visible.
*/
DisableOverviewProgressBars: boolean;
/**
* Enable bash hotkeys
*/
EnableBashHotkeys: boolean;
/**
* Timestamps format
*/
TimestampsFormat: string;
/**
* Locale used for display numbers
*/
Locale: string;
/**
* Limit the number of recently killed script entries being tracked.
*/
MaxRecentScriptsCapacity: number;
/**
* Limit the number of log entries for each script being executed on each server.
*/
MaxLogCapacity: number;
/**
* Limit how many entries can be written to a Netscript Port before entries start to get pushed out.
*/
MaxPortCapacity: number;
/**
* Limit the number of entries in the terminal.
*/
MaxTerminalCapacity: number;
/**
* Port the Remote File API client will try to connect to.
*/
RemoteFileApiPort: number;
/**
* Save the game when you save any file.
*/
SaveGameOnFileSave: boolean;
/**
* Whether the player should be asked to confirm purchasing each and every augmentation.
*/
SuppressBuyAugmentationConfirmation: boolean;
/**
* Whether the user should be prompted to join each faction via a dialog box.
*/
SuppressFactionInvites: boolean;
/**
* Whether the user should be shown a dialog box whenever they receive a new message file.
*/
SuppressMessages: boolean;
/**
* Whether the user should be asked to confirm travelling between cities.
*/
SuppressTravelConfirmation: boolean;
/**
* Whether the user should be displayed a popup message when his Bladeburner actions are cancelled.
*/
SuppressBladeburnerPopup: boolean;
/**
* Whether the user should be displayed a popup message on stock market actions.
*/
SuppressTIXPopup: boolean;
/**
* Whether the user should be displayed a toast alert when the game is saved.
*/
SuppressSavedGameToast: boolean;
/**
* Whether the user should be displayed a toast warning when the autosave is disabled.
*/
SuppressAutosaveDisabledWarnings: boolean;
/*
* Whether the game should skip saving the running scripts for late game
*/
ExcludeRunningScriptsFromSave: boolean;
/*
* Theme colors
*/
theme: ITheme;
/*
* Interface styles
*/
styles: IStyleSettings;
/*
* Use GiB instead of GB
*/
UseIEC60027_2: boolean;
/*
* Display intermediary time unit when their value is null
*/
ShowMiddleNullTimeUnit: boolean;
/*
* Character overview settings
*/
overview: OverviewSettings;
/**
* If the game's sidebar is opened
*/
IsSidebarOpened: boolean;
/**
* Script editor theme data
*/
EditorTheme: IScriptEditorTheme;
}
/**
* Represents all possible settings the player wants to customize to their play style.
*/
interface ISettings extends IDefaultSettings {
/**
* What order the player's owned Augmentations/Source Files should be displayed in
*/
OwnedAugmentationsOrder: OwnedAugmentationsOrderSetting;
/**
* What order the Augmentations should be displayed in when purchasing from a Faction
*/
PurchaseAugmentationsOrder: PurchaseAugmentationsOrderSetting;
MonacoTheme: string;
MonacoInsertSpaces: boolean;
MonacoFontSize: number;
MonacoVim: boolean;
MonacoWordWrap: WordWrapOptions;
}
export const defaultSettings: IDefaultSettings = {
ActiveScriptsServerPageSize: 10, ActiveScriptsServerPageSize: 10,
/** How many scripts per page */
ActiveScriptsScriptPageSize: 10, ActiveScriptsScriptPageSize: 10,
/** How often the game should autosave the player's progress, in seconds. */
AutosaveInterval: 60, AutosaveInterval: 60,
CodeInstructionRunTime: 50, /** How many milliseconds between execution points for Netscript 1 statements. */
DisableASCIIArt: false,
DisableHotkeys: false,
DisableTextEffects: false,
DisableOverviewProgressBars: false,
EnableBashHotkeys: false,
TimestampsFormat: "",
Locale: "en",
MaxRecentScriptsCapacity: 50,
MaxLogCapacity: 50,
MaxPortCapacity: 50,
MaxTerminalCapacity: 500,
RemoteFileApiPort: 0,
SaveGameOnFileSave: true,
SuppressBuyAugmentationConfirmation: false,
SuppressFactionInvites: false,
SuppressMessages: false,
SuppressTravelConfirmation: false,
SuppressBladeburnerPopup: false,
SuppressTIXPopup: false,
SuppressSavedGameToast: false,
SuppressAutosaveDisabledWarnings: false,
UseIEC60027_2: false,
ShowMiddleNullTimeUnit: false,
ExcludeRunningScriptsFromSave: false,
IsSidebarOpened: true,
theme: defaultTheme,
styles: defaultStyles,
overview: { x: 0, y: 0, opened: true },
EditorTheme: defaultMonacoTheme,
};
/**
* The current options the player has customized to their play style.
*/
// tslint:disable-next-line:variable-name
export const Settings: ISettings & ISelfInitializer & ISelfLoading = {
ActiveScriptsServerPageSize: defaultSettings.ActiveScriptsServerPageSize,
ActiveScriptsScriptPageSize: defaultSettings.ActiveScriptsScriptPageSize,
AutosaveInterval: defaultSettings.AutosaveInterval,
CodeInstructionRunTime: 25, CodeInstructionRunTime: 25,
DisableASCIIArt: defaultSettings.DisableASCIIArt, /** Whether to render city as list of buttons. */
DisableHotkeys: defaultSettings.DisableHotkeys, DisableASCIIArt: false,
DisableTextEffects: defaultSettings.DisableTextEffects, /** Whether global keyboard shortcuts should be disabled throughout the game. */
DisableOverviewProgressBars: defaultSettings.DisableOverviewProgressBars, DisableHotkeys: false,
EnableBashHotkeys: defaultSettings.EnableBashHotkeys, /** Whether text effects such as corruption should be disabled. */
TimestampsFormat: defaultSettings.TimestampsFormat, DisableTextEffects: false,
/** Whether overview progress bars should be visible. */
DisableOverviewProgressBars: false,
/** Whether to enable bash hotkeys */
EnableBashHotkeys: false,
/** Timestamps format string */
TimestampsFormat: "",
/** Locale used for display numbers. */
Locale: "en", Locale: "en",
MaxRecentScriptsCapacity: defaultSettings.MaxRecentScriptsCapacity, /** Limit the number of recently killed script entries being tracked. */
MaxLogCapacity: defaultSettings.MaxLogCapacity, MaxRecentScriptsCapacity: 50,
MaxPortCapacity: defaultSettings.MaxPortCapacity, /** Limit the number of log entries for each script being executed on each server. */
MaxTerminalCapacity: defaultSettings.MaxTerminalCapacity, MaxLogCapacity: 50,
/** Limit how many entries can be written to a Netscript Port before entries start to get pushed out. */
MaxPortCapacity: 50,
/** Limit the number of entries in the terminal. */
MaxTerminalCapacity: 500,
/** Port the Remote File API client will try to connect to. 0 to disable. */
RemoteFileApiPort: 0,
/** Whether to save the game when the player saves any file. */
SaveGameOnFileSave: true,
/** Whether to hide the confirmation dialog for augmentation purchases. */
SuppressBuyAugmentationConfirmation: false,
/** Whether to hide the dialog showing new faction invites. */
SuppressFactionInvites: false,
/** Whether to hide the dialog when the player receives a new message file. */
SuppressMessages: false,
/** Whether to hide the confirmation dialog when the player attempts to travel between cities. */
SuppressTravelConfirmation: false,
/** Whether to hide the dialog when the player's Bladeburner actions are cancelled. */
SuppressBladeburnerPopup: false,
/** Whether to hide dialogs for stock market actions. */
SuppressTIXPopup: false,
/** Whether to hide the toast alert when the game is saved. */
SuppressSavedGameToast: false,
/** Whether to hide the toast warning when the autosave is disabled. */
SuppressAutosaveDisabledWarnings: false,
/** Whether to GiB instead of GB. */
UseIEC60027_2: false,
/** Whether to display intermediary time unit when their value is null */
ShowMiddleNullTimeUnit: false,
/** Whether the game should skip saving the running scripts to the save file. */
ExcludeRunningScriptsFromSave: false,
/** Whether the game's sidebar is opened. */
IsSidebarOpened: true,
/** Theme colors. */
theme: {...defaultTheme},
/** Interface styles. */
styles: {...defaultStyles},
/** Character overview settings. */
overview: { x: 0, y: 0, opened: true },
/** Script editor theme data. */
EditorTheme: {...defaultMonacoTheme},
/** Order to display the player's owned Augmentations/Source Files. */
OwnedAugmentationsOrder: OwnedAugmentationsOrderSetting.AcquirementTime, OwnedAugmentationsOrder: OwnedAugmentationsOrderSetting.AcquirementTime,
/** What order the Augmentations should be displayed in when purchasing from a Faction. */
PurchaseAugmentationsOrder: PurchaseAugmentationsOrderSetting.Default, PurchaseAugmentationsOrder: PurchaseAugmentationsOrderSetting.Default,
RemoteFileApiPort: defaultSettings.RemoteFileApiPort, /** Script editor theme. */
SaveGameOnFileSave: defaultSettings.SaveGameOnFileSave,
SuppressBuyAugmentationConfirmation: defaultSettings.SuppressBuyAugmentationConfirmation,
SuppressFactionInvites: defaultSettings.SuppressFactionInvites,
SuppressMessages: defaultSettings.SuppressMessages,
SuppressTravelConfirmation: defaultSettings.SuppressTravelConfirmation,
SuppressBladeburnerPopup: defaultSettings.SuppressBladeburnerPopup,
SuppressTIXPopup: defaultSettings.SuppressTIXPopup,
SuppressSavedGameToast: defaultSettings.SuppressSavedGameToast,
SuppressAutosaveDisabledWarnings: defaultSettings.SuppressAutosaveDisabledWarnings,
UseIEC60027_2: defaultSettings.UseIEC60027_2,
ShowMiddleNullTimeUnit: defaultSettings.ShowMiddleNullTimeUnit,
ExcludeRunningScriptsFromSave: defaultSettings.ExcludeRunningScriptsFromSave,
IsSidebarOpened: defaultSettings.IsSidebarOpened,
MonacoTheme: "monokai", MonacoTheme: "monokai",
MonacoInsertSpaces: false, MonacoInsertSpaces: false,
/** Text size for script editor. */
MonacoFontSize: 20, MonacoFontSize: 20,
/** Whether to use Vim mod by default in the script editor */
MonacoVim: false, MonacoVim: false,
MonacoWordWrap: "off", /** Word wrap setting for Script Editor. */
MonacoWordWrap: "off" as WordWrapOptions,
theme: { ...defaultTheme },
styles: { ...defaultStyles },
overview: defaultSettings.overview,
EditorTheme: { ...defaultMonacoTheme },
init() {
Object.assign(Settings, defaultSettings);
},
load(saveString: string) { load(saveString: string) {
const save = JSON.parse(saveString); const save = JSON.parse(saveString);
Object.assign(Settings.theme, save.theme); save.theme && Object.assign(Settings.theme, save.theme);
delete save.theme; save.styles && Object.assign(Settings.styles, save.styles);
Object.assign(Settings.styles, save.styles); save.overview && Object.assign(Settings.overview, save.overview);
delete save.styles; save.EditorTheme && Object.assign(Settings.EditorTheme, save.EditorTheme);
Object.assign(Settings.overview, save.overview); delete save.theme, save.styles, save.overview, save.EditorTheme;
delete save.overview;
Object.assign(Settings.EditorTheme, save.EditorTheme);
delete save.EditorTheme;
Object.assign(Settings, save); Object.assign(Settings, save);
}, },
}; };

@ -1,9 +1,8 @@
import React from "react"; import React from "react";
import { SourceFile } from "./SourceFile"; import { SourceFile } from "./SourceFile";
import { IMap } from "../types";
import { initBitNodes, initBitNodeMultipliers } from "../BitNode/BitNode"; import { initBitNodes, initBitNodeMultipliers } from "../BitNode/BitNode";
export const SourceFiles: IMap<SourceFile> = {}; export const SourceFiles: Record<string, SourceFile> = {};
/** Engine initializer for SourceFiles, BitNodes, and BitNodeMultipliers. Run once at engine load. */ /** Engine initializer for SourceFiles, BitNodes, and BitNodeMultipliers. Run once at engine load. */
export function initSourceFiles() { export function initSourceFiles() {
initBitNodes(); initBitNodes();

@ -11,8 +11,6 @@ import { Stock } from "./Stock";
import { OrderTypes } from "./data/OrderTypes"; import { OrderTypes } from "./data/OrderTypes";
import { PositionTypes } from "./data/PositionTypes"; import { PositionTypes } from "./data/PositionTypes";
import { IMap } from "../types";
import { numeralWrapper } from "../ui/numeralFormat"; import { numeralWrapper } from "../ui/numeralFormat";
import { Money } from "../ui/React/Money"; import { Money } from "../ui/React/Money";
@ -23,7 +21,7 @@ import * as React from "react";
export interface IProcessOrderRefs { export interface IProcessOrderRefs {
stockMarket: IStockMarket; stockMarket: IStockMarket;
symbolToStockMap: IMap<Stock>; symbolToStockMap: Record<string, Stock>;
} }
/** /**

@ -10,8 +10,6 @@ import { PositionTypes } from "./data/PositionTypes";
import { StockSymbols } from "./data/StockSymbols"; import { StockSymbols } from "./data/StockSymbols";
import { CONSTANTS } from "../Constants"; import { CONSTANTS } from "../Constants";
import { IMap } from "../types";
import { numeralWrapper } from "../ui/numeralFormat"; import { numeralWrapper } from "../ui/numeralFormat";
import { dialogBoxCreate } from "../ui/React/DialogBox"; import { dialogBoxCreate } from "../ui/React/DialogBox";
@ -25,7 +23,7 @@ export let StockMarket: IStockMarket = {
storedCycles: 0, storedCycles: 0,
ticksUntilCycle: 0, ticksUntilCycle: 0,
} as IStockMarket; // Maps full stock name -> Stock object } as IStockMarket; // Maps full stock name -> Stock object
export const SymbolToStockMap: IMap<Stock> = {}; // Maps symbol -> Stock object export const SymbolToStockMap: Record<string, Stock> = {}; // Maps symbol -> Stock object
export function placeOrder( export function placeOrder(
stock: Stock, stock: Stock,
@ -172,7 +170,7 @@ export function initStockMarket(): void {
} }
export function initSymbolToStockMap(): void { export function initSymbolToStockMap(): void {
for (const name of Object.keys(StockSymbols)) { for (const name of Object.keys(StockSymbols) as Array<keyof typeof StockSymbols>) {
if (StockSymbols.hasOwnProperty(name)) { if (StockSymbols.hasOwnProperty(name)) {
const stock = StockMarket[name]; const stock = StockMarket[name];
if (stock == null) { if (stock == null) {

@ -1,41 +1,40 @@
import { IMap } from "../../types";
import { LocationName } from "../../Locations/data/LocationNames"; import { LocationName } from "../../Locations/data/LocationNames";
export const StockSymbols: IMap<string> = {}; export const StockSymbols = {
// Stocks for companies at which you can work
[LocationName.AevumECorp]: "ECP",
[LocationName.Sector12MegaCorp]: "MGCP",
[LocationName.Sector12BladeIndustries]: "BLD",
[LocationName.AevumClarkeIncorporated]: "CLRK",
[LocationName.VolhavenOmniTekIncorporated]: "OMTK",
[LocationName.Sector12FourSigma]: "FSIG",
[LocationName.ChongqingKuaiGongInternational]: "KGI",
[LocationName.AevumFulcrumTechnologies]: "FLCM",
[LocationName.IshimaStormTechnologies]: "STM",
[LocationName.NewTokyoDefComm]: "DCOMM",
[LocationName.VolhavenHeliosLabs]: "HLS",
[LocationName.NewTokyoVitaLife]: "VITA",
[LocationName.Sector12IcarusMicrosystems]: "ICRS",
[LocationName.Sector12UniversalEnergy]: "UNV",
[LocationName.AevumAeroCorp]: "AERO",
[LocationName.VolhavenOmniaCybersystems]: "OMN",
[LocationName.ChongqingSolarisSpaceSystems]: "SLRS",
[LocationName.NewTokyoGlobalPharmaceuticals]: "GPH",
[LocationName.IshimaNovaMedical]: "NVMD",
[LocationName.AevumWatchdogSecurity]: "WDS",
[LocationName.VolhavenLexoCorp]: "LXO",
[LocationName.AevumRhoConstruction]: "RHOC",
[LocationName.Sector12AlphaEnterprises]: "APHE",
[LocationName.VolhavenSysCoreSecurities]: "SYSC",
[LocationName.VolhavenCompuTek]: "CTK",
[LocationName.AevumNetLinkTechnologies]: "NTLK",
[LocationName.IshimaOmegaSoftware]: "OMGA",
[LocationName.Sector12FoodNStuff]: "FNS",
[LocationName.Sector12JoesGuns]: "JGN",
// Stocks for companies at which you can work // Stocks for other companies
StockSymbols[LocationName.AevumECorp] = "ECP"; ["Sigma Cosmetics"]: "SGC",
StockSymbols[LocationName.Sector12MegaCorp] = "MGCP"; ["Catalyst Ventures"]: "CTYS",
StockSymbols[LocationName.Sector12BladeIndustries] = "BLD"; ["Microdyne Technologies"]: "MDYN",
StockSymbols[LocationName.AevumClarkeIncorporated] = "CLRK"; ["Titan Laboratories"]: "TITN",
StockSymbols[LocationName.VolhavenOmniTekIncorporated] = "OMTK"; } as const;
StockSymbols[LocationName.Sector12FourSigma] = "FSIG";
StockSymbols[LocationName.ChongqingKuaiGongInternational] = "KGI";
StockSymbols[LocationName.AevumFulcrumTechnologies] = "FLCM";
StockSymbols[LocationName.IshimaStormTechnologies] = "STM";
StockSymbols[LocationName.NewTokyoDefComm] = "DCOMM";
StockSymbols[LocationName.VolhavenHeliosLabs] = "HLS";
StockSymbols[LocationName.NewTokyoVitaLife] = "VITA";
StockSymbols[LocationName.Sector12IcarusMicrosystems] = "ICRS";
StockSymbols[LocationName.Sector12UniversalEnergy] = "UNV";
StockSymbols[LocationName.AevumAeroCorp] = "AERO";
StockSymbols[LocationName.VolhavenOmniaCybersystems] = "OMN";
StockSymbols[LocationName.ChongqingSolarisSpaceSystems] = "SLRS";
StockSymbols[LocationName.NewTokyoGlobalPharmaceuticals] = "GPH";
StockSymbols[LocationName.IshimaNovaMedical] = "NVMD";
StockSymbols[LocationName.AevumWatchdogSecurity] = "WDS";
StockSymbols[LocationName.VolhavenLexoCorp] = "LXO";
StockSymbols[LocationName.AevumRhoConstruction] = "RHOC";
StockSymbols[LocationName.Sector12AlphaEnterprises] = "APHE";
StockSymbols[LocationName.VolhavenSysCoreSecurities] = "SYSC";
StockSymbols[LocationName.VolhavenCompuTek] = "CTK";
StockSymbols[LocationName.AevumNetLinkTechnologies] = "NTLK";
StockSymbols[LocationName.IshimaOmegaSoftware] = "OMGA";
StockSymbols[LocationName.Sector12FoodNStuff] = "FNS";
StockSymbols[LocationName.Sector12JoesGuns] = "JGN";
// Stocks for other companies
StockSymbols["Sigma Cosmetics"] = "SGC";
StockSymbols["Catalyst Ventures"] = "CTYS";
StockSymbols["Microdyne Technologies"] = "MDYN";
StockSymbols["Titan Laboratories"] = "TITN";

@ -5,7 +5,7 @@ export const TickerHeaderFormatData = {
longestSymbol: 0, longestSymbol: 0,
}; };
for (const key of Object.keys(StockSymbols)) { for (const key of Object.keys(StockSymbols) as Array<keyof typeof StockSymbols>) {
TickerHeaderFormatData.longestName = Math.max(key.length, TickerHeaderFormatData.longestName); TickerHeaderFormatData.longestName = Math.max(key.length, TickerHeaderFormatData.longestName);
TickerHeaderFormatData.longestSymbol = Math.max(StockSymbols[key].length, TickerHeaderFormatData.longestSymbol); TickerHeaderFormatData.longestSymbol = Math.max(StockSymbols[key].length, TickerHeaderFormatData.longestSymbol);
} }

@ -1,5 +1,4 @@
/* tslint:disable:max-line-length completed-docs variable-name*/ /* tslint:disable:max-line-length completed-docs variable-name*/
import { IMap } from "../types";
export const TerminalHelpText: string[] = [ export const TerminalHelpText: string[] = [
"Type 'help name' to learn more about the command ", "Type 'help name' to learn more about the command ",
@ -47,7 +46,7 @@ export const TerminalHelpText: string[] = [
" ", " ",
]; ];
const TemplatedHelpTexts: IMap<(command: string) => string[]> = { const TemplatedHelpTexts: Record<string, (command: string) => string[]> = {
scriptEditor: (command) => { scriptEditor: (command) => {
return [ return [
`Usage: ${command} [file ...] | [glob]`, `Usage: ${command} [file ...] | [glob]`,
@ -70,7 +69,7 @@ const TemplatedHelpTexts: IMap<(command: string) => string[]> = {
}, },
}; };
export const HelpTexts: IMap<string[]> = { export const HelpTexts: Record<string, string[]> = {
alias: [ alias: [
'Usage: alias [-g] [name="value"] ', 'Usage: alias [-g] [name="value"] ',
" ", " ",

@ -3,7 +3,7 @@ import { BaseServer } from "../../Server/BaseServer";
import { MessageFilenames, showMessage } from "../../Message/MessageHelpers"; import { MessageFilenames, showMessage } from "../../Message/MessageHelpers";
import { showLiterature } from "../../Literature/LiteratureHelpers"; import { showLiterature } from "../../Literature/LiteratureHelpers";
import { dialogBoxCreate } from "../../ui/React/DialogBox"; import { dialogBoxCreate } from "../../ui/React/DialogBox";
import { checkEnum } from "../../utils/helpers/checkEnum"; import { checkObjContainsValue } from "../../utils/helpers/checkObjContains";
export function cat(args: (string | number | boolean)[], server: BaseServer): void { export function cat(args: (string | number | boolean)[], server: BaseServer): void {
if (args.length !== 1) { if (args.length !== 1) {
@ -35,7 +35,7 @@ export function cat(args: (string | number | boolean)[], server: BaseServer): vo
} else if (filename.endsWith(".msg")) { } else if (filename.endsWith(".msg")) {
const file = server.messages[i]; const file = server.messages[i];
if (file !== filename) continue; if (file !== filename) continue;
if (!checkEnum(MessageFilenames, file)) return; if (!checkObjContainsValue(MessageFilenames, file)) return;
showMessage(file); showMessage(file);
return; return;
} }

@ -1,4 +1,3 @@
import { IMap } from "../types";
import * as predefined from "./data"; import * as predefined from "./data";
export interface ITheme { export interface ITheme {
@ -51,6 +50,6 @@ export const defaultTheme: ITheme = {
...predefined.Default.colors, ...predefined.Default.colors,
}; };
export const getPredefinedThemes = (): IMap<IPredefinedTheme> => ({ export const getPredefinedThemes = (): Record<string, IPredefinedTheme> => ({
...predefined, ...predefined,
}); });

@ -10,7 +10,7 @@ import { StyleEditorButton } from "./StyleEditorButton";
import { ThemeEntry } from "./ThemeEntry"; import { ThemeEntry } from "./ThemeEntry";
import { ThemeCollaborate } from "./ThemeCollaborate"; import { ThemeCollaborate } from "./ThemeCollaborate";
import { Modal } from "../../ui/React/Modal"; import { Modal } from "../../ui/React/Modal";
import { SnackbarEvents, ToastVariant } from "../../ui/React/Snackbar"; import { SnackbarEvents } from "../../ui/React/Snackbar";
// Everything dies when the theme gets reloaded, so we'll keep the current scroll to not jump around. // Everything dies when the theme gets reloaded, so we'll keep the current scroll to not jump around.
let previousScrollY = 0; let previousScrollY = 0;
@ -49,7 +49,7 @@ export function ThemeBrowser(): React.ReactElement {
UNDO UNDO
</Button> </Button>
</>, </>,
ToastVariant.INFO, "info",
30000, 30000,
); );
} }

@ -12,7 +12,7 @@ import PaletteSharpIcon from "@mui/icons-material/PaletteSharp";
import HistoryIcon from "@mui/icons-material/History"; import HistoryIcon from "@mui/icons-material/History";
import { Color, ColorPicker } from "material-ui-color"; import { Color, ColorPicker } from "material-ui-color";
import { ThemeEvents } from "./Theme"; import { ThemeEvents } from "./Theme";
import { Settings, defaultSettings } from "../../Settings/Settings"; import { Settings } from "../../Settings/Settings";
import { defaultTheme } from "../Themes"; import { defaultTheme } from "../Themes";
import { UserInterfaceTheme } from "../../ScriptEditor/NetscriptDefinitions"; import { UserInterfaceTheme } from "../../ScriptEditor/NetscriptDefinitions";
import { Router } from "../../ui/GameRoot"; import { Router } from "../../ui/GameRoot";
@ -150,19 +150,19 @@ export function ThemeEditorModal(props: IProps): React.ReactElement {
name="primarylight" name="primarylight"
onColorChange={onColorChange} onColorChange={onColorChange}
color={customTheme["primarylight"]} color={customTheme["primarylight"]}
defaultColor={defaultSettings.theme["primarylight"]} defaultColor={defaultTheme["primarylight"]}
/> />
<ColorEditor <ColorEditor
name="primary" name="primary"
onColorChange={onColorChange} onColorChange={onColorChange}
color={customTheme["primary"]} color={customTheme["primary"]}
defaultColor={defaultSettings.theme["primary"]} defaultColor={defaultTheme["primary"]}
/> />
<ColorEditor <ColorEditor
name="primarydark" name="primarydark"
onColorChange={onColorChange} onColorChange={onColorChange}
color={customTheme["primarydark"]} color={customTheme["primarydark"]}
defaultColor={defaultSettings.theme["primarydark"]} defaultColor={defaultTheme["primarydark"]}
/> />
<br /> <br />
@ -170,19 +170,19 @@ export function ThemeEditorModal(props: IProps): React.ReactElement {
name="successlight" name="successlight"
onColorChange={onColorChange} onColorChange={onColorChange}
color={customTheme["successlight"]} color={customTheme["successlight"]}
defaultColor={defaultSettings.theme["successlight"]} defaultColor={defaultTheme["successlight"]}
/> />
<ColorEditor <ColorEditor
name="success" name="success"
onColorChange={onColorChange} onColorChange={onColorChange}
color={customTheme["success"]} color={customTheme["success"]}
defaultColor={defaultSettings.theme["success"]} defaultColor={defaultTheme["success"]}
/> />
<ColorEditor <ColorEditor
name="successdark" name="successdark"
onColorChange={onColorChange} onColorChange={onColorChange}
color={customTheme["successdark"]} color={customTheme["successdark"]}
defaultColor={defaultSettings.theme["successdark"]} defaultColor={defaultTheme["successdark"]}
/> />
<br /> <br />
@ -190,19 +190,19 @@ export function ThemeEditorModal(props: IProps): React.ReactElement {
name="errorlight" name="errorlight"
onColorChange={onColorChange} onColorChange={onColorChange}
color={customTheme["errorlight"]} color={customTheme["errorlight"]}
defaultColor={defaultSettings.theme["errorlight"]} defaultColor={defaultTheme["errorlight"]}
/> />
<ColorEditor <ColorEditor
name="error" name="error"
onColorChange={onColorChange} onColorChange={onColorChange}
color={customTheme["error"]} color={customTheme["error"]}
defaultColor={defaultSettings.theme["error"]} defaultColor={defaultTheme["error"]}
/> />
<ColorEditor <ColorEditor
name="errordark" name="errordark"
onColorChange={onColorChange} onColorChange={onColorChange}
color={customTheme["errordark"]} color={customTheme["errordark"]}
defaultColor={defaultSettings.theme["errordark"]} defaultColor={defaultTheme["errordark"]}
/> />
<br /> <br />
@ -210,19 +210,19 @@ export function ThemeEditorModal(props: IProps): React.ReactElement {
name="secondarylight" name="secondarylight"
onColorChange={onColorChange} onColorChange={onColorChange}
color={customTheme["secondarylight"]} color={customTheme["secondarylight"]}
defaultColor={defaultSettings.theme["secondarylight"]} defaultColor={defaultTheme["secondarylight"]}
/> />
<ColorEditor <ColorEditor
name="secondary" name="secondary"
onColorChange={onColorChange} onColorChange={onColorChange}
color={customTheme["secondary"]} color={customTheme["secondary"]}
defaultColor={defaultSettings.theme["secondary"]} defaultColor={defaultTheme["secondary"]}
/> />
<ColorEditor <ColorEditor
name="secondarydark" name="secondarydark"
onColorChange={onColorChange} onColorChange={onColorChange}
color={customTheme["secondarydark"]} color={customTheme["secondarydark"]}
defaultColor={defaultSettings.theme["secondarydark"]} defaultColor={defaultTheme["secondarydark"]}
/> />
<br /> <br />
@ -230,19 +230,19 @@ export function ThemeEditorModal(props: IProps): React.ReactElement {
name="warninglight" name="warninglight"
onColorChange={onColorChange} onColorChange={onColorChange}
color={customTheme["warninglight"]} color={customTheme["warninglight"]}
defaultColor={defaultSettings.theme["warninglight"]} defaultColor={defaultTheme["warninglight"]}
/> />
<ColorEditor <ColorEditor
name="warning" name="warning"
onColorChange={onColorChange} onColorChange={onColorChange}
color={customTheme["warning"]} color={customTheme["warning"]}
defaultColor={defaultSettings.theme["warning"]} defaultColor={defaultTheme["warning"]}
/> />
<ColorEditor <ColorEditor
name="warningdark" name="warningdark"
onColorChange={onColorChange} onColorChange={onColorChange}
color={customTheme["warningdark"]} color={customTheme["warningdark"]}
defaultColor={defaultSettings.theme["warningdark"]} defaultColor={defaultTheme["warningdark"]}
/> />
<br /> <br />
@ -250,19 +250,19 @@ export function ThemeEditorModal(props: IProps): React.ReactElement {
name="infolight" name="infolight"
onColorChange={onColorChange} onColorChange={onColorChange}
color={customTheme["infolight"]} color={customTheme["infolight"]}
defaultColor={defaultSettings.theme["infolight"]} defaultColor={defaultTheme["infolight"]}
/> />
<ColorEditor <ColorEditor
name="info" name="info"
onColorChange={onColorChange} onColorChange={onColorChange}
color={customTheme["info"]} color={customTheme["info"]}
defaultColor={defaultSettings.theme["info"]} defaultColor={defaultTheme["info"]}
/> />
<ColorEditor <ColorEditor
name="infodark" name="infodark"
onColorChange={onColorChange} onColorChange={onColorChange}
color={customTheme["infodark"]} color={customTheme["infodark"]}
defaultColor={defaultSettings.theme["infodark"]} defaultColor={defaultTheme["infodark"]}
/> />
<br /> <br />
@ -270,43 +270,43 @@ export function ThemeEditorModal(props: IProps): React.ReactElement {
name="welllight" name="welllight"
onColorChange={onColorChange} onColorChange={onColorChange}
color={customTheme["welllight"]} color={customTheme["welllight"]}
defaultColor={defaultSettings.theme["welllight"]} defaultColor={defaultTheme["welllight"]}
/> />
<ColorEditor <ColorEditor
name="well" name="well"
onColorChange={onColorChange} onColorChange={onColorChange}
color={customTheme["well"]} color={customTheme["well"]}
defaultColor={defaultSettings.theme["well"]} defaultColor={defaultTheme["well"]}
/> />
<ColorEditor <ColorEditor
name="white" name="white"
onColorChange={onColorChange} onColorChange={onColorChange}
color={customTheme["white"]} color={customTheme["white"]}
defaultColor={defaultSettings.theme["white"]} defaultColor={defaultTheme["white"]}
/> />
<ColorEditor <ColorEditor
name="black" name="black"
onColorChange={onColorChange} onColorChange={onColorChange}
color={customTheme["black"]} color={customTheme["black"]}
defaultColor={defaultSettings.theme["black"]} defaultColor={defaultTheme["black"]}
/> />
<ColorEditor <ColorEditor
name="backgroundprimary" name="backgroundprimary"
onColorChange={onColorChange} onColorChange={onColorChange}
color={customTheme["backgroundprimary"]} color={customTheme["backgroundprimary"]}
defaultColor={defaultSettings.theme["backgroundprimary"]} defaultColor={defaultTheme["backgroundprimary"]}
/> />
<ColorEditor <ColorEditor
name="backgroundsecondary" name="backgroundsecondary"
onColorChange={onColorChange} onColorChange={onColorChange}
color={customTheme["backgroundsecondary"]} color={customTheme["backgroundsecondary"]}
defaultColor={defaultSettings.theme["backgroundsecondary"]} defaultColor={defaultTheme["backgroundsecondary"]}
/> />
<ColorEditor <ColorEditor
name="button" name="button"
onColorChange={onColorChange} onColorChange={onColorChange}
color={customTheme["button"]} color={customTheme["button"]}
defaultColor={defaultSettings.theme["button"]} defaultColor={defaultTheme["button"]}
/> />
<br /> <br />
@ -314,49 +314,49 @@ export function ThemeEditorModal(props: IProps): React.ReactElement {
name="hp" name="hp"
onColorChange={onColorChange} onColorChange={onColorChange}
color={customTheme["hp"]} color={customTheme["hp"]}
defaultColor={defaultSettings.theme["hp"]} defaultColor={defaultTheme["hp"]}
/> />
<ColorEditor <ColorEditor
name="money" name="money"
onColorChange={onColorChange} onColorChange={onColorChange}
color={customTheme["money"]} color={customTheme["money"]}
defaultColor={defaultSettings.theme["money"]} defaultColor={defaultTheme["money"]}
/> />
<ColorEditor <ColorEditor
name="hack" name="hack"
onColorChange={onColorChange} onColorChange={onColorChange}
color={customTheme["hack"]} color={customTheme["hack"]}
defaultColor={defaultSettings.theme["hack"]} defaultColor={defaultTheme["hack"]}
/> />
<ColorEditor <ColorEditor
name="combat" name="combat"
onColorChange={onColorChange} onColorChange={onColorChange}
color={customTheme["combat"]} color={customTheme["combat"]}
defaultColor={defaultSettings.theme["combat"]} defaultColor={defaultTheme["combat"]}
/> />
<ColorEditor <ColorEditor
name="cha" name="cha"
onColorChange={onColorChange} onColorChange={onColorChange}
color={customTheme["cha"]} color={customTheme["cha"]}
defaultColor={defaultSettings.theme["cha"]} defaultColor={defaultTheme["cha"]}
/> />
<ColorEditor <ColorEditor
name="int" name="int"
onColorChange={onColorChange} onColorChange={onColorChange}
color={customTheme["int"]} color={customTheme["int"]}
defaultColor={defaultSettings.theme["int"]} defaultColor={defaultTheme["int"]}
/> />
<ColorEditor <ColorEditor
name="rep" name="rep"
onColorChange={onColorChange} onColorChange={onColorChange}
color={customTheme["rep"]} color={customTheme["rep"]}
defaultColor={defaultSettings.theme["rep"]} defaultColor={defaultTheme["rep"]}
/> />
<ColorEditor <ColorEditor
name="disabled" name="disabled"
onColorChange={onColorChange} onColorChange={onColorChange}
color={customTheme["disabled"]} color={customTheme["disabled"]}
defaultColor={defaultSettings.theme["disabled"]} defaultColor={defaultTheme["disabled"]}
/> />
</Paper> </Paper>

@ -46,7 +46,7 @@ import { calculateAchievements } from "./Achievements/Achievements";
import React from "react"; import React from "react";
import { setupUncaughtPromiseHandler } from "./UncaughtPromiseHandler"; import { setupUncaughtPromiseHandler } from "./UncaughtPromiseHandler";
import { Button, Typography } from "@mui/material"; import { Button, Typography } from "@mui/material";
import { SnackbarEvents, ToastVariant } from "./ui/React/Snackbar"; import { SnackbarEvents } from "./ui/React/Snackbar";
const Engine: { const Engine: {
_lastUpdate: number; _lastUpdate: number;
@ -431,7 +431,7 @@ function warnAutosaveDisabled(): void {
</Button> </Button>
</> </>
); );
SnackbarEvents.emit(warningToast, ToastVariant.WARNING, 5000); SnackbarEvents.emit(warningToast, "warning", 5000);
} }
export { Engine }; export { Engine };

@ -1,35 +1,8 @@
/** /** Construct a type using the values from an object. Requires object to be defined "as const" */
* Performs an equality check between two instances of the same type. export type ValuesFrom<T> = T[keyof T];
*/
export type EqualityFunc<T> = (a: T, b: T) => boolean;
/** /** Only allowed to be true if the types are equal. */
* A map is an object that holds a mapping between string keys and some consistent type. export type TypeEquality<T1, T2> = [T1] extends [T2] ? ([T2] extends [T1] ? true : false) : false;
*/
export interface IMap<T> {
[key: string]: T;
}
/**
* Contains a method to initialize itself to a known state.
*/
export interface ISelfInitializer {
/**
* Initialize/reset the object to a known, default state.
*/
init(): void;
}
/**
* Contains a method to repopulate itself based on a JSON string.
*/
export interface ISelfLoading {
/**
* Loads the save state onto the current object.
* @param saveState JSON string representing the save state.
*/
load(saveState: string): void;
}
/** /**
* Status object for functions that return a boolean indicating success/failure * Status object for functions that return a boolean indicating success/failure

@ -2,7 +2,7 @@ import React, { useEffect } from "react";
import { useSnackbar, SnackbarProvider as SB } from "notistack"; import { useSnackbar, SnackbarProvider as SB } from "notistack";
import makeStyles from "@mui/styles/makeStyles"; import makeStyles from "@mui/styles/makeStyles";
import { EventEmitter } from "../../utils/EventEmitter"; import { EventEmitter } from "../../utils/EventEmitter";
import Alert from "@mui/material/Alert"; import Alert, { AlertColor } from "@mui/material/Alert";
import Paper from "@mui/material/Paper"; import Paper from "@mui/material/Paper";
import { logBoxBaseZIndex } from "./LogBoxManager"; import { logBoxBaseZIndex } from "./LogBoxManager";
@ -10,12 +10,7 @@ interface IProps {
children: React.ReactNode | React.ReactNode[]; children: React.ReactNode | React.ReactNode[];
} }
export enum ToastVariant { export type ToastVariant = AlertColor;
SUCCESS = "success",
WARNING = "warning",
ERROR = "error",
INFO = "info",
}
const useStyles = makeStyles(() => ({ const useStyles = makeStyles(() => ({
snackbar: { snackbar: {

@ -1,5 +1,4 @@
import { Settings } from "../Settings/Settings"; import { Settings } from "../Settings/Settings";
import { EqualityFunc } from "../types";
import { isString } from "./helpers/isString"; import { isString } from "./helpers/isString";
/* /*
@ -65,7 +64,7 @@ function longestCommonStart(strings: string[]): string {
const a2: string = A[A.length - 1]; const a2: string = A[A.length - 1];
const L: number = a1.length; const L: number = a1.length;
let i = 0; let i = 0;
const areEqualCaseInsensitive: EqualityFunc<string> = (a: string, b: string) => a.toUpperCase() === b.toUpperCase(); const areEqualCaseInsensitive = (a: string, b: string) => a.toUpperCase() === b.toUpperCase();
while (i < L && areEqualCaseInsensitive(a1.charAt(i), a2.charAt(i))) { while (i < L && areEqualCaseInsensitive(a1.charAt(i), a2.charAt(i))) {
i++; i++;
} }

@ -1,6 +0,0 @@
export function checkEnum<T extends string, TEnumValue extends string>(
enumVariable: { [key in T]: TEnumValue },
value: string,
): value is TEnumValue {
return Object.values(enumVariable).includes(value);
}

@ -0,0 +1,7 @@
// This works for both enums and regular objects.
export function checkObjContainsValue<T extends Record<string, string>>(
obj: T,
value: string,
): value is T[keyof T] {
return Object.values(obj).includes(value);
}

@ -1,6 +1,5 @@
import { CONSTANTS } from "../../src/Constants"; import { CONSTANTS } from "../../src/Constants";
import { Player } from "../../src/Player"; import { Player } from "../../src/Player";
import { IMap } from "../../src/types";
import { Company } from "../../src/Company/Company"; import { Company } from "../../src/Company/Company";
import { Server } from "../../src/Server/Server"; import { Server } from "../../src/Server/Server";
@ -457,7 +456,7 @@ describe("Stock Market Tests", function () {
it("should trigger a price update when it has enough cycles", function () { it("should trigger a price update when it has enough cycles", function () {
// Get the initial prices // Get the initial prices
const initialValues: IMap<any> = {}; const initialValues: Record<string, any> = {};
for (const stockName in StockMarket) { for (const stockName in StockMarket) {
const stock = StockMarket[stockName]; const stock = StockMarket[stockName];
if (!(stock instanceof Stock)) { if (!(stock instanceof Stock)) {