mirror of
https://github.com/bitburner-official/bitburner-src.git
synced 2024-12-24 07:02:26 +01:00
Convert crime to new work model
This commit is contained in:
parent
7d263e4223
commit
3ee7d593d0
@ -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;
|
||||
|
21
src/PersonObjects/Player/PlayerObjectWorkMethods.ts
Normal file
21
src/PersonObjects/Player/PlayerObjectWorkMethods.ts
Normal file
@ -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;
|
||||
}
|
1
src/ScriptEditor/NetscriptDefinitions.d.ts
vendored
1
src/ScriptEditor/NetscriptDefinitions.d.ts
vendored
@ -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
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
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);
|
||||
|
||||
Player.process(Router, 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:
|
||||
router.toTerminal();
|
||||
workInfo = null;
|
||||
if (player.currentWork === null) {
|
||||
router.toTerminal();
|
||||
}
|
||||
}
|
||||
|
||||
if (workInfo === null) {
|
||||
if (workInfo.title === "") {
|
||||
return <></>;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user