diff --git a/src/Hacknet/HacknetHelpers.tsx b/src/Hacknet/HacknetHelpers.tsx index e1ad643ec..d019ad54e 100644 --- a/src/Hacknet/HacknetHelpers.tsx +++ b/src/Hacknet/HacknetHelpers.tsx @@ -21,6 +21,7 @@ import { iTutorialSteps, iTutorialNextStep, ITutorial } from "../InteractiveTuto import { Player } from "@player"; import { GetServer } from "../Server/AllServers"; import { Server } from "../Server/Server"; +import { Companies } from "../Company/Companies"; // Returns a boolean indicating whether the player has Hacknet Servers // (the upgraded form of Hacknet Nodes) @@ -562,6 +563,14 @@ export function purchaseHashUpgrade(upgName: string, upgTarget: string, count = } break; } + case "Company Favor": { + if (!(upgTarget in Companies)) { + console.error(`Invalid target specified in purchaseHashUpgrade(): ${upgTarget}`); + throw new Error(`'${upgTarget}' is not a company.`); + } + Companies[upgTarget].favor += 5; + break; + } default: console.warn(`Unrecognized upgrade name ${upgName}. Upgrade has no effect`); return false; diff --git a/src/Hacknet/HashUpgrade.ts b/src/Hacknet/HashUpgrade.ts index 5b6c14ae1..c5735ab24 100644 --- a/src/Hacknet/HashUpgrade.ts +++ b/src/Hacknet/HashUpgrade.ts @@ -4,6 +4,7 @@ export interface IConstructorParams { costPerLevel: number; desc: string; hasTargetServer?: boolean; + hasTargetCompany?: boolean; name: string; value: number; effectText?: (level: number) => JSX.Element | null; @@ -33,6 +34,12 @@ export class HashUpgrade { */ hasTargetServer = false; + /** + * Boolean indicating that this upgrade's effect affects a single company, + * the "target" company + */ + hasTargetCompany = false; + /** Name of upgrade */ name = ""; @@ -51,6 +58,7 @@ export class HashUpgrade { this.costPerLevel = p.costPerLevel; this.desc = p.desc; this.hasTargetServer = p.hasTargetServer ? p.hasTargetServer : false; + this.hasTargetCompany = p.hasTargetCompany ? p.hasTargetCompany : false; this.name = p.name; this.value = p.value; } diff --git a/src/Hacknet/data/HashUpgradesMetadata.tsx b/src/Hacknet/data/HashUpgradesMetadata.tsx index 9c49311ed..0db9638b3 100644 --- a/src/Hacknet/data/HashUpgradesMetadata.tsx +++ b/src/Hacknet/data/HashUpgradesMetadata.tsx @@ -101,4 +101,11 @@ export const HashUpgradesMetadata: IConstructorParams[] = [ effectText: (level: number): JSX.Element | null => <>Generated {level} contracts., value: 1, }, + { + costPerLevel: 200, + desc: "Use hashes to increase the favor with a company by 5. This effect is permanent.", + hasTargetCompany: true, + name: "Company Favor", + value: 5, + }, ]; diff --git a/src/Hacknet/ui/HacknetUpgradeElem.tsx b/src/Hacknet/ui/HacknetUpgradeElem.tsx index 7c4e3053f..65289a5bf 100644 --- a/src/Hacknet/ui/HacknetUpgradeElem.tsx +++ b/src/Hacknet/ui/HacknetUpgradeElem.tsx @@ -5,6 +5,7 @@ import { HashManager } from "../HashManager"; import { HashUpgrade } from "../HashUpgrade"; import { ServerDropdown, ServerType } from "../../ui/React/ServerDropdown"; +import { CompanyDropdown } from "../../ui/React/CompanyDropdown"; import { dialogBoxCreate } from "../../ui/React/DialogBox"; import { CopyableText } from "../../ui/React/CopyableText"; @@ -15,6 +16,7 @@ import Paper from "@mui/material/Paper"; import Button from "@mui/material/Button"; import { SelectChangeEvent } from "@mui/material/Select"; import { FactionNames } from "../../Faction/data/FactionNames"; +import { companiesMetadata } from "../../Company/data/CompaniesMetadata"; interface IProps { hashManager: HashManager; @@ -23,6 +25,7 @@ interface IProps { } const serversMap: { [key: string]: string } = {}; +const companiesMap: { [key: string]: string } = {}; export function HacknetUpgradeElem(props: IProps): React.ReactElement { const [selectedServer, setSelectedServer] = useState( @@ -32,11 +35,20 @@ export function HacknetUpgradeElem(props: IProps): React.ReactElement { setSelectedServer(event.target.value); serversMap[props.upg.name] = event.target.value; } - + const [selectedCompany, setSelectedCompany] = useState( + companiesMap[props.upg.name] ? companiesMap[props.upg.name] : companiesMetadata[0].name, + ); + function changeTargetCompany(event: SelectChangeEvent): void { + setSelectedCompany(event.target.value); + companiesMap[props.upg.name] = event.target.value; + } function purchase(): void { const canPurchase = props.hashManager.hashes >= props.hashManager.getUpgradeCost(props.upg.name); if (canPurchase) { - const res = purchaseHashUpgrade(props.upg.name, selectedServer); + const res = purchaseHashUpgrade( + props.upg.name, + props.upg.name === "Company Favor" ? selectedCompany : selectedServer, + ); if (!res) { dialogBoxCreate( "Failed to purchase upgrade. This may be because you do not have enough hashes, " + @@ -67,7 +79,7 @@ export function HacknetUpgradeElem(props: IProps): React.ReactElement { {upg.desc} - {!upg.hasTargetServer && ( + {!upg.hasTargetServer && !upg.hasTargetCompany && ( @@ -81,6 +93,14 @@ export function HacknetUpgradeElem(props: IProps): React.ReactElement { onChange={changeTargetServer} /> )} + {upg.hasTargetCompany && ( + + )} {level > 0 && effect && {effect}} ); diff --git a/src/SaveObject.tsx b/src/SaveObject.tsx index 405591ddc..4914e8535 100755 --- a/src/SaveObject.tsx +++ b/src/SaveObject.tsx @@ -657,6 +657,9 @@ function evaluateVersionCompatibility(ver: string | number): void { // Prior to v2.2.0, sleeve shock was 0 to 100 internally but displayed as 100 to 0. This unifies them as 100 to 0. for (const sleeve of Player.sleeves) sleeve.shock = 100 - sleeve.shock; } + if (anyPlayer.hashManager !== undefined) { + anyPlayer.hashManager.upgrades["Company Favor"] ??= 0; + } } function loadGame(saveString: string): boolean { diff --git a/src/ui/React/CompanyDropdown.tsx b/src/ui/React/CompanyDropdown.tsx new file mode 100644 index 000000000..076f37a3f --- /dev/null +++ b/src/ui/React/CompanyDropdown.tsx @@ -0,0 +1,44 @@ +/** + * Creates a dropdown (select HTML element) with company names as options + */ +import React from "react"; +import { companiesMetadata } from "../../Company/data/CompaniesMetadata"; + +import Select, { SelectChangeEvent } from "@mui/material/Select"; +import MenuItem from "@mui/material/MenuItem"; +import Button from "@mui/material/Button"; + +interface IProps { + purchase: () => void; + canPurchase: boolean; + onChange: (event: SelectChangeEvent) => void; + value: string; +} + +const sortedCompanies = companiesMetadata.sort((a, b) => a.name.localeCompare(b.name)); + +export function CompanyDropdown(props: IProps): React.ReactElement { + const companies = []; + for (const company of sortedCompanies) { + companies.push( + + {company.name} + , + ); + } + + return ( + + ); +}