Merge branch 'dev' of github.com:danielyxie/bitburner into fix/nfg-level-application

This commit is contained in:
nickofolas 2022-05-05 08:34:26 -05:00
commit 6d9dcfe81f
24 changed files with 878 additions and 830 deletions

4
dist/main.bundle.js vendored

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

42
dist/vendor.bundle.js vendored

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

@ -24,6 +24,7 @@ import { IMap } from "../types";
import * as data from "./AchievementData.json";
import { FactionNames } from "../Faction/data/FactionNames";
import { BlackOperationNames } from "../Bladeburner/data/BlackOperationNames";
import { ClassType } from "../utils/WorkType";
// Unable to correctly cast the JSON data into AchievementDataJson type otherwise...
const achievementData = (<AchievementDataJson>(<unknown>data)).achievements;
@ -391,12 +392,9 @@ export const achievements: IMap<Achievement> = {
...achievementData["WORKOUT"],
Icon: "WORKOUT",
Condition: () =>
[
CONSTANTS.ClassGymStrength,
CONSTANTS.ClassGymDefense,
CONSTANTS.ClassGymDexterity,
CONSTANTS.ClassGymAgility,
].includes(Player.className),
[ClassType.GymStrength, ClassType.GymDefense, ClassType.GymDexterity, ClassType.GymAgility].includes(
Player.className,
),
},
TOR: {
...achievementData["TOR"],

@ -63,26 +63,6 @@ export const CONSTANTS: {
GameCyclesPerQuarterHour: number;
MillisecondsPerFiveMinutes: number;
GameCyclesPerFiveMinutes: number;
FactionWorkHacking: string;
FactionWorkField: string;
FactionWorkSecurity: string;
WorkTypeCompany: string;
WorkTypeCompanyPartTime: string;
WorkTypeFaction: string;
WorkTypeCreateProgram: string;
WorkTypeStudyClass: string;
WorkTypeCrime: string;
WorkTypeGraftAugmentation: string;
ClassStudyComputerScience: string;
ClassDataStructures: string;
ClassNetworks: string;
ClassAlgorithms: string;
ClassManagement: string;
ClassLeadership: string;
ClassGymStrength: string;
ClassGymDefense: string;
ClassGymDexterity: string;
ClassGymAgility: string;
ClassDataStructuresBaseCost: number;
ClassNetworksBaseCost: number;
ClassAlgorithmsBaseCost: number;
@ -95,18 +75,6 @@ export const CONSTANTS: {
ClassAlgorithmsBaseExp: number;
ClassManagementBaseExp: number;
ClassLeadershipBaseExp: number;
CrimeShoplift: string;
CrimeRobStore: string;
CrimeMug: string;
CrimeLarceny: string;
CrimeDrugs: string;
CrimeBondForgery: string;
CrimeTraffickArms: string;
CrimeHomicide: string;
CrimeGrandTheftAuto: string;
CrimeKidnap: string;
CrimeAssassination: string;
CrimeHeist: string;
CodingContractBaseFactionRepGain: number;
CodingContractBaseCompanyRepGain: number;
CodingContractBaseMoneyGain: number;
@ -223,28 +191,6 @@ export const CONSTANTS: {
// Player Work & Action
BaseFocusBonus: 0.8,
FactionWorkHacking: "Faction Hacking Work",
FactionWorkField: "Faction Field Work",
FactionWorkSecurity: "Faction Security Work",
WorkTypeCompany: "Working for Company",
WorkTypeCompanyPartTime: "Working for Company part-time",
WorkTypeFaction: "Working for Faction",
WorkTypeCreateProgram: "Working on Create a Program",
WorkTypeStudyClass: "Studying or Taking a class at university",
WorkTypeCrime: "Committing a crime",
WorkTypeGraftAugmentation: "Grafting an Augmentation",
ClassStudyComputerScience: "studying Computer Science",
ClassDataStructures: "taking a Data Structures course",
ClassNetworks: "taking a Networks course",
ClassAlgorithms: "taking an Algorithms course",
ClassManagement: "taking a Management course",
ClassLeadership: "taking a Leadership course",
ClassGymStrength: "training your strength at a gym",
ClassGymDefense: "training your defense at a gym",
ClassGymDexterity: "training your dexterity at a gym",
ClassGymAgility: "training your agility at a gym",
ClassDataStructuresBaseCost: 40,
ClassNetworksBaseCost: 80,
@ -260,19 +206,6 @@ export const CONSTANTS: {
ClassManagementBaseExp: 2,
ClassLeadershipBaseExp: 4,
CrimeShoplift: "shoplift",
CrimeRobStore: "rob a store",
CrimeMug: "mug someone",
CrimeLarceny: "commit larceny",
CrimeDrugs: "deal drugs",
CrimeBondForgery: "forge corporate bonds",
CrimeTraffickArms: "traffick illegal arms",
CrimeHomicide: "commit homicide",
CrimeGrandTheftAuto: "commit grand theft auto",
CrimeKidnap: "kidnap someone for ransom",
CrimeAssassination: "assassinate a high-profile target",
CrimeHeist: "pull off the ultimate heist",
// Coding Contract
// TODO: Move this into Coding contract implementation?
CodingContractBaseFactionRepGain: 2500,

@ -3,6 +3,7 @@ import { IPlayer } from "../PersonObjects/IPlayer";
import { IPlayerOrSleeve } from "../PersonObjects/IPlayerOrSleeve";
import { IRouter } from "../ui/Router";
import { WorkerScript } from "../Netscript/WorkerScript";
import { CrimeType } from "../utils/WorkType";
interface IConstructorParams {
hacking_success_weight?: number;
@ -42,7 +43,7 @@ export class Crime {
time = 0;
// Corresponding type in CONSTANTS. Contains a description for the crime activity
type = "";
type: CrimeType;
// Weighting factors that determine how stats affect the success rate of this crime
hacking_success_weight = 0;
@ -61,7 +62,15 @@ export class Crime {
charisma_exp = 0;
intelligence_exp = 0;
constructor(name = "", type = "", time = 0, money = 0, difficulty = 0, karma = 0, params: IConstructorParams = {}) {
constructor(
name = "",
type: CrimeType,
time = 0,
money = 0,
difficulty = 0,
karma = 0,
params: IConstructorParams = {},
) {
this.name = name;
this.type = type;
this.time = time;

@ -9,7 +9,7 @@ export function determineCrimeSuccess(p: IPlayer, type: string): boolean {
let found = false;
for (const i of Object.keys(Crimes)) {
const crime = Crimes[i];
if (crime.type == type) {
if (crime.type === type) {
chance = crime.successRate(p);
found = true;
break;

@ -3,8 +3,10 @@ import { Crime } from "./Crime";
import { CONSTANTS } from "../Constants";
import { IMap } from "../types";
import { CrimeType } from "../utils/WorkType";
export const Crimes: IMap<Crime> = {
Shoplift: new Crime("Shoplift", CONSTANTS.CrimeShoplift, 2e3, 15e3, 1 / 20, 0.1, {
Shoplift: new Crime("Shoplift", CrimeType.Shoplift, 2e3, 15e3, 1 / 20, 0.1, {
dexterity_success_weight: 1,
agility_success_weight: 1,
@ -12,7 +14,7 @@ export const Crimes: IMap<Crime> = {
agility_exp: 2,
}),
RobStore: new Crime("Rob Store", CONSTANTS.CrimeRobStore, 60e3, 400e3, 1 / 5, 0.5, {
RobStore: new Crime("Rob Store", CrimeType.RobStore, 60e3, 400e3, 1 / 5, 0.5, {
hacking_exp: 30,
dexterity_exp: 45,
agility_exp: 45,
@ -24,7 +26,7 @@ export const Crimes: IMap<Crime> = {
intelligence_exp: 7.5 * CONSTANTS.IntelligenceCrimeBaseExpGain,
}),
Mug: new Crime("Mug", CONSTANTS.CrimeMug, 4e3, 36e3, 1 / 5, 0.25, {
Mug: new Crime("Mug", CrimeType.Mug, 4e3, 36e3, 1 / 5, 0.25, {
strength_exp: 3,
defense_exp: 3,
dexterity_exp: 3,
@ -36,7 +38,7 @@ export const Crimes: IMap<Crime> = {
agility_success_weight: 0.5,
}),
Larceny: new Crime("Larceny", CONSTANTS.CrimeLarceny, 90e3, 800e3, 1 / 3, 1.5, {
Larceny: new Crime("Larceny", CrimeType.Larceny, 90e3, 800e3, 1 / 3, 1.5, {
hacking_exp: 45,
dexterity_exp: 60,
agility_exp: 60,
@ -48,7 +50,7 @@ export const Crimes: IMap<Crime> = {
intelligence_exp: 15 * CONSTANTS.IntelligenceCrimeBaseExpGain,
}),
DealDrugs: new Crime("Deal Drugs", CONSTANTS.CrimeDrugs, 10e3, 120e3, 1, 0.5, {
DealDrugs: new Crime("Deal Drugs", CrimeType.Drugs, 10e3, 120e3, 1, 0.5, {
dexterity_exp: 5,
agility_exp: 5,
charisma_exp: 10,
@ -58,7 +60,7 @@ export const Crimes: IMap<Crime> = {
agility_success_weight: 1,
}),
BondForgery: new Crime("Bond Forgery", CONSTANTS.CrimeBondForgery, 300e3, 4.5e6, 1 / 2, 0.1, {
BondForgery: new Crime("Bond Forgery", CrimeType.BondForgery, 300e3, 4.5e6, 1 / 2, 0.1, {
hacking_exp: 100,
dexterity_exp: 150,
charisma_exp: 15,
@ -69,7 +71,7 @@ export const Crimes: IMap<Crime> = {
intelligence_exp: 60 * CONSTANTS.IntelligenceCrimeBaseExpGain,
}),
TraffickArms: new Crime("Traffick Arms", CONSTANTS.CrimeTraffickArms, 40e3, 600e3, 2, 1, {
TraffickArms: new Crime("Traffick Arms", CrimeType.TraffickArms, 40e3, 600e3, 2, 1, {
strength_exp: 20,
defense_exp: 20,
dexterity_exp: 20,
@ -83,7 +85,7 @@ export const Crimes: IMap<Crime> = {
agility_success_weight: 1,
}),
Homicide: new Crime("Homicide", CONSTANTS.CrimeHomicide, 3e3, 45e3, 1, 3, {
Homicide: new Crime("Homicide", CrimeType.Homicide, 3e3, 45e3, 1, 3, {
strength_exp: 2,
defense_exp: 2,
dexterity_exp: 2,
@ -97,7 +99,7 @@ export const Crimes: IMap<Crime> = {
kills: 1,
}),
GrandTheftAuto: new Crime("Grand Theft Auto", CONSTANTS.CrimeGrandTheftAuto, 80e3, 1.6e6, 8, 5, {
GrandTheftAuto: new Crime("Grand Theft Auto", CrimeType.GrandTheftAuto, 80e3, 1.6e6, 8, 5, {
strength_exp: 20,
defense_exp: 20,
dexterity_exp: 20,
@ -113,7 +115,7 @@ export const Crimes: IMap<Crime> = {
intelligence_exp: 16 * CONSTANTS.IntelligenceCrimeBaseExpGain,
}),
Kidnap: new Crime("Kidnap", CONSTANTS.CrimeKidnap, 120e3, 3.6e6, 5, 6, {
Kidnap: new Crime("Kidnap", CrimeType.Kidnap, 120e3, 3.6e6, 5, 6, {
strength_exp: 80,
defense_exp: 80,
dexterity_exp: 80,
@ -128,7 +130,7 @@ export const Crimes: IMap<Crime> = {
intelligence_exp: 26 * CONSTANTS.IntelligenceCrimeBaseExpGain,
}),
Assassination: new Crime("Assassination", CONSTANTS.CrimeAssassination, 300e3, 12e6, 8, 10, {
Assassination: new Crime("Assassination", CrimeType.Assassination, 300e3, 12e6, 8, 10, {
strength_exp: 300,
defense_exp: 300,
dexterity_exp: 300,
@ -143,7 +145,7 @@ export const Crimes: IMap<Crime> = {
kills: 1,
}),
Heist: new Crime("Heist", CONSTANTS.CrimeHeist, 600e3, 120e6, 18, 15, {
Heist: new Crime("Heist", CrimeType.Heist, 600e3, 120e6, 18, 15, {
hacking_exp: 450,
strength_exp: 450,
defense_exp: 450,

@ -1,19 +1,8 @@
import { LinearProgress, Paper } from "@mui/material";
import { Theme } from "@mui/material/styles";
import withStyles from "@mui/styles/withStyles";
import { Paper } from "@mui/material";
import React, { useEffect, useState } from "react";
import { AugmentationNames } from "../../Augmentation/data/AugmentationNames";
import { use } from "../../ui/Context";
const TimerProgress = withStyles((theme: Theme) => ({
root: {
backgroundColor: theme.palette.background.paper,
},
bar: {
transition: "none",
backgroundColor: theme.palette.primary.main,
},
}))(LinearProgress);
import { ProgressBar } from "../../ui/React/Progress";
interface IProps {
millis: number;
@ -43,10 +32,10 @@ export function GameTimer(props: IProps): React.ReactElement {
// TODO(hydroflame): there's like a bug where it triggers the end before the
// bar physically reaches the end
return props.noPaper ? (
<TimerProgress variant="determinate" value={v} color="primary" />
<ProgressBar variant="determinate" value={v} color="primary" />
) : (
<Paper sx={{ p: 1, mb: 1 }}>
<TimerProgress variant="determinate" value={v} color="primary" />
<ProgressBar variant="determinate" value={v} color="primary" />
</Paper>
);
}

@ -17,6 +17,7 @@ import { Money } from "../../ui/React/Money";
import { IRouter } from "../../ui/Router";
import { serverMetadata } from "../../Server/data/servers";
import { Box } from "@mui/material";
import { ClassType } from "../../utils/WorkType";
type IProps = {
loc: Location;
@ -33,7 +34,7 @@ export function GymLocation(props: IProps): React.ReactElement {
return props.loc.costMult * discount;
}
function train(stat: string): void {
function train(stat: ClassType): void {
const loc = props.loc;
props.p.startClass(calculateCost(), loc.expMult, stat);
props.p.startFocusing();
@ -41,19 +42,19 @@ export function GymLocation(props: IProps): React.ReactElement {
}
function trainStrength(): void {
train(CONSTANTS.ClassGymStrength);
train(ClassType.GymStrength);
}
function trainDefense(): void {
train(CONSTANTS.ClassGymDefense);
train(ClassType.GymDefense);
}
function trainDexterity(): void {
train(CONSTANTS.ClassGymDexterity);
train(ClassType.GymDexterity);
}
function trainAgility(): void {
train(CONSTANTS.ClassGymAgility);
train(ClassType.GymAgility);
}
const cost = CONSTANTS.ClassGymBaseCost * calculateCost();

@ -17,6 +17,8 @@ import { Money } from "../../ui/React/Money";
import { use } from "../../ui/Context";
import { Box } from "@mui/material";
import { ClassType } from "../../utils/WorkType";
type IProps = {
loc: Location;
};
@ -32,7 +34,7 @@ export function UniversityLocation(props: IProps): React.ReactElement {
return props.loc.costMult * discount;
}
function take(stat: string): void {
function take(stat: ClassType): void {
const loc = props.loc;
player.startClass(calculateCost(), loc.expMult, stat);
player.startFocusing();
@ -40,27 +42,27 @@ export function UniversityLocation(props: IProps): React.ReactElement {
}
function study(): void {
take(CONSTANTS.ClassStudyComputerScience);
take(ClassType.StudyComputerScience);
}
function dataStructures(): void {
take(CONSTANTS.ClassDataStructures);
take(ClassType.DataStructures);
}
function networks(): void {
take(CONSTANTS.ClassNetworks);
take(ClassType.Networks);
}
function algorithms(): void {
take(CONSTANTS.ClassAlgorithms);
take(ClassType.Algorithms);
}
function management(): void {
take(CONSTANTS.ClassManagement);
take(ClassType.Management);
}
function leadership(): void {
take(CONSTANTS.ClassLeadership);
take(ClassType.Leadership);
}
const costMult: number = calculateCost();

@ -49,6 +49,7 @@ import { InternalAPI, NetscriptContext } from "src/Netscript/APIWrapper";
import { BlackOperationNames } from "../Bladeburner/data/BlackOperationNames";
import { enterBitNode } from "../RedPill";
import { FactionNames } from "../Faction/data/FactionNames";
import { ClassType, WorkType } from "../utils/WorkType";
export function NetscriptSingularity(player: IPlayer, workerScript: WorkerScript): InternalAPI<ISingularity> {
const getAugmentation = function (_ctx: NetscriptContext, name: string): Augmentation {
@ -298,25 +299,25 @@ export function NetscriptSingularity(player: IPlayer, workerScript: WorkerScript
return false;
}
let task = "";
let task: ClassType;
switch (className.toLowerCase()) {
case "Study Computer Science".toLowerCase():
task = CONSTANTS.ClassStudyComputerScience;
task = ClassType.StudyComputerScience;
break;
case "Data Structures".toLowerCase():
task = CONSTANTS.ClassDataStructures;
task = ClassType.DataStructures;
break;
case "Networks".toLowerCase():
task = CONSTANTS.ClassNetworks;
task = ClassType.Networks;
break;
case "Algorithms".toLowerCase():
task = CONSTANTS.ClassAlgorithms;
task = ClassType.Algorithms;
break;
case "Management".toLowerCase():
task = CONSTANTS.ClassManagement;
task = ClassType.Management;
break;
case "Leadership".toLowerCase():
task = CONSTANTS.ClassLeadership;
task = ClassType.Leadership;
break;
default:
_ctx.log(() => `Invalid class name: ${className}.`);
@ -415,19 +416,19 @@ export function NetscriptSingularity(player: IPlayer, workerScript: WorkerScript
switch (stat.toLowerCase()) {
case "strength".toLowerCase():
case "str".toLowerCase():
player.startClass(costMult, expMult, CONSTANTS.ClassGymStrength);
player.startClass(costMult, expMult, ClassType.GymStrength);
break;
case "defense".toLowerCase():
case "def".toLowerCase():
player.startClass(costMult, expMult, CONSTANTS.ClassGymDefense);
player.startClass(costMult, expMult, ClassType.GymDefense);
break;
case "dexterity".toLowerCase():
case "dex".toLowerCase():
player.startClass(costMult, expMult, CONSTANTS.ClassGymDexterity);
player.startClass(costMult, expMult, ClassType.GymDexterity);
break;
case "agility".toLowerCase():
case "agi".toLowerCase():
player.startClass(costMult, expMult, CONSTANTS.ClassGymAgility);
player.startClass(costMult, expMult, ClassType.GymAgility);
break;
default:
_ctx.log(() => `Invalid stat: ${stat}.`);
@ -650,11 +651,11 @@ export function NetscriptSingularity(player: IPlayer, workerScript: WorkerScript
}
if (
!(
player.workType == CONSTANTS.WorkTypeFaction ||
player.workType == CONSTANTS.WorkTypeCompany ||
player.workType == CONSTANTS.WorkTypeCompanyPartTime ||
player.workType == CONSTANTS.WorkTypeCreateProgram ||
player.workType == CONSTANTS.WorkTypeStudyClass
player.workType === WorkType.Faction ||
player.workType === WorkType.Company ||
player.workType === WorkType.CompanyPartTime ||
player.workType === WorkType.CreateProgram ||
player.workType === WorkType.StudyClass
)
) {
throw _ctx.helper.makeRuntimeErrorMsg("Cannot change focus for current job");

@ -30,6 +30,7 @@ import { WorkerScript } from "../Netscript/WorkerScript";
import { HacknetServer } from "../Hacknet/HacknetServer";
import { ISkillProgress } from "./formulas/skill";
import { PlayerAchievement } from "../Achievements/Achievements";
import { WorkType, ClassType, CrimeType } from "../utils/WorkType";
export interface IPlayer {
// Class members
@ -130,14 +131,14 @@ export interface IPlayer {
timeWorkedCreateProgram: number;
graftAugmentationName: string;
timeWorkedGraftAugmentation: number;
crimeType: string;
crimeType: CrimeType;
committingCrimeThruSingFn: boolean;
singFnCrimeWorkerScript: WorkerScript | null;
timeNeededToCompleteWork: number;
focus: boolean;
className: string;
className: ClassType;
currentWorkFactionName: string;
workType: string;
workType: WorkType;
workCostMult: number;
workExpMult: number;
currentWorkFactionDescription: string;
@ -219,11 +220,11 @@ export interface IPlayer {
singularityStopWork(): string;
startBladeburner(p: any): void;
startFactionWork(faction: Faction): void;
startClass(costMult: number, expMult: number, className: string): void;
startClass(costMult: number, expMult: number, className: ClassType): void;
startCorporation(corpName: string, additionalShares?: number): void;
startCrime(
router: IRouter,
crimeType: string,
crimeType: CrimeType,
hackExp: number,
strExp: number,
defExp: number,
@ -269,7 +270,7 @@ export interface IPlayer {
prestigeSourceFile(): void;
calculateSkill(exp: number, mult?: number): number;
calculateSkillProgress(exp: number, mult?: number): ISkillProgress;
resetWorkStatus(generalType?: string, group?: string, workType?: string): void;
resetWorkStatus(generalType?: WorkType, group?: string, workType?: string): void;
getWorkHackExpGain(): number;
getWorkStrExpGain(): number;
getWorkDefExpGain(): number;

@ -38,6 +38,7 @@ import { PlayerAchievement } from "../../Achievements/Achievements";
import { cyrb53 } from "../../utils/StringHelperFunctions";
import { getRandomInt } from "../../utils/helpers/getRandomInt";
import { CONSTANTS } from "../../Constants";
import { WorkType, ClassType, CrimeType, PlayerFactionWorkType } from "../../utils/WorkType";
export class PlayerObject implements IPlayer {
// Class members
@ -135,19 +136,19 @@ export class PlayerObject implements IPlayer {
bladeburner_success_chance_mult: number;
createProgramReqLvl: number;
factionWorkType: string;
factionWorkType: PlayerFactionWorkType;
createProgramName: string;
timeWorkedCreateProgram: number;
graftAugmentationName: string;
timeWorkedGraftAugmentation: number;
crimeType: string;
crimeType: CrimeType;
committingCrimeThruSingFn: boolean;
singFnCrimeWorkerScript: WorkerScript | null;
timeNeededToCompleteWork: number;
focus: boolean;
className: string;
className: ClassType;
currentWorkFactionName: string;
workType: string;
workType: WorkType;
workCostMult: number;
workExpMult: number;
currentWorkFactionDescription: string;
@ -229,11 +230,11 @@ export class PlayerObject implements IPlayer {
singularityStopWork: () => string;
startBladeburner: (p: any) => void;
startFactionWork: (faction: Faction) => void;
startClass: (costMult: number, expMult: number, className: string) => void;
startClass: (costMult: number, expMult: number, className: ClassType) => void;
startCorporation: (corpName: string, additionalShares?: number) => void;
startCrime: (
router: IRouter,
crimeType: string,
crimeType: CrimeType,
hackExp: number,
strExp: number,
defExp: number,
@ -280,7 +281,7 @@ export class PlayerObject implements IPlayer {
prestigeSourceFile: () => void;
calculateSkill: (exp: number, mult?: number) => number;
calculateSkillProgress: (exp: number, mult?: number) => ISkillProgress;
resetWorkStatus: (generalType?: string, group?: string, workType?: string) => void;
resetWorkStatus: (generalType?: WorkType, group?: string, workType?: string) => void;
getWorkHackExpGain: () => number;
getWorkStrExpGain: () => number;
getWorkDefExpGain: () => number;
@ -398,7 +399,7 @@ export class PlayerObject implements IPlayer {
//Flags/variables for working (Company, Faction, Creating Program, Taking Class)
this.isWorking = false;
this.focus = false;
this.workType = "";
this.workType = WorkType.None;
this.workCostMult = 1;
this.workExpMult = 1;
@ -430,9 +431,9 @@ export class PlayerObject implements IPlayer {
this.graftAugmentationName = "";
this.timeWorkedGraftAugmentation = 0;
this.className = "";
this.className = ClassType.None;
this.crimeType = "";
this.crimeType = CrimeType.None;
this.timeWorked = 0; //in m;
this.timeWorkedCreateProgram = 0;
@ -618,7 +619,7 @@ export class PlayerObject implements IPlayer {
this.getUpgradeHomeRamCost = serverMethods.getUpgradeHomeRamCost;
this.getUpgradeHomeCoresCost = serverMethods.getUpgradeHomeCoresCost;
this.createHacknetServer = serverMethods.createHacknetServer;
this.factionWorkType = "";
this.factionWorkType = PlayerFactionWorkType.None;
this.committingCrimeThruSingFn = false;
this.singFnCrimeWorkerScript = null;

@ -66,6 +66,8 @@ import { achievements } from "../../Achievements/Achievements";
import { FactionNames } from "../../Faction/data/FactionNames";
import { graftingIntBonus } from "../Grafting/GraftingHelpers";
import { WorkType, PlayerFactionWorkType, ClassType, CrimeType } from "../../utils/WorkType";
export function init(this: IPlayer): void {
/* Initialize Player's home computer */
const t_homeComp = safetlyCreateUniqueServer({
@ -140,8 +142,8 @@ export function prestigeAugmentation(this: PlayerObject): void {
this.currentWorkFactionName = "";
this.currentWorkFactionDescription = "";
this.createProgramName = "";
this.className = "";
this.crimeType = "";
this.className = ClassType.None;
this.crimeType = CrimeType.None;
this.workHackExpGainRate = 0;
this.workStrExpGainRate = 0;
@ -500,9 +502,8 @@ export function queryStatFromString(this: IPlayer, str: string): number {
}
/******* Working functions *******/
export function resetWorkStatus(this: IPlayer, generalType?: string, group?: string, workType?: string): void {
if (this.workType !== CONSTANTS.WorkTypeFaction && generalType === this.workType && group === this.companyName)
return;
export function resetWorkStatus(this: IPlayer, generalType?: WorkType, group?: string, workType?: string): void {
if (this.workType !== WorkType.Faction && generalType === this.workType && group === this.companyName) return;
if (generalType === this.workType && group === this.currentWorkFactionName && workType === this.factionWorkType)
return;
if (this.isWorking) this.singularityStopWork();
@ -533,8 +534,8 @@ export function resetWorkStatus(this: IPlayer, generalType?: string, group?: str
this.currentWorkFactionDescription = "";
this.createProgramName = "";
this.graftAugmentationName = "";
this.className = "";
this.workType = "";
this.className = ClassType.None;
this.workType = WorkType.None;
}
export function processWorkEarnings(this: IPlayer, numCycles = 1): void {
@ -569,10 +570,10 @@ export function processWorkEarnings(this: IPlayer, numCycles = 1): void {
/* Working for Company */
export function startWork(this: IPlayer, companyName: string): void {
this.resetWorkStatus(CONSTANTS.WorkTypeCompany, companyName);
this.resetWorkStatus(WorkType.Company, companyName);
this.isWorking = true;
this.companyName = companyName;
this.workType = CONSTANTS.WorkTypeCompany;
this.workType = WorkType.Company;
this.workHackExpGainRate = this.getWorkHackExpGain();
this.workStrExpGainRate = this.getWorkStrExpGain();
@ -589,27 +590,27 @@ export function startWork(this: IPlayer, companyName: string): void {
export function process(this: IPlayer, router: IRouter, numCycles = 1): void {
// Working
if (this.isWorking) {
if (this.workType == CONSTANTS.WorkTypeFaction) {
if (this.workType === WorkType.Faction) {
if (this.workForFaction(numCycles)) {
router.toFaction(Factions[this.currentWorkFactionName]);
}
} else if (this.workType == CONSTANTS.WorkTypeCreateProgram) {
} else if (this.workType === WorkType.CreateProgram) {
if (this.createProgramWork(numCycles)) {
router.toTerminal();
}
} else if (this.workType == CONSTANTS.WorkTypeStudyClass) {
} else if (this.workType === WorkType.StudyClass) {
if (this.takeClass(numCycles)) {
router.toCity();
}
} else if (this.workType == CONSTANTS.WorkTypeCrime) {
} else if (this.workType === WorkType.Crime) {
if (this.commitCrime(numCycles)) {
router.toLocation(Locations[LocationName.Slums]);
}
} else if (this.workType == CONSTANTS.WorkTypeCompanyPartTime) {
} else if (this.workType === WorkType.CompanyPartTime) {
if (this.workPartTime(numCycles)) {
router.toCity();
}
} else if (this.workType === CONSTANTS.WorkTypeGraftAugmentation) {
} else if (this.workType === WorkType.GraftAugmentation) {
if (this.graftAugmentationWork(numCycles)) {
router.toGrafting();
}
@ -765,10 +766,10 @@ export function finishWork(this: IPlayer, cancelled: boolean, sing = false): str
}
export function startWorkPartTime(this: IPlayer, companyName: string): void {
this.resetWorkStatus(CONSTANTS.WorkTypeCompanyPartTime, companyName);
this.resetWorkStatus(WorkType.CompanyPartTime, companyName);
this.isWorking = true;
this.companyName = companyName;
this.workType = CONSTANTS.WorkTypeCompanyPartTime;
this.workType = WorkType.CompanyPartTime;
this.workHackExpGainRate = this.getWorkHackExpGain();
this.workStrExpGainRate = this.getWorkStrExpGain();
@ -881,26 +882,26 @@ export function startFactionWork(this: IPlayer, faction: Faction): void {
this.workRepGainRate *= BitNodeMultipliers.FactionWorkRepGain;
this.isWorking = true;
this.workType = CONSTANTS.WorkTypeFaction;
this.workType = WorkType.Faction;
this.currentWorkFactionName = faction.name;
this.timeNeededToCompleteWork = CONSTANTS.MillisecondsPer20Hours;
}
export function startFactionHackWork(this: IPlayer, faction: Faction): void {
this.resetWorkStatus(CONSTANTS.WorkTypeFaction, faction.name, CONSTANTS.FactionWorkHacking);
this.resetWorkStatus(WorkType.Faction, faction.name, PlayerFactionWorkType.Hacking);
this.workHackExpGainRate = 0.15 * this.hacking_exp_mult * BitNodeMultipliers.FactionWorkExpGain;
this.workRepGainRate = getHackingWorkRepGain(this, faction);
this.factionWorkType = CONSTANTS.FactionWorkHacking;
this.factionWorkType = PlayerFactionWorkType.Hacking;
this.currentWorkFactionDescription = "carrying out hacking contracts";
this.startFactionWork(faction);
}
export function startFactionFieldWork(this: IPlayer, faction: Faction): void {
this.resetWorkStatus(CONSTANTS.WorkTypeFaction, faction.name, CONSTANTS.FactionWorkField);
this.resetWorkStatus(WorkType.Faction, faction.name, PlayerFactionWorkType.Field);
this.workHackExpGainRate = 0.1 * this.hacking_exp_mult * BitNodeMultipliers.FactionWorkExpGain;
this.workStrExpGainRate = 0.1 * this.strength_exp_mult * BitNodeMultipliers.FactionWorkExpGain;
@ -910,14 +911,14 @@ export function startFactionFieldWork(this: IPlayer, faction: Faction): void {
this.workChaExpGainRate = 0.1 * this.charisma_exp_mult * BitNodeMultipliers.FactionWorkExpGain;
this.workRepGainRate = getFactionFieldWorkRepGain(this, faction);
this.factionWorkType = CONSTANTS.FactionWorkField;
this.factionWorkType = PlayerFactionWorkType.Field;
this.currentWorkFactionDescription = "carrying out field missions";
this.startFactionWork(faction);
}
export function startFactionSecurityWork(this: IPlayer, faction: Faction): void {
this.resetWorkStatus(CONSTANTS.WorkTypeFaction, faction.name, CONSTANTS.FactionWorkSecurity);
this.resetWorkStatus(WorkType.Faction, faction.name, PlayerFactionWorkType.Security);
this.workHackExpGainRate = 0.05 * this.hacking_exp_mult * BitNodeMultipliers.FactionWorkExpGain;
this.workStrExpGainRate = 0.15 * this.strength_exp_mult * BitNodeMultipliers.FactionWorkExpGain;
@ -927,7 +928,7 @@ export function startFactionSecurityWork(this: IPlayer, faction: Faction): void
this.workChaExpGainRate = 0.0 * this.charisma_exp_mult * BitNodeMultipliers.FactionWorkExpGain;
this.workRepGainRate = getFactionSecurityWorkRepGain(this, faction);
this.factionWorkType = CONSTANTS.FactionWorkSecurity;
this.factionWorkType = PlayerFactionWorkType.Security;
this.currentWorkFactionDescription = "performing security detail";
this.startFactionWork(faction);
@ -942,13 +943,13 @@ export function workForFaction(this: IPlayer, numCycles: number): boolean {
//Constantly update the rep gain rate
switch (this.factionWorkType) {
case CONSTANTS.FactionWorkHacking:
case PlayerFactionWorkType.Hacking:
this.workRepGainRate = getHackingWorkRepGain(this, faction);
break;
case CONSTANTS.FactionWorkField:
case PlayerFactionWorkType.Field:
this.workRepGainRate = getFactionFieldWorkRepGain(this, faction);
break;
case CONSTANTS.FactionWorkSecurity:
case PlayerFactionWorkType.Security:
this.workRepGainRate = getFactionSecurityWorkRepGain(this, faction);
break;
default:
@ -1261,7 +1262,7 @@ export function getWorkRepGain(this: IPlayer): number {
export function startCreateProgramWork(this: IPlayer, programName: string, time: number, reqLevel: number): void {
this.resetWorkStatus();
this.isWorking = true;
this.workType = CONSTANTS.WorkTypeCreateProgram;
this.workType = WorkType.CreateProgram;
//Time needed to complete work affected by hacking skill (linearly based on
//ratio of (your skill - required level) to MAX skill)
@ -1338,7 +1339,7 @@ export function finishCreateProgramWork(this: IPlayer, cancelled: boolean): stri
export function startGraftAugmentationWork(this: IPlayer, augmentationName: string, time: number): void {
this.resetWorkStatus();
this.isWorking = true;
this.workType = CONSTANTS.WorkTypeGraftAugmentation;
this.workType = WorkType.GraftAugmentation;
this.timeNeededToCompleteWork = time;
this.graftAugmentationName = augmentationName;
@ -1392,10 +1393,10 @@ export function finishGraftAugmentationWork(this: IPlayer, cancelled: boolean, s
}
/* Studying/Taking Classes */
export function startClass(this: IPlayer, costMult: number, expMult: number, className: string): void {
export function startClass(this: IPlayer, costMult: number, expMult: number, className: ClassType): void {
this.resetWorkStatus();
this.isWorking = true;
this.workType = CONSTANTS.WorkTypeStudyClass;
this.workType = WorkType.StudyClass;
this.workCostMult = costMult;
this.workExpMult = expMult;
this.className = className;
@ -1487,7 +1488,7 @@ export function finishClass(this: IPlayer, sing = false): string {
export function startCrime(
this: IPlayer,
router: IRouter,
crimeType: string,
crimeType: CrimeType,
hackExp: number,
strExp: number,
defExp: number,
@ -1503,7 +1504,7 @@ export function startCrime(
this.resetWorkStatus();
this.isWorking = true;
this.focus = true;
this.workType = CONSTANTS.WorkTypeCrime;
this.workType = WorkType.Crime;
if (workerscript !== null) {
this.committingCrimeThruSingFn = true;
@ -1668,7 +1669,7 @@ export function finishCrime(this: IPlayer, cancelled: boolean): string {
this.committingCrimeThruSingFn = false;
this.singFnCrimeWorkerScript = null;
this.isWorking = false;
this.crimeType = "";
this.crimeType = CrimeType.None;
this.resetWorkStatus();
return "";
}
@ -1681,25 +1682,25 @@ export function singularityStopWork(this: IPlayer): string {
}
let res = ""; //Earnings text for work
switch (this.workType) {
case CONSTANTS.WorkTypeStudyClass:
case WorkType.StudyClass:
res = this.finishClass(true);
break;
case CONSTANTS.WorkTypeCompany:
case WorkType.Company:
res = this.finishWork(true, true);
break;
case CONSTANTS.WorkTypeCompanyPartTime:
case WorkType.CompanyPartTime:
res = this.finishWorkPartTime(true);
break;
case CONSTANTS.WorkTypeFaction:
case WorkType.Faction:
res = this.finishFactionWork(true, true);
break;
case CONSTANTS.WorkTypeCreateProgram:
case WorkType.CreateProgram:
res = this.finishCreateProgramWork(true);
break;
case CONSTANTS.WorkTypeCrime:
case WorkType.Crime:
res = this.finishCrime(true);
break;
case CONSTANTS.WorkTypeGraftAugmentation:
case WorkType.GraftAugmentation:
res = this.finishGraftAugmentationWork(true, true);
break;
default:
@ -1793,7 +1794,7 @@ export function applyForJob(this: IPlayer, entryPosType: CompanyPosition, sing =
}
this.jobs[company.name] = pos.name;
if (!this.isWorking || !this.workType.includes("Working for Company")) this.companyName = company.name;
if (!this.isWorking || this.workType !== WorkType.Company) this.companyName = company.name;
if (!sing) {
dialogBoxCreate("Congratulations! You were offered a new job at " + company.name + " as a " + pos.name + "!");
@ -1842,7 +1843,7 @@ export function getNextCompanyPosition(
}
export function quitJob(this: IPlayer, company: string, _sing = false): void {
if (this.isWorking == true && this.workType.includes("Working for Company") && this.companyName == company) {
if (this.isWorking == true && this.workType !== WorkType.Company && this.companyName == company) {
this.finishWork(true);
}
delete this.jobs[company];

@ -1,23 +1,19 @@
import { Box, Button, Paper, Tooltip, Typography } from "@mui/material";
import React, { useState } from "react";
import { Box, Paper, Typography, Button, Tooltip } from "@mui/material";
import { CONSTANTS } from "../../../Constants";
import { Crimes } from "../../../Crime/Crimes";
import { numeralWrapper } from "../../../ui/numeralFormat";
import { createProgressBarText } from "../../../utils/helpers/createProgressBarText";
import { use } from "../../../ui/Context";
import { FactionWorkType } from "../../../Faction/FactionWorkTypeEnum";
import { use } from "../../../ui/Context";
import { numeralWrapper } from "../../../ui/numeralFormat";
import { ProgressBar } from "../../../ui/React/Progress";
import { Sleeve } from "../Sleeve";
import { SleeveTaskType } from "../SleeveTaskTypesEnum";
import { SleeveAugmentationsModal } from "./SleeveAugmentationsModal";
import { TravelModal } from "./TravelModal";
import { StatsElement, EarningsElement } from "./StatsElement";
import { MoreStatsModal } from "./MoreStatsModal";
import { MoreEarningsModal } from "./MoreEarningsModal";
import { MoreStatsModal } from "./MoreStatsModal";
import { SleeveAugmentationsModal } from "./SleeveAugmentationsModal";
import { EarningsElement, StatsElement } from "./StatsElement";
import { TaskSelector } from "./TaskSelector";
import { TravelModal } from "./TravelModal";
interface IProps {
sleeve: Sleeve;
@ -131,10 +127,9 @@ export function SleeveElem(props: IProps): React.ReactElement {
}
return (
<Box component={Paper} sx={{ width: "auto" }}>
<Box sx={{ m: 1 }}>
<Box display="grid" sx={{ gridTemplateColumns: "1fr 1fr", width: "100%", gap: 1 }}>
<Box>
<>
<Paper sx={{ p: 1, display: "grid", gridTemplateColumns: "1fr 1fr", width: "auto", gap: 1 }}>
<span>
<StatsElement sleeve={props.sleeve} />
<Box display="grid" sx={{ gridTemplateColumns: "1fr 1fr", width: "100%" }}>
<Button onClick={() => setStatsOpen(true)}>More Stats</Button>
@ -151,9 +146,7 @@ export function SleeveElem(props: IProps): React.ReactElement {
</span>
</Tooltip>
<Tooltip
title={
props.sleeve.shock < 100 ? <Typography>Unlocked when sleeve has fully recovered</Typography> : ""
}
title={props.sleeve.shock < 100 ? <Typography>Unlocked when sleeve has fully recovered</Typography> : ""}
>
<span>
<Button
@ -166,24 +159,25 @@ export function SleeveElem(props: IProps): React.ReactElement {
</span>
</Tooltip>
</Box>
</Box>
<Box>
</span>
<span>
<EarningsElement sleeve={props.sleeve} />
<Box>
<TaskSelector player={player} sleeve={props.sleeve} setABC={setABC} />
<Button onClick={setTask} sx={{ width: "100%" }}>
Set Task
</Button>
<Typography>{desc}</Typography>
<Typography>
{props.sleeve.currentTask === SleeveTaskType.Crime &&
createProgressBarText({
progress: props.sleeve.currentTaskTime / props.sleeve.currentTaskMaxTime,
totalTicks: 25,
})}
{props.sleeve.currentTask === SleeveTaskType.Crime && (
<ProgressBar
variant="determinate"
value={(props.sleeve.currentTaskTime / props.sleeve.currentTaskMaxTime) * 100}
color="primary"
/>
)}
</Typography>
</Box>
</Box>
</span>
</Paper>
<MoreStatsModal open={statsOpen} onClose={() => setStatsOpen(false)} sleeve={props.sleeve} />
<MoreEarningsModal open={earningsOpen} onClose={() => setEarningsOpen(false)} sleeve={props.sleeve} />
<TravelModal
@ -197,8 +191,6 @@ export function SleeveElem(props: IProps): React.ReactElement {
onClose={() => setAugmentationsOpen(false)}
sleeve={props.sleeve}
/>
</Box>
</Box>
</Box>
</>
);
}

@ -1,6 +1,7 @@
import { CONSTANTS } from "../../Constants";
import { BitNodeMultipliers } from "../../BitNode/BitNodeMultipliers";
import { IPlayer } from "../IPlayer";
import { ClassType } from "../../utils/WorkType";
export interface WorkEarnings {
workMoneyLossRate: number;
@ -25,43 +26,43 @@ export function calculateClassEarnings(player: IPlayer): WorkEarnings {
chaExp = 0;
const hashManager = player.hashManager;
switch (player.className) {
case CONSTANTS.ClassStudyComputerScience:
case ClassType.StudyComputerScience:
hackExp =
((CONSTANTS.ClassStudyComputerScienceBaseExp * player.workExpMult) / gameCPS) * hashManager.getStudyMult();
break;
case CONSTANTS.ClassDataStructures:
case ClassType.DataStructures:
cost = (CONSTANTS.ClassDataStructuresBaseCost * player.workCostMult) / gameCPS;
hackExp = ((CONSTANTS.ClassDataStructuresBaseExp * player.workExpMult) / gameCPS) * hashManager.getStudyMult();
break;
case CONSTANTS.ClassNetworks:
case ClassType.Networks:
cost = (CONSTANTS.ClassNetworksBaseCost * player.workCostMult) / gameCPS;
hackExp = ((CONSTANTS.ClassNetworksBaseExp * player.workExpMult) / gameCPS) * hashManager.getStudyMult();
break;
case CONSTANTS.ClassAlgorithms:
case ClassType.Algorithms:
cost = (CONSTANTS.ClassAlgorithmsBaseCost * player.workCostMult) / gameCPS;
hackExp = ((CONSTANTS.ClassAlgorithmsBaseExp * player.workExpMult) / gameCPS) * hashManager.getStudyMult();
break;
case CONSTANTS.ClassManagement:
case ClassType.Management:
cost = (CONSTANTS.ClassManagementBaseCost * player.workCostMult) / gameCPS;
chaExp = ((CONSTANTS.ClassManagementBaseExp * player.workExpMult) / gameCPS) * hashManager.getStudyMult();
break;
case CONSTANTS.ClassLeadership:
case ClassType.Leadership:
cost = (CONSTANTS.ClassLeadershipBaseCost * player.workCostMult) / gameCPS;
chaExp = ((CONSTANTS.ClassLeadershipBaseExp * player.workExpMult) / gameCPS) * hashManager.getStudyMult();
break;
case CONSTANTS.ClassGymStrength:
case ClassType.GymStrength:
cost = (CONSTANTS.ClassGymBaseCost * player.workCostMult) / gameCPS;
strExp = (player.workExpMult / gameCPS) * hashManager.getTrainingMult();
break;
case CONSTANTS.ClassGymDefense:
case ClassType.GymDefense:
cost = (CONSTANTS.ClassGymBaseCost * player.workCostMult) / gameCPS;
defExp = (player.workExpMult / gameCPS) * hashManager.getTrainingMult();
break;
case CONSTANTS.ClassGymDexterity:
case ClassType.GymDexterity:
cost = (CONSTANTS.ClassGymBaseCost * player.workCostMult) / gameCPS;
dexExp = (player.workExpMult / gameCPS) * hashManager.getTrainingMult();
break;
case CONSTANTS.ClassGymAgility:
case ClassType.GymAgility:
cost = (CONSTANTS.ClassGymBaseCost * player.workCostMult) / gameCPS;
agiExp = (player.workExpMult / gameCPS) * hashManager.getTrainingMult();
break;

@ -50,6 +50,8 @@ import { setupUncaughtPromiseHandler } from "./UncaughtPromiseHandler";
import { Button, Typography } from "@mui/material";
import { SnackbarEvents, ToastVariant } from "./ui/React/Snackbar";
import { WorkType } from "./utils/WorkType";
const Engine: {
_lastUpdate: number;
updateGame: (numCycles?: number) => void;
@ -292,19 +294,26 @@ const Engine: {
loadAllRunningScripts(Player); // This also takes care of offline production for those scripts
if (Player.isWorking) {
Player.focus = true;
if (Player.workType == CONSTANTS.WorkTypeFaction) {
switch (Player.workType) {
case WorkType.Faction:
Player.workForFaction(numCyclesOffline);
} else if (Player.workType == CONSTANTS.WorkTypeCreateProgram) {
break;
case WorkType.CreateProgram:
Player.createProgramWork(numCyclesOffline);
} else if (Player.workType == CONSTANTS.WorkTypeStudyClass) {
break;
case WorkType.StudyClass:
Player.takeClass(numCyclesOffline);
} else if (Player.workType == CONSTANTS.WorkTypeCrime) {
break;
case WorkType.Crime:
Player.commitCrime(numCyclesOffline);
} else if (Player.workType == CONSTANTS.WorkTypeCompanyPartTime) {
break;
case WorkType.CompanyPartTime:
Player.workPartTime(numCyclesOffline);
} else if (Player.workType === CONSTANTS.WorkTypeGraftAugmentation) {
break;
case WorkType.GraftAugmentation:
Player.graftAugmentationWork(numCyclesOffline);
} else {
break;
default:
Player.work(numCyclesOffline);
}
} else {

@ -25,7 +25,8 @@ import { StatsProgressOverviewCell } from "./StatsProgressBar";
import { BitNodeMultipliers } from "../../BitNode/BitNodeMultipliers";
import { Box, Tooltip } from "@mui/material";
import { CONSTANTS } from "../../Constants";
import { WorkType } from "../../utils/WorkType";
interface IProps {
save: () => void;
@ -144,8 +145,8 @@ function Work(): React.ReactElement {
let header = <></>;
let innerText = <></>;
switch (player.workType) {
case CONSTANTS.WorkTypeCompanyPartTime:
case CONSTANTS.WorkTypeCompany:
case WorkType.CompanyPartTime:
case WorkType.Company:
details = (
<>
{player.jobs[player.companyName]} at <strong>{player.companyName}</strong>
@ -162,7 +163,7 @@ function Work(): React.ReactElement {
</>
);
break;
case CONSTANTS.WorkTypeFaction:
case WorkType.Faction:
details = (
<>
{player.factionWorkType} for <strong>{player.currentWorkFactionName}</strong>
@ -179,12 +180,12 @@ function Work(): React.ReactElement {
</>
);
break;
case CONSTANTS.WorkTypeStudyClass:
case WorkType.StudyClass:
details = <>{player.workType}</>;
header = <>You are {player.className}</>;
innerText = <>{convertTimeMsToTimeElapsedString(player.timeWorked)}</>;
break;
case CONSTANTS.WorkTypeCreateProgram:
case WorkType.CreateProgram:
details = <>Coding {player.createProgramName}</>;
header = <>Creating a program</>;
innerText = (
@ -194,7 +195,7 @@ function Work(): React.ReactElement {
</>
);
break;
case CONSTANTS.WorkTypeGraftAugmentation:
case WorkType.GraftAugmentation:
details = <>Grafting {player.graftAugmentationName}</>;
header = <>Grafting an Augmentation</>;
innerText = (

13
src/ui/React/Progress.tsx Normal file

@ -0,0 +1,13 @@
import LinearProgress from "@mui/material/LinearProgress";
import { Theme } from "@mui/material/styles";
import withStyles from "@mui/styles/withStyles";
export const ProgressBar = withStyles((theme: Theme) => ({
root: {
backgroundColor: theme.palette.background.paper,
},
bar: {
transition: "none",
backgroundColor: theme.palette.primary.main,
},
}))(LinearProgress);

@ -16,13 +16,14 @@ interface IProps {
name: string;
color: string;
classes?: any;
data: ITableRowData;
data?: ITableRowData;
children?: React.ReactElement;
}
export const StatsRow = ({ name, color, classes = useStyles(), children, data }: IProps): React.ReactElement => {
let content;
let content = "";
if (data) {
if (data.content !== undefined) {
content = data.content;
} else if (data.level !== undefined && data.exp !== undefined) {
@ -30,6 +31,7 @@ export const StatsRow = ({ name, color, classes = useStyles(), children, data }:
} else if (data.level !== undefined && data.exp === undefined) {
content = `${formatNumber(data.level, 0)}`;
}
}
return (
<TableRow>

@ -1,26 +1,47 @@
import React, { useState, useEffect } from "react";
import { use } from "./Context";
import { Box, Container, Paper, Table, TableBody, Tooltip } from "@mui/material";
import Button from "@mui/material/Button";
import Typography from "@mui/material/Typography";
import { uniqueId } from "lodash";
import React, { useEffect, useState } from "react";
import { Companies } from "../Company/Companies";
import { Company } from "../Company/Company";
import { CONSTANTS } from "../Constants";
import { Factions } from "../Faction/Factions";
import { LocationName } from "../Locations/data/LocationNames";
import { Locations } from "../Locations/Locations";
import { Settings } from "../Settings/Settings";
import { convertTimeMsToTimeElapsedString } from "../utils/StringHelperFunctions";
import { use } from "./Context";
import { numeralWrapper } from "./numeralFormat";
import { Money } from "./React/Money";
import { MoneyRate } from "./React/MoneyRate";
import { ProgressBar } from "./React/Progress";
import { Reputation } from "./React/Reputation";
import { ReputationRate } from "./React/ReputationRate";
import { MoneyRate } from "./React/MoneyRate";
import { Money } from "./React/Money";
import { convertTimeMsToTimeElapsedString } from "../utils/StringHelperFunctions";
import { Factions } from "../Faction/Factions";
import { Company } from "../Company/Company";
import { Companies } from "../Company/Companies";
import { Locations } from "../Locations/Locations";
import { LocationName } from "../Locations/data/LocationNames";
import Typography from "@mui/material/Typography";
import Grid from "@mui/material/Grid";
import Button from "@mui/material/Button";
import { createProgressBarText } from "../utils/helpers/createProgressBarText";
import { StatsRow } from "./React/StatsRow";
import { WorkType, ClassType } from "../utils/WorkType";
const CYCLES_PER_SEC = 1000 / CONSTANTS.MilliPerCycle;
interface IWorkInfo {
buttons: {
cancel: () => void;
unfocus?: () => void;
};
title: string | React.ReactElement;
description?: string | React.ReactElement;
gains?: (string | React.ReactElement)[];
progress?: {
elapsed?: number;
remaining?: number;
percentage?: number;
};
stopText: string;
stopTooltip?: string | React.ReactElement;
}
export function WorkInProgressRoot(): React.ReactElement {
const setRerender = useState(false)[1];
function rerender(): void {
@ -35,18 +56,103 @@ export function WorkInProgressRoot(): React.ReactElement {
const player = use.Player();
const router = use.Router();
if (player.workType == CONSTANTS.WorkTypeFaction) {
const expGains = [
player.workHackExpGained > 0 ? (
<StatsRow
name="Hacking Exp"
color={Settings.theme.hack}
data={{
content: `${numeralWrapper.formatExp(player.workHackExpGained)} (${numeralWrapper.formatExp(
player.workHackExpGainRate * CYCLES_PER_SEC,
)} / sec)`,
}}
/>
) : (
<></>
),
player.workStrExpGained > 0 ? (
<StatsRow
name="Strength Exp"
color={Settings.theme.combat}
data={{
content: `${numeralWrapper.formatExp(player.workStrExpGained)} (${numeralWrapper.formatExp(
player.workStrExpGainRate * CYCLES_PER_SEC,
)} / sec)`,
}}
/>
) : (
<></>
),
player.workDefExpGained > 0 ? (
<StatsRow
name="Defense Exp"
color={Settings.theme.combat}
data={{
content: `${numeralWrapper.formatExp(player.workDefExpGained)} (${numeralWrapper.formatExp(
player.workDefExpGainRate * CYCLES_PER_SEC,
)} / sec)`,
}}
/>
) : (
<></>
),
player.workDexExpGained > 0 ? (
<StatsRow
name="Dexterity Exp"
color={Settings.theme.combat}
data={{
content: `${numeralWrapper.formatExp(player.workDexExpGained)} (${numeralWrapper.formatExp(
player.workDexExpGainRate * CYCLES_PER_SEC,
)} / sec)`,
}}
/>
) : (
<></>
),
player.workAgiExpGained > 0 ? (
<StatsRow
name="Agility Exp"
color={Settings.theme.combat}
data={{
content: `${numeralWrapper.formatExp(player.workAgiExpGained)} (${numeralWrapper.formatExp(
player.workAgiExpGainRate * CYCLES_PER_SEC,
)} / sec)`,
}}
/>
) : (
<></>
),
player.workChaExpGained > 0 ? (
<StatsRow
name="Charisma Exp"
color={Settings.theme.cha}
data={{
content: `${numeralWrapper.formatExp(player.workChaExpGained)} (${numeralWrapper.formatExp(
player.workChaExpGainRate * CYCLES_PER_SEC,
)} / sec)`,
}}
/>
) : (
<></>
),
];
let workInfo: IWorkInfo | null;
switch (player.workType) {
case WorkType.Faction: {
const faction = Factions[player.currentWorkFactionName];
if (!faction) {
return (
<>
<Typography variant="h4" color="primary">
You have not joined {player.currentWorkFactionName || "(Faction not found)"} yet or cannot work at this
time, please try again if you think this should have worked
</Typography>
<Button onClick={() => router.toFactions()}>Back to Factions</Button>
</>
);
workInfo = {
buttons: {
cancel: () => router.toFactions(),
},
title:
`You have not joined ${player.currentWorkFactionName || "(Faction not found)"} at this time,` +
" please try again if you think this should have worked",
stopText: "Back to Factions",
};
}
function cancel(): void {
@ -57,81 +163,54 @@ export function WorkInProgressRoot(): React.ReactElement {
router.toFaction(faction);
player.stopFocusing();
}
return (
<Grid container direction="column" justifyContent="center" alignItems="center" style={{ minHeight: "100vh" }}>
<Grid item>
workInfo = {
buttons: {
cancel: cancel,
unfocus: unfocus,
},
title: (
<>
You are currently {player.currentWorkFactionDescription} for your faction <b>{faction.name}</b>
</>
),
description: (
<>
Current Faction Reputation: <Reputation reputation={faction.playerReputation} />
</>
),
gains: [
player.workMoneyGained > 0 ? (
<StatsRow name="Money" color={Settings.theme.money}>
<Typography>
You are currently {player.currentWorkFactionDescription} for your faction {faction.name}
<br />
(Current Faction Reputation: <Reputation reputation={faction.playerReputation} />
). <br />
You have been doing this for {convertTimeMsToTimeElapsedString(player.timeWorked)}
<br />
<br />
You have earned: <br />
<br />
<Money money={player.workMoneyGained} /> (<MoneyRate money={player.workMoneyGainRate * CYCLES_PER_SEC} />){" "}
<br />
<br />
<Reputation reputation={player.workRepGained} /> (
<ReputationRate reputation={player.workRepGainRate * CYCLES_PER_SEC} />) reputation for this faction <br />
<br />
{player.workHackExpGained > 0 && (
<>
{numeralWrapper.formatExp(player.workHackExpGained)} (
{numeralWrapper.formatExp(player.workHackExpGainRate * CYCLES_PER_SEC)} / sec) hacking exp <br />
</>
)}
<br />
{player.workStrExpGained > 0 && (
<>
{numeralWrapper.formatExp(player.workStrExpGained)} (
{numeralWrapper.formatExp(player.workStrExpGainRate * CYCLES_PER_SEC)} / sec) strength exp <br />
</>
)}
{player.workDefExpGained > 0 && (
<>
{numeralWrapper.formatExp(player.workDefExpGained)} (
{numeralWrapper.formatExp(player.workDefExpGainRate * CYCLES_PER_SEC)} / sec) defense exp <br />
</>
)}
{player.workDexExpGained > 0 && (
<>
{numeralWrapper.formatExp(player.workDexExpGained)} (
{numeralWrapper.formatExp(player.workDexExpGainRate * CYCLES_PER_SEC)} / sec) dexterity exp <br />
</>
)}
{player.workAgiExpGained > 0 && (
<>
{numeralWrapper.formatExp(player.workAgiExpGained)} (
{numeralWrapper.formatExp(player.workAgiExpGainRate * CYCLES_PER_SEC)} / sec) agility exp <br />
</>
)}
<br />
{player.workChaExpGained > 0 && (
<>
{numeralWrapper.formatExp(player.workChaExpGained)} (
{numeralWrapper.formatExp(player.workChaExpGainRate * CYCLES_PER_SEC)} / sec) charisma exp <br />
</>
)}
<br />
You will automatically finish after working for 20 hours. You can cancel earlier if you wish.
<br />
There is no penalty for cancelling earlier.
<Money money={player.workMoneyGained} /> (
<MoneyRate money={player.workMoneyGainRate * CYCLES_PER_SEC} />)
</Typography>
</Grid>
<Grid item>
<Button sx={{ mx: 2 }} onClick={cancel}>
Stop Faction Work
</Button>
<Button onClick={unfocus}>Do something else simultaneously</Button>
</Grid>
</Grid>
);
</StatsRow>
) : (
<></>
),
<StatsRow name="Faction Reputation" color={Settings.theme.rep}>
<Typography>
<Reputation reputation={player.workRepGained} /> (
<ReputationRate reputation={player.workRepGainRate * CYCLES_PER_SEC} />)
</Typography>
</StatsRow>,
...expGains,
],
progress: {
elapsed: player.timeWorked,
},
stopText: "Stop Faction work",
};
break;
}
case WorkType.StudyClass: {
const className = player.className;
if (player.className !== "") {
function cancel(): void {
player.finishClass(true);
router.toCity();
@ -144,89 +223,59 @@ export function WorkInProgressRoot(): React.ReactElement {
let stopText = "";
if (
className == CONSTANTS.ClassGymStrength ||
className == CONSTANTS.ClassGymDefense ||
className == CONSTANTS.ClassGymDexterity ||
className == CONSTANTS.ClassGymAgility
className === ClassType.GymStrength ||
className === ClassType.GymDefense ||
className === ClassType.GymDexterity ||
className === ClassType.GymAgility
) {
stopText = "Stop training at gym";
} else {
stopText = "Stop taking course";
}
return (
<Grid container direction="column" justifyContent="center" alignItems="center" style={{ minHeight: "100vh" }}>
<Grid item>
workInfo = {
buttons: {
cancel: cancel,
unfocus: unfocus,
},
title: (
<>
You are currently <b>{className}</b>
</>
),
gains: [
<StatsRow name="Total Cost" color={Settings.theme.money}>
<Typography>
You have been {className} for {convertTimeMsToTimeElapsedString(player.timeWorked)}
<br />
<br />
This has cost you: <br />
<Money money={-player.workMoneyGained} /> (<MoneyRate money={player.workMoneyLossRate * CYCLES_PER_SEC} />){" "}
<br />
<br />
You have gained: <br />
{player.workHackExpGained > 0 && (
<>
{numeralWrapper.formatExp(player.workHackExpGained)} (
{numeralWrapper.formatExp(player.workHackExpGainRate * CYCLES_PER_SEC)} / sec) hacking exp <br />
</>
)}
{player.workStrExpGained > 0 && (
<>
{numeralWrapper.formatExp(player.workStrExpGained)} (
{numeralWrapper.formatExp(player.workStrExpGainRate * CYCLES_PER_SEC)} / sec) strength exp <br />
</>
)}
{player.workDefExpGained > 0 && (
<>
{numeralWrapper.formatExp(player.workDefExpGained)} (
{numeralWrapper.formatExp(player.workDefExpGainRate * CYCLES_PER_SEC)} / sec) defense exp <br />
</>
)}
{player.workDexExpGained > 0 && (
<>
{numeralWrapper.formatExp(player.workDexExpGained)} (
{numeralWrapper.formatExp(player.workDexExpGainRate * CYCLES_PER_SEC)} / sec) dexterity exp <br />
</>
)}
{player.workAgiExpGained > 0 && (
<>
{numeralWrapper.formatExp(player.workAgiExpGained)} (
{numeralWrapper.formatExp(player.workAgiExpGainRate * CYCLES_PER_SEC)} / sec) agility exp <br />
</>
)}
{player.workChaExpGained > 0 && (
<>
{numeralWrapper.formatExp(player.workChaExpGained)} (
{numeralWrapper.formatExp(player.workChaExpGainRate * CYCLES_PER_SEC)} / sec) charisma exp <br />
</>
)}
You may cancel at any time
<Money money={-player.workMoneyGained} /> (<MoneyRate money={player.workMoneyLossRate * CYCLES_PER_SEC} />
)
</Typography>
</Grid>
<Grid item>
<Button sx={{ mx: 2 }} onClick={cancel}>
{stopText}
</Button>
<Button onClick={unfocus}>Do something else simultaneously</Button>
</Grid>
</Grid>
);
</StatsRow>,
...expGains,
],
progress: {
elapsed: player.timeWorked,
},
stopText: stopText,
};
break;
}
if (player.workType == CONSTANTS.WorkTypeCompany) {
case WorkType.Company: {
const comp = Companies[player.companyName];
if (comp == null || !(comp instanceof Company)) {
return (
<>
<Typography variant="h4" color="primary">
You cannot work for {player.companyName || "(Company not found)"} at this time, please try again if you
think this should have worked
</Typography>
<Button onClick={() => router.toTerminal()}>Back to Terminal</Button>
</>
);
workInfo = {
buttons: {
cancel: () => router.toTerminal(),
},
title:
`You cannot work for ${player.companyName || "(Company not found)"} at this time,` +
" please try again if you think this should have worked",
stopText: "Back to Terminal",
};
}
const companyRep = comp.playerReputation;
@ -245,84 +294,51 @@ export function WorkInProgressRoot(): React.ReactElement {
const penalty = player.cancelationPenalty();
const penaltyString = penalty === 0.5 ? "half" : "three-quarters";
return (
<Grid container direction="column" justifyContent="center" alignItems="center" style={{ minHeight: "100vh" }}>
<Grid item>
workInfo = {
buttons: {
cancel: cancel,
unfocus: unfocus,
},
title: (
<>
You are currently working as a <b>{position}</b> at <b>{player.companyName}</b>
</>
),
description: (
<>
Current Company Reputation: <Reputation reputation={companyRep} />
</>
),
gains: [
<StatsRow name="Money" color={Settings.theme.money}>
<Typography>
You are currently working as a {position} at {player.companyName} (Current Company Reputation:{" "}
<Reputation reputation={companyRep} />)<br />
<br />
You have been working for {convertTimeMsToTimeElapsedString(player.timeWorked)}
<br />
<br />
You have earned: <br />
<br />
<Money money={player.workMoneyGained} /> (<MoneyRate money={player.workMoneyGainRate * CYCLES_PER_SEC} />){" "}
<br />
<br />
<Reputation reputation={player.workRepGained} /> (
<ReputationRate reputation={player.workRepGainRate * CYCLES_PER_SEC} />) reputation for this company <br />
<br />
{player.workHackExpGained > 0 && (
<>
{numeralWrapper.formatExp(player.workHackExpGained)} (
{`${numeralWrapper.formatExp(player.workHackExpGainRate * CYCLES_PER_SEC)} / sec`}
) hacking exp <br />
</>
)}
<br />
{player.workStrExpGained > 0 && (
<>
{numeralWrapper.formatExp(player.workStrExpGained)} (
{`${numeralWrapper.formatExp(player.workStrExpGainRate * CYCLES_PER_SEC)} / sec`}
) strength exp <br />
</>
)}
{player.workDefExpGained > 0 && (
<>
{numeralWrapper.formatExp(player.workDefExpGained)} (
{`${numeralWrapper.formatExp(player.workDefExpGainRate * CYCLES_PER_SEC)} / sec`}
) defense exp <br />
</>
)}
{player.workDexExpGained > 0 && (
<>
{numeralWrapper.formatExp(player.workDexExpGained)} (
{`${numeralWrapper.formatExp(player.workDexExpGainRate * CYCLES_PER_SEC)} / sec`}
) dexterity exp <br />
</>
)}
{player.workAgiExpGained > 0 && (
<>
{numeralWrapper.formatExp(player.workAgiExpGained)} (
{`${numeralWrapper.formatExp(player.workAgiExpGainRate * CYCLES_PER_SEC)} / sec`}
) agility exp <br />
</>
)}
<br />
{player.workChaExpGained > 0 && (
<>
{numeralWrapper.formatExp(player.workChaExpGained)} (
{`${numeralWrapper.formatExp(player.workChaExpGainRate * CYCLES_PER_SEC)} / sec`}
) charisma exp <br />
</>
)}
<br />
You will automatically finish after working for 8 hours. You can cancel earlier if you wish, but you will
only gain {penaltyString} of the reputation you've earned so far.
<Money money={player.workMoneyGained} /> (<MoneyRate money={player.workMoneyGainRate * CYCLES_PER_SEC} />)
</Typography>
</Grid>
<Grid item>
<Button sx={{ mx: 2 }} onClick={cancel}>
Stop Working
</Button>
<Button onClick={unfocus}>Do something else simultaneously</Button>
</Grid>
</Grid>
);
</StatsRow>,
<StatsRow name="Company Reputation" color={Settings.theme.rep}>
<Typography>
<Reputation reputation={player.workRepGained} /> (
<ReputationRate reputation={player.workRepGainRate * CYCLES_PER_SEC} />)
</Typography>
</StatsRow>,
...expGains,
],
progress: {
elapsed: player.timeWorked,
},
stopText: "Stop working",
stopTooltip:
"You will automatically finish after working for 8 hours. You can cancel earlier if you wish" +
` but you will only gain ${penaltyString} of the reputation you've earned so far.`,
};
break;
}
if (player.workType == CONSTANTS.WorkTypeCompanyPartTime) {
case WorkType.CompanyPartTime: {
function cancel(): void {
player.finishWorkPartTime(true);
router.toJob();
@ -339,126 +355,74 @@ export function WorkInProgressRoot(): React.ReactElement {
companyRep = comp.playerReputation;
const position = player.jobs[player.companyName];
return (
<Grid container direction="column" justifyContent="center" alignItems="center" style={{ minHeight: "100vh" }}>
<Grid item>
workInfo = {
buttons: {
cancel: cancel,
unfocus: unfocus,
},
title: (
<>
You are currently working as a <b>{position}</b> at <b>{player.companyName}</b>
</>
),
description: (
<>
Current Company Reputation: <Reputation reputation={companyRep} />
</>
),
gains: [
<StatsRow name="Money" color={Settings.theme.money}>
<Typography>
<Money money={player.workMoneyGained} /> (<MoneyRate money={player.workMoneyGainRate * CYCLES_PER_SEC} />)
</Typography>
</StatsRow>,
<StatsRow name="Company Reputation" color={Settings.theme.rep}>
<Typography>
You are currently working as a {position} at {player.companyName} (Current Company Reputation:{" "}
<Reputation reputation={companyRep} />)<br />
<br />
You have been working for {convertTimeMsToTimeElapsedString(player.timeWorked)}
<br />
<br />
You have earned: <br />
<br />
<Money money={player.workMoneyGained} /> (<MoneyRate money={player.workMoneyGainRate * CYCLES_PER_SEC} />){" "}
<br />
<br />
<Reputation reputation={player.workRepGained} /> (
<ReputationRate reputation={player.workRepGainRate * CYCLES_PER_SEC} />
) reputation for this company <br />
<br />
{player.workHackExpGained > 0 && (
<>
{numeralWrapper.formatExp(player.workHackExpGained)} (
{`${numeralWrapper.formatExp(player.workHackExpGainRate * CYCLES_PER_SEC)} / sec`}
) hacking exp <br />
</>
)}
<br />
{player.workStrExpGained > 0 && (
<>
{numeralWrapper.formatExp(player.workStrExpGained)} (
{`${numeralWrapper.formatExp(player.workStrExpGainRate * CYCLES_PER_SEC)} / sec`}
) strength exp <br />
</>
)}
{player.workDefExpGained > 0 && (
<>
{numeralWrapper.formatExp(player.workDefExpGained)} (
{`${numeralWrapper.formatExp(player.workDefExpGainRate * CYCLES_PER_SEC)} / sec`}
) defense exp <br />
</>
)}
{player.workDexExpGained > 0 && (
<>
{numeralWrapper.formatExp(player.workDexExpGained)} (
{`${numeralWrapper.formatExp(player.workDexExpGainRate * CYCLES_PER_SEC)} / sec`}
) dexterity exp <br />
</>
)}
{player.workAgiExpGained > 0 && (
<>
{numeralWrapper.formatExp(player.workAgiExpGained)} (
{`${numeralWrapper.formatExp(player.workAgiExpGainRate * CYCLES_PER_SEC)} / sec`}
) agility exp <br />
</>
)}
<br />
{player.workChaExpGained > 0 && (
<>
{numeralWrapper.formatExp(player.workChaExpGained)} (
{`${numeralWrapper.formatExp(player.workChaExpGainRate * CYCLES_PER_SEC)} / sec`}
) charisma exp <br />
</>
)}
<br />
You will automatically finish after working for 8 hours. You can cancel earlier if you wish, and there will
be no penalty because this is a part-time job.
<ReputationRate reputation={player.workRepGainRate * CYCLES_PER_SEC} />)
</Typography>
</Grid>
<Grid item>
<Button sx={{ mx: 2 }} onClick={cancel}>
Stop Working
</Button>
<Button onClick={unfocus}>Do something else simultaneously</Button>
</Grid>
</Grid>
);
</StatsRow>,
...expGains,
],
progress: {
elapsed: player.timeWorked,
},
stopText: "Stop working",
stopTooltip:
"You will automatically finish after working for 8 hours. You can cancel earlier if you wish" +
" and there will be no penalty because this is a part-time job.",
};
break;
}
if (player.crimeType !== "") {
const percent = Math.round((player.timeWorked / player.timeNeededToCompleteWork) * 100);
let numBars = Math.round(percent / 5);
if (numBars < 0) {
numBars = 0;
}
if (numBars > 20) {
numBars = 20;
}
// const progressBar = "[" + Array(numBars + 1).join("|") + Array(20 - numBars + 1).join(" ") + "]";
const progressBar = createProgressBarText({ progress: (numBars + 1) / 20, totalTicks: 20 });
case WorkType.Crime: {
const completion = Math.round((player.timeWorked / player.timeNeededToCompleteWork) * 100);
return (
<Grid container direction="column" justifyContent="center" alignItems="center" style={{ minHeight: "100vh" }}>
<Grid item>
<Typography>
<Typography>You are attempting to {player.crimeType}.</Typography>
<br />
<Typography>
Time remaining: {convertTimeMsToTimeElapsedString(player.timeNeededToCompleteWork - player.timeWorked)}
</Typography>
<br />
<pre>{progressBar}</pre>
</Typography>
</Grid>
<Grid item>
<Button
onClick={() => {
workInfo = {
buttons: {
cancel: () => {
router.toLocation(Locations[LocationName.Slums]);
player.finishCrime(true);
}}
>
Cancel crime
</Button>
</Grid>
</Grid>
);
},
},
title: `You are attempting to ${player.crimeType}`,
progress: {
remaining: player.timeNeededToCompleteWork - player.timeWorked,
percentage: completion,
},
stopText: "Cancel crime",
};
break;
}
if (player.createProgramName !== "") {
case WorkType.CreateProgram: {
function cancel(): void {
player.finishCreateProgramWork(true);
router.toTerminal();
@ -467,31 +431,33 @@ export function WorkInProgressRoot(): React.ReactElement {
router.toTerminal();
player.stopFocusing();
}
return (
<Grid container direction="column" justifyContent="center" alignItems="center" style={{ minHeight: "100vh" }}>
<Grid item>
<Typography>
You are currently working on coding {player.createProgramName}.<br />
<br />
You have been working for {convertTimeMsToTimeElapsedString(player.timeWorked)}
<br />
<br />
The program is {((player.timeWorkedCreateProgram / player.timeNeededToCompleteWork) * 100).toFixed(2)}
% complete. <br />
If you cancel, your work will be saved and you can come back to complete the program later.
</Typography>
</Grid>
<Grid item>
<Button sx={{ mx: 2 }} onClick={cancel}>
Cancel work on creating program
</Button>
<Button onClick={unfocus}>Do something else simultaneously</Button>
</Grid>
</Grid>
);
const completion = (player.timeWorkedCreateProgram / player.timeNeededToCompleteWork) * 100;
workInfo = {
buttons: {
cancel: cancel,
unfocus: unfocus,
},
title: (
<>
You are currently working on coding <b>{player.createProgramName}</b>
</>
),
progress: {
elapsed: player.timeWorked,
percentage: completion,
},
stopText: "Stop creating program",
stopTooltip: "Your work will be saved and you can return to complete the program later.",
};
break;
}
if (player.graftAugmentationName !== "") {
case WorkType.GraftAugmentation: {
function cancel(): void {
player.finishGraftAugmentationWork(true);
router.toTerminal();
@ -500,34 +466,111 @@ export function WorkInProgressRoot(): React.ReactElement {
router.toTerminal();
player.stopFocusing();
}
return (
<Grid container direction="column" justifyContent="center" alignItems="center" style={{ minHeight: "100vh" }}>
<Grid item>
<Typography>
You are currently working on grafting {player.graftAugmentationName}.
<br />
<br />
You have been working for {convertTimeMsToTimeElapsedString(player.timeWorked)}
<br />
<br />
The augmentation is{" "}
{((player.timeWorkedGraftAugmentation / player.timeNeededToCompleteWork) * 100).toFixed(2)}% done being
crafted.
<br />
If you cancel, your work will <b>not</b> be saved, and the money you spent will <b>not</b> be returned.
</Typography>
</Grid>
<Grid item>
<Button sx={{ mx: 2 }} onClick={cancel}>
Cancel work on grafting Augmentation
</Button>
<Button onClick={unfocus}>Do something else simultaneously</Button>
</Grid>
</Grid>
);
const completion = (player.timeWorkedGraftAugmentation / player.timeNeededToCompleteWork) * 100;
workInfo = {
buttons: {
cancel: cancel,
unfocus: unfocus,
},
title: (
<>
You are currently working on grafting <b>{player.graftAugmentationName}</b>
</>
),
progress: {
elapsed: player.timeWorked,
percentage: completion,
},
stopText: "Stop grafting",
stopTooltip: (
<>
If you cancel, your work will <b>not</b> be saved, and the money you spent will <b>not</b> be returned
</>
),
};
break;
}
if (!player.workType) router.toTerminal();
default:
router.toTerminal();
workInfo = null;
}
if (workInfo === null) {
return <></>;
}
const tooltipInfo =
typeof workInfo?.stopTooltip === "string" ? (
<Typography>{workInfo.stopTooltip}</Typography>
) : (
workInfo.stopTooltip || <></>
);
return (
<Container
maxWidth="md"
sx={{ display: "flex", flexDirection: "column", justifyContent: "center", height: "calc(100vh - 16px)" }}
>
<Paper sx={{ p: 1, mb: 1 }}>
<Typography variant="h6">{workInfo.title}</Typography>
<Typography>{workInfo.description}</Typography>
{workInfo.gains && (
<Table sx={{ mt: 1 }}>
<TableBody>
{workInfo.gains.map((row) => (
<React.Fragment key={uniqueId()}>{row}</React.Fragment>
))}
</TableBody>
</Table>
)}
</Paper>
<Paper sx={{ mb: 1, p: 1 }}>
{workInfo.progress !== undefined && (
<Box sx={{ mb: 1 }}>
<Box
display="grid"
sx={{
gridTemplateColumns: `repeat(${Object.keys(workInfo.progress).length}, 1fr)`,
width: "100%",
justifyItems: "center",
textAlign: "center",
}}
>
{workInfo.progress.elapsed !== undefined && (
<Typography>{convertTimeMsToTimeElapsedString(workInfo.progress.elapsed)} elapsed</Typography>
)}
{workInfo.progress.remaining !== undefined && (
<Typography>{convertTimeMsToTimeElapsedString(workInfo.progress.remaining)} remaining</Typography>
)}
{workInfo.progress.percentage !== undefined && (
<Typography>{workInfo.progress.percentage.toFixed(2)}% done</Typography>
)}
</Box>
{workInfo.progress.percentage !== undefined && (
<ProgressBar variant="determinate" value={workInfo.progress.percentage} color="primary" />
)}
</Box>
)}
<Box display="grid" sx={{ gridTemplateColumns: `repeat(${Object.keys(workInfo.buttons).length}, 1fr)` }}>
{workInfo.stopTooltip ? (
<Tooltip title={tooltipInfo}>
<Button onClick={workInfo.buttons.cancel}>{workInfo.stopText}</Button>
</Tooltip>
) : (
<Button onClick={workInfo.buttons.cancel}>{workInfo.stopText}</Button>
)}
{workInfo.buttons.unfocus && (
<Button onClick={workInfo.buttons.unfocus}>Do something else simultaneously</Button>
)}
</Box>
</Paper>
</Container>
);
}

49
src/utils/WorkType.ts Normal file

@ -0,0 +1,49 @@
export enum WorkType {
None = "",
Company = "Working for Company",
CompanyPartTime = "Working for Company part-time",
Faction = "Working for Faction",
CreateProgram = "Working on Create a Program",
StudyClass = "Studying or Taking a class at university",
Crime = "Committing a crime",
GraftAugmentation = "Grafting an Augmentation",
}
export enum PlayerFactionWorkType {
None = "",
Hacking = "Faction Hacking Work",
Field = "Faction Field Work",
Security = "Faction Security Work",
}
export enum ClassType {
None = "",
StudyComputerScience = "studying Computer Science",
DataStructures = "taking a Data Structures course",
Networks = "taking a Networks course",
Algorithms = "taking an Algorithms course",
Management = "taking a Management course",
Leadership = "taking a Leadership course",
GymStrength = "training your strength at a gym",
GymDefense = "training your defense at a gym",
GymDexterity = "training your dexterity at a gym",
GymAgility = "training your agility at a gym",
}
export enum CrimeType {
None = "",
Shoplift = "shoplift",
RobStore = "rob a store",
Mug = "mug someone",
Larceny = "commit larceny",
Drugs = "deal drugs",
BondForgery = "forge corporate bonds",
TraffickArms = "traffick illegal arms",
Homicide = "commit homicide",
GrandTheftAuto = "commit grand theft auto",
Kidnap = "kidnap someone for ransom",
Assassination = "assassinate a high-profile target",
Heist = "pull off the ultimate heist",
}