bitburner-src/src/PersonObjects/Sleeve/ui/TaskSelector.tsx

418 lines
14 KiB
TypeScript
Raw Normal View History

import React, { useState } from "react";
import { Sleeve } from "../Sleeve";
import { IPlayer } from "../../IPlayer";
import { Crimes } from "../../../Crime/Crimes";
import { LocationName } from "../../../Locations/data/LocationNames";
import { CityName } from "../../../Locations/data/CityNames";
import { Factions } from "../../../Faction/Factions";
2021-09-27 02:55:38 +02:00
import Select, { SelectChangeEvent } from "@mui/material/Select";
import MenuItem from "@mui/material/MenuItem";
import { FactionNames } from "../../../Faction/data/FactionNames";
2022-07-28 09:08:39 +02:00
import { isSleeveFactionWork } from "../Work/SleeveFactionWork";
import { isSleeveCompanyWork } from "../Work/SleeveCompanyWork";
import { isSleeveBladeburnerWork } from "../Work/SleeveBladeburnerWork";
2022-07-28 20:35:55 +02:00
import { isSleeveRecoveryWork } from "../Work/SleeveRecoveryWork";
import { isSleeveSynchroWork } from "../Work/SleeveSynchroWork";
import { isSleeveClassWork } from "../Work/SleeveClassWork";
import { isSleeveInfiltrateWork } from "../Work/SleeveInfiltrateWork";
import { isSleeveSupportWork } from "../Work/SleeveSupportWork";
import { ClassType } from "../../../Work/ClassWork";
import { isSleeveCrimeWork } from "../Work/SleeveCrimeWork";
import { FactionWorkType } from "../../../Work/data/FactionWorkType";
const universitySelectorOptions: string[] = [
"Study Computer Science",
"Data Structures",
"Networks",
"Algorithms",
"Management",
"Leadership",
];
const gymSelectorOptions: string[] = ["Train Strength", "Train Defense", "Train Dexterity", "Train Agility"];
2022-04-14 18:00:17 +02:00
const bladeburnerSelectorOptions: string[] = [
"Field analysis",
2022-04-14 18:00:17 +02:00
"Recruitment",
"Diplomacy",
"Infiltrate synthoids",
"Support main sleeve",
"Take on contracts",
2022-04-14 18:00:17 +02:00
];
interface IProps {
sleeve: Sleeve;
player: IPlayer;
setABC: (abc: string[]) => void;
}
interface ITaskDetails {
first: string[];
second: (s1: string) => string[];
}
function possibleJobs(player: IPlayer, sleeve: Sleeve): string[] {
// Array of all companies that other sleeves are working at
const forbiddenCompanies: string[] = [];
for (const otherSleeve of player.sleeves) {
if (sleeve === otherSleeve) {
continue;
}
2022-07-28 09:08:39 +02:00
if (isSleeveCompanyWork(otherSleeve.currentWork)) {
forbiddenCompanies.push(otherSleeve.currentWork.companyName);
}
}
2021-09-10 04:57:37 +02:00
const allJobs: string[] = Object.keys(player.jobs);
return allJobs.filter((company) => !forbiddenCompanies.includes(company));
}
function possibleFactions(player: IPlayer, sleeve: Sleeve): string[] {
// Array of all factions that other sleeves are working for
2022-04-22 21:30:49 +02:00
const forbiddenFactions = [FactionNames.Bladeburners as string, FactionNames.ShadowsOfAnarchy as string];
2021-09-11 07:54:19 +02:00
if (player.gang) {
forbiddenFactions.push(player.gang.facName);
}
for (const otherSleeve of player.sleeves) {
if (sleeve === otherSleeve) {
continue;
}
2022-07-28 09:08:39 +02:00
if (isSleeveFactionWork(otherSleeve.currentWork)) {
forbiddenFactions.push(otherSleeve.currentWork.factionName);
}
}
const factions = [];
for (const fac of player.factions) {
if (!forbiddenFactions.includes(fac)) {
factions.push(fac);
}
}
2022-04-07 01:30:08 +02:00
return factions.filter((faction) => {
const factionObj = Factions[faction];
if (!factionObj) return false;
const facInfo = factionObj.getInfo();
2022-04-07 01:30:08 +02:00
return facInfo.offerHackingWork || facInfo.offerFieldWork || facInfo.offerSecurityWork;
});
}
function possibleContracts(player: IPlayer, sleeve: Sleeve): string[] {
const bb = player.bladeburner;
2022-04-14 18:00:17 +02:00
if (bb === null) {
return ["------"];
}
let contracts = bb.getContractNamesNetscriptFn();
for (const otherSleeve of player.sleeves) {
if (sleeve === otherSleeve) {
continue;
}
2022-07-28 09:08:39 +02:00
if (isSleeveBladeburnerWork(otherSleeve.currentWork) && otherSleeve.currentWork.actionType === "Contracts") {
const w = otherSleeve.currentWork;
contracts = contracts.filter((x) => x != w.actionName);
}
}
2022-04-14 18:00:17 +02:00
if (contracts.length === 0) {
return ["------"];
}
return contracts;
}
const tasks: {
[key: string]: undefined | ((player: IPlayer, sleeve: Sleeve) => ITaskDetails);
["------"]: (player: IPlayer, sleeve: Sleeve) => ITaskDetails;
["Work for Company"]: (player: IPlayer, sleeve: Sleeve) => ITaskDetails;
["Work for Faction"]: (player: IPlayer, sleeve: Sleeve) => ITaskDetails;
["Commit Crime"]: (player: IPlayer, sleeve: Sleeve) => ITaskDetails;
["Take University Course"]: (player: IPlayer, sleeve: Sleeve) => ITaskDetails;
["Workout at Gym"]: (player: IPlayer, sleeve: Sleeve) => ITaskDetails;
["Perform Bladeburner Actions"]: (player: IPlayer, sleeve: Sleeve) => ITaskDetails;
["Shock Recovery"]: (player: IPlayer, sleeve: Sleeve) => ITaskDetails;
["Synchronize"]: (player: IPlayer, sleeve: Sleeve) => ITaskDetails;
} = {
2021-09-10 04:57:37 +02:00
"------": (): ITaskDetails => {
return { first: ["------"], second: () => ["------"] };
},
"Work for Company": (player: IPlayer, sleeve: Sleeve): ITaskDetails => {
let jobs = possibleJobs(player, sleeve);
if (jobs.length === 0) jobs = ["------"];
return { first: jobs, second: () => ["------"] };
},
"Work for Faction": (player: IPlayer, sleeve: Sleeve): ITaskDetails => {
let factions = possibleFactions(player, sleeve);
if (factions.length === 0) factions = ["------"];
return {
first: factions,
second: (s1: string) => {
const faction = Factions[s1];
2022-04-25 03:38:07 +02:00
if (!faction) return ["------"];
const facInfo = faction.getInfo();
const options: string[] = [];
if (facInfo.offerHackingWork) {
options.push("Hacking Contracts");
}
if (facInfo.offerFieldWork) {
options.push("Field Work");
}
if (facInfo.offerSecurityWork) {
options.push("Security Work");
}
return options;
},
};
},
2021-09-10 04:57:37 +02:00
"Commit Crime": (): ITaskDetails => {
return { first: Object.values(Crimes).map((crime) => crime.name), second: () => ["------"] };
},
"Take University Course": (player: IPlayer, sleeve: Sleeve): ITaskDetails => {
let universities: string[] = [];
switch (sleeve.city) {
case CityName.Aevum:
universities = [LocationName.AevumSummitUniversity];
break;
case CityName.Sector12:
universities = [LocationName.Sector12RothmanUniversity];
break;
case CityName.Volhaven:
universities = [LocationName.VolhavenZBInstituteOfTechnology];
break;
default:
universities = ["No university available in city!"];
break;
}
return { first: universitySelectorOptions, second: () => universities };
},
"Workout at Gym": (player: IPlayer, sleeve: Sleeve): ITaskDetails => {
let gyms: string[] = [];
switch (sleeve.city) {
case CityName.Aevum:
gyms = [LocationName.AevumCrushFitnessGym, LocationName.AevumSnapFitnessGym];
break;
case CityName.Sector12:
gyms = [LocationName.Sector12IronGym, LocationName.Sector12PowerhouseGym];
break;
case CityName.Volhaven:
gyms = [LocationName.VolhavenMilleniumFitnessGym];
break;
default:
gyms = ["No gym available in city!"];
break;
}
return { first: gymSelectorOptions, second: () => gyms };
},
"Perform Bladeburner Actions": (player: IPlayer, sleeve: Sleeve): ITaskDetails => {
2022-04-14 17:57:01 +02:00
return {
first: bladeburnerSelectorOptions,
second: (s1: string) => {
if (s1 === "Take on contracts") {
return possibleContracts(player, sleeve);
} else {
return ["------"];
}
2022-04-14 18:00:17 +02:00
},
};
},
2021-09-10 04:57:37 +02:00
"Shock Recovery": (): ITaskDetails => {
return { first: ["------"], second: () => ["------"] };
},
2021-09-10 04:57:37 +02:00
Synchronize: (): ITaskDetails => {
return { first: ["------"], second: () => ["------"] };
},
};
const canDo: {
[key: string]: undefined | ((player: IPlayer, sleeve: Sleeve) => boolean);
["------"]: (player: IPlayer, sleeve: Sleeve) => boolean;
["Work for Company"]: (player: IPlayer, sleeve: Sleeve) => boolean;
["Work for Faction"]: (player: IPlayer, sleeve: Sleeve) => boolean;
["Commit Crime"]: (player: IPlayer, sleeve: Sleeve) => boolean;
["Take University Course"]: (player: IPlayer, sleeve: Sleeve) => boolean;
["Workout at Gym"]: (player: IPlayer, sleeve: Sleeve) => boolean;
["Perform Bladeburner Actions"]: (player: IPlayer, sleeve: Sleeve) => boolean;
["Shock Recovery"]: (player: IPlayer, sleeve: Sleeve) => boolean;
["Synchronize"]: (player: IPlayer, sleeve: Sleeve) => boolean;
} = {
2021-09-10 04:57:37 +02:00
"------": () => true,
"Work for Company": (player: IPlayer, sleeve: Sleeve) => possibleJobs(player, sleeve).length > 0,
"Work for Faction": (player: IPlayer, sleeve: Sleeve) => possibleFactions(player, sleeve).length > 0,
"Commit Crime": () => true,
2021-09-22 18:56:55 +02:00
"Take University Course": (player: IPlayer, sleeve: Sleeve) =>
[CityName.Aevum, CityName.Sector12, CityName.Volhaven].includes(sleeve.city),
"Workout at Gym": (player: IPlayer, sleeve: Sleeve) =>
[CityName.Aevum, CityName.Sector12, CityName.Volhaven].includes(sleeve.city),
2022-07-19 18:19:32 +02:00
"Perform Bladeburner Actions": (player: IPlayer) => player.inBladeburner(),
2021-09-10 04:57:37 +02:00
"Shock Recovery": (player: IPlayer, sleeve: Sleeve) => sleeve.shock < 100,
Synchronize: (player: IPlayer, sleeve: Sleeve) => sleeve.sync < 100,
};
function getABC(sleeve: Sleeve): [string, string, string] {
2022-07-28 20:35:55 +02:00
const w = sleeve.currentWork;
if (w === null) {
return ["------", "------", "------"];
}
2022-07-28 09:08:39 +02:00
2022-07-28 20:35:55 +02:00
if (isSleeveCompanyWork(w)) {
return ["Work for Company", w.companyName, "------"];
}
if (isSleeveFactionWork(w)) {
let workType = "";
switch (w.factionWorkType) {
case FactionWorkType.HACKING:
workType = "Hacking Contracts";
break;
case FactionWorkType.FIELD:
workType = "Field Work";
break;
case FactionWorkType.SECURITY:
workType = "Security Work";
break;
}
return ["Work for Faction", w.factionName, workType];
}
if (isSleeveBladeburnerWork(w)) {
if (w.actionType === "Contracts") {
return ["Perform Bladeburner Actions", "Take on contracts", w.actionName];
}
switch (w.actionName) {
case "Field Analysis":
return ["Perform Bladeburner Actions", "Field Analysis", "------"];
case "Diplomacy":
return ["Perform Bladeburner Actions", "Diplomacy", "------"];
case "Recruitment":
return ["Perform Bladeburner Actions", "Recruitment", "------"];
}
}
if (isSleeveClassWork(w)) {
switch (w.classType) {
case ClassType.StudyComputerScience:
return ["Take University Course", "Study Computer Science", w.location];
case ClassType.DataStructures:
return ["Take University Course", "Data Structures", w.location];
case ClassType.Networks:
return ["Take University Course", "Networks", w.location];
case ClassType.Algorithms:
return ["Take University Course", "Algorithms", w.location];
case ClassType.Management:
return ["Take University Course", "Management", w.location];
case ClassType.Leadership:
return ["Take University Course", "Leadership", w.location];
case ClassType.GymStrength:
return ["Workout at Gym", "Train Strength", w.location];
case ClassType.GymDefense:
return ["Workout at Gym", "Train Defense", w.location];
case ClassType.GymDexterity:
return ["Workout at Gym", "Train Dexterity", w.location];
case ClassType.GymAgility:
return ["Workout at Gym", "Train Agility", w.location];
}
}
if (isSleeveCrimeWork(w)) {
return [
"Commit Crime",
Object.values(Crimes).find((crime) => crime.type === w.crimeType)?.name ?? "Shoplift",
"------",
];
}
if (isSleeveSupportWork(w)) {
return ["Perform Bladeburner Actions", "Support main sleeve", "------"];
}
if (isSleeveInfiltrateWork(w)) {
return ["Perform Bladeburner Actions", "Infiltrate synthoids", "------"];
}
if (isSleeveRecoveryWork(w)) {
return ["Shock Recovery", "------", "------"];
}
if (isSleeveSynchroWork(w)) {
return ["Synchronize", "------", "------"];
}
return ["------", "------", "------"];
}
export function TaskSelector(props: IProps): React.ReactElement {
const abc = getABC(props.sleeve);
const [s0, setS0] = useState(abc[0]);
const [s1, setS1] = useState(abc[1]);
const [s2, setS2] = useState(abc[2]);
2021-09-22 18:56:55 +02:00
const validActions = Object.keys(canDo).filter((k) =>
(canDo[k] as (player: IPlayer, sleeve: Sleeve) => boolean)(props.player, props.sleeve),
);
const detailsF = tasks[s0];
if (detailsF === undefined) throw new Error(`No function for task '${s0}'`);
const details = detailsF(props.player, props.sleeve);
const details2 = details.second(s1);
2021-09-11 07:54:19 +02:00
if (details.first.length > 0 && !details.first.includes(s1)) {
setS1(details.first[0]);
props.setABC([s0, details.first[0], s2]);
}
if (details2.length > 0 && !details2.includes(s2)) {
setS2(details2[0]);
props.setABC([s0, s1, details2[0]]);
}
2021-09-27 02:55:38 +02:00
function onS0Change(event: SelectChangeEvent<string>): void {
const n = event.target.value;
const detailsF = tasks[n];
if (detailsF === undefined) throw new Error(`No function for task '${s0}'`);
const details = detailsF(props.player, props.sleeve);
2022-04-25 03:38:07 +02:00
const details2 = details.second(details.first[0]) ?? ["------"];
setS2(details2[0]);
setS1(details.first[0]);
setS0(n);
props.setABC([n, details.first[0], details2[0]]);
}
2021-09-27 02:55:38 +02:00
function onS1Change(event: SelectChangeEvent<string>): void {
setS1(event.target.value);
props.setABC([s0, event.target.value, s2]);
}
2021-09-27 02:55:38 +02:00
function onS2Change(event: SelectChangeEvent<string>): void {
setS2(event.target.value);
props.setABC([s0, s1, event.target.value]);
}
return (
<>
2022-04-07 01:30:08 +02:00
<Select onChange={onS0Change} value={s0} sx={{ width: "100%" }}>
{validActions.map((task) => (
2021-09-27 02:55:38 +02:00
<MenuItem key={task} value={task}>
{task}
2021-09-27 02:55:38 +02:00
</MenuItem>
))}
2021-09-27 02:55:38 +02:00
</Select>
{!(details.first.length === 1 && details.first[0] === "------") && (
2021-09-27 02:55:38 +02:00
<>
2022-04-07 01:30:08 +02:00
<Select onChange={onS1Change} value={s1} sx={{ width: "100%" }}>
2021-09-27 02:55:38 +02:00
{details.first.map((detail) => (
<MenuItem key={detail} value={detail}>
{detail}
</MenuItem>
))}
</Select>
</>
)}
{!(details2.length === 1 && details2[0] === "------") && (
2021-09-27 02:55:38 +02:00
<>
2022-04-07 01:30:08 +02:00
<Select onChange={onS2Change} value={s2} sx={{ width: "100%" }}>
2021-09-27 02:55:38 +02:00
{details2.map((detail) => (
<MenuItem key={detail} value={detail}>
{detail}
</MenuItem>
))}
</Select>
</>
)}
</>
);
}