mirror of
https://github.com/bitburner-official/bitburner-src.git
synced 2026-05-08 08:37:48 +02:00
work on sleeve new work system
This commit is contained in:
@@ -0,0 +1,59 @@
|
||||
import { IPlayer } from "../../IPlayer";
|
||||
import { Generic_fromJSON, Generic_toJSON, IReviverValue, Reviver } from "../../../utils/JSONReviver";
|
||||
import { Sleeve } from "../Sleeve";
|
||||
import { Work, WorkType } from "./Work";
|
||||
import { CONSTANTS } from "../../../Constants";
|
||||
|
||||
export const isSleeveBladeburnerGeneralWork = (w: Work | null): w is SleeveBladeburnerGeneralWork =>
|
||||
w !== null && w.type === WorkType.BLADEBURNER_GENERAL;
|
||||
|
||||
export class SleeveBladeburnerGeneralWork extends Work {
|
||||
cyclesWorked = 0;
|
||||
action: string;
|
||||
|
||||
constructor(action?: string) {
|
||||
super(WorkType.BLADEBURNER_GENERAL);
|
||||
this.action = action ?? "Field analysis";
|
||||
}
|
||||
|
||||
cyclesNeeded(player: IPlayer, sleeve: Sleeve): number {
|
||||
const ret = player.bladeburner?.getActionTimeNetscriptFn(sleeve, "General", this.action);
|
||||
if (!ret || typeof ret === "string") throw new Error(`Error querying ${this.action} time`);
|
||||
return ret / CONSTANTS._idleSpeed;
|
||||
}
|
||||
|
||||
process(player: IPlayer, sleeve: Sleeve, cycles: number): number {
|
||||
if (!player.bladeburner) throw new Error("sleeve doing blade work without being a member");
|
||||
this.cyclesWorked += cycles;
|
||||
while (this.cyclesWorked > this.cyclesNeeded(player, sleeve)) {
|
||||
const actionIdent = player.bladeburner.getActionIdFromTypeAndName("General", this.action);
|
||||
if (!actionIdent) throw new Error(`Error getting ${this.action} action`);
|
||||
player.bladeburner.completeAction(player, sleeve, actionIdent, false);
|
||||
this.cyclesWorked -= this.cyclesNeeded(player, sleeve);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
APICopy(): Record<string, unknown> {
|
||||
return {
|
||||
type: this.type,
|
||||
action: this.action,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Serialize the current object to a JSON save state.
|
||||
*/
|
||||
toJSON(): IReviverValue {
|
||||
return Generic_toJSON("SleeveBladeburnerGeneralWork", this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initiatizes a BladeburnerWork object from a JSON save state.
|
||||
*/
|
||||
static fromJSON(value: IReviverValue): SleeveBladeburnerGeneralWork {
|
||||
return Generic_fromJSON(SleeveBladeburnerGeneralWork, value.data);
|
||||
}
|
||||
}
|
||||
|
||||
Reviver.constructors.SleeveBladeburnerGeneralWork = SleeveBladeburnerGeneralWork;
|
||||
@@ -0,0 +1,71 @@
|
||||
import { IPlayer } from "../../IPlayer";
|
||||
import { Generic_fromJSON, Generic_toJSON, IReviverValue, Reviver } from "../../../utils/JSONReviver";
|
||||
import { Work, WorkType } from "./Work";
|
||||
import { ClassType } from "../../../Work/ClassWork";
|
||||
import { LocationName } from "../../../Locations/data/LocationNames";
|
||||
import { calculateClassEarnings } from "../../../Work/formulas/Class";
|
||||
import { Sleeve } from "../Sleeve";
|
||||
import { applyWorkStats, applyWorkStatsExp, scaleWorkStats, WorkStats } from "../../../Work/WorkStats";
|
||||
|
||||
export const isSleeveClassWork = (w: Work | null): w is SleeveClassWork => w !== null && w.type === WorkType.CLASS;
|
||||
|
||||
interface ClassWorkParams {
|
||||
classType: ClassType;
|
||||
location: LocationName;
|
||||
}
|
||||
|
||||
export class SleeveClassWork extends Work {
|
||||
classType: ClassType;
|
||||
location: LocationName;
|
||||
|
||||
constructor(params?: ClassWorkParams) {
|
||||
super(WorkType.CLASS);
|
||||
this.classType = params?.classType ?? ClassType.StudyComputerScience;
|
||||
this.location = params?.location ?? LocationName.Sector12RothmanUniversity;
|
||||
}
|
||||
|
||||
calculateRates(player: IPlayer, sleeve: Sleeve): WorkStats {
|
||||
return scaleWorkStats(
|
||||
calculateClassEarnings(player, sleeve, this.classType, this.location),
|
||||
sleeve.shockBonus(),
|
||||
false,
|
||||
);
|
||||
}
|
||||
|
||||
isGym(): boolean {
|
||||
return [ClassType.GymAgility, ClassType.GymDefense, ClassType.GymDexterity, ClassType.GymStrength].includes(
|
||||
this.classType,
|
||||
);
|
||||
}
|
||||
|
||||
process(player: IPlayer, sleeve: Sleeve, cycles: number): number {
|
||||
let rate = this.calculateRates(player, sleeve);
|
||||
applyWorkStatsExp(sleeve, rate, cycles);
|
||||
rate = scaleWorkStats(rate, sleeve.syncBonus(), false);
|
||||
applyWorkStats(player, player, rate, cycles, "sleeves");
|
||||
player.sleeves.filter((s) => s != sleeve).forEach((s) => applyWorkStatsExp(s, rate, cycles));
|
||||
return 0;
|
||||
}
|
||||
APICopy(): Record<string, unknown> {
|
||||
return {
|
||||
type: this.type,
|
||||
classType: this.classType,
|
||||
location: this.location,
|
||||
};
|
||||
}
|
||||
/**
|
||||
* Serialize the current object to a JSON save state.
|
||||
*/
|
||||
toJSON(): IReviverValue {
|
||||
return Generic_toJSON("SleeveClassWork", this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initiatizes a ClassWork object from a JSON save state.
|
||||
*/
|
||||
static fromJSON(value: IReviverValue): SleeveClassWork {
|
||||
return Generic_fromJSON(SleeveClassWork, value.data);
|
||||
}
|
||||
}
|
||||
|
||||
Reviver.constructors.SleeveClassWork = SleeveClassWork;
|
||||
@@ -0,0 +1,70 @@
|
||||
import { IPlayer } from "../../IPlayer";
|
||||
import { Generic_fromJSON, Generic_toJSON, IReviverValue, Reviver } from "../../../utils/JSONReviver";
|
||||
import { Sleeve } from "../Sleeve";
|
||||
import { Work, WorkType } from "./Work";
|
||||
import { LocationName } from "../../../Locations/data/LocationNames";
|
||||
import { Companies } from "../../../Company/Companies";
|
||||
import { Company } from "../../../Company/Company";
|
||||
import { calculateCompanyWorkStats } from "../../../Work/formulas/Company";
|
||||
import { applyWorkStats, applyWorkStatsExp, WorkStats } from "../../../Work/WorkStats";
|
||||
import { influenceStockThroughCompanyWork } from "../../../StockMarket/PlayerInfluencing";
|
||||
|
||||
interface SleeveCompanyWorkParams {
|
||||
companyName: string;
|
||||
}
|
||||
|
||||
export const isSleeveCompanyWork = (w: Work | null): w is SleeveCompanyWork =>
|
||||
w !== null && w.type === WorkType.COMPANY;
|
||||
|
||||
export class SleeveCompanyWork extends Work {
|
||||
companyName: string;
|
||||
|
||||
constructor(params?: SleeveCompanyWorkParams) {
|
||||
super(WorkType.COMPANY);
|
||||
this.companyName = params?.companyName ?? LocationName.NewTokyoNoodleBar;
|
||||
}
|
||||
|
||||
getCompany(): Company {
|
||||
const c = Companies[this.companyName];
|
||||
if (!c) throw new Error(`Company not found: '${this.companyName}'`);
|
||||
return c;
|
||||
}
|
||||
|
||||
getGainRates(player: IPlayer, sleeve: Sleeve): WorkStats {
|
||||
return calculateCompanyWorkStats(player, sleeve, this.getCompany());
|
||||
}
|
||||
|
||||
process(player: IPlayer, sleeve: Sleeve, cycles: number): number {
|
||||
const company = this.getCompany();
|
||||
const gains = this.getGainRates(player, sleeve);
|
||||
applyWorkStatsExp(sleeve, gains, cycles);
|
||||
applyWorkStats(player, player, gains, cycles, "sleeves");
|
||||
player.sleeves.filter((s) => s != sleeve).forEach((s) => applyWorkStatsExp(s, gains, cycles));
|
||||
company.playerReputation += gains.reputation * cycles;
|
||||
influenceStockThroughCompanyWork(company, gains.reputation, cycles);
|
||||
return 0;
|
||||
}
|
||||
|
||||
APICopy(): Record<string, unknown> {
|
||||
return {
|
||||
type: this.type,
|
||||
companyName: this.companyName,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Serialize the current object to a JSON save state.
|
||||
*/
|
||||
toJSON(): IReviverValue {
|
||||
return Generic_toJSON("SleeveCompanyWork", this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initiatizes a CompanyWork object from a JSON save state.
|
||||
*/
|
||||
static fromJSON(value: IReviverValue): SleeveCompanyWork {
|
||||
return Generic_fromJSON(SleeveCompanyWork, value.data);
|
||||
}
|
||||
}
|
||||
|
||||
Reviver.constructors.SleeveCompanyWork = SleeveCompanyWork;
|
||||
@@ -0,0 +1,96 @@
|
||||
import { IPlayer } from "../../IPlayer";
|
||||
import { Generic_fromJSON, Generic_toJSON, IReviverValue, Reviver } from "../../../utils/JSONReviver";
|
||||
import { Sleeve } from "../Sleeve";
|
||||
import { Work, WorkType } from "./Work";
|
||||
import { FactionWorkType } from "../../../Work/data/FactionWorkType";
|
||||
import { FactionNames } from "../../../Faction/data/FactionNames";
|
||||
import { Factions } from "../../../Faction/Factions";
|
||||
import { calculateFactionExp } from "../../../Work/formulas/Faction";
|
||||
import { applyWorkStatsExp, scaleWorkStats, WorkStats } from "../../../Work/WorkStats";
|
||||
import { Faction } from "../../../Faction/Faction";
|
||||
import {
|
||||
getFactionFieldWorkRepGain,
|
||||
getFactionSecurityWorkRepGain,
|
||||
getHackingWorkRepGain,
|
||||
} from "../../../PersonObjects/formulas/reputation";
|
||||
|
||||
interface SleeveFactionWorkParams {
|
||||
factionWorkType: FactionWorkType;
|
||||
factionName: string;
|
||||
}
|
||||
|
||||
export const isSleeveFactionWork = (w: Work | null): w is SleeveFactionWork =>
|
||||
w !== null && w.type === WorkType.FACTION;
|
||||
|
||||
export class SleeveFactionWork extends Work {
|
||||
factionWorkType: FactionWorkType;
|
||||
factionName: string;
|
||||
|
||||
constructor(params?: SleeveFactionWorkParams) {
|
||||
super(WorkType.FACTION);
|
||||
this.factionWorkType = params?.factionWorkType ?? FactionWorkType.HACKING;
|
||||
this.factionName = params?.factionName ?? FactionNames.Sector12;
|
||||
}
|
||||
|
||||
getExpRates(sleeve: Sleeve): WorkStats {
|
||||
return scaleWorkStats(calculateFactionExp(sleeve, this.factionWorkType), sleeve.shockBonus());
|
||||
}
|
||||
|
||||
getReputationRate(sleeve: Sleeve): number {
|
||||
const faction = this.getFaction();
|
||||
const repFormulas = {
|
||||
[FactionWorkType.HACKING]: getHackingWorkRepGain,
|
||||
[FactionWorkType.FIELD]: getFactionFieldWorkRepGain,
|
||||
[FactionWorkType.SECURITY]: getFactionSecurityWorkRepGain,
|
||||
};
|
||||
return repFormulas[this.factionWorkType](sleeve, faction) * sleeve.shockBonus();
|
||||
}
|
||||
|
||||
getFaction(): Faction {
|
||||
const f = Factions[this.factionName];
|
||||
if (!f) throw new Error(`Faction work started with invalid / unknown faction: '${this.factionName}'`);
|
||||
return f;
|
||||
}
|
||||
|
||||
process(player: IPlayer, sleeve: Sleeve, cycles: number): number {
|
||||
if (player.gang) {
|
||||
if (this.factionName === player.gang.facName) {
|
||||
sleeve.currentWork = null;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
let exp = this.getExpRates(sleeve);
|
||||
applyWorkStatsExp(sleeve, exp, cycles);
|
||||
exp = scaleWorkStats(exp, sleeve.syncBonus());
|
||||
applyWorkStatsExp(player, exp, cycles);
|
||||
player.sleeves.filter((s) => s != sleeve).forEach((s) => applyWorkStatsExp(s, exp, cycles));
|
||||
const rep = this.getReputationRate(sleeve);
|
||||
this.getFaction().playerReputation += rep;
|
||||
return 0;
|
||||
}
|
||||
|
||||
APICopy(): Record<string, unknown> {
|
||||
return {
|
||||
type: this.type,
|
||||
factionWorkType: this.factionWorkType,
|
||||
factionName: this.factionName,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Serialize the current object to a JSON save state.
|
||||
*/
|
||||
toJSON(): IReviverValue {
|
||||
return Generic_toJSON("SleeveFactionWork", this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initiatizes a FactionWork object from a JSON save state.
|
||||
*/
|
||||
static fromJSON(value: IReviverValue): SleeveFactionWork {
|
||||
return Generic_fromJSON(SleeveFactionWork, value.data);
|
||||
}
|
||||
}
|
||||
|
||||
Reviver.constructors.SleeveFactionWork = SleeveFactionWork;
|
||||
@@ -0,0 +1,54 @@
|
||||
import { IPlayer } from "../../IPlayer";
|
||||
import { Generic_fromJSON, Generic_toJSON, IReviverValue, Reviver } from "../../../utils/JSONReviver";
|
||||
import { Sleeve } from "../Sleeve";
|
||||
import { Work, WorkType } from "./Work";
|
||||
import { CONSTANTS } from "../../../Constants";
|
||||
|
||||
const infiltrateCycles = 600000 / CONSTANTS._idleSpeed;
|
||||
|
||||
export const isSleeveInfiltrateWork = (w: Work | null): w is SleeveInfiltrateWork =>
|
||||
w !== null && w.type === WorkType.INFILTRATE;
|
||||
|
||||
export class SleeveInfiltrateWork extends Work {
|
||||
cyclesWorked = 0;
|
||||
|
||||
constructor() {
|
||||
super(WorkType.INFILTRATE);
|
||||
}
|
||||
|
||||
cyclesNeeded(): number {
|
||||
return infiltrateCycles;
|
||||
}
|
||||
|
||||
process(player: IPlayer, sleeve: Sleeve, cycles: number): number {
|
||||
if (!player.bladeburner) throw new Error("sleeve doing blade work without being a member");
|
||||
this.cyclesWorked += cycles;
|
||||
if (this.cyclesWorked > this.cyclesNeeded()) {
|
||||
this.cyclesWorked -= this.cyclesNeeded();
|
||||
player.bladeburner.infiltrateSynthoidCommunities(player);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
APICopy(): Record<string, unknown> {
|
||||
return {
|
||||
type: this.type,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Serialize the current object to a JSON save state.
|
||||
*/
|
||||
toJSON(): IReviverValue {
|
||||
return Generic_toJSON("SleeveInfiltrateWork", this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initiatizes a BladeburnerWork object from a JSON save state.
|
||||
*/
|
||||
static fromJSON(value: IReviverValue): SleeveInfiltrateWork {
|
||||
return Generic_fromJSON(SleeveInfiltrateWork, value.data);
|
||||
}
|
||||
}
|
||||
|
||||
Reviver.constructors.SleeveInfiltrateWork = SleeveInfiltrateWork;
|
||||
@@ -0,0 +1,41 @@
|
||||
import { IPlayer } from "../../IPlayer";
|
||||
import { Generic_fromJSON, Generic_toJSON, IReviverValue, Reviver } from "../../../utils/JSONReviver";
|
||||
import { Sleeve } from "../Sleeve";
|
||||
import { Work, WorkType } from "./Work";
|
||||
|
||||
export const isSleeveRecoveryWork = (w: Work | null): w is SleeveRecoveryWork =>
|
||||
w !== null && w.type === WorkType.RECOVERY;
|
||||
|
||||
export class SleeveRecoveryWork extends Work {
|
||||
constructor() {
|
||||
super(WorkType.RECOVERY);
|
||||
}
|
||||
|
||||
process(player: IPlayer, sleeve: Sleeve, cycles: number): number {
|
||||
sleeve.shock = Math.min(100, sleeve.shock + 0.0002 * cycles);
|
||||
if (sleeve.shock >= 100) sleeve.currentWork = null;
|
||||
return 0;
|
||||
}
|
||||
|
||||
APICopy(): Record<string, unknown> {
|
||||
return {
|
||||
type: this.type,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Serialize the current object to a JSON save state.
|
||||
*/
|
||||
toJSON(): IReviverValue {
|
||||
return Generic_toJSON("SleeveRecoveryWork", this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initiatizes a RecoveryWork object from a JSON save state.
|
||||
*/
|
||||
static fromJSON(value: IReviverValue): SleeveRecoveryWork {
|
||||
return Generic_fromJSON(SleeveRecoveryWork, value.data);
|
||||
}
|
||||
}
|
||||
|
||||
Reviver.constructors.SleeveRecoveryWork = SleeveRecoveryWork;
|
||||
@@ -0,0 +1,41 @@
|
||||
import { IPlayer } from "../../IPlayer";
|
||||
import { Generic_fromJSON, Generic_toJSON, IReviverValue, Reviver } from "../../../utils/JSONReviver";
|
||||
import { Sleeve } from "../Sleeve";
|
||||
import { Work, WorkType } from "./Work";
|
||||
|
||||
export const isSleeveSynchroWork = (w: Work | null): w is SleeveSynchroWork =>
|
||||
w !== null && w.type === WorkType.SYNCHRO;
|
||||
|
||||
export class SleeveSynchroWork extends Work {
|
||||
constructor() {
|
||||
super(WorkType.SYNCHRO);
|
||||
}
|
||||
|
||||
process(player: IPlayer, sleeve: Sleeve, cycles: number): number {
|
||||
sleeve.sync = Math.min(100, sleeve.sync + player.getIntelligenceBonus(0.5) * 0.0002 * cycles);
|
||||
if (sleeve.sync >= 100) sleeve.currentWork = null;
|
||||
return 0;
|
||||
}
|
||||
|
||||
APICopy(): Record<string, unknown> {
|
||||
return {
|
||||
type: this.type,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Serialize the current object to a JSON save state.
|
||||
*/
|
||||
toJSON(): IReviverValue {
|
||||
return Generic_toJSON("SleeveSynchroWork", this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initiatizes a SynchroWork object from a JSON save state.
|
||||
*/
|
||||
static fromJSON(value: IReviverValue): SleeveSynchroWork {
|
||||
return Generic_fromJSON(SleeveSynchroWork, value.data);
|
||||
}
|
||||
}
|
||||
|
||||
Reviver.constructors.SleeveSynchroWork = SleeveSynchroWork;
|
||||
@@ -0,0 +1,28 @@
|
||||
import { IPlayer } from "../../IPlayer";
|
||||
import { IReviverValue } from "../../../utils/JSONReviver";
|
||||
import { Sleeve } from "../Sleeve";
|
||||
|
||||
export abstract class Work {
|
||||
type: WorkType;
|
||||
|
||||
constructor(type: WorkType) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
abstract process(player: IPlayer, sleeve: Sleeve, cycles: number): number;
|
||||
abstract APICopy(): Record<string, unknown>;
|
||||
abstract toJSON(): IReviverValue;
|
||||
}
|
||||
|
||||
export enum WorkType {
|
||||
COMPANY = "COMPANY",
|
||||
FACTION = "FACTION",
|
||||
CRIME = "CRIME",
|
||||
CLASS = "CLASS",
|
||||
RECOVERY = "RECOVERY",
|
||||
SYNCHRO = "SYNCHRO",
|
||||
BLADEBURNER_GENERAL = "BLADEBURNER_GENERAL",
|
||||
INFILTRATE = "INFILTRATE",
|
||||
BLADEBURNER_SUPPORT = "SUPPORT",
|
||||
BLADEBURNER_CONTRACTS = "CONTRACTS",
|
||||
}
|
||||
Reference in New Issue
Block a user