mirror of
https://github.com/bitburner-official/bitburner-src.git
synced 2026-05-07 16:17:49 +02:00
SLEEVE: Fixed inconsistencies in how sleeve work rewards are handled. (#211)
This commit is contained in:
@@ -4,7 +4,7 @@ import { Sleeve } from "../Sleeve";
|
||||
import { applySleeveGains, Work, WorkType } from "./Work";
|
||||
import { CONSTANTS } from "../../../Constants";
|
||||
import { GeneralActions } from "../../../Bladeburner/data/GeneralActions";
|
||||
import { WorkStats } from "../../../Work/WorkStats";
|
||||
import { scaleWorkStats } from "../../../Work/WorkStats";
|
||||
|
||||
interface SleeveBladeburnerWorkParams {
|
||||
type: string;
|
||||
@@ -31,7 +31,7 @@ export class SleeveBladeburnerWork extends Work {
|
||||
return ret / CONSTANTS._idleSpeed;
|
||||
}
|
||||
|
||||
process(sleeve: Sleeve, cycles: number): number {
|
||||
process(sleeve: Sleeve, cycles: number) {
|
||||
if (!Player.bladeburner) throw new Error("sleeve doing blade work without being a member");
|
||||
this.cyclesWorked += cycles;
|
||||
const actionIdent = Player.bladeburner.getActionIdFromTypeAndName(this.actionType, this.actionName);
|
||||
@@ -39,35 +39,27 @@ export class SleeveBladeburnerWork extends Work {
|
||||
if (this.actionType === "Contracts") {
|
||||
const action = Player.bladeburner.getActionObject(actionIdent);
|
||||
if (!action) throw new Error(`Error getting ${this.actionName} action object`);
|
||||
if (action.count <= 0) {
|
||||
sleeve.stopWork();
|
||||
return 0;
|
||||
}
|
||||
if (action.count <= 0) return sleeve.stopWork();
|
||||
}
|
||||
|
||||
while (this.cyclesWorked > this.cyclesNeeded(sleeve)) {
|
||||
if (this.actionType === "Contracts") {
|
||||
const action = Player.bladeburner.getActionObject(actionIdent);
|
||||
if (!action) throw new Error(`Error getting ${this.actionName} action object`);
|
||||
if (action.count <= 0) {
|
||||
sleeve.stopWork();
|
||||
return 0;
|
||||
}
|
||||
if (action.count <= 0) return sleeve.stopWork();
|
||||
}
|
||||
const retValue = Player.bladeburner.completeAction(sleeve, actionIdent, false);
|
||||
let exp: WorkStats | undefined;
|
||||
if (this.actionType === "General") {
|
||||
exp = GeneralActions[this.actionName]?.exp;
|
||||
const exp = GeneralActions[this.actionName]?.exp;
|
||||
if (!exp) throw new Error(`Somehow there was no exp for action ${this.actionType} ${this.actionName}`);
|
||||
applySleeveGains(sleeve, exp, 1);
|
||||
applySleeveGains(sleeve, scaleWorkStats(exp, sleeve.shockBonus(), false));
|
||||
}
|
||||
|
||||
if (this.actionType === "Contracts") {
|
||||
applySleeveGains(sleeve, retValue, 1);
|
||||
applySleeveGains(sleeve, scaleWorkStats(retValue, sleeve.shockBonus(), false));
|
||||
}
|
||||
this.cyclesWorked -= this.cyclesNeeded(sleeve);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
APICopy(): Record<string, unknown> {
|
||||
|
||||
@@ -33,11 +33,11 @@ export class SleeveClassWork extends Work {
|
||||
);
|
||||
}
|
||||
|
||||
process(sleeve: Sleeve, cycles: number): number {
|
||||
process(sleeve: Sleeve, cycles: number) {
|
||||
const rate = this.calculateRates(sleeve);
|
||||
applySleeveGains(sleeve, rate, cycles);
|
||||
return 0;
|
||||
}
|
||||
|
||||
APICopy(): Record<string, unknown> {
|
||||
return {
|
||||
type: this.type,
|
||||
|
||||
@@ -5,7 +5,7 @@ import { LocationName } from "../../../Locations/data/LocationNames";
|
||||
import { Companies } from "../../../Company/Companies";
|
||||
import { Company } from "../../../Company/Company";
|
||||
import { calculateCompanyWorkStats } from "../../../Work/Formulas";
|
||||
import { WorkStats } from "../../../Work/WorkStats";
|
||||
import { scaleWorkStats, WorkStats } from "../../../Work/WorkStats";
|
||||
import { influenceStockThroughCompanyWork } from "../../../StockMarket/PlayerInfluencing";
|
||||
import { Player } from "@player";
|
||||
import { CompanyPositions } from "../../../Company/CompanyPositions";
|
||||
@@ -33,16 +33,19 @@ export class SleeveCompanyWork extends Work {
|
||||
|
||||
getGainRates(sleeve: Sleeve): WorkStats {
|
||||
const company = this.getCompany();
|
||||
return calculateCompanyWorkStats(sleeve, company, CompanyPositions[Player.jobs[company.name]], company.favor);
|
||||
return scaleWorkStats(
|
||||
calculateCompanyWorkStats(sleeve, company, CompanyPositions[Player.jobs[company.name]], company.favor),
|
||||
sleeve.shockBonus(),
|
||||
false,
|
||||
);
|
||||
}
|
||||
|
||||
process(sleeve: Sleeve, cycles: number): number {
|
||||
process(sleeve: Sleeve, cycles: number) {
|
||||
const company = this.getCompany();
|
||||
const gains = this.getGainRates(sleeve);
|
||||
applySleeveGains(sleeve, gains, cycles);
|
||||
company.playerReputation += gains.reputation * cycles;
|
||||
influenceStockThroughCompanyWork(company, gains.reputation, cycles);
|
||||
return 0;
|
||||
}
|
||||
|
||||
APICopy(): Record<string, unknown> {
|
||||
|
||||
@@ -26,29 +26,24 @@ export class SleeveCrimeWork extends Work {
|
||||
}
|
||||
|
||||
getExp(sleeve: Sleeve): WorkStats {
|
||||
return calculateCrimeWorkStats(sleeve, this.getCrime());
|
||||
return scaleWorkStats(calculateCrimeWorkStats(sleeve, this.getCrime()), sleeve.shockBonus(), false);
|
||||
}
|
||||
|
||||
cyclesNeeded(): number {
|
||||
return this.getCrime().time / CONSTANTS._idleSpeed;
|
||||
}
|
||||
|
||||
process(sleeve: Sleeve, cycles: number): number {
|
||||
process(sleeve: Sleeve, cycles: number) {
|
||||
this.cyclesWorked += cycles;
|
||||
if (this.cyclesWorked < this.cyclesNeeded()) return;
|
||||
|
||||
const crime = this.getCrime();
|
||||
let gains = this.getExp(sleeve);
|
||||
if (this.cyclesWorked >= this.cyclesNeeded()) {
|
||||
if (Math.random() < crime.successRate(sleeve)) {
|
||||
Player.karma -= crime.karma * sleeve.syncBonus();
|
||||
} else {
|
||||
gains.money = 0;
|
||||
gains = scaleWorkStats(gains, 0.25);
|
||||
}
|
||||
applySleeveGains(sleeve, gains, cycles);
|
||||
this.cyclesWorked -= this.cyclesNeeded();
|
||||
}
|
||||
return 0;
|
||||
const gains = this.getExp(sleeve);
|
||||
const success = Math.random() < crime.successRate(sleeve);
|
||||
if (success) Player.karma -= crime.karma * sleeve.syncBonus();
|
||||
else gains.money = 0;
|
||||
applySleeveGains(sleeve, gains, success ? 1 : 0.25);
|
||||
this.cyclesWorked -= this.cyclesNeeded();
|
||||
}
|
||||
|
||||
APICopy(): Record<string, unknown> {
|
||||
|
||||
@@ -28,7 +28,7 @@ export class SleeveFactionWork extends Work {
|
||||
}
|
||||
|
||||
getExpRates(sleeve: Sleeve): WorkStats {
|
||||
return scaleWorkStats(calculateFactionExp(sleeve, this.factionWorkType), sleeve.shockBonus());
|
||||
return scaleWorkStats(calculateFactionExp(sleeve, this.factionWorkType), sleeve.shockBonus(), false);
|
||||
}
|
||||
|
||||
getReputationRate(sleeve: Sleeve): number {
|
||||
@@ -41,17 +41,13 @@ export class SleeveFactionWork extends Work {
|
||||
return f;
|
||||
}
|
||||
|
||||
process(sleeve: Sleeve, cycles: number): number {
|
||||
if (this.factionName === Player.gang?.facName) {
|
||||
sleeve.stopWork();
|
||||
return 0;
|
||||
}
|
||||
process(sleeve: Sleeve, cycles: number) {
|
||||
if (this.factionName === Player.gang?.facName) return sleeve.stopWork();
|
||||
|
||||
const exp = this.getExpRates(sleeve);
|
||||
applySleeveGains(sleeve, exp, cycles);
|
||||
const rep = this.getReputationRate(sleeve);
|
||||
this.getFaction().playerReputation += rep;
|
||||
return 0;
|
||||
this.getFaction().playerReputation += rep * cycles;
|
||||
}
|
||||
|
||||
APICopy(): Record<string, unknown> {
|
||||
|
||||
@@ -20,14 +20,13 @@ export class SleeveInfiltrateWork extends Work {
|
||||
return infiltrateCycles;
|
||||
}
|
||||
|
||||
process(_sleeve: Sleeve, cycles: number): number {
|
||||
process(_sleeve: Sleeve, cycles: 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();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
APICopy(): Record<string, unknown> {
|
||||
|
||||
@@ -10,10 +10,9 @@ export class SleeveRecoveryWork extends Work {
|
||||
super(WorkType.RECOVERY);
|
||||
}
|
||||
|
||||
process(sleeve: Sleeve, cycles: number): number {
|
||||
process(sleeve: Sleeve, cycles: number) {
|
||||
sleeve.shock = Math.min(100, sleeve.shock + 0.0002 * cycles);
|
||||
if (sleeve.shock >= 100) sleeve.stopWork();
|
||||
return 0;
|
||||
}
|
||||
|
||||
APICopy(): Record<string, unknown> {
|
||||
|
||||
@@ -11,8 +11,8 @@ export class SleeveSupportWork extends Work {
|
||||
Player.bladeburner?.sleeveSupport(true);
|
||||
}
|
||||
|
||||
process(): number {
|
||||
return 0;
|
||||
process() {
|
||||
return;
|
||||
}
|
||||
|
||||
finish(): void {
|
||||
|
||||
@@ -12,13 +12,12 @@ export class SleeveSynchroWork extends Work {
|
||||
super(WorkType.SYNCHRO);
|
||||
}
|
||||
|
||||
process(sleeve: Sleeve, cycles: number): number {
|
||||
process(sleeve: Sleeve, cycles: number) {
|
||||
sleeve.sync = Math.min(
|
||||
100,
|
||||
sleeve.sync + calculateIntelligenceBonus(Player.skills.intelligence, 0.5) * 0.0002 * cycles,
|
||||
);
|
||||
if (sleeve.sync >= 100) sleeve.stopWork();
|
||||
return 0;
|
||||
}
|
||||
|
||||
APICopy(): Record<string, unknown> {
|
||||
|
||||
@@ -1,14 +1,16 @@
|
||||
import { Player } from "@player";
|
||||
import { IReviverValue } from "../../../utils/JSONReviver";
|
||||
import { Sleeve } from "../Sleeve";
|
||||
import { applyWorkStats, applyWorkStatsExp, scaleWorkStats, WorkStats } from "../../../Work/WorkStats";
|
||||
import { applyWorkStatsExp, WorkStats } from "../../../Work/WorkStats";
|
||||
|
||||
export const applySleeveGains = (sleeve: Sleeve, rawStats: WorkStats, cycles = 1): void => {
|
||||
const shockedStats = scaleWorkStats(rawStats, sleeve.shockBonus(), rawStats.money > 0);
|
||||
applyWorkStatsExp(sleeve, shockedStats, cycles);
|
||||
const syncStats = scaleWorkStats(shockedStats, sleeve.syncBonus(), rawStats.money > 0);
|
||||
applyWorkStats(Player, syncStats, cycles, "sleeves");
|
||||
Player.sleeves.filter((s) => s !== sleeve).forEach((s) => applyWorkStatsExp(s, syncStats, cycles));
|
||||
export const applySleeveGains = (sleeve: Sleeve, shockedStats: WorkStats, mult = 1): void => {
|
||||
applyWorkStatsExp(sleeve, shockedStats, mult);
|
||||
Player.gainMoney(shockedStats.money * mult, "sleeves");
|
||||
const sync = sleeve.syncBonus();
|
||||
// The receiving sleeves and the player do not apply their xp multipliers from augs (avoid double dipping xp mults)
|
||||
applyWorkStatsExp(Player, shockedStats, mult * sync);
|
||||
// Sleeves apply their own shock bonus to the XP they receive, even though it is also shocked by the working sleeve
|
||||
Player.sleeves.forEach((s) => s !== sleeve && applyWorkStatsExp(s, shockedStats, mult * sync * s.shockBonus()));
|
||||
};
|
||||
|
||||
export abstract class Work {
|
||||
@@ -18,7 +20,7 @@ export abstract class Work {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
abstract process(sleeve: Sleeve, cycles: number): number;
|
||||
abstract process(sleeve: Sleeve, cycles: number): void;
|
||||
abstract APICopy(): Record<string, unknown>;
|
||||
abstract toJSON(): IReviverValue;
|
||||
finish(): void {
|
||||
|
||||
@@ -133,7 +133,7 @@ export function EarningsElement(props: IProps): React.ReactElement {
|
||||
[`Dexterity Exp:`, `${numeralWrapper.formatExp(CYCLES_PER_SEC * rates.dexExp)} / sec`],
|
||||
[`Agility Exp:`, `${numeralWrapper.formatExp(CYCLES_PER_SEC * rates.agiExp)} / sec`],
|
||||
[`Charisma Exp:`, `${numeralWrapper.formatExp(CYCLES_PER_SEC * rates.chaExp)} / sec`],
|
||||
[`Reputation:`, <ReputationRate reputation={repGain} />],
|
||||
[`Reputation:`, <ReputationRate reputation={CYCLES_PER_SEC * repGain} />],
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user