Convert crime to new work model

This commit is contained in:
Olivier Gagnon 2022-07-07 02:00:23 -04:00
parent 7d263e4223
commit 3ee7d593d0
12 changed files with 238 additions and 292 deletions

@ -4,6 +4,7 @@ import { IPerson } from "../PersonObjects/IPerson";
import { IRouter } from "../ui/Router";
import { WorkerScript } from "../Netscript/WorkerScript";
import { CrimeType } from "../utils/WorkType";
import { CrimeWork } from "../Work/CrimeWork";
interface IConstructorParams {
hacking_success_weight?: number;
@ -100,19 +101,13 @@ export class Crime {
if (div <= 0) {
div = 1;
}
p.startCrime(
router,
this.type,
this.hacking_exp / div,
this.strength_exp / div,
this.defense_exp / div,
this.dexterity_exp / div,
this.agility_exp / div,
this.charisma_exp / div,
this.money / div,
this.time,
workerScript,
p.startNEWWork(
new CrimeWork({
crimeType: this.type,
singularity: workerScript !== null,
}),
);
router.toWork();
return this.time;
}

@ -2421,7 +2421,6 @@ export function NetscriptFunctions(workerScript: WorkerScript): NS {
createProgramName: Player.createProgramName,
createProgramReqLvl: Player.createProgramReqLvl,
className: Player.className,
crimeType: Player.crimeType,
work_money_mult: Player.work_money_mult,
hacknet_node_money_mult: Player.hacknet_node_money_mult,
hacknet_node_purchase_cost_mult: Player.hacknet_node_purchase_cost_mult,

@ -32,6 +32,7 @@ import { ISkillProgress } from "./formulas/skill";
import { PlayerAchievement } from "../Achievements/Achievements";
import { IPerson } from "./IPerson";
import { WorkType, ClassType, CrimeType } from "../utils/WorkType";
import { Work } from "src/Work/Work";
export interface IPlayer extends IPerson {
bitNodeN: number;
@ -124,15 +125,13 @@ export interface IPlayer extends IPerson {
bladeburner_analysis_mult: number;
bladeburner_success_chance_mult: number;
currentWork: Work | null;
createProgramReqLvl: number;
factionWorkType: string;
createProgramName: string;
timeWorkedCreateProgram: number;
graftAugmentationName: string;
timeWorkedGraftAugmentation: number;
crimeType: CrimeType;
committingCrimeThruSingFn: boolean;
singFnCrimeWorkerScript: WorkerScript | null;
timeNeededToCompleteWork: number;
focus: boolean;
className: ClassType;
@ -163,6 +162,9 @@ export interface IPlayer extends IPerson {
entropy: number;
// Methods
startNEWWork(w: Work): void;
processNEWWork(cycles: number): void;
finishNEWWork(cancelled: boolean): void;
work(numCycles: number): boolean;
workPartTime(numCycles: number): boolean;
workForFaction(numCycles: number): boolean;
@ -213,19 +215,6 @@ export interface IPlayer extends IPerson {
startFactionWork(faction: Faction): void;
startClass(costMult: number, expMult: number, className: ClassType): void;
startCorporation(corpName: string, additionalShares?: number): void;
startCrime(
router: IRouter,
crimeType: CrimeType,
hackExp: number,
strExp: number,
defExp: number,
dexExp: number,
agiExp: number,
chaExp: number,
money: number,
time: number,
singParams: any,
): void;
startFactionFieldWork(faction: Faction): void;
startFactionHackWork(faction: Faction): void;
startFactionSecurityWork(faction: Faction): void;
@ -251,7 +240,6 @@ export interface IPlayer extends IPerson {
finishWork(cancelled: boolean, sing?: boolean): string;
cancelationPenalty(): number;
finishWorkPartTime(sing?: boolean): string;
finishCrime(cancelled: boolean): string;
finishCreateProgramWork(cancelled: boolean): string;
resetMultipliers(): void;
prestigeAugmentation(): void;
@ -270,7 +258,6 @@ export interface IPlayer extends IPerson {
hospitalize(): void;
createProgramWork(numCycles: number): boolean;
takeClass(numCycles: number): boolean;
commitCrime(numCycles: number): boolean;
checkForFactionInvitations(): Faction[];
setBitNodeNumber(n: number): void;
getMult(name: string): number;

@ -4,6 +4,7 @@ import * as corporationMethods from "./PlayerObjectCorporationMethods";
import * as gangMethods from "./PlayerObjectGangMethods";
import * as generalMethods from "./PlayerObjectGeneralMethods";
import * as serverMethods from "./PlayerObjectServerMethods";
import * as workMethods from "./PlayerObjectWorkMethods";
import { IMap } from "../../types";
import { Sleeve } from "../Sleeve/Sleeve";
@ -40,6 +41,7 @@ import { getRandomInt } from "../../utils/helpers/getRandomInt";
import { ITaskTracker } from "../ITaskTracker";
import { CONSTANTS } from "../../Constants";
import { WorkType, ClassType, CrimeType, PlayerFactionWorkType } from "../../utils/WorkType";
import { Work } from "src/Work/Work";
export class PlayerObject implements IPlayer {
// Class members
@ -136,15 +138,13 @@ export class PlayerObject implements IPlayer {
bladeburner_analysis_mult: number;
bladeburner_success_chance_mult: number;
currentWork: Work | null;
createProgramReqLvl: number;
factionWorkType: PlayerFactionWorkType;
createProgramName: string;
timeWorkedCreateProgram: number;
graftAugmentationName: string;
timeWorkedGraftAugmentation: number;
crimeType: CrimeType;
committingCrimeThruSingFn: boolean;
singFnCrimeWorkerScript: WorkerScript | null;
timeNeededToCompleteWork: number;
focus: boolean;
className: ClassType;
@ -175,6 +175,9 @@ export class PlayerObject implements IPlayer {
entropy: number;
// Methods
startNEWWork: (w: Work) => void;
processNEWWork: (cycles: number) => void;
finishNEWWork: (cancelled: boolean) => void;
work: (numCycles: number) => boolean;
workPartTime: (numCycles: number) => boolean;
workForFaction: (numCycles: number) => boolean;
@ -234,19 +237,6 @@ export class PlayerObject implements IPlayer {
startFactionWork: (faction: Faction) => void;
startClass: (costMult: number, expMult: number, className: ClassType) => void;
startCorporation: (corpName: string, additionalShares?: number) => void;
startCrime: (
router: IRouter,
crimeType: CrimeType,
hackExp: number,
strExp: number,
defExp: number,
dexExp: number,
agiExp: number,
chaExp: number,
money: number,
time: number,
singParams: any,
) => void;
startFactionFieldWork: (faction: Faction) => void;
startFactionHackWork: (faction: Faction) => void;
startFactionSecurityWork: (faction: Faction) => void;
@ -276,7 +266,6 @@ export class PlayerObject implements IPlayer {
finishWork: (cancelled: boolean, sing?: boolean) => string;
cancelationPenalty: () => number;
finishWorkPartTime: (sing?: boolean) => string;
finishCrime: (cancelled: boolean) => string;
finishCreateProgramWork: (cancelled: boolean) => string;
resetMultipliers: () => void;
prestigeAugmentation: () => void;
@ -296,7 +285,6 @@ export class PlayerObject implements IPlayer {
hospitalize: () => void;
createProgramWork: (numCycles: number) => boolean;
takeClass: (numCycles: number) => boolean;
commitCrime: (numCycles: number) => boolean;
checkForFactionInvitations: () => Faction[];
setBitNodeNumber: (n: number) => void;
getMult: (name: string) => number;
@ -435,8 +423,6 @@ export class PlayerObject implements IPlayer {
this.className = ClassType.None;
this.crimeType = CrimeType.None;
this.timeWorked = 0; //in m;
this.timeWorkedCreateProgram = 0;
this.timeNeededToCompleteWork = 0;
@ -495,6 +481,8 @@ export class PlayerObject implements IPlayer {
this.achievements = [];
this.terminalCommandHistory = [];
this.currentWork = null;
// Let's get a hash of some semi-random stuff so we have something unique.
this.identifier = cyrb53(
"I-" +
@ -532,6 +520,9 @@ export class PlayerObject implements IPlayer {
this.processWorkEarnings = generalMethods.processWorkEarnings;
this.startWork = generalMethods.startWork;
this.cancelationPenalty = generalMethods.cancelationPenalty;
this.startNEWWork = workMethods.start;
this.processNEWWork = workMethods.process;
this.finishNEWWork = workMethods.finish;
this.work = generalMethods.work;
this.finishWork = generalMethods.finishWork;
this.startWorkPartTime = generalMethods.startWorkPartTime;
@ -563,9 +554,6 @@ export class PlayerObject implements IPlayer {
this.startClass = generalMethods.startClass;
this.takeClass = generalMethods.takeClass;
this.finishClass = generalMethods.finishClass;
this.startCrime = generalMethods.startCrime;
this.commitCrime = generalMethods.commitCrime;
this.finishCrime = generalMethods.finishCrime;
this.singularityStopWork = generalMethods.singularityStopWork;
this.takeDamage = generalMethods.takeDamage;
this.regenerateHp = generalMethods.regenerateHp;
@ -623,8 +611,6 @@ export class PlayerObject implements IPlayer {
this.getUpgradeHomeCoresCost = serverMethods.getUpgradeHomeCoresCost;
this.createHacknetServer = serverMethods.createHacknetServer;
this.factionWorkType = PlayerFactionWorkType.None;
this.committingCrimeThruSingFn = false;
this.singFnCrimeWorkerScript = null;
this.getMult = generalMethods.getMult;
this.setMult = generalMethods.setMult;

@ -146,7 +146,6 @@ export function prestigeAugmentation(this: PlayerObject): void {
this.currentWorkFactionDescription = "";
this.createProgramName = "";
this.className = ClassType.None;
this.crimeType = CrimeType.None;
this.workHackExpGainRate = 0;
this.workStrExpGainRate = 0;
@ -615,10 +614,6 @@ export function process(this: IPlayer, router: IRouter, numCycles = 1): void {
if (this.takeClass(numCycles)) {
router.toCity();
}
} else if (this.workType === WorkType.Crime) {
if (this.commitCrime(numCycles)) {
router.toLocation(Locations[LocationName.Slums]);
}
} else if (this.workType === WorkType.CompanyPartTime) {
if (this.workPartTime(numCycles)) {
router.toCity();
@ -1330,10 +1325,7 @@ export function finishCreateProgramWork(this: IPlayer, cancelled: boolean): stri
if (!cancelled) {
//Complete case
this.gainIntelligenceExp((CONSTANTS.IntelligenceProgramBaseExpGain * this.timeWorked) / 1000);
const lines = [
`You've finished creating ${programName}!`,
"The new program can be found on your home computer.",
];
const lines = [`You've finished creating ${programName}!`, "The new program can be found on your home computer."];
dialogBoxCreate(lines.join("<br>"));
message = lines.join(" ");
@ -1501,196 +1493,6 @@ export function finishClass(this: IPlayer, sing = false): string {
return "";
}
//The EXP and $ gains are hardcoded. Time is in ms
export function startCrime(
this: IPlayer,
router: IRouter,
crimeType: CrimeType,
hackExp: number,
strExp: number,
defExp: number,
dexExp: number,
agiExp: number,
chaExp: number,
money: number,
time: number,
workerscript: WorkerScript | null = null,
): void {
this.crimeType = crimeType;
this.resetWorkStatus();
this.isWorking = true;
this.focus = true;
this.workType = WorkType.Crime;
if (workerscript !== null) {
this.committingCrimeThruSingFn = true;
this.singFnCrimeWorkerScript = workerscript;
}
this.workHackExpGained = hackExp * this.hacking_exp_mult * BitNodeMultipliers.CrimeExpGain;
this.workStrExpGained = strExp * this.strength_exp_mult * BitNodeMultipliers.CrimeExpGain;
this.workDefExpGained = defExp * this.defense_exp_mult * BitNodeMultipliers.CrimeExpGain;
this.workDexExpGained = dexExp * this.dexterity_exp_mult * BitNodeMultipliers.CrimeExpGain;
this.workAgiExpGained = agiExp * this.agility_exp_mult * BitNodeMultipliers.CrimeExpGain;
this.workChaExpGained = chaExp * this.charisma_exp_mult * BitNodeMultipliers.CrimeExpGain;
this.workMoneyGained = money * this.crime_money_mult * BitNodeMultipliers.CrimeMoney;
this.timeNeededToCompleteWork = time;
router.toWork();
}
export function commitCrime(this: IPlayer, numCycles: number): boolean {
this.timeWorked += CONSTANTS._idleSpeed * numCycles;
if (this.timeWorked >= this.timeNeededToCompleteWork) {
this.finishCrime(false);
return true;
}
return false;
}
export function finishCrime(this: IPlayer, cancelled: boolean): string {
//Determine crime success/failure
if (!cancelled) {
if (determineCrimeSuccess(this, this.crimeType)) {
//Handle Karma and crime statistics
let crime = null;
for (const i of Object.keys(Crimes)) {
if (Crimes[i].type == this.crimeType) {
crime = Crimes[i];
break;
}
}
if (crime == null) {
dialogBoxCreate(
`ERR: Unrecognized crime type (${this.crimeType}). This is probably a bug please contact the developer`,
);
return "";
}
this.gainMoney(this.workMoneyGained, "crime");
this.karma -= crime.karma;
this.numPeopleKilled += crime.kills;
if (crime.intelligence_exp > 0) {
this.gainIntelligenceExp(crime.intelligence_exp);
}
//On a crime success, gain 2x exp
this.workHackExpGained *= 2;
this.workStrExpGained *= 2;
this.workDefExpGained *= 2;
this.workDexExpGained *= 2;
this.workAgiExpGained *= 2;
this.workChaExpGained *= 2;
const ws = this.singFnCrimeWorkerScript;
if (this.committingCrimeThruSingFn && ws !== null) {
if (ws.disableLogs.ALL == null && ws.disableLogs.commitCrime == null) {
ws.scriptRef.log(
"SUCCESS: Crime successful! Gained " +
numeralWrapper.formatMoney(this.workMoneyGained) +
", " +
numeralWrapper.formatExp(this.workHackExpGained) +
" hack exp, " +
numeralWrapper.formatExp(this.workStrExpGained) +
" str exp, " +
numeralWrapper.formatExp(this.workDefExpGained) +
" def exp, " +
numeralWrapper.formatExp(this.workDexExpGained) +
" dex exp, " +
numeralWrapper.formatExp(this.workAgiExpGained) +
" agi exp, " +
numeralWrapper.formatExp(this.workChaExpGained) +
" cha exp.",
);
}
} else {
dialogBoxCreate(
<>
Crime successful!
<br />
<br />
You gained:
<br />
<Money money={this.workMoneyGained} />
<br />
{numeralWrapper.formatExp(this.workHackExpGained)} hacking experience <br />
{numeralWrapper.formatExp(this.workStrExpGained)} strength experience
<br />
{numeralWrapper.formatExp(this.workDefExpGained)} defense experience
<br />
{numeralWrapper.formatExp(this.workDexExpGained)} dexterity experience
<br />
{numeralWrapper.formatExp(this.workAgiExpGained)} agility experience
<br />
{numeralWrapper.formatExp(this.workChaExpGained)} charisma experience
</>,
);
}
} else {
//Exp halved on failure
this.workHackExpGained /= 2;
this.workStrExpGained /= 2;
this.workDefExpGained /= 2;
this.workDexExpGained /= 2;
this.workAgiExpGained /= 2;
this.workChaExpGained /= 2;
const ws = this.singFnCrimeWorkerScript;
if (this.committingCrimeThruSingFn && ws !== null) {
if (ws.disableLogs.ALL == null && ws.disableLogs.commitCrime == null) {
ws.scriptRef.log(
"FAIL: Crime failed! Gained " +
numeralWrapper.formatExp(this.workHackExpGained) +
" hack exp, " +
numeralWrapper.formatExp(this.workStrExpGained) +
" str exp, " +
numeralWrapper.formatExp(this.workDefExpGained) +
" def exp, " +
numeralWrapper.formatExp(this.workDexExpGained) +
" dex exp, " +
numeralWrapper.formatExp(this.workAgiExpGained) +
" agi exp, " +
numeralWrapper.formatExp(this.workChaExpGained) +
" cha exp.",
);
}
} else {
dialogBoxCreate(
<>
Crime failed!
<br />
<br />
You gained:
<br />
{numeralWrapper.formatExp(this.workHackExpGained)} hacking experience <br />
{numeralWrapper.formatExp(this.workStrExpGained)} strength experience
<br />
{numeralWrapper.formatExp(this.workDefExpGained)} defense experience
<br />
{numeralWrapper.formatExp(this.workDexExpGained)} dexterity experience
<br />
{numeralWrapper.formatExp(this.workAgiExpGained)} agility experience
<br />
{numeralWrapper.formatExp(this.workChaExpGained)} charisma experience
</>,
);
}
}
this.gainHackingExp(this.workHackExpGained);
this.gainStrengthExp(this.workStrExpGained);
this.gainDefenseExp(this.workDefExpGained);
this.gainDexterityExp(this.workDexExpGained);
this.gainAgilityExp(this.workAgiExpGained);
this.gainCharismaExp(this.workChaExpGained);
}
this.committingCrimeThruSingFn = false;
this.singFnCrimeWorkerScript = null;
this.isWorking = false;
this.crimeType = CrimeType.None;
this.resetWorkStatus();
return "";
}
//Cancels the player's current "work" assignment and gives the proper rewards
//Used only for Singularity functions, so no popups are created
export function singularityStopWork(this: IPlayer): string {
@ -1714,9 +1516,6 @@ export function singularityStopWork(this: IPlayer): string {
case WorkType.CreateProgram:
res = this.finishCreateProgramWork(true);
break;
case WorkType.Crime:
res = this.finishCrime(true);
break;
case WorkType.GraftAugmentation:
res = this.finishGraftAugmentationWork(true, true);
break;

@ -0,0 +1,21 @@
import { Work } from "../../Work/Work";
import { IPlayer } from "../IPlayer";
export function start(this: IPlayer, w: Work): void {
if (this.currentWork !== null) {
this.currentWork.finish(this, true);
}
this.currentWork = w;
}
export function process(this: IPlayer, cycles = 1): void {
if (this.currentWork === null) return;
const finished = this.currentWork.process(this, cycles);
if (finished) {
this.finishNEWWork(false);
}
}
export function finish(this: IPlayer, cancelled: boolean): void {
if (this.currentWork === null) return;
this.currentWork.finish(this, cancelled);
this.currentWork = null;
}

@ -71,7 +71,6 @@ interface Player {
createProgramName: string;
createProgramReqLvl: number;
className: string;
crimeType: string;
work_money_mult: number;
hacknet_node_money_mult: number;
hacknet_node_purchase_cost_mult: number;

139
src/Work/CrimeWork.tsx Normal file

@ -0,0 +1,139 @@
import React from "react";
import { Reviver, Generic_toJSON, Generic_fromJSON } from "../utils/JSONReviver";
import { Crime } from "../Crime/Crime";
import { CONSTANTS } from "../Constants";
import { determineCrimeSuccess } from "../Crime/CrimeHelpers";
import { Crimes } from "../Crime/Crimes";
import { IPlayer } from "../PersonObjects/IPlayer";
import { numeralWrapper } from "../ui/numeralFormat";
import { dialogBoxCreate } from "../ui/React/DialogBox";
import { Money } from "../ui/React/Money";
import { CrimeType, WorkType } from "../utils/WorkType";
import { Work } from "./Work";
interface CrimeWorkParams {
crimeType: CrimeType;
singularity: boolean;
}
export const isCrimeWork = (w: Work): w is CrimeWork => w.type === WorkType.Crime;
export class CrimeWork extends Work {
type = WorkType.Crime;
crimeType: CrimeType;
cyclesWorked: number;
singularity: boolean;
constructor(params?: CrimeWorkParams) {
super();
this.crimeType = params?.crimeType ?? CrimeType.Shoplift;
this.singularity = params?.singularity ?? false;
this.cyclesWorked = 0;
}
getCrime(): Crime {
const crime = Object.values(Crimes).find((c) => c.type === this.crimeType);
if (!crime) throw new Error("CrimeWork object constructed with invalid crime type");
return crime;
}
process(player: IPlayer, cycles = 1): boolean {
this.cyclesWorked += cycles;
const time = Object.values(Crimes).find((c) => c.type === this.crimeType)?.time ?? 0;
return this.cyclesWorked * CONSTANTS._idleSpeed >= time;
}
finish(player: IPlayer, cancelled: boolean): void {
if (cancelled) return;
let crime = null;
for (const i of Object.keys(Crimes)) {
if (Crimes[i].type == this.crimeType) {
crime = Crimes[i];
break;
}
}
if (crime == null) {
dialogBoxCreate(
`ERR: Unrecognized crime type (${this.crimeType}). This is probably a bug please contact the developer`,
);
return;
}
// exp times 2 because were trying to maintain the same numbers as before the conversion
// Technically the definition of Crimes should have the success numbers and failure should divide by 4
let hackExp = crime.hacking_exp * 2;
let StrExp = crime.strength_exp * 2;
let DefExp = crime.defense_exp * 2;
let DexExp = crime.dexterity_exp * 2;
let AgiExp = crime.agility_exp * 2;
let ChaExp = crime.charisma_exp * 2;
let karma = crime.karma;
const success = determineCrimeSuccess(player, crime.type);
if (success) {
player.gainMoney(crime.money, "crime");
player.numPeopleKilled += crime.kills;
player.gainIntelligenceExp(crime.intelligence_exp);
} else {
hackExp /= 4;
StrExp /= 4;
DefExp /= 4;
DexExp /= 4;
AgiExp /= 4;
ChaExp /= 4;
karma /= 4;
}
player.gainHackingExp(hackExp);
player.gainStrengthExp(StrExp);
player.gainDefenseExp(DefExp);
player.gainDexterityExp(DexExp);
player.gainAgilityExp(AgiExp);
player.gainCharismaExp(ChaExp);
player.karma -= karma;
if (!this.singularity) {
dialogBoxCreate(
<>
Crime {success ? "successful" : "failed"}!
<br />
<br />
You gained:
{success && (
<>
<br />
<Money money={crime.money} />
</>
)}
<br />
{numeralWrapper.formatExp(hackExp)} hacking experience <br />
{numeralWrapper.formatExp(StrExp)} strength experience
<br />
{numeralWrapper.formatExp(DefExp)} defense experience
<br />
{numeralWrapper.formatExp(DexExp)} dexterity experience
<br />
{numeralWrapper.formatExp(AgiExp)} agility experience
<br />
{numeralWrapper.formatExp(ChaExp)} charisma experience
</>,
);
}
}
/**
* Serialize the current object to a JSON save state.
*/
toJSON(): any {
return Generic_toJSON("CrimeWork", this);
}
/**
* Initiatizes a CrimeWork object from a JSON save state.
*/
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
static fromJSON(value: any): CrimeWork {
return Generic_fromJSON(CrimeWork, value.data);
}
}
Reviver.constructors.CrimeWork = CrimeWork;

9
src/Work/Work.ts Normal file

@ -0,0 +1,9 @@
import { IPlayer } from "src/PersonObjects/IPlayer";
import { WorkType } from "src/utils/WorkType";
export abstract class Work {
abstract type: WorkType;
abstract process(player: IPlayer, cycles: number): boolean;
abstract finish(player: IPlayer, cancelled: boolean): void;
}

@ -96,7 +96,11 @@ const Engine: {
Terminal.process(Router, Player, numCycles);
if (Player.currentWork !== null) {
Player.processNEWWork(numCycles);
} else {
Player.process(Router, numCycles);
}
// Update stock prices
if (Player.hasWseAccount) {
@ -293,7 +297,9 @@ const Engine: {
Player.gainMoney(offlineHackingIncome, "hacking");
// Process offline progress
loadAllRunningScripts(Player); // This also takes care of offline production for those scripts
if (Player.isWorking) {
if (Player.currentWork !== null) {
Player.processNEWWork(numCyclesOffline);
} else if (Player.isWorking) {
Player.focus = true;
switch (Player.workType) {
case WorkType.Faction:
@ -305,9 +311,6 @@ const Engine: {
case WorkType.StudyClass:
Player.takeClass(numCyclesOffline);
break;
case WorkType.Crime:
Player.commitCrime(numCyclesOffline);
break;
case WorkType.CompanyPartTime:
Player.workPartTime(numCyclesOffline);
break;

@ -154,7 +154,7 @@ export let Router: IRouter = {
function determineStartPage(player: IPlayer): Page {
if (RecoveryMode) return Page.Recovery;
if (player.isWorking) return Page.Work;
if (player.isWorking || player.currentWork !== null) return Page.Work;
return Page.Terminal;
}

@ -20,6 +20,7 @@ import { Reputation } from "./React/Reputation";
import { ReputationRate } from "./React/ReputationRate";
import { StatsRow } from "./React/StatsRow";
import { WorkType, ClassType } from "../utils/WorkType";
import { isCrimeWork } from "../Work/CrimeWork";
const CYCLES_PER_SEC = 1000 / CONSTANTS.MilliPerCycle;
@ -137,7 +138,37 @@ export function WorkInProgressRoot(): React.ReactElement {
),
];
let workInfo: IWorkInfo | null;
let workInfo: IWorkInfo = {
buttons: {
cancel: () => undefined,
},
title: "",
stopText: "",
};
if (player.currentWork !== null) {
if (isCrimeWork(player.currentWork)) {
const crime = player.currentWork.getCrime();
const completion = Math.round(((player.currentWork.cyclesWorked * CONSTANTS._idleSpeed) / crime.time) * 100);
workInfo = {
buttons: {
cancel: () => {
router.toLocation(Locations[LocationName.Slums]);
player.finishNEWWork(true);
},
},
title: `You are attempting to ${crime.type}`,
progress: {
remaining: crime.time - player.currentWork.cyclesWorked * CONSTANTS._idleSpeed,
percentage: completion,
},
stopText: "Cancel crime",
};
}
}
switch (player.workType) {
case WorkType.Faction: {
@ -399,29 +430,6 @@ export function WorkInProgressRoot(): React.ReactElement {
break;
}
case WorkType.Crime: {
const completion = Math.round((player.timeWorked / player.timeNeededToCompleteWork) * 100);
workInfo = {
buttons: {
cancel: () => {
router.toLocation(Locations[LocationName.Slums]);
player.finishCrime(true);
},
},
title: `You are attempting to ${player.crimeType}`,
progress: {
remaining: player.timeNeededToCompleteWork - player.timeWorked,
percentage: completion,
},
stopText: "Cancel crime",
};
break;
}
case WorkType.CreateProgram: {
function cancel(): void {
player.finishCreateProgramWork(true);
@ -497,11 +505,12 @@ export function WorkInProgressRoot(): React.ReactElement {
}
default:
if (player.currentWork === null) {
router.toTerminal();
workInfo = null;
}
}
if (workInfo === null) {
if (workInfo.title === "") {
return <></>;
}