diff --git a/src/Faction/FactionHelpers.tsx b/src/Faction/FactionHelpers.tsx index d91c5cad7..0237d6e6a 100644 --- a/src/Faction/FactionHelpers.tsx +++ b/src/Faction/FactionHelpers.tsx @@ -19,6 +19,7 @@ import { dialogBoxCreate } from "../ui/React/DialogBox"; import { InvitationEvent } from "./ui/InvitationModal"; import { FactionNames } from "./data/FactionNames"; import { SFC32RNG } from "../Casino/RNG"; +import { isFactionWork } from "../Work/FactionWork"; export function inviteToFaction(faction: Faction): void { Player.receiveInvite(faction.name); @@ -113,7 +114,7 @@ export function purchaseAugmentation(aug: Augmentation, fac: Faction, sing = fal export function processPassiveFactionRepGain(numCycles: number): void { for (const name of Object.keys(Factions)) { - if (name === Player.currentWorkFactionName) continue; + if (isFactionWork(Player.currentWork) && name === Player.currentWork.factionName) continue; if (!Factions.hasOwnProperty(name)) continue; const faction = Factions[name]; if (!faction.isMember) continue; diff --git a/src/Faction/FactionWorkTypeEnum.ts b/src/Faction/FactionWorkTypeEnum.ts deleted file mode 100644 index 40374c360..000000000 --- a/src/Faction/FactionWorkTypeEnum.ts +++ /dev/null @@ -1,6 +0,0 @@ -export enum FactionWorkType { - Field, - Hacking, - None, - Security, -} diff --git a/src/Faction/ui/FactionRoot.tsx b/src/Faction/ui/FactionRoot.tsx index bcb37a563..213a697a5 100644 --- a/src/Faction/ui/FactionRoot.tsx +++ b/src/Faction/ui/FactionRoot.tsx @@ -21,6 +21,8 @@ import { Typography, Button } from "@mui/material"; import { CovenantPurchasesRoot } from "../../PersonObjects/Sleeve/ui/CovenantPurchasesRoot"; import { FactionNames } from "../data/FactionNames"; import { GangButton } from "./GangButton"; +import { FactionWork } from "../../Work/FactionWork"; +import { FactionWorkType } from "../../Work/data/FactionWorkType"; type IProps = { faction: Faction; @@ -67,17 +69,35 @@ function MainPage({ faction, rerender, onAugmentations }: IMainProps): React.Rea } function startFieldWork(faction: Faction): void { - player.startFactionFieldWork(faction); + player.startNEWWork( + new FactionWork({ + singularity: false, + faction: faction.name, + factionWorkType: FactionWorkType.HACKING, + }), + ); startWork(); } function startHackingContracts(faction: Faction): void { - player.startFactionHackWork(faction); + player.startNEWWork( + new FactionWork({ + singularity: false, + faction: faction.name, + factionWorkType: FactionWorkType.HACKING, + }), + ); startWork(); } function startSecurityWork(faction: Faction): void { - player.startFactionSecurityWork(faction); + player.startNEWWork( + new FactionWork({ + singularity: false, + faction: faction.name, + factionWorkType: FactionWorkType.HACKING, + }), + ); startWork(); } diff --git a/src/NetscriptFunctions.ts b/src/NetscriptFunctions.ts index 74565c368..1d0005f64 100644 --- a/src/NetscriptFunctions.ts +++ b/src/NetscriptFunctions.ts @@ -2399,8 +2399,6 @@ export function NetscriptFunctions(workerScript: WorkerScript): NS { crime_success_mult: Player.crime_success_mult, isWorking: Player.isWorking, workType: Player.workType, - currentWorkFactionName: Player.currentWorkFactionName, - currentWorkFactionDescription: Player.currentWorkFactionDescription, workHackExpGainRate: Player.workHackExpGainRate, workStrExpGainRate: Player.workStrExpGainRate, workDefExpGainRate: Player.workDefExpGainRate, diff --git a/src/NetscriptFunctions/Singularity.ts b/src/NetscriptFunctions/Singularity.ts index 1f0549dfc..ecd4d3247 100644 --- a/src/NetscriptFunctions/Singularity.ts +++ b/src/NetscriptFunctions/Singularity.ts @@ -52,6 +52,8 @@ import { FactionNames } from "../Faction/data/FactionNames"; import { WorkType } from "../utils/WorkType"; import { ClassWork, ClassType } from "../Work/ClassWork"; import { CreateProgramWork, isCreateProgramWork } from "../Work/CreateProgramWork"; +import { FactionWork } from "../Work/FactionWork"; +import { FactionWorkType } from "../Work/data/FactionWorkType"; export function NetscriptSingularity(player: IPlayer, workerScript: WorkerScript): InternalAPI { const getAugmentation = function (_ctx: NetscriptContext, name: string): Augmentation { @@ -1033,7 +1035,13 @@ export function NetscriptSingularity(player: IPlayer, workerScript: WorkerScript _ctx.log(() => `Faction '${faction.name}' do not need help with hacking contracts.`); return false; } - player.startFactionHackWork(faction); + player.startNEWWork( + new FactionWork({ + singularity: true, + factionWorkType: FactionWorkType.HACKING, + faction: faction.name, + }), + ); if (focus) { player.startFocusing(); Router.toWork(); @@ -1050,7 +1058,13 @@ export function NetscriptSingularity(player: IPlayer, workerScript: WorkerScript _ctx.log(() => `Faction '${faction.name}' do not need help with field missions.`); return false; } - player.startFactionFieldWork(faction); + player.startNEWWork( + new FactionWork({ + singularity: true, + factionWorkType: FactionWorkType.FIELD, + faction: faction.name, + }), + ); if (focus) { player.startFocusing(); Router.toWork(); @@ -1067,7 +1081,13 @@ export function NetscriptSingularity(player: IPlayer, workerScript: WorkerScript _ctx.log(() => `Faction '${faction.name}' do not need help with security work.`); return false; } - player.startFactionSecurityWork(faction); + player.startNEWWork( + new FactionWork({ + singularity: true, + factionWorkType: FactionWorkType.SECURITY, + faction: faction.name, + }), + ); if (focus) { player.startFocusing(); Router.toWork(); diff --git a/src/NetscriptFunctions/Sleeve.ts b/src/NetscriptFunctions/Sleeve.ts index bd3c604bd..c98d8b888 100644 --- a/src/NetscriptFunctions/Sleeve.ts +++ b/src/NetscriptFunctions/Sleeve.ts @@ -1,5 +1,4 @@ import { IPlayer } from "../PersonObjects/IPlayer"; -import { FactionWorkType } from "../Faction/FactionWorkTypeEnum"; import { SleeveTaskType } from "../PersonObjects/Sleeve/SleeveTaskTypesEnum"; import { findSleevePurchasableAugs } from "../PersonObjects/Sleeve/SleeveHelpers"; import { StaticAugmentations } from "../Augmentation/StaticAugmentations"; @@ -15,6 +14,7 @@ import { } from "../ScriptEditor/NetscriptDefinitions"; import { checkEnum } from "../utils/helpers/checkEnum"; import { InternalAPI, NetscriptContext } from "../Netscript/APIWrapper"; +import { FactionWorkType } from "../Work/data/FactionWorkType"; export function NetscriptSleeve(player: IPlayer): InternalAPI { const checkSleeveAPIAccess = function (ctx: NetscriptContext): void { diff --git a/src/PersonObjects/IPlayer.ts b/src/PersonObjects/IPlayer.ts index b5e57bc63..ba3400cee 100644 --- a/src/PersonObjects/IPlayer.ts +++ b/src/PersonObjects/IPlayer.ts @@ -125,14 +125,11 @@ export interface IPlayer extends IPerson { bladeburner_success_chance_mult: number; currentWork: Work | null; - factionWorkType: string; timeNeededToCompleteWork: number; focus: boolean; - currentWorkFactionName: string; workType: WorkType; workCostMult: number; workExpMult: number; - currentWorkFactionDescription: string; timeWorked: number; workMoneyGained: number; workMoneyGainRate: number; @@ -160,7 +157,6 @@ export interface IPlayer extends IPerson { finishNEWWork(cancelled: boolean): void; work(numCycles: number): boolean; workPartTime(numCycles: number): boolean; - workForFaction(numCycles: number): boolean; applyForAgentJob(sing?: boolean): boolean; applyForBusinessConsultantJob(sing?: boolean): boolean; applyForBusinessJob(sing?: boolean): boolean; @@ -205,11 +201,7 @@ export interface IPlayer extends IPerson { setMoney(amt: number): void; singularityStopWork(): string; startBladeburner(p: any): void; - startFactionWork(faction: Faction): void; startCorporation(corpName: string, additionalShares?: number): void; - startFactionFieldWork(faction: Faction): void; - startFactionHackWork(faction: Faction): void; - startFactionSecurityWork(faction: Faction): void; startFocusing(): void; startGang(facName: string, isHacking: boolean): void; startWork(companyName: string): void; @@ -226,7 +218,6 @@ export interface IPlayer extends IPerson { updateSkillLevels(): void; gainCodingContractReward(reward: ICodingContractReward, difficulty?: number): string; stopFocusing(): void; - finishFactionWork(cancelled: boolean, sing?: boolean): string; finishWork(cancelled: boolean, sing?: boolean): string; cancelationPenalty(): number; finishWorkPartTime(sing?: boolean): string; diff --git a/src/PersonObjects/Player/PlayerObject.ts b/src/PersonObjects/Player/PlayerObject.ts index 6dfd05c19..f44abcd81 100644 --- a/src/PersonObjects/Player/PlayerObject.ts +++ b/src/PersonObjects/Player/PlayerObject.ts @@ -39,7 +39,7 @@ import { cyrb53 } from "../../utils/StringHelperFunctions"; import { getRandomInt } from "../../utils/helpers/getRandomInt"; import { ITaskTracker } from "../ITaskTracker"; import { CONSTANTS } from "../../Constants"; -import { WorkType, PlayerFactionWorkType } from "../../utils/WorkType"; +import { WorkType } from "../../utils/WorkType"; import { Work } from "src/Work/Work"; export class PlayerObject implements IPlayer { @@ -138,14 +138,11 @@ export class PlayerObject implements IPlayer { bladeburner_success_chance_mult: number; currentWork: Work | null; - factionWorkType: PlayerFactionWorkType; timeNeededToCompleteWork: number; focus: boolean; - currentWorkFactionName: string; workType: WorkType; workCostMult: number; workExpMult: number; - currentWorkFactionDescription: string; timeWorked: number; workMoneyGained: number; workMoneyGainRate: number; @@ -173,7 +170,6 @@ export class PlayerObject implements IPlayer { finishNEWWork: (cancelled: boolean) => void; work: (numCycles: number) => boolean; workPartTime: (numCycles: number) => boolean; - workForFaction: (numCycles: number) => boolean; applyForAgentJob: (sing?: boolean) => boolean; applyForBusinessConsultantJob: (sing?: boolean) => boolean; applyForBusinessJob: (sing?: boolean) => boolean; @@ -227,11 +223,7 @@ export class PlayerObject implements IPlayer { setMoney: (amt: number) => void; singularityStopWork: () => string; startBladeburner: (p: any) => void; - startFactionWork: (faction: Faction) => void; startCorporation: (corpName: string, additionalShares?: number) => void; - startFactionFieldWork: (faction: Faction) => void; - startFactionHackWork: (faction: Faction) => void; - startFactionSecurityWork: (faction: Faction) => void; startFocusing: () => void; startGang: (facName: string, isHacking: boolean) => void; startWork: (companyName: string) => void; @@ -252,7 +244,6 @@ export class PlayerObject implements IPlayer { updateSkillLevels: () => void; gainCodingContractReward: (reward: ICodingContractReward, difficulty?: number) => string; stopFocusing: () => void; - finishFactionWork: (cancelled: boolean, sing?: boolean) => string; finishWork: (cancelled: boolean, sing?: boolean) => string; cancelationPenalty: () => number; finishWorkPartTime: (sing?: boolean) => string; @@ -377,9 +368,6 @@ export class PlayerObject implements IPlayer { this.workCostMult = 1; this.workExpMult = 1; - this.currentWorkFactionName = ""; - this.currentWorkFactionDescription = ""; - this.workHackExpGainRate = 0; this.workStrExpGainRate = 0; this.workDefExpGainRate = 0; @@ -505,12 +493,6 @@ export class PlayerObject implements IPlayer { this.finishWorkPartTime = generalMethods.finishWorkPartTime; this.startFocusing = generalMethods.startFocusing; this.stopFocusing = generalMethods.stopFocusing; - this.startFactionWork = generalMethods.startFactionWork; - this.startFactionHackWork = generalMethods.startFactionHackWork; - this.startFactionFieldWork = generalMethods.startFactionFieldWork; - this.startFactionSecurityWork = generalMethods.startFactionSecurityWork; - this.workForFaction = generalMethods.workForFaction; - this.finishFactionWork = generalMethods.finishFactionWork; this.getWorkMoneyGain = generalMethods.getWorkMoneyGain; this.getWorkHackExpGain = generalMethods.getWorkHackExpGain; this.getWorkStrExpGain = generalMethods.getWorkStrExpGain; @@ -576,7 +558,6 @@ export class PlayerObject implements IPlayer { this.getUpgradeHomeRamCost = serverMethods.getUpgradeHomeRamCost; this.getUpgradeHomeCoresCost = serverMethods.getUpgradeHomeCoresCost; this.createHacknetServer = serverMethods.createHacknetServer; - this.factionWorkType = PlayerFactionWorkType.None; this.getMult = generalMethods.getMult; this.setMult = generalMethods.setMult; diff --git a/src/PersonObjects/Player/PlayerObjectGeneralMethods.tsx b/src/PersonObjects/Player/PlayerObjectGeneralMethods.tsx index 6c49ab856..8aff9aa54 100644 --- a/src/PersonObjects/Player/PlayerObjectGeneralMethods.tsx +++ b/src/PersonObjects/Player/PlayerObjectGeneralMethods.tsx @@ -29,11 +29,6 @@ import { ISkillProgress, } from "../formulas/skill"; import { calculateIntelligenceBonus } from "../formulas/intelligence"; -import { - getHackingWorkRepGain, - getFactionSecurityWorkRepGain, - getFactionFieldWorkRepGain, -} from "../formulas/reputation"; import { GetServer, AddToAllServers, createUniqueRandomIp } from "../../Server/AllServers"; import { Server } from "../../Server/Server"; import { safetlyCreateUniqueServer } from "../../Server/ServerHelpers"; @@ -64,7 +59,7 @@ import { ITaskTracker } from "../ITaskTracker"; import { IPerson } from "../IPerson"; import { Player } from "../../Player"; -import { WorkType, PlayerFactionWorkType } from "../../utils/WorkType"; +import { WorkType } from "../../utils/WorkType"; export function init(this: IPlayer): void { /* Initialize Player's home computer */ @@ -137,8 +132,6 @@ export function prestigeAugmentation(this: PlayerObject): void { } this.isWorking = false; - this.currentWorkFactionName = ""; - this.currentWorkFactionDescription = ""; this.workHackExpGainRate = 0; this.workStrExpGainRate = 0; @@ -509,8 +502,7 @@ export function queryStatFromString(this: IPlayer, str: string): number { /******* Working functions *******/ 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 (generalType === this.workType) return; if (this.isWorking) this.singularityStopWork(); this.workHackExpGainRate = 0; this.workStrExpGainRate = 0; @@ -533,8 +525,6 @@ export function resetWorkStatus(this: IPlayer, generalType?: WorkType, group?: s this.timeWorked = 0; - this.currentWorkFactionName = ""; - this.currentWorkFactionDescription = ""; this.workType = WorkType.None; } @@ -590,11 +580,7 @@ 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 === WorkType.Faction) { - if (this.workForFaction(numCycles)) { - router.toFaction(Factions[this.currentWorkFactionName]); - } - } else if (this.workType === WorkType.CompanyPartTime) { + if (this.workType === WorkType.CompanyPartTime) { if (this.workPartTime(numCycles)) { router.toCity(); } @@ -855,165 +841,6 @@ export function stopFocusing(this: IPlayer): void { this.focus = false; } -/* Working for Faction */ -export function startFactionWork(this: IPlayer, faction: Faction): void { - //Update reputation gain rate to account for faction favor - let favorMult = 1 + faction.favor / 100; - if (isNaN(favorMult)) { - favorMult = 1; - } - this.workRepGainRate *= favorMult; - this.workRepGainRate *= BitNodeMultipliers.FactionWorkRepGain; - - this.isWorking = true; - this.workType = WorkType.Faction; - this.currentWorkFactionName = faction.name; - - this.timeNeededToCompleteWork = CONSTANTS.MillisecondsPer20Hours; -} - -export function startFactionHackWork(this: IPlayer, faction: Faction): void { - 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 = PlayerFactionWorkType.Hacking; - this.currentWorkFactionDescription = "carrying out hacking contracts"; - - this.startFactionWork(faction); -} - -export function startFactionFieldWork(this: IPlayer, faction: Faction): void { - 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; - this.workDefExpGainRate = 0.1 * this.defense_exp_mult * BitNodeMultipliers.FactionWorkExpGain; - this.workDexExpGainRate = 0.1 * this.dexterity_exp_mult * BitNodeMultipliers.FactionWorkExpGain; - this.workAgiExpGainRate = 0.1 * this.agility_exp_mult * BitNodeMultipliers.FactionWorkExpGain; - this.workChaExpGainRate = 0.1 * this.charisma_exp_mult * BitNodeMultipliers.FactionWorkExpGain; - this.workRepGainRate = getFactionFieldWorkRepGain(this, faction); - - this.factionWorkType = PlayerFactionWorkType.Field; - this.currentWorkFactionDescription = "carrying out field missions"; - - this.startFactionWork(faction); -} - -export function startFactionSecurityWork(this: IPlayer, faction: Faction): void { - 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; - this.workDefExpGainRate = 0.15 * this.defense_exp_mult * BitNodeMultipliers.FactionWorkExpGain; - this.workDexExpGainRate = 0.15 * this.dexterity_exp_mult * BitNodeMultipliers.FactionWorkExpGain; - this.workAgiExpGainRate = 0.15 * this.agility_exp_mult * BitNodeMultipliers.FactionWorkExpGain; - this.workChaExpGainRate = 0.0 * this.charisma_exp_mult * BitNodeMultipliers.FactionWorkExpGain; - this.workRepGainRate = getFactionSecurityWorkRepGain(this, faction); - - this.factionWorkType = PlayerFactionWorkType.Security; - this.currentWorkFactionDescription = "performing security detail"; - - this.startFactionWork(faction); -} - -export function workForFaction(this: IPlayer, numCycles: number): boolean { - const faction = Factions[this.currentWorkFactionName]; - - if (!faction) { - return false; - } - - //Constantly update the rep gain rate - switch (this.factionWorkType) { - case PlayerFactionWorkType.Hacking: - this.workRepGainRate = getHackingWorkRepGain(this, faction); - break; - case PlayerFactionWorkType.Field: - this.workRepGainRate = getFactionFieldWorkRepGain(this, faction); - break; - case PlayerFactionWorkType.Security: - this.workRepGainRate = getFactionSecurityWorkRepGain(this, faction); - break; - default: - break; - } - this.workRepGainRate *= BitNodeMultipliers.FactionWorkRepGain; - - //Cap the number of cycles being processed to whatever would put you at limit (20 hours) - let overMax = false; - if (this.timeWorked + CONSTANTS._idleSpeed * numCycles >= CONSTANTS.MillisecondsPer20Hours) { - overMax = true; - numCycles = Math.round((CONSTANTS.MillisecondsPer20Hours - this.timeWorked) / CONSTANTS._idleSpeed); - } - this.timeWorked += CONSTANTS._idleSpeed * numCycles; - - this.processWorkEarnings(numCycles); - - //If timeWorked == 20 hours, then finish. You can only work for the faction for 20 hours - if (overMax || this.timeWorked >= CONSTANTS.MillisecondsPer20Hours) { - this.finishFactionWork(false); - return true; - } - return false; -} - -export function finishFactionWork(this: IPlayer, cancelled: boolean, sing = false): string { - const faction = Factions[this.currentWorkFactionName]; - faction.playerReputation += this.workRepGained; - - this.updateSkillLevels(); - let res = ""; - - if (!sing) { - dialogBoxCreate( - <> - You worked for your faction {faction.name} for a total of {convertTimeMsToTimeElapsedString(this.timeWorked)}{" "} -
-
- You earned a total of:
- -
- reputation for the faction
- {numeralWrapper.formatExp(this.workHackExpGained)} hacking exp
- {numeralWrapper.formatExp(this.workStrExpGained)} strength exp
- {numeralWrapper.formatExp(this.workDefExpGained)} defense exp
- {numeralWrapper.formatExp(this.workDexExpGained)} dexterity exp
- {numeralWrapper.formatExp(this.workAgiExpGained)} agility exp
- {numeralWrapper.formatExp(this.workChaExpGained)} charisma exp -
- , - ); - } else { - res = - "You worked for your faction " + - faction.name + - " for a total of " + - convertTimeMsToTimeElapsedString(this.timeWorked) + - ". " + - "You earned " + - numeralWrapper.formatReputation(this.workRepGained) + - " rep, " + - numeralWrapper.formatExp(this.workHackExpGained) + - " hacking 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, and " + - numeralWrapper.formatExp(this.workChaExpGained) + - " cha exp."; - } - - this.isWorking = false; - this.resetWorkStatus(); - return res; -} - //Money gained per game cycle export function getWorkMoneyGain(this: IPlayer): number { // If player has SF-11, calculate salary multiplier from favor @@ -1220,26 +1047,6 @@ export function getWorkRepGain(this: IPlayer): number { return jobPerformance * this.company_rep_mult * favorMult; } -// export function getFactionSecurityWorkRepGain(this: IPlayer) { -// var t = 0.9 * (this.hacking / CONSTANTS.MaxSkillLevel + -// this.strength / CONSTANTS.MaxSkillLevel + -// this.defense / CONSTANTS.MaxSkillLevel + -// this.dexterity / CONSTANTS.MaxSkillLevel + -// this.agility / CONSTANTS.MaxSkillLevel) / 4.5; -// return t * this.faction_rep_mult; -// } - -// export function getFactionFieldWorkRepGain(this: IPlayer) { -// var t = 0.9 * (this.hacking / CONSTANTS.MaxSkillLevel + -// this.strength / CONSTANTS.MaxSkillLevel + -// this.defense / CONSTANTS.MaxSkillLevel + -// this.dexterity / CONSTANTS.MaxSkillLevel + -// this.agility / CONSTANTS.MaxSkillLevel + -// this.charisma / CONSTANTS.MaxSkillLevel + -// this.intelligence / CONSTANTS.MaxSkillLevel) / 5.5; -// return t * this.faction_rep_mult; -// } - //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 { @@ -1257,9 +1064,6 @@ export function singularityStopWork(this: IPlayer): string { case WorkType.CompanyPartTime: res = this.finishWorkPartTime(true); break; - case WorkType.Faction: - res = this.finishFactionWork(true, true); - break; default: console.error(`Unrecognized work type (${this.workType})`); return ""; diff --git a/src/PersonObjects/Sleeve/Sleeve.ts b/src/PersonObjects/Sleeve/Sleeve.ts index 9b49e6e22..08aa2074c 100644 --- a/src/PersonObjects/Sleeve/Sleeve.ts +++ b/src/PersonObjects/Sleeve/Sleeve.ts @@ -28,7 +28,6 @@ import { CONSTANTS } from "../../Constants"; import { Faction } from "../../Faction/Faction"; import { Factions } from "../../Faction/Factions"; -import { FactionWorkType } from "../../Faction/FactionWorkTypeEnum"; import { CityName } from "../../Locations/data/CityNames"; import { LocationName } from "../../Locations/data/LocationNames"; @@ -37,6 +36,7 @@ import { Generic_fromJSON, Generic_toJSON, Reviver } from "../../utils/JSONReviv import { BladeburnerConstants } from "../../Bladeburner/data/Constants"; import { numeralWrapper } from "../../ui/numeralFormat"; import { capitalizeFirstLetter, capitalizeEachWord } from "../../utils/StringHelperFunctions"; +import { FactionWorkType } from "../../Work/data/FactionWorkType"; export class Sleeve extends Person { /** @@ -94,7 +94,7 @@ export class Sleeve extends Person { /** * Keeps track of what type of work sleeve is doing for faction, if applicable */ - factionWorkType: FactionWorkType = FactionWorkType.None; + factionWorkType: FactionWorkType = FactionWorkType.HACKING; /** * Records experience gain rate for the current task @@ -444,11 +444,11 @@ export class Sleeve extends Person { } switch (this.factionWorkType) { - case FactionWorkType.Hacking: + case FactionWorkType.HACKING: return this.getFactionHackingWorkRepGain() * (this.shock / 100) * favorMult; - case FactionWorkType.Field: + case FactionWorkType.FIELD: return this.getFactionFieldWorkRepGain() * (this.shock / 100) * favorMult; - case FactionWorkType.Security: + case FactionWorkType.SECURITY: return this.getFactionSecurityWorkRepGain() * (this.shock / 100) * favorMult; default: console.warn(`Invalid Sleeve.factionWorkType property in Sleeve.getRepGain(): ${this.factionWorkType}`); @@ -660,7 +660,7 @@ export class Sleeve extends Person { this.currentTask = SleeveTaskType.Idle; this.currentTaskTime = 0; this.currentTaskMaxTime = 0; - this.factionWorkType = FactionWorkType.None; + this.factionWorkType = FactionWorkType.HACKING; this.crimeType = ""; this.currentTaskLocation = ""; this.gymStatType = ""; @@ -969,13 +969,13 @@ export class Sleeve extends Person { if (!factionInfo.offerHackingWork) { return false; } - this.factionWorkType = FactionWorkType.Hacking; + this.factionWorkType = FactionWorkType.HACKING; this.gainRatesForTask.hack = 0.15 * this.hacking_exp_mult * BitNodeMultipliers.FactionWorkExpGain; } else if (sanitizedWorkType.includes("field")) { if (!factionInfo.offerFieldWork) { return false; } - this.factionWorkType = FactionWorkType.Field; + this.factionWorkType = FactionWorkType.FIELD; this.gainRatesForTask.hack = 0.1 * this.hacking_exp_mult * BitNodeMultipliers.FactionWorkExpGain; this.gainRatesForTask.str = 0.1 * this.strength_exp_mult * BitNodeMultipliers.FactionWorkExpGain; this.gainRatesForTask.def = 0.1 * this.defense_exp_mult * BitNodeMultipliers.FactionWorkExpGain; @@ -986,7 +986,7 @@ export class Sleeve extends Person { if (!factionInfo.offerSecurityWork) { return false; } - this.factionWorkType = FactionWorkType.Security; + this.factionWorkType = FactionWorkType.SECURITY; this.gainRatesForTask.hack = 0.1 * this.hacking_exp_mult * BitNodeMultipliers.FactionWorkExpGain; this.gainRatesForTask.str = 0.15 * this.strength_exp_mult * BitNodeMultipliers.FactionWorkExpGain; this.gainRatesForTask.def = 0.15 * this.defense_exp_mult * BitNodeMultipliers.FactionWorkExpGain; diff --git a/src/PersonObjects/Sleeve/ui/SleeveElem.tsx b/src/PersonObjects/Sleeve/ui/SleeveElem.tsx index cc87927d3..64853d7f9 100644 --- a/src/PersonObjects/Sleeve/ui/SleeveElem.tsx +++ b/src/PersonObjects/Sleeve/ui/SleeveElem.tsx @@ -1,8 +1,8 @@ import { Box, Button, Paper, Tooltip, Typography } from "@mui/material"; import React, { useState } from "react"; +import { FactionWorkType } from "../../../Work/data/FactionWorkType"; import { CONSTANTS } from "../../../Constants"; import { Crimes } from "../../../Crime/Crimes"; -import { FactionWorkType } from "../../../Faction/FactionWorkTypeEnum"; import { use } from "../../../ui/Context"; import { numeralWrapper } from "../../../ui/numeralFormat"; import { ProgressBar } from "../../../ui/React/Progress"; @@ -75,13 +75,13 @@ export function SleeveElem(props: IProps): React.ReactElement { case SleeveTaskType.Faction: { let doing = "nothing"; switch (props.sleeve.factionWorkType) { - case FactionWorkType.Field: + case FactionWorkType.FIELD: doing = "Field work"; break; - case FactionWorkType.Hacking: + case FactionWorkType.HACKING: doing = "Hacking contracts"; break; - case FactionWorkType.Security: + case FactionWorkType.SECURITY: doing = "Security work"; break; } diff --git a/src/PersonObjects/Sleeve/ui/TaskSelector.tsx b/src/PersonObjects/Sleeve/ui/TaskSelector.tsx index 0de75b9b0..f6e100b1a 100644 --- a/src/PersonObjects/Sleeve/ui/TaskSelector.tsx +++ b/src/PersonObjects/Sleeve/ui/TaskSelector.tsx @@ -6,10 +6,10 @@ import { Crimes } from "../../../Crime/Crimes"; import { LocationName } from "../../../Locations/data/LocationNames"; import { CityName } from "../../../Locations/data/CityNames"; import { Factions } from "../../../Faction/Factions"; -import { FactionWorkType } from "../../../Faction/FactionWorkTypeEnum"; import Select, { SelectChangeEvent } from "@mui/material/Select"; import MenuItem from "@mui/material/MenuItem"; import { FactionNames } from "../../../Faction/data/FactionNames"; +import { FactionWorkType } from "../../../Work/data/FactionWorkType"; const universitySelectorOptions: string[] = [ "Study Computer Science", @@ -254,13 +254,13 @@ function getABC(sleeve: Sleeve): [string, string, string] { case SleeveTaskType.Faction: { let workType = ""; switch (sleeve.factionWorkType) { - case FactionWorkType.Hacking: + case FactionWorkType.HACKING: workType = "Hacking Contracts"; break; - case FactionWorkType.Field: + case FactionWorkType.FIELD: workType = "Field Work"; break; - case FactionWorkType.Security: + case FactionWorkType.SECURITY: workType = "Security Work"; break; } diff --git a/src/ScriptEditor/NetscriptDefinitions.d.ts b/src/ScriptEditor/NetscriptDefinitions.d.ts index 3624f4ad1..a61055fa4 100644 --- a/src/ScriptEditor/NetscriptDefinitions.d.ts +++ b/src/ScriptEditor/NetscriptDefinitions.d.ts @@ -49,8 +49,6 @@ interface Player { crime_success_mult: number; isWorking: boolean; workType: string; - currentWorkFactionName: string; - currentWorkFactionDescription: string; workHackExpGainRate: number; workStrExpGainRate: number; workDefExpGainRate: number; diff --git a/src/Work/ClassWork.tsx b/src/Work/ClassWork.tsx index 3e9eefef3..ab444bed8 100644 --- a/src/Work/ClassWork.tsx +++ b/src/Work/ClassWork.tsx @@ -1,5 +1,5 @@ import React from "react"; -import { Reviver, Generic_toJSON, Generic_fromJSON } from "../utils/JSONReviver"; +import { Reviver, Generic_toJSON, Generic_fromJSON, IReviverValue } from "../utils/JSONReviver"; import { CONSTANTS } from "../Constants"; import { LocationName } from "../Locations/data/LocationNames"; import { numeralWrapper } from "../ui/numeralFormat"; @@ -129,14 +129,12 @@ export class ClassWork extends Work { classType: ClassType; location: LocationName; cyclesWorked: number; - singularity: boolean; earnings = newWorkStats(); constructor(params?: ClassWorkParams) { - super(WorkType.CLASS); + super(WorkType.CLASS, params?.singularity ?? true); this.classType = params?.classType ?? ClassType.StudyComputerScience; this.location = params?.location ?? LocationName.Sector12RothmanUniversity; - this.singularity = params?.singularity ?? false; this.cyclesWorked = 0; } @@ -186,15 +184,14 @@ export class ClassWork extends Work { /** * Serialize the current object to a JSON save state. */ - toJSON(): any { + toJSON(): IReviverValue { return Generic_toJSON("ClassWork", this); } /** * Initiatizes a ClassWork object from a JSON save state. */ - // eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types - static fromJSON(value: any): ClassWork { + static fromJSON(value: IReviverValue): ClassWork { return Generic_fromJSON(ClassWork, value.data); } } diff --git a/src/Work/CreateProgramWork.ts b/src/Work/CreateProgramWork.ts index 3b011c7d4..a3f4ef2a9 100644 --- a/src/Work/CreateProgramWork.ts +++ b/src/Work/CreateProgramWork.ts @@ -1,5 +1,5 @@ import { dialogBoxCreate } from "../ui/React/DialogBox"; -import { Reviver, Generic_toJSON, Generic_fromJSON } from "../utils/JSONReviver"; +import { Reviver, Generic_toJSON, Generic_fromJSON, IReviverValue } from "../utils/JSONReviver"; import { AugmentationNames } from "../Augmentation/data/AugmentationNames"; import { CONSTANTS } from "../Constants"; import { IPlayer } from "../PersonObjects/IPlayer"; @@ -20,16 +20,14 @@ export class CreateProgramWork extends Work { programName: string; // amount of cycles spent doing this task cyclesWorked: number; - singularity: boolean; // amount of effective work completed on the program (time boosted by skills). unitCompleted: number; constructor(params?: CreateProgramWorkParams) { - super(WorkType.CREATE_PROGRAM); + super(WorkType.CREATE_PROGRAM, params?.singularity ?? true); this.cyclesWorked = 0; this.unitCompleted = 0; this.programName = params?.programName ?? ""; - this.singularity = params?.singularity ?? false; if (params?.player) { const player = params.player; @@ -109,15 +107,14 @@ export class CreateProgramWork extends Work { /** * Serialize the current object to a JSON save state. */ - toJSON(): any { + toJSON(): IReviverValue { return Generic_toJSON("CreateProgramWork", this); } /** * Initiatizes a CreateProgramWork object from a JSON save state. */ - // eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types - static fromJSON(value: any): CreateProgramWork { + static fromJSON(value: IReviverValue): CreateProgramWork { return Generic_fromJSON(CreateProgramWork, value.data); } } diff --git a/src/Work/CrimeWork.tsx b/src/Work/CrimeWork.tsx index 912eb8801..761377bec 100644 --- a/src/Work/CrimeWork.tsx +++ b/src/Work/CrimeWork.tsx @@ -1,5 +1,5 @@ import React from "react"; -import { Reviver, Generic_toJSON, Generic_fromJSON } from "../utils/JSONReviver"; +import { Reviver, Generic_toJSON, Generic_fromJSON, IReviverValue } from "../utils/JSONReviver"; import { Crime } from "../Crime/Crime"; import { CONSTANTS } from "../Constants"; import { determineCrimeSuccess } from "../Crime/CrimeHelpers"; @@ -21,12 +21,10 @@ export const isCrimeWork = (w: Work | null): w is CrimeWork => w !== null && w.t export class CrimeWork extends Work { crimeType: CrimeType; cyclesWorked: number; - singularity: boolean; constructor(params?: CrimeWorkParams) { - super(WorkType.CRIME); + super(WorkType.CRIME, params?.singularity ?? true); this.crimeType = params?.crimeType ?? CrimeType.Shoplift; - this.singularity = params?.singularity ?? false; this.cyclesWorked = 0; } @@ -121,15 +119,14 @@ export class CrimeWork extends Work { /** * Serialize the current object to a JSON save state. */ - toJSON(): any { + toJSON(): IReviverValue { 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 { + static fromJSON(value: IReviverValue): CrimeWork { return Generic_fromJSON(CrimeWork, value.data); } } diff --git a/src/Work/FactionWork.tsx b/src/Work/FactionWork.tsx new file mode 100644 index 000000000..d1671ba09 --- /dev/null +++ b/src/Work/FactionWork.tsx @@ -0,0 +1,103 @@ +import React from "react"; +import { Work, WorkType } from "./Work"; +import { Reviver, Generic_toJSON, Generic_fromJSON, IReviverValue } from "../utils/JSONReviver"; +import { IPlayer } from "../PersonObjects/IPlayer"; +import { FactionNames } from "../Faction/data/FactionNames"; +import { Factions } from "../Faction/Factions"; +import { Faction } from "../Faction/Faction"; +import { applyWorkStats, WorkStats } from "./WorkStats"; +import { dialogBoxCreate } from "../ui/React/DialogBox"; +import { Reputation } from "../ui/React/Reputation"; +import { + getFactionFieldWorkRepGain, + getFactionSecurityWorkRepGain, + getHackingWorkRepGain, +} from "../PersonObjects/formulas/reputation"; +import { CONSTANTS } from "../Constants"; +import { AugmentationNames } from "../Augmentation/data/AugmentationNames"; +import { calculateFactionExp } from "./formulas/Faction"; +import { FactionWorkType } from "./data/FactionWorkType"; + +interface FactionWorkParams { + singularity: boolean; + factionWorkType: FactionWorkType; + faction: string; +} + +export const isFactionWork = (w: Work | null): w is FactionWork => w !== null && w.type === WorkType.FACTION; + +export class FactionWork extends Work { + factionWorkType: FactionWorkType; + factionName: string; + cyclesWorked: number; + + constructor(params?: FactionWorkParams) { + super(WorkType.FACTION, params?.singularity ?? true); + this.factionWorkType = params?.factionWorkType ?? FactionWorkType.HACKING; + this.factionName = params?.faction ?? FactionNames.Sector12; + this.cyclesWorked = 0; + } + + getFaction(): Faction { + const f = Factions[this.factionName]; + if (!f) throw new Error(`Faction work started with invalid / unknown faction: '${this.factionName}'`); + return f; + } + + getReputationRate(player: IPlayer): number { + const faction = this.getFaction(); + const repFormulas = { + [FactionWorkType.HACKING]: getHackingWorkRepGain, + [FactionWorkType.FIELD]: getFactionFieldWorkRepGain, + [FactionWorkType.SECURITY]: getFactionSecurityWorkRepGain, + }; + const rep = repFormulas[this.factionWorkType](player, faction); + let focusBonus = 1; + if (!player.hasAugmentation(AugmentationNames.NeuroreceptorManager)) { + focusBonus = player.focus ? 1 : CONSTANTS.BaseFocusBonus; + } + return rep * focusBonus; + } + + getExpRates(player: IPlayer): WorkStats { + return calculateFactionExp(player, this.factionWorkType); + } + + process(player: IPlayer, cycles: number): boolean { + this.cyclesWorked += cycles; + this.getFaction().playerReputation += this.getReputationRate(player) * cycles; + + const rate = this.getExpRates(player); + applyWorkStats(player, rate, cycles, "class"); + + return false; + } + + finish(): void { + if (!this.singularity) { + dialogBoxCreate( + <> + You worked for {this.getFaction().name}. +
+ They now have a total of reputation. + , + ); + } + } + + /** + * Serialize the current object to a JSON save state. + */ + toJSON(): IReviverValue { + return Generic_toJSON("FactionWork", this); + } + + /** + * Initiatizes a FactionWork object from a JSON save state. + */ + static fromJSON(value: IReviverValue): FactionWork { + return Generic_fromJSON(FactionWork, value.data); + } +} + +Reviver.constructors.FactionWork = FactionWork; diff --git a/src/Work/GraftingWork.tsx b/src/Work/GraftingWork.tsx index 2ed9ddb4f..d149e9ad5 100644 --- a/src/Work/GraftingWork.tsx +++ b/src/Work/GraftingWork.tsx @@ -7,7 +7,7 @@ import { Work, WorkType } from "./Work"; import { graftingIntBonus } from "../PersonObjects/Grafting/GraftingHelpers"; import { applyAugmentation } from "../Augmentation/AugmentationHelpers"; import { dialogBoxCreate } from "../ui/React/DialogBox"; -import { Reviver, Generic_toJSON, Generic_fromJSON } from "../utils/JSONReviver"; +import { Reviver, Generic_toJSON, Generic_fromJSON, IReviverValue } from "../utils/JSONReviver"; import { GraftableAugmentation } from "../PersonObjects/Grafting/GraftableAugmentation"; import { StaticAugmentations } from "../Augmentation/StaticAugmentations"; @@ -15,22 +15,21 @@ export const isGraftingWork = (w: Work | null): w is GraftingWork => w !== null interface GraftingWorkParams { augmentation: string; - singularity: boolean; player: IPlayer; + singularity: boolean; } export class GraftingWork extends Work { augmentation: string; - singularity: boolean; cyclesWorked: number; unitCompleted: number; constructor(params?: GraftingWorkParams) { - super(WorkType.GRAFTING); + super(WorkType.GRAFTING, params?.singularity ?? true); this.cyclesWorked = 0; this.unitCompleted = 0; this.augmentation = params?.augmentation ?? AugmentationNames.Targeting1; - this.singularity = params?.singularity ?? false; + if (params?.player) params.player.loseMoney(GraftableAugmentations[this.augmentation].cost, "augmentations"); } @@ -90,15 +89,14 @@ export class GraftingWork extends Work { /** * Serialize the current object to a JSON save state. */ - toJSON(): any { + toJSON(): IReviverValue { return Generic_toJSON("GraftingWork", this); } /** * Initiatizes a GraftingWork object from a JSON save state. */ - // eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types - static fromJSON(value: any): GraftingWork { + static fromJSON(value: IReviverValue): GraftingWork { return Generic_fromJSON(GraftingWork, value.data); } } diff --git a/src/Work/Work.ts b/src/Work/Work.ts index 964643376..e3c93e0ed 100644 --- a/src/Work/Work.ts +++ b/src/Work/Work.ts @@ -1,15 +1,18 @@ -import { IPlayer } from "src/PersonObjects/IPlayer"; +import { IPlayer } from "../PersonObjects/IPlayer"; +import { IReviverValue } from "../utils/JSONReviver"; export abstract class Work { type: WorkType; + singularity: boolean; - constructor(type: WorkType) { + constructor(type: WorkType, singularity: boolean) { this.type = type; + this.singularity = singularity; } abstract process(player: IPlayer, cycles: number): boolean; abstract finish(player: IPlayer, cancelled: boolean): void; - abstract toJSON(): any; + abstract toJSON(): IReviverValue; } export enum WorkType { @@ -17,4 +20,5 @@ export enum WorkType { CLASS = "CLASS", CREATE_PROGRAM = "CREATE_PROGRAM", GRAFTING = "GRAFTING", + FACTION = "FACTION", } diff --git a/src/Work/WorkStats.ts b/src/Work/WorkStats.ts index 9e17c11dd..7881b5abf 100644 --- a/src/Work/WorkStats.ts +++ b/src/Work/WorkStats.ts @@ -4,7 +4,6 @@ import { IPlayer } from "../PersonObjects/IPlayer"; export interface WorkStats { money: number; - reputation: number; hackExp: number; strExp: number; defExp: number; @@ -16,7 +15,6 @@ export interface WorkStats { interface newWorkStatsParams { money?: number; - reputation?: number; hackExp?: number; strExp?: number; defExp?: number; @@ -29,7 +27,6 @@ interface newWorkStatsParams { export const newWorkStats = (params?: newWorkStatsParams): WorkStats => { return { money: params?.money ?? 0, - reputation: params?.reputation ?? 0, hackExp: params?.hackExp ?? 0, strExp: params?.strExp ?? 0, defExp: params?.defExp ?? 0, @@ -43,7 +40,6 @@ export const newWorkStats = (params?: newWorkStatsParams): WorkStats => { export const sumWorkStats = (w0: WorkStats, w1: WorkStats): WorkStats => { return { money: w0.money + w1.money, - reputation: w0.reputation + w1.reputation, hackExp: w0.hackExp + w1.hackExp, strExp: w0.strExp + w1.strExp, defExp: w0.defExp + w1.defExp, @@ -57,7 +53,6 @@ export const sumWorkStats = (w0: WorkStats, w1: WorkStats): WorkStats => { export const scaleWorkStats = (w: WorkStats, n: number): WorkStats => { return { money: w.money * n, - reputation: w.reputation * n, hackExp: w.hackExp * n, strExp: w.strExp * n, defExp: w.defExp * n, @@ -75,7 +70,6 @@ export const applyWorkStats = (player: IPlayer, workStats: WorkStats, cycles: nu } const gains = { money: workStats.money * cycles, - reputation: focusBonus * workStats.reputation * cycles, hackExp: focusBonus * workStats.hackExp * cycles, strExp: focusBonus * workStats.strExp * cycles, defExp: focusBonus * workStats.defExp * cycles, diff --git a/src/Work/data/FactionWorkType.ts b/src/Work/data/FactionWorkType.ts new file mode 100644 index 000000000..336ead4b1 --- /dev/null +++ b/src/Work/data/FactionWorkType.ts @@ -0,0 +1,5 @@ +export enum FactionWorkType { + HACKING = "HACKING", + FIELD = "FIELD", + SECURITY = "SECURITY", +} diff --git a/src/Work/formulas/Class.ts b/src/Work/formulas/Class.ts index 6f5e29565..4351c2679 100644 --- a/src/Work/formulas/Class.ts +++ b/src/Work/formulas/Class.ts @@ -35,7 +35,6 @@ export function calculateClassEarnings(player: IPlayer, work: ClassWork): WorkSt const chaExp = ((classs.earnings.chaExp * location.expMult) / gameCPS) * hashMult; return { money: cost, - reputation: 0, hackExp: hackExp * player.hacking_exp_mult * BitNodeMultipliers.ClassGymExpGain, strExp: strExp * player.strength_exp_mult * BitNodeMultipliers.ClassGymExpGain, defExp: defExp * player.defense_exp_mult * BitNodeMultipliers.ClassGymExpGain, diff --git a/src/Work/formulas/Faction.ts b/src/Work/formulas/Faction.ts new file mode 100644 index 000000000..6104e540e --- /dev/null +++ b/src/Work/formulas/Faction.ts @@ -0,0 +1,40 @@ +import { BitNodeMultipliers } from "../../BitNode/BitNodeMultipliers"; +import { CONSTANTS } from "../../Constants"; +import { IPlayer } from "../../PersonObjects/IPlayer"; +import { FactionWorkType } from "../data/FactionWorkType"; +import { newWorkStats, WorkStats } from "../WorkStats"; + +const gameCPS = 1000 / CONSTANTS._idleSpeed; // 5 cycles per second + +export const FactionWorkStats: Record = { + [FactionWorkType.HACKING]: newWorkStats({ hackExp: 15 }), + [FactionWorkType.FIELD]: newWorkStats({ + hackExp: 10, + strExp: 10, + defExp: 10, + dexExp: 10, + agiExp: 10, + chaExp: 10, + }), + [FactionWorkType.SECURITY]: newWorkStats({ + hackExp: 5, + strExp: 15, + defExp: 15, + dexExp: 15, + agiExp: 15, + }), +}; + +export function calculateFactionExp(player: IPlayer, tpe: FactionWorkType): WorkStats { + const baseStats = FactionWorkStats[tpe]; + return { + money: 0, + hackExp: (baseStats.hackExp * player.hacking_exp_mult * BitNodeMultipliers.FactionWorkExpGain) / gameCPS, + strExp: (baseStats.strExp * player.strength_exp_mult * BitNodeMultipliers.FactionWorkExpGain) / gameCPS, + defExp: (baseStats.defExp * player.defense_exp_mult * BitNodeMultipliers.FactionWorkExpGain) / gameCPS, + dexExp: (baseStats.dexExp * player.dexterity_exp_mult * BitNodeMultipliers.FactionWorkExpGain) / gameCPS, + agiExp: (baseStats.agiExp * player.agility_exp_mult * BitNodeMultipliers.FactionWorkExpGain) / gameCPS, + chaExp: (baseStats.chaExp * player.charisma_exp_mult * BitNodeMultipliers.FactionWorkExpGain) / gameCPS, + intExp: 0, + }; +} diff --git a/src/engine.tsx b/src/engine.tsx index e58df6b9a..301a1d15b 100644 --- a/src/engine.tsx +++ b/src/engine.tsx @@ -303,9 +303,6 @@ const Engine: { } else if (Player.isWorking) { Player.focus = true; switch (Player.workType) { - case WorkType.Faction: - Player.workForFaction(numCyclesOffline); - break; case WorkType.CompanyPartTime: Player.workPartTime(numCyclesOffline); break; diff --git a/src/ui/GameRoot.tsx b/src/ui/GameRoot.tsx index e5db96ed7..f7da37a73 100644 --- a/src/ui/GameRoot.tsx +++ b/src/ui/GameRoot.tsx @@ -87,6 +87,7 @@ import { BypassWrapper } from "./React/BypassWrapper"; import _wrap from "lodash/wrap"; import _functions from "lodash/functions"; import { Apr1 } from "./Apr1"; +import { isFactionWork } from "../Work/FactionWork"; const htmlLocation = location; @@ -165,7 +166,7 @@ export function GameRoot({ player, engine, terminal }: IProps): React.ReactEleme const setRerender = useState(0)[1]; const [augPage, setAugPage] = useState(false); const [faction, setFaction] = useState( - player.currentWorkFactionName ? Factions[player.currentWorkFactionName] : (undefined as unknown as Faction), + isFactionWork(player.currentWork) ? Factions[player.currentWork.factionName] : (undefined as unknown as Faction), ); if (faction === undefined && page === Page.Faction) throw new Error("Trying to go to a page without the proper setup"); diff --git a/src/ui/React/CharacterOverview.tsx b/src/ui/React/CharacterOverview.tsx index 2f9a82722..ced8be855 100644 --- a/src/ui/React/CharacterOverview.tsx +++ b/src/ui/React/CharacterOverview.tsx @@ -31,6 +31,8 @@ import { isClassWork } from "../../Work/ClassWork"; import { CONSTANTS } from "../../Constants"; import { isCreateProgramWork } from "../../Work/CreateProgramWork"; import { isGraftingWork } from "../../Work/GraftingWork"; +import { isFactionWork } from "../../Work/FactionWork"; +import { ReputationRate } from "./ReputationRate"; interface IProps { save: () => void; @@ -172,6 +174,22 @@ function Work(): React.ReactElement { ); } + + if (isFactionWork(player.currentWork)) { + const factionWork = player.currentWork; + header = ( + <> + Working for {factionWork.factionName} + + ); + innerText = ( + <> + rep +
( + ) + + ); + } switch (player.workType) { case WorkType.CompanyPartTime: case WorkType.Company: @@ -191,23 +209,6 @@ function Work(): React.ReactElement { ); break; - case WorkType.Faction: - details = ( - <> - {player.factionWorkType} for {player.currentWorkFactionName} - - ); - header = ( - <> - Working for {player.currentWorkFactionName} - - ); - innerText = ( - <> - + rep - - ); - break; } return ( diff --git a/src/ui/WorkInProgressRoot.tsx b/src/ui/WorkInProgressRoot.tsx index 4da7725a1..fb5879975 100644 --- a/src/ui/WorkInProgressRoot.tsx +++ b/src/ui/WorkInProgressRoot.tsx @@ -6,7 +6,6 @@ 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"; @@ -22,9 +21,11 @@ import { StatsRow } from "./React/StatsRow"; import { WorkType } from "../utils/WorkType"; import { isCrimeWork } from "../Work/CrimeWork"; import { isClassWork } from "../Work/ClassWork"; -import { WorkStats } from "../Work/WorkStats"; +import { newWorkStats, WorkStats } from "../Work/WorkStats"; import { isCreateProgramWork } from "../Work/CreateProgramWork"; import { isGraftingWork } from "../Work/GraftingWork"; +import { isFactionWork } from "../Work/FactionWork"; +import { FactionWorkType } from "../Work/data/FactionWorkType"; const CYCLES_PER_SEC = 1000 / CONSTANTS.MilliPerCycle; @@ -47,81 +48,69 @@ interface IWorkInfo { stopTooltip?: string | React.ReactElement; } -export function ExpRows(total: WorkStats, rate: WorkStats): React.ReactElement[] { +export function ExpRows(rate: WorkStats): React.ReactElement[] { return [ - total.hackExp > 0 ? ( + rate.hackExp > 0 ? ( ) : ( <> ), - total.strExp > 0 ? ( + rate.strExp > 0 ? ( ) : ( <> ), - total.defExp > 0 ? ( + rate.defExp > 0 ? ( ) : ( <> ), - total.dexExp > 0 ? ( + rate.dexExp > 0 ? ( ) : ( <> ), - total.agiExp > 0 ? ( + rate.agiExp > 0 ? ( ) : ( <> ), - total.chaExp > 0 ? ( + rate.chaExp > 0 ? ( ) : ( @@ -276,7 +265,7 @@ export function WorkInProgressRoot(): React.ReactElement { } const rates = classWork.calculateRates(player); - expGains = ExpRows(classWork.earnings, rates); + expGains = ExpRows(rates); workInfo = { buttons: { cancel: cancel, @@ -373,18 +362,16 @@ export function WorkInProgressRoot(): React.ReactElement { ), }; } - } - switch (player.workType) { - case WorkType.Faction: { - const faction = Factions[player.currentWorkFactionName]; + if (isFactionWork(player.currentWork)) { + const faction = player.currentWork.getFaction(); if (!faction) { workInfo = { buttons: { cancel: () => router.toFactions(), }, title: - `You have not joined ${player.currentWorkFactionName || "(Faction not found)"} at this time,` + + `You have not joined ${player.currentWork.factionName || "(Faction not found)"} at this time,` + " please try again if you think this should have worked", stopText: "Back to Factions", @@ -393,13 +380,21 @@ export function WorkInProgressRoot(): React.ReactElement { function cancel(): void { router.toFaction(faction); - player.finishFactionWork(true); + player.finishNEWWork(true); } function unfocus(): void { router.toFaction(faction); player.stopFocusing(); } + const description = { + [FactionWorkType.HACKING]: "carrying out hacking contracts", + [FactionWorkType.FIELD]: "carrying out field missions", + [FactionWorkType.SECURITY]: "performing security detail", + }; + + const exp = player.currentWork.getExpRates(player); + workInfo = { buttons: { cancel: cancel, @@ -407,44 +402,27 @@ export function WorkInProgressRoot(): React.ReactElement { }, title: ( <> - You are currently {player.currentWorkFactionDescription} for your faction {faction.name} + You are currently {description[player.currentWork.factionWorkType]} for {faction.name} ), description: ( <> - Current Faction Reputation: + Current Faction Reputation: ( + ) ), - gains: [ - player.workMoneyGained > 0 ? ( - - - ( - ) - - - ) : ( - <> - ), - - - ( - ) - - , - ...expGains, - ], + gains: ExpRows(exp), progress: { - elapsed: player.timeWorked, + elapsed: player.currentWork.cyclesWorked * CONSTANTS._idleSpeed, }, stopText: "Stop Faction work", }; - - break; } + } + switch (player.workType) { case WorkType.Company: { const comp = Companies[player.companyName]; if (comp == null || !(comp instanceof Company)) { diff --git a/src/utils/WorkType.ts b/src/utils/WorkType.ts index e43890698..3acea0fe1 100644 --- a/src/utils/WorkType.ts +++ b/src/utils/WorkType.ts @@ -9,29 +9,6 @@ export enum WorkType { 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",