mirror of
https://github.com/bitburner-official/bitburner-src.git
synced 2024-12-20 13:15:48 +01:00
Merge pull request #3935 from danielyxie/sleeve-work
API: rework sleeve work
This commit is contained in:
commit
72a75fe7b7
@ -95,10 +95,10 @@ Singularity
|
|||||||
This means calls like 'ns.connect' need to be changed to 'ns.singularity.connect'
|
This means calls like 'ns.connect' need to be changed to 'ns.singularity.connect'
|
||||||
|
|
||||||
|
|
||||||
stock.buy and stock.sell
|
stock.buy, stock.sell, stock.short
|
||||||
------------------------
|
----------------------------------
|
||||||
|
|
||||||
These 2 functions were renamed to stock.buyStock and stock.sellStock because 'buy' and 'sell'
|
These functions were renamed to stock.buyStock, stock.sellStock, and stock.buyShort because 'buy', 'sell', and 'short'
|
||||||
are very common tokens that would trick the ram calculation.
|
are very common tokens that would trick the ram calculation.
|
||||||
|
|
||||||
corporation.bribe
|
corporation.bribe
|
||||||
|
@ -36,6 +36,8 @@ import { joinFaction } from "../Faction/FactionHelpers";
|
|||||||
import { WorkerScript } from "../Netscript/WorkerScript";
|
import { WorkerScript } from "../Netscript/WorkerScript";
|
||||||
import { FactionNames } from "../Faction/data/FactionNames";
|
import { FactionNames } from "../Faction/data/FactionNames";
|
||||||
import { KEY } from "../utils/helpers/keyCodes";
|
import { KEY } from "../utils/helpers/keyCodes";
|
||||||
|
import { isSleeveInfiltrateWork } from "../PersonObjects/Sleeve/Work/SleeveInfiltrateWork";
|
||||||
|
import { isSleeveSupportWork } from "../PersonObjects/Sleeve/Work/SleeveSupportWork";
|
||||||
|
|
||||||
interface BlackOpsAttempt {
|
interface BlackOpsAttempt {
|
||||||
error?: string;
|
error?: string;
|
||||||
@ -1124,7 +1126,7 @@ export class Bladeburner implements IBladeburner {
|
|||||||
const losses = getRandomInt(0, max);
|
const losses = getRandomInt(0, max);
|
||||||
this.teamSize -= losses;
|
this.teamSize -= losses;
|
||||||
if (this.teamSize < this.sleeveSize) {
|
if (this.teamSize < this.sleeveSize) {
|
||||||
const sup = player.sleeves.filter((x) => x.bbAction == "Support main sleeve");
|
const sup = player.sleeves.filter((x) => isSleeveSupportWork(x.currentWork));
|
||||||
for (let i = 0; i > this.teamSize - this.sleeveSize; i--) {
|
for (let i = 0; i > this.teamSize - this.sleeveSize; i--) {
|
||||||
const r = Math.floor(Math.random() * sup.length);
|
const r = Math.floor(Math.random() * sup.length);
|
||||||
sup[r].takeDamage(sup[r].hp.max);
|
sup[r].takeDamage(sup[r].hp.max);
|
||||||
@ -1438,7 +1440,7 @@ export class Bladeburner implements IBladeburner {
|
|||||||
const losses = getRandomInt(1, teamLossMax);
|
const losses = getRandomInt(1, teamLossMax);
|
||||||
this.teamSize -= losses;
|
this.teamSize -= losses;
|
||||||
if (this.teamSize < this.sleeveSize) {
|
if (this.teamSize < this.sleeveSize) {
|
||||||
const sup = player.sleeves.filter((x) => x.bbAction == "Support main sleeve");
|
const sup = player.sleeves.filter((x) => isSleeveSupportWork(x.currentWork));
|
||||||
for (let i = 0; i > this.teamSize - this.sleeveSize; i--) {
|
for (let i = 0; i > this.teamSize - this.sleeveSize; i--) {
|
||||||
const r = Math.floor(Math.random() * sup.length);
|
const r = Math.floor(Math.random() * sup.length);
|
||||||
sup[r].takeDamage(sup[r].hp.max);
|
sup[r].takeDamage(sup[r].hp.max);
|
||||||
@ -1452,7 +1454,7 @@ export class Bladeburner implements IBladeburner {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (e: unknown) {
|
} catch (e: unknown) {
|
||||||
exceptionAlert(e);
|
exceptionAlert(String(e));
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -1602,7 +1604,7 @@ export class Bladeburner implements IBladeburner {
|
|||||||
}
|
}
|
||||||
|
|
||||||
infiltrateSynthoidCommunities(p: IPlayer): void {
|
infiltrateSynthoidCommunities(p: IPlayer): void {
|
||||||
const infilSleeves = p.sleeves.filter((s) => s.bbAction === "Infiltrate synthoids").length;
|
const infilSleeves = p.sleeves.filter((s) => isSleeveInfiltrateWork(s.currentWork)).length;
|
||||||
const amt = Math.pow(infilSleeves, -0.5) / 2;
|
const amt = Math.pow(infilSleeves, -0.5) / 2;
|
||||||
for (const contract of Object.keys(this.contracts)) {
|
for (const contract of Object.keys(this.contracts)) {
|
||||||
this.contracts[contract].count += amt;
|
this.contracts[contract].count += amt;
|
||||||
|
@ -1,11 +1,13 @@
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
|
import { newWorkStats, WorkStats } from "../../Work/WorkStats";
|
||||||
|
|
||||||
interface IContract {
|
interface IGeneral {
|
||||||
desc: JSX.Element;
|
desc: JSX.Element;
|
||||||
|
exp: WorkStats;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const GeneralActions: {
|
export const GeneralActions: {
|
||||||
[key: string]: IContract | undefined;
|
[key: string]: IGeneral | undefined;
|
||||||
} = {
|
} = {
|
||||||
Training: {
|
Training: {
|
||||||
desc: (
|
desc: (
|
||||||
@ -14,6 +16,12 @@ export const GeneralActions: {
|
|||||||
all combat stats and also increases your max stamina.
|
all combat stats and also increases your max stamina.
|
||||||
</>
|
</>
|
||||||
),
|
),
|
||||||
|
exp: newWorkStats({
|
||||||
|
strExp: 30,
|
||||||
|
defExp: 30,
|
||||||
|
dexExp: 30,
|
||||||
|
agiExp: 30,
|
||||||
|
}),
|
||||||
},
|
},
|
||||||
|
|
||||||
"Field Analysis": {
|
"Field Analysis": {
|
||||||
@ -27,6 +35,10 @@ export const GeneralActions: {
|
|||||||
Does NOT require stamina.
|
Does NOT require stamina.
|
||||||
</>
|
</>
|
||||||
),
|
),
|
||||||
|
exp: newWorkStats({
|
||||||
|
hackExp: 20,
|
||||||
|
chaExp: 20,
|
||||||
|
}),
|
||||||
},
|
},
|
||||||
|
|
||||||
Recruitment: {
|
Recruitment: {
|
||||||
@ -38,6 +50,9 @@ export const GeneralActions: {
|
|||||||
Does NOT require stamina.
|
Does NOT require stamina.
|
||||||
</>
|
</>
|
||||||
),
|
),
|
||||||
|
exp: newWorkStats({
|
||||||
|
chaExp: 120,
|
||||||
|
}),
|
||||||
},
|
},
|
||||||
|
|
||||||
Diplomacy: {
|
Diplomacy: {
|
||||||
@ -50,6 +65,9 @@ export const GeneralActions: {
|
|||||||
Does NOT require stamina.
|
Does NOT require stamina.
|
||||||
</>
|
</>
|
||||||
),
|
),
|
||||||
|
exp: newWorkStats({
|
||||||
|
chaExp: 120,
|
||||||
|
}),
|
||||||
},
|
},
|
||||||
|
|
||||||
"Hyperbolic Regeneration Chamber": {
|
"Hyperbolic Regeneration Chamber": {
|
||||||
@ -61,6 +79,7 @@ export const GeneralActions: {
|
|||||||
<br />
|
<br />
|
||||||
</>
|
</>
|
||||||
),
|
),
|
||||||
|
exp: newWorkStats(),
|
||||||
},
|
},
|
||||||
"Incite Violence": {
|
"Incite Violence": {
|
||||||
desc: (
|
desc: (
|
||||||
@ -69,5 +88,12 @@ export const GeneralActions: {
|
|||||||
additional contracts and operations, at the cost of increased Chaos.
|
additional contracts and operations, at the cost of increased Chaos.
|
||||||
</>
|
</>
|
||||||
),
|
),
|
||||||
|
exp: newWorkStats({
|
||||||
|
strExp: 10,
|
||||||
|
defExp: 10,
|
||||||
|
dexExp: 10,
|
||||||
|
agiExp: 10,
|
||||||
|
chaExp: 10,
|
||||||
|
}),
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
@ -6,7 +6,7 @@ import { IMap } from "../types";
|
|||||||
import { CrimeType } from "../utils/WorkType";
|
import { CrimeType } from "../utils/WorkType";
|
||||||
|
|
||||||
export const Crimes: IMap<Crime> = {
|
export const Crimes: IMap<Crime> = {
|
||||||
Shoplift: new Crime("Shoplift", CrimeType.Shoplift, 2e3, 15e3, 1 / 20, 0.1, {
|
Shoplift: new Crime("Shoplift", CrimeType.SHOPLIFT, 2e3, 15e3, 1 / 20, 0.1, {
|
||||||
dexterity_success_weight: 1,
|
dexterity_success_weight: 1,
|
||||||
agility_success_weight: 1,
|
agility_success_weight: 1,
|
||||||
|
|
||||||
@ -14,7 +14,7 @@ export const Crimes: IMap<Crime> = {
|
|||||||
agility_exp: 2,
|
agility_exp: 2,
|
||||||
}),
|
}),
|
||||||
|
|
||||||
RobStore: new Crime("Rob Store", CrimeType.RobStore, 60e3, 400e3, 1 / 5, 0.5, {
|
RobStore: new Crime("Rob Store", CrimeType.ROB_STORE, 60e3, 400e3, 1 / 5, 0.5, {
|
||||||
hacking_exp: 30,
|
hacking_exp: 30,
|
||||||
dexterity_exp: 45,
|
dexterity_exp: 45,
|
||||||
agility_exp: 45,
|
agility_exp: 45,
|
||||||
@ -26,7 +26,7 @@ export const Crimes: IMap<Crime> = {
|
|||||||
intelligence_exp: 7.5 * CONSTANTS.IntelligenceCrimeBaseExpGain,
|
intelligence_exp: 7.5 * CONSTANTS.IntelligenceCrimeBaseExpGain,
|
||||||
}),
|
}),
|
||||||
|
|
||||||
Mug: new Crime("Mug", CrimeType.Mug, 4e3, 36e3, 1 / 5, 0.25, {
|
Mug: new Crime("Mug", CrimeType.MUG, 4e3, 36e3, 1 / 5, 0.25, {
|
||||||
strength_exp: 3,
|
strength_exp: 3,
|
||||||
defense_exp: 3,
|
defense_exp: 3,
|
||||||
dexterity_exp: 3,
|
dexterity_exp: 3,
|
||||||
@ -38,7 +38,7 @@ export const Crimes: IMap<Crime> = {
|
|||||||
agility_success_weight: 0.5,
|
agility_success_weight: 0.5,
|
||||||
}),
|
}),
|
||||||
|
|
||||||
Larceny: new Crime("Larceny", CrimeType.Larceny, 90e3, 800e3, 1 / 3, 1.5, {
|
Larceny: new Crime("Larceny", CrimeType.LARCENY, 90e3, 800e3, 1 / 3, 1.5, {
|
||||||
hacking_exp: 45,
|
hacking_exp: 45,
|
||||||
dexterity_exp: 60,
|
dexterity_exp: 60,
|
||||||
agility_exp: 60,
|
agility_exp: 60,
|
||||||
@ -50,7 +50,7 @@ export const Crimes: IMap<Crime> = {
|
|||||||
intelligence_exp: 15 * CONSTANTS.IntelligenceCrimeBaseExpGain,
|
intelligence_exp: 15 * CONSTANTS.IntelligenceCrimeBaseExpGain,
|
||||||
}),
|
}),
|
||||||
|
|
||||||
DealDrugs: new Crime("Deal Drugs", CrimeType.Drugs, 10e3, 120e3, 1, 0.5, {
|
DealDrugs: new Crime("Deal Drugs", CrimeType.DRUGS, 10e3, 120e3, 1, 0.5, {
|
||||||
dexterity_exp: 5,
|
dexterity_exp: 5,
|
||||||
agility_exp: 5,
|
agility_exp: 5,
|
||||||
charisma_exp: 10,
|
charisma_exp: 10,
|
||||||
@ -60,7 +60,7 @@ export const Crimes: IMap<Crime> = {
|
|||||||
agility_success_weight: 1,
|
agility_success_weight: 1,
|
||||||
}),
|
}),
|
||||||
|
|
||||||
BondForgery: new Crime("Bond Forgery", CrimeType.BondForgery, 300e3, 4.5e6, 1 / 2, 0.1, {
|
BondForgery: new Crime("Bond Forgery", CrimeType.BOND_FORGERY, 300e3, 4.5e6, 1 / 2, 0.1, {
|
||||||
hacking_exp: 100,
|
hacking_exp: 100,
|
||||||
dexterity_exp: 150,
|
dexterity_exp: 150,
|
||||||
charisma_exp: 15,
|
charisma_exp: 15,
|
||||||
@ -71,7 +71,7 @@ export const Crimes: IMap<Crime> = {
|
|||||||
intelligence_exp: 60 * CONSTANTS.IntelligenceCrimeBaseExpGain,
|
intelligence_exp: 60 * CONSTANTS.IntelligenceCrimeBaseExpGain,
|
||||||
}),
|
}),
|
||||||
|
|
||||||
TraffickArms: new Crime("Traffick Arms", CrimeType.TraffickArms, 40e3, 600e3, 2, 1, {
|
TraffickArms: new Crime("Traffick Arms", CrimeType.TRAFFIC_ARMS, 40e3, 600e3, 2, 1, {
|
||||||
strength_exp: 20,
|
strength_exp: 20,
|
||||||
defense_exp: 20,
|
defense_exp: 20,
|
||||||
dexterity_exp: 20,
|
dexterity_exp: 20,
|
||||||
@ -85,7 +85,7 @@ export const Crimes: IMap<Crime> = {
|
|||||||
agility_success_weight: 1,
|
agility_success_weight: 1,
|
||||||
}),
|
}),
|
||||||
|
|
||||||
Homicide: new Crime("Homicide", CrimeType.Homicide, 3e3, 45e3, 1, 3, {
|
Homicide: new Crime("Homicide", CrimeType.HOMICIDE, 3e3, 45e3, 1, 3, {
|
||||||
strength_exp: 2,
|
strength_exp: 2,
|
||||||
defense_exp: 2,
|
defense_exp: 2,
|
||||||
dexterity_exp: 2,
|
dexterity_exp: 2,
|
||||||
@ -99,7 +99,7 @@ export const Crimes: IMap<Crime> = {
|
|||||||
kills: 1,
|
kills: 1,
|
||||||
}),
|
}),
|
||||||
|
|
||||||
GrandTheftAuto: new Crime("Grand Theft Auto", CrimeType.GrandTheftAuto, 80e3, 1.6e6, 8, 5, {
|
GrandTheftAuto: new Crime("Grand Theft Auto", CrimeType.GRAND_THEFT_AUTO, 80e3, 1.6e6, 8, 5, {
|
||||||
strength_exp: 20,
|
strength_exp: 20,
|
||||||
defense_exp: 20,
|
defense_exp: 20,
|
||||||
dexterity_exp: 20,
|
dexterity_exp: 20,
|
||||||
@ -115,7 +115,7 @@ export const Crimes: IMap<Crime> = {
|
|||||||
intelligence_exp: 16 * CONSTANTS.IntelligenceCrimeBaseExpGain,
|
intelligence_exp: 16 * CONSTANTS.IntelligenceCrimeBaseExpGain,
|
||||||
}),
|
}),
|
||||||
|
|
||||||
Kidnap: new Crime("Kidnap", CrimeType.Kidnap, 120e3, 3.6e6, 5, 6, {
|
Kidnap: new Crime("Kidnap", CrimeType.KIDNAP, 120e3, 3.6e6, 5, 6, {
|
||||||
strength_exp: 80,
|
strength_exp: 80,
|
||||||
defense_exp: 80,
|
defense_exp: 80,
|
||||||
dexterity_exp: 80,
|
dexterity_exp: 80,
|
||||||
@ -130,7 +130,7 @@ export const Crimes: IMap<Crime> = {
|
|||||||
intelligence_exp: 26 * CONSTANTS.IntelligenceCrimeBaseExpGain,
|
intelligence_exp: 26 * CONSTANTS.IntelligenceCrimeBaseExpGain,
|
||||||
}),
|
}),
|
||||||
|
|
||||||
Assassination: new Crime("Assassination", CrimeType.Assassination, 300e3, 12e6, 8, 10, {
|
Assassination: new Crime("Assassination", CrimeType.ASSASSINATION, 300e3, 12e6, 8, 10, {
|
||||||
strength_exp: 300,
|
strength_exp: 300,
|
||||||
defense_exp: 300,
|
defense_exp: 300,
|
||||||
dexterity_exp: 300,
|
dexterity_exp: 300,
|
||||||
@ -145,7 +145,7 @@ export const Crimes: IMap<Crime> = {
|
|||||||
kills: 1,
|
kills: 1,
|
||||||
}),
|
}),
|
||||||
|
|
||||||
Heist: new Crime("Heist", CrimeType.Heist, 600e3, 120e6, 18, 15, {
|
Heist: new Crime("Heist", CrimeType.HEIST, 600e3, 120e6, 18, 15, {
|
||||||
hacking_exp: 450,
|
hacking_exp: 450,
|
||||||
strength_exp: 450,
|
strength_exp: 450,
|
||||||
defense_exp: 450,
|
defense_exp: 450,
|
||||||
|
@ -136,7 +136,7 @@ const stock = {
|
|||||||
getSaleGain: RamCostConstants.ScriptGetStockRamCost,
|
getSaleGain: RamCostConstants.ScriptGetStockRamCost,
|
||||||
buyStock: RamCostConstants.ScriptBuySellStockRamCost,
|
buyStock: RamCostConstants.ScriptBuySellStockRamCost,
|
||||||
sellStock: RamCostConstants.ScriptBuySellStockRamCost,
|
sellStock: RamCostConstants.ScriptBuySellStockRamCost,
|
||||||
short: RamCostConstants.ScriptBuySellStockRamCost,
|
buyShort: RamCostConstants.ScriptBuySellStockRamCost,
|
||||||
sellShort: RamCostConstants.ScriptBuySellStockRamCost,
|
sellShort: RamCostConstants.ScriptBuySellStockRamCost,
|
||||||
placeOrder: RamCostConstants.ScriptBuySellStockRamCost,
|
placeOrder: RamCostConstants.ScriptBuySellStockRamCost,
|
||||||
cancelOrder: RamCostConstants.ScriptBuySellStockRamCost,
|
cancelOrder: RamCostConstants.ScriptBuySellStockRamCost,
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
import { IPlayer } from "../PersonObjects/IPlayer";
|
import { IPlayer } from "../PersonObjects/IPlayer";
|
||||||
import { SleeveTaskType } from "../PersonObjects/Sleeve/SleeveTaskTypesEnum";
|
|
||||||
import { findSleevePurchasableAugs } from "../PersonObjects/Sleeve/SleeveHelpers";
|
import { findSleevePurchasableAugs } from "../PersonObjects/Sleeve/SleeveHelpers";
|
||||||
import { StaticAugmentations } from "../Augmentation/StaticAugmentations";
|
import { StaticAugmentations } from "../Augmentation/StaticAugmentations";
|
||||||
import { CityName } from "../Locations/data/CityNames";
|
import { CityName } from "../Locations/data/CityNames";
|
||||||
@ -15,7 +14,9 @@ import {
|
|||||||
} from "../ScriptEditor/NetscriptDefinitions";
|
} from "../ScriptEditor/NetscriptDefinitions";
|
||||||
import { checkEnum } from "../utils/helpers/checkEnum";
|
import { checkEnum } from "../utils/helpers/checkEnum";
|
||||||
import { InternalAPI, NetscriptContext } from "../Netscript/APIWrapper";
|
import { InternalAPI, NetscriptContext } from "../Netscript/APIWrapper";
|
||||||
import { FactionWorkType } from "../Work/data/FactionWorkType";
|
import { isSleeveBladeburnerWork } from "../PersonObjects/Sleeve/Work/SleeveBladeburnerWork";
|
||||||
|
import { isSleeveFactionWork } from "../PersonObjects/Sleeve/Work/SleeveFactionWork";
|
||||||
|
import { isSleeveCompanyWork } from "../PersonObjects/Sleeve/Work/SleeveCompanyWork";
|
||||||
|
|
||||||
export function NetscriptSleeve(player: IPlayer): InternalAPI<ISleeve> {
|
export function NetscriptSleeve(player: IPlayer): InternalAPI<ISleeve> {
|
||||||
const checkSleeveAPIAccess = function (ctx: NetscriptContext): void {
|
const checkSleeveAPIAccess = function (ctx: NetscriptContext): void {
|
||||||
@ -120,7 +121,7 @@ export function NetscriptSleeve(player: IPlayer): InternalAPI<ISleeve> {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
const other = player.sleeves[i];
|
const other = player.sleeves[i];
|
||||||
if (other.currentTask === SleeveTaskType.Company && other.currentTaskLocation === companyName) {
|
if (isSleeveCompanyWork(other.currentWork) && other.currentWork.companyName === companyName) {
|
||||||
throw ctx.makeRuntimeErrorMsg(
|
throw ctx.makeRuntimeErrorMsg(
|
||||||
`Sleeve ${sleeveNumber} cannot work for company ${companyName} because Sleeve ${i} is already working for them.`,
|
`Sleeve ${sleeveNumber} cannot work for company ${companyName} because Sleeve ${i} is already working for them.`,
|
||||||
);
|
);
|
||||||
@ -144,7 +145,7 @@ export function NetscriptSleeve(player: IPlayer): InternalAPI<ISleeve> {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
const other = player.sleeves[i];
|
const other = player.sleeves[i];
|
||||||
if (other.currentTask === SleeveTaskType.Faction && other.currentTaskLocation === factionName) {
|
if (isSleeveFactionWork(other.currentWork) && other.currentWork.factionName === factionName) {
|
||||||
throw ctx.makeRuntimeErrorMsg(
|
throw ctx.makeRuntimeErrorMsg(
|
||||||
`Sleeve ${sleeveNumber} cannot work for faction ${factionName} because Sleeve ${i} is already working for them.`,
|
`Sleeve ${sleeveNumber} cannot work for faction ${factionName} because Sleeve ${i} is already working for them.`,
|
||||||
);
|
);
|
||||||
@ -180,20 +181,14 @@ export function NetscriptSleeve(player: IPlayer): InternalAPI<ISleeve> {
|
|||||||
},
|
},
|
||||||
getTask:
|
getTask:
|
||||||
(ctx: NetscriptContext) =>
|
(ctx: NetscriptContext) =>
|
||||||
(_sleeveNumber: unknown): SleeveTask => {
|
(_sleeveNumber: unknown): SleeveTask | null => {
|
||||||
const sleeveNumber = ctx.helper.number("sleeveNumber", _sleeveNumber);
|
const sleeveNumber = ctx.helper.number("sleeveNumber", _sleeveNumber);
|
||||||
checkSleeveAPIAccess(ctx);
|
checkSleeveAPIAccess(ctx);
|
||||||
checkSleeveNumber(ctx, sleeveNumber);
|
checkSleeveNumber(ctx, sleeveNumber);
|
||||||
|
|
||||||
const sl = player.sleeves[sleeveNumber];
|
const sl = player.sleeves[sleeveNumber];
|
||||||
return {
|
if (sl.currentWork === null) return null;
|
||||||
task: SleeveTaskType[sl.currentTask],
|
return sl.currentWork.APICopy();
|
||||||
crime: sl.crimeType,
|
|
||||||
location: sl.currentTaskLocation,
|
|
||||||
gymStatType: sl.gymStatType,
|
|
||||||
factionWorkType: FactionWorkType[sl.factionWorkType],
|
|
||||||
className: sl.className,
|
|
||||||
};
|
|
||||||
},
|
},
|
||||||
getInformation:
|
getInformation:
|
||||||
(ctx: NetscriptContext) =>
|
(ctx: NetscriptContext) =>
|
||||||
@ -229,36 +224,6 @@ export function NetscriptSleeve(player: IPlayer): InternalAPI<ISleeve> {
|
|||||||
strengthExp: sl.mults.strength_exp,
|
strengthExp: sl.mults.strength_exp,
|
||||||
workMoney: sl.mults.work_money,
|
workMoney: sl.mults.work_money,
|
||||||
},
|
},
|
||||||
|
|
||||||
timeWorked: sl.currentTaskTime,
|
|
||||||
earningsForSleeves: {
|
|
||||||
workHackExpGain: sl.earningsForSleeves.hack,
|
|
||||||
workStrExpGain: sl.earningsForSleeves.str,
|
|
||||||
workDefExpGain: sl.earningsForSleeves.def,
|
|
||||||
workDexExpGain: sl.earningsForSleeves.dex,
|
|
||||||
workAgiExpGain: sl.earningsForSleeves.agi,
|
|
||||||
workChaExpGain: sl.earningsForSleeves.cha,
|
|
||||||
workMoneyGain: sl.earningsForSleeves.money,
|
|
||||||
},
|
|
||||||
earningsForPlayer: {
|
|
||||||
workHackExpGain: sl.earningsForPlayer.hack,
|
|
||||||
workStrExpGain: sl.earningsForPlayer.str,
|
|
||||||
workDefExpGain: sl.earningsForPlayer.def,
|
|
||||||
workDexExpGain: sl.earningsForPlayer.dex,
|
|
||||||
workAgiExpGain: sl.earningsForPlayer.agi,
|
|
||||||
workChaExpGain: sl.earningsForPlayer.cha,
|
|
||||||
workMoneyGain: sl.earningsForPlayer.money,
|
|
||||||
},
|
|
||||||
earningsForTask: {
|
|
||||||
workHackExpGain: sl.earningsForTask.hack,
|
|
||||||
workStrExpGain: sl.earningsForTask.str,
|
|
||||||
workDefExpGain: sl.earningsForTask.def,
|
|
||||||
workDexExpGain: sl.earningsForTask.dex,
|
|
||||||
workAgiExpGain: sl.earningsForTask.agi,
|
|
||||||
workChaExpGain: sl.earningsForTask.cha,
|
|
||||||
workMoneyGain: sl.earningsForTask.money,
|
|
||||||
},
|
|
||||||
workRepGain: sl.getRepGain(player),
|
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
getSleeveAugmentations:
|
getSleeveAugmentations:
|
||||||
@ -349,11 +314,7 @@ export function NetscriptSleeve(player: IPlayer): InternalAPI<ISleeve> {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
const other = player.sleeves[i];
|
const other = player.sleeves[i];
|
||||||
if (
|
if (isSleeveBladeburnerWork(other.currentWork) && other.currentWork.actionName === contract) {
|
||||||
other.currentTask === SleeveTaskType.Bladeburner &&
|
|
||||||
other.bbAction === action &&
|
|
||||||
other.bbContract === contract
|
|
||||||
) {
|
|
||||||
throw ctx.helper.makeRuntimeErrorMsg(
|
throw ctx.helper.makeRuntimeErrorMsg(
|
||||||
`Sleeve ${sleeveNumber} cannot take on contracts because Sleeve ${i} is already performing that action.`,
|
`Sleeve ${sleeveNumber} cannot take on contracts because Sleeve ${i} is already performing that action.`,
|
||||||
);
|
);
|
||||||
|
@ -165,7 +165,7 @@ export function NetscriptStockMarket(player: IPlayer, workerScript: WorkerScript
|
|||||||
|
|
||||||
return res ? stock.getBidPrice() : 0;
|
return res ? stock.getBidPrice() : 0;
|
||||||
},
|
},
|
||||||
short:
|
buyShort:
|
||||||
(ctx: NetscriptContext) =>
|
(ctx: NetscriptContext) =>
|
||||||
(_symbol: unknown, _shares: unknown): number => {
|
(_symbol: unknown, _shares: unknown): number => {
|
||||||
const symbol = ctx.helper.string("symbol", _symbol);
|
const symbol = ctx.helper.string("symbol", _symbol);
|
||||||
|
File diff suppressed because it is too large
Load Diff
74
src/PersonObjects/Sleeve/Work/SleeveBladeburnerWork.ts
Normal file
74
src/PersonObjects/Sleeve/Work/SleeveBladeburnerWork.ts
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
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";
|
||||||
|
import { GeneralActions } from "../../../Bladeburner/data/GeneralActions";
|
||||||
|
import { applyWorkStatsExp, WorkStats } from "../../../Work/WorkStats";
|
||||||
|
|
||||||
|
interface SleeveBladeburnerWorkParams {
|
||||||
|
type: string;
|
||||||
|
name: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const isSleeveBladeburnerWork = (w: Work | null): w is SleeveBladeburnerWork =>
|
||||||
|
w !== null && w.type === WorkType.BLADEBURNER;
|
||||||
|
|
||||||
|
export class SleeveBladeburnerWork extends Work {
|
||||||
|
cyclesWorked = 0;
|
||||||
|
actionType: string;
|
||||||
|
actionName: string;
|
||||||
|
|
||||||
|
constructor(params?: SleeveBladeburnerWorkParams) {
|
||||||
|
super(WorkType.BLADEBURNER);
|
||||||
|
this.actionType = params?.type ?? "General";
|
||||||
|
this.actionName = params?.name ?? "Field analysis";
|
||||||
|
}
|
||||||
|
|
||||||
|
cyclesNeeded(player: IPlayer, sleeve: Sleeve): number {
|
||||||
|
const ret = player.bladeburner?.getActionTimeNetscriptFn(sleeve, this.actionType, this.actionName);
|
||||||
|
if (!ret || typeof ret === "string") throw new Error(`Error querying ${this.actionName} 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(this.actionType, this.actionName);
|
||||||
|
if (!actionIdent) throw new Error(`Error getting ${this.actionName} action`);
|
||||||
|
player.bladeburner.completeAction(player, sleeve, actionIdent, false);
|
||||||
|
let exp: WorkStats | undefined;
|
||||||
|
if (this.actionType === "General") {
|
||||||
|
exp = GeneralActions[this.actionName]?.exp;
|
||||||
|
if (!exp) throw new Error(`Somehow there was no exp for action ${this.actionType} ${this.actionName}`);
|
||||||
|
applyWorkStatsExp(sleeve, exp, 1);
|
||||||
|
}
|
||||||
|
this.cyclesWorked -= this.cyclesNeeded(player, sleeve);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
APICopy(): Record<string, unknown> {
|
||||||
|
return {
|
||||||
|
actionType: this.actionType,
|
||||||
|
actionName: this.actionName,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Serialize the current object to a JSON save state.
|
||||||
|
*/
|
||||||
|
toJSON(): IReviverValue {
|
||||||
|
return Generic_toJSON("SleeveBladeburnerWork", this);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initiatizes a BladeburnerWork object from a JSON save state.
|
||||||
|
*/
|
||||||
|
static fromJSON(value: IReviverValue): SleeveBladeburnerWork {
|
||||||
|
return Generic_fromJSON(SleeveBladeburnerWork, value.data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Reviver.constructors.SleeveBladeburnerWork = SleeveBladeburnerWork;
|
71
src/PersonObjects/Sleeve/Work/SleeveClassWork.ts
Normal file
71
src/PersonObjects/Sleeve/Work/SleeveClassWork.ts
Normal file
@ -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;
|
70
src/PersonObjects/Sleeve/Work/SleeveCompanyWork.ts
Normal file
70
src/PersonObjects/Sleeve/Work/SleeveCompanyWork.ts
Normal file
@ -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;
|
84
src/PersonObjects/Sleeve/Work/SleeveCrimeWork.ts
Normal file
84
src/PersonObjects/Sleeve/Work/SleeveCrimeWork.ts
Normal file
@ -0,0 +1,84 @@
|
|||||||
|
import { IPlayer } from "../../IPlayer";
|
||||||
|
import { Generic_fromJSON, Generic_toJSON, IReviverValue, Reviver } from "../../../utils/JSONReviver";
|
||||||
|
import { Sleeve } from "../Sleeve";
|
||||||
|
import { Work, WorkType } from "./Work";
|
||||||
|
import { CrimeType } from "../../../utils/WorkType";
|
||||||
|
import { Crimes } from "../../../Crime/Crimes";
|
||||||
|
import { Crime } from "../../../Crime/Crime";
|
||||||
|
import { applyWorkStats, newWorkStats, scaleWorkStats, WorkStats } from "../../../Work/WorkStats";
|
||||||
|
import { CONSTANTS } from "../../../Constants";
|
||||||
|
|
||||||
|
export const isSleeveCrimeWork = (w: Work | null): w is SleeveCrimeWork => w !== null && w.type === WorkType.CRIME;
|
||||||
|
|
||||||
|
export class SleeveCrimeWork extends Work {
|
||||||
|
crimeType: CrimeType;
|
||||||
|
cyclesWorked = 0;
|
||||||
|
constructor(crimeType?: CrimeType) {
|
||||||
|
super(WorkType.CRIME);
|
||||||
|
this.crimeType = crimeType ?? CrimeType.SHOPLIFT;
|
||||||
|
}
|
||||||
|
|
||||||
|
getCrime(): Crime {
|
||||||
|
const crime = Object.values(Crimes).find((crime) => crime.type === this.crimeType);
|
||||||
|
if (!crime) throw new Error("crime should not be undefined");
|
||||||
|
return crime;
|
||||||
|
}
|
||||||
|
|
||||||
|
getExp(): WorkStats {
|
||||||
|
const crime = this.getCrime();
|
||||||
|
return newWorkStats({
|
||||||
|
money: crime.money,
|
||||||
|
hackExp: crime.hacking_exp,
|
||||||
|
strExp: crime.strength_exp,
|
||||||
|
defExp: crime.defense_exp,
|
||||||
|
dexExp: crime.dexterity_exp,
|
||||||
|
agiExp: crime.agility_exp,
|
||||||
|
chaExp: crime.charisma_exp,
|
||||||
|
intExp: crime.intelligence_exp,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
cyclesNeeded(): number {
|
||||||
|
return this.getCrime().time / CONSTANTS._idleSpeed;
|
||||||
|
}
|
||||||
|
|
||||||
|
process(player: IPlayer, sleeve: Sleeve, cycles: number): number {
|
||||||
|
this.cyclesWorked += cycles;
|
||||||
|
|
||||||
|
const crime = this.getCrime();
|
||||||
|
const gains = this.getExp();
|
||||||
|
if (this.cyclesWorked >= this.cyclesNeeded()) {
|
||||||
|
if (Math.random() < crime.successRate(sleeve)) {
|
||||||
|
applyWorkStats(player, sleeve, gains, 1, "sleeves");
|
||||||
|
|
||||||
|
player.karma -= crime.karma * sleeve.syncBonus();
|
||||||
|
} else {
|
||||||
|
applyWorkStats(player, sleeve, scaleWorkStats(gains, 0.25), 1, "sleeves");
|
||||||
|
}
|
||||||
|
this.cyclesWorked -= this.cyclesNeeded();
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
APICopy(): Record<string, unknown> {
|
||||||
|
return {
|
||||||
|
type: this.type,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Serialize the current object to a JSON save state.
|
||||||
|
*/
|
||||||
|
toJSON(): IReviverValue {
|
||||||
|
return Generic_toJSON("SleeveCrimeWork", this);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initiatizes a RecoveryWork object from a JSON save state.
|
||||||
|
*/
|
||||||
|
static fromJSON(value: IReviverValue): SleeveCrimeWork {
|
||||||
|
return Generic_fromJSON(SleeveCrimeWork, value.data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Reviver.constructors.SleeveCrimeWork = SleeveCrimeWork;
|
96
src/PersonObjects/Sleeve/Work/SleeveFactionWork.ts
Normal file
96
src/PersonObjects/Sleeve/Work/SleeveFactionWork.ts
Normal file
@ -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.stopWork(player);
|
||||||
|
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;
|
54
src/PersonObjects/Sleeve/Work/SleeveInfiltrateWork.ts
Normal file
54
src/PersonObjects/Sleeve/Work/SleeveInfiltrateWork.ts
Normal file
@ -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;
|
41
src/PersonObjects/Sleeve/Work/SleeveRecoveryWork.ts
Normal file
41
src/PersonObjects/Sleeve/Work/SleeveRecoveryWork.ts
Normal file
@ -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.stopWork(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("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;
|
43
src/PersonObjects/Sleeve/Work/SleeveSupportWork.ts
Normal file
43
src/PersonObjects/Sleeve/Work/SleeveSupportWork.ts
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
import { IPlayer } from "../../../PersonObjects/IPlayer";
|
||||||
|
import { Generic_fromJSON, Generic_toJSON, IReviverValue, Reviver } from "../../../utils/JSONReviver";
|
||||||
|
import { Work, WorkType } from "./Work";
|
||||||
|
|
||||||
|
export const isSleeveSupportWork = (w: Work | null): w is SleeveSupportWork =>
|
||||||
|
w !== null && w.type === WorkType.SUPPORT;
|
||||||
|
|
||||||
|
export class SleeveSupportWork extends Work {
|
||||||
|
constructor(player?: IPlayer) {
|
||||||
|
super(WorkType.SUPPORT);
|
||||||
|
if (player) player.bladeburner?.sleeveSupport(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
process(): number {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
finish(player: IPlayer): void {
|
||||||
|
player.bladeburner?.sleeveSupport(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
APICopy(): Record<string, unknown> {
|
||||||
|
return {
|
||||||
|
type: this.type,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Serialize the current object to a JSON save state.
|
||||||
|
*/
|
||||||
|
toJSON(): IReviverValue {
|
||||||
|
return Generic_toJSON("SleeveSupportWork", this);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initiatizes a BladeburnerWork object from a JSON save state.
|
||||||
|
*/
|
||||||
|
static fromJSON(value: IReviverValue): SleeveSupportWork {
|
||||||
|
return Generic_fromJSON(SleeveSupportWork, value.data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Reviver.constructors.SleeveSupportWork = SleeveSupportWork;
|
41
src/PersonObjects/Sleeve/Work/SleeveSynchroWork.ts
Normal file
41
src/PersonObjects/Sleeve/Work/SleeveSynchroWork.ts
Normal file
@ -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.stopWork(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("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;
|
30
src/PersonObjects/Sleeve/Work/Work.ts
Normal file
30
src/PersonObjects/Sleeve/Work/Work.ts
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
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;
|
||||||
|
finish(_player: IPlayer): void {
|
||||||
|
/* left for children to implement */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export enum WorkType {
|
||||||
|
COMPANY = "COMPANY",
|
||||||
|
FACTION = "FACTION",
|
||||||
|
CRIME = "CRIME",
|
||||||
|
CLASS = "CLASS",
|
||||||
|
RECOVERY = "RECOVERY",
|
||||||
|
SYNCHRO = "SYNCHRO",
|
||||||
|
BLADEBURNER = "BLADEBURNER",
|
||||||
|
INFILTRATE = "INFILTRATE",
|
||||||
|
SUPPORT = "SUPPORT",
|
||||||
|
}
|
@ -1,58 +0,0 @@
|
|||||||
import { Sleeve } from "../Sleeve";
|
|
||||||
import { numeralWrapper } from "../../../ui/numeralFormat";
|
|
||||||
import { Money } from "../../../ui/React/Money";
|
|
||||||
import * as React from "react";
|
|
||||||
import { StatsTable } from "../../../ui/React/StatsTable";
|
|
||||||
import { Modal } from "../../../ui/React/Modal";
|
|
||||||
|
|
||||||
interface IProps {
|
|
||||||
open: boolean;
|
|
||||||
onClose: () => void;
|
|
||||||
sleeve: Sleeve;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function MoreEarningsModal(props: IProps): React.ReactElement {
|
|
||||||
return (
|
|
||||||
<Modal open={props.open} onClose={props.onClose}>
|
|
||||||
<StatsTable
|
|
||||||
rows={[
|
|
||||||
["Money ", <Money money={props.sleeve.earningsForTask.money} />],
|
|
||||||
["Hacking Exp ", numeralWrapper.formatExp(props.sleeve.earningsForTask.hack)],
|
|
||||||
["Strength Exp ", numeralWrapper.formatExp(props.sleeve.earningsForTask.str)],
|
|
||||||
["Defense Exp ", numeralWrapper.formatExp(props.sleeve.earningsForTask.def)],
|
|
||||||
["Dexterity Exp ", numeralWrapper.formatExp(props.sleeve.earningsForTask.dex)],
|
|
||||||
["Agility Exp ", numeralWrapper.formatExp(props.sleeve.earningsForTask.agi)],
|
|
||||||
["Charisma Exp ", numeralWrapper.formatExp(props.sleeve.earningsForTask.cha)],
|
|
||||||
]}
|
|
||||||
title="Earnings for Current Task:"
|
|
||||||
/>
|
|
||||||
<br />
|
|
||||||
<StatsTable
|
|
||||||
rows={[
|
|
||||||
["Money: ", <Money money={props.sleeve.earningsForPlayer.money} />],
|
|
||||||
["Hacking Exp: ", numeralWrapper.formatExp(props.sleeve.earningsForPlayer.hack)],
|
|
||||||
["Strength Exp: ", numeralWrapper.formatExp(props.sleeve.earningsForPlayer.str)],
|
|
||||||
["Defense Exp: ", numeralWrapper.formatExp(props.sleeve.earningsForPlayer.def)],
|
|
||||||
["Dexterity Exp: ", numeralWrapper.formatExp(props.sleeve.earningsForPlayer.dex)],
|
|
||||||
["Agility Exp: ", numeralWrapper.formatExp(props.sleeve.earningsForPlayer.agi)],
|
|
||||||
["Charisma Exp: ", numeralWrapper.formatExp(props.sleeve.earningsForPlayer.cha)],
|
|
||||||
]}
|
|
||||||
title="Total Earnings for Host Consciousness:"
|
|
||||||
/>
|
|
||||||
<br />
|
|
||||||
<StatsTable
|
|
||||||
rows={[
|
|
||||||
["Money: ", <Money money={props.sleeve.earningsForSleeves.money} />],
|
|
||||||
["Hacking Exp: ", numeralWrapper.formatExp(props.sleeve.earningsForSleeves.hack)],
|
|
||||||
["Strength Exp: ", numeralWrapper.formatExp(props.sleeve.earningsForSleeves.str)],
|
|
||||||
["Defense Exp: ", numeralWrapper.formatExp(props.sleeve.earningsForSleeves.def)],
|
|
||||||
["Dexterity Exp: ", numeralWrapper.formatExp(props.sleeve.earningsForSleeves.dex)],
|
|
||||||
["Agility Exp: ", numeralWrapper.formatExp(props.sleeve.earningsForSleeves.agi)],
|
|
||||||
["Charisma Exp: ", numeralWrapper.formatExp(props.sleeve.earningsForSleeves.cha)],
|
|
||||||
]}
|
|
||||||
title="Total Earnings for Other Sleeves:"
|
|
||||||
/>
|
|
||||||
<br />
|
|
||||||
</Modal>
|
|
||||||
);
|
|
||||||
}
|
|
@ -2,18 +2,24 @@ import { Box, Button, Paper, Tooltip, Typography } from "@mui/material";
|
|||||||
import React, { useState } from "react";
|
import React, { useState } from "react";
|
||||||
import { FactionWorkType } from "../../../Work/data/FactionWorkType";
|
import { FactionWorkType } from "../../../Work/data/FactionWorkType";
|
||||||
import { CONSTANTS } from "../../../Constants";
|
import { CONSTANTS } from "../../../Constants";
|
||||||
import { Crimes } from "../../../Crime/Crimes";
|
|
||||||
import { use } from "../../../ui/Context";
|
import { use } from "../../../ui/Context";
|
||||||
import { numeralWrapper } from "../../../ui/numeralFormat";
|
import { numeralWrapper } from "../../../ui/numeralFormat";
|
||||||
import { ProgressBar } from "../../../ui/React/Progress";
|
import { ProgressBar } from "../../../ui/React/Progress";
|
||||||
import { Sleeve } from "../Sleeve";
|
import { Sleeve } from "../Sleeve";
|
||||||
import { SleeveTaskType } from "../SleeveTaskTypesEnum";
|
|
||||||
import { MoreEarningsModal } from "./MoreEarningsModal";
|
|
||||||
import { MoreStatsModal } from "./MoreStatsModal";
|
import { MoreStatsModal } from "./MoreStatsModal";
|
||||||
import { SleeveAugmentationsModal } from "./SleeveAugmentationsModal";
|
import { SleeveAugmentationsModal } from "./SleeveAugmentationsModal";
|
||||||
import { EarningsElement, StatsElement } from "./StatsElement";
|
import { EarningsElement, StatsElement } from "./StatsElement";
|
||||||
import { TaskSelector } from "./TaskSelector";
|
import { TaskSelector } from "./TaskSelector";
|
||||||
import { TravelModal } from "./TravelModal";
|
import { TravelModal } from "./TravelModal";
|
||||||
|
import { isSleeveClassWork } from "../Work/SleeveClassWork";
|
||||||
|
import { isSleeveSynchroWork } from "../Work/SleeveSynchroWork";
|
||||||
|
import { isSleeveRecoveryWork } from "../Work/SleeveRecoveryWork";
|
||||||
|
import { isSleeveFactionWork } from "../Work/SleeveFactionWork";
|
||||||
|
import { isSleeveCompanyWork } from "../Work/SleeveCompanyWork";
|
||||||
|
import { isSleeveInfiltrateWork } from "../Work/SleeveInfiltrateWork";
|
||||||
|
import { isSleeveSupportWork } from "../Work/SleeveSupportWork";
|
||||||
|
import { isSleeveBladeburnerWork } from "../Work/SleeveBladeburnerWork";
|
||||||
|
import { isSleeveCrimeWork } from "../Work/SleeveCrimeWork";
|
||||||
|
|
||||||
interface IProps {
|
interface IProps {
|
||||||
sleeve: Sleeve;
|
sleeve: Sleeve;
|
||||||
@ -23,7 +29,6 @@ interface IProps {
|
|||||||
export function SleeveElem(props: IProps): React.ReactElement {
|
export function SleeveElem(props: IProps): React.ReactElement {
|
||||||
const player = use.Player();
|
const player = use.Player();
|
||||||
const [statsOpen, setStatsOpen] = useState(false);
|
const [statsOpen, setStatsOpen] = useState(false);
|
||||||
const [earningsOpen, setEarningsOpen] = useState(false);
|
|
||||||
const [travelOpen, setTravelOpen] = useState(false);
|
const [travelOpen, setTravelOpen] = useState(false);
|
||||||
const [augmentationsOpen, setAugmentationsOpen] = useState(false);
|
const [augmentationsOpen, setAugmentationsOpen] = useState(false);
|
||||||
|
|
||||||
@ -64,83 +69,85 @@ export function SleeveElem(props: IProps): React.ReactElement {
|
|||||||
props.rerender();
|
props.rerender();
|
||||||
}
|
}
|
||||||
|
|
||||||
let desc = <></>;
|
let desc = <>This sleeve is currently idle</>;
|
||||||
switch (props.sleeve.currentTask) {
|
|
||||||
case SleeveTaskType.Idle:
|
if (isSleeveCrimeWork(props.sleeve.currentWork)) {
|
||||||
desc = <>This sleeve is currently idle</>;
|
const w = props.sleeve.currentWork;
|
||||||
break;
|
const crime = w.getCrime();
|
||||||
case SleeveTaskType.Company:
|
desc = (
|
||||||
desc = <>This sleeve is currently working your job at {props.sleeve.currentTaskLocation}.</>;
|
<>
|
||||||
break;
|
This sleeve is currently attempting to {crime.type} (Success Rate:{" "}
|
||||||
case SleeveTaskType.Faction: {
|
{numeralWrapper.formatPercentage(crime.successRate(props.sleeve))}).
|
||||||
let doing = "nothing";
|
</>
|
||||||
switch (props.sleeve.factionWorkType) {
|
);
|
||||||
case FactionWorkType.FIELD:
|
}
|
||||||
doing = "Field work";
|
|
||||||
break;
|
if (isSleeveClassWork(props.sleeve.currentWork)) {
|
||||||
case FactionWorkType.HACKING:
|
if (props.sleeve.currentWork.isGym())
|
||||||
doing = "Hacking contracts";
|
desc = <>This sleeve is currently working out at {props.sleeve.currentWork.location}.</>;
|
||||||
break;
|
else desc = <>This sleeve is currently studying at {props.sleeve.currentWork.location}.</>;
|
||||||
case FactionWorkType.SECURITY:
|
}
|
||||||
doing = "Security work";
|
if (isSleeveSynchroWork(props.sleeve.currentWork)) {
|
||||||
break;
|
desc = (
|
||||||
}
|
<>
|
||||||
desc = (
|
This sleeve is currently set to synchronize with the original consciousness. This causes the Sleeve's
|
||||||
<>
|
synchronization to increase.
|
||||||
This sleeve is currently doing {doing} for {props.sleeve.currentTaskLocation}.
|
</>
|
||||||
</>
|
);
|
||||||
);
|
}
|
||||||
break;
|
if (isSleeveRecoveryWork(props.sleeve.currentWork)) {
|
||||||
|
desc = (
|
||||||
|
<>
|
||||||
|
This sleeve is currently set to focus on shock recovery. This causes the Sleeve's shock to decrease at a faster
|
||||||
|
rate.
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if (isSleeveFactionWork(props.sleeve.currentWork)) {
|
||||||
|
let doing = "nothing";
|
||||||
|
switch (props.sleeve.currentWork.factionWorkType) {
|
||||||
|
case FactionWorkType.FIELD:
|
||||||
|
doing = "Field work";
|
||||||
|
break;
|
||||||
|
case FactionWorkType.HACKING:
|
||||||
|
doing = "Hacking contracts";
|
||||||
|
break;
|
||||||
|
case FactionWorkType.SECURITY:
|
||||||
|
doing = "Security work";
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
case SleeveTaskType.Crime: {
|
desc = (
|
||||||
const crime = Object.values(Crimes).find((crime) => crime.name === props.sleeve.crimeType);
|
<>
|
||||||
if (!crime) throw new Error("crime should not be undefined");
|
This sleeve is currently doing {doing} for {props.sleeve.currentWork.factionName}.
|
||||||
desc = (
|
</>
|
||||||
<>
|
);
|
||||||
This sleeve is currently attempting to {crime.type} (Success Rate:{" "}
|
}
|
||||||
{numeralWrapper.formatPercentage(crime.successRate(props.sleeve))}).
|
if (isSleeveCompanyWork(props.sleeve.currentWork)) {
|
||||||
</>
|
desc = <>This sleeve is currently working your job at {props.sleeve.currentWork.companyName}.</>;
|
||||||
);
|
}
|
||||||
break;
|
|
||||||
}
|
if (isSleeveBladeburnerWork(props.sleeve.currentWork)) {
|
||||||
case SleeveTaskType.Class:
|
const w = props.sleeve.currentWork;
|
||||||
desc = <>This sleeve is currently studying/taking a course at {props.sleeve.currentTaskLocation}.</>;
|
desc = (
|
||||||
break;
|
<>
|
||||||
case SleeveTaskType.Gym:
|
This sleeve is currently attempting to perform {w.actionName}. (
|
||||||
desc = <>This sleeve is currently working out at {props.sleeve.currentTaskLocation}.</>;
|
{((100 * w.cyclesWorked) / w.cyclesNeeded(player, props.sleeve)).toFixed(2)}%)
|
||||||
break;
|
</>
|
||||||
case SleeveTaskType.Bladeburner: {
|
);
|
||||||
let message = "";
|
}
|
||||||
if (props.sleeve.bbContract !== "------") {
|
|
||||||
message = ` - ${props.sleeve.bbContract} (Success Rate: ${props.sleeve.currentTaskLocation})`;
|
if (isSleeveInfiltrateWork(props.sleeve.currentWork)) {
|
||||||
} else if (props.sleeve.currentTaskLocation !== "") {
|
const w = props.sleeve.currentWork;
|
||||||
message = props.sleeve.currentTaskLocation;
|
desc = (
|
||||||
}
|
<>
|
||||||
desc = (
|
This sleeve is currently attempting to infiltrate synthoids communities. (
|
||||||
<>
|
{((100 * w.cyclesWorked) / w.cyclesNeeded()).toFixed(2)}%)
|
||||||
This sleeve is currently attempting to {props.sleeve.bbAction}. {message}
|
</>
|
||||||
</>
|
);
|
||||||
);
|
}
|
||||||
break;
|
|
||||||
}
|
if (isSleeveSupportWork(props.sleeve.currentWork)) {
|
||||||
case SleeveTaskType.Recovery:
|
desc = <>This sleeve is currently supporting you in your bladeburner activities.</>;
|
||||||
desc = (
|
|
||||||
<>
|
|
||||||
This sleeve is currently set to focus on shock recovery. This causes the Sleeve's shock to decrease at a
|
|
||||||
faster rate.
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
break;
|
|
||||||
case SleeveTaskType.Synchro:
|
|
||||||
desc = (
|
|
||||||
<>
|
|
||||||
This sleeve is currently set to synchronize with the original consciousness. This causes the Sleeve's
|
|
||||||
synchronization to increase.
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
console.error(`Invalid/Unrecognized taskValue in updateSleeveTaskDescription(): ${abc[0]}`);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@ -150,7 +157,6 @@ export function SleeveElem(props: IProps): React.ReactElement {
|
|||||||
<StatsElement sleeve={props.sleeve} />
|
<StatsElement sleeve={props.sleeve} />
|
||||||
<Box display="grid" sx={{ gridTemplateColumns: "1fr 1fr", width: "100%" }}>
|
<Box display="grid" sx={{ gridTemplateColumns: "1fr 1fr", width: "100%" }}>
|
||||||
<Button onClick={() => setStatsOpen(true)}>More Stats</Button>
|
<Button onClick={() => setStatsOpen(true)}>More Stats</Button>
|
||||||
<Button onClick={() => setEarningsOpen(true)}>More Earnings Info</Button>
|
|
||||||
<Tooltip title={player.money < CONSTANTS.TravelCost ? <Typography>Insufficient funds</Typography> : ""}>
|
<Tooltip title={player.money < CONSTANTS.TravelCost ? <Typography>Insufficient funds</Typography> : ""}>
|
||||||
<span>
|
<span>
|
||||||
<Button
|
<Button
|
||||||
@ -185,20 +191,28 @@ export function SleeveElem(props: IProps): React.ReactElement {
|
|||||||
</Button>
|
</Button>
|
||||||
<Typography>{desc}</Typography>
|
<Typography>{desc}</Typography>
|
||||||
<Typography>
|
<Typography>
|
||||||
{(props.sleeve.currentTask === SleeveTaskType.Crime ||
|
{isSleeveCrimeWork(props.sleeve.currentWork) && (
|
||||||
props.sleeve.currentTask === SleeveTaskType.Bladeburner) &&
|
<ProgressBar
|
||||||
props.sleeve.currentTaskMaxTime > 0 && (
|
variant="determinate"
|
||||||
<ProgressBar
|
value={(props.sleeve.currentWork.cyclesWorked / props.sleeve.currentWork.cyclesNeeded()) * 100}
|
||||||
variant="determinate"
|
color="primary"
|
||||||
value={(props.sleeve.currentTaskTime / props.sleeve.currentTaskMaxTime) * 100}
|
/>
|
||||||
color="primary"
|
)}
|
||||||
/>
|
{isSleeveBladeburnerWork(props.sleeve.currentWork) && (
|
||||||
)}
|
<ProgressBar
|
||||||
|
variant="determinate"
|
||||||
|
value={
|
||||||
|
(props.sleeve.currentWork.cyclesWorked /
|
||||||
|
props.sleeve.currentWork.cyclesNeeded(player, props.sleeve)) *
|
||||||
|
100
|
||||||
|
}
|
||||||
|
color="primary"
|
||||||
|
/>
|
||||||
|
)}
|
||||||
</Typography>
|
</Typography>
|
||||||
</span>
|
</span>
|
||||||
</Paper>
|
</Paper>
|
||||||
<MoreStatsModal open={statsOpen} onClose={() => setStatsOpen(false)} sleeve={props.sleeve} />
|
<MoreStatsModal open={statsOpen} onClose={() => setStatsOpen(false)} sleeve={props.sleeve} />
|
||||||
<MoreEarningsModal open={earningsOpen} onClose={() => setEarningsOpen(false)} sleeve={props.sleeve} />
|
|
||||||
<TravelModal
|
<TravelModal
|
||||||
open={travelOpen}
|
open={travelOpen}
|
||||||
onClose={() => setTravelOpen(false)}
|
onClose={() => setTravelOpen(false)}
|
||||||
|
@ -13,6 +13,10 @@ import { use } from "../../../ui/Context";
|
|||||||
|
|
||||||
import { Sleeve } from "../Sleeve";
|
import { Sleeve } from "../Sleeve";
|
||||||
import { SleeveTaskType } from "../SleeveTaskTypesEnum";
|
import { SleeveTaskType } from "../SleeveTaskTypesEnum";
|
||||||
|
import { isSleeveClassWork } from "../Work/SleeveClassWork";
|
||||||
|
import { isSleeveFactionWork } from "../Work/SleeveFactionWork";
|
||||||
|
import { isSleeveCompanyWork } from "../Work/SleeveCompanyWork";
|
||||||
|
import { isSleeveCrimeWork } from "../Work/SleeveCrimeWork";
|
||||||
|
|
||||||
interface IProps {
|
interface IProps {
|
||||||
sleeve: Sleeve;
|
sleeve: Sleeve;
|
||||||
@ -94,35 +98,56 @@ export function EarningsElement(props: IProps): React.ReactElement {
|
|||||||
const player = use.Player();
|
const player = use.Player();
|
||||||
|
|
||||||
let data: (string | JSX.Element)[][] = [];
|
let data: (string | JSX.Element)[][] = [];
|
||||||
if (props.sleeve.currentTask === SleeveTaskType.Crime) {
|
if (isSleeveCrimeWork(props.sleeve.currentWork)) {
|
||||||
|
const gains = props.sleeve.currentWork.getExp();
|
||||||
data = [
|
data = [
|
||||||
[
|
[`Money:`, <Money money={5 * gains.money} />],
|
||||||
`Money`,
|
[`Hacking Exp:`, `${numeralWrapper.formatExp(5 * gains.hackExp)}`],
|
||||||
<>
|
[`Strength Exp:`, `${numeralWrapper.formatExp(5 * gains.strExp)}`],
|
||||||
<Money money={parseFloat(props.sleeve.currentTaskLocation)} /> (on success)
|
[`Defense Exp:`, `${numeralWrapper.formatExp(5 * gains.defExp)}`],
|
||||||
</>,
|
[`Dexterity Exp:`, `${numeralWrapper.formatExp(5 * gains.dexExp)}`],
|
||||||
],
|
[`Agility Exp:`, `${numeralWrapper.formatExp(5 * gains.agiExp)}`],
|
||||||
[`Hacking Exp`, `${numeralWrapper.formatExp(props.sleeve.gainRatesForTask.hack)} (2x on success)`],
|
[`Charisma Exp:`, `${numeralWrapper.formatExp(5 * gains.chaExp)}`],
|
||||||
[`Strength Exp`, `${numeralWrapper.formatExp(props.sleeve.gainRatesForTask.str)} (2x on success)`],
|
|
||||||
[`Defense Exp`, `${numeralWrapper.formatExp(props.sleeve.gainRatesForTask.def)} (2x on success)`],
|
|
||||||
[`Dexterity Exp`, `${numeralWrapper.formatExp(props.sleeve.gainRatesForTask.dex)} (2x on success)`],
|
|
||||||
[`Agility Exp`, `${numeralWrapper.formatExp(props.sleeve.gainRatesForTask.agi)} (2x on success)`],
|
|
||||||
[`Charisma Exp`, `${numeralWrapper.formatExp(props.sleeve.gainRatesForTask.cha)} (2x on success)`],
|
|
||||||
];
|
];
|
||||||
} else {
|
}
|
||||||
|
if (isSleeveClassWork(props.sleeve.currentWork)) {
|
||||||
|
const rates = props.sleeve.currentWork.calculateRates(player, props.sleeve);
|
||||||
data = [
|
data = [
|
||||||
[`Money:`, <MoneyRate money={5 * props.sleeve.gainRatesForTask.money} />],
|
[`Money:`, <MoneyRate money={5 * rates.money} />],
|
||||||
[`Hacking Exp:`, `${numeralWrapper.formatExp(5 * props.sleeve.gainRatesForTask.hack)} / sec`],
|
[`Hacking Exp:`, `${numeralWrapper.formatExp(5 * rates.hackExp)} / sec`],
|
||||||
[`Strength Exp:`, `${numeralWrapper.formatExp(5 * props.sleeve.gainRatesForTask.str)} / sec`],
|
[`Strength Exp:`, `${numeralWrapper.formatExp(5 * rates.strExp)} / sec`],
|
||||||
[`Defense Exp:`, `${numeralWrapper.formatExp(5 * props.sleeve.gainRatesForTask.def)} / sec`],
|
[`Defense Exp:`, `${numeralWrapper.formatExp(5 * rates.defExp)} / sec`],
|
||||||
[`Dexterity Exp:`, `${numeralWrapper.formatExp(5 * props.sleeve.gainRatesForTask.dex)} / sec`],
|
[`Dexterity Exp:`, `${numeralWrapper.formatExp(5 * rates.dexExp)} / sec`],
|
||||||
[`Agility Exp:`, `${numeralWrapper.formatExp(5 * props.sleeve.gainRatesForTask.agi)} / sec`],
|
[`Agility Exp:`, `${numeralWrapper.formatExp(5 * rates.agiExp)} / sec`],
|
||||||
[`Charisma Exp:`, `${numeralWrapper.formatExp(5 * props.sleeve.gainRatesForTask.cha)} / sec`],
|
[`Charisma Exp:`, `${numeralWrapper.formatExp(5 * rates.chaExp)} / sec`],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
if (isSleeveFactionWork(props.sleeve.currentWork)) {
|
||||||
|
const rates = props.sleeve.currentWork.getExpRates(props.sleeve);
|
||||||
|
const repGain = props.sleeve.currentWork.getReputationRate(props.sleeve);
|
||||||
|
data = [
|
||||||
|
[`Hacking Exp:`, `${numeralWrapper.formatExp(5 * rates.hackExp)} / sec`],
|
||||||
|
[`Strength Exp:`, `${numeralWrapper.formatExp(5 * rates.strExp)} / sec`],
|
||||||
|
[`Defense Exp:`, `${numeralWrapper.formatExp(5 * rates.defExp)} / sec`],
|
||||||
|
[`Dexterity Exp:`, `${numeralWrapper.formatExp(5 * rates.dexExp)} / sec`],
|
||||||
|
[`Agility Exp:`, `${numeralWrapper.formatExp(5 * rates.agiExp)} / sec`],
|
||||||
|
[`Charisma Exp:`, `${numeralWrapper.formatExp(5 * rates.chaExp)} / sec`],
|
||||||
|
[`Reputation:`, <ReputationRate reputation={5 * repGain} />],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isSleeveCompanyWork(props.sleeve.currentWork)) {
|
||||||
|
const rates = props.sleeve.currentWork.getGainRates(player, props.sleeve);
|
||||||
|
data = [
|
||||||
|
[`Money:`, <MoneyRate money={5 * rates.money} />],
|
||||||
|
[`Hacking Exp:`, `${numeralWrapper.formatExp(5 * rates.hackExp)} / sec`],
|
||||||
|
[`Strength Exp:`, `${numeralWrapper.formatExp(5 * rates.strExp)} / sec`],
|
||||||
|
[`Defense Exp:`, `${numeralWrapper.formatExp(5 * rates.defExp)} / sec`],
|
||||||
|
[`Dexterity Exp:`, `${numeralWrapper.formatExp(5 * rates.dexExp)} / sec`],
|
||||||
|
[`Agility Exp:`, `${numeralWrapper.formatExp(5 * rates.agiExp)} / sec`],
|
||||||
|
[`Charisma Exp:`, `${numeralWrapper.formatExp(5 * rates.chaExp)} / sec`],
|
||||||
|
[`Reputation:`, <ReputationRate reputation={5 * rates.reputation} />],
|
||||||
];
|
];
|
||||||
if (props.sleeve.currentTask === SleeveTaskType.Company || props.sleeve.currentTask === SleeveTaskType.Faction) {
|
|
||||||
const repGain: number = props.sleeve.getRepGain(player);
|
|
||||||
data.push([`Reputation:`, <ReputationRate reputation={5 * repGain} />]);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@ -130,7 +155,7 @@ export function EarningsElement(props: IProps): React.ReactElement {
|
|||||||
<TableBody>
|
<TableBody>
|
||||||
<TableRow>
|
<TableRow>
|
||||||
<TableCell classes={{ root: classes.cellNone }}>
|
<TableCell classes={{ root: classes.cellNone }}>
|
||||||
<Typography variant="h6">Earnings</Typography>
|
<Typography variant="h6">Earnings {props.sleeve.storedCycles > 50 ? "(overclock)" : ""}</Typography>
|
||||||
</TableCell>
|
</TableCell>
|
||||||
</TableRow>
|
</TableRow>
|
||||||
{data.map(([a, b]) => (
|
{data.map(([a, b]) => (
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
import React, { useState } from "react";
|
import React, { useState } from "react";
|
||||||
import { Sleeve } from "../Sleeve";
|
import { Sleeve } from "../Sleeve";
|
||||||
import { IPlayer } from "../../IPlayer";
|
import { IPlayer } from "../../IPlayer";
|
||||||
import { SleeveTaskType } from "../SleeveTaskTypesEnum";
|
|
||||||
import { Crimes } from "../../../Crime/Crimes";
|
import { Crimes } from "../../../Crime/Crimes";
|
||||||
import { LocationName } from "../../../Locations/data/LocationNames";
|
import { LocationName } from "../../../Locations/data/LocationNames";
|
||||||
import { CityName } from "../../../Locations/data/CityNames";
|
import { CityName } from "../../../Locations/data/CityNames";
|
||||||
@ -9,7 +8,9 @@ import { Factions } from "../../../Faction/Factions";
|
|||||||
import Select, { SelectChangeEvent } from "@mui/material/Select";
|
import Select, { SelectChangeEvent } from "@mui/material/Select";
|
||||||
import MenuItem from "@mui/material/MenuItem";
|
import MenuItem from "@mui/material/MenuItem";
|
||||||
import { FactionNames } from "../../../Faction/data/FactionNames";
|
import { FactionNames } from "../../../Faction/data/FactionNames";
|
||||||
import { FactionWorkType } from "../../../Work/data/FactionWorkType";
|
import { isSleeveFactionWork } from "../Work/SleeveFactionWork";
|
||||||
|
import { isSleeveCompanyWork } from "../Work/SleeveCompanyWork";
|
||||||
|
import { isSleeveBladeburnerWork } from "../Work/SleeveBladeburnerWork";
|
||||||
|
|
||||||
const universitySelectorOptions: string[] = [
|
const universitySelectorOptions: string[] = [
|
||||||
"Study Computer Science",
|
"Study Computer Science",
|
||||||
@ -49,8 +50,8 @@ function possibleJobs(player: IPlayer, sleeve: Sleeve): string[] {
|
|||||||
if (sleeve === otherSleeve) {
|
if (sleeve === otherSleeve) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (otherSleeve.currentTask === SleeveTaskType.Company) {
|
if (isSleeveCompanyWork(otherSleeve.currentWork)) {
|
||||||
forbiddenCompanies.push(otherSleeve.currentTaskLocation);
|
forbiddenCompanies.push(otherSleeve.currentWork.companyName);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const allJobs: string[] = Object.keys(player.jobs);
|
const allJobs: string[] = Object.keys(player.jobs);
|
||||||
@ -68,8 +69,8 @@ function possibleFactions(player: IPlayer, sleeve: Sleeve): string[] {
|
|||||||
if (sleeve === otherSleeve) {
|
if (sleeve === otherSleeve) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (otherSleeve.currentTask === SleeveTaskType.Faction) {
|
if (isSleeveFactionWork(otherSleeve.currentWork)) {
|
||||||
forbiddenFactions.push(otherSleeve.currentTaskLocation);
|
forbiddenFactions.push(otherSleeve.currentWork.factionName);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -98,8 +99,9 @@ function possibleContracts(player: IPlayer, sleeve: Sleeve): string[] {
|
|||||||
if (sleeve === otherSleeve) {
|
if (sleeve === otherSleeve) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (otherSleeve.currentTask === SleeveTaskType.Bladeburner && otherSleeve.bbAction == "Take on contracts") {
|
if (isSleeveBladeburnerWork(otherSleeve.currentWork) && otherSleeve.currentWork.actionType === "Contracts") {
|
||||||
contracts = contracts.filter((x) => x != otherSleeve.bbContract);
|
const w = otherSleeve.currentWork;
|
||||||
|
contracts = contracts.filter((x) => x != w.actionName);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (contracts.length === 0) {
|
if (contracts.length === 0) {
|
||||||
@ -241,51 +243,37 @@ const canDo: {
|
|||||||
};
|
};
|
||||||
|
|
||||||
function getABC(sleeve: Sleeve): [string, string, string] {
|
function getABC(sleeve: Sleeve): [string, string, string] {
|
||||||
switch (sleeve.currentTask) {
|
return ["------", "------", "------"];
|
||||||
case SleeveTaskType.Idle:
|
|
||||||
return ["------", "------", "------"];
|
// switch (sleeve.currentTask) {
|
||||||
case SleeveTaskType.Company:
|
// case SleeveTaskType.Idle:
|
||||||
return ["Work for Company", sleeve.currentTaskLocation, "------"];
|
// case SleeveTaskType.Company:
|
||||||
case SleeveTaskType.Faction: {
|
// case SleeveTaskType.Faction: {
|
||||||
let workType = "";
|
// }
|
||||||
switch (sleeve.factionWorkType) {
|
// case SleeveTaskType.Crime:
|
||||||
case FactionWorkType.HACKING:
|
// return ["Commit Crime", sleeve.crimeType, "------"];
|
||||||
workType = "Hacking Contracts";
|
// case SleeveTaskType.Class:
|
||||||
break;
|
// case SleeveTaskType.Gym: {
|
||||||
case FactionWorkType.FIELD:
|
// switch (sleeve.gymStatType) {
|
||||||
workType = "Field Work";
|
// case "none":
|
||||||
break;
|
// return ["Idle", "------", "------"];
|
||||||
case FactionWorkType.SECURITY:
|
// case "str":
|
||||||
workType = "Security Work";
|
// return ["Workout at Gym", "Train Strength", sleeve.currentTaskLocation];
|
||||||
break;
|
// case "def":
|
||||||
}
|
// return ["Workout at Gym", "Train Defense", sleeve.currentTaskLocation];
|
||||||
return ["Work for Faction", sleeve.currentTaskLocation, workType];
|
// case "dex":
|
||||||
}
|
// return ["Workout at Gym", "Train Dexterity", sleeve.currentTaskLocation];
|
||||||
case SleeveTaskType.Crime:
|
// case "agi":
|
||||||
return ["Commit Crime", sleeve.crimeType, "------"];
|
// return ["Workout at Gym", "Train Agility", sleeve.currentTaskLocation];
|
||||||
case SleeveTaskType.Class:
|
// }
|
||||||
return ["Take University Course", sleeve.className, sleeve.currentTaskLocation];
|
// }
|
||||||
case SleeveTaskType.Gym: {
|
// case SleeveTaskType.Bladeburner:
|
||||||
switch (sleeve.gymStatType) {
|
// return ["Perform Bladeburner Actions", sleeve.bbAction, sleeve.bbContract];
|
||||||
case "none":
|
// case SleeveTaskType.Recovery:
|
||||||
return ["Idle", "------", "------"];
|
// return ["Shock Recovery", "------", "------"];
|
||||||
case "str":
|
// case SleeveTaskType.Synchro:
|
||||||
return ["Workout at Gym", "Train Strength", sleeve.currentTaskLocation];
|
// return ["Synchronize", "------", "------"];
|
||||||
case "def":
|
// }
|
||||||
return ["Workout at Gym", "Train Defense", sleeve.currentTaskLocation];
|
|
||||||
case "dex":
|
|
||||||
return ["Workout at Gym", "Train Dexterity", sleeve.currentTaskLocation];
|
|
||||||
case "agi":
|
|
||||||
return ["Workout at Gym", "Train Agility", sleeve.currentTaskLocation];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
case SleeveTaskType.Bladeburner:
|
|
||||||
return ["Perform Bladeburner Actions", sleeve.bbAction, sleeve.bbContract];
|
|
||||||
case SleeveTaskType.Recovery:
|
|
||||||
return ["Shock Recovery", "------", "------"];
|
|
||||||
case SleeveTaskType.Synchro:
|
|
||||||
return ["Synchronize", "------", "------"];
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export function TaskSelector(props: IProps): React.ReactElement {
|
export function TaskSelector(props: IProps): React.ReactElement {
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
import { IPlayer } from "../IPlayer";
|
|
||||||
import { Faction } from "../../Faction/Faction";
|
import { Faction } from "../../Faction/Faction";
|
||||||
import { CONSTANTS } from "../../Constants";
|
import { CONSTANTS } from "../../Constants";
|
||||||
import { BitNodeMultipliers } from "../../BitNode/BitNodeMultipliers";
|
import { BitNodeMultipliers } from "../../BitNode/BitNodeMultipliers";
|
||||||
import { CalculateShareMult } from "../../NetworkShare/Share";
|
import { CalculateShareMult } from "../../NetworkShare/Share";
|
||||||
|
import { IPerson } from "../IPerson";
|
||||||
|
|
||||||
function mult(f: Faction): number {
|
function mult(f: Faction): number {
|
||||||
let favorMult = 1 + f.favor / 100;
|
let favorMult = 1 + f.favor / 100;
|
||||||
@ -12,7 +12,7 @@ function mult(f: Faction): number {
|
|||||||
return favorMult * BitNodeMultipliers.FactionWorkRepGain;
|
return favorMult * BitNodeMultipliers.FactionWorkRepGain;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getHackingWorkRepGain(p: IPlayer, f: Faction): number {
|
export function getHackingWorkRepGain(p: IPerson, f: Faction): number {
|
||||||
return (
|
return (
|
||||||
((p.skills.hacking + p.skills.intelligence / 3) / CONSTANTS.MaxSkillLevel) *
|
((p.skills.hacking + p.skills.intelligence / 3) / CONSTANTS.MaxSkillLevel) *
|
||||||
p.mults.faction_rep *
|
p.mults.faction_rep *
|
||||||
@ -22,7 +22,7 @@ export function getHackingWorkRepGain(p: IPlayer, f: Faction): number {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getFactionSecurityWorkRepGain(p: IPlayer, f: Faction): number {
|
export function getFactionSecurityWorkRepGain(p: IPerson, f: Faction): number {
|
||||||
const t =
|
const t =
|
||||||
(0.9 *
|
(0.9 *
|
||||||
(p.skills.strength +
|
(p.skills.strength +
|
||||||
@ -35,7 +35,7 @@ export function getFactionSecurityWorkRepGain(p: IPlayer, f: Faction): number {
|
|||||||
return t * p.mults.faction_rep * mult(f) * p.getIntelligenceBonus(1);
|
return t * p.mults.faction_rep * mult(f) * p.getIntelligenceBonus(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getFactionFieldWorkRepGain(p: IPlayer, f: Faction): number {
|
export function getFactionFieldWorkRepGain(p: IPerson, f: Faction): number {
|
||||||
const t =
|
const t =
|
||||||
(0.9 *
|
(0.9 *
|
||||||
(p.skills.strength +
|
(p.skills.strength +
|
||||||
|
27
src/ScriptEditor/NetscriptDefinitions.d.ts
vendored
27
src/ScriptEditor/NetscriptDefinitions.d.ts
vendored
@ -1016,36 +1016,13 @@ export interface SleeveInformation {
|
|||||||
tor: boolean;
|
tor: boolean;
|
||||||
/** Sleeve multipliers */
|
/** Sleeve multipliers */
|
||||||
mult: CharacterMult;
|
mult: CharacterMult;
|
||||||
/** Time spent on the current task in milliseconds */
|
|
||||||
timeWorked: number;
|
|
||||||
/** Earnings synchronized to other sleeves */
|
|
||||||
earningsForSleeves: SleeveWorkGains;
|
|
||||||
/** Earnings synchronized to the player */
|
|
||||||
earningsForPlayer: SleeveWorkGains;
|
|
||||||
/** Earnings for this sleeve */
|
|
||||||
earningsForTask: SleeveWorkGains;
|
|
||||||
/** Faction or company reputation gained for the current task */
|
|
||||||
workRepGain: number;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Object representing a sleeve current task.
|
* Object representing a sleeve current task.
|
||||||
* @public
|
* @public
|
||||||
*/
|
*/
|
||||||
export interface SleeveTask {
|
export type SleeveTask = any;
|
||||||
/** Task type */
|
|
||||||
task: string;
|
|
||||||
/** Crime currently attempting, if any */
|
|
||||||
crime: string;
|
|
||||||
/** Location of the task, if any */
|
|
||||||
location: string;
|
|
||||||
/** Stat being trained at the gym, if any */
|
|
||||||
gymStatType: string;
|
|
||||||
/** Faction work type being performed, if any */
|
|
||||||
factionWorkType: string;
|
|
||||||
/** Class being taken at university, if any */
|
|
||||||
className: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Object representing a port. A port is a serialized queue.
|
* Object representing a port. A port is a serialized queue.
|
||||||
@ -1310,7 +1287,7 @@ export interface TIX {
|
|||||||
* @param shares - Number of shares to short. Must be positive. Will be rounded to nearest integer.
|
* @param shares - Number of shares to short. Must be positive. Will be rounded to nearest integer.
|
||||||
* @returns The stock price at which each share was purchased, otherwise 0 if the shares weren't purchased.
|
* @returns The stock price at which each share was purchased, otherwise 0 if the shares weren't purchased.
|
||||||
*/
|
*/
|
||||||
short(sym: string, shares: number): number;
|
buyShort(sym: string, shares: number): number;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sell short stock.
|
* Sell short stock.
|
||||||
|
@ -147,13 +147,13 @@ export class ClassWork extends Work {
|
|||||||
}
|
}
|
||||||
|
|
||||||
calculateRates(player: IPlayer): WorkStats {
|
calculateRates(player: IPlayer): WorkStats {
|
||||||
return calculateClassEarningsRate(player, this);
|
return calculateClassEarningsRate(player, player, this.classType, this.location);
|
||||||
}
|
}
|
||||||
|
|
||||||
process(player: IPlayer, cycles: number): boolean {
|
process(player: IPlayer, cycles: number): boolean {
|
||||||
this.cyclesWorked += cycles;
|
this.cyclesWorked += cycles;
|
||||||
const rate = this.calculateRates(player);
|
const rate = this.calculateRates(player);
|
||||||
const earnings = applyWorkStats(player, rate, cycles, "class");
|
const earnings = applyWorkStats(player, player, rate, cycles, "class");
|
||||||
this.earnings = sumWorkStats(this.earnings, earnings);
|
this.earnings = sumWorkStats(this.earnings, earnings);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -10,6 +10,8 @@ import { applyWorkStats, WorkStats } from "./WorkStats";
|
|||||||
import { Company } from "../Company/Company";
|
import { Company } from "../Company/Company";
|
||||||
import { dialogBoxCreate } from "../ui/React/DialogBox";
|
import { dialogBoxCreate } from "../ui/React/DialogBox";
|
||||||
import { Reputation } from "../ui/React/Reputation";
|
import { Reputation } from "../ui/React/Reputation";
|
||||||
|
import { AugmentationNames } from "../Augmentation/data/AugmentationNames";
|
||||||
|
import { CONSTANTS } from "../Constants";
|
||||||
|
|
||||||
interface CompanyWorkParams {
|
interface CompanyWorkParams {
|
||||||
companyName: string;
|
companyName: string;
|
||||||
@ -32,14 +34,18 @@ export class CompanyWork extends Work {
|
|||||||
}
|
}
|
||||||
|
|
||||||
getGainRates(player: IPlayer): WorkStats {
|
getGainRates(player: IPlayer): WorkStats {
|
||||||
return calculateCompanyWorkStats(player, this.getCompany());
|
let focusBonus = 1;
|
||||||
|
if (!player.hasAugmentation(AugmentationNames.NeuroreceptorManager)) {
|
||||||
|
focusBonus = player.focus ? 1 : CONSTANTS.BaseFocusBonus;
|
||||||
|
}
|
||||||
|
return calculateCompanyWorkStats(player, player, this.getCompany());
|
||||||
}
|
}
|
||||||
|
|
||||||
process(player: IPlayer, cycles: number): boolean {
|
process(player: IPlayer, cycles: number): boolean {
|
||||||
this.cyclesWorked += cycles;
|
this.cyclesWorked += cycles;
|
||||||
const company = this.getCompany();
|
const company = this.getCompany();
|
||||||
const gains = this.getGainRates(player);
|
const gains = this.getGainRates(player);
|
||||||
applyWorkStats(player, gains, cycles, "work");
|
applyWorkStats(player, player, gains, cycles, "work");
|
||||||
company.playerReputation += gains.reputation * cycles;
|
company.playerReputation += gains.reputation * cycles;
|
||||||
influenceStockThroughCompanyWork(company, gains.reputation, cycles);
|
influenceStockThroughCompanyWork(company, gains.reputation, cycles);
|
||||||
return false;
|
return false;
|
||||||
|
@ -26,29 +26,29 @@ enum newCrimeType {
|
|||||||
|
|
||||||
const convertCrimeType = (crimeType: CrimeType): newCrimeType => {
|
const convertCrimeType = (crimeType: CrimeType): newCrimeType => {
|
||||||
switch (crimeType) {
|
switch (crimeType) {
|
||||||
case CrimeType.Shoplift:
|
case CrimeType.SHOPLIFT:
|
||||||
return newCrimeType.SHOPLIFT;
|
return newCrimeType.SHOPLIFT;
|
||||||
case CrimeType.RobStore:
|
case CrimeType.ROB_STORE:
|
||||||
return newCrimeType.ROBSTORE;
|
return newCrimeType.ROBSTORE;
|
||||||
case CrimeType.Mug:
|
case CrimeType.MUG:
|
||||||
return newCrimeType.MUG;
|
return newCrimeType.MUG;
|
||||||
case CrimeType.Larceny:
|
case CrimeType.LARCENY:
|
||||||
return newCrimeType.LARCENY;
|
return newCrimeType.LARCENY;
|
||||||
case CrimeType.Drugs:
|
case CrimeType.DRUGS:
|
||||||
return newCrimeType.DRUGS;
|
return newCrimeType.DRUGS;
|
||||||
case CrimeType.BondForgery:
|
case CrimeType.BOND_FORGERY:
|
||||||
return newCrimeType.BONDFORGERY;
|
return newCrimeType.BONDFORGERY;
|
||||||
case CrimeType.TraffickArms:
|
case CrimeType.TRAFFIC_ARMS:
|
||||||
return newCrimeType.TRAFFICKARMS;
|
return newCrimeType.TRAFFICKARMS;
|
||||||
case CrimeType.Homicide:
|
case CrimeType.HOMICIDE:
|
||||||
return newCrimeType.HOMICIDE;
|
return newCrimeType.HOMICIDE;
|
||||||
case CrimeType.GrandTheftAuto:
|
case CrimeType.GRAND_THEFT_AUTO:
|
||||||
return newCrimeType.GRANDTHEFTAUTO;
|
return newCrimeType.GRANDTHEFTAUTO;
|
||||||
case CrimeType.Kidnap:
|
case CrimeType.KIDNAP:
|
||||||
return newCrimeType.KIDNAP;
|
return newCrimeType.KIDNAP;
|
||||||
case CrimeType.Assassination:
|
case CrimeType.ASSASSINATION:
|
||||||
return newCrimeType.ASSASSINATION;
|
return newCrimeType.ASSASSINATION;
|
||||||
case CrimeType.Heist:
|
case CrimeType.HEIST:
|
||||||
return newCrimeType.HEIST;
|
return newCrimeType.HEIST;
|
||||||
}
|
}
|
||||||
return newCrimeType.SHOPLIFT;
|
return newCrimeType.SHOPLIFT;
|
||||||
@ -67,7 +67,7 @@ export class CrimeWork extends Work {
|
|||||||
|
|
||||||
constructor(params?: CrimeWorkParams) {
|
constructor(params?: CrimeWorkParams) {
|
||||||
super(WorkType.CRIME, params?.singularity ?? true);
|
super(WorkType.CRIME, params?.singularity ?? true);
|
||||||
this.crimeType = params?.crimeType ?? CrimeType.Shoplift;
|
this.crimeType = params?.crimeType ?? CrimeType.SHOPLIFT;
|
||||||
this.unitCompleted = 0;
|
this.unitCompleted = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5,7 +5,7 @@ import { IPlayer } from "../PersonObjects/IPlayer";
|
|||||||
import { FactionNames } from "../Faction/data/FactionNames";
|
import { FactionNames } from "../Faction/data/FactionNames";
|
||||||
import { Factions } from "../Faction/Factions";
|
import { Factions } from "../Faction/Factions";
|
||||||
import { Faction } from "../Faction/Faction";
|
import { Faction } from "../Faction/Faction";
|
||||||
import { applyWorkStats, WorkStats } from "./WorkStats";
|
import { applyWorkStats, scaleWorkStats, WorkStats } from "./WorkStats";
|
||||||
import { dialogBoxCreate } from "../ui/React/DialogBox";
|
import { dialogBoxCreate } from "../ui/React/DialogBox";
|
||||||
import { Reputation } from "../ui/React/Reputation";
|
import { Reputation } from "../ui/React/Reputation";
|
||||||
import {
|
import {
|
||||||
@ -58,7 +58,12 @@ export class FactionWork extends Work {
|
|||||||
}
|
}
|
||||||
|
|
||||||
getExpRates(player: IPlayer): WorkStats {
|
getExpRates(player: IPlayer): WorkStats {
|
||||||
return calculateFactionExp(player, this.factionWorkType);
|
let focusBonus = 1;
|
||||||
|
if (!player.hasAugmentation(AugmentationNames.NeuroreceptorManager)) {
|
||||||
|
focusBonus = player.focus ? 1 : CONSTANTS.BaseFocusBonus;
|
||||||
|
}
|
||||||
|
const rate = calculateFactionExp(player, this.factionWorkType);
|
||||||
|
return scaleWorkStats(rate, focusBonus, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
process(player: IPlayer, cycles: number): boolean {
|
process(player: IPlayer, cycles: number): boolean {
|
||||||
@ -66,7 +71,7 @@ export class FactionWork extends Work {
|
|||||||
this.getFaction().playerReputation += this.getReputationRate(player) * cycles;
|
this.getFaction().playerReputation += this.getReputationRate(player) * cycles;
|
||||||
|
|
||||||
const rate = this.getExpRates(player);
|
const rate = this.getExpRates(player);
|
||||||
applyWorkStats(player, rate, cycles, "class");
|
applyWorkStats(player, player, rate, cycles, "class");
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
import { IPerson } from "src/PersonObjects/IPerson";
|
||||||
import { IPlayer } from "../PersonObjects/IPlayer";
|
import { IPlayer } from "../PersonObjects/IPlayer";
|
||||||
|
|
||||||
export interface WorkStats {
|
export interface WorkStats {
|
||||||
@ -52,9 +53,10 @@ export const sumWorkStats = (w0: WorkStats, w1: WorkStats): WorkStats => {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
export const scaleWorkStats = (w: WorkStats, n: number): WorkStats => {
|
export const scaleWorkStats = (w: WorkStats, n: number, scaleMoney = true): WorkStats => {
|
||||||
|
const m = scaleMoney ? n : 1;
|
||||||
return {
|
return {
|
||||||
money: w.money * n,
|
money: w.money * m,
|
||||||
reputation: w.reputation * n,
|
reputation: w.reputation * n,
|
||||||
hackExp: w.hackExp * n,
|
hackExp: w.hackExp * n,
|
||||||
strExp: w.strExp * n,
|
strExp: w.strExp * n,
|
||||||
@ -66,10 +68,34 @@ export const scaleWorkStats = (w: WorkStats, n: number): WorkStats => {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
export const applyWorkStats = (player: IPlayer, workStats: WorkStats, cycles: number, source: string): WorkStats => {
|
export const applyWorkStats = (
|
||||||
|
player: IPlayer,
|
||||||
|
target: IPerson,
|
||||||
|
workStats: WorkStats,
|
||||||
|
cycles: number,
|
||||||
|
source: string,
|
||||||
|
): WorkStats => {
|
||||||
|
const expStats = applyWorkStatsExp(target, workStats, cycles);
|
||||||
const gains = {
|
const gains = {
|
||||||
money: workStats.money * cycles,
|
money: workStats.money * cycles,
|
||||||
reputation: 0,
|
reputation: 0,
|
||||||
|
hackExp: expStats.hackExp,
|
||||||
|
strExp: expStats.strExp,
|
||||||
|
defExp: expStats.defExp,
|
||||||
|
dexExp: expStats.dexExp,
|
||||||
|
agiExp: expStats.agiExp,
|
||||||
|
chaExp: expStats.chaExp,
|
||||||
|
intExp: expStats.intExp,
|
||||||
|
};
|
||||||
|
player.gainMoney(gains.money, source);
|
||||||
|
|
||||||
|
return gains;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const applyWorkStatsExp = (target: IPerson, workStats: WorkStats, cycles: number): WorkStats => {
|
||||||
|
const gains = {
|
||||||
|
money: 0,
|
||||||
|
reputation: 0,
|
||||||
hackExp: workStats.hackExp * cycles,
|
hackExp: workStats.hackExp * cycles,
|
||||||
strExp: workStats.strExp * cycles,
|
strExp: workStats.strExp * cycles,
|
||||||
defExp: workStats.defExp * cycles,
|
defExp: workStats.defExp * cycles,
|
||||||
@ -78,13 +104,12 @@ export const applyWorkStats = (player: IPlayer, workStats: WorkStats, cycles: nu
|
|||||||
chaExp: workStats.chaExp * cycles,
|
chaExp: workStats.chaExp * cycles,
|
||||||
intExp: workStats.intExp * cycles,
|
intExp: workStats.intExp * cycles,
|
||||||
};
|
};
|
||||||
player.gainHackingExp(gains.hackExp);
|
target.gainHackingExp(gains.hackExp);
|
||||||
player.gainStrengthExp(gains.strExp);
|
target.gainStrengthExp(gains.strExp);
|
||||||
player.gainDefenseExp(gains.defExp);
|
target.gainDefenseExp(gains.defExp);
|
||||||
player.gainDexterityExp(gains.dexExp);
|
target.gainDexterityExp(gains.dexExp);
|
||||||
player.gainAgilityExp(gains.agiExp);
|
target.gainAgilityExp(gains.agiExp);
|
||||||
player.gainCharismaExp(gains.chaExp);
|
target.gainCharismaExp(gains.chaExp);
|
||||||
player.gainIntelligenceExp(gains.intExp);
|
target.gainIntelligenceExp(gains.intExp);
|
||||||
player.gainMoney(gains.money, source);
|
|
||||||
return gains;
|
return gains;
|
||||||
};
|
};
|
||||||
|
@ -3,11 +3,13 @@ import { Location } from "../../Locations/Location";
|
|||||||
import { BitNodeMultipliers } from "../../BitNode/BitNodeMultipliers";
|
import { BitNodeMultipliers } from "../../BitNode/BitNodeMultipliers";
|
||||||
import { CONSTANTS } from "../../Constants";
|
import { CONSTANTS } from "../../Constants";
|
||||||
import { IPlayer } from "../../PersonObjects/IPlayer";
|
import { IPlayer } from "../../PersonObjects/IPlayer";
|
||||||
import { Class, Classes, ClassWork } from "../ClassWork";
|
import { Class, Classes, ClassType } from "../ClassWork";
|
||||||
import { WorkStats } from "../WorkStats";
|
import { WorkStats } from "../WorkStats";
|
||||||
import { Server } from "../../Server/Server";
|
import { Server } from "../../Server/Server";
|
||||||
import { GetServer } from "../../Server/AllServers";
|
import { GetServer } from "../../Server/AllServers";
|
||||||
import { serverMetadata } from "../../Server/data/servers";
|
import { serverMetadata } from "../../Server/data/servers";
|
||||||
|
import { IPerson } from "../../PersonObjects/IPerson";
|
||||||
|
import { LocationName } from "../../Locations/data/LocationNames";
|
||||||
|
|
||||||
const gameCPS = 1000 / CONSTANTS._idleSpeed; // 5 cycles per second
|
const gameCPS = 1000 / CONSTANTS._idleSpeed; // 5 cycles per second
|
||||||
|
|
||||||
@ -18,13 +20,22 @@ export function calculateCost(classs: Class, location: Location): number {
|
|||||||
return classs.earnings.money * location.costMult * discount;
|
return classs.earnings.money * location.costMult * discount;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function calculateClassEarnings(player: IPlayer, work: ClassWork): WorkStats {
|
export function calculateClassEarnings(
|
||||||
|
player: IPlayer,
|
||||||
|
target: IPerson,
|
||||||
|
type: ClassType,
|
||||||
|
locationName: LocationName,
|
||||||
|
): WorkStats {
|
||||||
//Find cost and exp gain per game cycle
|
//Find cost and exp gain per game cycle
|
||||||
const hashManager = player.hashManager;
|
const hashManager = player.hashManager;
|
||||||
const classs = Classes[work.classType];
|
const classs = Classes[type];
|
||||||
const location = Locations[work.location];
|
const location = Locations[locationName];
|
||||||
|
|
||||||
const hashMult = work.isGym() ? hashManager.getTrainingMult() : hashManager.getStudyMult();
|
const hashMult = [ClassType.GymAgility, ClassType.GymDefense, ClassType.GymStrength, ClassType.GymDexterity].includes(
|
||||||
|
type,
|
||||||
|
)
|
||||||
|
? hashManager.getTrainingMult()
|
||||||
|
: hashManager.getStudyMult();
|
||||||
|
|
||||||
const cost = calculateCost(classs, location) / gameCPS;
|
const cost = calculateCost(classs, location) / gameCPS;
|
||||||
const hackExp = ((classs.earnings.hackExp * location.expMult) / gameCPS) * hashMult;
|
const hackExp = ((classs.earnings.hackExp * location.expMult) / gameCPS) * hashMult;
|
||||||
@ -36,12 +47,12 @@ export function calculateClassEarnings(player: IPlayer, work: ClassWork): WorkSt
|
|||||||
return {
|
return {
|
||||||
money: cost,
|
money: cost,
|
||||||
reputation: 0,
|
reputation: 0,
|
||||||
hackExp: hackExp * player.mults.hacking_exp * BitNodeMultipliers.ClassGymExpGain,
|
hackExp: hackExp * target.mults.hacking_exp * BitNodeMultipliers.ClassGymExpGain,
|
||||||
strExp: strExp * player.mults.strength_exp * BitNodeMultipliers.ClassGymExpGain,
|
strExp: strExp * target.mults.strength_exp * BitNodeMultipliers.ClassGymExpGain,
|
||||||
defExp: defExp * player.mults.defense_exp * BitNodeMultipliers.ClassGymExpGain,
|
defExp: defExp * target.mults.defense_exp * BitNodeMultipliers.ClassGymExpGain,
|
||||||
dexExp: dexExp * player.mults.dexterity_exp * BitNodeMultipliers.ClassGymExpGain,
|
dexExp: dexExp * target.mults.dexterity_exp * BitNodeMultipliers.ClassGymExpGain,
|
||||||
agiExp: agiExp * player.mults.agility_exp * BitNodeMultipliers.ClassGymExpGain,
|
agiExp: agiExp * target.mults.agility_exp * BitNodeMultipliers.ClassGymExpGain,
|
||||||
chaExp: chaExp * player.mults.charisma_exp * BitNodeMultipliers.ClassGymExpGain,
|
chaExp: chaExp * target.mults.charisma_exp * BitNodeMultipliers.ClassGymExpGain,
|
||||||
intExp: 0,
|
intExp: 0,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -5,16 +5,12 @@ import { WorkStats } from "../WorkStats";
|
|||||||
import { BitNodeMultipliers } from "../../BitNode/BitNodeMultipliers";
|
import { BitNodeMultipliers } from "../../BitNode/BitNodeMultipliers";
|
||||||
import { CONSTANTS } from "../../Constants";
|
import { CONSTANTS } from "../../Constants";
|
||||||
import { AugmentationNames } from "../../Augmentation/data/AugmentationNames";
|
import { AugmentationNames } from "../../Augmentation/data/AugmentationNames";
|
||||||
|
import { IPerson } from "src/PersonObjects/IPerson";
|
||||||
|
|
||||||
export const calculateCompanyWorkStats = (player: IPlayer, company: Company): WorkStats => {
|
export const calculateCompanyWorkStats = (player: IPlayer, worker: IPerson, company: Company): WorkStats => {
|
||||||
const companyPositionName = player.jobs[company.name];
|
const companyPositionName = player.jobs[company.name];
|
||||||
const companyPosition = CompanyPositions[companyPositionName];
|
const companyPosition = CompanyPositions[companyPositionName];
|
||||||
|
|
||||||
let focusBonus = 1;
|
|
||||||
if (!player.hasAugmentation(AugmentationNames.NeuroreceptorManager)) {
|
|
||||||
focusBonus = player.focus ? 1 : CONSTANTS.BaseFocusBonus;
|
|
||||||
}
|
|
||||||
|
|
||||||
// If player has SF-11, calculate salary multiplier from favor
|
// If player has SF-11, calculate salary multiplier from favor
|
||||||
let favorMult = 1 + company.favor / 100;
|
let favorMult = 1 + company.favor / 100;
|
||||||
if (isNaN(favorMult)) {
|
if (isNaN(favorMult)) {
|
||||||
@ -27,60 +23,53 @@ export const calculateCompanyWorkStats = (player: IPlayer, company: Company): Wo
|
|||||||
}
|
}
|
||||||
|
|
||||||
let jobPerformance = companyPosition.calculateJobPerformance(
|
let jobPerformance = companyPosition.calculateJobPerformance(
|
||||||
player.skills.hacking,
|
worker.skills.hacking,
|
||||||
player.skills.strength,
|
worker.skills.strength,
|
||||||
player.skills.defense,
|
worker.skills.defense,
|
||||||
player.skills.dexterity,
|
worker.skills.dexterity,
|
||||||
player.skills.agility,
|
worker.skills.agility,
|
||||||
player.skills.charisma,
|
worker.skills.charisma,
|
||||||
);
|
);
|
||||||
|
|
||||||
jobPerformance += player.skills.intelligence / CONSTANTS.MaxSkillLevel;
|
jobPerformance += worker.skills.intelligence / CONSTANTS.MaxSkillLevel;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
money:
|
money:
|
||||||
focusBonus *
|
|
||||||
companyPosition.baseSalary *
|
companyPosition.baseSalary *
|
||||||
company.salaryMultiplier *
|
company.salaryMultiplier *
|
||||||
player.mults.work_money *
|
worker.mults.work_money *
|
||||||
BitNodeMultipliers.CompanyWorkMoney *
|
BitNodeMultipliers.CompanyWorkMoney *
|
||||||
bn11Mult,
|
bn11Mult,
|
||||||
reputation: focusBonus * jobPerformance * player.mults.company_rep * favorMult,
|
reputation: jobPerformance * worker.mults.company_rep * favorMult,
|
||||||
hackExp:
|
hackExp:
|
||||||
focusBonus *
|
|
||||||
companyPosition.hackingExpGain *
|
companyPosition.hackingExpGain *
|
||||||
company.expMultiplier *
|
company.expMultiplier *
|
||||||
player.mults.hacking_exp *
|
worker.mults.hacking_exp *
|
||||||
BitNodeMultipliers.CompanyWorkExpGain,
|
BitNodeMultipliers.CompanyWorkExpGain,
|
||||||
strExp:
|
strExp:
|
||||||
focusBonus *
|
|
||||||
companyPosition.strengthExpGain *
|
companyPosition.strengthExpGain *
|
||||||
company.expMultiplier *
|
company.expMultiplier *
|
||||||
player.mults.strength_exp *
|
worker.mults.strength_exp *
|
||||||
BitNodeMultipliers.CompanyWorkExpGain,
|
BitNodeMultipliers.CompanyWorkExpGain,
|
||||||
defExp:
|
defExp:
|
||||||
focusBonus *
|
|
||||||
companyPosition.defenseExpGain *
|
companyPosition.defenseExpGain *
|
||||||
company.expMultiplier *
|
company.expMultiplier *
|
||||||
player.mults.defense_exp *
|
worker.mults.defense_exp *
|
||||||
BitNodeMultipliers.CompanyWorkExpGain,
|
BitNodeMultipliers.CompanyWorkExpGain,
|
||||||
dexExp:
|
dexExp:
|
||||||
focusBonus *
|
|
||||||
companyPosition.dexterityExpGain *
|
companyPosition.dexterityExpGain *
|
||||||
company.expMultiplier *
|
company.expMultiplier *
|
||||||
player.mults.dexterity_exp *
|
worker.mults.dexterity_exp *
|
||||||
BitNodeMultipliers.CompanyWorkExpGain,
|
BitNodeMultipliers.CompanyWorkExpGain,
|
||||||
agiExp:
|
agiExp:
|
||||||
focusBonus *
|
|
||||||
companyPosition.agilityExpGain *
|
companyPosition.agilityExpGain *
|
||||||
company.expMultiplier *
|
company.expMultiplier *
|
||||||
player.mults.agility_exp *
|
worker.mults.agility_exp *
|
||||||
BitNodeMultipliers.CompanyWorkExpGain,
|
BitNodeMultipliers.CompanyWorkExpGain,
|
||||||
chaExp:
|
chaExp:
|
||||||
focusBonus *
|
|
||||||
companyPosition.charismaExpGain *
|
companyPosition.charismaExpGain *
|
||||||
company.expMultiplier *
|
company.expMultiplier *
|
||||||
player.mults.charisma_exp *
|
worker.mults.charisma_exp *
|
||||||
BitNodeMultipliers.CompanyWorkExpGain,
|
BitNodeMultipliers.CompanyWorkExpGain,
|
||||||
intExp: 0,
|
intExp: 0,
|
||||||
};
|
};
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
import { AugmentationNames } from "../../Augmentation/data/AugmentationNames";
|
import { IPerson } from "../../PersonObjects/IPerson";
|
||||||
import { BitNodeMultipliers } from "../../BitNode/BitNodeMultipliers";
|
import { BitNodeMultipliers } from "../../BitNode/BitNodeMultipliers";
|
||||||
import { CONSTANTS } from "../../Constants";
|
import { CONSTANTS } from "../../Constants";
|
||||||
import { IPlayer } from "../../PersonObjects/IPlayer";
|
|
||||||
import { FactionWorkType } from "../data/FactionWorkType";
|
import { FactionWorkType } from "../data/FactionWorkType";
|
||||||
import { newWorkStats, WorkStats } from "../WorkStats";
|
import { newWorkStats, WorkStats } from "../WorkStats";
|
||||||
|
|
||||||
@ -26,27 +25,17 @@ export const FactionWorkStats: Record<FactionWorkType, WorkStats> = {
|
|||||||
}),
|
}),
|
||||||
};
|
};
|
||||||
|
|
||||||
export function calculateFactionExp(player: IPlayer, tpe: FactionWorkType): WorkStats {
|
export function calculateFactionExp(person: IPerson, tpe: FactionWorkType): WorkStats {
|
||||||
let focusBonus = 1;
|
|
||||||
if (!player.hasAugmentation(AugmentationNames.NeuroreceptorManager)) {
|
|
||||||
focusBonus = player.focus ? 1 : CONSTANTS.BaseFocusBonus;
|
|
||||||
}
|
|
||||||
const baseStats = FactionWorkStats[tpe];
|
const baseStats = FactionWorkStats[tpe];
|
||||||
return {
|
return {
|
||||||
money: 0,
|
money: 0,
|
||||||
reputation: 0,
|
reputation: 0,
|
||||||
hackExp:
|
hackExp: (baseStats.hackExp * person.mults.hacking_exp * BitNodeMultipliers.FactionWorkExpGain) / gameCPS,
|
||||||
(focusBonus * (baseStats.hackExp * player.mults.hacking_exp * BitNodeMultipliers.FactionWorkExpGain)) / gameCPS,
|
strExp: (baseStats.strExp * person.mults.strength_exp * BitNodeMultipliers.FactionWorkExpGain) / gameCPS,
|
||||||
strExp:
|
defExp: (baseStats.defExp * person.mults.defense_exp * BitNodeMultipliers.FactionWorkExpGain) / gameCPS,
|
||||||
(focusBonus * (baseStats.strExp * player.mults.strength_exp * BitNodeMultipliers.FactionWorkExpGain)) / gameCPS,
|
dexExp: (baseStats.dexExp * person.mults.dexterity_exp * BitNodeMultipliers.FactionWorkExpGain) / gameCPS,
|
||||||
defExp:
|
agiExp: (baseStats.agiExp * person.mults.agility_exp * BitNodeMultipliers.FactionWorkExpGain) / gameCPS,
|
||||||
(focusBonus * (baseStats.defExp * player.mults.defense_exp * BitNodeMultipliers.FactionWorkExpGain)) / gameCPS,
|
chaExp: (baseStats.chaExp * person.mults.charisma_exp * BitNodeMultipliers.FactionWorkExpGain) / gameCPS,
|
||||||
dexExp:
|
|
||||||
(focusBonus * (baseStats.dexExp * player.mults.dexterity_exp * BitNodeMultipliers.FactionWorkExpGain)) / gameCPS,
|
|
||||||
agiExp:
|
|
||||||
(focusBonus * (baseStats.agiExp * player.mults.agility_exp * BitNodeMultipliers.FactionWorkExpGain)) / gameCPS,
|
|
||||||
chaExp:
|
|
||||||
(focusBonus * (baseStats.chaExp * player.mults.charisma_exp * BitNodeMultipliers.FactionWorkExpGain)) / gameCPS,
|
|
||||||
intExp: 0,
|
intExp: 0,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -1,15 +1,15 @@
|
|||||||
export enum CrimeType {
|
export enum CrimeType {
|
||||||
None = "",
|
None = "",
|
||||||
Shoplift = "shoplift",
|
SHOPLIFT = "SHOPLIFT", //"shoplift",
|
||||||
RobStore = "rob a store",
|
ROB_STORE = "ROBSTORE", //"rob a store",
|
||||||
Mug = "mug someone",
|
MUG = "MUG", //"mug someone",
|
||||||
Larceny = "commit larceny",
|
LARCENY = "LARCENY", //"commit larceny",
|
||||||
Drugs = "deal drugs",
|
DRUGS = "DRUGS", //"deal drugs",
|
||||||
BondForgery = "forge corporate bonds",
|
BOND_FORGERY = "BONDFORGERY", //"forge corporate bonds",
|
||||||
TraffickArms = "traffick illegal arms",
|
TRAFFIC_ARMS = "TRAFFICKARMS", //"traffick illegal arms",
|
||||||
Homicide = "commit homicide",
|
HOMICIDE = "HOMICIDE", //"commit homicide",
|
||||||
GrandTheftAuto = "commit grand theft auto",
|
GRAND_THEFT_AUTO = "GRANDTHEFTAUTO", //"commit grand theft auto",
|
||||||
Kidnap = "kidnap someone for ransom",
|
KIDNAP = "KIDNAP", //"kidnap someone for ransom",
|
||||||
Assassination = "assassinate a high-profile target",
|
ASSASSINATION = "ASSASSINATION", //"assassinate a high-profile target",
|
||||||
Heist = "pull off the ultimate heist",
|
HEIST = "HEIST", //"pull off the ultimate heist",
|
||||||
}
|
}
|
||||||
|
@ -185,6 +185,12 @@ export const v2APIBreak = () => {
|
|||||||
reason: "sell is a very common word so in order to avoid ram costs it was renamed ns.stock.sellStock",
|
reason: "sell is a very common word so in order to avoid ram costs it was renamed ns.stock.sellStock",
|
||||||
offenders: [],
|
offenders: [],
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
matchJS: /ns\.stock\.short/g,
|
||||||
|
matchScript: /stock\.short/g,
|
||||||
|
reason: "short is a very common word so in order to avoid ram costs it was renamed ns.stock.buyShort",
|
||||||
|
offenders: [],
|
||||||
|
},
|
||||||
{
|
{
|
||||||
matchJS: /ns\.corporation\.bribe/g,
|
matchJS: /ns\.corporation\.bribe/g,
|
||||||
matchScript: /corporation\.bribe/g,
|
matchScript: /corporation\.bribe/g,
|
||||||
|
Loading…
Reference in New Issue
Block a user