From 1f98eecb57fd65d86d11f30b96ffeb429539df96 Mon Sep 17 00:00:00 2001 From: Mughur Date: Sat, 18 Mar 2023 03:12:43 +0200 Subject: [PATCH] CORP: rework (#428) * corp overhaul: Corp production quality now depends on materials * corp overhaul: Product price can be set separately for each city * corp overhaul: export uses relatives * corp overhaul: ignore energy in quality * corp overhaul: getProduct() is city dependant * corp overhaul: bulkbuy available from start * corp overhaul: add multibuy for leveled upgrads * corp overhaul: changes to UI * corp overhaul: base quality 1, reqmat changes * corp overhaul: puchased material quality is 1 * corp overhaul: get rid of the text box from ta2 * corp overhaul: sold shares limitations * corp overhaul: coffee -> tea, training -> intern * corp overhaul: smartsupply has multiple options * corp overhaul: restart, literature, investore, ui * corp overhaul: nerf advertising * corp overhaul: bunch of stuff --- .gitignore | 6 +- ...ner.corpconstants.coffeecostperemployee.md | 11 -- markdown/bitburner.corpconstants.md | 4 +- ...itburner.corpconstants.minemployeedecay.md | 2 +- ...burner.corpconstants.teacostperemployee.md | 11 ++ markdown/bitburner.corpemployeeposition.md | 2 +- markdown/bitburner.corpindustryname.md | 5 +- markdown/bitburner.corpmaterialname.md | 3 +- .../bitburner.corporation.buybackshares.md | 2 +- markdown/bitburner.corporation.sellshares.md | 2 +- markdown/bitburner.material.md | 1 + markdown/bitburner.material.samt.md | 13 ++ markdown/bitburner.office.avghap.md | 13 -- markdown/bitburner.office.maxhap.md | 13 -- markdown/bitburner.office.md | 2 - ...offee.md => bitburner.officeapi.buytea.md} | 10 +- markdown/bitburner.officeapi.md | 2 +- markdown/bitburner.officeapi.throwparty.md | 2 +- markdown/bitburner.product.citydata.md | 13 -- markdown/bitburner.product.effrat.md | 13 ++ markdown/bitburner.product.md | 8 +- markdown/bitburner.product.prod.md | 13 ++ markdown/bitburner.product.qty.md | 13 ++ markdown/bitburner.product.samt.md | 13 ++ markdown/bitburner.product.scost.md | 2 +- markdown/bitburner.product.sell.md | 13 ++ markdown/bitburner.warehouseapi.getproduct.md | 3 +- markdown/bitburner.warehouseapi.md | 8 +- ...burner.warehouseapi.setproductmarketta1.md | 3 +- ...burner.warehouseapi.setproductmarketta2.md | 3 +- ...rner.warehouseapi.setsmartsupplyoption.md} | 10 +- src/BitNode/BitNode.tsx | 17 +- src/BitNode/BitNodeMultipliers.ts | 5 +- .../ui/BitnodeMultipliersDescription.tsx | 1 + src/Corporation/Actions.ts | 74 +++++---- src/Corporation/Corporation.tsx | 17 +- src/Corporation/Industry.ts | 155 +++++++++++++----- src/Corporation/IndustryData.tsx | 70 ++++---- src/Corporation/Material.ts | 2 +- src/Corporation/MaterialInfo.ts | 21 ++- src/Corporation/OfficeSpace.ts | 83 +++++----- src/Corporation/Product.ts | 10 +- src/Corporation/Warehouse.ts | 8 +- src/Corporation/data/BaseResearchTree.ts | 4 - src/Corporation/data/Constants.ts | 32 +++- src/Corporation/data/CorporationUpgrades.ts | 2 +- src/Corporation/data/Enums.ts | 9 +- src/Corporation/data/ResearchMetadata.ts | 24 +-- src/Corporation/helpers.tsx | 35 ++++ src/Corporation/ui/ExpandIndustryTab.tsx | 17 +- src/Corporation/ui/IndustryOffice.tsx | 37 ++--- src/Corporation/ui/IndustryOverview.tsx | 2 +- src/Corporation/ui/LevelableUpgrade.tsx | 12 +- src/Corporation/ui/MultiplierButtons.tsx | 50 ++++++ src/Corporation/ui/Overview.tsx | 66 +++++++- src/Corporation/ui/ProductElem.tsx | 12 +- src/Corporation/ui/UnlockUpgrade.tsx | 11 +- .../ui/modals/CreateCorporationModal.tsx | 4 +- src/Corporation/ui/modals/ExportModal.tsx | 20 ++- src/Corporation/ui/modals/GoPublicModal.tsx | 4 +- .../ui/modals/MakeProductModal.tsx | 2 +- .../ui/modals/MaterialMarketTaModal.tsx | 65 ++------ .../ui/modals/ProductMarketTaModal.tsx | 55 ++----- .../ui/modals/PurchaseMaterialModal.tsx | 7 +- .../ui/modals/SellCorporationModal.tsx | 71 ++++++++ .../ui/modals/SellDivisionModal.tsx | 100 +++++++++++ .../ui/modals/SellProductModal.tsx | 6 +- src/Corporation/ui/modals/SellSharesModal.tsx | 12 +- .../ui/modals/SmartSupplyModal.tsx | 53 ++++-- src/Corporation/ui/modals/ThrowPartyModal.tsx | 4 +- src/DevMenu/ui/General.tsx | 2 +- src/Literature/Literatures.ts | 81 ++++----- src/Netscript/RamCostGenerator.ts | 4 +- src/NetscriptFunctions/Corporation.ts | 56 ++++--- .../Player/PlayerObjectCorporationMethods.ts | 8 +- src/Prestige.ts | 3 + src/ScriptEditor/NetscriptDefinitions.d.ts | 63 ++++--- 77 files changed, 1045 insertions(+), 570 deletions(-) delete mode 100644 markdown/bitburner.corpconstants.coffeecostperemployee.md create mode 100644 markdown/bitburner.corpconstants.teacostperemployee.md create mode 100644 markdown/bitburner.material.samt.md delete mode 100644 markdown/bitburner.office.avghap.md delete mode 100644 markdown/bitburner.office.maxhap.md rename markdown/{bitburner.officeapi.buycoffee.md => bitburner.officeapi.buytea.md} (62%) delete mode 100644 markdown/bitburner.product.citydata.md create mode 100644 markdown/bitburner.product.effrat.md create mode 100644 markdown/bitburner.product.prod.md create mode 100644 markdown/bitburner.product.qty.md create mode 100644 markdown/bitburner.product.samt.md create mode 100644 markdown/bitburner.product.sell.md rename markdown/{bitburner.warehouseapi.setsmartsupplyuseleftovers.md => bitburner.warehouseapi.setsmartsupplyoption.md} (64%) create mode 100644 src/Corporation/helpers.tsx create mode 100644 src/Corporation/ui/MultiplierButtons.tsx create mode 100644 src/Corporation/ui/modals/SellCorporationModal.tsx create mode 100644 src/Corporation/ui/modals/SellDivisionModal.tsx diff --git a/.gitignore b/.gitignore index 2992c7521..4ac55efac 100644 --- a/.gitignore +++ b/.gitignore @@ -20,9 +20,9 @@ dist/assets dist/*.worker.* # tmp folder for build and electron -.app -.package -.build + .app + .package + .build # editor files .vscode diff --git a/markdown/bitburner.corpconstants.coffeecostperemployee.md b/markdown/bitburner.corpconstants.coffeecostperemployee.md deleted file mode 100644 index 162421b07..000000000 --- a/markdown/bitburner.corpconstants.coffeecostperemployee.md +++ /dev/null @@ -1,11 +0,0 @@ - - -[Home](./index.md) > [bitburner](./bitburner.md) > [CorpConstants](./bitburner.corpconstants.md) > [coffeeCostPerEmployee](./bitburner.corpconstants.coffeecostperemployee.md) - -## CorpConstants.coffeeCostPerEmployee property - -**Signature:** - -```typescript -coffeeCostPerEmployee: number; -``` diff --git a/markdown/bitburner.corpconstants.md b/markdown/bitburner.corpconstants.md index f1121b97e..ae01bca09 100644 --- a/markdown/bitburner.corpconstants.md +++ b/markdown/bitburner.corpconstants.md @@ -19,7 +19,6 @@ interface CorpConstants | [baseProductProfitMult](./bitburner.corpconstants.baseproductprofitmult.md) | | number | | | [bribeAmountPerReputation](./bitburner.corpconstants.bribeamountperreputation.md) | | number | | | [bribeThreshold](./bitburner.corpconstants.bribethreshold.md) | | number | | -| [coffeeCostPerEmployee](./bitburner.corpconstants.coffeecostperemployee.md) | | number | | | [dividendMaxRate](./bitburner.corpconstants.dividendmaxrate.md) | | number | | | [employeeRaiseAmount](./bitburner.corpconstants.employeeraiseamount.md) | | number | | | [employeeSalaryMultiplier](./bitburner.corpconstants.employeesalarymultiplier.md) | | number | Conversion factor for employee stats to initial salary | @@ -31,7 +30,7 @@ interface CorpConstants | [marketCyclesPerEmployeeRaise](./bitburner.corpconstants.marketcyclesperemployeeraise.md) | | number | | | [materialNames](./bitburner.corpconstants.materialnames.md) | | [CorpMaterialName](./bitburner.corpmaterialname.md)\[\] | Names of all materials | | [maxProductsBase](./bitburner.corpconstants.maxproductsbase.md) | | number | Max products for a division without upgrades | -| [minEmployeeDecay](./bitburner.corpconstants.minemployeedecay.md) | | number | The minimum decay value for happiness/morale/energy | +| [minEmployeeDecay](./bitburner.corpconstants.minemployeedecay.md) | | number | The minimum decay value for morale/energy | | [officeInitialCost](./bitburner.corpconstants.officeinitialcost.md) | | number | | | [officeInitialSize](./bitburner.corpconstants.officeinitialsize.md) | | number | | | [officeSizeUpgradeCostBase](./bitburner.corpconstants.officesizeupgradecostbase.md) | | number | | @@ -42,6 +41,7 @@ interface CorpConstants | [sellSharesCooldown](./bitburner.corpconstants.sellsharescooldown.md) | | number | Cooldown for selling shares in game cycles (1 game cycle = 200ms) | | [sharesPerPriceUpdate](./bitburner.corpconstants.sharesperpriceupdate.md) | | number | When selling large number of shares, price is dynamically updated for every batch of this amount | | [stateNames](./bitburner.corpconstants.statenames.md) | | [CorpStateName](./bitburner.corpstatename.md)\[\] | Names of all corporation game states | +| [teaCostPerEmployee](./bitburner.corpconstants.teacostperemployee.md) | | number | | | [unlockNames](./bitburner.corpconstants.unlocknames.md) | | [CorpUnlockName](./bitburner.corpunlockname.md)\[\] | Names of all one-time corporation-wide unlocks | | [upgradeNames](./bitburner.corpconstants.upgradenames.md) | | [CorpUpgradeName](./bitburner.corpupgradename.md)\[\] | Names of all corporation-wide upgrades | | [warehouseInitialCost](./bitburner.corpconstants.warehouseinitialcost.md) | | number | | diff --git a/markdown/bitburner.corpconstants.minemployeedecay.md b/markdown/bitburner.corpconstants.minemployeedecay.md index d596c0556..0e5152339 100644 --- a/markdown/bitburner.corpconstants.minemployeedecay.md +++ b/markdown/bitburner.corpconstants.minemployeedecay.md @@ -4,7 +4,7 @@ ## CorpConstants.minEmployeeDecay property -The minimum decay value for happiness/morale/energy +The minimum decay value for morale/energy **Signature:** diff --git a/markdown/bitburner.corpconstants.teacostperemployee.md b/markdown/bitburner.corpconstants.teacostperemployee.md new file mode 100644 index 000000000..7ed69c83c --- /dev/null +++ b/markdown/bitburner.corpconstants.teacostperemployee.md @@ -0,0 +1,11 @@ + + +[Home](./index.md) > [bitburner](./bitburner.md) > [CorpConstants](./bitburner.corpconstants.md) > [teaCostPerEmployee](./bitburner.corpconstants.teacostperemployee.md) + +## CorpConstants.teaCostPerEmployee property + +**Signature:** + +```typescript +teaCostPerEmployee: number; +``` diff --git a/markdown/bitburner.corpemployeeposition.md b/markdown/bitburner.corpemployeeposition.md index 07de11b22..5bd40bb6c 100644 --- a/markdown/bitburner.corpemployeeposition.md +++ b/markdown/bitburner.corpemployeeposition.md @@ -14,6 +14,6 @@ type CorpEmployeePosition = | "Business" | "Management" | "Research & Development" - | "Training" + | "Intern" | "Unassigned"; ``` diff --git a/markdown/bitburner.corpindustryname.md b/markdown/bitburner.corpindustryname.md index 034e68f8e..bdccf95b7 100644 --- a/markdown/bitburner.corpindustryname.md +++ b/markdown/bitburner.corpindustryname.md @@ -9,12 +9,13 @@ ```typescript type CorpIndustryName = - | "Energy" + | "Spring Water" | "Water Utilities" | "Agriculture" | "Fishing" | "Mining" - | "Food" + | "Refinery" + | "Restaurant" | "Tobacco" | "Chemical" | "Pharmaceutical" diff --git a/markdown/bitburner.corpmaterialname.md b/markdown/bitburner.corpmaterialname.md index 678cc8301..0428f6fc4 100644 --- a/markdown/bitburner.corpmaterialname.md +++ b/markdown/bitburner.corpmaterialname.md @@ -9,8 +9,9 @@ ```typescript type CorpMaterialName = + | "Minerals" + | "Ore" | "Water" - | "Energy" | "Food" | "Plants" | "Metal" diff --git a/markdown/bitburner.corporation.buybackshares.md b/markdown/bitburner.corporation.buybackshares.md index 1cd48f59e..0e16a29ca 100644 --- a/markdown/bitburner.corporation.buybackshares.md +++ b/markdown/bitburner.corporation.buybackshares.md @@ -16,7 +16,7 @@ buyBackShares(amount: number): void; | Parameter | Type | Description | | --- | --- | --- | -| amount | number | Amount of shares to buy back. | +| amount | number | Amount of shares to buy back, must be integer and larger than 0 | **Returns:** diff --git a/markdown/bitburner.corporation.sellshares.md b/markdown/bitburner.corporation.sellshares.md index 327af394d..803e0931a 100644 --- a/markdown/bitburner.corporation.sellshares.md +++ b/markdown/bitburner.corporation.sellshares.md @@ -16,7 +16,7 @@ sellShares(amount: number): void; | Parameter | Type | Description | | --- | --- | --- | -| amount | number | Amount of shares to sell. | +| amount | number | Amount of shares to sell, must be integer between 1 and 100t | **Returns:** diff --git a/markdown/bitburner.material.md b/markdown/bitburner.material.md index e59bbc387..427144b6a 100644 --- a/markdown/bitburner.material.md +++ b/markdown/bitburner.material.md @@ -24,6 +24,7 @@ interface Material | [prod](./bitburner.material.prod.md) | | number | Amount of material produced | | [qlt](./bitburner.material.qlt.md) | | number | Quality of the material | | [qty](./bitburner.material.qty.md) | | number | Amount of material | +| [sAmt](./bitburner.material.samt.md) | | string \| number | Sell amount, can be "PROD/2" | | [sCost](./bitburner.material.scost.md) | | string \| number | Sell cost, can be "MP+5" | | [sell](./bitburner.material.sell.md) | | number | Amount of material sold | diff --git a/markdown/bitburner.material.samt.md b/markdown/bitburner.material.samt.md new file mode 100644 index 000000000..c34a1ea15 --- /dev/null +++ b/markdown/bitburner.material.samt.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [bitburner](./bitburner.md) > [Material](./bitburner.material.md) > [sAmt](./bitburner.material.samt.md) + +## Material.sAmt property + +Sell amount, can be "PROD/2" + +**Signature:** + +```typescript +sAmt: string | number; +``` diff --git a/markdown/bitburner.office.avghap.md b/markdown/bitburner.office.avghap.md deleted file mode 100644 index 0131d16d9..000000000 --- a/markdown/bitburner.office.avghap.md +++ /dev/null @@ -1,13 +0,0 @@ - - -[Home](./index.md) > [bitburner](./bitburner.md) > [Office](./bitburner.office.md) > [avgHap](./bitburner.office.avghap.md) - -## Office.avgHap property - -Average happiness of the employees - -**Signature:** - -```typescript -avgHap: number; -``` diff --git a/markdown/bitburner.office.maxhap.md b/markdown/bitburner.office.maxhap.md deleted file mode 100644 index 9e62ed6da..000000000 --- a/markdown/bitburner.office.maxhap.md +++ /dev/null @@ -1,13 +0,0 @@ - - -[Home](./index.md) > [bitburner](./bitburner.md) > [Office](./bitburner.office.md) > [maxHap](./bitburner.office.maxhap.md) - -## Office.maxHap property - -Maximum happiness of the employees - -**Signature:** - -```typescript -maxHap: number; -``` diff --git a/markdown/bitburner.office.md b/markdown/bitburner.office.md index 57c0fcbf2..bbcb4d16e 100644 --- a/markdown/bitburner.office.md +++ b/markdown/bitburner.office.md @@ -17,14 +17,12 @@ export interface Office | Property | Modifiers | Type | Description | | --- | --- | --- | --- | | [avgEne](./bitburner.office.avgene.md) | | number | Average energy of the employees | -| [avgHap](./bitburner.office.avghap.md) | | number | Average happiness of the employees | | [avgMor](./bitburner.office.avgmor.md) | | number | Average morale of the employees | | [employeeJobs](./bitburner.office.employeejobs.md) | | Record<[CorpEmployeePosition](./bitburner.corpemployeeposition.md), number> | Positions of the employees | | [employeeProd](./bitburner.office.employeeprod.md) | | Record<[CorpEmployeePosition](./bitburner.corpemployeeposition.md), number> | Production of the employees | | [employees](./bitburner.office.employees.md) | | number | Amount of employees | | [loc](./bitburner.office.loc.md) | | [CityName](./bitburner.cityname.md) | City of the office | | [maxEne](./bitburner.office.maxene.md) | | number | Maximum amount of energy of the employees | -| [maxHap](./bitburner.office.maxhap.md) | | number | Maximum happiness of the employees | | [maxMor](./bitburner.office.maxmor.md) | | number | Maximum morale of the employees | | [size](./bitburner.office.size.md) | | number | Maximum number of employee | | [totalExperience](./bitburner.office.totalexperience.md) | | number | Total experience of all employees | diff --git a/markdown/bitburner.officeapi.buycoffee.md b/markdown/bitburner.officeapi.buytea.md similarity index 62% rename from markdown/bitburner.officeapi.buycoffee.md rename to markdown/bitburner.officeapi.buytea.md index e5a4b05dc..5abc4ec5a 100644 --- a/markdown/bitburner.officeapi.buycoffee.md +++ b/markdown/bitburner.officeapi.buytea.md @@ -1,15 +1,15 @@ -[Home](./index.md) > [bitburner](./bitburner.md) > [OfficeAPI](./bitburner.officeapi.md) > [buyCoffee](./bitburner.officeapi.buycoffee.md) +[Home](./index.md) > [bitburner](./bitburner.md) > [OfficeAPI](./bitburner.officeapi.md) > [buyTea](./bitburner.officeapi.buytea.md) -## OfficeAPI.buyCoffee() method +## OfficeAPI.buyTea() method -Buy coffee for your employees +Buy tea for your employees **Signature:** ```typescript -buyCoffee(divisionName: string, city: CityName | `${CityName}`): boolean; +buyTea(divisionName: string, city: CityName | `${CityName}`): boolean; ``` ## Parameters @@ -23,5 +23,5 @@ buyCoffee(divisionName: string, city: CityName | `${CityName}`): boolean; boolean -true if buying coffee was successful, false otherwise +true if buying tea was successful, false otherwise diff --git a/markdown/bitburner.officeapi.md b/markdown/bitburner.officeapi.md index fdbfb2f4a..df10976a8 100644 --- a/markdown/bitburner.officeapi.md +++ b/markdown/bitburner.officeapi.md @@ -20,7 +20,7 @@ requires the Office API upgrade from your corporation. | Method | Description | | --- | --- | -| [buyCoffee(divisionName, city)](./bitburner.officeapi.buycoffee.md) | Buy coffee for your employees | +| [buyTea(divisionName, city)](./bitburner.officeapi.buytea.md) | Buy tea for your employees | | [getHireAdVertCost(divisionName)](./bitburner.officeapi.gethireadvertcost.md) | Get the cost to hire AdVert. | | [getHireAdVertCount(divisionName)](./bitburner.officeapi.gethireadvertcount.md) | Get the number of times you have hired AdVert. | | [getOffice(divisionName, city)](./bitburner.officeapi.getoffice.md) | Get data about an office | diff --git a/markdown/bitburner.officeapi.throwparty.md b/markdown/bitburner.officeapi.throwparty.md index 2e8366549..430e7edfe 100644 --- a/markdown/bitburner.officeapi.throwparty.md +++ b/markdown/bitburner.officeapi.throwparty.md @@ -24,5 +24,5 @@ throwParty(divisionName: string, city: CityName | `${CityName}`, costPerEmployee number -Multiplier for happiness and morale, or zero on failure +Multiplier for morale, or zero on failure diff --git a/markdown/bitburner.product.citydata.md b/markdown/bitburner.product.citydata.md deleted file mode 100644 index 9816006fd..000000000 --- a/markdown/bitburner.product.citydata.md +++ /dev/null @@ -1,13 +0,0 @@ - - -[Home](./index.md) > [bitburner](./bitburner.md) > [Product](./bitburner.product.md) > [cityData](./bitburner.product.citydata.md) - -## Product.cityData property - -Data refers to the production, sale, and quantity of the products These values are specific to a city For each city, the data is \[qty, prod, sell\] - -**Signature:** - -```typescript -cityData: Record; -``` diff --git a/markdown/bitburner.product.effrat.md b/markdown/bitburner.product.effrat.md new file mode 100644 index 000000000..8d93ddce2 --- /dev/null +++ b/markdown/bitburner.product.effrat.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [bitburner](./bitburner.md) > [Product](./bitburner.product.md) > [effRat](./bitburner.product.effrat.md) + +## Product.effRat property + +Effective rating + +**Signature:** + +```typescript +effRat: number; +``` diff --git a/markdown/bitburner.product.md b/markdown/bitburner.product.md index 29403c422..ea03553e3 100644 --- a/markdown/bitburner.product.md +++ b/markdown/bitburner.product.md @@ -16,13 +16,17 @@ interface Product | Property | Modifiers | Type | Description | | --- | --- | --- | --- | -| [cityData](./bitburner.product.citydata.md) | | Record<[CityName](./bitburner.cityname.md) \| \`${[CityName](./bitburner.cityname.md)}\`, number\[\]> | Data refers to the production, sale, and quantity of the products These values are specific to a city For each city, the data is \[qty, prod, sell\] | | [cmp](./bitburner.product.cmp.md) | | number \| undefined | Competition for the product, only present if "Market Research - Competition" unlocked | | [developmentProgress](./bitburner.product.developmentprogress.md) | | number | Creation progress - A number between 0-100 representing percentage | | [dmd](./bitburner.product.dmd.md) | | number \| undefined | Demand for the product, only present if "Market Research - Demand" unlocked | +| [effRat](./bitburner.product.effrat.md) | | number | Effective rating | | [name](./bitburner.product.name.md) | | string | Name of the product | | [pCost](./bitburner.product.pcost.md) | | number | Production cost | +| [prod](./bitburner.product.prod.md) | | number | Amount of product produced | | [properties](./bitburner.product.properties.md) | | { \[key: string\]: number } | Product Properties. The data is {qlt, per, dur, rel, aes, fea} | +| [qty](./bitburner.product.qty.md) | | number | Amount of product | | [rat](./bitburner.product.rat.md) | | number | Product Rating | -| [sCost](./bitburner.product.scost.md) | | string \| number | Sell cost, can be "MP+5" | +| [sAmt](./bitburner.product.samt.md) | | string | Sell amount, can be "PROD/2" | +| [sCost](./bitburner.product.scost.md) | | string | Sell cost, can be "MP+5" | +| [sell](./bitburner.product.sell.md) | | number | Amount of product sold | diff --git a/markdown/bitburner.product.prod.md b/markdown/bitburner.product.prod.md new file mode 100644 index 000000000..a389700b8 --- /dev/null +++ b/markdown/bitburner.product.prod.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [bitburner](./bitburner.md) > [Product](./bitburner.product.md) > [prod](./bitburner.product.prod.md) + +## Product.prod property + +Amount of product produced + +**Signature:** + +```typescript +prod: number; +``` diff --git a/markdown/bitburner.product.qty.md b/markdown/bitburner.product.qty.md new file mode 100644 index 000000000..7aa538e9d --- /dev/null +++ b/markdown/bitburner.product.qty.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [bitburner](./bitburner.md) > [Product](./bitburner.product.md) > [qty](./bitburner.product.qty.md) + +## Product.qty property + +Amount of product + +**Signature:** + +```typescript +qty: number; +``` diff --git a/markdown/bitburner.product.samt.md b/markdown/bitburner.product.samt.md new file mode 100644 index 000000000..dd23a4b4f --- /dev/null +++ b/markdown/bitburner.product.samt.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [bitburner](./bitburner.md) > [Product](./bitburner.product.md) > [sAmt](./bitburner.product.samt.md) + +## Product.sAmt property + +Sell amount, can be "PROD/2" + +**Signature:** + +```typescript +sAmt: string; +``` diff --git a/markdown/bitburner.product.scost.md b/markdown/bitburner.product.scost.md index 97825a85f..5e27849cb 100644 --- a/markdown/bitburner.product.scost.md +++ b/markdown/bitburner.product.scost.md @@ -9,5 +9,5 @@ Sell cost, can be "MP+5" **Signature:** ```typescript -sCost: string | number; +sCost: string; ``` diff --git a/markdown/bitburner.product.sell.md b/markdown/bitburner.product.sell.md new file mode 100644 index 000000000..26311ba0e --- /dev/null +++ b/markdown/bitburner.product.sell.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [bitburner](./bitburner.md) > [Product](./bitburner.product.md) > [sell](./bitburner.product.sell.md) + +## Product.sell property + +Amount of product sold + +**Signature:** + +```typescript +sell: number; +``` diff --git a/markdown/bitburner.warehouseapi.getproduct.md b/markdown/bitburner.warehouseapi.getproduct.md index 1c07f887d..2c307c23b 100644 --- a/markdown/bitburner.warehouseapi.getproduct.md +++ b/markdown/bitburner.warehouseapi.getproduct.md @@ -9,7 +9,7 @@ Get product data **Signature:** ```typescript -getProduct(divisionName: string, productName: string): Product; +getProduct(divisionName: string, city: CityName | `${CityName}`, productName: string): Product; ``` ## Parameters @@ -17,6 +17,7 @@ getProduct(divisionName: string, productName: string): Product; | Parameter | Type | Description | | --- | --- | --- | | divisionName | string | Name of the division | +| city | [CityName](./bitburner.cityname.md) \| \`${[CityName](./bitburner.cityname.md)}\` | Name of the city | | productName | string | Name of the product | **Returns:** diff --git a/markdown/bitburner.warehouseapi.md b/markdown/bitburner.warehouseapi.md index 0fa653b03..6e23cb1f7 100644 --- a/markdown/bitburner.warehouseapi.md +++ b/markdown/bitburner.warehouseapi.md @@ -26,7 +26,7 @@ Requires the Warehouse API upgrade from your corporation. | [discontinueProduct(divisionName, productName)](./bitburner.warehouseapi.discontinueproduct.md) | Discontinue a product. | | [exportMaterial(sourceDivision, sourceCity, targetDivision, targetCity, materialName, amt)](./bitburner.warehouseapi.exportmaterial.md) | Set material export data | | [getMaterial(divisionName, city, materialName)](./bitburner.warehouseapi.getmaterial.md) | Get material data | -| [getProduct(divisionName, productName)](./bitburner.warehouseapi.getproduct.md) | Get product data | +| [getProduct(divisionName, city, productName)](./bitburner.warehouseapi.getproduct.md) | Get product data | | [getUpgradeWarehouseCost(divisionName, city, amt)](./bitburner.warehouseapi.getupgradewarehousecost.md) | Gets the cost to upgrade a warehouse to the next level | | [getWarehouse(divisionName, city)](./bitburner.warehouseapi.getwarehouse.md) | Get warehouse data | | [hasWarehouse(divisionName, city)](./bitburner.warehouseapi.haswarehouse.md) | Check if you have a warehouse in city | @@ -38,9 +38,9 @@ Requires the Warehouse API upgrade from your corporation. | [sellProduct(divisionName, city, productName, amt, price, all)](./bitburner.warehouseapi.sellproduct.md) | Set product sell data. | | [setMaterialMarketTA1(divisionName, city, materialName, on)](./bitburner.warehouseapi.setmaterialmarketta1.md) | Set market TA 1 for a material. | | [setMaterialMarketTA2(divisionName, city, materialName, on)](./bitburner.warehouseapi.setmaterialmarketta2.md) | Set market TA 2 for a material. | -| [setProductMarketTA1(divisionName, productName, on)](./bitburner.warehouseapi.setproductmarketta1.md) | Set market TA 1 for a product. | -| [setProductMarketTA2(divisionName, productName, on)](./bitburner.warehouseapi.setproductmarketta2.md) | Set market TA 2 for a product. | +| [setProductMarketTA1(divisionName, city, productName, on)](./bitburner.warehouseapi.setproductmarketta1.md) | Set market TA 1 for a product. | +| [setProductMarketTA2(divisionName, city, productName, on)](./bitburner.warehouseapi.setproductmarketta2.md) | Set market TA 2 for a product. | | [setSmartSupply(divisionName, city, enabled)](./bitburner.warehouseapi.setsmartsupply.md) | Set smart supply | -| [setSmartSupplyUseLeftovers(divisionName, city, materialName, enabled)](./bitburner.warehouseapi.setsmartsupplyuseleftovers.md) | Set whether smart supply uses leftovers before buying | +| [setSmartSupplyOption(divisionName, city, materialName, option)](./bitburner.warehouseapi.setsmartsupplyoption.md) | Set whether smart supply uses leftovers before buying | | [upgradeWarehouse(divisionName, city, amt)](./bitburner.warehouseapi.upgradewarehouse.md) | Upgrade warehouse | diff --git a/markdown/bitburner.warehouseapi.setproductmarketta1.md b/markdown/bitburner.warehouseapi.setproductmarketta1.md index 161f9118a..92cdcec07 100644 --- a/markdown/bitburner.warehouseapi.setproductmarketta1.md +++ b/markdown/bitburner.warehouseapi.setproductmarketta1.md @@ -9,7 +9,7 @@ Set market TA 1 for a product. **Signature:** ```typescript -setProductMarketTA1(divisionName: string, productName: string, on: boolean): void; +setProductMarketTA1(divisionName: string, city: CityName | `${CityName}`, productName: string, on: boolean): void; ``` ## Parameters @@ -17,6 +17,7 @@ setProductMarketTA1(divisionName: string, productName: string, on: boolean): voi | Parameter | Type | Description | | --- | --- | --- | | divisionName | string | Name of the division | +| city | [CityName](./bitburner.cityname.md) \| \`${[CityName](./bitburner.cityname.md)}\` | Name of the city | | productName | string | Name of the product | | on | boolean | market ta enabled | diff --git a/markdown/bitburner.warehouseapi.setproductmarketta2.md b/markdown/bitburner.warehouseapi.setproductmarketta2.md index d2c7c07ea..0d10ee665 100644 --- a/markdown/bitburner.warehouseapi.setproductmarketta2.md +++ b/markdown/bitburner.warehouseapi.setproductmarketta2.md @@ -9,7 +9,7 @@ Set market TA 2 for a product. **Signature:** ```typescript -setProductMarketTA2(divisionName: string, productName: string, on: boolean): void; +setProductMarketTA2(divisionName: string, city: CityName | `${CityName}`, productName: string, on: boolean): void; ``` ## Parameters @@ -17,6 +17,7 @@ setProductMarketTA2(divisionName: string, productName: string, on: boolean): voi | Parameter | Type | Description | | --- | --- | --- | | divisionName | string | Name of the division | +| city | [CityName](./bitburner.cityname.md) \| \`${[CityName](./bitburner.cityname.md)}\` | Name of the city | | productName | string | Name of the product | | on | boolean | market ta enabled | diff --git a/markdown/bitburner.warehouseapi.setsmartsupplyuseleftovers.md b/markdown/bitburner.warehouseapi.setsmartsupplyoption.md similarity index 64% rename from markdown/bitburner.warehouseapi.setsmartsupplyuseleftovers.md rename to markdown/bitburner.warehouseapi.setsmartsupplyoption.md index b4889cc45..5b7a443c9 100644 --- a/markdown/bitburner.warehouseapi.setsmartsupplyuseleftovers.md +++ b/markdown/bitburner.warehouseapi.setsmartsupplyoption.md @@ -1,19 +1,19 @@ -[Home](./index.md) > [bitburner](./bitburner.md) > [WarehouseAPI](./bitburner.warehouseapi.md) > [setSmartSupplyUseLeftovers](./bitburner.warehouseapi.setsmartsupplyuseleftovers.md) +[Home](./index.md) > [bitburner](./bitburner.md) > [WarehouseAPI](./bitburner.warehouseapi.md) > [setSmartSupplyOption](./bitburner.warehouseapi.setsmartsupplyoption.md) -## WarehouseAPI.setSmartSupplyUseLeftovers() method +## WarehouseAPI.setSmartSupplyOption() method Set whether smart supply uses leftovers before buying **Signature:** ```typescript -setSmartSupplyUseLeftovers( +setSmartSupplyOption( divisionName: string, city: CityName | `${CityName}`, materialName: string, - enabled: boolean, + option: string, ): void; ``` @@ -24,7 +24,7 @@ setSmartSupplyUseLeftovers( | divisionName | string | Name of the division | | city | [CityName](./bitburner.cityname.md) \| \`${[CityName](./bitburner.cityname.md)}\` | Name of the city | | materialName | string | Name of the material | -| enabled | boolean | smart supply use leftovers enabled | +| option | string | smart supply option, "leftovers" to use leftovers, "imports" to use only imported materials, "none" to not use materials from store | **Returns:** diff --git a/src/BitNode/BitNode.tsx b/src/BitNode/BitNode.tsx index 2678ddc6f..388175227 100644 --- a/src/BitNode/BitNode.tsx +++ b/src/BitNode/BitNode.tsx @@ -499,6 +499,7 @@ export const defaultMultipliers: IBitNodeMultipliers = { CorporationValuation: 1, CorporationSoftcap: 1, + CorporationDivisions: 1, BladeburnerRank: 1, BladeburnerSkillCost: 1, @@ -538,6 +539,7 @@ export function getBitNodeMultipliers(n: number, lvl: number): IBitNodeMultiplie FactionWorkRepGain: 0.5, CorporationSoftcap: 0.9, + CorporationDivisions: 0.9, InfiltrationMoney: 3, StaneksGiftPowerMultiplier: 2, @@ -623,7 +625,8 @@ export function getBitNodeMultipliers(n: number, lvl: number): IBitNodeMultiplie InfiltrationMoney: 1.5, InfiltrationRep: 1.5, - CorporationValuation: 0.5, + CorporationValuation: 0.75, + CorporationDivisions: 0.75, GangUniqueAugs: 0.5, @@ -654,6 +657,7 @@ export function getBitNodeMultipliers(n: number, lvl: number): IBitNodeMultiplie CorporationValuation: 0.2, CorporationSoftcap: 0.9, + CorporationDivisions: 0.8, GangSoftcap: 0.7, GangUniqueAugs: 0.2, @@ -692,6 +696,7 @@ export function getBitNodeMultipliers(n: number, lvl: number): IBitNodeMultiplie CorporationValuation: 0.2, CorporationSoftcap: 0.9, + CorporationDivisions: 0.8, BladeburnerRank: 0.6, BladeburnerSkillCost: 2, @@ -725,6 +730,7 @@ export function getBitNodeMultipliers(n: number, lvl: number): IBitNodeMultiplie CorporationValuation: 0, CorporationSoftcap: 0, + CorporationDivisions: 0, BladeburnerRank: 0, @@ -760,7 +766,8 @@ export function getBitNodeMultipliers(n: number, lvl: number): IBitNodeMultiplie FourSigmaMarketDataApiCost: 4, CorporationValuation: 0.5, - CorporationSoftcap: 0.7, + CorporationSoftcap: 0.75, + CorporationDivisions: 0.8, BladeburnerRank: 0.9, BladeburnerSkillCost: 1.2, @@ -804,6 +811,7 @@ export function getBitNodeMultipliers(n: number, lvl: number): IBitNodeMultiplie CorporationValuation: 0.5, CorporationSoftcap: 0.9, + CorporationDivisions: 0.9, BladeburnerRank: 0.8, @@ -844,6 +852,7 @@ export function getBitNodeMultipliers(n: number, lvl: number): IBitNodeMultiplie CorporationValuation: 0.1, CorporationSoftcap: 0.9, + CorporationDivisions: 0.9, GangUniqueAugs: 0.75, @@ -907,6 +916,7 @@ export function getBitNodeMultipliers(n: number, lvl: number): IBitNodeMultiplie CorporationValuation: dec, CorporationSoftcap: 0.8, + CorporationDivisions: 0.5, BladeburnerRank: dec, BladeburnerSkillCost: inc, @@ -952,7 +962,8 @@ export function getBitNodeMultipliers(n: number, lvl: number): IBitNodeMultiplie FourSigmaMarketDataApiCost: 10, CorporationValuation: 0.001, - CorporationSoftcap: 0.3, + CorporationSoftcap: 0.4, + CorporationDivisions: 0.4, BladeburnerRank: 0.45, BladeburnerSkillCost: 2, diff --git a/src/BitNode/BitNodeMultipliers.ts b/src/BitNode/BitNodeMultipliers.ts index 3609fe567..3d51bc540 100644 --- a/src/BitNode/BitNodeMultipliers.ts +++ b/src/BitNode/BitNodeMultipliers.ts @@ -154,9 +154,12 @@ export interface IBitNodeMultipliers { /** Influences the hacking skill required to backdoor the world daemon. */ WorldDaemonDifficulty: number; - /** Influences corporation dividends. */ + /** Influences profits from corporation dividends and selling shares. */ CorporationSoftcap: number; + /** Influences number of divisions a corporation can have. */ + CorporationDivisions: number; + // Index signature [key: string]: number; } diff --git a/src/BitNode/ui/BitnodeMultipliersDescription.tsx b/src/BitNode/ui/BitnodeMultipliersDescription.tsx index 00dffbf22..4336ceda3 100644 --- a/src/BitNode/ui/BitnodeMultipliersDescription.tsx +++ b/src/BitNode/ui/BitnodeMultipliersDescription.tsx @@ -343,6 +343,7 @@ function CorporationMults({ mults }: IMultsProps): React.ReactElement { content: mults.CorporationSoftcap.toFixed(3), }, CorporationValuation: { name: "Valuation" }, + CorporationDivisions: { name: "Division limit" }, }; return ; diff --git a/src/Corporation/Actions.ts b/src/Corporation/Actions.ts index db17cd81b..770c62365 100644 --- a/src/Corporation/Actions.ts +++ b/src/Corporation/Actions.ts @@ -17,10 +17,12 @@ import { isRelevantMaterial } from "./ui/Helpers"; import { CityName } from "../Enums"; import { getRandomInt } from "../utils/helpers/getRandomInt"; import { CorpResearchName } from "@nsdefs"; +import { calculateUpgradeCost } from "./helpers"; +import { isInteger } from "lodash"; export function NewIndustry(corporation: Corporation, industry: IndustryType, name: string): void { - if (corporation.divisions.find(({ type }) => industry == type)) - throw new Error(`You have already expanded into the ${industry} industry!`); + if (corporation.divisions.length >= corporation.maxDivisions) + throw new Error(`Cannot expand into ${industry} industry, too many divisions!`); for (let i = 0; i < corporation.divisions.length; ++i) { if (corporation.divisions[i].name === name) { @@ -47,6 +49,13 @@ export function NewIndustry(corporation: Corporation, industry: IndustryType, na } } +export function removeIndustry(corporation: Corporation, name: string) { + const divIndex = corporation.divisions.findIndex((div) => div.name === name); + if (divIndex === -1) throw new Error("There is no division called " + name); + + corporation.divisions.splice(divIndex, 1); +} + export function NewCity(corporation: Corporation, division: Industry, city: CityName): void { if (corporation.funds < corpConstants.officeInitialCost) { throw new Error("You don't have enough company funds to open a new office!"); @@ -71,15 +80,12 @@ export function UnlockUpgrade(corporation: Corporation, upgrade: CorporationUnlo corporation.unlock(upgrade); } -export function LevelUpgrade(corporation: Corporation, upgrade: CorporationUpgrade): void { - const baseCost = upgrade.basePrice; - const priceMult = upgrade.priceMult; - const level = corporation.upgrades[upgrade.index]; - const cost = baseCost * Math.pow(priceMult, level); +export function LevelUpgrade(corporation: Corporation, upgrade: CorporationUpgrade, amount: number): void { + const cost = calculateUpgradeCost(corporation, upgrade, amount); if (corporation.funds < cost) { throw new Error("Insufficient funds"); } else { - corporation.upgrade(upgrade); + corporation.upgrade(upgrade, amount); } } @@ -101,7 +107,7 @@ export function IssueNewShares(corporation: Corporation, amount: number): [numbe throw new Error(`Invalid value. Must be an number between 10m and ${max} (20% of total shares)`); } - const newSharePrice = Math.round(corporation.sharePrice * 0.9); + const newSharePrice = Math.round(corporation.sharePrice * 0.8); const profit = amount * newSharePrice; corporation.issueNewSharesCooldown = corpConstants.issueNewSharesCooldown; @@ -143,21 +149,21 @@ export function SellMaterial(mat: Material, amt: string, price: string): void { //Parse quantity amt = amt.toUpperCase(); - if (amt.includes("MAX") || amt.includes("PROD")) { + if (amt.includes("MAX") || amt.includes("PROD") || amt.includes("INV")) { let q = amt.replace(/\s+/g, ""); - q = q.replace(/[^-()\d/*+.MAXPROD]/g, ""); + q = q.replace(/[^-()\d/*+.MAXPRODINV]/g, ""); let tempQty = q.replace(/MAX/g, mat.maxsll.toString()); tempQty = tempQty.replace(/PROD/g, mat.prd.toString()); + tempQty = tempQty.replace(/INV/g, mat.prd.toString()); try { tempQty = eval(tempQty); } catch (e) { throw new Error("Invalid value or expression for sell quantity field: " + e); } - if (tempQty == null || isNaN(parseFloat(tempQty)) || parseFloat(tempQty) < 0) { + if (tempQty == null || isNaN(parseFloat(tempQty))) { throw new Error("Invalid value or expression for sell quantity field"); } - mat.sllman[0] = true; mat.sllman[1] = q; //Use sanitized input } else if (isNaN(parseFloat(amt)) || parseFloat(amt) < 0) { @@ -194,13 +200,13 @@ export function SellProduct(product: Product, city: string, amt: string, price: if (temp == null || isNaN(parseFloat(temp))) { throw new Error("Invalid value or expression for sell price field."); } - product.sCost = price; //Use sanitized price + product.sCost[city] = price; //Use sanitized price } else { const cost = parseFloat(price); if (isNaN(cost)) { throw new Error("Invalid value for sell price field"); } - product.sCost = cost; + product.sCost[city] = cost; } // Array of all cities. Used later @@ -208,19 +214,20 @@ export function SellProduct(product: Product, city: string, amt: string, price: // Parse quantity amt = amt.toUpperCase(); - if (amt.includes("MAX") || amt.includes("PROD")) { + if (amt.includes("MAX") || amt.includes("PROD") || amt.includes("INV")) { //Dynamically evaluated quantity. First test to make sure its valid let qty = amt.replace(/\s+/g, ""); - qty = qty.replace(/[^-()\d/*+.MAXPROD]/g, ""); + qty = qty.replace(/[^-()\d/*+.MAXPRODINV]/g, ""); let temp = qty.replace(/MAX/g, product.maxsll.toString()); temp = temp.replace(/PROD/g, product.data[city][1].toString()); + temp = temp.replace(/INV/g, product.data[city][0].toString()); try { temp = eval(temp); } catch (e) { throw new Error("Invalid value or expression for sell quantity field: " + e); } - if (temp == null || isNaN(parseFloat(temp)) || parseFloat(temp) < 0) { + if (temp == null || isNaN(parseFloat(temp))) { throw new Error("Invalid value or expression for sell quantity field"); } if (all) { @@ -268,8 +275,11 @@ export function SetSmartSupply(warehouse: Warehouse, smartSupply: boolean): void warehouse.smartSupplyEnabled = smartSupply; } -export function SetSmartSupplyUseLeftovers(warehouse: Warehouse, material: Material, useLeftover: boolean): void { - warehouse.smartSupplyUseLeftovers[material.name] = useLeftover; +export function SetSmartSupplyOption(warehouse: Warehouse, material: Material, useOption: string): void { + if (!corpConstants.smartSupplyUseOptions.includes(useOption)) { + throw new Error(`Invalid Smart Supply option '${useOption}'`); + } + warehouse.smartSupplyOptions[material.name] = useOption; } export function BuyMaterial(material: Material, amt: number): void { @@ -298,9 +308,11 @@ export function BulkPurchase(corp: Corporation, warehouse: Warehouse, material: } export function SellShares(corporation: Corporation, numShares: number): number { - if (isNaN(numShares)) throw new Error("Invalid value for number of shares"); - if (numShares < 0) throw new Error("Invalid value for number of shares"); + if (isNaN(numShares) || !isInteger(numShares)) throw new Error("Invalid value for number of shares"); + if (numShares <= 0) throw new Error("Invalid value for number of shares"); if (numShares > corporation.numShares) throw new Error("You don't have that many shares to sell!"); + if (numShares === corporation.numShares) throw new Error("You cant't sell all your shares!"); + if (numShares > 1e14) throw new Error("Invalid value for number of shares"); if (!corporation.public) throw new Error("You haven't gone public!"); if (corporation.shareSaleCooldown) throw new Error("Share sale on cooldown!"); const stockSaleResults = corporation.calculateShareSale(numShares); @@ -318,8 +330,8 @@ export function SellShares(corporation: Corporation, numShares: number): number } export function BuyBackShares(corporation: Corporation, numShares: number): boolean { - if (isNaN(numShares)) throw new Error("Invalid value for number of shares"); - if (numShares < 0) throw new Error("Invalid value for number of shares"); + if (isNaN(numShares) || !isInteger(numShares)) throw new Error("Invalid value for number of shares"); + if (numShares <= 0) throw new Error("Invalid value for number of shares"); if (numShares > corporation.issuedShares) throw new Error("You don't have that many shares to buy!"); if (!corporation.public) throw new Error("You haven't gone public!"); const buybackPrice = corporation.sharePrice * 1.1; @@ -344,9 +356,9 @@ export function UpgradeOfficeSize(corp: Corporation, office: OfficeSpace, size: corp.funds = corp.funds - cost; } -export function BuyCoffee(corp: Corporation, office: OfficeSpace): boolean { - const cost = office.getCoffeeCost(); - if (corp.funds < cost || !office.setCoffee()) return false; +export function BuyTea(corp: Corporation, office: OfficeSpace): boolean { + const cost = office.getTeaCost(); + if (corp.funds < cost || !office.setTea()) return false; corp.funds -= cost; return true; } @@ -495,8 +507,12 @@ export function ExportMaterial( ): void { // Sanitize amt let sanitizedAmt = amt.replace(/\s+/g, "").toUpperCase(); - sanitizedAmt = sanitizedAmt.replace(/[^-()\d/*+.MAX]/g, ""); + sanitizedAmt = sanitizedAmt.replace(/[^-()\d/*+.MAXEPRODINV]/g, ""); let temp = sanitizedAmt.replace(/MAX/g, "1"); + temp = temp.replace(/IPROD/g, "1"); + temp = temp.replace(/EPROD/g, "1"); + temp = temp.replace(/IINV/g, "1"); + temp = temp.replace(/EINV/g, "1"); try { temp = eval(temp); } catch (e) { @@ -505,7 +521,7 @@ export function ExportMaterial( const n = parseFloat(temp); - if (n == null || isNaN(n) || n < 0) { + if (n == null || isNaN(n)) { throw new Error("Invalid amount entered for export"); } diff --git a/src/Corporation/Corporation.tsx b/src/Corporation/Corporation.tsx index b394d2870..e9229b5ef 100644 --- a/src/Corporation/Corporation.tsx +++ b/src/Corporation/Corporation.tsx @@ -14,9 +14,11 @@ import { Reviver, Generic_toJSON, Generic_fromJSON, IReviverValue } from "../uti import { isString } from "../utils/helpers/isString"; import { CityName } from "../Enums"; import { CorpStateName } from "@nsdefs"; +import { calculateUpgradeCost } from "./helpers"; interface IParams { name?: string; + seedFunded?: boolean; } export class Corporation { @@ -24,6 +26,7 @@ export class Corporation { //A division/business sector is represented by the object: divisions: Industry[] = []; + maxDivisions = 20 * BitNodeMultipliers.CorporationDivisions; //Financial stats funds = 150e9; @@ -50,6 +53,8 @@ export class Corporation { valuationsList = [0]; valuation = 0; + seedFunded: boolean; + state = new CorporationState(); constructor(params: IParams = {}) { @@ -59,6 +64,7 @@ export class Corporation { this.unlockUpgrades = Array(numUnlockUpgrades).fill(0); this.upgrades = Array(numUpgrades).fill(0); this.upgradeMultipliers = Array(numUpgrades).fill(1); + this.seedFunded = params.seedFunded ?? false; } addFunds(amt: number): void { @@ -78,6 +84,8 @@ export class Corporation { } process(): void { + if (this.storedCycles < 0) this.storedCycles = 0; + if (this.storedCycles >= corpConstants.gameCyclesPerCorpStateCycle) { const state = this.getState(); const marketCycles = 1; @@ -305,10 +313,9 @@ export class Corporation { } //Levelable upgrades - upgrade(upgrade: CorporationUpgrade): void { + upgrade(upgrade: CorporationUpgrade, amount: number): void { + if (amount < 1) amount = 1; const upgN = upgrade.index, - basePrice = upgrade.basePrice, - priceMult = upgrade.priceMult, upgradeAmt = upgrade.benefit; //Amount by which the upgrade multiplier gets increased (additive) while (this.upgrades.length <= upgN) { this.upgrades.push(0); @@ -316,12 +323,12 @@ export class Corporation { while (this.upgradeMultipliers.length <= upgN) { this.upgradeMultipliers.push(1); } - const totalCost = basePrice * Math.pow(priceMult, this.upgrades[upgN]); + const totalCost = calculateUpgradeCost(this, upgrade, amount); if (this.funds < totalCost) { dialogBoxCreate("You don't have enough funds to purchase this!"); return; } - ++this.upgrades[upgN]; + this.upgrades[upgN] += amount; this.funds = this.funds - totalCost; //Increase upgrade multiplier diff --git a/src/Corporation/Industry.ts b/src/Corporation/Industry.ts index d6ee84433..ba567221c 100644 --- a/src/Corporation/Industry.ts +++ b/src/Corporation/Industry.ts @@ -321,6 +321,7 @@ export class Industry { buyAmt = Math.min(buyAmt, maxAmt); if (buyAmt > 0) { + mat.qlt = Math.max(0.1, (mat.qlt * mat.qty + 1 * buyAmt) / (mat.qty + buyAmt)); mat.qty += buyAmt; expenses += buyAmt * mat.bCost; } @@ -382,18 +383,25 @@ export class Industry { // Use the materials already in the warehouse if the option is on. for (const matName of Object.keys(smartBuy) as CorpMaterialName[]) { - if (!warehouse.smartSupplyUseLeftovers[matName]) continue; + if (warehouse.smartSupplyOptions[matName] === "none") continue; const mat = warehouse.materials[matName]; const buyAmt = smartBuy[matName]; if (buyAmt === undefined) throw new Error(`Somehow smartbuy matname is undefined`); - smartBuy[matName] = Math.max(0, buyAmt - mat.qty); + if (warehouse.smartSupplyOptions[matName] === "leftovers") { + smartBuy[matName] = Math.max(0, buyAmt - mat.qty); + } else { + smartBuy[matName] = Math.max(0, buyAmt - mat.imp); + } } // buy them for (const [matName, buyAmt] of Object.entries(smartBuy) as [CorpMaterialName, number][]) { const mat = warehouse.materials[matName]; if (buyAmt === undefined) throw new Error(`Somehow smartbuy matname is undefined`); + if (mat.qty + buyAmt != 0) mat.qlt = (mat.qlt * mat.qty + 1 * buyAmt) / (mat.qty + buyAmt); + else mat.qlt = 1; mat.qty += buyAmt; + mat.buy = buyAmt / 10; expenses += buyAmt * mat.bCost; } break; @@ -463,6 +471,8 @@ export class Industry { // Make our materials if they are producable if (producableFrac > 0 && prod > 0) { + let avgQlt = 0; + let divider = 0; for (const reqMatName of Object.keys(this.reqMats) as CorpMaterialName[]) { const reqMat = this.reqMats[reqMatName]; if (reqMat === undefined) continue; @@ -471,13 +481,26 @@ export class Industry { warehouse.materials[reqMatName].prd = 0; warehouse.materials[reqMatName].prd -= reqMatQtyNeeded / (corpConstants.secondsPerMarketCycle * marketCycles); + + avgQlt += warehouse.materials[reqMatName].qlt; + divider++; } + avgQlt /= divider; + avgQlt = Math.max(avgQlt, 1); for (let j = 0; j < this.prodMats.length; ++j) { - warehouse.materials[this.prodMats[j]].qty += prod * producableFrac; - warehouse.materials[this.prodMats[j]].qlt = + let tempQlt = office.employeeProd[EmployeePositions.Engineer] / 90 + Math.pow(this.sciResearch, this.sciFac) + Math.pow(warehouse.materials["AI Cores"].qty, this.aiFac) / 10e3; + const logQlt = Math.max(Math.pow(tempQlt, 0.5), 1); + tempQlt = Math.min(tempQlt, avgQlt * logQlt); + warehouse.materials[this.prodMats[j]].qlt = Math.max( + 1, + (warehouse.materials[this.prodMats[j]].qlt * warehouse.materials[this.prodMats[j]].qty + + tempQlt * prod * producableFrac) / + (warehouse.materials[this.prodMats[j]].qty + prod * producableFrac), + ); + warehouse.materials[this.prodMats[j]].qty += prod * producableFrac; } } else { for (const reqMatName of Object.keys(this.reqMats) as CorpMaterialName[]) { @@ -610,6 +633,28 @@ export class Industry { corporation.getSalesMultiplier() * advertisingFactor * this.getSalesMultiplier(); + if (isString(mat.sllman[1])) { + //Dynamically evaluated + let tmp = (mat.sllman[1] as string).replace(/MAX/g, (mat.maxsll + "").toUpperCase()); + tmp = tmp.replace(/PROD/g, mat.prd + ""); + + try { + sellAmt = eval(tmp); + } catch (e) { + dialogBoxCreate( + `Error evaluating your sell amount for material ${mat.name} in ${this.name}'s ${city} office. The sell amount is being set to zero, sellAmt is set to ${sellAmt}`, + ); + sellAmt = 0; + } + sellAmt = Math.min(mat.maxsll, sellAmt); + sellAmt = Math.max(sellAmt, 0); + } else if (mat.sllman[1] === -1) { + //Backwards compatibility, -1 = MAX + sellAmt = mat.maxsll; + } else { + //Player's input value is just a number + sellAmt = Math.min(mat.maxsll, mat.sllman[1] as number); + } sellAmt = Math.min(mat.maxsll, sellAmt); sellAmt = sellAmt * corpConstants.secondsPerMarketCycle * marketCycles; sellAmt = Math.min(mat.qty, sellAmt); @@ -636,10 +681,27 @@ export class Industry { mat.totalExp = 0; //Reset export for (let expI = 0; expI < mat.exp.length; ++expI) { const exp = mat.exp[expI]; - const amtStr = exp.amt.replace( + + const expIndustry = corporation.divisions.find((div) => div.name === exp.ind); + if (!expIndustry) { + console.error(`Invalid export! ${exp.ind}`); + continue; + } + const expWarehouse = expIndustry.warehouses[exp.city]; + if (!expWarehouse) { + console.error(`Invalid export! ${expIndustry.name} ${exp.city}`); + continue; + } + const tempMaterial = expWarehouse.materials[matName]; + + let amtStr = exp.amt.replace( /MAX/g, (mat.qty / (corpConstants.secondsPerMarketCycle * marketCycles) + "").toUpperCase(), ); + amtStr = amtStr.replace(/EPROD/g, mat.prd.toString()); + amtStr = amtStr.replace(/IPROD/g, tempMaterial.prd.toString()); + amtStr = amtStr.replace(/EINV/g, mat.qty.toString()); + amtStr = amtStr.replace(/IINV/g, tempMaterial.qty.toString()); let amt = 0; try { amt = eval(amtStr); @@ -660,38 +722,33 @@ export class Industry { if (mat.qty < amt) { amt = mat.qty; } - if (amt === 0) { - break; //None left - } - for (let foo = 0; foo < corporation.divisions.length; ++foo) { - if (corporation.divisions[foo].name === exp.ind) { - const expIndustry = corporation.divisions[foo]; - const expWarehouse = expIndustry.warehouses[exp.city]; - if (!expWarehouse) { - console.error(`Invalid export! ${expIndustry.name} ${exp.city}`); - break; - } - // Make sure theres enough space in warehouse - if (expWarehouse.sizeUsed >= expWarehouse.size) { - // Warehouse at capacity. Exporting doesn't - // affect revenue so just return 0's - return [0, 0]; - } else { - const maxAmt = Math.floor( - (expWarehouse.size - expWarehouse.sizeUsed) / MaterialInfo[matName].size, - ); - amt = Math.min(maxAmt, amt); - } - expWarehouse.materials[matName].imp += amt / (corpConstants.secondsPerMarketCycle * marketCycles); - expWarehouse.materials[matName].qty += amt; - expWarehouse.materials[matName].qlt = mat.qlt; - mat.qty -= amt; - mat.totalExp += amt; - expIndustry.updateWarehouseSizeUsed(expWarehouse); - break; - } + // Make sure theres enough space in warehouse + if (expWarehouse.sizeUsed >= expWarehouse.size) { + // Warehouse at capacity. Exporting doesn't + // affect revenue so just return 0's + continue; + } else { + const maxAmt = Math.floor((expWarehouse.size - expWarehouse.sizeUsed) / MaterialInfo[matName].size); + amt = Math.min(maxAmt, amt); } + if (amt <= 0) { + continue; + } + expWarehouse.materials[matName].imp += amt / (corpConstants.secondsPerMarketCycle * marketCycles); + + //Pretty sure this can cause some issues if there are multiple sources importing same material to same warehouse + //but this will do for now + expWarehouse.materials[matName].qlt = Math.max( + 0.1, + (expWarehouse.materials[matName].qlt * expWarehouse.materials[matName].qty + amt * mat.qlt) / + (expWarehouse.materials[matName].qty + amt), + ); + + expWarehouse.materials[matName].qty += amt; + mat.qty -= amt; + mat.totalExp += amt; + expIndustry.updateWarehouseSizeUsed(expWarehouse); } //totalExp should be per second mat.totalExp /= corpConstants.secondsPerMarketCycle * marketCycles; @@ -814,12 +871,20 @@ export class Industry { //Make our Products if they are producable if (producableFrac > 0 && prod > 0) { + let avgQlt = 1; for (const [reqMatName, reqQty] of Object.entries(product.reqMats) as [CorpMaterialName, number][]) { const reqMatQtyNeeded = reqQty * prod * producableFrac; warehouse.materials[reqMatName].qty -= reqMatQtyNeeded; warehouse.materials[reqMatName].prd -= reqMatQtyNeeded / (corpConstants.secondsPerMarketCycle * marketCycles); + avgQlt += warehouse.materials[reqMatName].qlt; } + avgQlt /= Object.keys(product.reqMats).length; + const tempEffRat = Math.min(product.rat, avgQlt * Math.pow(product.rat, 0.5)); + //Effective Rating + product.data[city][3] = + (product.data[city][3] * product.data[city][0] + tempEffRat * prod * producableFrac) / + (product.data[city][0] + prod * producableFrac); //Quantity product.data[city][0] += prod * producableFrac; } @@ -874,7 +939,7 @@ export class Industry { } // Calculate Sale Cost (sCost), which could be dynamically evaluated - const markupLimit = product.rat / product.mku; + const markupLimit = Math.max(product.data[city][3], 0.001) / product.mku; let sCost; if (product.marketTa2) { // Reverse engineer the 'maxSell' formula @@ -885,7 +950,7 @@ export class Industry { const sqrtNumerator = sellAmt; const sqrtDenominator = 0.5 * - Math.pow(product.rat, 0.65) * + Math.pow(product.data[city][3], 0.65) * marketFactor * corporation.getSalesMultiplier() * businessFactor * @@ -909,16 +974,16 @@ export class Industry { sCost = optimalPrice; } else if (product.marketTa1) { sCost = product.pCost + markupLimit; - } else if (isString(product.sCost)) { - const sCostString = product.sCost as string; + } else if (isString(product.sCost[city])) { + const sCostString = product.sCost[city] as string; if (product.mku === 0) { console.error(`mku is zero, reverting to 1 to avoid Infinity`); product.mku = 1; } - sCost = sCostString.replace(/MP/g, product.pCost + product.rat / product.mku + ""); + sCost = sCostString.replace(/MP/g, product.pCost + ""); sCost = Math.max(product.pCost, eval(sCost)); } else { - sCost = product.sCost; + sCost = product.sCost[city]; } let markup = 1; @@ -930,7 +995,7 @@ export class Industry { product.maxsll = 0.5 * - Math.pow(product.rat, 0.65) * + Math.pow(product.data[city][3], 0.65) * marketFactor * corporation.getSalesMultiplier() * Math.pow(markup, 2) * @@ -996,10 +1061,10 @@ export class Industry { applyAdVert(corporation: Corporation): void { const advMult = corporation.getAdvertisingMultiplier() * this.getAdvertisingMultiplier(); - const awareness = (this.awareness + 3 * advMult) * (1.01 * advMult); + const awareness = (this.awareness + 3 * advMult) * (1.005 * advMult); this.awareness = Math.min(awareness, Number.MAX_VALUE); - const popularity = (this.popularity + 1 * advMult) * ((1 + getRandomInt(1, 3) / 100) * advMult); + const popularity = (this.popularity + 1 * advMult) * ((1 + getRandomInt(1, 3) / 200) * advMult); this.popularity = Math.min(popularity, Number.MAX_VALUE); ++this.numAdVerts; @@ -1154,7 +1219,7 @@ export class Industry { const matNameMap = { AICores: "AI Cores", RealEstate: "Real Estate" }; const indNameMap = { RealEstate: IndustryType.RealEstate, - Utilities: IndustryType.Utilities, + Water: IndustryType.Water, Computers: IndustryType.Computers, Computer: IndustryType.Computers, }; diff --git a/src/Corporation/IndustryData.tsx b/src/Corporation/IndustryData.tsx index 00dc03769..3a95dc3ee 100644 --- a/src/Corporation/IndustryData.tsx +++ b/src/Corporation/IndustryData.tsx @@ -17,9 +17,35 @@ export const IndustriesData: Record = { robotFactor: 0.3, aiCoreFactor: 0.3, advertisingFactor: 0.04, - requiredMaterials: { Water: 0.5, Energy: 0.5 }, + requiredMaterials: { Water: 0.5, Chemicals: 0.2 }, producedMaterials: ["Plants", "Food"], }, + [IndustryType.Spring]: { + startingCost: 10e9, + description: "Gather water through passive means.", + recommendStarting: false, + realEstateFactor: 0.2, + scienceFactor: 0.1, + hardwareFactor: 0.0, + robotFactor: 0.0, + aiCoreFactor: 0.1, + advertisingFactor: 0.03, + requiredMaterials: {}, + producedMaterials: ["Plants", "Food"], + }, + [IndustryType.Refinery]: { + startingCost: 50e9, + description: "Refine ore into usable metal.", + recommendStarting: true, + realEstateFactor: 0.3, + scienceFactor: 0.5, + hardwareFactor: 0.5, + robotFactor: 0.4, + aiCoreFactor: 0.3, + advertisingFactor: 0.04, + requiredMaterials: { Ore: 1 }, + producedMaterials: ["Metal"], + }, [IndustryType.Chemical]: { startingCost: 70e9, description: "Produce industrial chemicals.", @@ -30,7 +56,7 @@ export const IndustriesData: Record = { robotFactor: 0.25, aiCoreFactor: 0.2, advertisingFactor: 0.07, - requiredMaterials: { Plants: 1, Energy: 0.5, Water: 0.5 }, + requiredMaterials: { Plants: 1, Water: 0.5 }, producedMaterials: ["Chemicals"], }, [IndustryType.Computers]: { @@ -55,21 +81,9 @@ export const IndustriesData: Record = { robotFactor: 0.36, aiCoreFactor: 0.19, advertisingFactor: 0.17, - requiredMaterials: { Metal: 2, Energy: 1 }, + requiredMaterials: { Metal: 2 }, producedMaterials: ["Hardware"], }, - [IndustryType.Energy]: { - startingCost: 225e9, - description: "Engage in the production and distribution of energy.", - recommendStarting: false, - realEstateFactor: 0.65, - scienceFactor: 0.7, - robotFactor: 0.05, - aiCoreFactor: 0.3, - advertisingFactor: 0.08, - requiredMaterials: { Hardware: 0.1, Metal: 0.2 }, - producedMaterials: ["Energy"], - }, [IndustryType.Fishing]: { startingCost: 80e9, description: "Produce food through the breeding and processing of fish and fish products.", @@ -80,10 +94,10 @@ export const IndustriesData: Record = { robotFactor: 0.5, aiCoreFactor: 0.2, advertisingFactor: 0.08, - requiredMaterials: { Energy: 0.5 }, + requiredMaterials: { Plants: 0.5 }, producedMaterials: ["Food"], }, - [IndustryType.Food]: { + [IndustryType.Restaurant]: { startingCost: 10e9, description: "Create your own restaurants all around the world.", product: { @@ -103,7 +117,7 @@ export const IndustriesData: Record = { aiCoreFactor: 0.25, advertisingFactor: 0.25, realEstateFactor: 0.05, - requiredMaterials: { Food: 0.5, Water: 0.5, Energy: 0.2 }, + requiredMaterials: { Food: 0.5, Water: 0.5 }, }, [IndustryType.Healthcare]: { startingCost: 750e9, @@ -127,7 +141,7 @@ export const IndustriesData: Record = { hardwareFactor: 0.1, robotFactor: 0.1, aiCoreFactor: 0.1, - requiredMaterials: { Robots: 10, "AI Cores": 5, Energy: 5, Water: 5 }, + requiredMaterials: { Robots: 10, "AI Cores": 5, Drugs: 5, Food: 5 }, }, [IndustryType.Mining]: { startingCost: 300e9, @@ -139,8 +153,8 @@ export const IndustriesData: Record = { robotFactor: 0.45, aiCoreFactor: 0.45, advertisingFactor: 0.06, - requiredMaterials: { Energy: 0.8 }, - producedMaterials: ["Metal"], + requiredMaterials: { Hardware: 0.1 }, + producedMaterials: ["Ore", "Minerals"], }, [IndustryType.Pharmaceutical]: { startingCost: 200e9, @@ -164,7 +178,7 @@ export const IndustriesData: Record = { robotFactor: 0.25, aiCoreFactor: 0.2, advertisingFactor: 0.16, - requiredMaterials: { Chemicals: 2, Energy: 1, Water: 0.5 }, + requiredMaterials: { Chemicals: 2, Water: 0.5 }, producedMaterials: ["Drugs"], }, [IndustryType.RealEstate]: { @@ -188,7 +202,7 @@ export const IndustriesData: Record = { advertisingFactor: 0.25, scienceFactor: 0.05, hardwareFactor: 0.05, - requiredMaterials: { Metal: 5, Energy: 5, Water: 2, Hardware: 4 }, + requiredMaterials: { Metal: 5, Plants: 1, Water: 2, Hardware: 4 }, producedMaterials: ["Real Estate"], }, [IndustryType.Robotics]: { @@ -213,7 +227,7 @@ export const IndustriesData: Record = { aiCoreFactor: 0.36, advertisingFactor: 0.18, hardwareFactor: 0.19, - requiredMaterials: { Hardware: 5, Energy: 3 }, + requiredMaterials: { Hardware: 5, "AI Cores": 3 }, producedMaterials: ["Robots"], }, [IndustryType.Software]: { @@ -238,7 +252,7 @@ export const IndustriesData: Record = { realEstateFactor: 0.15, aiCoreFactor: 0.18, robotFactor: 0.05, - requiredMaterials: { Hardware: 0.5, Energy: 0.5 }, + requiredMaterials: { Hardware: 0.5 }, producedMaterials: ["AI Cores"], }, [IndustryType.Tobacco]: { @@ -261,9 +275,9 @@ export const IndustriesData: Record = { robotFactor: 0.2, aiCoreFactor: 0.15, advertisingFactor: 0.2, - requiredMaterials: { Plants: 1, Water: 0.2 }, + requiredMaterials: { Plants: 1 }, }, - [IndustryType.Utilities]: { + [IndustryType.Water]: { startingCost: 150e9, description: "Distribute water and provide wastewater services.", recommendStarting: false, @@ -272,7 +286,7 @@ export const IndustriesData: Record = { robotFactor: 0.4, aiCoreFactor: 0.4, advertisingFactor: 0.08, - requiredMaterials: { Hardware: 0.1, Metal: 0.1 }, + requiredMaterials: { Hardware: 0.1 }, producedMaterials: ["Water"], }, }; diff --git a/src/Corporation/Material.ts b/src/Corporation/Material.ts index 95904b173..636df77c7 100644 --- a/src/Corporation/Material.ts +++ b/src/Corporation/Material.ts @@ -16,7 +16,7 @@ export class Material { qty = 0; // Material's "quality". Unbounded - qlt = 0; + qlt = 1; // How much demand the Material has in the market, and the range of possible // values for this "demand" diff --git a/src/Corporation/MaterialInfo.ts b/src/Corporation/MaterialInfo.ts index b67b802e9..ce9ea8cfc 100644 --- a/src/Corporation/MaterialInfo.ts +++ b/src/Corporation/MaterialInfo.ts @@ -13,14 +13,25 @@ export const MaterialInfo: Record = maxVolatility: 0.2, baseMarkup: 6, }, - Energy: { - name: "Energy", + Ore: { + name: "Ore", size: 0.01, - demandBase: 90, - demandRange: [80, 99], + demandBase: 50, + demandRange: [40, 60], competitionBase: 80, competitionRange: [65, 95], - baseCost: 2000, + baseCost: 500, + maxVolatility: 0.2, + baseMarkup: 6, + }, + Minerals: { + name: "Minerals", + size: 0.04, + demandBase: 75, + demandRange: [90, 60], + competitionBase: 80, + competitionRange: [65, 95], + baseCost: 500, maxVolatility: 0.2, baseMarkup: 6, }, diff --git a/src/Corporation/OfficeSpace.ts b/src/Corporation/OfficeSpace.ts index 74c61cbe2..7b093d2ef 100644 --- a/src/Corporation/OfficeSpace.ts +++ b/src/Corporation/OfficeSpace.ts @@ -16,11 +16,9 @@ export class OfficeSpace { size: number; maxEne = 100; - maxHap = 100; maxMor = 100; avgEne = 75; - avgHap = 75; avgMor = 75; avgInt = 75; @@ -32,9 +30,9 @@ export class OfficeSpace { totalEmployees = 0; totalSalary = 0; - autoCoffee = false; + autoTea = false; autoParty = false; - coffeePending = false; + teaPending = false; partyMult = 1; employeeProd: Record = { @@ -43,7 +41,7 @@ export class OfficeSpace { [EmployeePositions.Business]: 0, [EmployeePositions.Management]: 0, [EmployeePositions.RandD]: 0, - [EmployeePositions.Training]: 0, + [EmployeePositions.Intern]: 0, [EmployeePositions.Unassigned]: 0, total: 0, }; @@ -53,7 +51,7 @@ export class OfficeSpace { [EmployeePositions.Business]: 0, [EmployeePositions.Management]: 0, [EmployeePositions.RandD]: 0, - [EmployeePositions.Training]: 0, + [EmployeePositions.Intern]: 0, [EmployeePositions.Unassigned]: 0, }; employeeNextJobs: Record = { @@ -62,7 +60,7 @@ export class OfficeSpace { [EmployeePositions.Business]: 0, [EmployeePositions.Management]: 0, [EmployeePositions.RandD]: 0, - [EmployeePositions.Training]: 0, + [EmployeePositions.Intern]: 0, [EmployeePositions.Unassigned]: 0, }; @@ -76,10 +74,10 @@ export class OfficeSpace { } process(marketCycles = 1, corporation: Corporation, industry: Industry): number { - // HRBuddy AutoRecruitment and training + // HRBuddy AutoRecruitment and Interning if (industry.hasResearch("HRBuddy-Recruitment") && !this.atCapacity()) { this.hireRandomEmployee( - industry.hasResearch("HRBuddy-Training") ? EmployeePositions.Training : EmployeePositions.Unassigned, + industry.hasResearch("HRBuddy-Training") ? EmployeePositions.Intern : EmployeePositions.Unassigned, ); } @@ -90,62 +88,57 @@ export class OfficeSpace { // Process Office properties this.maxEne = 100; - this.maxHap = 100; this.maxMor = 100; if (industry.hasResearch("Go-Juice")) this.maxEne += 10; - if (industry.hasResearch("JoyWire")) this.maxHap += 10; if (industry.hasResearch("Sti.mu")) this.maxMor += 10; - if (industry.hasResearch("AutoBrew")) this.autoCoffee = true; + if (industry.hasResearch("AutoBrew")) this.autoTea = true; if (industry.hasResearch("AutoPartyManager")) this.autoParty = true; if (this.totalEmployees > 0) { - /** Multiplier for employee morale/happiness/energy based on company performance */ - const perfMult = Math.pow( - 1.002 - - (corporation.funds < 0 ? 0.002 : 0) - - (industry.lastCycleRevenue < industry.lastCycleExpenses ? 0.002 : 0), - marketCycles, - ); + /** Multiplier for employee morale/energy based on company performance */ + let perfMult = 1.002; + if (this.totalEmployees >= 9) { + perfMult = Math.pow( + 1 + + 0.002 * Math.min(1 / 9, this.employeeJobs.Intern / this.totalEmployees - 1 / 9) * 9 - + (corporation.funds < 0 && industry.lastCycleRevenue < industry.lastCycleExpenses ? 0.001 : 0), + marketCycles, + ); + } // Flat reduction per cycle. - // This does not cause a noticable decrease (it's only -.001% per cycle), it only serves - // to make the numbers slightly different between Happiness and Morale. - const reduction = 0.001 * marketCycles; + // This does not cause a noticable decrease (it's only -.001% per cycle). + const reduction = 0.002 * marketCycles; - if (this.autoCoffee) { + if (this.autoTea) { this.avgEne = this.maxEne; } else { - // Coffee gives a flat +3 to energy - this.avgEne = (this.avgEne - reduction) * perfMult + (this.coffeePending ? 3 : 0); - // Coffee also halves the difference between current and max energy - if (this.coffeePending) this.avgEne = this.maxEne - (this.maxEne - this.avgEne) / 2; + // Tea gives a flat +2 to energy + this.avgEne = (this.avgEne - reduction * Math.random()) * perfMult + (this.teaPending ? 2 : 0); } if (this.autoParty) { this.avgMor = this.maxMor; - this.avgHap = this.maxHap; } else { - // Each 5% multiplier gives an extra flat +1 to morale and happiness to make recovering from low morale easier. - const increase = this.partyMult > 1 ? (this.partyMult - 1) * 20 : 0; - this.avgHap = ((this.avgHap - reduction) * perfMult + increase) * this.partyMult; - this.avgMor = (this.avgMor * perfMult + increase) * this.partyMult; + // Each 5% multiplier gives an extra flat +1 to morale to make recovering from low morale easier. + const increase = this.partyMult > 1 ? (this.partyMult - 1) * 10 : 0; + this.avgMor = ((this.avgMor - reduction * Math.random()) * perfMult + increase) * this.partyMult; } this.avgEne = Math.max(Math.min(this.avgEne, this.maxEne), corpConstants.minEmployeeDecay); this.avgMor = Math.max(Math.min(this.avgMor, this.maxMor), corpConstants.minEmployeeDecay); - this.avgHap = Math.max(Math.min(this.avgHap, this.maxHap), corpConstants.minEmployeeDecay); - this.coffeePending = false; + this.teaPending = false; this.partyMult = 1; } - // Get experience increase; unassigned employees do not contribute, employees in training contribute 5x + // Get experience increase; unassigned employees do not contribute, interning employees contribute 10x this.totalExp += 0.0015 * marketCycles * (this.totalEmployees - this.employeeJobs[EmployeePositions.Unassigned] + - this.employeeJobs[EmployeePositions.Training] * 4); + this.employeeJobs[EmployeePositions.Intern] * 9); this.calculateEmployeeProductivity(corporation, industry); if (this.totalEmployees === 0) { @@ -165,7 +158,7 @@ export class OfficeSpace { effCha = this.avgCha * corporation.getEmployeeChaMultiplier() * industry.getEmployeeChaMultiplier(), effInt = this.avgInt * corporation.getEmployeeIntMultiplier() * industry.getEmployeeIntMultiplier(), effEff = this.avgEff * corporation.getEmployeeEffMultiplier() * industry.getEmployeeEffMultiplier(); - const prodBase = this.avgMor * this.avgHap * this.avgEne * 1e-6; + const prodBase = this.avgMor * this.avgEne * 1e-4; let total = 0; const exp = this.totalExp / this.totalEmployees || 0; @@ -188,7 +181,7 @@ export class OfficeSpace { prodMult = 1.5 * effInt + 0.8 * exp + effCre + 0.5 * effEff; break; case EmployeePositions.Unassigned: - case EmployeePositions.Training: + case EmployeePositions.Intern: case "total": continue; default: @@ -213,7 +206,6 @@ export class OfficeSpace { this.totalExp += getRandomInt(50, 100); this.avgMor = (this.avgMor * this.totalEmployees + getRandomInt(50, 100)) / (this.totalEmployees + 1); - this.avgHap = (this.avgHap * this.totalEmployees + getRandomInt(50, 100)) / (this.totalEmployees + 1); this.avgEne = (this.avgEne * this.totalEmployees + getRandomInt(50, 100)) / (this.totalEmployees + 1); this.avgInt = (this.avgInt * this.totalEmployees + getRandomInt(50, 100)) / (this.totalEmployees + 1); @@ -240,13 +232,13 @@ export class OfficeSpace { return false; } - getCoffeeCost(): number { - return corpConstants.coffeeCostPerEmployee * this.totalEmployees; + getTeaCost(): number { + return corpConstants.teaCostPerEmployee * this.totalEmployees; } - setCoffee(): boolean { - if (!this.coffeePending && !this.autoCoffee && this.totalEmployees > 0) { - this.coffeePending = true; + setTea(): boolean { + if (!this.teaPending && !this.autoTea && this.totalEmployees > 0) { + this.teaPending = true; return true; } return false; @@ -267,11 +259,10 @@ export class OfficeSpace { static fromJSON(value: IReviverValue): OfficeSpace { // Convert employees from the old version if (value.data.hasOwnProperty("employees")) { - const empCopy: [{ data: { hap: number; mor: number; ene: number; exp: number } }] = value.data.employees; + const empCopy: [{ data: { mor: number; ene: number; exp: number } }] = value.data.employees; delete value.data.employees; const ret = Generic_fromJSON(OfficeSpace, value.data); ret.totalEmployees = empCopy.length; - ret.avgHap = empCopy.reduce((a, b) => a + b.data.hap, 0) / ret.totalEmployees || 75; ret.avgMor = empCopy.reduce((a, b) => a + b.data.mor, 0) / ret.totalEmployees || 75; ret.avgEne = empCopy.reduce((a, b) => a + b.data.ene, 0) / ret.totalEmployees || 75; ret.totalExp = empCopy.reduce((a, b) => a + b.data.exp, 0); diff --git a/src/Corporation/Product.ts b/src/Corporation/Product.ts index 85de60b76..4cf7a2f36 100644 --- a/src/Corporation/Product.ts +++ b/src/Corporation/Product.ts @@ -47,8 +47,8 @@ export class Product { // Production cost - estimation of how much money it costs to make this Product pCost = 0; - // Sell cost - sCost: string | number = 0; + // Sell costs + sCost: Record = createCityMap(0); // Variables for handling the creation process of this Product fin = false; // Whether this Product has finished being created @@ -82,8 +82,8 @@ export class Product { // Data refers to the production, sale, and quantity of the products // These values are specific to a city - // For each city, the data is [qty, prod, sell] - data: Record = createCityMap([0, 0, 0]); + // For each city, the data is [qty, prod, sell, effRat] + data: Record = createCityMap([0, 0, 0, 0]); // Location of this Product // Only applies for location-based products like restaurants/hospitals @@ -130,7 +130,7 @@ export class Product { } // Make progress on this product based on current employee productivity - createProduct(marketCycles: number, employeeProd: typeof this["creationProd"]): void { + createProduct(marketCycles: number, employeeProd: typeof this.creationProd): void { if (this.fin) { return; } diff --git a/src/Corporation/Warehouse.ts b/src/Corporation/Warehouse.ts index 6ee6d8f25..8b2bc93ff 100644 --- a/src/Corporation/Warehouse.ts +++ b/src/Corporation/Warehouse.ts @@ -34,8 +34,8 @@ export class Warehouse { // Whether Smart Supply is enabled for this Industry (the Industry that this Warehouse is for) smartSupplyEnabled = false; - // Decide if smart supply should use the materials already in the warehouse when deciding on the amount to buy. - smartSupplyUseLeftovers: Record; + // Decide if smart supply should use the amount of materials imported into account when deciding on the amount to buy. + smartSupplyOptions: Record; // Stores the amount of product to be produced. Used for Smart Supply unlock. // The production tracked by smart supply is always based on the previous cycle, @@ -47,10 +47,10 @@ export class Warehouse { this.size = params.size ? params.size : 0; this.materials = {} as Record; - this.smartSupplyUseLeftovers = {} as Record; + this.smartSupplyOptions = {} as Record; for (const matName of materialNames) { this.materials[matName] = new Material({ name: matName }); - this.smartSupplyUseLeftovers[matName] = true; + this.smartSupplyOptions[matName] = "leftovers"; } if (params.corp && params.industry) { diff --git a/src/Corporation/data/BaseResearchTree.ts b/src/Corporation/data/BaseResearchTree.ts index 8eee5d6dc..f839431ee 100644 --- a/src/Corporation/data/BaseResearchTree.ts +++ b/src/Corporation/data/BaseResearchTree.ts @@ -20,7 +20,6 @@ function createBaseResearchTreeNodes(): Node { const autoBrew: Node = makeNode("AutoBrew"); const autoParty: Node = makeNode("AutoPartyManager"); const autoDrugs: Node = makeNode("Automatic Drug Administration"); - const bulkPurchasing: Node = makeNode("Bulk Purchasing"); const cph4: Node = makeNode("CPH4 Injections"); const drones: Node = makeNode("Drones"); const dronesAssembly: Node = makeNode("Drones - Assembly"); @@ -28,7 +27,6 @@ function createBaseResearchTreeNodes(): Node { const goJuice: Node = makeNode("Go-Juice"); const hrRecruitment: Node = makeNode("HRBuddy-Recruitment"); const hrTraining: Node = makeNode("HRBuddy-Training"); - const joywire: Node = makeNode("JoyWire"); const marketta1: Node = makeNode("Market-TA.I"); const marketta2: Node = makeNode("Market-TA.II"); const overclock: Node = makeNode("Overclock"); @@ -50,10 +48,8 @@ function createBaseResearchTreeNodes(): Node { rootNode.addChild(autoBrew); rootNode.addChild(autoParty); rootNode.addChild(autoDrugs); - rootNode.addChild(bulkPurchasing); rootNode.addChild(drones); rootNode.addChild(hrRecruitment); - rootNode.addChild(joywire); rootNode.addChild(marketta1); rootNode.addChild(overclock); rootNode.addChild(scAssemblers); diff --git a/src/Corporation/data/Constants.ts b/src/Corporation/data/Constants.ts index edacf2405..b5823560c 100644 --- a/src/Corporation/data/Constants.ts +++ b/src/Corporation/data/Constants.ts @@ -24,7 +24,8 @@ export const stateNames: CorpStateName[] = ["START", "PURCHASE", "PRODUCTION", " /** Names of all materials */ materialNames: CorpMaterialName[] = [ "Water", - "Energy", + "Ore", + "Minerals", "Food", "Plants", "Metal", @@ -73,7 +74,6 @@ export const stateNames: CorpStateName[] = ["START", "PURCHASE", "PRODUCTION", " "Go-Juice", "HRBuddy-Recruitment", "HRBuddy-Training", - "JoyWire", "Market-TA.I", "Market-TA.II", "Overclock", @@ -96,7 +96,7 @@ export const stateNames: CorpStateName[] = ["START", "PURCHASE", "PRODUCTION", " issueNewSharesCooldown = 216e3, /** Cooldown for selling shares in game cycles. 1 hour. */ sellSharesCooldown = 18e3, - coffeeCostPerEmployee = 500e3, + teaCostPerEmployee = 500e3, gameCyclesPerMarketCycle = 50, gameCyclesPerCorpStateCycle = gameCyclesPerMarketCycle / stateNames.length, secondsPerMarketCycle = (gameCyclesPerMarketCycle * CONSTANTS.MilliPerCycle) / 1000, @@ -117,7 +117,25 @@ export const stateNames: CorpStateName[] = ["START", "PURCHASE", "PRODUCTION", " /** Max products for a division without upgrades */ maxProductsBase = 3, fundingRoundShares = [0.1, 0.35, 0.25, 0.2], - fundingRoundMultiplier = [4, 3, 3, 2.5], - valuationLength = 5, - /** Minimum decay value for employee morale/happiness/energy */ - minEmployeeDecay = 10; + fundingRoundMultiplier = [3, 2, 2, 1.5], + valuationLength = 10, + /** Minimum decay value for employee morale/energy */ + minEmployeeDecay = 10, + /**smart supply ot */ + smartSupplyUseOptions = ["leftovers", "imports", "none"], + PurchaseMultipliers: { + [key: string]: number | "MAX" | undefined; + x1: number; + x5: number; + x10: number; + x50: number; + x100: number; + MAX: "MAX"; + } = { + x1: 1, + x5: 5, + x10: 10, + x50: 50, + x100: 100, + MAX: "MAX", + }; diff --git a/src/Corporation/data/CorporationUpgrades.ts b/src/Corporation/data/CorporationUpgrades.ts index 3e9f86211..15cd5f582 100644 --- a/src/Corporation/data/CorporationUpgrades.ts +++ b/src/Corporation/data/CorporationUpgrades.ts @@ -66,7 +66,7 @@ export const CorporationUpgrades: Record= 1; i /= 2) { + if (calculateUpgradeCost(corporation, upgrade, n + i) < corporation.funds) n += i; + } + + return amount === "MAX" ? n : Math.min(n, amount); +} diff --git a/src/Corporation/ui/ExpandIndustryTab.tsx b/src/Corporation/ui/ExpandIndustryTab.tsx index 41c33e3fe..2e3669c16 100644 --- a/src/Corporation/ui/ExpandIndustryTab.tsx +++ b/src/Corporation/ui/ExpandIndustryTab.tsx @@ -3,7 +3,6 @@ import { dialogBoxCreate } from "../../ui/React/DialogBox"; import { IndustryDescriptions, IndustriesData } from "../IndustryData"; import { IndustryType } from "../data/Enums"; import { useCorporation } from "./Context"; -import { Industry } from "../Industry"; import { NewIndustry } from "../Actions"; import Typography from "@mui/material/Typography"; @@ -21,20 +20,13 @@ interface IProps { export function ExpandIndustryTab(props: IProps): React.ReactElement { const corp = useCorporation(); const allIndustries = Object.values(IndustryType).sort(); - const possibleIndustries = allIndustries.filter( - (industryType: IndustryType) => - corp.divisions.find((division: Industry) => division.type === industryType) === undefined, - ); - const [industry, setIndustry] = useState(possibleIndustries[0]); + const [industry, setIndustry] = useState(allIndustries[0]); const [name, setName] = useState(""); - //If there are no possible industries to expand into, nothing to render in this tab. - if (possibleIndustries.length === 0) return <>; - const data = IndustriesData[industry]; if (!data) return <>; - const disabled = corp.funds < data.startingCost; + const disabled = corp.funds < data.startingCost && corp.divisions.length < corp.maxDivisions; function newIndustry(): void { if (disabled) return; @@ -67,9 +59,12 @@ export function ExpandIndustryTab(props: IProps): React.ReactElement { return ( <> + + {corp.name} has {corp.divisions.length}/{corp.maxDivisions} divisions. + Create a new division to expand into a new industry: {corp.divisions diff --git a/src/Corporation/ui/modals/GoPublicModal.tsx b/src/Corporation/ui/modals/GoPublicModal.tsx index 620fa19ee..2652c073d 100644 --- a/src/Corporation/ui/modals/GoPublicModal.tsx +++ b/src/Corporation/ui/modals/GoPublicModal.tsx @@ -55,11 +55,11 @@ export function GoPublicModal(props: IProps): React.ReactElement { be deposited directly into your Corporation's funds).

- You have a total of {formatShares(corp.numShares)} shares that you can issue. + You have a total of {formatShares(corp.numShares)}-1 shares that you can issue. You cannot sell all your shares. - diff --git a/src/Corporation/ui/modals/MakeProductModal.tsx b/src/Corporation/ui/modals/MakeProductModal.tsx index bc5fec9cf..ae7f21dd2 100644 --- a/src/Corporation/ui/modals/MakeProductModal.tsx +++ b/src/Corporation/ui/modals/MakeProductModal.tsx @@ -20,7 +20,7 @@ interface IProps { } function productPlaceholder(type: string): string { - if (type === IndustryType.Food) { + if (type === IndustryType.Restaurant) { return "Restaurant Name"; } else if (type === IndustryType.Healthcare) { return "Hospital Name"; diff --git a/src/Corporation/ui/modals/MaterialMarketTaModal.tsx b/src/Corporation/ui/modals/MaterialMarketTaModal.tsx index db02f8d52..7335cec5d 100644 --- a/src/Corporation/ui/modals/MaterialMarketTaModal.tsx +++ b/src/Corporation/ui/modals/MaterialMarketTaModal.tsx @@ -1,13 +1,11 @@ import React, { useState } from "react"; -import { formatMoney, formatPreciseMultiplier } from "../../../ui/formatNumber"; +import { formatMoney } from "../../../ui/formatNumber"; import { Material } from "../../Material"; import { Modal } from "../../../ui/React/Modal"; import { useDivision } from "../Context"; import Typography from "@mui/material/Typography"; -import TextField from "@mui/material/TextField"; import FormControlLabel from "@mui/material/FormControlLabel"; import Switch from "@mui/material/Switch"; -import Tooltip from "@mui/material/Tooltip"; import { useRerender } from "../../../ui/React/hooks"; interface IMarketTA2Props { @@ -17,30 +15,7 @@ interface IMarketTA2Props { function MarketTA2(props: IMarketTA2Props): React.ReactElement { const division = useDivision(); if (!division.hasResearch("Market-TA.II")) return <>; - const [newCost, setNewCost] = useState(props.mat.bCost); const rerender = useRerender(); - const markupLimit = props.mat.getMarkupLimit(); - - function onChange(event: React.ChangeEvent): void { - if (event.target.value === "") setNewCost(0); - else setNewCost(parseFloat(event.target.value)); - } - - const sCost = newCost; - let markup = 1; - if (sCost > props.mat.bCost) { - //Penalty if difference between sCost and bCost is greater than markup limit - if (sCost - props.mat.bCost > markupLimit) { - markup = Math.pow(markupLimit / (sCost - props.mat.bCost), 2); - } - } else if (sCost < props.mat.bCost) { - if (sCost <= 0) { - markup = 1e12; //Sell everything, essentially discard - } else { - //Lower prices than market increases sales - markup = props.mat.bCost / sCost; - } - } function onMarketTA2(event: React.ChangeEvent): void { props.mat.marketTa2 = event.target.checked; @@ -50,28 +25,15 @@ function MarketTA2(props: IMarketTA2Props): React.ReactElement { return ( <> Market-TA.II -
- If you sell at {formatMoney(sCost)}, then you will sell x{formatPreciseMultiplier(markup)} as much compared to - if you sold at market price. + If this is enabled, then this Material will automatically be sold at the optimal price such that the amount sold + matches the amount produced. (i.e. the highest possible price, while still ensuring that all produced materials + will be sold) -
} - label={ - - If this is enabled, then this Material will automatically be sold at the optimal price such that the - amount sold matches the amount produced. (i.e. the highest possible price, while still ensuring that all - produced materials will be sold) - - } - > - Use Market-TA.II for Auto-Sale Price - - } + label={Use Market-TA.II for Auto-Sale Price} /> ); @@ -103,22 +65,15 @@ export function MaterialMarketTaModal(props: IProps): React.ReactElement { The maximum sale price you can mark this up to is {formatMoney(props.mat.bCost + markupLimit)}. This means that if you set the sale price higher than this, you will begin to experience a loss in number of sales +

+

+ If this is enabled, then this Material will automatically be sold at the price identified by Market-TA.I (i.e. + the price shown above)
} - label={ - - If this is enabled, then this Material will automatically be sold at the price identified by - Market-TA.I (i.e. the price shown above) - - } - > - Use Market-TA.I for Auto-Sale Price - - } + label={Use Market-TA.I for Auto-Sale Price} /> diff --git a/src/Corporation/ui/modals/ProductMarketTaModal.tsx b/src/Corporation/ui/modals/ProductMarketTaModal.tsx index de0ea2ada..aea7cc542 100644 --- a/src/Corporation/ui/modals/ProductMarketTaModal.tsx +++ b/src/Corporation/ui/modals/ProductMarketTaModal.tsx @@ -1,13 +1,11 @@ import React, { useState } from "react"; -import { formatMoney, formatPreciseMultiplier } from "../../../ui/formatNumber"; +import { formatMoney } from "../../../ui/formatNumber"; import { Product } from "../../Product"; import { Modal } from "../../../ui/React/Modal"; import { useDivision } from "../Context"; import Typography from "@mui/material/Typography"; -import TextField from "@mui/material/TextField"; import FormControlLabel from "@mui/material/FormControlLabel"; import Switch from "@mui/material/Switch"; -import Tooltip from "@mui/material/Tooltip"; import { useRerender } from "../../../ui/React/hooks"; interface ITa2Props { @@ -17,52 +15,26 @@ interface ITa2Props { function MarketTA2(props: ITa2Props): React.ReactElement { const division = useDivision(); if (!division.hasResearch("Market-TA.II")) return <>; - const markupLimit = props.product.rat / props.product.mku; - const [value, setValue] = useState(props.product.pCost); const rerender = useRerender(); - function onChange(event: React.ChangeEvent): void { - setValue(parseFloat(event.target.value)); - } - function onCheckedChange(event: React.ChangeEvent): void { props.product.marketTa2 = event.target.checked; rerender(); } - const sCost = value; - let markup = 1; - if (sCost > props.product.pCost) { - if (sCost - props.product.pCost > markupLimit) { - markup = markupLimit / (sCost - props.product.pCost); - } - } - return ( <> Market-TA.II
- If you sell at {formatMoney(sCost)}, then you will sell x{formatPreciseMultiplier(markup)} as much compared to - if you sold at market price. + If this is enabled, then this product will automatically be sold at the optimal price such that the amount sold + matches the amount produced. (i.e. the highest possible price, while still ensuring that all produced materials + will be sold) -
} - label={ - - If this is enabled, then this Material will automatically be sold at the optimal price such that the - amount sold matches the amount produced. (i.e. the highest possible price, while still ensuring that all - produced materials will be sold) - - } - > - Use Market-TA.II for Auto-Sale Price - - } + label={Use Market-TA.II for Auto-Sale Price} /> ); @@ -94,22 +66,15 @@ export function ProductMarketTaModal(props: IProps): React.ReactElement { The maximum sale price you can mark this up to is {formatMoney(props.product.pCost + markupLimit)}. This means that if you set the sale price higher than this, you will begin to experience a loss in number of sales +

+

+ If this is enabled, then this product will automatically be sold at the price identified by Market-TA.I (i.e. + the price shown above)
} - label={ - - If this is enabled, then this Material will automatically be sold at the price identified by - Market-TA.I (i.e. the price shown above) - - } - > - Use Market-TA.I for Auto-Sale Price - - } + label={Use Market-TA.I for Auto-Sale Price} /> diff --git a/src/Corporation/ui/modals/PurchaseMaterialModal.tsx b/src/Corporation/ui/modals/PurchaseMaterialModal.tsx index 9f6014ede..baada7697 100644 --- a/src/Corporation/ui/modals/PurchaseMaterialModal.tsx +++ b/src/Corporation/ui/modals/PurchaseMaterialModal.tsx @@ -6,7 +6,7 @@ import { Material } from "../../Material"; import { formatMatPurchaseAmount, formatMoney } from "../../../ui/formatNumber"; import { BulkPurchase, BuyMaterial } from "../../Actions"; import { Modal } from "../../../ui/React/Modal"; -import { useCorporation, useDivision } from "../Context"; +import { useCorporation } from "../Context"; import Typography from "@mui/material/Typography"; import TextField from "@mui/material/TextField"; import Button from "@mui/material/Button"; @@ -110,7 +110,6 @@ interface IProps { // Create a popup that lets the player purchase a Material export function PurchaseMaterialModal(props: IProps): React.ReactElement { - const division = useDivision(); const [buyAmt, setBuyAmt] = useState(props.mat.buy ? props.mat.buy : 0); function purchaseMaterial(): void { @@ -160,9 +159,7 @@ export function PurchaseMaterialModal(props: IProps): React.ReactElement { - {division.hasResearch("Bulk Purchasing") && ( - - )} + {} ); diff --git a/src/Corporation/ui/modals/SellCorporationModal.tsx b/src/Corporation/ui/modals/SellCorporationModal.tsx new file mode 100644 index 000000000..5145a42d8 --- /dev/null +++ b/src/Corporation/ui/modals/SellCorporationModal.tsx @@ -0,0 +1,71 @@ +import React, { useState } from "react"; + +import { Money } from "../../../ui/React/Money"; +import { Modal } from "../../../ui/React/Modal"; +import { Router } from "../../../ui/GameRoot"; +import { Page } from "../../../ui/Router"; +import { Player } from "@player"; +import Typography from "@mui/material/Typography"; +import Button from "@mui/material/Button"; +import TextField from "@mui/material/TextField"; + +interface IProps { + open: boolean; + onClose: () => void; +} + +export function SellCorporationModal(props: IProps): React.ReactElement { + let cost = 150e9; + if (!Player.corporation?.seedFunded) { + cost /= 3; + } + const canSelfFund = Player.canAfford(cost); + + const [name, setName] = useState(""); + function onChange(event: React.ChangeEvent): void { + setName(event.target.value); + } + + function selfFund(): void { + if (!canSelfFund) return; + if (name == "") return; + + Player.startCorporation(name, false); + Player.loseMoney(cost, "corporation"); + + props.onClose(); + Router.toPage(Page.Corporation); + } + + function seed(): void { + if (name == "") { + return; + } + + Player.startCorporation(name, true); + + props.onClose(); + Router.toPage(Page.Corporation); + } + + return ( + + + Would you like to sell your position as CEO and start a new corporation? Everything from your current + corporation will be gone and you start fresh. +
+
+ If you would like to start new one, please enter a name for your corporation below: +
+ + {Player.bitNodeN === 3 && ( + + )} + +
+ ); +} diff --git a/src/Corporation/ui/modals/SellDivisionModal.tsx b/src/Corporation/ui/modals/SellDivisionModal.tsx new file mode 100644 index 000000000..22415682d --- /dev/null +++ b/src/Corporation/ui/modals/SellDivisionModal.tsx @@ -0,0 +1,100 @@ +import React, { useState } from "react"; + +import { Modal } from "../../../ui/React/Modal"; +import Typography from "@mui/material/Typography"; +import Button from "@mui/material/Button"; +import MenuItem from "@mui/material/MenuItem"; +import Select, { SelectChangeEvent } from "@mui/material/Select"; +import { useCorporation } from "../../ui/Context"; +import { Industry } from "src/Corporation/Industry"; +import { CityName } from "@nsdefs"; +import * as corpConstants from "../../data/Constants"; +import { formatMoney, formatNumber } from "../../../ui/formatNumber"; +import { removeIndustry } from "../../Actions"; +import { dialogBoxCreate } from "../../../ui/React/DialogBox"; + +interface IProps { + open: boolean; + onClose: () => void; +} + +export function SellDivisionModal(props: IProps): React.ReactElement { + const corp = useCorporation(); + const allIndustries = Object.values(corp.divisions).sort(); + const [industry, setIndustry] = useState(allIndustries[0]); + const price = calculatePrice(); + + function calculatePrice() { + let price = industry.startingCost; + for (const city in industry.offices) { + if (industry.offices[city as CityName] === 0) continue; + if (city === "Sector-12") continue; + price += corpConstants.officeInitialCost; + if (industry.warehouses[city as CityName] !== 0) price += corpConstants.warehouseInitialCost; + } + price /= 2; + return price; + } + + function onIndustryChange(event: SelectChangeEvent): void { + setIndustry(corp.divisions.find((div) => div.name === event.target.value) as Industry); + } + + function sum(total: number, num: number) { + return total + num; + } + + function sellDivision() { + removeIndustry(corp, industry.name); + corp.funds += price; + props.onClose(); + dialogBoxCreate( + <> + Sold {industry.name} for {formatMoney(price)}, you now have space for{" "} + {corp.maxDivisions - corp.divisions.length} more divisions. + , + ); + } + + return ( + + + Would you like to sell a division? +

+ You'll get back half the money you've spent on starting the division and expanding to offices and warehouses. +
+ + + + Division {industry.name} has: +

- Profit: ${formatNumber((industry.lastCycleRevenue - industry.lastCycleExpenses) / 10)} / sec +

- Cities:{" "} + {Object.keys(industry.offices) + .map((city) => (!!industry.offices[city as CityName] ? 1 : 0)) + .reduce(sum, 0)} +

- Warehouses:{" "} + {Object.keys(industry.warehouses) + .map((city) => (!!industry.warehouses[city as CityName] ? 1 : 0)) + .reduce(sum, 0)} + {industry.makesProducts ?? ( + + {" "} +

- Products: {industry.products.length}{" "} +
+ )} +

+

+ Sell price: {formatNumber(price)} +
+ +
+ ); +} diff --git a/src/Corporation/ui/modals/SellProductModal.tsx b/src/Corporation/ui/modals/SellProductModal.tsx index 2c95e7003..4dcd3ccc6 100644 --- a/src/Corporation/ui/modals/SellProductModal.tsx +++ b/src/Corporation/ui/modals/SellProductModal.tsx @@ -11,8 +11,8 @@ import FormControlLabel from "@mui/material/FormControlLabel"; import Switch from "@mui/material/Switch"; import { KEY } from "../../../utils/helpers/keyCodes"; -function initialPrice(product: Product): string { - let val = product.sCost ? product.sCost + "" : ""; +function initialPrice(product: Product, city: string): string { + let val = product.sCost[city] ? product.sCost[city] + "" : ""; if (product.marketTa2) { val += " (Market-TA.II)"; } else if (product.marketTa1) { @@ -34,7 +34,7 @@ export function SellProductModal(props: IProps): React.ReactElement { const [iQty, setQty] = useState( props.product.sllman[props.city][1] ? props.product.sllman[props.city][1] : "", ); - const [px, setPx] = useState(initialPrice(props.product)); + const [px, setPx] = useState(initialPrice(props.product, props.city)); function onCheckedChange(event: React.ChangeEvent): void { setChecked(event.target.checked); diff --git a/src/Corporation/ui/modals/SellSharesModal.tsx b/src/Corporation/ui/modals/SellSharesModal.tsx index f5cacce77..80ad43fb7 100644 --- a/src/Corporation/ui/modals/SellSharesModal.tsx +++ b/src/Corporation/ui/modals/SellSharesModal.tsx @@ -10,6 +10,7 @@ import { Money } from "../../../ui/React/Money"; import { SellShares } from "../../Actions"; import { KEY } from "../../../utils/helpers/keyCodes"; import { NumberInput } from "../../../ui/React/NumberInput"; +import { isInteger } from "lodash"; interface IProps { open: boolean; onClose: () => void; @@ -22,15 +23,19 @@ export function SellSharesModal(props: IProps): React.ReactElement { const corp = useCorporation(); const [shares, setShares] = useState(NaN); - const disabled = isNaN(shares) || shares <= 0 || shares > corp.numShares; + const disabled = isNaN(shares) || shares <= 0 || shares >= corp.numShares; function ProfitIndicator(props: { shares: number | null; corp: Corporation }): React.ReactElement { if (props.shares === null) return <>; let text = ""; - if (isNaN(props.shares) || props.shares <= 0) { + if (isNaN(props.shares) || props.shares <= 0 || !isInteger(props.shares)) { text = `ERROR: Invalid value entered for number of shares to sell`; } else if (props.shares > corp.numShares) { text = `You don't have this many shares to sell!`; + } else if (props.shares === corp.numShares) { + text = `You can not sell all your shares!`; + } else if (props.shares > 1e14) { + text = `You can't sell more than 100t shares at once!`; } else { const stockSaleResults = corp.calculateShareSale(props.shares); const profit = stockSaleResults[0]; @@ -74,6 +79,9 @@ export function SellSharesModal(props: IProps): React.ReactElement { (NOT your Corporation).

+ The amount sold must be an integer between 1 and 100t. +
+
Selling your shares will cause your corporation's stock price to fall due to dilution. Furthermore, selling a large number of shares all at once will have an immediate effect in reducing your stock price.
diff --git a/src/Corporation/ui/modals/SmartSupplyModal.tsx b/src/Corporation/ui/modals/SmartSupplyModal.tsx index 399e70476..b5a12f290 100644 --- a/src/Corporation/ui/modals/SmartSupplyModal.tsx +++ b/src/Corporation/ui/modals/SmartSupplyModal.tsx @@ -1,7 +1,7 @@ import React, { useState } from "react"; import { Warehouse } from "../../Warehouse"; -import { SetSmartSupply, SetSmartSupplyUseLeftovers } from "../../Actions"; +import { SetSmartSupply, SetSmartSupplyOption } from "../../Actions"; import { dialogBoxCreate } from "../../../ui/React/DialogBox"; import { Modal } from "../../../ui/React/Modal"; import { useDivision } from "../Context"; @@ -12,30 +12,50 @@ import { CorpMaterialName } from "@nsdefs"; import { materialNames } from "../../data/Constants"; import { useRerender } from "../../../ui/React/hooks"; -interface ILeftoverProps { +interface ISSoptionProps { matName: CorpMaterialName; warehouse: Warehouse; } -function Leftover(props: ILeftoverProps): React.ReactElement { - const [checked, setChecked] = useState(!!props.warehouse.smartSupplyUseLeftovers[props.matName]); +function SSoption(props: ISSoptionProps): React.ReactElement { + const [value, setChecked] = useState(props.warehouse.smartSupplyOptions[props.matName]); - function onChange(event: React.ChangeEvent): void { + //leftover switch + function onLOChange(): void { + const newValue = value != "leftovers" ? "leftovers" : "none"; try { const matName = props.matName; const material = props.warehouse.materials[matName]; - SetSmartSupplyUseLeftovers(props.warehouse, material, event.target.checked); + SetSmartSupplyOption(props.warehouse, material, newValue); } catch (err) { dialogBoxCreate(err + ""); } - setChecked(event.target.checked); + setChecked(newValue); + } + + //imports switch + function onIChange(): void { + const newValue = value != "imports" ? "imports" : "none"; + try { + const matName = props.matName; + const material = props.warehouse.materials[matName]; + SetSmartSupplyOption(props.warehouse, material, newValue); + } catch (err) { + dialogBoxCreate(err + ""); + } + setChecked(newValue); } return ( <> + label={{props.warehouse.materials[props.matName].name}} } - label={{props.warehouse.materials[props.matName].name}} + control={} + label={{"Use leftovers"}} + /> + } + label={{"Use imported"}} />
@@ -63,18 +83,29 @@ export function SmartSupplyModal(props: IProps): React.ReactElement { for (const matName of Object.values(materialNames)) { if (!props.warehouse.materials[matName]) continue; if (!Object.keys(division.reqMats).includes(matName)) continue; - mats.push(); + mats.push(); } return ( <> + Smart Supply purchases the exact amount of materials needed for maximal production. +
} label={Enable Smart Supply} />
- Use materials already in the warehouse instead of buying new ones, if available: + + Options: +
+ - Use leftovers takes the amount of that material already in storage into account when purchasing new ones. +
+ - Use imported takes the amount of that materials that was imported in previous cycle into account. +
+ if neither is toggled on, Smart Supply will ignore any materials in store and attempts to buy as much as is + needed for production. +
{mats}
diff --git a/src/Corporation/ui/modals/ThrowPartyModal.tsx b/src/Corporation/ui/modals/ThrowPartyModal.tsx index 804794746..8282eedbd 100644 --- a/src/Corporation/ui/modals/ThrowPartyModal.tsx +++ b/src/Corporation/ui/modals/ThrowPartyModal.tsx @@ -38,12 +38,12 @@ export function ThrowPartyModal(props: IProps): React.ReactElement { dialogBoxCreate("You don't have enough company funds to throw a party!"); } else { const mult = ThrowParty(corp, props.office, cost); - // Each 5% multiplier gives an extra flat +1 to morale and happiness to make recovering from low morale easier. + // Each 5% multiplier gives an extra flat +1 to morale to make recovering from low morale easier. const increase = mult > 1 ? (mult - 1) * 0.2 : 0; if (mult > 0) { dialogBoxCreate( - "You threw a party for the office! The morale and happiness of each employee increased by " + + "You threw a party for the office! The morale of each employee increased by " + formatPercent(increase) + " and was multiplied by " + formatMultiplier(mult), diff --git a/src/DevMenu/ui/General.tsx b/src/DevMenu/ui/General.tsx index 79f29448b..5f812852d 100644 --- a/src/DevMenu/ui/General.tsx +++ b/src/DevMenu/ui/General.tsx @@ -37,7 +37,7 @@ export function General(): React.ReactElement { // Corp functions const createCorporation = () => { - Player.startCorporation(corporationName); + Player.startCorporation(corporationName, false); // Rerender so the corp menu option will show up immediately on the devmenu page selection ThemeEvents.emit(); }; diff --git a/src/Literature/Literatures.ts b/src/Literature/Literatures.ts index 17ba5fbac..8ac860218 100644 --- a/src/Literature/Literatures.ts +++ b/src/Literature/Literatures.ts @@ -34,49 +34,54 @@ export const Literatures: Record = {}; fn = LiteratureNames.CorporationManagementHandbook; txt = "Getting Started with Corporations
" + - "To get started, visit the City Hall in Sector-12 in order to create a Corporation. This requires " + - "$150b of your own money, but this $150b will get put into your Corporation's funds. " + - "Your Corporation can have many different divisions, each in a different Industry. There are many different " + - "types of Industries, each with different properties. To create your first division, click the " + - "'Expand into new Industry' button at the top of the management UI. The Agriculture " + - "and Software industries are recommended for your first division.

" + - "The first thing you'll need to do is hire some employees. Employees can be assigned to five different positions. " + - "Each position has a different effect on various aspects of your Corporation. It is recommended to have at least " + - "one employee at each position.

" + - "Each industry uses some combination of Materials in order to produce other Materials and/or create Products. " + - "Specific information about this is displayed in each of your divisions' UI.

" + - "Products are special, industry-specific objects. They are different than Materials because you " + - "must manually choose to develop them, and you can choose to develop any number of Products. Developing " + - "a Product takes time, but a Product typically generates significantly more revenue than any Material. " + - "Not all industries allow you to create Products. To create a Product, look for a button " + - "in the top-left panel of the division UI (e.g. For the Software Industry, the button says 'Develop Software').

" + - "To get your supply chain system started, " + - "purchase the Materials that your industry needs to produce other Materials/Products. This can be done " + - "by clicking the 'Buy' button next to the corresponding Material(s). After you have the required Materials, " + - "you will immediately start production. The amount of Materials/Products you produce is based on a variety of factors, " + - "one of which is your employees and their productivity.

" + - "Once you start producing Materials/Products, you can sell them in order to start earning revenue. This can be done " + - "by clicking the 'Sell' button next to the corresponding Material or Product. The amount of Material/Product you sell is dependent " + - "on a wide variety of different factors.

" + - "These are the basics of getting your Corporation up and running! Now, you can start purchasing upgrades to improve " + - "your bottom line. If you need money, consider looking for seed investors, who will give you money in exchange for stock shares. " + - "Otherwise, once you feel you are ready, take your Corporation public! Once your Corporation goes public, you can no longer " + - "find investors. Instead, your Corporation will be publicly traded and its stock price will change based on how well " + - "it's performing financially. You can then sell your stock shares in order to make money.

" + + "To get started, visit the City Hall in Sector-12 in order to create a Corporation. This requires $150b of your own money, " + + "but this $150b will get put into your Corporation's funds. If you're in BitNode 3 you also have option to get seed money from " + + "the government in exchange for 500m shares. Your Corporation can have many different divisions, each in a different Industry. " + + "There are many different types of Industries, each with different properties. To create your first division, click the 'Expand' " + + "(into new Industry) button at the top of the management UI. The Agriculture industry is recommended for your first division.

" + + "The first thing you'll need to do is hire some employees. Employees can be assigned to five different positions. Each position has a " + + "different effect on various aspects of your Corporation. It is recommended to have at least one employee at each position.

" + + "Each industry uses some combination of Materials in order to produce other Materials and/or create Products. Specific information " + + "about this is displayed in each of your divisions' UI.

" + + "Products are special, industry-specific objects. They are different than Materials because you must manually choose to develop them, " + + "and you can choose to develop any number of Products. Developing a Product takes time, but a Product typically generates significantly " + + "more revenue than any Material. Not all industries allow you to create Products. To create a Product, look for a button in the top-left " + + "panel of the division UI (e.g. For the Software Industry, the button says 'Develop Software').

" + + "To get your supply chain system started, purchase the Materials that your industry needs to produce other Materials/Products. This can be " + + "done by clicking the 'Buy' button next to the corresponding Material(s). After you have the required Materials, you will immediately start " + + "production. The amount and quality/effective rating of Materials/Products you produce is based on a variety of factors, such as your employees " + + "and their productivity and the quality of materials used for production.

" + + "Once you start producing Materials/Products, you can sell them in order to start earning revenue. This can be done by clicking the 'Sell' " + + "button next to the corresponding Material or Product. The amount of Material/Product you sell is dependent on a wide variety of different factors. " + + "In order to produce and sell a Product you'll have to fully develop it first.

" + + "These are the basics of getting your Corporation up and running! Now, you can start purchasing upgrades to improve your bottom line. " + + "If you need money, consider looking for seed investors, who will give you money in exchange for stock shares. Otherwise, once you feel " + + "you are ready, take your Corporation public! Once your Corporation goes public, you can no longer find investors. Instead, your Corporation " + + "will be publicly traded and its stock price will change based on how well it's performing financially. In order to make money for yourself you " + + "can set dividends for a solid reliable income or you can sell your stock shares in order to make quick money.

" + "Tips/Pointers
" + + "-Start with one division, such as Agriculture. Get it profitable on it's own, then expand to a division that consumes/produces " + + "a material that the division you selected produces/consumes.

" + + "-Materials are profitable, but Products are where the real money is, although if the product had a low development budget or is " + + "produced with low quality materials it won't sell well.

" + "-The 'Smart Supply' upgrade is extremely useful. Consider purchasing it as soon as possible.

" + - "-Purchasing Hardware, Robots, AI Cores, and Real Estate can potentially increase your production. " + - "The effects of these depend on what industry you are in.

" + - "-In order to optimize your production, you will need a good balance of Operators, Managers, and Engineers

" + - "-Different employees excel in different jobs. For example, the highly intelligent employees will probably do best " + - "if they are assigned to do Engineering work or Research & Development.

" + - "-If your employees have low morale, energy, or happiness, their production will greatly suffer.

" + - "-Tech is important, but don't neglect sales! Having several Businessmen can boost your sales and your bottom line.

" + + "-Purchasing Hardware, Robots, AI Cores, and Real Estate can potentially increase your production. The effects of these depend on " + + "what industry you are in.

" + + "-In order to optimize your production, you will need a good balance of all employee positions, about 1/9 should be interning

" + + "-Quality of materials used for production affects the quality/effective rating of materials/products produced, so vertical integration " + + "is important for high profits.

" + + "-Materials purchased from the open market are always of quality 1.

" + + "-The price at which you can sell your Materials/Products is highly affected by the quality/effective rating

" + + "-When developing a product, different employee positions affect the development process differently, " + + "some improve the development speed, some improve the rating of the finished product.

" + + "-If your employees have low morale or energy, their production will greatly suffer. Having enough interns will make sure those stats get " + + "high and stay high.

" + "-Don't forget to advertise your company. You won't have any business if nobody knows you.

" + - "-Having company awareness is great, but what's really important is your company's popularity. Try to keep " + - "your popularity as high as possible to see the biggest benefit for your sales

" + + "-Having company awareness is great, but what's really important is your company's popularity. Try to keep your popularity as high as " + + "possible to see the biggest benefit for your sales

" + "-Remember, you need to spend money to make money!

" + "-Corporations do not reset when installing Augmentations, but they do reset when destroying a BitNode"; + Literatures[fn] = new Literature(title, fn, txt); title = "A Brief History of Synthoids"; diff --git a/src/Netscript/RamCostGenerator.ts b/src/Netscript/RamCostGenerator.ts index 6269bf0ad..429f283c5 100644 --- a/src/Netscript/RamCostGenerator.ts +++ b/src/Netscript/RamCostGenerator.ts @@ -373,7 +373,7 @@ const corporation = { sellProduct: RamCostConstants.Corporation, discontinueProduct: RamCostConstants.Corporation, setSmartSupply: RamCostConstants.Corporation, - setSmartSupplyUseLeftovers: RamCostConstants.Corporation, + setSmartSupplyOption: RamCostConstants.Corporation, buyMaterial: RamCostConstants.Corporation, bulkPurchase: RamCostConstants.Corporation, getWarehouse: RamCostConstants.Corporation, @@ -395,7 +395,7 @@ const corporation = { hireEmployee: RamCostConstants.Corporation, upgradeOfficeSize: RamCostConstants.Corporation, throwParty: RamCostConstants.Corporation, - buyCoffee: RamCostConstants.Corporation, + buyTea: RamCostConstants.Corporation, hireAdVert: RamCostConstants.Corporation, research: RamCostConstants.Corporation, getOffice: RamCostConstants.Corporation, diff --git a/src/NetscriptFunctions/Corporation.ts b/src/NetscriptFunctions/Corporation.ts index 1ad20d337..1033d2ee2 100644 --- a/src/NetscriptFunctions/Corporation.ts +++ b/src/NetscriptFunctions/Corporation.ts @@ -32,7 +32,7 @@ import { UpgradeOfficeSize, PurchaseWarehouse, UpgradeWarehouse, - BuyCoffee, + BuyTea, ThrowParty, HireAdVert, MakeProduct, @@ -46,7 +46,7 @@ import { BulkPurchase, SellShares, BuyBackShares, - SetSmartSupplyUseLeftovers, + SetSmartSupplyOption, LimitMaterialProduction, LimitProductProduction, UpgradeWarehouseCost, @@ -76,10 +76,10 @@ export function NetscriptCorporation(): InternalAPI { if (selfFund) { if (!player.canAfford(150e9)) return false; - player.startCorporation(corporationName); + player.startCorporation(corporationName, false); player.loseMoney(150e9, "corporation"); } else { - player.startCorporation(corporationName, 500e6); + player.startCorporation(corporationName, true); } return true; } @@ -243,7 +243,7 @@ export function NetscriptCorporation(): InternalAPI { return material; } - function getProduct(divisionName: string, productName: string): Product { + function getProduct(divisionName: string, cityName: string, productName: string): Product { const division = getDivision(divisionName); const product = division.products[productName]; if (product === undefined) throw new Error(`Invalid product name: '${productName}'`); @@ -331,6 +331,7 @@ export function NetscriptCorporation(): InternalAPI { return { cost: material.bCost, sCost: material.sCost, + sAmt: material.sllman[1], name: material.name, qty: material.qty, qlt: material.qlt, @@ -341,17 +342,19 @@ export function NetscriptCorporation(): InternalAPI { exp: exports, }; }, - getProduct: (ctx) => (_divisionName, _productName) => { + getProduct: (ctx) => (_divisionName, _cityName, _productName) => { checkAccess(ctx, 7); const divisionName = helpers.string(ctx, "divisionName", _divisionName); const productName = helpers.string(ctx, "productName", _productName); - const product = getProduct(divisionName, productName); + const cityName = helpers.city(ctx, "cityName", _cityName); + const product = getProduct(divisionName, cityName, productName); const corporation = getCorporation(); return { name: product.name, dmd: corporation.unlockUpgrades[2] ? product.dmd : undefined, cmp: corporation.unlockUpgrades[3] ? product.cmp : undefined, rat: product.rat, + effRat: product.data[cityName][3], properties: { qlt: product.qlt, per: product.per, @@ -361,8 +364,11 @@ export function NetscriptCorporation(): InternalAPI { fea: product.fea, }, pCost: product.pCost, - sCost: product.sCost, - cityData: product.data, + sCost: product.sCost[cityName], + sAmt: product.sllman[cityName][1], + qty: product.data[cityName][0], + prod: product.data[cityName][1], + sell: product.data[cityName][2], developmentProgress: product.prog, }; }, @@ -406,14 +412,14 @@ export function NetscriptCorporation(): InternalAPI { const amt = helpers.string(ctx, "amt", _amt); const price = helpers.string(ctx, "price", _price); const all = !!_all; - const product = getProduct(divisionName, productName); + const product = getProduct(divisionName, cityName, productName); SellProduct(product, cityName, amt, price, all); }, discontinueProduct: (ctx) => (_divisionName, _productName) => { checkAccess(ctx, 7); const divisionName = helpers.string(ctx, "divisionName", _divisionName); const productName = helpers.string(ctx, "productName", _productName); - getDivision(divisionName).discontinueProduct(getProduct(divisionName, productName)); + getDivision(divisionName).discontinueProduct(getProduct(divisionName, "Sector-12", productName)); }, setSmartSupply: (ctx) => (_divisionName, _cityName, _enabled) => { checkAccess(ctx, 7); @@ -425,17 +431,17 @@ export function NetscriptCorporation(): InternalAPI { throw helpers.makeRuntimeErrorMsg(ctx, `You have not purchased the Smart Supply upgrade!`); SetSmartSupply(warehouse, enabled); }, - setSmartSupplyUseLeftovers: (ctx) => (_divisionName, _cityName, materialName, _enabled) => { + setSmartSupplyOption: (ctx) => (_divisionName, _cityName, materialName, _option) => { checkAccess(ctx, 7); const divisionName = helpers.string(ctx, "divisionName", _divisionName); const cityName = helpers.city(ctx, "cityName", _cityName); assertMember(ctx, corpConstants.materialNames, "Material Name", "materialName", materialName); - const enabled = !!_enabled; const warehouse = getWarehouse(divisionName, cityName); const material = getMaterial(divisionName, cityName, materialName); + const option = helpers.string(ctx, "option", _option); if (!hasUnlockUpgrade("Smart Supply")) throw helpers.makeRuntimeErrorMsg(ctx, `You have not purchased the Smart Supply upgrade!`); - SetSmartSupplyUseLeftovers(warehouse, material, enabled); + SetSmartSupplyOption(warehouse, material, option); }, buyMaterial: (ctx) => (_divisionName, _cityName, materialName, _amt) => { checkAccess(ctx, 7); @@ -451,8 +457,6 @@ export function NetscriptCorporation(): InternalAPI { bulkPurchase: (ctx) => (_divisionName, _cityName, materialName, _amt) => { checkAccess(ctx, 7); const divisionName = helpers.string(ctx, "divisionName", _divisionName); - if (!hasResearched(getDivision(divisionName), "Bulk Purchasing")) - throw new Error(`You have not researched Bulk Purchasing in ${divisionName}`); const corporation = getCorporation(); const cityName = helpers.city(ctx, "cityName", _cityName); assertMember(ctx, corpConstants.materialNames, "Material Name", "materialName", materialName); @@ -479,7 +483,7 @@ export function NetscriptCorporation(): InternalAPI { const cityName = helpers.city(ctx, "cityName", _cityName); const productName = helpers.string(ctx, "productName", _productName); const qty = helpers.number(ctx, "qty", _qty); - LimitProductProduction(getProduct(divisionName, productName), cityName, qty); + LimitProductProduction(getProduct(divisionName, cityName, productName), cityName, qty); }, exportMaterial: (ctx) => @@ -539,23 +543,25 @@ export function NetscriptCorporation(): InternalAPI { throw helpers.makeRuntimeErrorMsg(ctx, `You have not researched MarketTA.II for division: ${divisionName}`); SetMaterialMarketTA2(getMaterial(divisionName, cityName, materialName), on); }, - setProductMarketTA1: (ctx) => (_divisionName, _productName, _on) => { + setProductMarketTA1: (ctx) => (_divisionName, _cityName, _productName, _on) => { checkAccess(ctx, 7); const divisionName = helpers.string(ctx, "divisionName", _divisionName); + const cityName = helpers.city(ctx, "cityName", _cityName); const productName = helpers.string(ctx, "productName", _productName); const on = !!_on; if (!getDivision(divisionName).hasResearch("Market-TA.I")) throw helpers.makeRuntimeErrorMsg(ctx, `You have not researched MarketTA.I for division: ${divisionName}`); - SetProductMarketTA1(getProduct(divisionName, productName), on); + SetProductMarketTA1(getProduct(divisionName, cityName, productName), on); }, - setProductMarketTA2: (ctx) => (_divisionName, _productName, _on) => { + setProductMarketTA2: (ctx) => (_divisionName, _cityName, _productName, _on) => { checkAccess(ctx, 7); const divisionName = helpers.string(ctx, "divisionName", _divisionName); + const cityName = helpers.city(ctx, "cityName", _cityName); const productName = helpers.string(ctx, "productName", _productName); const on = !!_on; if (!getDivision(divisionName).hasResearch("Market-TA.II")) throw helpers.makeRuntimeErrorMsg(ctx, `You have not researched MarketTA.II for division: ${divisionName}`); - SetProductMarketTA2(getProduct(divisionName, productName), on); + SetProductMarketTA2(getProduct(divisionName, cityName, productName), on); }, }; @@ -660,14 +666,14 @@ export function NetscriptCorporation(): InternalAPI { return ThrowParty(corporation, office, costPerEmployee); }, - buyCoffee: (ctx) => (_divisionName, _cityName) => { + buyTea: (ctx) => (_divisionName, _cityName) => { checkAccess(ctx, 8); const divisionName = helpers.string(ctx, "divisionName", _divisionName); const cityName = helpers.city(ctx, "cityName", _cityName); const corporation = getCorporation(); const office = getOffice(divisionName, cityName); - return BuyCoffee(corporation, office); + return BuyTea(corporation, office); }, hireAdVert: (ctx) => (_divisionName) => { checkAccess(ctx, 8); @@ -690,11 +696,9 @@ export function NetscriptCorporation(): InternalAPI { loc: office.loc, size: office.size, maxEne: office.maxEne, - maxHap: office.maxHap, maxMor: office.maxMor, employees: office.totalEmployees, avgEne: office.avgEne, - avgHap: office.avgHap, avgMor: office.avgMor, totalExperience: office.totalExp, employeeProd: Object.assign({}, office.employeeProd), @@ -761,7 +765,7 @@ export function NetscriptCorporation(): InternalAPI { const corporation = getCorporation(); const upgrade = Object.values(CorporationUpgrades).find((upgrade) => upgrade.name === upgradeName); if (upgrade === undefined) throw new Error(`No upgrade named '${upgradeName}'`); - LevelUpgrade(corporation, upgrade); + LevelUpgrade(corporation, upgrade, 1); }, issueDividends: (ctx) => (_rate) => { checkAccess(ctx); diff --git a/src/PersonObjects/Player/PlayerObjectCorporationMethods.ts b/src/PersonObjects/Player/PlayerObjectCorporationMethods.ts index a6a21cb82..2eba7702e 100644 --- a/src/PersonObjects/Player/PlayerObjectCorporationMethods.ts +++ b/src/PersonObjects/Player/PlayerObjectCorporationMethods.ts @@ -4,15 +4,19 @@ import { CorporationUnlockUpgrades, } from "../../Corporation/data/CorporationUnlockUpgrades"; import { PlayerObject } from "./PlayerObject"; +import { resetIndustryResearchTrees } from "../../Corporation/IndustryData"; export function canAccessCorporation(this: PlayerObject): boolean { return this.bitNodeN === 3 || this.sourceFileLvl(3) > 0; } -export function startCorporation(this: PlayerObject, corpName: string, additionalShares = 0): void { +export function startCorporation(this: PlayerObject, corpName: string, seedFunded: boolean): void { this.corporation = new Corporation({ name: corpName, + seedFunded: seedFunded, }); + //reset the research tree in case the corporation was restarted + resetIndustryResearchTrees(); if (this.bitNodeN === 3 || this.sourceFileLvl(3) === 3) { const warehouseApi = CorporationUnlockUpgrades[CorporationUnlockUpgradeIndex.WarehouseAPI].index; @@ -22,5 +26,5 @@ export function startCorporation(this: PlayerObject, corpName: string, additiona this.corporation.unlockUpgrades[OfficeApi] = 1; } - this.corporation.totalShares += additionalShares; + this.corporation.totalShares += seedFunded ? 500_000_000 : 0; } diff --git a/src/Prestige.ts b/src/Prestige.ts index 744c4d401..6f6df39a7 100755 --- a/src/Prestige.ts +++ b/src/Prestige.ts @@ -248,8 +248,11 @@ export function prestigeSourceFile(flume: boolean): void { homeComp.programs.push(Programs.Formulas.name); } + console.log(Player.bitNodeN); + dialogBoxCreate("hello"); // BitNode 3: Corporatocracy if (Player.bitNodeN === 3) { + console.log("why isn't the dialogbox happening?"); homeComp.messages.push(LiteratureNames.CorporationManagementHandbook); dialogBoxCreate( "You received a copy of the Corporation Management Handbook on your home computer. " + diff --git a/src/ScriptEditor/NetscriptDefinitions.d.ts b/src/ScriptEditor/NetscriptDefinitions.d.ts index 2e28c715e..ae0694d7b 100644 --- a/src/ScriptEditor/NetscriptDefinitions.d.ts +++ b/src/ScriptEditor/NetscriptDefinitions.d.ts @@ -6887,17 +6887,18 @@ type CorpEmployeePosition = | "Business" | "Management" | "Research & Development" - | "Training" + | "Intern" | "Unassigned"; /** @public */ type CorpIndustryName = - | "Energy" + | "Spring Water" | "Water Utilities" | "Agriculture" | "Fishing" | "Mining" - | "Food" + | "Refinery" + | "Restaurant" | "Tobacco" | "Chemical" | "Pharmaceutical" @@ -7026,16 +7027,16 @@ export interface OfficeAPI { * @param divisionName - Name of the division * @param city - Name of the city * @param costPerEmployee - Amount to spend per employee. - * @returns Multiplier for happiness and morale, or zero on failure + * @returns Multiplier for morale, or zero on failure */ throwParty(divisionName: string, city: CityName | `${CityName}`, costPerEmployee: number): number; /** - * Buy coffee for your employees + * Buy tea for your employees * @param divisionName - Name of the division * @param city - Name of the city - * @returns true if buying coffee was successful, false otherwise + * @returns true if buying tea was successful, false otherwise */ - buyCoffee(divisionName: string, city: CityName | `${CityName}`): boolean; + buyTea(divisionName: string, city: CityName | `${CityName}`): boolean; /** * Hire AdVert. * @param divisionName - Name of the division @@ -7156,13 +7157,13 @@ export interface WarehouseAPI { * @param divisionName - Name of the division * @param city - Name of the city * @param materialName - Name of the material - * @param enabled - smart supply use leftovers enabled + * @param option - smart supply option, "leftovers" to use leftovers, "imports" to use only imported materials, "none" to not use materials from store */ - setSmartSupplyUseLeftovers( + setSmartSupplyOption( divisionName: string, city: CityName | `${CityName}`, materialName: string, - enabled: boolean, + option: string, ): void; /** * Set material buy data @@ -7190,10 +7191,11 @@ export interface WarehouseAPI { /** * Get product data * @param divisionName - Name of the division + * @param city - Name of the city * @param productName - Name of the product * @returns product data */ - getProduct(divisionName: string, productName: string): Product; + getProduct(divisionName: string, city: CityName | `${CityName}`, productName: string): Product; /** * Get material data * @param divisionName - Name of the division @@ -7221,17 +7223,19 @@ export interface WarehouseAPI { /** * Set market TA 1 for a product. * @param divisionName - Name of the division + * @param city - Name of the city * @param productName - Name of the product * @param on - market ta enabled */ - setProductMarketTA1(divisionName: string, productName: string, on: boolean): void; + setProductMarketTA1(divisionName: string, city: CityName | `${CityName}`, productName: string, on: boolean): void; /** * Set market TA 2 for a product. * @param divisionName - Name of the division + * @param city - Name of the city * @param productName - Name of the product * @param on - market ta enabled */ - setProductMarketTA2(divisionName: string, productName: string, on: boolean): void; + setProductMarketTA2(divisionName: string, city: CityName | `${CityName}`, productName: string, on: boolean): void; /** * Set material export data * @param sourceDivision - Source division @@ -7433,11 +7437,11 @@ export interface Corporation extends WarehouseAPI, OfficeAPI { issueNewShares(amount?: number): number; /** Buyback Shares - * @param amount - Amount of shares to buy back. */ + * @param amount - Amount of shares to buy back, must be integer and larger than 0 */ buyBackShares(amount: number): void; /** Sell Shares - * @param amount - Amount of shares to sell. */ + * @param amount - Amount of shares to sell, must be integer between 1 and 100t */ sellShares(amount: number): void; /** Get bonus time. @@ -7555,7 +7559,7 @@ interface CorpConstants { issueNewSharesCooldown: number; /** Cooldown for selling shares in game cycles (1 game cycle = 200ms) */ sellSharesCooldown: number; - coffeeCostPerEmployee: number; + teaCostPerEmployee: number; gameCyclesPerMarketCycle: number; gameCyclesPerCorpStateCycle: number; secondsPerMarketCycle: number; @@ -7575,7 +7579,7 @@ interface CorpConstants { employeeRaiseAmount: number; /** Max products for a division without upgrades */ maxProductsBase: number; - /** The minimum decay value for happiness/morale/energy */ + /** The minimum decay value for morale/energy */ minEmployeeDecay: number; } /** @public */ @@ -7583,8 +7587,9 @@ type CorpStateName = "START" | "PURCHASE" | "PRODUCTION" | "EXPORT" | "SALE"; /** @public */ type CorpMaterialName = + | "Minerals" + | "Ore" | "Water" - | "Energy" | "Food" | "Plants" | "Metal" @@ -7699,16 +7704,22 @@ interface Product { cmp: number | undefined; /** Product Rating */ rat: number; + /** Effective rating */ + effRat: number; /** Product Properties. The data is \{qlt, per, dur, rel, aes, fea\} */ properties: { [key: string]: number }; /** Production cost */ pCost: number; /** Sell cost, can be "MP+5" */ - sCost: string | number; - /** Data refers to the production, sale, and quantity of the products - * These values are specific to a city - * For each city, the data is [qty, prod, sell] */ - cityData: Record; + sCost: string; + /** Sell amount, can be "PROD/2" */ + sAmt: string; + /** Amount of product */ + qty: number; + /** Amount of product produced */ + prod: number; + /** Amount of product sold */ + sell: number; /** Creation progress - A number between 0-100 representing percentage */ developmentProgress: number; } @@ -7736,6 +7747,8 @@ interface Material { cost: number; /** Sell cost, can be "MP+5" */ sCost: string | number; + /** Sell amount, can be "PROD/2" */ + sAmt: string | number; /** Export orders */ exp: Export[]; } @@ -7781,16 +7794,12 @@ export interface Office { size: number; /** Maximum amount of energy of the employees */ maxEne: number; - /** Maximum happiness of the employees */ - maxHap: number; /** Maximum morale of the employees */ maxMor: number; /** Amount of employees */ employees: number; /** Average energy of the employees */ avgEne: number; - /** Average happiness of the employees */ - avgHap: number; /** Average morale of the employees */ avgMor: number; /** Total experience of all employees */