mirror of
https://github.com/bitburner-official/bitburner-src.git
synced 2026-04-16 14:28:36 +02:00
Compare commits
53 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5c738919fc | ||
|
|
223d9b9cdb | ||
|
|
6a63f8a02c | ||
|
|
ad6f919d64 | ||
|
|
c5e2f65cb0 | ||
|
|
7fad6e0778 | ||
|
|
6d3495d05f | ||
|
|
875bddbbdb | ||
|
|
648c180952 | ||
|
|
3ae3f947ac | ||
|
|
f6e1c171ae | ||
|
|
1b81fe8766 | ||
|
|
e1d2e12747 | ||
|
|
b9d13063ac | ||
|
|
47176b7809 | ||
|
|
d914040ae7 | ||
|
|
cb93f4d108 | ||
|
|
fe0f8cad4d | ||
|
|
b6eafce563 | ||
|
|
99e5c5e6b0 | ||
|
|
bf5e638891 | ||
|
|
d2b3659512 | ||
|
|
a6ff0d3e14 | ||
|
|
c4482a70f9 | ||
|
|
3c42880185 | ||
|
|
7b2e8e5312 | ||
|
|
b844593e22 | ||
|
|
624a0a5b02 | ||
|
|
bba2ccd83a | ||
|
|
25dae7ec8b | ||
|
|
f95ca64e01 | ||
|
|
0ed88a4317 | ||
|
|
8d3f2bd750 | ||
|
|
bec737a253 | ||
|
|
66ac31ee99 | ||
|
|
52769706d2 | ||
|
|
ae87851889 | ||
|
|
7c82221a13 | ||
|
|
b7fdcdf35d | ||
|
|
ad9bde40e0 | ||
|
|
8c86e1e07a | ||
|
|
1ea555f572 | ||
|
|
bc7482b0a2 | ||
|
|
12de5505b5 | ||
|
|
62058a7f78 | ||
|
|
9a0d688909 | ||
|
|
b4f33fe655 | ||
|
|
4b627cde1e | ||
|
|
101fb21c58 | ||
|
|
79b677973b | ||
|
|
93235570d0 | ||
|
|
51b03003f6 | ||
|
|
281e22c90c |
@@ -35,4 +35,9 @@ module.exports = {
|
||||
"@typescript-eslint/no-explicit-any": "off",
|
||||
"react/no-unescaped-entities": "off",
|
||||
},
|
||||
settings: {
|
||||
react: {
|
||||
version: "detect",
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
4
electron/package-lock.json
generated
4
electron/package-lock.json
generated
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "bitburner",
|
||||
"version": "2.3.2dev",
|
||||
"version": "2.5.0",
|
||||
"lockfileVersion": 2,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "bitburner",
|
||||
"version": "2.3.2dev",
|
||||
"version": "2.5.0",
|
||||
"dependencies": {
|
||||
"electron-config": "^2.0.0",
|
||||
"electron-log": "^4.4.8",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "bitburner",
|
||||
"version": "2.4.1",
|
||||
"version": "2.5.0",
|
||||
"description": "A cyberpunk-themed programming incremental game",
|
||||
"main": "main.js",
|
||||
"author": "Daniel Xie, Olivier Gagnon, et al.",
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
|
||||
|
||||
[Home](./index.md) > [bitburner](./bitburner.md) > [BitNodeMultipliers](./bitburner.bitnodemultipliers.md) > [CorporationDivisions](./bitburner.bitnodemultipliers.corporationdivisions.md)
|
||||
|
||||
## BitNodeMultipliers.CorporationDivisions property
|
||||
|
||||
Influences the amount of divisions a corporation can have have at the same time
|
||||
|
||||
**Signature:**
|
||||
|
||||
```typescript
|
||||
CorporationDivisions: number;
|
||||
```
|
||||
@@ -26,6 +26,7 @@ interface BitNodeMultipliers
|
||||
| [CodingContractMoney](./bitburner.bitnodemultipliers.codingcontractmoney.md) | | number | Influences the amount of money gained from completing Coding Contracts |
|
||||
| [CompanyWorkExpGain](./bitburner.bitnodemultipliers.companyworkexpgain.md) | | number | Influences the experience gained for each ability when the player completes working their job. |
|
||||
| [CompanyWorkMoney](./bitburner.bitnodemultipliers.companyworkmoney.md) | | number | Influences how much money the player earns when completing working their job. |
|
||||
| [CorporationDivisions](./bitburner.bitnodemultipliers.corporationdivisions.md) | | number | Influences the amount of divisions a corporation can have have at the same time |
|
||||
| [CorporationSoftcap](./bitburner.bitnodemultipliers.corporationsoftcap.md) | | number | Influences the money gain from dividends of corporations created by the player. |
|
||||
| [CorporationValuation](./bitburner.bitnodemultipliers.corporationvaluation.md) | | number | Influences the valuation of corporations created by the player. |
|
||||
| [CrimeExpGain](./bitburner.bitnodemultipliers.crimeexpgain.md) | | number | Influences the base experience gained for each ability when the player commits a crime. |
|
||||
|
||||
@@ -18,7 +18,7 @@ getActionRepGain(type: string, name: string, level: number): number;
|
||||
| --- | --- | --- |
|
||||
| type | string | Type of action. |
|
||||
| name | string | Name of action. Must be an exact match. |
|
||||
| level | number | Optional action level at which to calculate the gain |
|
||||
| level | number | Optional number. Action level at which to calculate the gain. Will be the action's current level if not given. |
|
||||
|
||||
**Returns:**
|
||||
|
||||
|
||||
13
markdown/bitburner.corpindustrydata.makesmaterials.md
Normal file
13
markdown/bitburner.corpindustrydata.makesmaterials.md
Normal file
@@ -0,0 +1,13 @@
|
||||
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
|
||||
|
||||
[Home](./index.md) > [bitburner](./bitburner.md) > [CorpIndustryData](./bitburner.corpindustrydata.md) > [makesMaterials](./bitburner.corpindustrydata.makesmaterials.md)
|
||||
|
||||
## CorpIndustryData.makesMaterials property
|
||||
|
||||
Whether the industry of this division is capable of producing materials
|
||||
|
||||
**Signature:**
|
||||
|
||||
```typescript
|
||||
makesMaterials: boolean;
|
||||
```
|
||||
13
markdown/bitburner.corpindustrydata.makesproducts.md
Normal file
13
markdown/bitburner.corpindustrydata.makesproducts.md
Normal file
@@ -0,0 +1,13 @@
|
||||
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
|
||||
|
||||
[Home](./index.md) > [bitburner](./bitburner.md) > [CorpIndustryData](./bitburner.corpindustrydata.md) > [makesProducts](./bitburner.corpindustrydata.makesproducts.md)
|
||||
|
||||
## CorpIndustryData.makesProducts property
|
||||
|
||||
Whether the industry of this division is capable of developing and producing products
|
||||
|
||||
**Signature:**
|
||||
|
||||
```typescript
|
||||
makesProducts: boolean;
|
||||
```
|
||||
@@ -20,7 +20,9 @@ interface CorpIndustryData
|
||||
| [aiCoreFactor?](./bitburner.corpindustrydata.aicorefactor.md) | | number | _(Optional)_ AI Cores factor |
|
||||
| [description](./bitburner.corpindustrydata.description.md) | | string | |
|
||||
| [hardwareFactor?](./bitburner.corpindustrydata.hardwarefactor.md) | | number | _(Optional)_ Hardware factor |
|
||||
| [producedMaterials?](./bitburner.corpindustrydata.producedmaterials.md) | | [CorpMaterialName](./bitburner.corpmaterialname.md)<!-- -->\[\] | _(Optional)_ |
|
||||
| [makesMaterials](./bitburner.corpindustrydata.makesmaterials.md) | | boolean | Whether the industry of this division is capable of producing materials |
|
||||
| [makesProducts](./bitburner.corpindustrydata.makesproducts.md) | | boolean | Whether the industry of this division is capable of developing and producing products |
|
||||
| [producedMaterials?](./bitburner.corpindustrydata.producedmaterials.md) | | [CorpMaterialName](./bitburner.corpmaterialname.md)<!-- -->\[\] | _(Optional)_ Array of Materials produced |
|
||||
| [product?](./bitburner.corpindustrydata.product.md) | | [CorpProductData](./bitburner.corpproductdata.md) | _(Optional)_ |
|
||||
| [realEstateFactor?](./bitburner.corpindustrydata.realestatefactor.md) | | number | _(Optional)_ Real estate factor |
|
||||
| [recommendStarting](./bitburner.corpindustrydata.recommendstarting.md) | | boolean | |
|
||||
|
||||
@@ -4,6 +4,8 @@
|
||||
|
||||
## CorpIndustryData.producedMaterials property
|
||||
|
||||
Array of Materials produced
|
||||
|
||||
**Signature:**
|
||||
|
||||
```typescript
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
## Corporation.buyBackShares() method
|
||||
|
||||
Buyback Shares
|
||||
Buyback Shares. Spend money from the player's wallet to transfer shares from public traders to the CEO.
|
||||
|
||||
**Signature:**
|
||||
|
||||
|
||||
@@ -19,7 +19,7 @@ export interface Corporation extends WarehouseAPI, OfficeAPI
|
||||
| --- | --- |
|
||||
| [acceptInvestmentOffer()](./bitburner.corporation.acceptinvestmentoffer.md) | Accept investment based on you companies current valuation |
|
||||
| [bribe(factionName, amountCash)](./bitburner.corporation.bribe.md) | Bribe a faction |
|
||||
| [buyBackShares(amount)](./bitburner.corporation.buybackshares.md) | Buyback Shares |
|
||||
| [buyBackShares(amount)](./bitburner.corporation.buybackshares.md) | Buyback Shares. Spend money from the player's wallet to transfer shares from public traders to the CEO. |
|
||||
| [createCorporation(corporationName, selfFund)](./bitburner.corporation.createcorporation.md) | Create a Corporation |
|
||||
| [expandCity(divisionName, city)](./bitburner.corporation.expandcity.md) | Expand to a new city |
|
||||
| [expandIndustry(industryType, divisionName)](./bitburner.corporation.expandindustry.md) | Expand to a new industry |
|
||||
@@ -40,5 +40,5 @@ export interface Corporation extends WarehouseAPI, OfficeAPI
|
||||
| [issueNewShares(amount)](./bitburner.corporation.issuenewshares.md) | Issue new shares |
|
||||
| [levelUpgrade(upgradeName)](./bitburner.corporation.levelupgrade.md) | Level an upgrade. |
|
||||
| [purchaseUnlock(upgradeName)](./bitburner.corporation.purchaseunlock.md) | Unlock an upgrade |
|
||||
| [sellShares(amount)](./bitburner.corporation.sellshares.md) | Sell Shares |
|
||||
| [sellShares(amount)](./bitburner.corporation.sellshares.md) | Sell Shares. Transfer shares from the CEO to public traders to receive money in the player's wallet. |
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
## Corporation.sellShares() method
|
||||
|
||||
Sell Shares
|
||||
Sell Shares. Transfer shares from the CEO to public traders to receive money in the player's wallet.
|
||||
|
||||
**Signature:**
|
||||
|
||||
|
||||
13
markdown/bitburner.corporationinfo.investorshares.md
Normal file
13
markdown/bitburner.corporationinfo.investorshares.md
Normal file
@@ -0,0 +1,13 @@
|
||||
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
|
||||
|
||||
[Home](./index.md) > [bitburner](./bitburner.md) > [CorporationInfo](./bitburner.corporationinfo.md) > [investorShares](./bitburner.corporationinfo.investorshares.md)
|
||||
|
||||
## CorporationInfo.investorShares property
|
||||
|
||||
Amount of shares owned by private investors. Not available for public sale or CEO buyback.
|
||||
|
||||
**Signature:**
|
||||
|
||||
```typescript
|
||||
investorShares: number;
|
||||
```
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
## CorporationInfo.issuedShares property
|
||||
|
||||
Amount of acquirable shares.
|
||||
Amount of shares owned by public traders. Available for CEO buyback.
|
||||
|
||||
**Signature:**
|
||||
|
||||
|
||||
13
markdown/bitburner.corporationinfo.issuenewsharescooldown.md
Normal file
13
markdown/bitburner.corporationinfo.issuenewsharescooldown.md
Normal file
@@ -0,0 +1,13 @@
|
||||
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
|
||||
|
||||
[Home](./index.md) > [bitburner](./bitburner.md) > [CorporationInfo](./bitburner.corporationinfo.md) > [issueNewSharesCooldown](./bitburner.corporationinfo.issuenewsharescooldown.md)
|
||||
|
||||
## CorporationInfo.issueNewSharesCooldown property
|
||||
|
||||
Cooldown until new shares can be issued
|
||||
|
||||
**Signature:**
|
||||
|
||||
```typescript
|
||||
issueNewSharesCooldown: number;
|
||||
```
|
||||
@@ -22,13 +22,15 @@ interface CorporationInfo
|
||||
| [divisions](./bitburner.corporationinfo.divisions.md) | | string\[\] | Array of all division names |
|
||||
| [expenses](./bitburner.corporationinfo.expenses.md) | | number | Expenses per second this cycle |
|
||||
| [funds](./bitburner.corporationinfo.funds.md) | | number | Funds available |
|
||||
| [issuedShares](./bitburner.corporationinfo.issuedshares.md) | | number | Amount of acquirable shares. |
|
||||
| [investorShares](./bitburner.corporationinfo.investorshares.md) | | number | Amount of shares owned by private investors. Not available for public sale or CEO buyback. |
|
||||
| [issuedShares](./bitburner.corporationinfo.issuedshares.md) | | number | Amount of shares owned by public traders. Available for CEO buyback. |
|
||||
| [issueNewSharesCooldown](./bitburner.corporationinfo.issuenewsharescooldown.md) | | number | Cooldown until new shares can be issued |
|
||||
| [name](./bitburner.corporationinfo.name.md) | | string | Name of the corporation |
|
||||
| [numShares](./bitburner.corporationinfo.numshares.md) | | number | Amount of share owned |
|
||||
| [numShares](./bitburner.corporationinfo.numshares.md) | | number | Amount of shares owned by the CEO. |
|
||||
| [public](./bitburner.corporationinfo.public.md) | | boolean | Indicating if the company is public |
|
||||
| [revenue](./bitburner.corporationinfo.revenue.md) | | number | Revenue per second this cycle |
|
||||
| [sharePrice](./bitburner.corporationinfo.shareprice.md) | | number | Price of the shares |
|
||||
| [shareSaleCooldown](./bitburner.corporationinfo.sharesalecooldown.md) | | number | Cooldown until shares can be sold again |
|
||||
| [state](./bitburner.corporationinfo.state.md) | | string | State of the corporation. Possible states are START, PURCHASE, PRODUCTION, EXPORT, SALE. |
|
||||
| [totalShares](./bitburner.corporationinfo.totalshares.md) | | number | Total number of shares issues by this corporation |
|
||||
| [state](./bitburner.corporationinfo.state.md) | | string | <p>The next state to be processed.</p><p>I.e. when the state is PURCHASE, it means purchasing will occur during the next state transition.</p><p>Possible states are START, PURCHASE, PRODUCTION, EXPORT, SALE.</p> |
|
||||
| [totalShares](./bitburner.corporationinfo.totalshares.md) | | number | Total number of shares issued by this corporation. |
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
## CorporationInfo.numShares property
|
||||
|
||||
Amount of share owned
|
||||
Amount of shares owned by the CEO.
|
||||
|
||||
**Signature:**
|
||||
|
||||
|
||||
@@ -4,7 +4,11 @@
|
||||
|
||||
## CorporationInfo.state property
|
||||
|
||||
State of the corporation. Possible states are START, PURCHASE, PRODUCTION, EXPORT, SALE.
|
||||
The next state to be processed.
|
||||
|
||||
I.e. when the state is PURCHASE, it means purchasing will occur during the next state transition.
|
||||
|
||||
Possible states are START, PURCHASE, PRODUCTION, EXPORT, SALE.
|
||||
|
||||
**Signature:**
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
## CorporationInfo.totalShares property
|
||||
|
||||
Total number of shares issues by this corporation
|
||||
Total number of shares issued by this corporation.
|
||||
|
||||
**Signature:**
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
## Division.makesProducts property
|
||||
|
||||
Whether the industry this division is in is capable of making products
|
||||
Whether the industry of this division is capable of developing and producing products
|
||||
|
||||
**Signature:**
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@ interface Division
|
||||
| [cities](./bitburner.division.cities.md) | | [CityName](./bitburner.cityname.md)<!-- -->\[\] | Cities in which this division has expanded |
|
||||
| [lastCycleExpenses](./bitburner.division.lastcycleexpenses.md) | | number | Expenses last cycle |
|
||||
| [lastCycleRevenue](./bitburner.division.lastcyclerevenue.md) | | number | Revenue last cycle |
|
||||
| [makesProducts](./bitburner.division.makesproducts.md) | | boolean | Whether the industry this division is in is capable of making products |
|
||||
| [makesProducts](./bitburner.division.makesproducts.md) | | boolean | Whether the industry of this division is capable of developing and producing products |
|
||||
| [maxProducts](./bitburner.division.maxproducts.md) | | number | How many products this division can support |
|
||||
| [name](./bitburner.division.name.md) | | string | Name of the division |
|
||||
| [numAdVerts](./bitburner.division.numadverts.md) | | number | Number of times AdVert has been bought |
|
||||
|
||||
23
markdown/bitburner.gang.getrecruitsavailable.md
Normal file
23
markdown/bitburner.gang.getrecruitsavailable.md
Normal file
@@ -0,0 +1,23 @@
|
||||
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
|
||||
|
||||
[Home](./index.md) > [bitburner](./bitburner.md) > [Gang](./bitburner.gang.md) > [getRecruitsAvailable](./bitburner.gang.getrecruitsavailable.md)
|
||||
|
||||
## Gang.getRecruitsAvailable() method
|
||||
|
||||
Check how many gang members you can currently recruit.
|
||||
|
||||
**Signature:**
|
||||
|
||||
```typescript
|
||||
getRecruitsAvailable(): number;
|
||||
```
|
||||
**Returns:**
|
||||
|
||||
number
|
||||
|
||||
Number indicating how many members can be recruited, considering current reputation and gang size.
|
||||
|
||||
## Remarks
|
||||
|
||||
RAM cost: 1 GB
|
||||
|
||||
@@ -34,11 +34,14 @@ If you are not in BitNode-2, then you must have Source-File 2 in order to use th
|
||||
| [getMemberInformation(name)](./bitburner.gang.getmemberinformation.md) | Get information about a specific gang member. |
|
||||
| [getMemberNames()](./bitburner.gang.getmembernames.md) | List all gang members. |
|
||||
| [getOtherGangInformation()](./bitburner.gang.getotherganginformation.md) | Get information about the other gangs. |
|
||||
| [getRecruitsAvailable()](./bitburner.gang.getrecruitsavailable.md) | Check how many gang members you can currently recruit. |
|
||||
| [getTaskNames()](./bitburner.gang.gettasknames.md) | List member task names. |
|
||||
| [getTaskStats(name)](./bitburner.gang.gettaskstats.md) | Get stats of a task. |
|
||||
| [inGang()](./bitburner.gang.ingang.md) | Check if you're in a gang. |
|
||||
| [purchaseEquipment(memberName, equipName)](./bitburner.gang.purchaseequipment.md) | Purchase an equipment for a gang member. |
|
||||
| [recruitMember(name)](./bitburner.gang.recruitmember.md) | Recruit a new gang member. |
|
||||
| [renameMember(memberName, newName)](./bitburner.gang.renamemember.md) | Rename a Gang member to a new unique name. |
|
||||
| [respectForNextRecruit()](./bitburner.gang.respectfornextrecruit.md) | Check the amount of Respect needed for your next gang recruit. |
|
||||
| [setMemberTask(memberName, taskName)](./bitburner.gang.setmembertask.md) | Set gang member to task. |
|
||||
| [setTerritoryWarfare(engage)](./bitburner.gang.setterritorywarfare.md) | Enable/Disable territory warfare. |
|
||||
|
||||
|
||||
33
markdown/bitburner.gang.renamemember.md
Normal file
33
markdown/bitburner.gang.renamemember.md
Normal file
@@ -0,0 +1,33 @@
|
||||
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
|
||||
|
||||
[Home](./index.md) > [bitburner](./bitburner.md) > [Gang](./bitburner.gang.md) > [renameMember](./bitburner.gang.renamemember.md)
|
||||
|
||||
## Gang.renameMember() method
|
||||
|
||||
Rename a Gang member to a new unique name.
|
||||
|
||||
**Signature:**
|
||||
|
||||
```typescript
|
||||
renameMember(memberName: string, newName: string): boolean;
|
||||
```
|
||||
|
||||
## Parameters
|
||||
|
||||
| Parameter | Type | Description |
|
||||
| --- | --- | --- |
|
||||
| memberName | string | Name of the member to change. |
|
||||
| newName | string | New name for that gang member. |
|
||||
|
||||
**Returns:**
|
||||
|
||||
boolean
|
||||
|
||||
True if successful, and false if not.
|
||||
|
||||
## Remarks
|
||||
|
||||
RAM cost: 0 GB
|
||||
|
||||
Rename a Gang Member if none already has the new name.
|
||||
|
||||
23
markdown/bitburner.gang.respectfornextrecruit.md
Normal file
23
markdown/bitburner.gang.respectfornextrecruit.md
Normal file
@@ -0,0 +1,23 @@
|
||||
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
|
||||
|
||||
[Home](./index.md) > [bitburner](./bitburner.md) > [Gang](./bitburner.gang.md) > [respectForNextRecruit](./bitburner.gang.respectfornextrecruit.md)
|
||||
|
||||
## Gang.respectForNextRecruit() method
|
||||
|
||||
Check the amount of Respect needed for your next gang recruit.
|
||||
|
||||
**Signature:**
|
||||
|
||||
```typescript
|
||||
respectForNextRecruit(): number;
|
||||
```
|
||||
**Returns:**
|
||||
|
||||
number
|
||||
|
||||
The static number value of Respect needed for the next recruit, with consideration to your current gang size. Returns `Infinity` if you have reached the gang size limit.
|
||||
|
||||
## Remarks
|
||||
|
||||
RAM cost: 1 GB
|
||||
|
||||
@@ -21,6 +21,7 @@ interface GangGenInfo
|
||||
| [moneyGainRate](./bitburner.ganggeninfo.moneygainrate.md) | | number | Money earned per game cycle |
|
||||
| [power](./bitburner.ganggeninfo.power.md) | | number | Gang's power for territory warfare |
|
||||
| [respect](./bitburner.ganggeninfo.respect.md) | | number | Gang's respect |
|
||||
| [respectForNextRecruit](./bitburner.ganggeninfo.respectfornextrecruit.md) | | number | Amount of Respect needed for next gang recruit, if possible |
|
||||
| [respectGainRate](./bitburner.ganggeninfo.respectgainrate.md) | | number | Respect earned per game cycle |
|
||||
| [territory](./bitburner.ganggeninfo.territory.md) | | number | Amount of territory held |
|
||||
| [territoryClashChance](./bitburner.ganggeninfo.territoryclashchance.md) | | number | Clash chance |
|
||||
|
||||
13
markdown/bitburner.ganggeninfo.respectfornextrecruit.md
Normal file
13
markdown/bitburner.ganggeninfo.respectfornextrecruit.md
Normal file
@@ -0,0 +1,13 @@
|
||||
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
|
||||
|
||||
[Home](./index.md) > [bitburner](./bitburner.md) > [GangGenInfo](./bitburner.ganggeninfo.md) > [respectForNextRecruit](./bitburner.ganggeninfo.respectfornextrecruit.md)
|
||||
|
||||
## GangGenInfo.respectForNextRecruit property
|
||||
|
||||
Amount of Respect needed for next gang recruit, if possible
|
||||
|
||||
**Signature:**
|
||||
|
||||
```typescript
|
||||
respectForNextRecruit: number;
|
||||
```
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
## GangMemberInfo.agi\_asc\_points property
|
||||
|
||||
Total earned agility experience
|
||||
Total Agility Ascension points accumulated
|
||||
|
||||
**Signature:**
|
||||
|
||||
|
||||
@@ -4,6 +4,8 @@
|
||||
|
||||
## GangMemberInfo.augmentations property
|
||||
|
||||
List of all Augmentations currently installed on gang member
|
||||
|
||||
**Signature:**
|
||||
|
||||
```typescript
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
## GangMemberInfo.cha\_asc\_points property
|
||||
|
||||
Total earned charisma experience
|
||||
Total Charisma Ascension points accumulated
|
||||
|
||||
**Signature:**
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
## GangMemberInfo.def\_asc\_points property
|
||||
|
||||
Total earned defense experience
|
||||
Total Defense Ascension points accumulated
|
||||
|
||||
**Signature:**
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
## GangMemberInfo.dex\_asc\_points property
|
||||
|
||||
Total earned dexterity experience
|
||||
Total Dexterity Ascension points accumulated
|
||||
|
||||
**Signature:**
|
||||
|
||||
|
||||
@@ -4,6 +4,8 @@
|
||||
|
||||
## GangMemberInfo.earnedRespect property
|
||||
|
||||
Amount of Respect earned by member since they last Ascended
|
||||
|
||||
**Signature:**
|
||||
|
||||
```typescript
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
## GangMemberInfo.hack\_asc\_points property
|
||||
|
||||
Total earned hack experience
|
||||
Total Hack Ascension points accumulated
|
||||
|
||||
**Signature:**
|
||||
|
||||
|
||||
@@ -16,41 +16,41 @@ interface GangMemberInfo
|
||||
| Property | Modifiers | Type | Description |
|
||||
| --- | --- | --- | --- |
|
||||
| [agi\_asc\_mult](./bitburner.gangmemberinfo.agi_asc_mult.md) | | number | Agility multiplier from ascensions |
|
||||
| [agi\_asc\_points](./bitburner.gangmemberinfo.agi_asc_points.md) | | number | Total earned agility experience |
|
||||
| [agi\_asc\_points](./bitburner.gangmemberinfo.agi_asc_points.md) | | number | Total Agility Ascension points accumulated |
|
||||
| [agi\_exp](./bitburner.gangmemberinfo.agi_exp.md) | | number | Current agility experience |
|
||||
| [agi\_mult](./bitburner.gangmemberinfo.agi_mult.md) | | number | Agility multiplier from equipment |
|
||||
| [agi](./bitburner.gangmemberinfo.agi.md) | | number | Agility skill level |
|
||||
| [augmentations](./bitburner.gangmemberinfo.augmentations.md) | | string\[\] | |
|
||||
| [augmentations](./bitburner.gangmemberinfo.augmentations.md) | | string\[\] | List of all Augmentations currently installed on gang member |
|
||||
| [cha\_asc\_mult](./bitburner.gangmemberinfo.cha_asc_mult.md) | | number | Charisma multiplier from ascensions |
|
||||
| [cha\_asc\_points](./bitburner.gangmemberinfo.cha_asc_points.md) | | number | Total earned charisma experience |
|
||||
| [cha\_asc\_points](./bitburner.gangmemberinfo.cha_asc_points.md) | | number | Total Charisma Ascension points accumulated |
|
||||
| [cha\_exp](./bitburner.gangmemberinfo.cha_exp.md) | | number | Current charisma experience |
|
||||
| [cha\_mult](./bitburner.gangmemberinfo.cha_mult.md) | | number | Charisma multiplier from equipment |
|
||||
| [cha](./bitburner.gangmemberinfo.cha.md) | | number | Charisma skill level |
|
||||
| [def\_asc\_mult](./bitburner.gangmemberinfo.def_asc_mult.md) | | number | Defense multiplier from ascensions |
|
||||
| [def\_asc\_points](./bitburner.gangmemberinfo.def_asc_points.md) | | number | Total earned defense experience |
|
||||
| [def\_asc\_points](./bitburner.gangmemberinfo.def_asc_points.md) | | number | Total Defense Ascension points accumulated |
|
||||
| [def\_exp](./bitburner.gangmemberinfo.def_exp.md) | | number | Current defense experience |
|
||||
| [def\_mult](./bitburner.gangmemberinfo.def_mult.md) | | number | Defense multiplier from equipment |
|
||||
| [def](./bitburner.gangmemberinfo.def.md) | | number | Defense skill level |
|
||||
| [dex\_asc\_mult](./bitburner.gangmemberinfo.dex_asc_mult.md) | | number | Dexterity multiplier from ascensions |
|
||||
| [dex\_asc\_points](./bitburner.gangmemberinfo.dex_asc_points.md) | | number | Total earned dexterity experience |
|
||||
| [dex\_asc\_points](./bitburner.gangmemberinfo.dex_asc_points.md) | | number | Total Dexterity Ascension points accumulated |
|
||||
| [dex\_exp](./bitburner.gangmemberinfo.dex_exp.md) | | number | Current dexterity experience |
|
||||
| [dex\_mult](./bitburner.gangmemberinfo.dex_mult.md) | | number | Dexterity multiplier from equipment |
|
||||
| [dex](./bitburner.gangmemberinfo.dex.md) | | number | Dexterity skill level |
|
||||
| [earnedRespect](./bitburner.gangmemberinfo.earnedrespect.md) | | number | |
|
||||
| [earnedRespect](./bitburner.gangmemberinfo.earnedrespect.md) | | number | Amount of Respect earned by member since they last Ascended |
|
||||
| [hack\_asc\_mult](./bitburner.gangmemberinfo.hack_asc_mult.md) | | number | Hack multiplier from ascensions |
|
||||
| [hack\_asc\_points](./bitburner.gangmemberinfo.hack_asc_points.md) | | number | Total earned hack experience |
|
||||
| [hack\_asc\_points](./bitburner.gangmemberinfo.hack_asc_points.md) | | number | Total Hack Ascension points accumulated |
|
||||
| [hack\_exp](./bitburner.gangmemberinfo.hack_exp.md) | | number | Current hack experience |
|
||||
| [hack\_mult](./bitburner.gangmemberinfo.hack_mult.md) | | number | Hack multiplier from equipment |
|
||||
| [hack](./bitburner.gangmemberinfo.hack.md) | | number | Hack skill level |
|
||||
| [moneyGain](./bitburner.gangmemberinfo.moneygain.md) | | number | |
|
||||
| [moneyGain](./bitburner.gangmemberinfo.moneygain.md) | | number | Per Cycle Income for this gang member |
|
||||
| [name](./bitburner.gangmemberinfo.name.md) | | string | Name of the gang member |
|
||||
| [respectGain](./bitburner.gangmemberinfo.respectgain.md) | | number | |
|
||||
| [respectGain](./bitburner.gangmemberinfo.respectgain.md) | | number | Per Cycle Rate this member is currently gaining Respect |
|
||||
| [str\_asc\_mult](./bitburner.gangmemberinfo.str_asc_mult.md) | | number | Strength multiplier from ascensions |
|
||||
| [str\_asc\_points](./bitburner.gangmemberinfo.str_asc_points.md) | | number | Total earned strength experience |
|
||||
| [str\_asc\_points](./bitburner.gangmemberinfo.str_asc_points.md) | | number | Total Strength Ascension points accumulated |
|
||||
| [str\_exp](./bitburner.gangmemberinfo.str_exp.md) | | number | Current strength experience |
|
||||
| [str\_mult](./bitburner.gangmemberinfo.str_mult.md) | | number | Strength multiplier from equipment |
|
||||
| [str](./bitburner.gangmemberinfo.str.md) | | number | Strength skill level |
|
||||
| [task](./bitburner.gangmemberinfo.task.md) | | string | Currently assigned task |
|
||||
| [upgrades](./bitburner.gangmemberinfo.upgrades.md) | | string\[\] | |
|
||||
| [wantedLevelGain](./bitburner.gangmemberinfo.wantedlevelgain.md) | | number | |
|
||||
| [upgrades](./bitburner.gangmemberinfo.upgrades.md) | | string\[\] | List of all non-Augmentation Equipment owned by gang member |
|
||||
| [wantedLevelGain](./bitburner.gangmemberinfo.wantedlevelgain.md) | | number | Per Cycle Rate by which this member is affecting your gang's Wanted Level |
|
||||
|
||||
|
||||
@@ -4,6 +4,8 @@
|
||||
|
||||
## GangMemberInfo.moneyGain property
|
||||
|
||||
Per Cycle Income for this gang member
|
||||
|
||||
**Signature:**
|
||||
|
||||
```typescript
|
||||
|
||||
@@ -4,6 +4,8 @@
|
||||
|
||||
## GangMemberInfo.respectGain property
|
||||
|
||||
Per Cycle Rate this member is currently gaining Respect
|
||||
|
||||
**Signature:**
|
||||
|
||||
```typescript
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
## GangMemberInfo.str\_asc\_points property
|
||||
|
||||
Total earned strength experience
|
||||
Total Strength Ascension points accumulated
|
||||
|
||||
**Signature:**
|
||||
|
||||
|
||||
@@ -4,6 +4,8 @@
|
||||
|
||||
## GangMemberInfo.upgrades property
|
||||
|
||||
List of all non-Augmentation Equipment owned by gang member
|
||||
|
||||
**Signature:**
|
||||
|
||||
```typescript
|
||||
|
||||
@@ -4,6 +4,8 @@
|
||||
|
||||
## GangMemberInfo.wantedLevelGain property
|
||||
|
||||
Per Cycle Rate by which this member is affecting your gang's Wanted Level
|
||||
|
||||
**Signature:**
|
||||
|
||||
```typescript
|
||||
|
||||
@@ -98,6 +98,7 @@
|
||||
| [Sleeve](./bitburner.sleeve.md) | Sleeve API |
|
||||
| [SleevePerson](./bitburner.sleeveperson.md) | |
|
||||
| [SourceFileLvl](./bitburner.sourcefilelvl.md) | |
|
||||
| [SpawnOptions](./bitburner.spawnoptions.md) | |
|
||||
| [Stanek](./bitburner.stanek.md) | Stanek's Gift API. |
|
||||
| [StockMarketConstants](./bitburner.stockmarketconstants.md) | Constants used for the stockmarket game mechanic. |
|
||||
| [StockOrder](./bitburner.stockorder.md) | <p>Return value of [getOrders](./bitburner.tix.getorders.md)</p><p>Keys are stock symbols, properties are arrays of [StockOrderObject](./bitburner.stockorderobject.md)</p> |
|
||||
|
||||
@@ -9,14 +9,14 @@ Clear data from a port.
|
||||
**Signature:**
|
||||
|
||||
```typescript
|
||||
clearPort(handle: number): void;
|
||||
clearPort(portNumber: number): void;
|
||||
```
|
||||
|
||||
## Parameters
|
||||
|
||||
| Parameter | Type | Description |
|
||||
| --- | --- | --- |
|
||||
| handle | number | Port to clear. |
|
||||
| portNumber | number | Port to clear data from. Must be a positive integer. |
|
||||
|
||||
**Returns:**
|
||||
|
||||
|
||||
@@ -31,8 +31,6 @@ RAM cost: 0.1 GB
|
||||
|
||||
Returns a boolean indicating whether the specified file exists on the target server. The filename for programs is case insensitive, other file types are case sensitive. For example, fileExists(“brutessh.exe”) will work fine, even though the actual program is named 'BruteSSH.exe'.
|
||||
|
||||
\*
|
||||
|
||||
## Example
|
||||
|
||||
|
||||
|
||||
@@ -16,7 +16,7 @@ getPortHandle(portNumber: number): NetscriptPort;
|
||||
|
||||
| Parameter | Type | Description |
|
||||
| --- | --- | --- |
|
||||
| portNumber | number | Port number. Must be an integer between 1 and 20. |
|
||||
| portNumber | number | Port number. Must be a positive integer. |
|
||||
|
||||
**Returns:**
|
||||
|
||||
|
||||
@@ -21,8 +21,8 @@ getRunningScript(
|
||||
| Parameter | Type | Description |
|
||||
| --- | --- | --- |
|
||||
| filename | [FilenameOrPID](./bitburner.filenameorpid.md) | _(Optional)_ Optional. Filename or PID of the script. |
|
||||
| hostname | string | _(Optional)_ Optional. Name of host server the script is running on. |
|
||||
| args | (string \| number \| boolean)\[\] | Arguments to identify the script |
|
||||
| hostname | string | _(Optional)_ Hostname of target server. Optional, defaults to the server the calling script is running on. |
|
||||
| args | (string \| number \| boolean)\[\] | Arguments to specify/identify the script. Optional, when looking for scripts run without arguments. |
|
||||
|
||||
**Returns:**
|
||||
|
||||
@@ -34,5 +34,5 @@ The info about the running script if found, and null otherwise.
|
||||
|
||||
RAM cost: 0.3 GB
|
||||
|
||||
Running with no args returns current script. If you use a PID as the first parameter, the hostname and args parameters are unnecessary.
|
||||
Running with no args returns current script. If you use a PID as the first parameter, the hostname and args parameters are unnecessary. If hostname is omitted while filename is used as the first parameter, hostname defaults to the server the calling script is running on. Remember that a script is semi-uniquely identified by both its name and its arguments. (You can run multiple copies of scripts with the same arguments, but for the purposes of functions like this that check based on filename, the filename plus arguments forms the key.)
|
||||
|
||||
|
||||
@@ -9,14 +9,14 @@ Get all the logs of a script.
|
||||
**Signature:**
|
||||
|
||||
```typescript
|
||||
getScriptLogs(fn?: string, host?: string, ...args: (string | number | boolean)[]): string[];
|
||||
getScriptLogs(fn?: FilenameOrPID, host?: string, ...args: (string | number | boolean)[]): string[];
|
||||
```
|
||||
|
||||
## Parameters
|
||||
|
||||
| Parameter | Type | Description |
|
||||
| --- | --- | --- |
|
||||
| fn | string | _(Optional)_ Optional. Filename of script to get logs from. |
|
||||
| fn | [FilenameOrPID](./bitburner.filenameorpid.md) | _(Optional)_ Optional. Filename or PID of script to get logs from. |
|
||||
| host | string | _(Optional)_ Optional. Hostname of the server that the script is on. |
|
||||
| args | (string \| number \| boolean)\[\] | Arguments to identify which scripts to get logs for. |
|
||||
|
||||
@@ -32,7 +32,7 @@ RAM cost: 0 GB
|
||||
|
||||
Returns a script’s logs. The logs are returned as an array, where each line is an element in the array. The most recently logged line is at the end of the array. Note that there is a maximum number of lines that a script stores in its logs. This is configurable in the game’s options. If the function is called with no arguments, it will return the current script’s logs.
|
||||
|
||||
Otherwise, the fn, hostname/ip, and args… arguments can be used to get the logs from another script. Remember that scripts are uniquely identified by both their names and arguments.
|
||||
Otherwise, the PID or filename, hostname/ip, and args… arguments can be used to get logs from another script. Remember that scripts are uniquely identified by both their names and arguments.
|
||||
|
||||
## Example
|
||||
|
||||
|
||||
@@ -17,8 +17,8 @@ isRunning(script: FilenameOrPID, host?: string, ...args: (string | number | bool
|
||||
| Parameter | Type | Description |
|
||||
| --- | --- | --- |
|
||||
| script | [FilenameOrPID](./bitburner.filenameorpid.md) | Filename or PID of script to check. This is case-sensitive. |
|
||||
| host | string | _(Optional)_ Hostname of target server. |
|
||||
| args | (string \| number \| boolean)\[\] | Arguments to specify/identify which scripts to search for. |
|
||||
| host | string | _(Optional)_ Hostname of target server. Optional, defaults to the server the calling script is running on. |
|
||||
| args | (string \| number \| boolean)\[\] | Arguments to specify/identify the script. Optional, when looking for scripts run without arguments. |
|
||||
|
||||
**Returns:**
|
||||
|
||||
@@ -30,7 +30,7 @@ True if the specified script is running on the target server, and false otherwis
|
||||
|
||||
RAM cost: 0.1 GB
|
||||
|
||||
Returns a boolean indicating whether the specified script is running on the target server. If you use a PID instead of a filename, the hostname and args parameters are unnecessary. Remember that a script is semi-uniquely identified by both its name and its arguments. (You can run multiple copies of scripts with the same arguments, but for the purposes of functions like this that check based on filename, the filename plus arguments forms the key.)
|
||||
Returns a boolean indicating whether the specified script is running on the target server. If you use a PID instead of a filename, the hostname and args parameters are unnecessary. If hostname is omitted while filename is used as the first parameter, hostname defaults to the server the calling script is running on. Remember that a script is semi-uniquely identified by both its name and its arguments. (You can run multiple copies of scripts with the same arguments, but for the purposes of functions like this that check based on filename, the filename plus arguments forms the key.)
|
||||
|
||||
## Example
|
||||
|
||||
|
||||
@@ -58,7 +58,7 @@ export async function main(ns) {
|
||||
| [brutessh(host)](./bitburner.ns.brutessh.md) | Runs BruteSSH.exe on a server. |
|
||||
| [clear(handle)](./bitburner.ns.clear.md) | Clear data from a file. |
|
||||
| [clearLog()](./bitburner.ns.clearlog.md) | Clears the script’s logs. |
|
||||
| [clearPort(handle)](./bitburner.ns.clearport.md) | Clear data from a port. |
|
||||
| [clearPort(portNumber)](./bitburner.ns.clearport.md) | Clear data from a port. |
|
||||
| [closeTail(pid)](./bitburner.ns.closetail.md) | Close the tail window of a script. |
|
||||
| [deleteServer(host)](./bitburner.ns.deleteserver.md) | Delete a purchased server. |
|
||||
| [disableLog(fn)](./bitburner.ns.disablelog.md) | Disables logging for the given function. |
|
||||
@@ -155,7 +155,7 @@ export async function main(ns) {
|
||||
| [setTitle(title, pid)](./bitburner.ns.settitle.md) | Set the title of the tail window of a script. |
|
||||
| [share()](./bitburner.ns.share.md) | Share the server's ram with your factions. |
|
||||
| [sleep(millis)](./bitburner.ns.sleep.md) | Suspends the script for n milliseconds. |
|
||||
| [spawn(script, threadOrOptions, args)](./bitburner.ns.spawn.md) | Terminate current script and start another in 10 seconds. |
|
||||
| [spawn(script, threadOrOptions, args)](./bitburner.ns.spawn.md) | Terminate current script and start another in a defined number of milliseconds. |
|
||||
| [sprintf(format, args)](./bitburner.ns.sprintf.md) | Format a string. |
|
||||
| [sqlinject(host)](./bitburner.ns.sqlinject.md) | Runs SQLInject.exe on a server. |
|
||||
| [tail(fn, host, args)](./bitburner.ns.tail.md) | Open the tail window of a script. |
|
||||
|
||||
@@ -16,7 +16,7 @@ peek(portNumber: number): PortData;
|
||||
|
||||
| Parameter | Type | Description |
|
||||
| --- | --- | --- |
|
||||
| portNumber | number | Port to peek. Must be an integer between 1 and 20. |
|
||||
| portNumber | number | Port to peek. Must be a positive integer. |
|
||||
|
||||
**Returns:**
|
||||
|
||||
|
||||
@@ -16,7 +16,7 @@ readPort(portNumber: number): PortData;
|
||||
|
||||
| Parameter | Type | Description |
|
||||
| --- | --- | --- |
|
||||
| portNumber | number | |
|
||||
| portNumber | number | Port to read from. Must be a positive integer. |
|
||||
|
||||
**Returns:**
|
||||
|
||||
|
||||
@@ -4,12 +4,12 @@
|
||||
|
||||
## NS.spawn() method
|
||||
|
||||
Terminate current script and start another in 10 seconds.
|
||||
Terminate current script and start another in a defined number of milliseconds.
|
||||
|
||||
**Signature:**
|
||||
|
||||
```typescript
|
||||
spawn(script: string, threadOrOptions?: number | RunOptions, ...args: (string | number | boolean)[]): void;
|
||||
spawn(script: string, threadOrOptions?: number | SpawnOptions, ...args: (string | number | boolean)[]): void;
|
||||
```
|
||||
|
||||
## Parameters
|
||||
@@ -17,7 +17,7 @@ spawn(script: string, threadOrOptions?: number | RunOptions, ...args: (string |
|
||||
| Parameter | Type | Description |
|
||||
| --- | --- | --- |
|
||||
| script | string | Filename of script to execute. |
|
||||
| threadOrOptions | number \| [RunOptions](./bitburner.runoptions.md) | _(Optional)_ Either an integer number of threads for new script, or a [RunOptions](./bitburner.runoptions.md) object. Threads defaults to 1. |
|
||||
| threadOrOptions | number \| [SpawnOptions](./bitburner.spawnoptions.md) | _(Optional)_ Either an integer number of threads for new script, or a [SpawnOptions](./bitburner.spawnoptions.md) object. Threads defaults to 1. |
|
||||
| args | (string \| number \| boolean)\[\] | Additional arguments to pass into the new script that is being run. |
|
||||
|
||||
**Returns:**
|
||||
@@ -28,7 +28,7 @@ void
|
||||
|
||||
RAM cost: 2 GB
|
||||
|
||||
Terminates the current script, and then after a delay of about 10 seconds it will execute the newly-specified script. The purpose of this function is to execute a new script without being constrained by the RAM usage of the current one. This function can only be used to run scripts on the local server.
|
||||
Terminates the current script, and then after a defined delay it will execute the newly-specified script. The purpose of this function is to execute a new script without being constrained by the RAM usage of the current one. This function can only be used to run scripts on the local server.
|
||||
|
||||
Because this function immediately terminates the script, it does not have a return value.
|
||||
|
||||
@@ -38,7 +38,7 @@ Running this function with 0 or fewer threads will cause a runtime error.
|
||||
|
||||
|
||||
```js
|
||||
//The following example will execute the script ‘foo.js’ with 10 threads and the arguments ‘foodnstuff’ and 90:
|
||||
ns.spawn('foo.js', 10, 'foodnstuff', 90);
|
||||
//The following example will execute the script ‘foo.js’ with 10 threads, in 500 milliseconds and the arguments ‘foodnstuff’ and 90:
|
||||
ns.spawn('foo.js', 10, 500, 'foodnstuff', 90);
|
||||
```
|
||||
|
||||
|
||||
@@ -32,7 +32,7 @@ Opens a script’s logs. This is functionally the same as the tail Terminal comm
|
||||
|
||||
If the function is called with no arguments, it will open the current script’s logs.
|
||||
|
||||
Otherwise, the fn, hostname/ip, and args… arguments can be used to get the logs from another script. Remember that scripts are uniquely identified by both their names and arguments.
|
||||
Otherwise, the PID or filename, hostname/ip, and args… arguments can be used to get the logs from another script. Remember that scripts are uniquely identified by both their names and arguments.
|
||||
|
||||
## Example
|
||||
|
||||
|
||||
@@ -16,7 +16,7 @@ tryWritePort(portNumber: number, data: string | number): boolean;
|
||||
|
||||
| Parameter | Type | Description |
|
||||
| --- | --- | --- |
|
||||
| portNumber | number | Port or text file that will be written to. |
|
||||
| portNumber | number | Port to attempt to write to to. Must be a positive integer. |
|
||||
| data | string \| number | Data to write. |
|
||||
|
||||
**Returns:**
|
||||
|
||||
@@ -16,7 +16,7 @@ writePort(portNumber: number, data: string | number): PortData | null;
|
||||
|
||||
| Parameter | Type | Description |
|
||||
| --- | --- | --- |
|
||||
| portNumber | number | |
|
||||
| portNumber | number | Port to write to. Must be a positive integer. |
|
||||
| data | string \| number | |
|
||||
|
||||
**Returns:**
|
||||
|
||||
20
markdown/bitburner.spawnoptions.md
Normal file
20
markdown/bitburner.spawnoptions.md
Normal file
@@ -0,0 +1,20 @@
|
||||
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
|
||||
|
||||
[Home](./index.md) > [bitburner](./bitburner.md) > [SpawnOptions](./bitburner.spawnoptions.md)
|
||||
|
||||
## SpawnOptions interface
|
||||
|
||||
|
||||
**Signature:**
|
||||
|
||||
```typescript
|
||||
interface SpawnOptions extends RunOptions
|
||||
```
|
||||
**Extends:** [RunOptions](./bitburner.runoptions.md)
|
||||
|
||||
## Properties
|
||||
|
||||
| Property | Modifiers | Type | Description |
|
||||
| --- | --- | --- | --- |
|
||||
| [spawnDelay?](./bitburner.spawnoptions.spawndelay.md) | | number | _(Optional)_ Number of milliseconds to delay before spawning script, defaults to 10000 (10s). Must be a positive integer. |
|
||||
|
||||
13
markdown/bitburner.spawnoptions.spawndelay.md
Normal file
13
markdown/bitburner.spawnoptions.spawndelay.md
Normal file
@@ -0,0 +1,13 @@
|
||||
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
|
||||
|
||||
[Home](./index.md) > [bitburner](./bitburner.md) > [SpawnOptions](./bitburner.spawnoptions.md) > [spawnDelay](./bitburner.spawnoptions.spawndelay.md)
|
||||
|
||||
## SpawnOptions.spawnDelay property
|
||||
|
||||
Number of milliseconds to delay before spawning script, defaults to 10000 (10s). Must be a positive integer.
|
||||
|
||||
**Signature:**
|
||||
|
||||
```typescript
|
||||
spawnDelay?: number;
|
||||
```
|
||||
@@ -28,7 +28,7 @@ sellProduct(
|
||||
| productName | string | Name of the product |
|
||||
| amt | string | Amount to sell, can be "MAX" |
|
||||
| price | string | Price to sell, can be "MP" |
|
||||
| all | boolean | Sell in all city |
|
||||
| all | boolean | Set sell amount and price in all cities |
|
||||
|
||||
**Returns:**
|
||||
|
||||
|
||||
16
package-lock.json
generated
16
package-lock.json
generated
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "bitburner",
|
||||
"version": "2.4.1",
|
||||
"version": "2.5.0",
|
||||
"lockfileVersion": 2,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "bitburner",
|
||||
"version": "2.4.1",
|
||||
"version": "2.5.0",
|
||||
"hasInstallScript": true,
|
||||
"license": "SEE LICENSE IN license.txt",
|
||||
"dependencies": {
|
||||
@@ -6233,9 +6233,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/caniuse-lite": {
|
||||
"version": "1.0.30001473",
|
||||
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001473.tgz",
|
||||
"integrity": "sha512-ewDad7+D2vlyy+E4UJuVfiBsU69IL+8oVmTuZnH5Q6CIUbxNfI50uVpRHbUPDD6SUaN2o0Lh4DhTrvLG/Tn1yg==",
|
||||
"version": "1.0.30001539",
|
||||
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001539.tgz",
|
||||
"integrity": "sha512-hfS5tE8bnNiNvEOEkm8HElUHroYwlqMMENEzELymy77+tJ6m+gA2krtHl5hxJaj71OlpC2cHZbdSMX1/YEqEkA==",
|
||||
"funding": [
|
||||
{
|
||||
"type": "opencollective",
|
||||
@@ -22616,9 +22616,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"caniuse-lite": {
|
||||
"version": "1.0.30001473",
|
||||
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001473.tgz",
|
||||
"integrity": "sha512-ewDad7+D2vlyy+E4UJuVfiBsU69IL+8oVmTuZnH5Q6CIUbxNfI50uVpRHbUPDD6SUaN2o0Lh4DhTrvLG/Tn1yg=="
|
||||
"version": "1.0.30001539",
|
||||
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001539.tgz",
|
||||
"integrity": "sha512-hfS5tE8bnNiNvEOEkm8HElUHroYwlqMMENEzELymy77+tJ6m+gA2krtHl5hxJaj71OlpC2cHZbdSMX1/YEqEkA=="
|
||||
},
|
||||
"ccount": {
|
||||
"version": "2.0.1",
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "bitburner",
|
||||
"license": "SEE LICENSE IN license.txt",
|
||||
"version": "2.4.1",
|
||||
"version": "2.5.0",
|
||||
"main": "electron-main.js",
|
||||
"author": {
|
||||
"name": "Daniel Xie, Olivier Gagnon, et al."
|
||||
@@ -111,7 +111,7 @@
|
||||
"doc": "bash ./tools/doc.sh",
|
||||
"format": "prettier -c --write .",
|
||||
"format:report": "prettier -c .",
|
||||
"start": "cd .app && http-server -p 8000",
|
||||
"start": "electron .app/index.html",
|
||||
"start:dev": "webpack serve --progress --env devServer --mode development",
|
||||
"build": "bash ./tools/build.sh production",
|
||||
"build:dev": "bash ./tools/build.sh development",
|
||||
|
||||
@@ -322,7 +322,7 @@ export const achievements: Record<string, Achievement> = {
|
||||
WORKOUT: {
|
||||
...achievementData.WORKOUT,
|
||||
Icon: "WORKOUT",
|
||||
Condition: () => isClassWork(Player.currentWork),
|
||||
Condition: () => isClassWork(Player.currentWork) && Player.currentWork.isGym(),
|
||||
},
|
||||
TOR: {
|
||||
...achievementData.TOR,
|
||||
|
||||
78
src/Alias.ts
78
src/Alias.ts
@@ -65,39 +65,51 @@ export function removeAlias(name: string): boolean {
|
||||
/**
|
||||
* Returns the original string with any aliases substituted in.
|
||||
* Aliases are only applied to "whole words", one level deep
|
||||
* @param origCommand the original command string
|
||||
*/
|
||||
export function substituteAliases(origCommand: string): string {
|
||||
const commandArray = origCommand.split(" ");
|
||||
if (commandArray.length > 0) {
|
||||
// For the alias and unalias commands, don't substitute
|
||||
if (commandArray[0] === "unalias" || commandArray[0] === "alias") {
|
||||
return commandArray.join(" ");
|
||||
}
|
||||
|
||||
let somethingSubstituted = true;
|
||||
let depth = 0;
|
||||
let lastAlias;
|
||||
|
||||
while (somethingSubstituted && depth < 10) {
|
||||
depth++;
|
||||
somethingSubstituted = false;
|
||||
const alias = Aliases.get(commandArray[0])?.split(" ");
|
||||
if (alias !== undefined) {
|
||||
somethingSubstituted = true;
|
||||
commandArray.splice(0, 1, ...alias);
|
||||
//commandArray[0] = alias;
|
||||
}
|
||||
for (let i = 0; i < commandArray.length; ++i) {
|
||||
const alias = GlobalAliases.get(commandArray[i])?.split(" ");
|
||||
if (alias !== undefined && (commandArray[i] != lastAlias || somethingSubstituted)) {
|
||||
somethingSubstituted = true;
|
||||
lastAlias = commandArray[i];
|
||||
commandArray.splice(i, 1, ...alias);
|
||||
i += alias.length - 1;
|
||||
//commandArray[i] = alias;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return commandArray.join(" ");
|
||||
return applyAliases(origCommand);
|
||||
}
|
||||
|
||||
/**
|
||||
* Recursively evaluates aliases and applies them to the command string,
|
||||
* unless there are any reference loops or the reference chain is too deep
|
||||
* @param origCommand the original command string
|
||||
* @param depth the current recursion depth
|
||||
* @param currentlyProcessingAliases any aliases that have been applied in the recursive evaluation leading to this point
|
||||
* @return { string } the provided command with all of its referenced aliases evaluated
|
||||
*/
|
||||
function applyAliases(origCommand: string, depth = 0, currentlyProcessingAliases: string[] = []) {
|
||||
if (!origCommand) {
|
||||
return origCommand;
|
||||
}
|
||||
const commandArray = origCommand.split(" ");
|
||||
|
||||
// Do not apply aliases when defining a new alias
|
||||
if (commandArray[0] === "unalias" || commandArray[0] === "alias") {
|
||||
return commandArray.join(" ");
|
||||
}
|
||||
|
||||
// First get non-global aliases, and recursively apply them
|
||||
// (unless there are any reference loops or the reference chain is too deep)
|
||||
const localAlias = Aliases.get(commandArray[0]);
|
||||
if (localAlias && !currentlyProcessingAliases.includes(localAlias)) {
|
||||
const appliedAlias = applyAliases(localAlias, depth + 1, [commandArray[0], ...currentlyProcessingAliases]);
|
||||
commandArray.splice(0, 1, ...appliedAlias.split(" "));
|
||||
}
|
||||
|
||||
// Once local aliasing is complete (or if none are present) handle any global aliases
|
||||
const processedCommands = commandArray.reduce((resolvedCommandArray: string[], command) => {
|
||||
const globalAlias = GlobalAliases.get(command);
|
||||
if (globalAlias && !currentlyProcessingAliases.includes(globalAlias)) {
|
||||
const appliedAlias = applyAliases(globalAlias, depth + 1, [command, ...currentlyProcessingAliases]);
|
||||
resolvedCommandArray.push(appliedAlias);
|
||||
} else {
|
||||
// If there is no alias, or if the alias has a circular reference, leave the command as-is
|
||||
resolvedCommandArray.push(command);
|
||||
}
|
||||
return resolvedCommandArray;
|
||||
}, []);
|
||||
|
||||
return processedCommands.join(" ");
|
||||
}
|
||||
|
||||
@@ -154,6 +154,7 @@ export function AugmentationsRoot(props: IProps): React.ReactElement {
|
||||
<br />- skill / experience
|
||||
<br />- every server except home
|
||||
<br />- factions and reputation
|
||||
<br />- current work activity
|
||||
<br />
|
||||
<br />
|
||||
You will keep:
|
||||
@@ -162,8 +163,7 @@ export function AugmentationsRoot(props: IProps): React.ReactElement {
|
||||
<br />- home ram and cores
|
||||
<br />
|
||||
<br />
|
||||
It is recommended to install several Augmentations at once. Preferably everything from any faction of
|
||||
your choosing.
|
||||
It is recommended to install several Augmentations at once.
|
||||
</>
|
||||
}
|
||||
/>
|
||||
|
||||
@@ -73,16 +73,16 @@ export function initBitNodes() {
|
||||
<br />
|
||||
Certain Factions ({FactionName.SlumSnakes}, {FactionName.Tetrads}, {FactionName.TheSyndicate},{" "}
|
||||
{FactionName.TheDarkArmy}, {FactionName.SpeakersForTheDead}, {FactionName.NiteSec}, {FactionName.TheBlackHand}
|
||||
) give the player the ability to form and manage their own gangs. These gangs will earn the player money and
|
||||
reputation with the corresponding Faction
|
||||
) give the player the ability to form and manage their own gang, which can earn the player money and reputation
|
||||
with the corresponding Faction. Gangs offer more Augmentations than Factions, and in BitNode-2 offer a way to
|
||||
destroy the BitNode.
|
||||
<br />
|
||||
Every Augmentation in the game will be available through the Factions listed above
|
||||
<br />
|
||||
<br />
|
||||
Destroying this BitNode will give you Source-File 2, or if you already have this Source-File it will upgrade its
|
||||
level up to a maximum of 3. This Source-File allows you to form gangs in other BitNodes once your karma
|
||||
decreases to a certain value. It also increases the player's crime success rate, crime money, and charisma
|
||||
multipliers by:
|
||||
decreases to a certain value. It also increases your crime success rate, crime money, and charisma multipliers
|
||||
by:
|
||||
<br />
|
||||
<br />
|
||||
Level 1: 24%
|
||||
|
||||
@@ -157,7 +157,7 @@ export class BitNodeMultipliers {
|
||||
/** Influences profits from corporation dividends and selling shares. */
|
||||
CorporationSoftcap = 1;
|
||||
|
||||
/** Influences number of divisions a corporation can have. */
|
||||
/** Influences the amount of divisions a corporation can have have at the same time*/
|
||||
CorporationDivisions = 1;
|
||||
|
||||
constructor(a: PartialRecord<keyof BitNodeMultipliers, number> = {}) {
|
||||
|
||||
@@ -223,7 +223,8 @@ export class Action {
|
||||
let low = real - diff;
|
||||
let high = real + diff;
|
||||
const city = inst.getCurrentCity();
|
||||
const r = city.pop / city.popEst;
|
||||
let r = city.pop / city.popEst;
|
||||
if (Number.isNaN(r)) r = 0;
|
||||
if (r < 1) low *= r;
|
||||
else high *= r;
|
||||
return [clamp(low), clamp(high)];
|
||||
|
||||
@@ -83,9 +83,9 @@ export const CONSTANTS: {
|
||||
Donations: number; // number of blood/plasma/palette donation the dev have verified., boosts NFG
|
||||
LatestUpdate: string;
|
||||
} = {
|
||||
VersionString: "2.4.1",
|
||||
VersionString: "2.5.0",
|
||||
isDevBranch: false,
|
||||
VersionNumber: 34,
|
||||
VersionNumber: 35,
|
||||
|
||||
/** Max level for any skill, assuming no multipliers. Determined by max numerical value in javascript for experience
|
||||
* and the skill level formula in Player.js. Note that all this means it that when experience hits MAX_INT, then
|
||||
@@ -219,44 +219,57 @@ export const CONSTANTS: {
|
||||
|
||||
// Also update doc/source/changelog.rst
|
||||
LatestUpdate: `
|
||||
## v2.4.1 Update (8/26/23)
|
||||
## v2.5.0 (10/2/2023)
|
||||
|
||||
### FEATURE ADDITIONS:
|
||||
### NOTES
|
||||
(Corporation) Bugfixes in Corporation may cause a large balance shift for this mechanic.
|
||||
|
||||
- Added "Enable terminal history search with arrow keys" option in Misc options category, inspired by similar functionality in shells like zsh. (@ficocelliguy)
|
||||
### API CHANGES:
|
||||
- ns.print and ns.tprint now handle printing Set and Map objects directly (@ficocelliguy)
|
||||
- ns.spawn can now use a configurable delay instead of always 10 seconds (@muesli4brekkies)
|
||||
- (Corporation) Added CorporationDivisions property to BitNodeMultipliers interface (@Caldwell-74)
|
||||
- (Corporation) Added makesMaterials and makesProducts properties to CorpIndustryData interface (@Caldwell-74)
|
||||
- (Corporation) Added issueNewSharesCooldown property to the CorporationInfo interface (@Caldwell-74)
|
||||
- (Corporation) Significantly lowered ram cost of all corporation functions (@jjclark1982)
|
||||
- (Gang) Added ns.gang.getRecruitsAvailable: Gets the number of additional gang members that can currently be recruited (@myCatsName)
|
||||
- (Gang) Added ns.gang.respectForNextRecruit: Gets the respect threshold for recruiting the next gang member (@myCatsName)
|
||||
- (Gang) Added ns.gang.renameMember: Renames a gang member (@myCatsName)
|
||||
|
||||
### BUGFIX:
|
||||
### BUGFIX
|
||||
- Taking a university class no longer gives the player an achievement for working out in a gym (@myCatsName)
|
||||
- Bash keybind ctrl-C clears an ongoing terminal history search (@ncharris93)
|
||||
- (Corporation): Fix bug in valuation calculation (@yichizhng)
|
||||
- (Corporation): Fix bug in share price calculation (@jjclark1982)
|
||||
- (Corporation) "Same sell amount in all cities" works with Products again (@Caldwell-74)
|
||||
- (Hashnet) Buying multiple company favor upgrades at the same time will actually apply them all instead of just one (@aschmider)
|
||||
|
||||
- Fixed a bug where buying NeuroFlux Governor would buy one less level than expected (@zerbosh)
|
||||
- Fixed an issue that could cause the Coding Contract UI to become unreachable (@myCatsName)
|
||||
- Infiltration: Knowledge of Apollo aug no longer highlights the incorrect wires (@Snarling)
|
||||
|
||||
### CODEBASE / DOCS / MISC:
|
||||
|
||||
- Added a new theme "zerenity" (@Zelow79)
|
||||
- Reorganize game constants (@zerbosh)
|
||||
- Reorganize ingame documentation folder structure, simplify documentation bundling (@Snarling)
|
||||
- IP Address coding contract accepts single-quoted entries (@myCatsName)
|
||||
- Updated an outdated message on ns.killall logs (@myCatsName)
|
||||
- Updated documentation for ns.share and ns.getSharePower (@myCatsName)
|
||||
- Removed functions (like ns.getServerRam) are no longer shown when enumerating ns entries. (@Snarling)
|
||||
- Removed more references to ReadTheDocs that remained after 2.4.0 (@hydroflame)
|
||||
- Fixed some typos/spacing (@myCatsName)
|
||||
- Fixed an issue with incorrect React keys in active scripts page (@zornlemma)
|
||||
|
||||
### API CHANGES (NON-SPOILER)
|
||||
|
||||
- Added ns.stock.getConstants (@Snarling)
|
||||
- Added ownedAugs and ownedSF properties to return data of ns.getResetInfo (@Snarling)
|
||||
|
||||
### API CHANGES (SPOILERS):
|
||||
|
||||
- Added ns.singularity.getAugmentationFactions to provide a list of factions that have a given augmentation (@myCatsName)
|
||||
- ns.corporation.getConstants now has a ram cost of 0 (@Snarling)
|
||||
|
||||
### OTHER CHANGES (SPOILERS):
|
||||
|
||||
- Successes for next level is now accurate in the UI for Bladeburner operations (@myCatsName)
|
||||
- ns.sleeve.setToFactionWork no longer allows working for factions the player has not joined (@Snarling)
|
||||
### OTHER CHANGES
|
||||
- MISC: Improved handling of aliases in the Terminal (@ficocelliguy)
|
||||
- MISC: Improved error messages for ns.getPurchasedServer (@ficocelliguy)
|
||||
- MISC: ns.sleep and ns.asleep now show a formatted time in the script log. (@ficocelliguy)
|
||||
- MISC: Fix an exploit that allowed over 100% utilization of a server's ram (@d0sboots)
|
||||
- MISC: (Bladeburner / Sleeve) Bladeburner training action is available for sleeves (@Zelow79)
|
||||
- MISC: (Gang) Renamed the Territory Warfare mechanic (now referred to as Territory Clashes) to deconflict with the Territory Warfare gang member task (@ficocelliguy)
|
||||
- UI: Infiltration now hides tail windows instead of temporarily removing them from the page. This means position/size will remain as they were before the infiltration, and any React content will remain active instead of being unmounted/remounted (@ficocelliguy)
|
||||
- UI: Faction augmentation page updates more reliably (@zerbosh)
|
||||
- UI: Added a text filter on the Faction Augmentations page (@ficocelliguy)
|
||||
- UI: Improved pagination of Active Scripts page (@Ookamiko, @ficocelliguy)
|
||||
- UI: Icarus message no longer shows repeatedly for players that are in the endgame (@ficocelliguy)
|
||||
- UI: Remove work completion dialogs when performing an augmentation install (@ficocelliguy)
|
||||
- UI: Improve soft reset dialog, and always show dialog when soft resetting (@myCatsName)
|
||||
- UI: While closing, modals no longer update displayed info and become inert (@Snarling)
|
||||
- UI: (Bladeburner) Fix a possible NaN display value in Bladeburner (@zerbosh)
|
||||
- UI: (Corporation) Multiple UI improvements for Corporation (@jjclark1982)
|
||||
- UI: (Corporation) Tweaked some number formatting to look better in Corp and Stats page (@zerbosh)
|
||||
- UI: (Corporation) Market TA no longer has its own dialog box, it's set in the normal sell dialog (@Caldwell-74)
|
||||
- UI: (Corporation) Fix an incorrect value in the party dialog box (@aschmider)
|
||||
- UI: (Corporation) Improved the descriptions for Corporation states (@Caldwell-74)
|
||||
- UI: (Gang) Various UI improvements for Gang (@myCatsName)
|
||||
- DOCS: Improve documentation for ports (@muesli4brekkies)
|
||||
- DOCS: Updated documentation for ns.tail and ns.getScriptLogs to make it clear a PID can be used (@myCatsName)
|
||||
- DOCS: Improve documentation for FilenameOrPID functions (@VictorS)
|
||||
- DOCS: Improved various existing ingame documentation pages (@myCatsName)
|
||||
- DOCS: (Bladeburner / Gang) Added initial ingame documentation for Bladeburner and Gang (@myCatsName)
|
||||
- DOCS: (Bladeburner / Gang) Improve API documentation for Bladeburner and Gang functions (@myCatsName)
|
||||
`,
|
||||
};
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
import { isInteger } from "lodash";
|
||||
|
||||
import { Player } from "@player";
|
||||
import { CorpResearchName, CorpSmartSupplyOption } from "@nsdefs";
|
||||
|
||||
@@ -18,6 +16,7 @@ import { isRelevantMaterial } from "./ui/Helpers";
|
||||
import { CityName } from "@enums";
|
||||
import { getRandomInt } from "../utils/helpers/getRandomInt";
|
||||
import { getRecordValues } from "../Types/Record";
|
||||
import { sellSharesFailureReason, buybackSharesFailureReason, issueNewSharesFailureReason } from "./helpers";
|
||||
|
||||
export function NewDivision(corporation: Corporation, industry: IndustryType, name: string): void {
|
||||
if (corporation.divisions.size >= corporation.maxDivisions)
|
||||
@@ -70,7 +69,7 @@ export function purchaseOffice(corporation: Corporation, division: Division, cit
|
||||
if (division.offices[city]) {
|
||||
throw new Error(`You have already expanded into ${city} for ${division.name}`);
|
||||
}
|
||||
corporation.funds = corporation.funds - corpConstants.officeInitialCost;
|
||||
corporation.addNonIncomeFunds(-corpConstants.officeInitialCost);
|
||||
division.offices[city] = new OfficeSpace({
|
||||
city: city,
|
||||
size: corpConstants.officeInitialSize,
|
||||
@@ -85,33 +84,72 @@ export function IssueDividends(corporation: Corporation, rate: number): void {
|
||||
corporation.dividendRate = rate;
|
||||
}
|
||||
|
||||
export function IssueNewShares(corporation: Corporation, amount: number): [number, number, number] {
|
||||
const max = corporation.calculateMaxNewShares();
|
||||
export function GoPublic(corporation: Corporation, numShares: number): void {
|
||||
const ceoOwnership = (corporation.numShares - numShares) / corporation.totalShares;
|
||||
const initialSharePrice = corporation.getTargetSharePrice(ceoOwnership);
|
||||
|
||||
// Round to nearest ten-millionth
|
||||
amount = Math.round(amount / 10e6) * 10e6;
|
||||
|
||||
if (isNaN(amount) || amount < 10e6 || amount > max) {
|
||||
throw new Error(`Invalid value. Must be an number between 10m and ${max} (20% of total shares)`);
|
||||
if (isNaN(numShares) || numShares < 0) {
|
||||
throw new Error("Invalid value for number of issued shares");
|
||||
}
|
||||
if (numShares > corporation.numShares) {
|
||||
throw new Error("You don't have that many shares to issue!");
|
||||
}
|
||||
corporation.public = true;
|
||||
corporation.sharePrice = initialSharePrice;
|
||||
corporation.issuedShares += numShares;
|
||||
corporation.numShares -= numShares;
|
||||
corporation.addNonIncomeFunds(numShares * initialSharePrice);
|
||||
}
|
||||
|
||||
const newSharePrice = Math.round(corporation.sharePrice * 0.8);
|
||||
export function IssueNewShares(
|
||||
corporation: Corporation,
|
||||
amount: number,
|
||||
): [profit: number, amount: number, privateShares: number] {
|
||||
const failureReason = issueNewSharesFailureReason(corporation, amount);
|
||||
if (failureReason) throw new Error(failureReason);
|
||||
|
||||
const profit = amount * newSharePrice;
|
||||
corporation.issueNewSharesCooldown = corpConstants.issueNewSharesCooldown;
|
||||
const ceoOwnership = corporation.numShares / (corporation.totalShares + amount);
|
||||
const newSharePrice = corporation.getTargetSharePrice(ceoOwnership);
|
||||
|
||||
const privateOwnedRatio = 1 - (corporation.numShares + corporation.issuedShares) / corporation.totalShares;
|
||||
const profit = (amount * (corporation.sharePrice + newSharePrice)) / 2;
|
||||
|
||||
const cooldownMultiplier = corporation.totalShares / corpConstants.initialShares;
|
||||
corporation.issueNewSharesCooldown = corpConstants.issueNewSharesCooldown * cooldownMultiplier;
|
||||
|
||||
const privateOwnedRatio = corporation.investorShares / corporation.totalShares;
|
||||
const maxPrivateShares = Math.round((amount / 2) * privateOwnedRatio);
|
||||
const privateShares = Math.round(getRandomInt(0, maxPrivateShares) / 10e6) * 10e6;
|
||||
|
||||
corporation.issuedShares += amount - privateShares;
|
||||
corporation.investorShares += privateShares;
|
||||
corporation.totalShares += amount;
|
||||
corporation.funds = corporation.funds + profit;
|
||||
corporation.immediatelyUpdateSharePrice();
|
||||
corporation.addNonIncomeFunds(profit);
|
||||
// Set sharePrice directly because all formulas will be based on stale cycleValuation data
|
||||
corporation.sharePrice = newSharePrice;
|
||||
|
||||
return [profit, amount, privateShares];
|
||||
}
|
||||
|
||||
export function AcceptInvestmentOffer(corporation: Corporation): void {
|
||||
if (
|
||||
corporation.fundingRound >= corpConstants.fundingRoundShares.length ||
|
||||
corporation.fundingRound >= corpConstants.fundingRoundMultiplier.length ||
|
||||
corporation.public
|
||||
) {
|
||||
throw new Error("No more investment offers are available.");
|
||||
}
|
||||
const val = corporation.valuation;
|
||||
const percShares = corpConstants.fundingRoundShares[corporation.fundingRound];
|
||||
const roundMultiplier = corpConstants.fundingRoundMultiplier[corporation.fundingRound];
|
||||
const funding = val * percShares * roundMultiplier;
|
||||
const investShares = Math.floor(corpConstants.initialShares * percShares);
|
||||
corporation.fundingRound++;
|
||||
corporation.addNonIncomeFunds(funding);
|
||||
|
||||
corporation.numShares -= investShares;
|
||||
corporation.investorShares += investShares;
|
||||
}
|
||||
|
||||
export function SellMaterial(material: Material, amount: string, price: string): void {
|
||||
if (price === "") price = "0";
|
||||
if (amount === "") amount = "0";
|
||||
@@ -166,6 +204,8 @@ export function SellMaterial(material: Material, amount: string, price: string):
|
||||
|
||||
export function SellProduct(product: Product, city: CityName, amt: string, price: string, all: boolean): void {
|
||||
//Parse price
|
||||
// initliaze newPrice with oldPrice as default
|
||||
let newPrice = product.cityData[city].desiredSellPrice;
|
||||
if (price.includes("MP")) {
|
||||
//Dynamically evaluated quantity. First test to make sure its valid
|
||||
//Sanitize input, then replace dynamic variables with arbitrary numbers
|
||||
@@ -181,17 +221,19 @@ export function SellProduct(product: Product, city: CityName, amt: string, price
|
||||
if (temp == null || isNaN(parseFloat(temp))) {
|
||||
throw new Error("Invalid value or expression for sell price field.");
|
||||
}
|
||||
product.cityData[city].desiredSellPrice = price; //Use sanitized price
|
||||
newPrice = price; //Use sanitized price
|
||||
} else {
|
||||
const cost = parseFloat(price);
|
||||
if (isNaN(cost)) {
|
||||
throw new Error("Invalid value for sell price field");
|
||||
}
|
||||
product.cityData[city].desiredSellPrice = cost;
|
||||
newPrice = cost;
|
||||
}
|
||||
|
||||
// Parse quantity
|
||||
amt = amt.toUpperCase();
|
||||
//initialize newAmount with old as default
|
||||
let newAmount = product.cityData[city].desiredSellAmount;
|
||||
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, "");
|
||||
@@ -208,14 +250,7 @@ export function SellProduct(product: Product, city: CityName, amt: string, price
|
||||
if (temp == null || isNaN(parseFloat(temp))) {
|
||||
throw new Error("Invalid value or expression for sell quantity field");
|
||||
}
|
||||
|
||||
if (all) {
|
||||
for (const cityName of Object.values(CityName)) {
|
||||
product.cityData[cityName].desiredSellAmount = qty; //Use sanitized input
|
||||
}
|
||||
} else {
|
||||
product.cityData[city].desiredSellAmount = qty; //Use sanitized input
|
||||
}
|
||||
newAmount = qty; //Use sanitized input
|
||||
} else if (isNaN(parseFloat(amt)) || parseFloat(amt) < 0) {
|
||||
throw new Error("Invalid value for sell quantity field! Must be numeric or 'PROD' or 'MAX'");
|
||||
} else {
|
||||
@@ -223,21 +258,17 @@ export function SellProduct(product: Product, city: CityName, amt: string, price
|
||||
if (isNaN(qty)) {
|
||||
qty = 0;
|
||||
}
|
||||
if (qty === 0) {
|
||||
if (all) {
|
||||
for (const cityName of Object.values(CityName)) {
|
||||
product.cityData[cityName].desiredSellAmount = 0;
|
||||
}
|
||||
} else {
|
||||
product.cityData[city].desiredSellAmount = 0;
|
||||
}
|
||||
} else if (all) {
|
||||
for (const cityName of Object.values(CityName)) {
|
||||
product.cityData[cityName].desiredSellAmount = qty;
|
||||
}
|
||||
} else {
|
||||
product.cityData[city].desiredSellAmount = qty;
|
||||
newAmount = qty;
|
||||
}
|
||||
//apply new price and amount to all or just current
|
||||
if (all) {
|
||||
for (const cityName of Object.values(CityName)) {
|
||||
product.cityData[cityName].desiredSellAmount = newAmount;
|
||||
product.cityData[cityName].desiredSellPrice = newPrice;
|
||||
}
|
||||
} else {
|
||||
product.cityData[city].desiredSellAmount = newAmount;
|
||||
product.cityData[city].desiredSellPrice = newPrice;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -287,17 +318,10 @@ export function BulkPurchase(
|
||||
}
|
||||
|
||||
export function SellShares(corporation: Corporation, numShares: number): number {
|
||||
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);
|
||||
const profit = stockSaleResults[0];
|
||||
const newSharePrice = stockSaleResults[1];
|
||||
const newSharesUntilUpdate = stockSaleResults[2];
|
||||
const failureReason = sellSharesFailureReason(corporation, numShares);
|
||||
if (failureReason) throw new Error(failureReason);
|
||||
|
||||
const [profit, newSharePrice, newSharesUntilUpdate] = corporation.calculateShareSale(numShares);
|
||||
|
||||
corporation.numShares -= numShares;
|
||||
corporation.issuedShares += numShares;
|
||||
@@ -309,15 +333,16 @@ export function SellShares(corporation: Corporation, numShares: number): number
|
||||
}
|
||||
|
||||
export function BuyBackShares(corporation: Corporation, numShares: number): boolean {
|
||||
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;
|
||||
if (Player.money < numShares * buybackPrice) throw new Error("You cant afford that many shares!");
|
||||
const failureReason = buybackSharesFailureReason(corporation, numShares);
|
||||
if (failureReason) throw new Error(failureReason);
|
||||
|
||||
const [cost, newSharePrice, newSharesUntilUpdate] = corporation.calculateShareBuyback(numShares);
|
||||
|
||||
corporation.numShares += numShares;
|
||||
corporation.issuedShares -= numShares;
|
||||
Player.loseMoney(numShares * buybackPrice, "corporation");
|
||||
corporation.sharePrice = newSharePrice;
|
||||
corporation.shareSalesUntilPriceUpdate = newSharesUntilUpdate;
|
||||
Player.loseMoney(cost, "corporation");
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -332,7 +357,7 @@ export function UpgradeOfficeSize(corp: Corporation, office: OfficeSpace, size:
|
||||
const cost = corpConstants.officeInitialCost * mult;
|
||||
if (corp.funds < cost) return;
|
||||
office.size += size;
|
||||
corp.funds = corp.funds - cost;
|
||||
corp.addNonIncomeFunds(-cost);
|
||||
}
|
||||
|
||||
export function BuyTea(corp: Corporation, office: OfficeSpace): boolean {
|
||||
@@ -360,7 +385,7 @@ export function ThrowParty(corp: Corporation, office: OfficeSpace, costPerEmploy
|
||||
export function purchaseWarehouse(corp: Corporation, division: Division, city: CityName): void {
|
||||
if (corp.funds < corpConstants.warehouseInitialCost) return;
|
||||
if (division.warehouses[city]) return;
|
||||
corp.funds = corp.funds - corpConstants.warehouseInitialCost;
|
||||
corp.addNonIncomeFunds(-corpConstants.warehouseInitialCost);
|
||||
division.warehouses[city] = new Warehouse({
|
||||
division: division,
|
||||
loc: city,
|
||||
@@ -380,7 +405,7 @@ export function UpgradeWarehouse(corp: Corporation, division: Division, warehous
|
||||
if (corp.funds < sizeUpgradeCost) return;
|
||||
warehouse.level += amt;
|
||||
warehouse.updateSize(corp, division);
|
||||
corp.funds = corp.funds - sizeUpgradeCost;
|
||||
corp.addNonIncomeFunds(-sizeUpgradeCost);
|
||||
}
|
||||
|
||||
export function HireAdVert(corp: Corporation, division: Division): void {
|
||||
|
||||
@@ -4,6 +4,7 @@ import { CorporationState } from "./CorporationState";
|
||||
import { CorpUnlocks } from "./data/CorporationUnlocks";
|
||||
import { CorpUpgrades } from "./data/CorporationUpgrades";
|
||||
import * as corpConstants from "./data/Constants";
|
||||
import { IndustriesData } from "./data/IndustryData";
|
||||
import { Division } from "./Division";
|
||||
|
||||
import { currentNodeMults } from "../BitNode/BitNodeMultipliers";
|
||||
@@ -11,7 +12,7 @@ import { showLiterature } from "../Literature/LiteratureHelpers";
|
||||
|
||||
import { dialogBoxCreate } from "../ui/React/DialogBox";
|
||||
import { constructorsForReviver, Generic_toJSON, Generic_fromJSON, IReviverValue } from "../utils/JSONReviver";
|
||||
import { CorpStateName } from "@nsdefs";
|
||||
import { CorpStateName, InvestmentOffer } from "@nsdefs";
|
||||
import { calculateUpgradeCost } from "./helpers";
|
||||
import { JSONMap, JSONSet } from "../Types/Jsonable";
|
||||
import { formatMoney } from "../ui/formatNumber";
|
||||
@@ -45,6 +46,7 @@ export class Corporation {
|
||||
issueNewSharesCooldown = 0; // Game cycles until player can issue shares again
|
||||
dividendRate = 0;
|
||||
dividendTax = 1 - currentNodeMults.CorporationSoftcap + 0.15;
|
||||
investorShares = 0;
|
||||
issuedShares = 0;
|
||||
sharePrice = 0;
|
||||
storedCycles = 0;
|
||||
@@ -56,6 +58,8 @@ export class Corporation {
|
||||
value: name === CorpUpgradeName.DreamSense ? 0 : 1,
|
||||
}));
|
||||
|
||||
previousTotalAssets = 150e9;
|
||||
totalAssets = 150e9;
|
||||
cycleValuation = 0;
|
||||
valuationsList = [0];
|
||||
valuation = 0;
|
||||
@@ -77,6 +81,17 @@ export class Corporation {
|
||||
this.funds += amt;
|
||||
}
|
||||
|
||||
// Add or subtract funds which should not be counted for valuation; e.g. investments,
|
||||
// upgrades, stock issuance
|
||||
addNonIncomeFunds(amt: number): void {
|
||||
if (!isFinite(amt)) {
|
||||
console.error("Trying to add invalid amount of funds. Report to a developer.");
|
||||
return;
|
||||
}
|
||||
this.totalAssets += amt;
|
||||
this.funds += amt;
|
||||
}
|
||||
|
||||
getState(): CorpStateName {
|
||||
return this.state.getState();
|
||||
}
|
||||
@@ -126,8 +141,6 @@ export class Corporation {
|
||||
this.expenses = this.expenses + ind.lastCycleExpenses;
|
||||
});
|
||||
const profit = this.revenue - this.expenses;
|
||||
this.cycleValuation = this.determineCycleValuation();
|
||||
this.determineValuation();
|
||||
const cycleProfit = profit * (marketCycles * corpConstants.secondsPerMarketCycle);
|
||||
if (isNaN(this.funds) || this.funds === Infinity || this.funds === -Infinity) {
|
||||
dialogBoxCreate(
|
||||
@@ -137,7 +150,6 @@ export class Corporation {
|
||||
);
|
||||
this.funds = 150e9;
|
||||
}
|
||||
|
||||
if (this.dividendRate > 0 && cycleProfit > 0) {
|
||||
// Validate input again, just to be safe
|
||||
if (isNaN(this.dividendRate) || this.dividendRate < 0 || this.dividendRate > corpConstants.dividendMaxRate) {
|
||||
@@ -151,7 +163,9 @@ export class Corporation {
|
||||
} else {
|
||||
this.addFunds(cycleProfit);
|
||||
}
|
||||
|
||||
this.updateTotalAssets();
|
||||
this.cycleValuation = this.determineCycleValuation();
|
||||
this.determineValuation();
|
||||
this.updateSharePrice();
|
||||
}
|
||||
|
||||
@@ -170,24 +184,27 @@ export class Corporation {
|
||||
|
||||
determineCycleValuation(): number {
|
||||
let val,
|
||||
profit = this.revenue - this.expenses;
|
||||
assetDelta = (this.totalAssets - this.previousTotalAssets) / corpConstants.secondsPerMarketCycle;
|
||||
// Handle pre-totalAssets saves
|
||||
assetDelta ??= this.revenue - this.expenses;
|
||||
if (this.public) {
|
||||
// Account for dividends
|
||||
if (this.dividendRate > 0) {
|
||||
profit *= 1 - this.dividendRate;
|
||||
assetDelta *= 1 - this.dividendRate;
|
||||
}
|
||||
|
||||
val = this.funds + profit * 85e3;
|
||||
val = this.funds + assetDelta * 85e3;
|
||||
val *= Math.pow(1.1, this.divisions.size);
|
||||
val = Math.max(val, 0);
|
||||
} else {
|
||||
val = 10e9 + Math.max(this.funds, 0) / 3; //Base valuation
|
||||
if (profit > 0) {
|
||||
val += profit * 315e3;
|
||||
val = 10e9 + this.funds / 3;
|
||||
if (assetDelta > 0) {
|
||||
val += assetDelta * 315e3;
|
||||
}
|
||||
val *= Math.pow(1.1, this.divisions.size);
|
||||
val -= val % 1e6; //Round down to nearest millionth
|
||||
}
|
||||
if (val < 10e9) val = 10e9; // Base valuation
|
||||
return val * currentNodeMults.CorporationValuation;
|
||||
}
|
||||
|
||||
@@ -195,14 +212,38 @@ export class Corporation {
|
||||
this.valuationsList.push(this.cycleValuation); //Add current valuation to the list
|
||||
if (this.valuationsList.length > corpConstants.valuationLength) this.valuationsList.shift();
|
||||
let val = this.valuationsList.reduce((a, b) => a + b); //Calculate valuations sum
|
||||
val /= corpConstants.valuationLength; //Calculate the average
|
||||
val /= this.valuationsList.length; //Calculate the average
|
||||
this.valuation = val;
|
||||
}
|
||||
|
||||
getTargetSharePrice(): number {
|
||||
// Note: totalShares - numShares is not the same as issuedShares because
|
||||
// issuedShares does not account for private investors
|
||||
return this.valuation / (2 * (this.totalShares - this.numShares) + 1);
|
||||
updateTotalAssets(): void {
|
||||
let assets = this.funds;
|
||||
this.divisions.forEach((ind) => {
|
||||
assets += IndustriesData[ind.type].startingCost;
|
||||
for (const warehouse of getRecordValues(ind.warehouses)) {
|
||||
for (const mat of getRecordValues(warehouse.materials)) {
|
||||
assets += mat.stored * mat.averagePrice;
|
||||
}
|
||||
for (const prod of ind.products.values()) {
|
||||
assets += prod.cityData[warehouse.city].stored * prod.productionCost;
|
||||
}
|
||||
}
|
||||
});
|
||||
this.previousTotalAssets = this.totalAssets;
|
||||
this.totalAssets = assets;
|
||||
}
|
||||
|
||||
getTargetSharePrice(ceoOwnership: number | null = null): number {
|
||||
// Share price is proportional to total corporation valuation.
|
||||
// When the CEO owns 0% of the company, market cap is 0.5x valuation.
|
||||
// When the CEO owns 25% of the company, market cap is 1.0x valuation.
|
||||
// When the CEO owns 100% of shares, market cap is 1.5x valuation.
|
||||
if (ceoOwnership === null) {
|
||||
ceoOwnership = this.numShares / this.totalShares;
|
||||
}
|
||||
const ceoConfidence = 0.5 + Math.sqrt(Math.max(0, ceoOwnership));
|
||||
const marketCap = this.valuation * ceoConfidence;
|
||||
return marketCap / this.totalShares;
|
||||
}
|
||||
|
||||
updateSharePrice(): void {
|
||||
@@ -217,10 +258,6 @@ export class Corporation {
|
||||
}
|
||||
}
|
||||
|
||||
immediatelyUpdateSharePrice(): void {
|
||||
this.sharePrice = this.getTargetSharePrice();
|
||||
}
|
||||
|
||||
calculateMaxNewShares(): number {
|
||||
const maxNewSharesUnrounded = Math.round(this.totalShares * 0.2);
|
||||
const maxNewShares = maxNewSharesUnrounded - (maxNewSharesUnrounded % 10e6);
|
||||
@@ -228,17 +265,18 @@ export class Corporation {
|
||||
}
|
||||
|
||||
// Calculates how much money will be made and what the resulting stock price
|
||||
// will be when the player sells his/her shares
|
||||
// will be when the player sells their shares
|
||||
// @return - [Player profit, final stock price, end shareSalesUntilPriceUpdate property]
|
||||
calculateShareSale(numShares: number): [number, number, number] {
|
||||
let sharesTracker = numShares;
|
||||
calculateShareSale(numShares: number): [profit: number, sharePrice: number, sharesUntilUpdate: number] {
|
||||
let sharesRemaining = numShares;
|
||||
let sharesUntilUpdate = this.shareSalesUntilPriceUpdate;
|
||||
let sharePrice = this.sharePrice;
|
||||
let sharesSold = 0;
|
||||
let profit = 0;
|
||||
let targetPrice = this.getTargetSharePrice();
|
||||
|
||||
const maxIterations = Math.ceil(numShares / corpConstants.sharesPerPriceUpdate);
|
||||
const sharesPerStep = Math.sign(numShares || 1) * corpConstants.sharesPerPriceUpdate;
|
||||
const maxIterations = Math.ceil(numShares / sharesPerStep);
|
||||
|
||||
if (isNaN(maxIterations) || maxIterations > 10e6) {
|
||||
console.error(
|
||||
`Something went wrong or unexpected when calculating share sale. Max iterations calculated to be ${maxIterations}`,
|
||||
@@ -247,28 +285,59 @@ export class Corporation {
|
||||
}
|
||||
|
||||
for (let i = 0; i < maxIterations; ++i) {
|
||||
if (sharesTracker < sharesUntilUpdate) {
|
||||
profit += sharePrice * sharesTracker;
|
||||
sharesUntilUpdate -= sharesTracker;
|
||||
if (Math.abs(sharesRemaining) < Math.abs(sharesUntilUpdate)) {
|
||||
profit += sharePrice * sharesRemaining;
|
||||
sharesUntilUpdate -= sharesRemaining;
|
||||
break;
|
||||
} else {
|
||||
profit += sharePrice * sharesUntilUpdate;
|
||||
sharesUntilUpdate = corpConstants.sharesPerPriceUpdate;
|
||||
sharesTracker -= sharesUntilUpdate;
|
||||
sharesSold += sharesUntilUpdate;
|
||||
targetPrice = this.valuation / (2 * (this.totalShares + sharesSold - this.numShares));
|
||||
// Calculate what new share price would be
|
||||
profit += sharePrice * sharesPerStep;
|
||||
sharesRemaining -= sharesPerStep;
|
||||
sharesSold += sharesPerStep;
|
||||
|
||||
// Update the share price
|
||||
const ceoOwnership = (this.numShares - sharesSold) / this.totalShares;
|
||||
const targetPrice = this.getTargetSharePrice(ceoOwnership);
|
||||
if (sharePrice <= targetPrice) {
|
||||
sharePrice *= 1 + 0.5 * 0.01;
|
||||
} else {
|
||||
sharePrice *= 1 - 0.5 * 0.01;
|
||||
}
|
||||
sharesUntilUpdate = corpConstants.sharesPerPriceUpdate;
|
||||
}
|
||||
}
|
||||
|
||||
return [profit, sharePrice, sharesUntilUpdate];
|
||||
}
|
||||
|
||||
calculateShareBuyback(numShares: number): [cost: number, sharePrice: number, sharesUntilUpdate: number] {
|
||||
const [profit, sharePrice, sharesUntilUpdate] = this.calculateShareSale(-numShares);
|
||||
const cost = -1.1 * profit;
|
||||
return [cost, sharePrice, sharesUntilUpdate];
|
||||
}
|
||||
|
||||
getInvestmentOffer(): InvestmentOffer {
|
||||
if (
|
||||
this.fundingRound >= corpConstants.fundingRoundShares.length ||
|
||||
this.fundingRound >= corpConstants.fundingRoundMultiplier.length ||
|
||||
this.public
|
||||
)
|
||||
return {
|
||||
funds: 0,
|
||||
shares: 0,
|
||||
round: this.fundingRound + 1, // Make more readable
|
||||
}; // Don't throw an error here, no reason to have a second function to check if you can get investment.
|
||||
const val = this.valuation;
|
||||
const percShares = corpConstants.fundingRoundShares[this.fundingRound];
|
||||
const roundMultiplier = corpConstants.fundingRoundMultiplier[this.fundingRound];
|
||||
const funding = val * percShares * roundMultiplier;
|
||||
const investShares = Math.floor(corpConstants.initialShares * percShares);
|
||||
return {
|
||||
funds: funding,
|
||||
shares: investShares,
|
||||
round: this.fundingRound + 1, // Make more readable
|
||||
};
|
||||
}
|
||||
|
||||
convertCooldownToString(cd: number): string {
|
||||
// The cooldown value is based on game cycles. Convert to a simple string
|
||||
const seconds = cd / 5;
|
||||
@@ -291,7 +360,7 @@ export class Corporation {
|
||||
if (this.unlocks.has(unlockName)) return `The corporation has already unlocked ${unlockName}`;
|
||||
const price = CorpUnlocks[unlockName].price;
|
||||
if (this.funds < price) return `Insufficient funds to purchase ${unlockName}, requires ${formatMoney(price)}`;
|
||||
this.funds -= price;
|
||||
this.addNonIncomeFunds(-price);
|
||||
this.unlocks.add(unlockName);
|
||||
|
||||
// Apply effects for one-time unlocks
|
||||
@@ -308,7 +377,7 @@ export class Corporation {
|
||||
const upgrade = CorpUpgrades[upgradeName];
|
||||
const totalCost = calculateUpgradeCost(this, upgrade, amount);
|
||||
if (this.funds < totalCost) return `Not enough funds to purchase ${amount} of upgrade ${upgradeName}.`;
|
||||
this.funds -= totalCost;
|
||||
this.addNonIncomeFunds(-totalCost);
|
||||
this.upgrades[upgradeName].level += amount;
|
||||
this.upgrades[upgradeName].value += upgrade.benefit * amount;
|
||||
|
||||
|
||||
@@ -33,7 +33,7 @@ export class Division {
|
||||
// Not included in save file. Just used for tracking whether research tree has been updated since game load.
|
||||
treeInitialized = false;
|
||||
|
||||
//An array of the name of materials being produced
|
||||
/** An array of the name of materials being produced */
|
||||
producedMaterials: CorpMaterialName[] = [];
|
||||
|
||||
products = new JSONMap<string, Product>();
|
||||
@@ -101,7 +101,7 @@ export class Division {
|
||||
// Loading data based on this division's industry type
|
||||
const data = IndustriesData[this.type];
|
||||
this.startingCost = data.startingCost;
|
||||
this.makesProducts = data.product ? true : false;
|
||||
this.makesProducts = data.makesProducts;
|
||||
this.realEstateFactor = data.realEstateFactor ?? 0;
|
||||
this.researchFactor = data.scienceFactor ?? 0;
|
||||
this.hardwareFactor = data.hardwareFactor ?? 0;
|
||||
@@ -311,6 +311,7 @@ export class Division {
|
||||
buyAmt = Math.min(buyAmt, maxAmt);
|
||||
if (buyAmt > 0) {
|
||||
mat.quality = Math.max(0.1, (mat.quality * mat.stored + 1 * buyAmt) / (mat.stored + buyAmt));
|
||||
mat.averagePrice = (mat.stored * mat.averagePrice + buyAmt * mat.marketPrice) / (mat.stored + buyAmt);
|
||||
mat.stored += buyAmt;
|
||||
expenses += buyAmt * mat.marketPrice;
|
||||
}
|
||||
@@ -364,8 +365,13 @@ export class Division {
|
||||
// buy them
|
||||
for (const [matName, [buyAmt]] of getRecordEntries(smartBuy)) {
|
||||
const mat = warehouse.materials[matName];
|
||||
if (mat.stored + buyAmt != 0) mat.quality = (mat.quality * mat.stored + 1 * buyAmt) / (mat.stored + buyAmt);
|
||||
else mat.quality = 1;
|
||||
if (mat.stored + buyAmt != 0) {
|
||||
mat.quality = (mat.quality * mat.stored + 1 * buyAmt) / (mat.stored + buyAmt);
|
||||
mat.averagePrice = (mat.averagePrice * mat.stored + mat.marketPrice * buyAmt) / (mat.stored + buyAmt);
|
||||
} else {
|
||||
mat.quality = 1;
|
||||
mat.averagePrice = mat.marketPrice;
|
||||
}
|
||||
mat.stored += buyAmt;
|
||||
mat.buyAmount = buyAmt / (corpConstants.secondsPerMarketCycle * marketCycles);
|
||||
expenses += buyAmt * mat.marketPrice;
|
||||
@@ -460,6 +466,11 @@ export class Division {
|
||||
tempQlt * prod * producableFrac) /
|
||||
(warehouse.materials[this.producedMaterials[j]].stored + prod * producableFrac),
|
||||
);
|
||||
warehouse.materials[this.producedMaterials[j]].averagePrice =
|
||||
(warehouse.materials[this.producedMaterials[j]].averagePrice *
|
||||
warehouse.materials[this.producedMaterials[j]].stored +
|
||||
warehouse.materials[this.producedMaterials[j]].marketPrice * prod * producableFrac) /
|
||||
(warehouse.materials[this.producedMaterials[j]].stored + prod * producableFrac);
|
||||
warehouse.materials[this.producedMaterials[j]].stored += prod * producableFrac;
|
||||
}
|
||||
} else {
|
||||
@@ -553,7 +564,8 @@ export class Division {
|
||||
sCost = optimalPrice;
|
||||
} else if (mat.marketTa1) {
|
||||
sCost = mat.marketPrice + markupLimit;
|
||||
} else if (isString(mat.desiredSellPrice)) {
|
||||
// check truthyness to avoid unnecessary eval
|
||||
} else if (isString(mat.desiredSellPrice) && mat.desiredSellPrice) {
|
||||
sCost = mat.desiredSellPrice.replace(/MP/g, mat.marketPrice.toString());
|
||||
sCost = eval(sCost);
|
||||
} else {
|
||||
@@ -677,6 +689,10 @@ export class Division {
|
||||
(expWarehouse.materials[matName].stored + amt),
|
||||
);
|
||||
|
||||
expWarehouse.materials[matName].averagePrice =
|
||||
(expWarehouse.materials[matName].averagePrice * expWarehouse.materials[matName].stored +
|
||||
expWarehouse.materials[matName].marketPrice * amt) /
|
||||
(expWarehouse.materials[matName].stored + amt);
|
||||
expWarehouse.materials[matName].stored += amt;
|
||||
mat.stored -= amt;
|
||||
mat.exportedLastCycle += amt;
|
||||
|
||||
@@ -52,12 +52,15 @@ export class Material {
|
||||
// Cost / sec to buy this material. AKA Market Price
|
||||
marketPrice = 0;
|
||||
|
||||
// Average price paid for the material (accounted as marketPrice for produced/imported materials)
|
||||
averagePrice = 0;
|
||||
|
||||
/** null if there is no limit set on production. 0 actually limits production to 0. */
|
||||
productionLimit: number | null = null;
|
||||
|
||||
// Player inputs for sell price and amount.
|
||||
desiredSellAmount: string | number = 0;
|
||||
desiredSellPrice: string | number = 0;
|
||||
desiredSellPrice: string | number = "";
|
||||
|
||||
// Flags that signal whether automatic sale pricing through Market TA is enabled
|
||||
marketTa1 = false;
|
||||
|
||||
@@ -96,7 +96,7 @@ export class OfficeSpace {
|
||||
if (this.autoParty) {
|
||||
this.avgMorale = this.maxMorale;
|
||||
} else {
|
||||
// Each 5% multiplier gives an extra flat +1 to morale to make recovering from low morale easier.
|
||||
// Each 10% 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.avgMorale = ((this.avgMorale - reduction * Math.random()) * perfMult + increase) * this.partyMult;
|
||||
}
|
||||
|
||||
@@ -81,7 +81,7 @@ export class Product {
|
||||
/** Player input sell amount e.g. "MAX" */
|
||||
desiredSellAmount: 0 as number | string,
|
||||
/** Player input sell price e.g. "MP * 5" */
|
||||
desiredSellPrice: 0 as number | string,
|
||||
desiredSellPrice: "" as string | number,
|
||||
}));
|
||||
|
||||
/** How much warehouse space is occupied per unit of this product */
|
||||
|
||||
@@ -33,7 +33,7 @@ export const stateNames: CorpStateName[] = ["START", "PURCHASE", "PRODUCTION", "
|
||||
/** Names of all one-time corporation-wide unlocks */
|
||||
unlockNames: APIUnlockName[] = Object.values(CorpUnlockName),
|
||||
upgradeNames: APIUpgradeName[] = Object.values(CorpUpgradeName),
|
||||
/** Names of all reasearches common to all industries */
|
||||
/** Names of all researches common to all industries */
|
||||
researchNamesBase: CorpResearchName[] = Object.values(CorpBaseResearchName),
|
||||
/** Names of all researches only available to product industries */
|
||||
researchNamesProductOnly: CorpResearchName[] = Object.values(CorpProductResearchName),
|
||||
@@ -42,8 +42,8 @@ export const stateNames: CorpStateName[] = ["START", "PURCHASE", "PRODUCTION", "
|
||||
initialShares = 1e9,
|
||||
/** When selling large number of shares, price is dynamically updated for every batch of this amount */
|
||||
sharesPerPriceUpdate = 1e6,
|
||||
/** Cooldown for issue new shares cooldown in game cycles. 12 hours. */
|
||||
issueNewSharesCooldown = 216e3,
|
||||
/** Cooldown for issue new shares cooldown in game cycles. Initially 4 hours. */
|
||||
issueNewSharesCooldown = 72e3,
|
||||
/** Cooldown for selling shares in game cycles. 1 hour. */
|
||||
sellSharesCooldown = 18e3,
|
||||
teaCostPerEmployee = 500e3,
|
||||
|
||||
@@ -17,6 +17,8 @@ export const IndustriesData: Record<IndustryType, CorpIndustryData> = {
|
||||
advertisingFactor: 0.04,
|
||||
requiredMaterials: { Water: 0.5, Chemicals: 0.2 },
|
||||
producedMaterials: ["Plants", "Food"],
|
||||
makesMaterials: true,
|
||||
makesProducts: false,
|
||||
},
|
||||
[IndustryType.Spring]: {
|
||||
startingCost: 10e9,
|
||||
@@ -30,6 +32,8 @@ export const IndustriesData: Record<IndustryType, CorpIndustryData> = {
|
||||
advertisingFactor: 0.03,
|
||||
requiredMaterials: {},
|
||||
producedMaterials: ["Water"],
|
||||
makesMaterials: true,
|
||||
makesProducts: false,
|
||||
},
|
||||
[IndustryType.Refinery]: {
|
||||
startingCost: 50e9,
|
||||
@@ -43,6 +47,8 @@ export const IndustriesData: Record<IndustryType, CorpIndustryData> = {
|
||||
advertisingFactor: 0.04,
|
||||
requiredMaterials: { Ore: 1 },
|
||||
producedMaterials: ["Metal"],
|
||||
makesMaterials: true,
|
||||
makesProducts: false,
|
||||
},
|
||||
[IndustryType.Chemical]: {
|
||||
startingCost: 70e9,
|
||||
@@ -56,6 +62,8 @@ export const IndustriesData: Record<IndustryType, CorpIndustryData> = {
|
||||
advertisingFactor: 0.07,
|
||||
requiredMaterials: { Plants: 1, Water: 0.5 },
|
||||
producedMaterials: ["Chemicals"],
|
||||
makesMaterials: true,
|
||||
makesProducts: false,
|
||||
},
|
||||
[IndustryType.Computers]: {
|
||||
startingCost: 500e9,
|
||||
@@ -81,6 +89,8 @@ export const IndustriesData: Record<IndustryType, CorpIndustryData> = {
|
||||
advertisingFactor: 0.17,
|
||||
requiredMaterials: { Metal: 2 },
|
||||
producedMaterials: ["Hardware"],
|
||||
makesMaterials: true,
|
||||
makesProducts: true,
|
||||
},
|
||||
[IndustryType.Fishing]: {
|
||||
startingCost: 80e9,
|
||||
@@ -94,6 +104,8 @@ export const IndustriesData: Record<IndustryType, CorpIndustryData> = {
|
||||
advertisingFactor: 0.08,
|
||||
requiredMaterials: { Plants: 0.5 },
|
||||
producedMaterials: ["Food"],
|
||||
makesMaterials: true,
|
||||
makesProducts: false,
|
||||
},
|
||||
[IndustryType.Restaurant]: {
|
||||
startingCost: 10e9,
|
||||
@@ -116,6 +128,8 @@ export const IndustriesData: Record<IndustryType, CorpIndustryData> = {
|
||||
advertisingFactor: 0.25,
|
||||
realEstateFactor: 0.05,
|
||||
requiredMaterials: { Food: 0.5, Water: 0.5 },
|
||||
makesMaterials: false,
|
||||
makesProducts: true,
|
||||
},
|
||||
[IndustryType.Healthcare]: {
|
||||
startingCost: 750e9,
|
||||
@@ -140,6 +154,8 @@ export const IndustriesData: Record<IndustryType, CorpIndustryData> = {
|
||||
robotFactor: 0.1,
|
||||
aiCoreFactor: 0.1,
|
||||
requiredMaterials: { Robots: 10, "AI Cores": 5, Drugs: 5, Food: 5 },
|
||||
makesMaterials: false,
|
||||
makesProducts: true,
|
||||
},
|
||||
[IndustryType.Mining]: {
|
||||
startingCost: 300e9,
|
||||
@@ -153,6 +169,8 @@ export const IndustriesData: Record<IndustryType, CorpIndustryData> = {
|
||||
advertisingFactor: 0.06,
|
||||
requiredMaterials: { Hardware: 0.1 },
|
||||
producedMaterials: ["Ore", "Minerals"],
|
||||
makesMaterials: true,
|
||||
makesProducts: false,
|
||||
},
|
||||
[IndustryType.Pharmaceutical]: {
|
||||
startingCost: 200e9,
|
||||
@@ -178,6 +196,8 @@ export const IndustriesData: Record<IndustryType, CorpIndustryData> = {
|
||||
advertisingFactor: 0.16,
|
||||
requiredMaterials: { Chemicals: 2, Water: 0.5 },
|
||||
producedMaterials: ["Drugs"],
|
||||
makesMaterials: true,
|
||||
makesProducts: true,
|
||||
},
|
||||
[IndustryType.RealEstate]: {
|
||||
startingCost: 600e9,
|
||||
@@ -202,6 +222,8 @@ export const IndustriesData: Record<IndustryType, CorpIndustryData> = {
|
||||
hardwareFactor: 0.05,
|
||||
requiredMaterials: { Metal: 5, Plants: 1, Water: 2, Hardware: 4 },
|
||||
producedMaterials: ["Real Estate"],
|
||||
makesMaterials: true,
|
||||
makesProducts: true,
|
||||
},
|
||||
[IndustryType.Robotics]: {
|
||||
startingCost: 1e12,
|
||||
@@ -227,6 +249,8 @@ export const IndustriesData: Record<IndustryType, CorpIndustryData> = {
|
||||
hardwareFactor: 0.19,
|
||||
requiredMaterials: { Hardware: 5, "AI Cores": 3 },
|
||||
producedMaterials: ["Robots"],
|
||||
makesMaterials: true,
|
||||
makesProducts: true,
|
||||
},
|
||||
[IndustryType.Software]: {
|
||||
startingCost: 25e9,
|
||||
@@ -252,6 +276,8 @@ export const IndustriesData: Record<IndustryType, CorpIndustryData> = {
|
||||
robotFactor: 0.05,
|
||||
requiredMaterials: { Hardware: 0.5 },
|
||||
producedMaterials: ["AI Cores"],
|
||||
makesMaterials: true,
|
||||
makesProducts: true,
|
||||
},
|
||||
[IndustryType.Tobacco]: {
|
||||
startingCost: 20e9,
|
||||
@@ -274,6 +300,8 @@ export const IndustriesData: Record<IndustryType, CorpIndustryData> = {
|
||||
aiCoreFactor: 0.15,
|
||||
advertisingFactor: 0.2,
|
||||
requiredMaterials: { Plants: 1 },
|
||||
makesMaterials: false,
|
||||
makesProducts: true,
|
||||
},
|
||||
[IndustryType.Water]: {
|
||||
startingCost: 150e9,
|
||||
@@ -286,6 +314,8 @@ export const IndustriesData: Record<IndustryType, CorpIndustryData> = {
|
||||
advertisingFactor: 0.08,
|
||||
requiredMaterials: { Hardware: 0.1 },
|
||||
producedMaterials: ["Water"],
|
||||
makesMaterials: true,
|
||||
makesProducts: false,
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
import { PositiveInteger } from "../types";
|
||||
import { Player } from "@player";
|
||||
import { PositiveInteger, isPositiveInteger } from "../types";
|
||||
import { formatShares } from "../ui/formatNumber";
|
||||
import { Corporation } from "./Corporation";
|
||||
import { CorpUpgrade } from "./data/CorporationUpgrades";
|
||||
|
||||
@@ -29,3 +31,43 @@ export function calculateMaxAffordableUpgrade(corp: Corporation, upgrade: CorpUp
|
||||
const sanitizedValue = maxAffordableUpgrades >= 0 ? maxAffordableUpgrades : 0;
|
||||
return sanitizedValue as PositiveInteger | 0;
|
||||
}
|
||||
|
||||
/** Returns a string representing the reason a share sale should fail, or empty string if there is no issue. */
|
||||
export function sellSharesFailureReason(corp: Corporation, numShares: number): string {
|
||||
if (!isPositiveInteger(numShares)) return "Number of shares must be a positive integer.";
|
||||
else if (numShares > corp.numShares) return "You do not have that many shares to sell.";
|
||||
else if (numShares === corp.numShares) return "You cannot sell all your shares.";
|
||||
else if (numShares > 1e14) return `Cannot sell more than ${formatShares(1e14)} shares at a time.`;
|
||||
else if (!corp.public) return "Cannot sell shares before going public.";
|
||||
else if (corp.shareSaleCooldown)
|
||||
return `Cannot sell shares for another ${corp.convertCooldownToString(corp.shareSaleCooldown)}.`;
|
||||
return "";
|
||||
}
|
||||
|
||||
/** Returns a string representing the reason a share buyback should fail, or empty string if there is no issue. */
|
||||
export function buybackSharesFailureReason(corp: Corporation, numShares: number): string {
|
||||
if (!isPositiveInteger(numShares)) return "Number of shares must be a positive integer.";
|
||||
if (numShares > corp.issuedShares) return "Not enough shares are available for buyback.";
|
||||
if (numShares > 1e14) return `Cannot buy more than ${formatShares(1e14)} shares at a time.`;
|
||||
if (!corp.public) return "Cannot buy back shares before going public.";
|
||||
|
||||
const [cost] = corp.calculateShareBuyback(numShares);
|
||||
if (Player.money < cost) return "You cannot afford that many shares.";
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
/** Returns a string representing the reason issuing new shares should fail, or empty string if there is no issue. */
|
||||
export function issueNewSharesFailureReason(corp: Corporation, numShares: number): string {
|
||||
if (!isPositiveInteger(numShares)) return "Number of shares must be a positive integer.";
|
||||
if (numShares % 10e6 !== 0) return "Number of shares must be a multiple of 10 million.";
|
||||
if (!corp.public) return "Cannot issue new shares before going public.";
|
||||
|
||||
const maxNewShares = corp.calculateMaxNewShares();
|
||||
if (numShares > maxNewShares) return `Number of shares cannot exceed ${maxNewShares} (20% of total shares).`;
|
||||
|
||||
const cooldown = corp.issueNewSharesCooldown;
|
||||
if (cooldown > 0) return `Cannot issue new shares for another ${corp.convertCooldownToString(cooldown)}.`;
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
@@ -58,23 +58,23 @@ function WarehouseRoot(props: WarehouseProps): React.ReactElement {
|
||||
props.rerender();
|
||||
}
|
||||
|
||||
// Current State:
|
||||
// Next state which will be processed:
|
||||
let stateText;
|
||||
switch (division.state) {
|
||||
case "START":
|
||||
stateText = "Current state: Preparing...";
|
||||
stateText = "Next state: Preparing";
|
||||
break;
|
||||
case "PURCHASE":
|
||||
stateText = "Current state: Purchasing materials...";
|
||||
stateText = "Next state: Purchasing materials";
|
||||
break;
|
||||
case "PRODUCTION":
|
||||
stateText = "Current state: Producing materials and/or products...";
|
||||
stateText = "Next state: Producing materials and/or products";
|
||||
break;
|
||||
case "SALE":
|
||||
stateText = "Current state: Selling materials and/or products...";
|
||||
stateText = "Next state: Selling materials and/or products";
|
||||
break;
|
||||
case "EXPORT":
|
||||
stateText = "Current state: Exporting materials and/or products...";
|
||||
stateText = "Next state: Exporting materials and/or products";
|
||||
break;
|
||||
default:
|
||||
console.error(`Invalid state: ${division.state}`);
|
||||
|
||||
@@ -6,10 +6,9 @@ import { CityName, CorpUnlockName } from "@enums";
|
||||
import { Material } from "../Material";
|
||||
import { Warehouse } from "../Warehouse";
|
||||
import { ExportModal } from "./modals/ExportModal";
|
||||
import { MaterialMarketTaModal } from "./modals/MaterialMarketTaModal";
|
||||
import { SellMaterialModal } from "./modals/SellMaterialModal";
|
||||
import { PurchaseMaterialModal } from "./modals/PurchaseMaterialModal";
|
||||
import { formatBigNumber, formatCorpStat, formatMoney, formatQuality } from "../../ui/formatNumber";
|
||||
import { formatBigNumber, formatCorpStat, formatQuality } from "../../ui/formatNumber";
|
||||
import { isString } from "../../utils/helpers/string";
|
||||
import { Money } from "../../ui/React/Money";
|
||||
import { useCorporation, useDivision } from "./Context";
|
||||
@@ -29,7 +28,6 @@ export function MaterialElem(props: IMaterialProps): React.ReactElement {
|
||||
const [purchaseMaterialOpen, setPurchaseMaterialOpen] = useState(false);
|
||||
const [exportOpen, setExportOpen] = useState(false);
|
||||
const [sellMaterialOpen, setSellMaterialOpen] = useState(false);
|
||||
const [materialMarketTaOpen, setMaterialMarketTaOpen] = useState(false);
|
||||
const [limitProductionOpen, setLimitProductionOpen] = useState(false);
|
||||
|
||||
const warehouse = props.warehouse;
|
||||
@@ -120,7 +118,9 @@ export function MaterialElem(props: IMaterialProps): React.ReactElement {
|
||||
</Typography>
|
||||
}
|
||||
>
|
||||
<Typography>MP: {formatMoney(mat.marketPrice)}</Typography>
|
||||
<Typography>
|
||||
MP: <Money money={mat.marketPrice} />
|
||||
</Typography>
|
||||
</Tooltip>
|
||||
<Tooltip
|
||||
title={<Typography>The quality of your material. Higher quality will lead to more sales</Typography>}
|
||||
@@ -159,18 +159,12 @@ export function MaterialElem(props: IMaterialProps): React.ReactElement {
|
||||
>
|
||||
{sellButtonText}
|
||||
</Button>
|
||||
<SellMaterialModal mat={mat} open={sellMaterialOpen} onClose={() => setSellMaterialOpen(false)} />
|
||||
{division.hasResearch("Market-TA.I") && (
|
||||
<>
|
||||
<Button onClick={() => setMaterialMarketTaOpen(true)}>Market-TA</Button>
|
||||
|
||||
<MaterialMarketTaModal
|
||||
mat={mat}
|
||||
open={materialMarketTaOpen}
|
||||
onClose={() => setMaterialMarketTaOpen(false)}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
<SellMaterialModal
|
||||
mat={mat}
|
||||
div={division}
|
||||
open={sellMaterialOpen}
|
||||
onClose={() => setSellMaterialOpen(false)}
|
||||
/>
|
||||
<Button color={tutorial ? "error" : "primary"} onClick={() => setLimitProductionOpen(true)}>
|
||||
{limitMaterialButtonText}
|
||||
</Button>
|
||||
|
||||
@@ -62,6 +62,7 @@ export function Overview({ rerender }: IProps): React.ReactElement {
|
||||
<StatsTable
|
||||
rows={[
|
||||
["Total Funds:", <Money key="funds" money={corp.funds} />],
|
||||
["Total Assets:", <Money key="assets" money={corp.totalAssets} />],
|
||||
["Total Revenue:", <MoneyRate key="revenue" money={corp.revenue} />],
|
||||
["Total Expenses:", <MoneyRate key="expenses" money={corp.expenses} />],
|
||||
["Total Profit:", <MoneyRate key="profit" money={corp.revenue - corp.expenses} />],
|
||||
@@ -76,8 +77,21 @@ export function Overview({ rerender }: IProps): React.ReactElement {
|
||||
title={
|
||||
<StatsTable
|
||||
rows={[
|
||||
["Outstanding Shares:", formatShares(corp.issuedShares)],
|
||||
["Private Shares:", formatShares(corp.totalShares - corp.issuedShares - corp.numShares)],
|
||||
[
|
||||
"Owned Stock Shares:",
|
||||
<> {formatShares(corp.numShares)} </>,
|
||||
<>({formatPercent(corp.numShares / corp.totalShares)})</>,
|
||||
],
|
||||
[
|
||||
"Outstanding Shares:",
|
||||
<> {formatShares(corp.issuedShares)} </>,
|
||||
<>({formatPercent(corp.issuedShares / corp.totalShares)})</>,
|
||||
],
|
||||
[
|
||||
"Private Shares:",
|
||||
<> {formatShares(corp.investorShares)} </>,
|
||||
<>({formatPercent(corp.investorShares / corp.totalShares)})</>,
|
||||
],
|
||||
]}
|
||||
/>
|
||||
}
|
||||
@@ -95,8 +109,8 @@ export function Overview({ rerender }: IProps): React.ReactElement {
|
||||
<ButtonWithTooltip
|
||||
normalTooltip={
|
||||
<>
|
||||
Get a copy of and read 'The Complete Handbook for Creating a Successful Corporation.' This is a .lit file
|
||||
that guides you through the beginning of setting up a Corporation and provides some tips/pointers for
|
||||
Get a copy of and read <i>The Complete Handbook for Creating a Successful Corporation</i>. This is a .lit
|
||||
file that guides you through the beginning of setting up a Corporation and provides some tips/pointers for
|
||||
helping you get started with managing it.
|
||||
</>
|
||||
}
|
||||
@@ -124,7 +138,7 @@ function PrivateButtons({ rerender }: IPrivateButtonsProps): React.ReactElement
|
||||
const [findInvestorsopen, setFindInvestorsopen] = useState(false);
|
||||
const [goPublicopen, setGoPublicopen] = useState(false);
|
||||
|
||||
const fundingAvailable = corp.fundingRound < 4;
|
||||
const fundingAvailable = corp.fundingRound < corpConstants.fundingRoundShares.length;
|
||||
const findInvestorsTooltip = fundingAvailable
|
||||
? "Search for private investors who will give you startup funding in exchange for equity (stock shares) in your company"
|
||||
: "";
|
||||
@@ -212,29 +226,27 @@ function PublicButtons({ rerender }: IPublicButtonsProps): React.ReactElement {
|
||||
const [issueDividendsOpen, setIssueDividendsOpen] = useState(false);
|
||||
|
||||
const sellSharesOnCd = corp.shareSaleCooldown > 0;
|
||||
const sellSharesTooltip = sellSharesOnCd
|
||||
? "Cannot sell shares for " + corp.convertCooldownToString(corp.shareSaleCooldown)
|
||||
: "Sell your shares in the company. The money earned from selling your " +
|
||||
"shares goes into your personal account, not the Corporation's. " +
|
||||
"This is one of the only ways to profit from your business venture.";
|
||||
const sellSharesTooltip =
|
||||
"Sell your shares in the company. The money earned from selling your " +
|
||||
"shares goes into your personal account, not the Corporation's. " +
|
||||
"This is one of the only ways to profit from your business venture.";
|
||||
|
||||
const issueNewSharesOnCd = corp.issueNewSharesCooldown > 0;
|
||||
const issueNewSharesTooltip = issueNewSharesOnCd
|
||||
? "Cannot issue new shares for " + corp.convertCooldownToString(corp.issueNewSharesCooldown)
|
||||
: "Issue new equity shares to raise capital.";
|
||||
|
||||
return (
|
||||
<>
|
||||
<ButtonWithTooltip
|
||||
normalTooltip={sellSharesTooltip}
|
||||
disabledTooltip={sellSharesOnCd ? "On cooldown" : ""}
|
||||
disabledTooltip={
|
||||
sellSharesOnCd ? "Cannot sell shares for " + corp.convertCooldownToString(corp.shareSaleCooldown) : ""
|
||||
}
|
||||
onClick={() => setSellSharesOpen(true)}
|
||||
>
|
||||
Sell Shares
|
||||
</ButtonWithTooltip>
|
||||
<SellSharesModal open={sellSharesOpen} onClose={() => setSellSharesOpen(false)} rerender={rerender} />
|
||||
<ButtonWithTooltip
|
||||
normalTooltip={"Buy back shares you that previously issued or sold at market price."}
|
||||
normalTooltip={"Buy back shares you that previously issued or sold on the market"}
|
||||
disabledTooltip={corp.issuedShares < 1 ? "No shares available to buy back" : ""}
|
||||
onClick={() => setBuybackSharesOpen(true)}
|
||||
>
|
||||
@@ -242,13 +254,15 @@ function PublicButtons({ rerender }: IPublicButtonsProps): React.ReactElement {
|
||||
</ButtonWithTooltip>
|
||||
<BuybackSharesModal open={buybackSharesOpen} onClose={() => setBuybackSharesOpen(false)} rerender={rerender} />
|
||||
<ButtonWithTooltip
|
||||
normalTooltip={issueNewSharesTooltip}
|
||||
disabledTooltip={issueNewSharesOnCd ? "On cooldown" : ""}
|
||||
normalTooltip={"Issue new equity shares to raise capital"}
|
||||
disabledTooltip={
|
||||
issueNewSharesOnCd ? `On cooldown for ${corp.convertCooldownToString(corp.issueNewSharesCooldown)}` : ""
|
||||
}
|
||||
onClick={() => setIssueNewSharesOpen(true)}
|
||||
>
|
||||
Issue New Shares
|
||||
</ButtonWithTooltip>
|
||||
<IssueNewSharesModal open={issueNewSharesOpen} onClose={() => setIssueNewSharesOpen(false)} />
|
||||
<IssueNewSharesModal open={issueNewSharesOpen} onClose={() => setIssueNewSharesOpen(false)} rerender={rerender} />
|
||||
<ButtonWithTooltip
|
||||
normalTooltip={"Manage the dividends that are paid out to shareholders (including yourself)"}
|
||||
onClick={() => setIssueDividendsOpen(true)}
|
||||
@@ -305,13 +319,22 @@ function SellDivisionButton(): React.ReactElement {
|
||||
function RestartButton(): React.ReactElement {
|
||||
const [open, setOpen] = useState(false);
|
||||
|
||||
const corp = useCorporation();
|
||||
const sellSharesOnCd = corp.shareSaleCooldown > 0;
|
||||
|
||||
function restart(): void {
|
||||
setOpen(true);
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<ButtonWithTooltip normalTooltip={"Sell corporation and start over"} onClick={restart}>
|
||||
<ButtonWithTooltip
|
||||
normalTooltip={"Sell corporation and start over"}
|
||||
disabledTooltip={
|
||||
sellSharesOnCd ? "Sell corporation and start over. Cannot do this while Sell Shares is on cooldown." : ""
|
||||
}
|
||||
onClick={restart}
|
||||
>
|
||||
Sell CEO position
|
||||
</ButtonWithTooltip>
|
||||
<SellCorporationModal open={open} onClose={() => setOpen(false)} />
|
||||
|
||||
@@ -6,10 +6,9 @@ import { Product } from "../Product";
|
||||
import { DiscontinueProductModal } from "./modals/DiscontinueProductModal";
|
||||
import { LimitProductProductionModal } from "./modals/LimitProductProductionModal";
|
||||
import { SellProductModal } from "./modals/SellProductModal";
|
||||
import { ProductMarketTaModal } from "./modals/ProductMarketTaModal";
|
||||
import { CancelProductModal } from "./modals/CancelProductModal";
|
||||
|
||||
import { formatBigNumber, formatCorpStat, formatMoney, formatPercent } from "../../ui/formatNumber";
|
||||
import { formatBigNumber, formatPercent } from "../../ui/formatNumber";
|
||||
|
||||
import { isString } from "../../utils/helpers/string";
|
||||
import { Money } from "../../ui/React/Money";
|
||||
@@ -29,7 +28,6 @@ export function ProductElem(props: IProductProps): React.ReactElement {
|
||||
const [limitOpen, setLimitOpen] = useState(false);
|
||||
const [discontinueOpen, setDiscontinueOpen] = useState(false);
|
||||
const [cancelOpen, setCancelOpen] = useState(false);
|
||||
const [marketTaOpen, setMarketTaOpen] = useState(false);
|
||||
const city = props.city;
|
||||
const product = props.product;
|
||||
|
||||
@@ -67,7 +65,7 @@ export function ProductElem(props: IProductProps): React.ReactElement {
|
||||
// Limit Production button
|
||||
const productionLimit = product.cityData[city].productionLimit;
|
||||
const limitProductionButtonText =
|
||||
"Limit Production" + (productionLimit !== null ? " (" + formatCorpStat(productionLimit) + ")" : "");
|
||||
"Limit Production" + (productionLimit !== null ? " (" + formatBigNumber(productionLimit) + ")" : "");
|
||||
|
||||
return (
|
||||
<Paper>
|
||||
@@ -109,35 +107,35 @@ export function ProductElem(props: IProductProps): React.ReactElement {
|
||||
title={
|
||||
<Typography>
|
||||
Effective rating is calculated from product rating and the quality of materials used <br />
|
||||
Rating: {formatCorpStat(product.rating)} <br /> <br />
|
||||
Quality: {formatCorpStat(product.stats.quality)} <br />
|
||||
Performance: {formatCorpStat(product.stats.performance)} <br />
|
||||
Durability: {formatCorpStat(product.stats.durability)} <br />
|
||||
Reliability: {formatCorpStat(product.stats.reliability)} <br />
|
||||
Aesthetics: {formatCorpStat(product.stats.aesthetics)} <br />
|
||||
Features: {formatCorpStat(product.stats.features)}
|
||||
Rating: {formatBigNumber(product.rating)} <br /> <br />
|
||||
Quality: {formatBigNumber(product.stats.quality)} <br />
|
||||
Performance: {formatBigNumber(product.stats.performance)} <br />
|
||||
Durability: {formatBigNumber(product.stats.durability)} <br />
|
||||
Reliability: {formatBigNumber(product.stats.reliability)} <br />
|
||||
Aesthetics: {formatBigNumber(product.stats.aesthetics)} <br />
|
||||
Features: {formatBigNumber(product.stats.features)}
|
||||
{corp.unlocks.has(CorpUnlockName.MarketResearchDemand) && (
|
||||
<>
|
||||
<br />
|
||||
{"Demand: " + formatCorpStat(product.demand)}
|
||||
{"Demand: " + formatBigNumber(product.demand)}
|
||||
</>
|
||||
)}
|
||||
{corp.unlocks.has(CorpUnlockName.MarketDataCompetition) && (
|
||||
<>
|
||||
<br />
|
||||
{"Competition: " + formatCorpStat(product.competition)}
|
||||
{"Competition: " + formatBigNumber(product.competition)}
|
||||
</>
|
||||
)}
|
||||
</Typography>
|
||||
}
|
||||
>
|
||||
<Typography>Effective rating: {formatCorpStat(product.cityData[city].effectiveRating)}</Typography>
|
||||
<Typography>Effective rating: {formatBigNumber(product.cityData[city].effectiveRating)}</Typography>
|
||||
</Tooltip>
|
||||
</Box>
|
||||
<Box display="flex">
|
||||
<Tooltip title={<Typography>An estimate of the material cost it takes to create this Product.</Typography>}>
|
||||
<Typography>
|
||||
Est. Production Cost: {formatMoney(product.productionCost / corpConstants.baseProductProfitMult)}
|
||||
Est. Production Cost: <Money money={product.productionCost / corpConstants.baseProductProfitMult} />
|
||||
</Typography>
|
||||
</Tooltip>
|
||||
</Box>
|
||||
@@ -150,7 +148,9 @@ export function ProductElem(props: IProductProps): React.ReactElement {
|
||||
</Typography>
|
||||
}
|
||||
>
|
||||
<Typography>Est. Market Price: {formatMoney(product.productionCost)}</Typography>
|
||||
<Typography>
|
||||
Est. Market Price: <Money money={product.productionCost} />
|
||||
</Typography>
|
||||
</Tooltip>
|
||||
</Box>
|
||||
<Button onClick={() => setDiscontinueOpen(true)}>Discontinue</Button>
|
||||
@@ -166,7 +166,13 @@ export function ProductElem(props: IProductProps): React.ReactElement {
|
||||
{(hasUpgradeDashboard || product.finished) && (
|
||||
<>
|
||||
<Button onClick={() => setSellOpen(true)}>{sellButtonText}</Button>
|
||||
<SellProductModal product={product} city={city} open={sellOpen} onClose={() => setSellOpen(false)} />
|
||||
<SellProductModal
|
||||
product={product}
|
||||
div={division}
|
||||
city={city}
|
||||
open={sellOpen}
|
||||
onClose={() => setSellOpen(false)}
|
||||
/>
|
||||
<br />
|
||||
<Button onClick={() => setLimitOpen(true)}>{limitProductionButtonText}</Button>
|
||||
<LimitProductProductionModal
|
||||
@@ -175,12 +181,6 @@ export function ProductElem(props: IProductProps): React.ReactElement {
|
||||
open={limitOpen}
|
||||
onClose={() => setLimitOpen(false)}
|
||||
/>
|
||||
{division.hasResearch("Market-TA.I") && (
|
||||
<>
|
||||
<Button onClick={() => setMarketTaOpen(true)}>Market-TA</Button>
|
||||
<ProductMarketTaModal product={product} open={marketTaOpen} onClose={() => setMarketTaOpen(false)} />
|
||||
</>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
</Paper>
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
import React, { useState } from "react";
|
||||
import { dialogBoxCreate } from "../../../ui/React/DialogBox";
|
||||
import { Modal } from "../../../ui/React/Modal";
|
||||
import { formatBigNumber, formatMoney } from "../../../ui/formatNumber";
|
||||
import { Player } from "@player";
|
||||
import { Money } from "../../../ui/React/Money";
|
||||
import { formatShares } from "../../../ui/formatNumber";
|
||||
import { useCorporation } from "../Context";
|
||||
import Typography from "@mui/material/Typography";
|
||||
import { ButtonWithTooltip } from "../../../ui/Components/ButtonWithTooltip";
|
||||
import { NumberInput } from "../../../ui/React/NumberInput";
|
||||
import { BuyBackShares } from "../../Actions";
|
||||
import { dialogBoxCreate } from "../../../ui/React/DialogBox";
|
||||
import { KEY } from "../../../utils/helpers/keyCodes";
|
||||
import { isPositiveInteger } from "../../../types";
|
||||
import { buybackSharesFailureReason } from "../../helpers";
|
||||
|
||||
interface IProps {
|
||||
open: boolean;
|
||||
@@ -23,44 +23,28 @@ export function BuybackSharesModal(props: IProps): React.ReactElement {
|
||||
const corp = useCorporation();
|
||||
const [shares, setShares] = useState<number>(NaN);
|
||||
|
||||
const currentStockPrice = corp.sharePrice;
|
||||
const buybackPrice = currentStockPrice * 1.1;
|
||||
const disabledText = !isPositiveInteger(shares)
|
||||
? "Number of shares must be a positive integer"
|
||||
: shares > corp.issuedShares
|
||||
? "There are not enough shares available to buyback this many"
|
||||
: shares * buybackPrice > Player.money
|
||||
? "Insufficient player funds"
|
||||
: "";
|
||||
const [cost, sharePrice] = corp.calculateShareBuyback((props.open && shares) || 0);
|
||||
const disabledText = buybackSharesFailureReason(corp, shares);
|
||||
|
||||
function buy(): void {
|
||||
if (disabledText) return;
|
||||
try {
|
||||
BuyBackShares(corp, shares);
|
||||
dialogBoxCreate(
|
||||
<>
|
||||
<Typography>
|
||||
You bought {formatShares(shares)} shares for <Money money={cost} />.
|
||||
</Typography>
|
||||
<Typography>
|
||||
<b>{corp.name}</b>'s stock price rose to <Money money={sharePrice} /> per share.
|
||||
</Typography>
|
||||
</>,
|
||||
);
|
||||
props.onClose();
|
||||
props.rerender();
|
||||
setShares(NaN);
|
||||
} catch (err) {
|
||||
dialogBoxCreate(err + "");
|
||||
}
|
||||
props.onClose();
|
||||
props.rerender();
|
||||
}
|
||||
|
||||
function CostIndicator(): React.ReactElement {
|
||||
if (shares === null) return <></>;
|
||||
if (isNaN(shares) || shares <= 0) {
|
||||
return <>ERROR: Invalid value entered for number of shares to buyback</>;
|
||||
} else if (shares > corp.issuedShares) {
|
||||
return (
|
||||
<>
|
||||
There are not this many shares available to buy back. There are only {formatBigNumber(corp.issuedShares)}{" "}
|
||||
outstanding shares.
|
||||
</>
|
||||
);
|
||||
} else {
|
||||
return (
|
||||
<>
|
||||
Purchase {shares} shares for a total of {formatMoney(shares * buybackPrice)}
|
||||
</>
|
||||
);
|
||||
dialogBoxCreate(`${err}`);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -70,23 +54,45 @@ export function BuybackSharesModal(props: IProps): React.ReactElement {
|
||||
|
||||
return (
|
||||
<Modal open={props.open} onClose={props.onClose}>
|
||||
<Typography>
|
||||
Enter the number of outstanding shares you would like to buy back. These shares must be bought at a 10% premium.
|
||||
However, repurchasing shares from the market tends to lead to an increase in stock price.
|
||||
<br />
|
||||
<br />
|
||||
To purchase these shares, you must use your own money (NOT your Corporation's funds).
|
||||
<br />
|
||||
<br />
|
||||
The current buyback price of your company's stock is {formatMoney(buybackPrice)}. Your company currently has{" "}
|
||||
{formatBigNumber(corp.issuedShares)} outstanding stock shares.
|
||||
<Typography component="div">
|
||||
Enter the number of outstanding shares you would like to buy back.
|
||||
<ul>
|
||||
<li>Buying back shares will cause the stock price to rise due to market forces.</li>
|
||||
<li>These shares must be bought at a 10% premium over the market price.</li>
|
||||
<li>You purchase these shares with your own money (NOT your Corporation's funds).</li>
|
||||
</ul>
|
||||
<b>{corp.name}</b> currently has {formatShares(corp.issuedShares)} outstanding stock shares, valued at{" "}
|
||||
<Money money={corp.sharePrice} /> per share.
|
||||
</Typography>
|
||||
<CostIndicator />
|
||||
<br />
|
||||
<NumberInput autoFocus={true} placeholder="Shares to buyback" onChange={setShares} onKeyDown={onKeyDown} />
|
||||
<NumberInput
|
||||
defaultValue={shares || ""}
|
||||
autoFocus={true}
|
||||
placeholder="Shares to buyback"
|
||||
onChange={setShares}
|
||||
onKeyDown={onKeyDown}
|
||||
/>
|
||||
<ButtonWithTooltip disabledTooltip={disabledText} onClick={buy}>
|
||||
Buy shares
|
||||
{cost > 0 ? (
|
||||
<>
|
||||
-
|
||||
<Money money={cost} forPurchase={true} />{" "}
|
||||
</>
|
||||
) : (
|
||||
<></>
|
||||
)}
|
||||
</ButtonWithTooltip>
|
||||
<br />
|
||||
<Typography sx={{ minHeight: "1.5em" }}>
|
||||
{!shares ? null : disabledText ? (
|
||||
disabledText
|
||||
) : (
|
||||
<>
|
||||
<b>{corp.name}</b>'s stock price will rise to <Money money={sharePrice} /> per share.
|
||||
</>
|
||||
)}
|
||||
</Typography>
|
||||
</Modal>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ import { Money } from "../../../ui/React/Money";
|
||||
import { Modal } from "../../../ui/React/Modal";
|
||||
import { Router } from "../../../ui/GameRoot";
|
||||
import { Page } from "../../../ui/Router";
|
||||
import { formatShares } from "../../../ui/formatNumber";
|
||||
import { Player } from "@player";
|
||||
import Typography from "@mui/material/Typography";
|
||||
import { ButtonWithTooltip } from "../../../ui/Components/ButtonWithTooltip";
|
||||
@@ -54,15 +55,19 @@ export function CreateCorporationModal(props: IProps): React.ReactElement {
|
||||
return (
|
||||
<Modal open={props.open} onClose={props.onClose}>
|
||||
<Typography>
|
||||
Would you like to start a corporation? This will require $150b for registration and initial funding.{" "}
|
||||
{Player.bitNodeN === 3 &&
|
||||
`This $150b
|
||||
can either be self-funded, or you can obtain the seed money from the government in exchange for 500 million
|
||||
shares`}
|
||||
Would you like to start a corporation? This will require <Money money={150e9} forPurchase={true} /> for
|
||||
registration and initial funding.{" "}
|
||||
{Player.bitNodeN === 3 && (
|
||||
<>
|
||||
This <Money money={150e9} /> can either be self-funded, or you can obtain the seed money from the government
|
||||
in exchange for {formatShares(500e6)} shares (a <b>33.3%</b> stake in the company).
|
||||
</>
|
||||
)}
|
||||
<br />
|
||||
<br />
|
||||
If you would like to start one, please enter a name for your corporation below:
|
||||
</Typography>
|
||||
<br />
|
||||
<TextField autoFocus={true} placeholder="Corporation Name" onChange={onChange} value={name} />
|
||||
{Player.bitNodeN === 3 && (
|
||||
<ButtonWithTooltip onClick={seed} disabledTooltip={disabledTextForNoName}>
|
||||
@@ -71,7 +76,7 @@ export function CreateCorporationModal(props: IProps): React.ReactElement {
|
||||
)}
|
||||
<ButtonWithTooltip
|
||||
onClick={selfFund}
|
||||
disabledTooltip={disabledTextForNoName || canSelfFund ? "" : "Insufficient player funds"}
|
||||
disabledTooltip={disabledTextForNoName || (canSelfFund ? "" : "Insufficient player funds")}
|
||||
>
|
||||
Self-Fund (<Money money={150e9} forPurchase={true} />)
|
||||
</ButtonWithTooltip>
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
import React from "react";
|
||||
import { formatMoney, formatPercent, formatShares } from "../../../ui/formatNumber";
|
||||
import * as corpConstants from "../../data/Constants";
|
||||
import { dialogBoxCreate } from "../../../ui/React/DialogBox";
|
||||
import { formatPercent, formatShares } from "../../../ui/formatNumber";
|
||||
import { Modal } from "../../../ui/React/Modal";
|
||||
import { Money } from "../../../ui/React/Money";
|
||||
import { useCorporation } from "../Context";
|
||||
import { AcceptInvestmentOffer } from "../../Actions";
|
||||
|
||||
import Typography from "@mui/material/Typography";
|
||||
import Button from "@mui/material/Button";
|
||||
@@ -13,40 +15,52 @@ interface IProps {
|
||||
rerender: () => void;
|
||||
}
|
||||
|
||||
// Create a popup that lets the player manage exports
|
||||
// Create a popup that lets the player manage investment offers
|
||||
export function FindInvestorsModal(props: IProps): React.ReactElement {
|
||||
const corporation = useCorporation();
|
||||
const val = corporation.valuation;
|
||||
if (
|
||||
corporation.fundingRound >= corpConstants.fundingRoundShares.length ||
|
||||
corporation.fundingRound >= corpConstants.fundingRoundMultiplier.length
|
||||
)
|
||||
return <></>;
|
||||
const percShares = corpConstants.fundingRoundShares[corporation.fundingRound];
|
||||
const roundMultiplier = corpConstants.fundingRoundMultiplier[corporation.fundingRound];
|
||||
const funding = val * percShares * roundMultiplier;
|
||||
const investShares = Math.floor(corpConstants.initialShares * percShares);
|
||||
const corp = useCorporation();
|
||||
const { funds, shares } = corp.getInvestmentOffer();
|
||||
|
||||
function findInvestors(): void {
|
||||
corporation.fundingRound++;
|
||||
corporation.addFunds(funding);
|
||||
corporation.numShares -= investShares;
|
||||
props.rerender();
|
||||
props.onClose();
|
||||
if (shares === 0) return;
|
||||
try {
|
||||
AcceptInvestmentOffer(corp);
|
||||
dialogBoxCreate(
|
||||
<>
|
||||
<Typography>You accepted the investment offer.</Typography>
|
||||
<Typography>
|
||||
<b>{corp.name}</b> received <Money money={funds} />.
|
||||
</Typography>
|
||||
<Typography>
|
||||
Your remaining equity is <b>{formatPercent(corp.numShares / corp.totalShares, 1)}</b>.
|
||||
</Typography>
|
||||
</>,
|
||||
);
|
||||
props.onClose();
|
||||
props.rerender();
|
||||
} catch (err) {
|
||||
dialogBoxCreate(`${err}`);
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<Modal open={props.open} onClose={props.onClose}>
|
||||
<Typography>
|
||||
An investment firm has offered you {formatMoney(funding)} in funding in exchange for a{" "}
|
||||
{formatPercent(percShares, 3)} stake in the company ({formatShares(investShares)} shares).
|
||||
An investment firm has offered to buy {formatShares(shares)} shares of stock (a{" "}
|
||||
<b>{formatPercent(shares / corp.totalShares, 1)}</b> stake in the company).
|
||||
<br />
|
||||
<br />
|
||||
Do you accept or reject this offer?
|
||||
<b>{corp.name}</b> will receive <Money money={funds} />.
|
||||
<br />
|
||||
Your equity will fall to <b>{formatPercent((corp.numShares - shares) / corp.totalShares, 1)}</b>.
|
||||
<br />
|
||||
<br />
|
||||
Hint: Investment firms will offer more money if your corporation is turning a profit
|
||||
<b>Hint</b>: Investment firms will offer more money if your Corporation is turning a profit.
|
||||
<br />
|
||||
<br />
|
||||
Do you accept this offer?
|
||||
</Typography>
|
||||
<Button onClick={findInvestors}>Accept</Button>
|
||||
<br />
|
||||
<Button onClick={findInvestors}>Accept</Button> <Button onClick={props.onClose}>Ignore</Button>
|
||||
</Modal>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
import React, { useState } from "react";
|
||||
import { dialogBoxCreate } from "../../../ui/React/DialogBox";
|
||||
import { Modal } from "../../../ui/React/Modal";
|
||||
import { formatMoney, formatShares } from "../../../ui/formatNumber";
|
||||
import { Money } from "../../../ui/React/Money";
|
||||
import { formatShares } from "../../../ui/formatNumber";
|
||||
import { useCorporation } from "../Context";
|
||||
import Typography from "@mui/material/Typography";
|
||||
import { ButtonWithTooltip } from "../../../ui/Components/ButtonWithTooltip";
|
||||
@@ -9,6 +10,7 @@ import { NumberInput } from "../../../ui/React/NumberInput";
|
||||
import Box from "@mui/material/Box";
|
||||
import { KEY } from "../../../utils/helpers/keyCodes";
|
||||
import { isPositiveInteger } from "../../../types";
|
||||
import { GoPublic } from "../../Actions";
|
||||
|
||||
interface IProps {
|
||||
open: boolean;
|
||||
@@ -20,26 +22,9 @@ interface IProps {
|
||||
export function GoPublicModal(props: IProps): React.ReactElement {
|
||||
const corp = useCorporation();
|
||||
const [shares, setShares] = useState<number>(NaN);
|
||||
const initialSharePrice = corp.valuation / corp.totalShares;
|
||||
|
||||
function goPublic(): void {
|
||||
const initialSharePrice = corp.valuation / corp.totalShares;
|
||||
if (shares >= corp.numShares || (shares !== 0 && !isPositiveInteger(shares))) return;
|
||||
corp.public = true;
|
||||
corp.sharePrice = initialSharePrice;
|
||||
corp.issuedShares = shares;
|
||||
corp.numShares -= shares;
|
||||
corp.addFunds(shares * initialSharePrice);
|
||||
props.rerender();
|
||||
dialogBoxCreate(
|
||||
`You took your ${corp.name} public and earned ` + `${formatMoney(shares * initialSharePrice)} in your IPO`,
|
||||
);
|
||||
props.onClose();
|
||||
}
|
||||
|
||||
function onKeyDown(event: React.KeyboardEvent<HTMLInputElement>): void {
|
||||
if (event.key === KEY.ENTER) goPublic();
|
||||
}
|
||||
const ceoOwnership = (corp.numShares - (shares || 0)) / corp.totalShares;
|
||||
const initialSharePrice = corp.getTargetSharePrice(ceoOwnership);
|
||||
|
||||
const disabledText =
|
||||
shares >= corp.numShares
|
||||
@@ -48,22 +33,62 @@ export function GoPublicModal(props: IProps): React.ReactElement {
|
||||
? "Must issue an non-negative integer number of shares"
|
||||
: "";
|
||||
|
||||
function goPublic(): void {
|
||||
if (disabledText) return;
|
||||
try {
|
||||
GoPublic(corp, shares);
|
||||
dialogBoxCreate(
|
||||
<Typography>
|
||||
<b>{corp.name}</b> went public and earned <Money money={shares * initialSharePrice} /> in its IPO.
|
||||
</Typography>,
|
||||
);
|
||||
props.onClose();
|
||||
props.rerender();
|
||||
setShares(NaN);
|
||||
} catch (err) {
|
||||
dialogBoxCreate(`${err}`);
|
||||
}
|
||||
}
|
||||
|
||||
function onKeyDown(event: React.KeyboardEvent<HTMLInputElement>): void {
|
||||
if (event.key === KEY.ENTER) goPublic();
|
||||
}
|
||||
|
||||
return (
|
||||
<Modal open={props.open} onClose={props.onClose}>
|
||||
<Typography>
|
||||
Enter the number of shares you would like to issue for your IPO. These shares will be publicly sold and you will
|
||||
no longer own them. Your Corporation will receive {formatMoney(initialSharePrice)} per share (the IPO money will
|
||||
be deposited directly into your Corporation's funds).
|
||||
<br />
|
||||
<br />
|
||||
<Typography component="div">
|
||||
Enter the number of shares you would like to issue for your IPO.
|
||||
<ul>
|
||||
<li>These shares will be publicly sold and you will no longer own them.</li>
|
||||
<li>The IPO money will be deposited directly into your Corporation's funds.</li>
|
||||
</ul>
|
||||
You can issue some, but not all, of your {formatShares(corp.numShares)} shares.
|
||||
</Typography>
|
||||
<br />
|
||||
<Box display="flex" alignItems="center">
|
||||
<NumberInput onChange={setShares} autoFocus placeholder="Shares to issue" onKeyDown={onKeyDown} />
|
||||
<NumberInput
|
||||
defaultValue={shares || ""}
|
||||
onChange={setShares}
|
||||
autoFocus
|
||||
placeholder="Shares to issue"
|
||||
onKeyDown={onKeyDown}
|
||||
/>
|
||||
<ButtonWithTooltip disabledTooltip={disabledText} onClick={goPublic}>
|
||||
Go Public
|
||||
</ButtonWithTooltip>
|
||||
</Box>
|
||||
<br />
|
||||
<Typography sx={{ minHeight: "3em" }}>
|
||||
{isNaN(shares) ? null : disabledText ? (
|
||||
disabledText
|
||||
) : (
|
||||
<>
|
||||
Go public at <Money money={initialSharePrice} /> per share?
|
||||
<br />
|
||||
<b>{corp.name}</b> will receive <Money money={initialSharePrice * (shares || 0)} />.
|
||||
</>
|
||||
)}
|
||||
</Typography>
|
||||
</Modal>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
import React, { useState } from "react";
|
||||
import { dialogBoxCreate } from "../../../ui/React/DialogBox";
|
||||
import { Modal } from "../../../ui/React/Modal";
|
||||
import { Money } from "../../../ui/React/Money";
|
||||
import { MoneyRate } from "../../../ui/React/MoneyRate";
|
||||
import * as corpConstants from "../../data/Constants";
|
||||
import { IssueDividends } from "../../Actions";
|
||||
import { useCorporation } from "../Context";
|
||||
@@ -53,20 +55,19 @@ export function IssueDividendsModal(props: IProps): React.ReactElement {
|
||||
yourself, as well.
|
||||
<br />
|
||||
<br />
|
||||
In order to issue dividends, simply allocate some percentage of your corporation's profits to dividends. This
|
||||
percentage must be an integer between 0 and 100. (A percentage of 0 means no dividends will be issued)
|
||||
Note that issuing dividends will negatively affect <b>{corp.name}</b>'s stock price.
|
||||
<br />
|
||||
<br />
|
||||
Two important things to note:
|
||||
<br />
|
||||
* Issuing dividends will negatively affect your corporation's stock price
|
||||
In order to issue dividends, simply allocate some percentage of your Corporation's profits to dividends. This
|
||||
percentage must be an integer between 0 and 100. (A percentage of 0 means no dividends will be issued.)
|
||||
<br />
|
||||
<br />
|
||||
Example: Assume your corporation makes $100m / sec in profit and you allocate 40% of that towards dividends.
|
||||
That means your corporation will gain $60m / sec in funds and the remaining $40m / sec will be paid as
|
||||
dividends. Since your corporation starts with 1 billion shares, every shareholder will be paid $0.04 per share
|
||||
per second before taxes.
|
||||
<b>Example:</b> Assume your corporation makes <MoneyRate money={100e6} /> in profit and you allocate 40% of that
|
||||
towards dividends. That means your corporation will gain <MoneyRate money={60e6} /> in funds and the remaining{" "}
|
||||
<MoneyRate money={40e6} /> will be paid as dividends. Since your corporation starts with 1 billion shares, every
|
||||
shareholder will be paid <Money money={0.04} /> per share per second before taxes.
|
||||
</Typography>
|
||||
<br />
|
||||
<TextField
|
||||
autoFocus
|
||||
value={percent}
|
||||
|
||||
@@ -1,50 +1,21 @@
|
||||
import React, { useState } from "react";
|
||||
import { formatMoney, formatShares } from "../../../ui/formatNumber";
|
||||
import { formatShares, formatPercent } from "../../../ui/formatNumber";
|
||||
import { dialogBoxCreate } from "../../../ui/React/DialogBox";
|
||||
import { Modal } from "../../../ui/React/Modal";
|
||||
import { Money } from "../../../ui/React/Money";
|
||||
import { useCorporation } from "../Context";
|
||||
import Typography from "@mui/material/Typography";
|
||||
import { NumberInput } from "../../../ui/React/NumberInput";
|
||||
import Button from "@mui/material/Button";
|
||||
import { ButtonWithTooltip } from "../../../ui/Components/ButtonWithTooltip";
|
||||
import { KEY } from "../../../utils/helpers/keyCodes";
|
||||
import { IssueNewShares } from "../../Actions";
|
||||
|
||||
interface IEffectTextProps {
|
||||
shares: number | null;
|
||||
}
|
||||
|
||||
function EffectText(props: IEffectTextProps): React.ReactElement {
|
||||
const corp = useCorporation();
|
||||
if (props.shares === null) return <></>;
|
||||
const newSharePrice = Math.round(corp.sharePrice * 0.9);
|
||||
const maxNewShares = corp.calculateMaxNewShares();
|
||||
let newShares = props.shares;
|
||||
if (isNaN(newShares)) {
|
||||
return <Typography>Invalid input</Typography>;
|
||||
}
|
||||
|
||||
// Round to nearest ten-millionth
|
||||
newShares /= 10e6;
|
||||
newShares = Math.round(newShares) * 10e6;
|
||||
|
||||
if (newShares < 10e6) {
|
||||
return <Typography>Must issue at least 10 million new shares</Typography>;
|
||||
}
|
||||
|
||||
if (newShares > maxNewShares) {
|
||||
return <Typography>You cannot issue that many shares</Typography>;
|
||||
}
|
||||
|
||||
return (
|
||||
<Typography>
|
||||
Issue {formatShares(newShares)} new shares for {formatMoney(newShares * newSharePrice)}?
|
||||
</Typography>
|
||||
);
|
||||
}
|
||||
import * as corpConstants from "../../data/Constants";
|
||||
import { issueNewSharesFailureReason } from "../../helpers";
|
||||
|
||||
interface IProps {
|
||||
open: boolean;
|
||||
onClose: () => void;
|
||||
rerender: () => void;
|
||||
}
|
||||
|
||||
// Create a popup that lets the player issue new shares
|
||||
@@ -52,56 +23,103 @@ interface IProps {
|
||||
export function IssueNewSharesModal(props: IProps): React.ReactElement {
|
||||
const corp = useCorporation();
|
||||
const [shares, setShares] = useState<number>(NaN);
|
||||
const maxNewShares = corp.calculateMaxNewShares();
|
||||
|
||||
const maxNewShares = corp.calculateMaxNewShares();
|
||||
const newShares = Math.round((shares || 0) / 10e6) * 10e6;
|
||||
const disabled = isNaN(shares) || isNaN(newShares) || newShares < 10e6 || newShares > maxNewShares;
|
||||
|
||||
const ceoOwnership = corp.numShares / (corp.totalShares + (newShares || 0));
|
||||
const newSharePrice = corp.getTargetSharePrice(ceoOwnership);
|
||||
const profit = ((shares || 0) * (corp.sharePrice + newSharePrice)) / 2;
|
||||
|
||||
const privateOwnedRatio = corp.investorShares / corp.totalShares;
|
||||
const maxPrivateShares = Math.round(((newShares / 2) * privateOwnedRatio) / 10e6) * 10e6;
|
||||
|
||||
const disabledText = issueNewSharesFailureReason(corp, shares);
|
||||
|
||||
function issueNewShares(): void {
|
||||
if (isNaN(shares)) return;
|
||||
if (disabled) return;
|
||||
const [profit, newShares, privateShares] = IssueNewShares(corp, shares);
|
||||
|
||||
props.onClose();
|
||||
|
||||
let dialogContents =
|
||||
`Issued ${formatShares(newShares)} new shares` + ` and raised ${formatMoney(profit)}.` + (privateShares > 0)
|
||||
? "\n" + formatShares(privateShares) + " of these shares were bought by private investors."
|
||||
: "";
|
||||
dialogContents += `\n\nStock price decreased to ${formatMoney(corp.sharePrice)}`;
|
||||
dialogBoxCreate(dialogContents);
|
||||
if (disabledText) return;
|
||||
try {
|
||||
const [profit, newShares, privateShares] = IssueNewShares(corp, shares);
|
||||
dialogBoxCreate(
|
||||
<>
|
||||
<Typography>
|
||||
Issued {formatShares(newShares)} new shares and raised <Money money={profit} />.
|
||||
</Typography>
|
||||
{privateShares > 0 ? (
|
||||
<Typography>{formatShares(privateShares)} of these shares were bought by private investors.</Typography>
|
||||
) : null}
|
||||
<Typography>
|
||||
<b>{corp.name}</b>'s stock price fell to <Money money={corp.sharePrice} />.
|
||||
</Typography>
|
||||
</>,
|
||||
);
|
||||
props.onClose();
|
||||
props.rerender();
|
||||
} catch (err) {
|
||||
dialogBoxCreate(`${err}`);
|
||||
}
|
||||
}
|
||||
|
||||
function onKeyDown(event: React.KeyboardEvent<HTMLInputElement>): void {
|
||||
if (event.key === KEY.ENTER) issueNewShares();
|
||||
}
|
||||
|
||||
const nextCooldown = corpConstants.issueNewSharesCooldown * (corp.totalShares / corpConstants.initialShares);
|
||||
|
||||
return (
|
||||
<Modal open={props.open} onClose={props.onClose}>
|
||||
<Typography>
|
||||
You can issue new equity shares (i.e. stocks) in order to raise capital for your corporation.
|
||||
<Typography component="div">
|
||||
You can issue new equity shares (i.e. stocks) in order to raise capital.
|
||||
<ul>
|
||||
<li>Issuing new shares will cause dilution, lowering stock price and reducing dividends per share.</li>
|
||||
<li>New shares are sold between the current price and the updated price.</li>
|
||||
<li>The money from issuing new shares will be deposited directly into your Corporation's funds.</li>
|
||||
<li>
|
||||
Private shareholders have first priority for buying new shares, up to half of their existing stake in the
|
||||
company <b>({formatPercent(privateOwnedRatio / 2, 1)})</b>.
|
||||
<br />
|
||||
If they choose to exercise this option, these newly issued shares become private, restricted shares, which
|
||||
means you cannot buy them back.
|
||||
</li>
|
||||
<li>
|
||||
You will not be able to issue new shares again for <b>{corp.convertCooldownToString(nextCooldown)}</b>.
|
||||
</li>
|
||||
</ul>
|
||||
You can issue at most {formatShares(maxNewShares)} new shares.
|
||||
<br />
|
||||
<br />
|
||||
* You can issue at most {formatShares(maxNewShares)} new shares
|
||||
<br />
|
||||
* New shares are sold at a 10% discount
|
||||
<br />
|
||||
* You can only issue new shares once every 12 hours
|
||||
<br />
|
||||
* Issuing new shares causes dilution, resulting in a decrease in stock price and lower dividends per share
|
||||
<br />
|
||||
* Number of new shares issued must be a multiple of 10 million
|
||||
<br />
|
||||
<br />
|
||||
When you choose to issue new equity, private shareholders have first priority for up to 0.5n% of the new shares,
|
||||
where n is the percentage of the company currently owned by private shareholders. If they choose to exercise
|
||||
this option, these newly issued shares become private, restricted shares, which means you cannot buy them back.
|
||||
The number of new shares issued must be a multiple of 10 million.
|
||||
</Typography>
|
||||
<EffectText shares={shares} />
|
||||
<NumberInput autoFocus placeholder="# New Shares" onChange={setShares} onKeyDown={onKeyDown} />
|
||||
<Button disabled={disabled} onClick={issueNewShares} sx={{ mx: 1 }}>
|
||||
<br />
|
||||
<NumberInput
|
||||
defaultValue={shares || ""}
|
||||
autoFocus
|
||||
placeholder="# New Shares"
|
||||
onChange={setShares}
|
||||
onKeyDown={onKeyDown}
|
||||
/>
|
||||
<ButtonWithTooltip disabledTooltip={disabledText} onClick={issueNewShares}>
|
||||
Issue New Shares
|
||||
</Button>
|
||||
</ButtonWithTooltip>
|
||||
<br />
|
||||
<Typography sx={{ minHeight: "6em" }}>
|
||||
{disabledText ? (
|
||||
disabledText
|
||||
) : (
|
||||
<>
|
||||
Issue {formatShares(newShares)} new shares?
|
||||
<br />
|
||||
{maxPrivateShares > 0
|
||||
? `Private investors may buy up to ${formatShares(
|
||||
maxPrivateShares,
|
||||
)} of these shares and keep them off the market.`
|
||||
: null}
|
||||
<br />
|
||||
<b>{corp.name}</b> will receive <Money money={profit} />.
|
||||
<br />
|
||||
<b>{corp.name}</b>'s stock price will fall to <Money money={newSharePrice} /> per share.
|
||||
</>
|
||||
)}
|
||||
</Typography>
|
||||
</Modal>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,84 +0,0 @@
|
||||
import React, { useState } from "react";
|
||||
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 FormControlLabel from "@mui/material/FormControlLabel";
|
||||
import Switch from "@mui/material/Switch";
|
||||
import { useRerender } from "../../../ui/React/hooks";
|
||||
|
||||
interface IMarketTA2Props {
|
||||
mat: Material;
|
||||
}
|
||||
|
||||
function MarketTA2(props: IMarketTA2Props): React.ReactElement {
|
||||
const rerender = useRerender();
|
||||
|
||||
const division = useDivision();
|
||||
if (!division.hasResearch("Market-TA.II")) return <></>;
|
||||
|
||||
function onMarketTA2(event: React.ChangeEvent<HTMLInputElement>): void {
|
||||
props.mat.marketTa2 = event.target.checked;
|
||||
rerender();
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<Typography variant="h4">Market-TA.II</Typography>
|
||||
<Typography>
|
||||
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)
|
||||
</Typography>
|
||||
<br />
|
||||
<FormControlLabel
|
||||
control={<Switch checked={props.mat.marketTa2} onChange={onMarketTA2} />}
|
||||
label={<Typography>Use Market-TA.II for Auto-Sale Price</Typography>}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
interface IProps {
|
||||
open: boolean;
|
||||
onClose: () => void;
|
||||
mat: Material;
|
||||
}
|
||||
|
||||
// Create a popup that lets the player use the Market TA research for Materials
|
||||
export function MaterialMarketTaModal(props: IProps): React.ReactElement {
|
||||
const setRerender = useState(false)[1];
|
||||
function rerender(): void {
|
||||
setRerender((old) => !old);
|
||||
}
|
||||
const markupLimit = props.mat.getMarkupLimit();
|
||||
|
||||
function onMarketTA1(event: React.ChangeEvent<HTMLInputElement>): void {
|
||||
props.mat.marketTa1 = event.target.checked;
|
||||
rerender();
|
||||
}
|
||||
|
||||
return (
|
||||
<Modal open={props.open} onClose={props.onClose}>
|
||||
<>
|
||||
<Typography variant="h4">Market-TA.I</Typography>
|
||||
<Typography>
|
||||
The maximum sale price you can mark this up to is {formatMoney(props.mat.marketPrice + markupLimit)}. This
|
||||
means that if you set the sale price higher than this, you will begin to experience a loss in number of sales
|
||||
<br></br>
|
||||
<br></br>
|
||||
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)
|
||||
</Typography>
|
||||
|
||||
<FormControlLabel
|
||||
control={<Switch checked={props.mat.marketTa1} onChange={onMarketTA1} />}
|
||||
label={<Typography>Use Market-TA.I for Auto-Sale Price</Typography>}
|
||||
/>
|
||||
</>
|
||||
|
||||
<MarketTA2 mat={props.mat} />
|
||||
</Modal>
|
||||
);
|
||||
}
|
||||
@@ -1,86 +0,0 @@
|
||||
import React, { useState } from "react";
|
||||
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 FormControlLabel from "@mui/material/FormControlLabel";
|
||||
import Switch from "@mui/material/Switch";
|
||||
import { useRerender } from "../../../ui/React/hooks";
|
||||
|
||||
interface ITa2Props {
|
||||
product: Product;
|
||||
}
|
||||
|
||||
function MarketTA2(props: ITa2Props): React.ReactElement {
|
||||
const rerender = useRerender();
|
||||
|
||||
const division = useDivision();
|
||||
if (!division.hasResearch("Market-TA.II")) return <></>;
|
||||
|
||||
function onCheckedChange(event: React.ChangeEvent<HTMLInputElement>): void {
|
||||
props.product.marketTa2 = event.target.checked;
|
||||
rerender();
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<Typography variant="h4">Market-TA.II</Typography>
|
||||
<br />
|
||||
<Typography>
|
||||
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)
|
||||
</Typography>
|
||||
<br />
|
||||
<FormControlLabel
|
||||
control={<Switch checked={props.product.marketTa2} onChange={onCheckedChange} />}
|
||||
label={<Typography>Use Market-TA.II for Auto-Sale Price</Typography>}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
interface IProps {
|
||||
open: boolean;
|
||||
onClose: () => void;
|
||||
product: Product;
|
||||
}
|
||||
|
||||
// Create a popup that lets the player use the Market TA research for Products
|
||||
export function ProductMarketTaModal(props: IProps): React.ReactElement {
|
||||
const markupLimit = props.product.rating / props.product.markup;
|
||||
const setRerender = useState(false)[1];
|
||||
function rerender(): void {
|
||||
setRerender((old) => !old);
|
||||
}
|
||||
|
||||
function onChange(event: React.ChangeEvent<HTMLInputElement>): void {
|
||||
props.product.marketTa1 = event.target.checked;
|
||||
rerender();
|
||||
}
|
||||
|
||||
return (
|
||||
<Modal open={props.open} onClose={props.onClose}>
|
||||
<>
|
||||
<Typography variant="h4">Market-TA.I</Typography>
|
||||
<Typography>
|
||||
The maximum sale price you can mark this up to is {formatMoney(props.product.productionCost + markupLimit)}.
|
||||
This means that if you set the sale price higher than this, you will begin to experience a loss in number of
|
||||
sales
|
||||
<br></br>
|
||||
<br></br>
|
||||
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)
|
||||
</Typography>
|
||||
|
||||
<FormControlLabel
|
||||
control={<Switch checked={props.product.marketTa1} onChange={onChange} />}
|
||||
label={<Typography>Use Market-TA.I for Auto-Sale Price</Typography>}
|
||||
/>
|
||||
</>
|
||||
|
||||
<MarketTA2 product={props.product} />
|
||||
</Modal>
|
||||
);
|
||||
}
|
||||
@@ -3,9 +3,10 @@ import { dialogBoxCreate } from "../../../ui/React/DialogBox";
|
||||
import { MaterialInfo } from "../../MaterialInfo";
|
||||
import { Warehouse } from "../../Warehouse";
|
||||
import { Material } from "../../Material";
|
||||
import { formatMatPurchaseAmount, formatMoney } from "../../../ui/formatNumber";
|
||||
import { formatMatPurchaseAmount } from "../../../ui/formatNumber";
|
||||
import { BulkPurchase, BuyMaterial } from "../../Actions";
|
||||
import { Modal } from "../../../ui/React/Modal";
|
||||
import { Money } from "../../../ui/React/Money";
|
||||
import { useCorporation, useDivision } from "../Context";
|
||||
import Typography from "@mui/material/Typography";
|
||||
import TextField from "@mui/material/TextField";
|
||||
@@ -56,7 +57,7 @@ function BulkPurchaseSection(props: IBPProps): React.ReactElement {
|
||||
return (
|
||||
<>
|
||||
<Typography>
|
||||
Purchasing {formatMatPurchaseAmount(parsedAmt)} of {props.mat.name} will cost {formatMoney(cost)}
|
||||
Purchasing {formatMatPurchaseAmount(parsedAmt)} of {props.mat.name} will cost <Money money={cost} />
|
||||
</Typography>
|
||||
</>
|
||||
);
|
||||
|
||||
@@ -57,6 +57,7 @@ export function SellCorporationModal(props: IProps): React.ReactElement {
|
||||
<br />
|
||||
If you would like to start new one, please enter a name for your corporation below:
|
||||
</Typography>
|
||||
<br />
|
||||
<TextField autoFocus={true} placeholder="Corporation Name" onChange={onChange} value={name} />
|
||||
{Player.bitNodeN === 3 && (
|
||||
<Button onClick={seed} disabled={name == ""}>
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import React, { useState } from "react";
|
||||
|
||||
import { Modal } from "../../../ui/React/Modal";
|
||||
import { Money } from "../../../ui/React/Money";
|
||||
import Typography from "@mui/material/Typography";
|
||||
import Button from "@mui/material/Button";
|
||||
import MenuItem from "@mui/material/MenuItem";
|
||||
@@ -8,7 +9,6 @@ import Select, { SelectChangeEvent } from "@mui/material/Select";
|
||||
import { useCorporation } from "../../ui/Context";
|
||||
import { CityName } from "@enums";
|
||||
import * as corpConstants from "../../data/Constants";
|
||||
import { formatMoney } from "../../../ui/formatNumber";
|
||||
import { removeDivision as removeDivision } from "../../Actions";
|
||||
import { dialogBoxCreate } from "../../../ui/React/DialogBox";
|
||||
import { getRecordKeys } from "../../../Types/Record";
|
||||
@@ -47,9 +47,10 @@ export function SellDivisionModal(props: IProps): React.ReactElement {
|
||||
corp.funds += price;
|
||||
props.onClose();
|
||||
dialogBoxCreate(
|
||||
`Sold ${divisionToSell.name} for ${formatMoney(price)}, you now have space for ${
|
||||
corp.maxDivisions - corp.divisions.size
|
||||
} more divisions.`,
|
||||
<Typography>
|
||||
Sold <b>{divisionToSell.name}</b> for <Money money={price} />, you now have space for
|
||||
{corp.maxDivisions - corp.divisions.size} more divisions.
|
||||
</Typography>,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -70,13 +71,15 @@ export function SellDivisionModal(props: IProps): React.ReactElement {
|
||||
</Select>
|
||||
<Typography>Division {divisionToSell.name} has:</Typography>
|
||||
<Typography>
|
||||
Profit: {formatMoney((divisionToSell.lastCycleRevenue - divisionToSell.lastCycleExpenses) / 10)} / sec{" "}
|
||||
Profit: <Money money={(divisionToSell.lastCycleRevenue - divisionToSell.lastCycleExpenses) / 10} /> / sec{" "}
|
||||
</Typography>
|
||||
<Typography>Cities:{getRecordKeys(divisionToSell.offices).length}</Typography>
|
||||
<Typography>Warehouses:{getRecordKeys(divisionToSell.warehouses).length}</Typography>
|
||||
{divisionToSell.makesProducts ?? <Typography>Products: {divisionToSell.products.size}</Typography>}
|
||||
<br />
|
||||
<Typography>Sell price: {formatMoney(price)}</Typography>
|
||||
<Typography>
|
||||
Sell price: <Money money={price} />
|
||||
</Typography>
|
||||
<Button onClick={sellDivision}>Sell division</Button>
|
||||
</>
|
||||
</Modal>
|
||||
|
||||
@@ -1,33 +1,25 @@
|
||||
import React, { useState } from "react";
|
||||
import { dialogBoxCreate } from "../../../ui/React/DialogBox";
|
||||
import { Material } from "../../Material";
|
||||
import { SellMaterial } from "../../Actions";
|
||||
import { Modal } from "../../../ui/React/Modal";
|
||||
import Typography from "@mui/material/Typography";
|
||||
import TextField from "@mui/material/TextField";
|
||||
import Button from "@mui/material/Button";
|
||||
import { KEY } from "../../../utils/helpers/keyCodes";
|
||||
import type { Division } from "../../Division";
|
||||
import type { Material } from "../../Material";
|
||||
|
||||
function initialPrice(mat: Material): string {
|
||||
let val = mat.desiredSellPrice ? mat.desiredSellPrice + "" : "";
|
||||
if (mat.marketTa2) {
|
||||
val += " (Market-TA.II)";
|
||||
} else if (mat.marketTa1) {
|
||||
val += " (Market-TA.I)";
|
||||
}
|
||||
return val;
|
||||
}
|
||||
import React, { useState } from "react";
|
||||
import { Button, FormControlLabel, Switch, TextField, Tooltip, Typography } from "@mui/material";
|
||||
import { Modal } from "../../../ui/React/Modal";
|
||||
import { dialogBoxCreate } from "../../../ui/React/DialogBox";
|
||||
|
||||
import { SellMaterial } from "../../Actions";
|
||||
import { KEY } from "../../../utils/helpers/keyCodes";
|
||||
|
||||
interface IProps {
|
||||
open: boolean;
|
||||
onClose: () => void;
|
||||
mat: Material;
|
||||
div: Division;
|
||||
}
|
||||
|
||||
// Create a popup that let the player manage sales of a material
|
||||
export function SellMaterialModal(props: IProps): React.ReactElement {
|
||||
const [amt, setAmt] = useState<string>(props.mat.desiredSellAmount + "");
|
||||
const [price, setPrice] = useState<string>(initialPrice(props.mat));
|
||||
const [amt, setAmt] = useState<string>(String(props.mat.desiredSellAmount));
|
||||
const [price, setPrice] = useState<string>(String(props.mat.desiredSellPrice));
|
||||
|
||||
function sellMaterial(): void {
|
||||
try {
|
||||
@@ -83,7 +75,51 @@ export function SellMaterialModal(props: IProps): React.ReactElement {
|
||||
onKeyDown={onKeyDown}
|
||||
/>
|
||||
<TextField value={price} type="text" placeholder="Sell price" onChange={onPriceChange} onKeyDown={onKeyDown} />
|
||||
<Button onClick={sellMaterial}>Confirm</Button>
|
||||
<Button onClick={sellMaterial} style={{ marginLeft: ".5rem", marginRight: ".5rem" }}>
|
||||
Confirm
|
||||
</Button>
|
||||
{props.div.hasResearch("Market-TA.I") && (
|
||||
<FormControlLabel
|
||||
style={{ marginRight: "1rem" }}
|
||||
control={
|
||||
<Switch checked={props.mat.marketTa1} onChange={(event) => (props.mat.marketTa1 = event.target.checked)} />
|
||||
}
|
||||
label={
|
||||
<Tooltip
|
||||
title={
|
||||
<Typography>
|
||||
If this is enabled, then this Material will automatically be sold at market price + markup.
|
||||
<br />
|
||||
This overrides player set pricing and gets overriden by an active TA2.
|
||||
</Typography>
|
||||
}
|
||||
>
|
||||
<Typography>Market-TA.I</Typography>
|
||||
</Tooltip>
|
||||
}
|
||||
/>
|
||||
)}
|
||||
{props.div.hasResearch("Market-TA.II") && (
|
||||
<FormControlLabel
|
||||
control={
|
||||
<Switch checked={props.mat.marketTa2} onChange={(event) => (props.mat.marketTa2 = event.target.checked)} />
|
||||
}
|
||||
label={
|
||||
<Tooltip
|
||||
title={
|
||||
<Typography>
|
||||
If this is enabled, then this Material will automatically be sold at the optimal price such that the
|
||||
amount sold matches the amount specified.
|
||||
<br />
|
||||
This overrides player set pricing and TA1.
|
||||
</Typography>
|
||||
}
|
||||
>
|
||||
<Typography>Market-TA.II</Typography>
|
||||
</Tooltip>
|
||||
}
|
||||
/>
|
||||
)}
|
||||
</Modal>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,39 +1,28 @@
|
||||
import type { CityName } from "@enums";
|
||||
import type { Division } from "../../Division";
|
||||
import type { Product } from "../../Product";
|
||||
|
||||
import React, { useState } from "react";
|
||||
import { dialogBoxCreate } from "../../../ui/React/DialogBox";
|
||||
import { Product } from "../../Product";
|
||||
import { SellProduct } from "../../Actions";
|
||||
import { Button, FormControlLabel, Switch, TextField, Tooltip, Typography } from "@mui/material";
|
||||
import { Modal } from "../../../ui/React/Modal";
|
||||
import { dialogBoxCreate } from "../../../ui/React/DialogBox";
|
||||
|
||||
import Typography from "@mui/material/Typography";
|
||||
import TextField from "@mui/material/TextField";
|
||||
import Button from "@mui/material/Button";
|
||||
import FormControlLabel from "@mui/material/FormControlLabel";
|
||||
import Switch from "@mui/material/Switch";
|
||||
import { SellProduct } from "../../Actions";
|
||||
import { KEY } from "../../../utils/helpers/keyCodes";
|
||||
import { CityName } from "@enums";
|
||||
|
||||
function initialPrice(product: Product, city: CityName): string {
|
||||
let val = String(product.cityData[city].desiredSellPrice || "");
|
||||
if (product.marketTa2) {
|
||||
val += " (Market-TA.II)";
|
||||
} else if (product.marketTa1) {
|
||||
val += " (Market-TA.I)";
|
||||
}
|
||||
return val;
|
||||
}
|
||||
|
||||
interface IProps {
|
||||
open: boolean;
|
||||
onClose: () => void;
|
||||
product: Product;
|
||||
city: CityName;
|
||||
div: Division;
|
||||
}
|
||||
|
||||
// Create a popup that let the player manage sales of a material
|
||||
export function SellProductModal(props: IProps): React.ReactElement {
|
||||
const [checked, setChecked] = useState(true);
|
||||
const [iQty, setQty] = useState<string>((props.product.cityData[props.city].desiredSellAmount ?? "").toString());
|
||||
const [px, setPx] = useState<string>(initialPrice(props.product, props.city));
|
||||
const [iQty, setQty] = useState<string>(String(props.product.cityData[props.city].desiredSellAmount));
|
||||
const [px, setPx] = useState<string>(String(props.product.cityData[props.city].desiredSellPrice));
|
||||
|
||||
function onCheckedChange(event: React.ChangeEvent<HTMLInputElement>): void {
|
||||
setChecked(event.target.checked);
|
||||
@@ -94,11 +83,62 @@ export function SellProductModal(props: IProps): React.ReactElement {
|
||||
onKeyDown={onKeyDown}
|
||||
/>
|
||||
<TextField value={px} type="text" placeholder="Sell price" onChange={onPriceChange} onKeyDown={onKeyDown} />
|
||||
<Button onClick={sellProduct}>Confirm</Button>
|
||||
<Button onClick={sellProduct} style={{ marginLeft: ".5rem", marginRight: ".5rem" }}>
|
||||
Confirm
|
||||
</Button>
|
||||
<FormControlLabel
|
||||
style={{ marginRight: ".5rem" }}
|
||||
control={<Switch checked={checked} onChange={onCheckedChange} />}
|
||||
label={<Typography>Use same 'Sell Amount' for all cities</Typography>}
|
||||
label={<Typography>Set for all cities</Typography>}
|
||||
/>
|
||||
{props.div.hasResearch("Market-TA.I") && (
|
||||
<FormControlLabel
|
||||
style={{ marginRight: "1rem" }}
|
||||
control={
|
||||
<Switch
|
||||
checked={props.product.marketTa1}
|
||||
onChange={(event) => (props.product.marketTa1 = event.target.checked)}
|
||||
/>
|
||||
}
|
||||
label={
|
||||
<Tooltip
|
||||
title={
|
||||
<Typography>
|
||||
If this is enabled, then this Material will automatically be sold at market price + markup.
|
||||
<br />
|
||||
This overrides player set pricing and gets overriden by an active TA2.
|
||||
</Typography>
|
||||
}
|
||||
>
|
||||
<Typography>Market-TA.I</Typography>
|
||||
</Tooltip>
|
||||
}
|
||||
/>
|
||||
)}
|
||||
{props.div.hasResearch("Market-TA.II") && (
|
||||
<FormControlLabel
|
||||
control={
|
||||
<Switch
|
||||
checked={props.product.marketTa2}
|
||||
onChange={(event) => (props.product.marketTa2 = event.target.checked)}
|
||||
/>
|
||||
}
|
||||
label={
|
||||
<Tooltip
|
||||
title={
|
||||
<Typography>
|
||||
If this is enabled, then this Material will automatically be sold at the optimal price such that the
|
||||
amount sold matches the amount specified.
|
||||
<br />
|
||||
This overrides player set pricing and TA1.
|
||||
</Typography>
|
||||
}
|
||||
>
|
||||
<Typography>Market-TA.II</Typography>
|
||||
</Tooltip>
|
||||
}
|
||||
/>
|
||||
)}
|
||||
</Modal>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,16 +1,17 @@
|
||||
import React, { useState } from "react";
|
||||
import { formatMoney } from "../../../ui/formatNumber";
|
||||
import { dialogBoxCreate } from "../../../ui/React/DialogBox";
|
||||
import { formatShares } from "../../../ui/formatNumber";
|
||||
import { Modal } from "../../../ui/React/Modal";
|
||||
import { useCorporation } from "../Context";
|
||||
import { Corporation } from "../../Corporation";
|
||||
import Typography from "@mui/material/Typography";
|
||||
import Button from "@mui/material/Button";
|
||||
import { Money } from "../../../ui/React/Money";
|
||||
import { useCorporation } from "../Context";
|
||||
import * as corpConstants from "../../data/Constants";
|
||||
import Typography from "@mui/material/Typography";
|
||||
import { ButtonWithTooltip } from "../../../ui/Components/ButtonWithTooltip";
|
||||
import { SellShares } from "../../Actions";
|
||||
import { KEY } from "../../../utils/helpers/keyCodes";
|
||||
import { NumberInput } from "../../../ui/React/NumberInput";
|
||||
import { isInteger } from "lodash";
|
||||
import { sellSharesFailureReason } from "../../helpers";
|
||||
|
||||
interface IProps {
|
||||
open: boolean;
|
||||
onClose: () => void;
|
||||
@@ -23,48 +24,28 @@ export function SellSharesModal(props: IProps): React.ReactElement {
|
||||
const corp = useCorporation();
|
||||
const [shares, setShares] = useState<number>(NaN);
|
||||
|
||||
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 || !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];
|
||||
text = `Sell ${props.shares} shares for a total of ${formatMoney(profit)}`;
|
||||
}
|
||||
|
||||
return (
|
||||
<Typography>
|
||||
<small>{text}</small>
|
||||
</Typography>
|
||||
);
|
||||
}
|
||||
const [profit, sharePrice] = corp.calculateShareSale((props.open && shares) || 0);
|
||||
const disabledText = sellSharesFailureReason(corp, shares);
|
||||
|
||||
function sell(): void {
|
||||
if (disabled) return;
|
||||
if (disabledText) return;
|
||||
try {
|
||||
const profit = SellShares(corp, shares);
|
||||
props.onClose();
|
||||
SellShares(corp, shares);
|
||||
dialogBoxCreate(
|
||||
<>
|
||||
Sold {formatMoney(shares)} shares for
|
||||
<Money money={profit} />. The corporation's stock price fell to <Money money={corp.sharePrice} />
|
||||
as a result of dilution.
|
||||
<Typography>
|
||||
You sold {formatShares(shares)} shares for <Money money={profit} />.
|
||||
</Typography>
|
||||
<Typography>
|
||||
<b>{corp.name}</b>'s stock price fell to <Money money={sharePrice} /> per share.
|
||||
</Typography>
|
||||
</>,
|
||||
);
|
||||
|
||||
props.onClose();
|
||||
props.rerender();
|
||||
setShares(NaN);
|
||||
} catch (err) {
|
||||
dialogBoxCreate(err + "");
|
||||
dialogBoxCreate(`${err as Error}`);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -74,32 +55,43 @@ export function SellSharesModal(props: IProps): React.ReactElement {
|
||||
|
||||
return (
|
||||
<Modal open={props.open} onClose={props.onClose}>
|
||||
<Typography>
|
||||
Enter the number of shares you would like to sell. The money from selling your shares will go directly to you
|
||||
(NOT your Corporation).
|
||||
<br />
|
||||
<br />
|
||||
The amount sold must be an integer between 1 and 100t.
|
||||
<br />
|
||||
<br />
|
||||
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.
|
||||
<br />
|
||||
<br />
|
||||
The current price of your company's stock is {formatMoney(corp.sharePrice)}
|
||||
<Typography component="div">
|
||||
Enter the number of shares you would like to sell.
|
||||
<ul>
|
||||
<li>Selling shares will cause stock price to fall due to market forces.</li>
|
||||
<li>The money from selling your shares will go directly to you (NOT your Corporation).</li>
|
||||
<li>
|
||||
You will not be able to sell shares again (or dissolve the corporation) for{" "}
|
||||
<b>{corp.convertCooldownToString(corpConstants.sellSharesCooldown)}</b>.
|
||||
</li>
|
||||
</ul>
|
||||
You currently have {formatShares(corp.numShares)} shares of <b>{corp.name}</b> stock, valued at{" "}
|
||||
<Money money={corp.sharePrice} /> per share.
|
||||
</Typography>
|
||||
<br />
|
||||
<NumberInput
|
||||
defaultValue={shares || ""}
|
||||
variant="standard"
|
||||
autoFocus
|
||||
placeholder="Shares to sell"
|
||||
onChange={setShares}
|
||||
onKeyDown={onKeyDown}
|
||||
/>
|
||||
<Button disabled={disabled} onClick={sell} sx={{ mx: 1 }}>
|
||||
<ButtonWithTooltip disabledTooltip={disabledText} onClick={sell}>
|
||||
Sell shares
|
||||
</Button>
|
||||
<ProfitIndicator shares={shares} corp={corp} />
|
||||
</ButtonWithTooltip>
|
||||
<br />
|
||||
<Typography sx={{ minHeight: "3em" }}>
|
||||
{!shares ? null : disabledText ? (
|
||||
disabledText
|
||||
) : (
|
||||
<>
|
||||
You will receive <Money money={profit} />.
|
||||
<br />
|
||||
<b>{corp.name}</b>'s stock price will fall to <Money money={sharePrice} /> per share.
|
||||
</>
|
||||
)}
|
||||
</Typography>
|
||||
</Modal>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -95,7 +95,7 @@ export function SmartSupplyModal(props: IProps): React.ReactElement {
|
||||
label={<Typography>Enable Smart Supply</Typography>}
|
||||
/>
|
||||
<br />
|
||||
<Typography>
|
||||
<Typography component="div">
|
||||
Options:
|
||||
<ul>
|
||||
<li>
|
||||
|
||||
@@ -3,7 +3,7 @@ import { formatMultiplier, formatPercent } from "../../../ui/formatNumber";
|
||||
import { dialogBoxCreate } from "../../../ui/React/DialogBox";
|
||||
import { OfficeSpace } from "../../OfficeSpace";
|
||||
import { ThrowParty } from "../../Actions";
|
||||
import { Money } from "../../../ui/React/Money";
|
||||
import { MoneyCost } from "../MoneyCost";
|
||||
import { Modal } from "../../../ui/React/Modal";
|
||||
import { useCorporation } from "../Context";
|
||||
import Typography from "@mui/material/Typography";
|
||||
@@ -38,8 +38,8 @@ 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 to make recovering from low morale easier.
|
||||
const increase = mult > 1 ? (mult - 1) * 0.2 : 0;
|
||||
// Each 10% multiplier gives an extra flat +1 to morale to make recovering from low morale easier.
|
||||
const increase = mult > 1 ? (mult - 1) * 0.1 : 0;
|
||||
|
||||
if (mult > 0) {
|
||||
dialogBoxCreate(
|
||||
@@ -59,7 +59,7 @@ export function ThrowPartyModal(props: IProps): React.ReactElement {
|
||||
if (isNaN(cost) || cost < 0) return <Typography>Invalid value entered!</Typography>;
|
||||
return (
|
||||
<Typography>
|
||||
Throwing this party will cost a total of <Money money={totalCost} />
|
||||
Throwing this party will cost a total of <MoneyCost money={totalCost} corp={corp} />
|
||||
</Typography>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -69,6 +69,12 @@ export function CorporationDev(): React.ReactElement {
|
||||
});
|
||||
}
|
||||
|
||||
function resetCorporationCooldowns(): void {
|
||||
if (!Player.corporation) return;
|
||||
Player.corporation.shareSaleCooldown = 0;
|
||||
Player.corporation.issueNewSharesCooldown = 0;
|
||||
}
|
||||
|
||||
return (
|
||||
<Accordion TransitionProps={{ unmountOnExit: true }}>
|
||||
<AccordionSummary expandIcon={<ExpandMoreIcon />}>
|
||||
@@ -117,6 +123,11 @@ export function CorporationDev(): React.ReactElement {
|
||||
<Button onClick={addCorporationResearch}>Tons of research</Button>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<Button onClick={resetCorporationCooldowns}>Reset stock cooldowns</Button>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</AccordionDetails>
|
||||
|
||||
@@ -1,3 +1,11 @@
|
||||
# Bladeburners
|
||||
|
||||
PLACEHOLDER
|
||||
Bladeburner divisions were created internationally in the mid-21st century. Tasked with monitoring and "managing" rogue Synthoids, which may have blended into society and are sometimes considered a threat, working for Bladeburners gives access to powerful enhancements and a goal of destroying [BitNodes](bitnodes.md) by operating against increasingly strong Synthoid opposition.
|
||||
|
||||
## Bladeburner Skills:
|
||||
|
||||
Designed to improve a human agent's capabilities beyond their natural limits, Bladeburner skills add a persistent bonus while in the [BitNode](bitnodes.md) where they were purchased. Bladeburner skills are purchased with Bladeburner skill points, not money.
|
||||
|
||||
## Faction and Rank:
|
||||
|
||||
Bladeburners also offer unique [Augmentations](../basic/augmentations.md) and a [Faction](factions.md) invite to agents who "put in the work" to gain a small amount of rank. While Bladeburner rank and skill points persist after any augmentation installs, faction reputation will be reset. Bladeburner faction reputation can only be gained through Bladeburner actions.
|
||||
|
||||
@@ -1,5 +1,35 @@
|
||||
# Gang
|
||||
# Gangs
|
||||
|
||||
Managing a gang can be very rewarding. By rising above all other gangs you get access to almost all augmentations in the game.
|
||||
In the wake of crisis and war, Gang activity surged. Stronger than ever in a lawless world - Enhanced with fantastic technology, no longer held back by ethics and morals, 'free from the shadows'....
|
||||
|
||||
PLACEHOLDER
|
||||
Seen by most of the population as nihilistic, murderous and vile, occassional rumors suggest Gangs sometimes involve themselves with vigilanteism, hacktivism, perhaps even plotting against The Enders, seeking to destroy a world they cannot save.
|
||||
|
||||
## Starting and Recruiting
|
||||
|
||||
Outside of [BitNode-2](bitnodes.md) gangs require much more crime and heartbreak to create, but can still be a great help. Creating a Gang in other [BitNodes](bitnodes.md) will offer more [Augmentations](../basic/augmentations.md) than other [Factions](../basic/factions.md), but they will not be a way to destroy the [BitNode](bitnodes.md) alone.
|
||||
|
||||
After creating a gang, you will be able to start recruiting, adding members to your gang as you gain Respect. While in a BitNode, your gang and gang member stats will not reset if you install augmentations.
|
||||
|
||||
## Respect
|
||||
|
||||
Earned as your gang members complete tasks, Respect affects your gang's productivity, including your Faction Reputation (needed to buy augmentations from your Gang Faction), and the number of recruits you can have. An individual gang member's Respect is lost or reset if they Ascend, or are killed in a Territory Warfare clash.
|
||||
|
||||
## Ascending
|
||||
|
||||
When experienced enough, gang members are offered Ascension, a permanent boost to their stat multipliers at the cost of resetting their base stats and equipment to 0, and reducing your Gang Reputation by the same amount as that member had earned since they last Ascended.
|
||||
|
||||
## Equipping and Managing
|
||||
|
||||
Buying Equipment for a gang member will give them a stat boost until they Ascend or are killed, at which point most equipment will reset.
|
||||
|
||||
Augmentations you install on gang members (in the Gang Equipment subpage) do not reset when they Ascend.
|
||||
|
||||
Active gang members earn stats, respect and money based on their current stats, their equipment, and the effects of Ascending.
|
||||
|
||||
## Wanted, Territory and Clashes
|
||||
|
||||
Your gang's "Wanted Level" can make tasks much less productive, and is affected by the tasks assigned to gang members. "Ethical Hacking" or "Vigilante Justice" tasks can lower Wanted Level.
|
||||
|
||||
"Territory Warfare" is a special task that builds Power for your gang. If "Territory Clashes" are enabled [see the Territory subpage of your Gang page], members have a chance to win or lose territory by clashing with other gangs. The % of Territory you control affects most aspects of your gang productivity.
|
||||
|
||||
Note that gang members can die during clashes, even if your gang wins.
|
||||
|
||||
27
src/Documentation/doc/advanced/offlineandbonustime.md
Normal file
27
src/Documentation/doc/advanced/offlineandbonustime.md
Normal file
@@ -0,0 +1,27 @@
|
||||
# How Scripts Work Offline
|
||||
|
||||
The scripts you write and execute in the BitVerse are real, working JavaScript.
|
||||
For this reason, it is not possible for Bitburner scripts to run when
|
||||
|
||||
- the game is closed
|
||||
- the browser tab is inactive (if playing Bitburner in a web browser)
|
||||
- or your system is sleeping
|
||||
|
||||
all of which we call being "offline" for game purposes.
|
||||
|
||||
It is important to know that logic such as `if`/`else` statements and most functions such as `ns.purchaseHacknetNode()`, `ns.hack()`, and `ns.nuke()` will not work while the game is offline.
|
||||
|
||||
However, scripts WILL continue to generate money and hacking exp for you while offline.
|
||||
This offline production is based on the average online production of all your hacking scripts since your last augmentation, as shown on your Active Scripts page.
|
||||
|
||||
`ns.grow()` and `ns.weaken()` methods are also applied when the game is offline, although at a slower rate.
|
||||
This is done by having each script track the rate at which the `ns.grow()` and `ns.weaken()` commands are called while online,
|
||||
then determining how many calls would have been made while offline, and their effect is applied.
|
||||
|
||||
Also, note that because of the way the JavaScript engine works, whenever you reload or re-open the game all of your Active Scripts will start again from the BEGINNING of their code. The game does not keep track of where exactly the execution of a script is when it saves/loads.
|
||||
|
||||
# Bonus Time
|
||||
|
||||
Because of the above details, some activities in Bitburner accumulate "Bonus Time" while the game is closed or in an inactive browser tab . For mechanics that have a Bonus Time effect, the rate of the associated activity or task is significantly increased.
|
||||
|
||||
For example if a certain [Bladeburner](bladeburners.md) contract requires 15 seconds to complete under normal conditions, the same task will be finished instead in 3 seconds if the Bonus Time effect is 5x. The specific details and effects of Bonus Time vary by mechanic.
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user