Merge branch 'dev' into patch-3

This commit is contained in:
Nikolai Korolev 2022-03-10 12:06:19 +03:00 committed by GitHub
commit 20e3924c6a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
69 changed files with 588 additions and 283 deletions

1
CODE_OF_CONDUCT.md Normal file

@ -0,0 +1 @@
Don't be an ass.

18
dist/bitburner.d.ts vendored

@ -958,6 +958,16 @@ export declare interface Corporation extends WarehouseAPI, OfficeAPI {
* @param percent - Percent of profit to issue as dividends.
*/
issueDividends(percent: number): void;
/**
* Buyback Shares
* @param amt - Number of shares to attempt to buyback.
*/
buyBackShares(amt: number): void;
/**
* Sell Shares
* @param amt - Number of shares to attempt to sell.
*/
sellShares(amt: number): void;
}
/**
@ -6635,6 +6645,14 @@ export declare interface WarehouseAPI {
* @param amt - Amount of material to buy
*/
buyMaterial(divisionName: string, cityName: string, materialName: string, amt: number): void;
/**
* Set material to bulk buy
* @param divisionName - Name of the division
* @param cityName - Name of the city
* @param materialName - Name of the material
* @param amt - Amount of material to buy
*/
bulkPurchase(divisionName: string, cityName: string, materialName: string, amt: number): void;
/**
* Get warehouse data
* @param divisionName - Name of the division

36
dist/vendor.bundle.js vendored

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

@ -6,32 +6,61 @@ Changelog
v1.5.0 - Steam Cloud integration
--------------------------------
** Misc. **
** Steam Cloud Saving **
* Added support for steam cloud saving (@MartinFournier)
** UI **
* The file API now allows GET and DELETE (@lordducky)
* Fix bug with async.
* Update documentation / typo (@lethern, @Meowdoleon, @JohnnyUrosevic, @JosephDavidTalbot,
@pd, @lethern, @lordducky, @zeddrak, @fearnlj01, @reasonablytall)
* Fix bug with corp API (@pigalot)
* background now matches game primary color (@nickofolas)
* page title contains version (@MartinFourier)
* Major text editor improvements (@nickofolas)
* Force achievement calculation on BN completion (@SagePtr)
* Cleanup in repository (@MartinFourier)
* Several improvements to the electron version (@MartinFourier)
* Add 'printf' ns function (@Ninetailed)
* Display bonus time on sleeve page (@MartinFourier)
* Several UI improvements (@nickofolas, @smolgumball)
* Fix bug with casino roulette (@jamie-mac)
* Several UI improvements (@nickofolas, @smolgumball, @DrCuriosity, @phyzical)
* Fix aug display in alpha (@Dominik Winter)
* Fix display of corporation product equation (@SagePtr)
* Make Bitverse more accessible (@ChrissiQ)
* Make corporation warehouse more accessible (@ChrissiQ)
* Make tab style more consistent (@nikfolas)
** Netscript **
* Fix bug with async.
* Add 'printf' ns function (@Ninetailed)
* Remove blob caching.
* Fix formulas access check (@Ornedan)
* Fix bug in exp calculation (@qcorradi)
* Fix NaN comparison (@qcorradi)
* Terminal history persists in savefile (@MartinFourier)
* Fix travelToCity with bad argument (@SlyCedix)
* Fix aug display in alpha (@Dominik Winter)
* Fix bug where augs could not be purchased via sing (@reacocard)
* Fix rounding error in donateToFaction (@Risenafis)
* Fix bug with weakenAnalyze (@rhobes)
* Prevent exploit with atExit (@Ornedan)
* Double 'share' power
** Corporations **
* Fix bugs with corp API (@pigalot)
* Add smart supply func to corp API (@pd)
** Misc. **
* The file API now allows GET and DELETE (@lordducky)
* Force achievement calculation on BN completion (@SagePtr)
* Cleanup in repository (@MartinFourier)
* Several improvements to the electron version (@MartinFourier)
* Fix bug with casino roulette (@jamie-mac)
* Terminal history persists in savefile (@MartinFourier)
* Fix tests (@jamie-mac)
* Fix crash with electron windows tracker (@smolgumball)
* Fix BN6/7 passive reputation gain (@BrianLDev)
* Fix Sleeve not resetting on install (@waffleattack)
* Sort joined factions (@jjayeon)
* Update documentation / typo (@lethern, @Meowdoleon, @JohnnyUrosevic, @JosephDavidTalbot,
@pd, @lethern, @lordducky, @zeddrak, @fearnlj01, @reasonablytall, @MatthewTh0,
@SagePtr, @manniL, @Jedimaster4559, @loganville, @Arrow2thekn33, @wdpk, @fwolfst,
@fschoenfeldt, @Waladil, @AdamTReineke, @citrusmunch, @factubsio, @ashtongreen,
@ChrissiQ, @DJ-Laser, @waffleattack, @ApamNapat, @CrafterKolyan, @DSteve595)
* Nerf noodle bar.
v1.4.0 - 2022-01-18 Sharing is caring

@ -64,9 +64,9 @@ documentation_title = '{0} Documentation'.format(project)
# built documents.
#
# The short X.Y version.
version = '1.4'
version = '1.5'
# The full version, including alpha/beta/rc tags.
release = '1.4.0'
release = '1.5.0'
# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

@ -0,0 +1,24 @@
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
[Home](./index.md) &gt; [bitburner](./bitburner.md) &gt; [Corporation](./bitburner.corporation.md) &gt; [buyBackShares](./bitburner.corporation.buybackshares.md)
## Corporation.buyBackShares() method
Buyback Shares
<b>Signature:</b>
```typescript
buyBackShares(amount: number): void;
```
## Parameters
| Parameter | Type | Description |
| --- | --- | --- |
| amount | number | Amount of shares to buy back. |
<b>Returns:</b>
void

@ -19,6 +19,7 @@ export interface Corporation extends WarehouseAPI, OfficeAPI
| --- | --- |
| [acceptInvestmentOffer()](./bitburner.corporation.acceptinvestmentoffer.md) | Accept investment based on you companies current valuation |
| [bribe(factionName, amountCash, amountShares)](./bitburner.corporation.bribe.md) | Bribe a faction |
| [buyBackShares(amount)](./bitburner.corporation.buybackshares.md) | Buyback Shares |
| [createCorporation(corporationName, selfFund)](./bitburner.corporation.createcorporation.md) | Create a Corporation |
| [expandCity(divisionName, cityName)](./bitburner.corporation.expandcity.md) | Expand to a new city |
| [expandIndustry(industryType, divisionName)](./bitburner.corporation.expandindustry.md) | Expand to a new industry |
@ -34,5 +35,6 @@ export interface Corporation extends WarehouseAPI, OfficeAPI
| [hasUnlockUpgrade(upgradeName)](./bitburner.corporation.hasunlockupgrade.md) | Check if you have a one time unlockable upgrade |
| [issueDividends(percent)](./bitburner.corporation.issuedividends.md) | Issue dividends |
| [levelUpgrade(upgradeName)](./bitburner.corporation.levelupgrade.md) | Level an upgrade. |
| [sellShares(amount)](./bitburner.corporation.sellshares.md) | Sell Shares |
| [unlockUpgrade(upgradeName)](./bitburner.corporation.unlockupgrade.md) | Unlock an upgrade |

@ -0,0 +1,24 @@
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
[Home](./index.md) &gt; [bitburner](./bitburner.md) &gt; [Corporation](./bitburner.corporation.md) &gt; [sellShares](./bitburner.corporation.sellshares.md)
## Corporation.sellShares() method
Sell Shares
<b>Signature:</b>
```typescript
sellShares(amount: number): void;
```
## Parameters
| Parameter | Type | Description |
| --- | --- | --- |
| amount | number | Amount of shares to sell. |
<b>Returns:</b>
void

@ -0,0 +1,27 @@
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
[Home](./index.md) &gt; [bitburner](./bitburner.md) &gt; [WarehouseAPI](./bitburner.warehouseapi.md) &gt; [bulkPurchase](./bitburner.warehouseapi.bulkpurchase.md)
## WarehouseAPI.bulkPurchase() method
Set material to bulk buy
<b>Signature:</b>
```typescript
bulkPurchase(divisionName: string, cityName: string, materialName: string, amt: number): void;
```
## Parameters
| Parameter | Type | Description |
| --- | --- | --- |
| divisionName | string | Name of the division |
| cityName | string | Name of the city |
| materialName | string | Name of the material |
| amt | number | Amount of material to buy |
<b>Returns:</b>
void

@ -1,7 +1,7 @@
{
"name": "bitburner",
"license": "SEE LICENSE IN license.txt",
"version": "1.4.0",
"version": "1.5.0",
"main": "electron-main.js",
"author": {
"name": "Daniel Xie & Olivier Gagnon"
@ -125,6 +125,6 @@
"electron:packager-win": "electron-packager .package bitburner --platform win32 --arch x64 --out .build --overwrite --icon .package/icon.png",
"electron:packager-mac": "electron-packager .package bitburner --platform darwin --arch x64 --out .build --overwrite --icon .package/icon.png",
"electron:packager-linux": "electron-packager .package bitburner --platform linux --arch x64 --out .build --overwrite --icon .package/icon.png",
"allbuild": "npm run build && npm run electron && git add --all && git commit --amend --no-edit && git push -f -u origin dev"
"allbuild": "npm run build && npm run electron && git add --all && git commit -m 'allbuild commit `git rev-parse --short HEAD`' && git push -f -u origin dev"
}
}

@ -8,8 +8,8 @@
import React, { useState } from "react";
import { AugmentationAccordion } from "../../ui/React/AugmentationAccordion";
import { Augmentations } from "../../Augmentation/Augmentations";
import { AugmentationNames } from "../../Augmentation/data/AugmentationNames";
import { Augmentations } from "../Augmentations";
import { AugmentationNames } from "../data/AugmentationNames";
import { Settings } from "../../Settings/Settings";
import { use } from "../../ui/Context";

@ -4,8 +4,8 @@
*/
import * as React from "react";
import { Augmentations } from "../../Augmentation/Augmentations";
import { AugmentationNames } from "../../Augmentation/data/AugmentationNames";
import { Augmentations } from "../Augmentations";
import { AugmentationNames } from "../data/AugmentationNames";
import { Player } from "../../Player";
import { AugmentationAccordion } from "../../ui/React/AugmentationAccordion";

@ -111,8 +111,8 @@ export const CONSTANTS: {
TotalNumBitNodes: number;
LatestUpdate: string;
} = {
VersionString: "1.4.0",
VersionNumber: 10,
VersionString: "1.5.0",
VersionNumber: 11,
// Speed (in ms) at which the main loop is updated
_idleSpeed: 200,
@ -276,32 +276,61 @@ export const CONSTANTS: {
v1.5.0 - Steam Cloud integration
--------------------------------
** Misc. **
** Steam Cloud Saving **
* Added (@MartinFournier)
** UI **
* The file API now allows GET and DELETE (@lordducky)
* Fix bug with async.
* Update documentation / typo (@lethern, @Meowdoleon, @JohnnyUrosevic, @JosephDavidTalbot,
@pd, @lethern, @lordducky, @zeddrak, @fearnlj01, @reasonablytall)
* Fix bug with corp API (@pigalot)
* background now matches game primary color (@nickofolas)
* page title contains version (@MartinFourier)
* Major text editor improvements (@nickofolas)
* Force achievement calculation on BN completion (@SagePtr)
* Cleanup in repository (@MartinFourier)
* Several improvements to the electron version (@MartinFourier)
* Add 'printf' ns function (@Ninetailed)
* Display bonus time on sleeve page (@MartinFourier)
* Several UI improvements (@nickofolas, @smolgumball)
* Fix bug with casino roulette (@jamie-mac)
* Several UI improvements (@nickofolas, @smolgumball, @DrCuriosity, @phyzical)
* Fix aug display in alpha (@Dominik Winter)
* Fix display of corporation product equation (@SagePtr)
* Make Bitverse more accessible (@ChrissiQ)
* Make corporation warehouse more accessible (@ChrissiQ)
* Make tab style more consistent (@nikfolas)
** Netscript **
* Fix bug with async.
* Add 'printf' ns function (@Ninetailed)
* Remove blob caching.
* Fix formulas access check (@Ornedan)
* Fix bug in exp calculation (@qcorradi)
* Fix NaN comparison (@qcorradi)
* Terminal history persists in savefile (@MartinFourier)
* Fix travelToCity with bad argument (@SlyCedix)
* Fix aug display in alpha (@Dominik Winter)
* Fix bug where augs could not be purchased via sing (@reacocard)
* Fix rounding error in donateToFaction (@Risenafis)
* Fix bug with weakenAnalyze (@rhobes)
* Prevent exploit with atExit (@Ornedan)
* Double 'share' power
** Corporations **
* Fix bugs with corp API (@pigalot)
* Add smart supply func to corp API (@pd)
** Misc. **
* The file API now allows GET and DELETE (@lordducky)
* Force achievement calculation on BN completion (@SagePtr)
* Cleanup in repository (@MartinFourier)
* Several improvements to the electron version (@MartinFourier)
* Fix bug with casino roulette (@jamie-mac)
* Terminal history persists in savefile (@MartinFourier)
* Fix tests (@jamie-mac)
* Fix crash with electron windows tracker (@smolgumball)
* Fix BN6/7 passive reputation gain (@BrianLDev)
* Fix Sleeve not resetting on install (@waffleattack)
* Sort joined factions (@jjayeon)
* Update documentation / typo (@lethern, @Meowdoleon, @JohnnyUrosevic, @JosephDavidTalbot,
@pd, @lethern, @lordducky, @zeddrak, @fearnlj01, @reasonablytall, @MatthewTh0,
@SagePtr, @manniL, @Jedimaster4559, @loganville, @Arrow2thekn33, @wdpk, @fwolfst,
@fschoenfeldt, @Waladil, @AdamTReineke, @citrusmunch, @factubsio, @ashtongreen,
@ChrissiQ, @DJ-Laser, @waffleattack, @ApamNapat, @CrafterKolyan, @DSteve595)
* Nerf noodle bar.
`,
};

@ -1,3 +1,5 @@
import { IPlayer } from 'src/PersonObjects/IPlayer';
import { MaterialSizes } from './MaterialSizes';
import { ICorporation } from "./ICorporation";
import { IIndustry } from "./IIndustry";
import { IndustryStartingCosts, IndustryResearchTrees } from "./IndustryData";
@ -14,12 +16,12 @@ import { EmployeePositions } from "./EmployeePositions";
import { Employee } from "./Employee";
import { IndustryUpgrades } from "./IndustryUpgrades";
import { ResearchMap } from "./ResearchMap";
import { isRelevantMaterial } from "./ui/Helpers";
export function NewIndustry(corporation: ICorporation, industry: string, name: string): void {
for (let i = 0; i < corporation.divisions.length; ++i) {
if (corporation.divisions[i].name === name) {
throw new Error("This division name is already in use!");
return;
}
}
@ -245,6 +247,57 @@ export function BuyMaterial(material: Material, amt: number): void {
material.buy = amt;
}
export function BulkPurchase(corp: ICorporation, warehouse: Warehouse, material: Material, amt: number): void {
const matSize = MaterialSizes[material.name];
const maxAmount = (warehouse.size - warehouse.sizeUsed) / matSize;
if (isNaN(amt) || amt < 0) {
throw new Error(`Invalid input amount`);
}
if (amt * matSize > maxAmount) {
throw new Error(`You do not have enough warehouse size to fit this purchase`);
}
const cost = amt * material.bCost;
if (corp.funds >= cost) {
corp.funds = corp.funds - cost;
material.qty += amt;
} else {
throw new Error(`You cannot afford this purchase.`);
}
}
export function SellShares(corporation: ICorporation, player: IPlayer, numShares: number): number {
if (isNaN(numShares)) throw new Error("Invalid value for number of shares");
if (numShares < 0) throw new Error("Invalid value for number of shares");
if (numShares > corporation.numShares) throw new Error("You don't have that many shares to sell!");
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];
corporation.numShares -= numShares;
corporation.issuedShares += numShares;
corporation.sharePrice = newSharePrice;
corporation.shareSalesUntilPriceUpdate = newSharesUntilUpdate;
corporation.shareSaleCooldown = CorporationConstants.SellSharesCooldown;
player.gainMoney(profit, "corporation");
return profit;
}
export function BuyBackShares(corporation: ICorporation, player: IPlayer, numShares: number): boolean {
if (isNaN(numShares)) throw new Error("Invalid value for number of shares");
if (numShares < 0) throw new Error("Invalid value for number of shares");
if (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!");
corporation.numShares += numShares;
corporation.issuedShares -= numShares;
player.loseMoney(numShares * buybackPrice, "corporation");
return true;
}
export function AssignJob(employee: Employee, job: string): void {
if (!Object.values(EmployeePositions).includes(job)) throw new Error(`'${job}' is not a valid job.`);
employee.pos = job;
@ -290,6 +343,7 @@ export function PurchaseWarehouse(corp: ICorporation, division: IIndustry, city:
export function UpgradeWarehouse(corp: ICorporation, division: IIndustry, warehouse: Warehouse): void {
const sizeUpgradeCost = CorporationConstants.WarehouseUpgradeBaseCost * Math.pow(1.07, warehouse.level + 1);
if (corp.funds < sizeUpgradeCost) return;
++warehouse.level;
warehouse.updateSize(corp, division);
corp.funds = corp.funds - sizeUpgradeCost;
@ -334,6 +388,9 @@ export function MakeProduct(
if (productName == null || productName === "") {
throw new Error("You must specify a name for your product!");
}
if (!division.makesProducts) {
throw new Error("You cannot create products for this industry!");
}
if (isNaN(designInvest)) {
throw new Error("Invalid value for design investment");
}
@ -343,17 +400,29 @@ export function MakeProduct(
if (corp.funds < designInvest + marketingInvest) {
throw new Error("You don't have enough company funds to make this large of an investment");
}
let maxProducts = 3
if (division.hasResearch("uPgrade: Capacity.II")) {
maxProducts = 5
} else if (division.hasResearch("uPgrade: Capacity.I")) {
maxProducts = 4
}
const products = division.products
if (Object.keys(products).length >= maxProducts) {
throw new Error(`You are already at the max products (${maxProducts}) for division: ${division.name}!`);
}
const product = new Product({
name: productName.replace(/[<>]/g, ""), //Sanitize for HTMl elements
createCity: city,
designCost: designInvest,
advCost: marketingInvest,
});
if (division.products[product.name] instanceof Product) {
if (products[product.name] instanceof Product) {
throw new Error(`You already have a product with this name!`);
}
corp.funds = corp.funds - (designInvest + marketingInvest);
division.products[product.name] = product;
products[product.name] = product;
}
export function Research(division: IIndustry, researchName: string): void {
@ -372,7 +441,7 @@ export function Research(division: IIndustry, researchName: string): void {
division.researched[researchName] = true;
}
export function ExportMaterial(divisionName: string, cityName: string, material: Material, amt: string): void {
export function ExportMaterial(divisionName: string, cityName: string, material: Material, amt: string, division?: Industry): void {
// Sanitize amt
let sanitizedAmt = amt.replace(/\s+/g, "").toUpperCase();
sanitizedAmt = sanitizedAmt.replace(/[^-()\d/*+.MAX]/g, "");
@ -388,6 +457,11 @@ export function ExportMaterial(divisionName: string, cityName: string, material:
if (n == null || isNaN(n) || n < 0) {
throw new Error("Invalid amount entered for export");
}
if (!division || !isRelevantMaterial(material.name, division)) {
throw new Error(`You cannot export material: ${material.name} to division: ${divisionName}!`);
}
const exportObj = { ind: divisionName, city: cityName, amt: sanitizedAmt };
material.exp.push(exportObj);
}

@ -174,33 +174,16 @@ export class OfficeSpace {
}
setEmployeeToJob(job: string, amount: number): boolean {
let unassignedCount = 0;
let jobCount = 0;
for (let i = 0; i < this.employees.length; ++i) {
if (this.employees[i].pos === EmployeePositions.Unassigned) {
unassignedCount++;
} else if (this.employees[i].pos === job) {
let jobCount = this.employees.reduce((acc, employee) => (employee.pos === job ? acc + 1 : acc), 0);
for (const employee of this.employees) {
if (jobCount == amount) return true
if (employee.pos === EmployeePositions.Unassigned && jobCount <= amount) {
employee.pos = job;
jobCount++;
}
}
if ((jobCount + unassignedCount) < amount) return false;
for (let i = 0; i < this.employees.length; ++i) {
if (this.employees[i].pos === EmployeePositions.Unassigned) {
if (jobCount <= amount) {
this.employees[i].pos = job;
jobCount++;
unassignedCount--;
}
if (jobCount === amount) break;
} else if (this.employees[i].pos === job) {
if (jobCount >= amount) {
this.employees[i].pos = EmployeePositions.Unassigned;
jobCount--;
unassignedCount++;
}
if (jobCount === amount) break;
} else if (employee.pos === job && jobCount >= amount) {
employee.pos = EmployeePositions.Unassigned;
jobCount--;
}
}
if (jobCount !== amount) return false;

@ -6,6 +6,8 @@ import { useCorporation } from "./Context";
import Typography from "@mui/material/Typography";
import Button from "@mui/material/Button";
import TextField from "@mui/material/TextField";
import { BuyBackShares } from '../Actions';
import { dialogBoxCreate } from '../../ui/React/DialogBox';
interface IProps {
open: boolean;
@ -36,20 +38,12 @@ export function BuybackSharesModal(props: IProps): React.ReactElement {
function buy(): void {
if (disabled) return;
if (shares === null) return;
corp.numShares += shares;
if (isNaN(corp.issuedShares)) {
console.warn("Corporation issuedShares is NaN: " + corp.issuedShares);
console.warn("Converting to number now");
const res = corp.issuedShares;
if (isNaN(res)) {
corp.issuedShares = 0;
} else {
corp.issuedShares = res;
}
try {
BuyBackShares(corp, player, shares)
}
catch (err) {
dialogBoxCreate(err + "");
}
corp.issuedShares -= shares;
player.loseMoney(shares * buybackPrice, "corporation");
props.onClose();
props.rerender();
}

@ -30,7 +30,7 @@ export function CityTabs(props: IProps): React.ReactElement {
}
return (
<>
<Tabs variant="fullWidth" value={city} onChange={handleChange}>
<Tabs variant="fullWidth" value={city} onChange={handleChange} sx={{ maxWidth: '65%' }}>
{Object.values(division.offices).map(
(office: OfficeSpace | 0) => office !== 0 && <Tab key={office.loc} label={office.loc} value={office.loc} />,
)}

@ -38,7 +38,7 @@ export function CorporationRoot(): React.ReactElement {
return (
<Context.Corporation.Provider value={corporation}>
<Tabs variant="fullWidth" value={divisionName} onChange={handleChange}>
<Tabs variant="scrollable" value={divisionName} onChange={handleChange} sx={{ maxWidth: '65%' }} scrollButtons>
<Tab label={corporation.name} value={"Overview"} />
{corporation.divisions.map((div) => (
<Tab key={div.name} label={div.name} value={div.name} />

@ -50,7 +50,7 @@ export function ExportModal(props: IProps): React.ReactElement {
function exportMaterial(): void {
try {
ExportMaterial(industry, city, props.mat, amt);
ExportMaterial(industry, city, props.mat, amt, currentDivision);
} catch (err) {
dialogBoxCreate(err + "");
}

@ -4,7 +4,7 @@ import { MaterialSizes } from "../MaterialSizes";
import { Warehouse } from "../Warehouse";
import { Material } from "../Material";
import { numeralWrapper } from "../../ui/numeralFormat";
import { BuyMaterial } from "../Actions";
import { BulkPurchase, BuyMaterial } from "../Actions";
import { Modal } from "../../ui/React/Modal";
import { useCorporation, useDivision } from "./Context";
import Typography from "@mui/material/Typography";
@ -54,33 +54,17 @@ interface IBPProps {
warehouse: Warehouse;
}
function BulkPurchase(props: IBPProps): React.ReactElement {
function BulkPurchaseSection(props: IBPProps): React.ReactElement {
const corp = useCorporation();
const [buyAmt, setBuyAmt] = useState("");
function bulkPurchase(): void {
const amount = parseFloat(buyAmt);
const matSize = MaterialSizes[props.mat.name];
const maxAmount = (props.warehouse.size - props.warehouse.sizeUsed) / matSize;
if (amount * matSize > maxAmount) {
dialogBoxCreate(`You do not have enough warehouse size to fit this purchase`);
return;
}
if (isNaN(amount) || amount < 0) {
dialogBoxCreate("Invalid input amount");
} else {
const cost = amount * props.mat.bCost;
if (corp.funds >= cost) {
corp.funds = corp.funds - cost;
props.mat.qty += amount;
} else {
dialogBoxCreate(`You cannot afford this purchase.`);
return;
}
props.onClose();
try {
BulkPurchase(corp, props.warehouse, props.mat, parseFloat(buyAmt));
} catch (err) {
dialogBoxCreate(err + "");
}
props.onClose();
}
function onKeyDown(event: React.KeyboardEvent<HTMLInputElement>): void {
@ -164,7 +148,7 @@ export function PurchaseMaterialModal(props: IProps): React.ReactElement {
<Button onClick={purchaseMaterial}>Confirm</Button>
<Button onClick={clearPurchase}>Clear Purchase</Button>
{division.hasResearch("Bulk Purchasing") && (
<BulkPurchase onClose={props.onClose} mat={props.mat} warehouse={props.warehouse} />
<BulkPurchaseSection onClose={props.onClose} mat={props.mat} warehouse={props.warehouse} />
)}
</>
</Modal>

@ -4,12 +4,12 @@ import { dialogBoxCreate } from "../../ui/React/DialogBox";
import { Modal } from "../../ui/React/Modal";
import { use } from "../../ui/Context";
import { useCorporation } from "./Context";
import { CorporationConstants } from "../data/Constants";
import { ICorporation } from "../ICorporation";
import Typography from "@mui/material/Typography";
import TextField from "@mui/material/TextField";
import Button from "@mui/material/Button";
import { Money } from "../../ui/React/Money";
import { SellShares } from "../Actions";
interface IProps {
open: boolean;
onClose: () => void;
@ -48,38 +48,23 @@ export function SellSharesModal(props: IProps): React.ReactElement {
}
function sell(): void {
if (shares === null) return;
if (disabled) return;
const stockSaleResults = corp.calculateShareSale(shares);
const profit = stockSaleResults[0];
const newSharePrice = stockSaleResults[1];
const newSharesUntilUpdate = stockSaleResults[2];
try {
const profit = SellShares(corp, player, shares)
props.onClose();
dialogBoxCreate(
<>
Sold {numeralWrapper.formatMoney(shares)} shares for
<Money money={profit} />. The corporation's stock price fell to&nbsp; <Money money={corp.sharePrice} />
as a result of dilution.
</>,
);
corp.numShares -= shares;
if (isNaN(corp.issuedShares)) {
console.error(`Corporation issuedShares is NaN: ${corp.issuedShares}`);
const res = corp.issuedShares;
if (isNaN(res)) {
corp.issuedShares = 0;
} else {
corp.issuedShares = res;
}
props.rerender();
} catch (err) {
dialogBoxCreate(err + "");
}
corp.issuedShares += shares;
corp.sharePrice = newSharePrice;
corp.shareSalesUntilPriceUpdate = newSharesUntilUpdate;
corp.shareSaleCooldown = CorporationConstants.SellSharesCooldown;
player.gainMoney(profit, "corporation");
props.onClose();
dialogBoxCreate(
<>
Sold {numeralWrapper.formatMoney(shares)} shares for
<Money money={profit} />. The corporation's stock price fell to&nbsp; <Money money={corp.sharePrice} />
as a result of dilution.
</>,
);
props.rerender();
}
function onKeyDown(event: React.KeyboardEvent<HTMLInputElement>): void {

@ -19,10 +19,18 @@ interface IProps {
export function Corporation(props: IProps): React.ReactElement {
function addTonsCorporationFunds(): void {
if (props.player.corporation) {
props.player.corporation.funds = props.player.corporation.funds + 1e99;
props.player.corporation.funds = props.player.corporation.funds + bigNumber;
}
}
function modifyCorporationFunds(modify: number): (x: number) => void {
return function (funds: number): void {
if (props.player.corporation) {
props.player.corporation.funds += funds * modify;
}
};
}
function resetCorporationFunds(): void {
if (props.player.corporation) {
props.player.corporation.funds = props.player.corporation.funds - props.player.corporation.funds;
@ -77,8 +85,17 @@ export function Corporation(props: IProps): React.ReactElement {
<tbody>
<tr>
<td>
<Button onClick={addTonsCorporationFunds}>Tons of funds</Button>
<Button onClick={resetCorporationFunds}>Reset funds</Button>
<Typography>Funds:</Typography>
</td>
<td>
<Adjuster
label="set funds"
placeholder="amt"
tons={addTonsCorporationFunds}
add={modifyCorporationFunds(1)}
subtract={modifyCorporationFunds(-1)}
reset={resetCorporationFunds}
/>
</td>
</tr>
<tr>

@ -7,7 +7,7 @@ import { PurchaseableAugmentation } from "./PurchaseableAugmentation";
import { Augmentations } from "../../Augmentation/Augmentations";
import { AugmentationNames } from "../../Augmentation/data/AugmentationNames";
import { Faction } from "../../Faction/Faction";
import { Faction } from "../Faction";
import { PurchaseAugmentationsOrderSetting } from "../../Settings/SettingEnums";
import { Settings } from "../../Settings/Settings";
import { hasAugmentationPrereqs } from "../FactionHelpers";

@ -4,7 +4,7 @@
import React, { useState } from "react";
import { CONSTANTS } from "../../Constants";
import { Faction } from "../../Faction/Faction";
import { Faction } from "../Faction";
import { IPlayer } from "../../PersonObjects/IPlayer";
import { repFromDonation } from "../formulas/donation";
import { Favor } from "../../ui/React/Favor";

@ -13,7 +13,7 @@ import { Option } from "./Option";
import { CONSTANTS } from "../../Constants";
import { BitNodeMultipliers } from "../../BitNode/BitNodeMultipliers";
import { Faction } from "../../Faction/Faction";
import { Faction } from "../Faction";
import { use } from "../../ui/Context";
import { CreateGangModal } from "./CreateGangModal";

@ -75,6 +75,15 @@ export function FactionsRoot(props: IProps): React.ReactElement {
<Button onClick={() => openFaction(Factions[faction])}>Details</Button>
</Box>
</TableCell>
<TableCell align="right">
<Typography noWrap ml={10} mb={1}>
Augmentations Left: {Factions[faction]
.augmentations
.filter((augmentation: string) =>
!props.player.hasAugmentation(augmentation))
.length}
</Typography>
</TableCell>
</TableRow>
))}
</TableBody>

@ -4,8 +4,8 @@
*/
import React, { useState, useEffect } from "react";
import { Faction } from "../../Faction/Faction";
import { FactionInfo } from "../../Faction/FactionInfo";
import { Faction } from "../Faction";
import { FactionInfo } from "../FactionInfo";
import { Reputation } from "../../ui/React/Reputation";
import { Favor } from "../../ui/React/Favor";

@ -9,7 +9,7 @@ import { PurchaseAugmentationModal } from "./PurchaseAugmentationModal";
import { Augmentations } from "../../Augmentation/Augmentations";
import { AugmentationNames } from "../../Augmentation/data/AugmentationNames";
import { Faction } from "../../Faction/Faction";
import { Faction } from "../Faction";
import { IPlayer } from "../../PersonObjects/IPlayer";
import { Settings } from "../../Settings/Settings";
import { Money } from "../../ui/React/Money";

@ -32,7 +32,7 @@ export function GangRoot(): React.ReactElement {
return (
<Context.Gang.Provider value={gang}>
<Tabs variant="fullWidth" value={value} onChange={handleChange}>
<Tabs variant="fullWidth" value={value} onChange={handleChange} sx={{ minWidth: 'fit-content', maxWidth: '45%' }}>
<Tab label="Management" />
<Tab label="Equipment" />
<Tab label="Territory" />

@ -1139,7 +1139,7 @@ export function NetscriptFunctions(workerScript: WorkerScript): NS {
// Invalid file name
if (!scriptname.endsWith(".lit") && !isScriptFilename(scriptname) && !scriptname.endsWith("txt")) {
throw makeRuntimeErrorMsg("scp", "Only works for .script, .lit, and .txt files");
throw makeRuntimeErrorMsg("scp", "Only works for scripts, .lit and .txt files");
}
let destServer: BaseServer | null;
@ -1646,7 +1646,7 @@ export function NetscriptFunctions(workerScript: WorkerScript): NS {
return cost;
},
purchaseServer: function (aname: any, aram: any): any {
updateDynamicRam("purchaseServer", getRamCost(Player, "purchaseServer"));
if (arguments.length !== 2) throw makeRuntimeErrorMsg("purchaseServer", "Takes 2 arguments");
const name = helper.string("purchaseServer", "name", aname);
const ram = helper.number("purchaseServer", "ram", aram);
updateDynamicRam("purchaseServer", getRamCost(Player, "purchaseServer"));

@ -49,6 +49,9 @@ import {
SetMaterialMarketTA2,
SetProductMarketTA1,
SetProductMarketTA2,
BulkPurchase,
SellShares,
BuyBackShares,
SetSmartSupplyUseLeftovers,
} from "../Corporation/Actions";
import { CorporationUnlockUpgrades } from "../Corporation/data/CorporationUnlockUpgrades";
@ -178,6 +181,7 @@ export function NetscriptCorporation(
return true;
}
function getResearchCost(division: IIndustry, researchName: string): number {
const researchTree = IndustryResearchTrees[division.type];
if (researchTree === undefined) throw new Error(`No research tree for industry '${division.type}'`);
@ -193,7 +197,8 @@ export function NetscriptCorporation(
function bribe(factionName: string, amountCash: number, amountShares: number): boolean {
if (!player.factions.includes(factionName)) throw new Error("Invalid faction name");
if (isNaN(amountCash) || amountCash < 0 || isNaN(amountShares) || amountShares < 0) throw new Error("Invalid value for amount field! Must be numeric, greater than 0.");
if (isNaN(amountCash) || amountCash < 0 || isNaN(amountShares) || amountShares < 0) throw new Error("Invalid value for amount field! Must be numeric, grater than 0.");
const corporation = getCorporation();
if (corporation.funds < amountCash) return false;
if (corporation.numShares < amountShares) return false;
@ -271,25 +276,25 @@ export function NetscriptCorporation(
function getSafeDivision(division: Industry): NSDivision {
const cities: string[] = [];
for (const office of Object.values(division.offices)) {
if (office === 0) continue;
cities.push(office.loc);
}
return {
name: division.name,
type: division.type,
awareness: division.awareness,
popularity: division.popularity,
prodMult: division.prodMult,
research: division.sciResearch.qty,
lastCycleRevenue: division.lastCycleRevenue,
lastCycleExpenses: division.lastCycleExpenses,
thisCycleRevenue: division.thisCycleRevenue,
thisCycleExpenses: division.thisCycleExpenses,
upgrades: division.upgrades,
cities: cities,
products: division.products === undefined ? [] : Object.keys(division.products),
};
for (const office of Object.values(division.offices)) {
if (office === 0) continue;
cities.push(office.loc);
}
return {
name: division.name,
type: division.type,
awareness: division.awareness,
popularity: division.popularity,
prodMult: division.prodMult,
research: division.sciResearch.qty,
lastCycleRevenue: division.lastCycleRevenue,
lastCycleExpenses: division.lastCycleExpenses,
thisCycleRevenue: division.thisCycleRevenue,
thisCycleExpenses: division.thisCycleExpenses,
upgrades: division.upgrades,
cities: cities,
products: division.products === undefined ? [] : Object.keys(division.products),
};
}
const warehouseAPI: WarehouseAPI = {
@ -409,6 +414,8 @@ export function NetscriptCorporation(
const cityName = helper.string("sellProduct", "cityName", acityName);
const enabled = helper.boolean(aenabled);
const warehouse = getWarehouse(divisionName, cityName);
if (!hasUnlockUpgrade("Smart Supply"))
throw helper.makeRuntimeErrorMsg(`corporation.setSmartSupply`, `You have not purchased the Smart Supply upgrade!`);
SetSmartSupply(warehouse, enabled);
},
setSmartSupplyUseLeftovers: function (adivisionName: any, acityName: any, amaterialName: any, aenabled: any): void {
@ -419,6 +426,8 @@ export function NetscriptCorporation(
const enabled = helper.boolean(aenabled);
const warehouse = getWarehouse(divisionName, cityName);
const material = getMaterial(divisionName, cityName, materialName);
if (!hasUnlockUpgrade("Smart Supply"))
throw helper.makeRuntimeErrorMsg(`corporation.setSmartSupply`, `You have not purchased the Smart Supply upgrade!`);
SetSmartSupplyUseLeftovers(warehouse, material, enabled);
},
buyMaterial: function (adivisionName: any, acityName: any, amaterialName: any, aamt: any): void {
@ -431,6 +440,18 @@ export function NetscriptCorporation(
const material = getMaterial(divisionName, cityName, materialName);
BuyMaterial(material, amt);
},
bulkPurchase: function (adivisionName: any, acityName: any, amaterialName: any, aamt: any): void {
checkAccess("bulkPurchase", 7);
const divisionName = helper.string("bulkPurchase", "divisionName", adivisionName);
if (!hasResearched(getDivision(adivisionName), "Bulk Purchasing")) throw new Error(`You have not researched Bulk Purchasing in ${divisionName}`)
const corporation = getCorporation();
const cityName = helper.string("bulkPurchase", "cityName", acityName);
const materialName = helper.string("bulkPurchase", "materialName", amaterialName);
const amt = helper.number("bulkPurchase", "amt", aamt);
const warehouse = getWarehouse(divisionName, cityName)
const material = getMaterial(divisionName, cityName, materialName);
BulkPurchase(corporation, warehouse, material, amt);
},
makeProduct: function (
adivisionName: any,
acityName: any,
@ -462,7 +483,7 @@ export function NetscriptCorporation(
const targetCity = helper.string("exportMaterial", "targetCity", atargetCity);
const materialName = helper.string("exportMaterial", "materialName", amaterialName);
const amt = helper.string("exportMaterial", "amt", aamt);
ExportMaterial(targetDivision, targetCity, getMaterial(sourceDivision, sourceCity, materialName), amt + "");
ExportMaterial(targetDivision, targetCity, getMaterial(sourceDivision, sourceCity, materialName), amt + "", getDivision(targetDivision));
},
cancelExportMaterial: function (
asourceDivision: any,
@ -487,6 +508,8 @@ export function NetscriptCorporation(
const cityName = helper.string("setMaterialMarketTA1", "cityName", acityName);
const materialName = helper.string("setMaterialMarketTA1", "materialName", amaterialName);
const on = helper.boolean(aon);
if (!getDivision(divisionName).hasResearch("Market-TA.I"))
throw helper.makeRuntimeErrorMsg(`corporation.setMaterialMarketTA1`, `You have not researched MarketTA.I for division: ${divisionName}`);
SetMaterialMarketTA1(getMaterial(divisionName, cityName, materialName), on);
},
setMaterialMarketTA2: function (adivisionName: any, acityName: any, amaterialName: any, aon: any): void {
@ -495,6 +518,8 @@ export function NetscriptCorporation(
const cityName = helper.string("setMaterialMarketTA2", "cityName", acityName);
const materialName = helper.string("setMaterialMarketTA2", "materialName", amaterialName);
const on = helper.boolean(aon);
if (!getDivision(divisionName).hasResearch("Market-TA.II"))
throw helper.makeRuntimeErrorMsg(`corporation.setMaterialMarketTA2`, `You have not researched MarketTA.II for division: ${divisionName}`);
SetMaterialMarketTA2(getMaterial(divisionName, cityName, materialName), on);
},
setProductMarketTA1: function (adivisionName: any, aproductName: any, aon: any): void {
@ -502,6 +527,8 @@ export function NetscriptCorporation(
const divisionName = helper.string("setProductMarketTA1", "divisionName", adivisionName);
const productName = helper.string("setProductMarketTA1", "productName", aproductName);
const on = helper.boolean(aon);
if (!getDivision(divisionName).hasResearch("Market-TA.I"))
throw helper.makeRuntimeErrorMsg(`corporation.setProductMarketTA1`, `You have not researched MarketTA.I for division: ${divisionName}`);
SetProductMarketTA1(getProduct(divisionName, productName), on);
},
setProductMarketTA2: function (adivisionName: any, aproductName: any, aon: any): void {
@ -509,6 +536,8 @@ export function NetscriptCorporation(
const divisionName = helper.string("setProductMarketTA2", "divisionName", adivisionName);
const productName = helper.string("setProductMarketTA2", "productName", aproductName);
const on = helper.boolean(aon);
if (!getDivision(divisionName).hasResearch("Market-TA.II"))
throw helper.makeRuntimeErrorMsg(`corporation.setProductMarketTA2`, `You have not researched MarketTA.II for division: ${divisionName}`);
SetProductMarketTA2(getProduct(divisionName, productName), on);
},
};
@ -723,6 +752,8 @@ export function NetscriptCorporation(
const percent = helper.number("issueDividends", "percent", apercent);
if (percent < 0 || percent > 100) throw new Error("Invalid value for percent field! Must be numeric, greater than 0, and less than 100");
const corporation = getCorporation();
if (!corporation.public)
throw helper.makeRuntimeErrorMsg(`corporation.issueDividends`, `Your company has not gone public!`);
IssueDividends(corporation, percent);
},
@ -781,24 +812,34 @@ export function NetscriptCorporation(
const industryName = helper.string("getExpandIndustryCost", "industryName", aindustryName);
return getExpandIndustryCost(industryName);
},
getExpandCityCost: function(): number {
getExpandCityCost: function (): number {
checkAccess("getExpandCityCost");
return getExpandCityCost();
},
getInvestmentOffer: function(): InvestmentOffer {
getInvestmentOffer: function (): InvestmentOffer {
checkAccess("getInvestmentOffer");
return getInvestmentOffer();
},
acceptInvestmentOffer: function(): boolean {
acceptInvestmentOffer: function (): boolean {
checkAccess("acceptInvestmentOffer");
return acceptInvestmentOffer();
},
goPublic: function(anumShares: any): boolean {
goPublic: function (anumShares: any): boolean {
checkAccess("acceptInvestmentOffer");
const numShares = helper.number("goPublic", "numShares", anumShares);
return goPublic(numShares);
},
bribe: function(afactionName: string, aamountCash: any, aamountShares: any): boolean {
sellShares: function (anumShares: any): number {
checkAccess("acceptInvestmentOffer");
const numShares = helper.number("sellStock", "numShares", anumShares);
return SellShares(getCorporation(), player, numShares);
},
buyBackShares: function (anumShares: any): boolean {
checkAccess("acceptInvestmentOffer");
const numShares = helper.number("buyStock", "numShares", anumShares);
return BuyBackShares(getCorporation(), player, numShares);
},
bribe: function (afactionName: string, aamountCash: any, aamountShares: any): boolean {
checkAccess("bribe");
const factionName = helper.string("bribe", "factionName", afactionName);
const amountCash = helper.number("bribe", "amountCash", aamountCash);

@ -14,7 +14,6 @@ export function NetscriptPort(): IPort {
const data: any[] = [];
return {
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
write: (value: any): any => {
data.push(value);
if (data.length > Settings.MaxPortCapacity) {
@ -23,7 +22,6 @@ export function NetscriptPort(): IPort {
return null;
},
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
tryWrite: (value: any): boolean => {
if (data.length >= Settings.MaxPortCapacity) {
return false;

@ -1,5 +1,5 @@
export function CalculateShareMult(power: number): number {
const x = 1 + Math.log(power) / (8 * Math.log(1000));
const x = 1 + Math.log(power) / 25;
if (isNaN(x) || !isFinite(x)) return 1;
return x;
}

@ -25,7 +25,7 @@ import { Cities } from "../../Locations/Cities";
import { Locations } from "../../Locations/Locations";
import { CityName } from "../../Locations/data/CityNames";
import { LocationName } from "../../Locations/data/LocationNames";
import { Sleeve } from "../../PersonObjects/Sleeve/Sleeve";
import { Sleeve } from "../Sleeve/Sleeve";
import {
calculateSkill as calculateSkillF,
calculateSkillProgress as calculateSkillProgressF,

@ -456,7 +456,7 @@ export class Sleeve extends Person {
// Reset Location
this.city=CityName.Sector12;
this.city = CityName.Sector12;
// Reset sleeve-related stats
this.shock = 1;
@ -859,10 +859,8 @@ export class Sleeve extends Person {
* Returns boolean indicating success
*/
workForFaction(p: IPlayer, factionName: string, workType: string): boolean {
if (factionName === "") {
return false;
}
if (!(Factions[factionName] instanceof Faction) || !p.factions.includes(factionName)) {
const faction = Factions[factionName]
if (factionName === "" || !faction || !(faction instanceof Faction) || !p.factions.includes(factionName)) {
return false;
}
@ -872,7 +870,7 @@ export class Sleeve extends Person {
this.resetTaskStatus();
}
const factionInfo = Factions[factionName].getInfo();
const factionInfo = faction.getInfo();
// Set type of work (hacking/field/security), and the experience gains
const sanitizedWorkType: string = workType.toLowerCase();

@ -17,10 +17,10 @@ import { Money } from "../../../ui/React/Money";
import { MoneyRate } from "../../../ui/React/MoneyRate";
import { use } from "../../../ui/Context";
import { ReputationRate } from "../../../ui/React/ReputationRate";
import { StatsElement } from "../ui/StatsElement";
import { StatsElement } from "./StatsElement";
import { MoreStatsModal } from "./MoreStatsModal";
import { MoreEarningsModal } from "../ui/MoreEarningsModal";
import { TaskSelector } from "../ui/TaskSelector";
import { MoreEarningsModal } from "./MoreEarningsModal";
import { TaskSelector } from "./TaskSelector";
import { FactionWorkType } from "../../../Faction/FactionWorkTypeEnum";
import { StatsTable } from "../../../ui/React/StatsTable";

@ -11,7 +11,7 @@ import acorn, { parse } from "acorn";
import { RamCalculationErrorCode } from "./RamCalculationErrorCodes";
import { RamCosts, RamCostConstants } from "../Netscript/RamCostGenerator";
import { Script } from "../Script/Script";
import { Script } from "./Script";
import { WorkerScript } from "../Netscript/WorkerScript";
import { areImportsEquals } from "../Terminal/DirectoryHelpers";
import { IPlayer } from "../PersonObjects/IPlayer";

@ -2,7 +2,7 @@ import { CONSTANTS } from "../Constants";
import { Player } from "../Player";
import { BaseServer } from "../Server/BaseServer";
import { Server } from "../Server/Server";
import { RunningScript } from "../Script/RunningScript";
import { RunningScript } from "./RunningScript";
import { processSingleServerGrowth } from "../Server/ServerHelpers";
import { GetServer } from "../Server/AllServers";

@ -535,6 +535,8 @@ export interface BitNodeMultipliers {
CompanyWorkExpGain: number;
/** Influences how much money the player earns when completing working their job. */
CompanyWorkMoney: number;
/** Influences the money gain from dividends of corporations created by the player. */
CorporationSoftCap: number;
/** Influences the valuation of corporations created by the player. */
CorporationValuation: number;
/** Influences the base experience gained for each ability when the player commits a crime. */
@ -6382,6 +6384,14 @@ export interface WarehouseAPI {
* @param amt - Amount of material to buy
*/
buyMaterial(divisionName: string, cityName: string, materialName: string, amt: number): void;
/**
* Set material to bulk buy
* @param divisionName - Name of the division
* @param cityName - Name of the city
* @param materialName - Name of the material
* @param amt - Amount of material to buy
*/
bulkPurchase(divisionName: string, cityName: string, materialName: string, amt: number): void;
/**
* Get warehouse data
* @param divisionName - Name of the division
@ -6622,6 +6632,18 @@ export interface Corporation extends WarehouseAPI, OfficeAPI {
* @param percent - Percent of profit to issue as dividends.
*/
issueDividends(percent: number): void;
/**
* Buyback Shares
* @param amount - Amount of shares to buy back.
*
*/
buyBackShares(amount: number): void;
/**
* Sell Shares
* @param amount - Amount of shares to sell.
*
*/
sellShares(amount: number): void;
}
/**
@ -6882,3 +6904,14 @@ interface GameInfo {
commit: string;
platform: string;
}
/**
* Used for autocompletion
* @public
*/
interface AutocompleteData {
servers: string[];
scripts: string[];
txts: string[];
flags(schema: [string, string | number | boolean | string[]][]): any;
}

@ -1,4 +1,3 @@
/* eslint-disable @typescript-eslint/no-non-null-assertion */
import React, { useState, useEffect, useRef, useMemo } from "react";
import Editor, { Monaco } from "@monaco-editor/react";
import * as monaco from "monaco-editor";
@ -812,7 +811,6 @@ export function Root(props: IProps): React.ReactElement {
{...provided.dragHandleProps}
style={{
...provided.draggableProps.style,
minWidth: '200px',
maxWidth: `${tabMaxWidth}px`,
marginRight: `${tabMargin}px`,
flexShrink: 0,

@ -14,7 +14,7 @@ import { WorkerScript } from "../Netscript/WorkerScript";
import { IMap } from "../types";
import { EventEmitter } from "../utils/EventEmitter";
import { numeralWrapper } from ".././ui/numeralFormat";
import { numeralWrapper } from "../ui/numeralFormat";
import { dialogBoxCreate } from "../ui/React/DialogBox";
import { Reviver } from "../utils/JSONReviver";

@ -5,7 +5,7 @@ import { toString } from "lodash";
import React from "react";
import { IPlayer } from "../../PersonObjects/IPlayer";
import { BaseServer } from "../../Server/BaseServer";
import { evaluateDirectoryPath, getFirstParentDirectory, isValidDirectoryPath } from "../../Terminal/DirectoryHelpers";
import { evaluateDirectoryPath, getFirstParentDirectory, isValidDirectoryPath } from "../DirectoryHelpers";
import { IRouter } from "../../ui/Router";
import { ITerminal } from "../ITerminal";

@ -10,6 +10,7 @@ import { HelpTexts } from "./HelpText";
import { isScriptFilename } from "../Script/isScriptFilename";
import { compile } from "../NetscriptJSEvaluator";
import { Flags } from "../NetscriptFunctions/Flags";
import { AutocompleteData } from "../ScriptEditor/NetscriptDefinitions";
import * as libarg from "arg";
// An array of all Terminal commands
@ -298,26 +299,27 @@ export async function determineAllPossibilitiesForTabCompletion(
argv: command.slice(2),
});
const flagFunc = Flags(flags._);
const autocompleteData: AutocompleteData = {
servers: GetAllServers().map((server) => server.hostname),
scripts: currServ.scripts.map((script) => script.filename),
txts: currServ.textFiles.map((txt) => txt.fn),
flags: (schema: any) => {
pos2 = schema.map((f: any) => {
if (f[0].length === 1) return "-" + f[0];
return "--" + f[0];
});
try {
return flagFunc(schema);
} catch (err) {
return undefined;
}
},
}
let pos: string[] = [];
let pos2: string[] = [];
pos = pos.concat(
loadedModule.autocomplete(
{
servers: GetAllServers().map((server) => server.hostname),
scripts: currServ.scripts.map((script) => script.filename),
txts: currServ.textFiles.map((txt) => txt.fn),
flags: (schema: any) => {
pos2 = schema.map((f: any) => {
if (f[0].length === 1) return "-" + f[0];
return "--" + f[0];
});
try {
return flagFunc(schema);
} catch (err) {
return undefined;
}
},
},
autocompleteData,
flags._,
),
);

@ -114,7 +114,6 @@ Reviver.constructors.TextFile = TextFile;
* @param server The server object to look in
* @returns The file object, or null if it couldn't find it.
*/
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
export function getTextFile(fn: string, server: BaseServer): TextFile | null {
let filename: string = !fn.endsWith(".txt") ? `${fn}.txt` : fn;
@ -138,7 +137,6 @@ export function getTextFile(fn: string, server: BaseServer): TextFile | null {
* @param server The server that the file should be created on.
* @returns The instance of the file.
*/
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
export function createTextFile(fn: string, txt: string, server: BaseServer): TextFile | undefined {
if (getTextFile(fn, server) !== null) {
// This should probably be a `throw`...

@ -336,6 +336,37 @@ export function refreshTheme(): void {
color: Settings.theme.primary,
},
},
root: {
backgroundColor: Settings.theme.backgroundsecondary,
border: "1px solid " + Settings.theme.well,
margin: '3px',
"&.Mui-selected": {
backgroundColor: Settings.theme.button
},
},
},
},
MuiTabs: {
styleOverrides: {
scrollButtons: {
backgroundColor: Settings.theme.backgroundsecondary,
color: Settings.theme.secondary,
margin: '3px',
opacity: 1,
width: 'fit-content',
"&.Mui-disabled": {
opacity: 0.5
}
}
},
defaultProps: {
TabIndicatorProps: {
style: {
display: "none"
}
}
},
},
MuiAlert: {

@ -816,7 +816,7 @@ export const codingContractTypesMetadata: ICodingContractTypeMetadata[] = [
`Examples:\n`,
`"()())()" -> [()()(), (())()]\n`,
`"(a)())()" -> [(a)()(), (a())()]\n`,
`")( -> [""]`,
`")(" -> [""]`,
].join(" ");
},
difficulty: 10,

@ -401,9 +401,12 @@ const Engine: {
() =>
AlertEvents.emit(
<>
Offline for {timeOfflineString}. While you were offline, your scripts generated{" "}
<Money money={offlineHackingIncome} />, your Hacknet Nodes generated {hacknetProdInfo} and you gained{" "}
<Reputation reputation={offlineReputation} /> reputation divided amongst your factions.
Offline for {timeOfflineString}. While you were offline:
<ul>
<li>Your scripts generated{" "} <Money money={offlineHackingIncome} /></li>
<li>Your Hacknet Nodes generated {hacknetProdInfo}</li>
<li>You gained{" "} <Reputation reputation={offlineReputation} /> reputation divided amongst your factions</li>
</ul>
</>,
),
250,

@ -31,9 +31,9 @@ export function ActiveScriptsRoot(props: IProps): React.ReactElement {
}
return (
<>
<Tabs variant="fullWidth" value={tab} onChange={handleChange}>
<Tabs variant="fullWidth" value={tab} onChange={handleChange} sx={{ minWidth: 'fit-content', maxWidth: '25%' }}>
<Tab label={"Active"} value={"active"} />
<Tab label={"Recent"} value={"recent"} />
<Tab label={"Recently Killed"} value={"recent"} />
</Tabs>
{tab === "active" && <ActiveScriptsPage workerScripts={props.workerScripts} />}

@ -26,7 +26,7 @@ import { convertTimeMsToTimeElapsedString } from "../../utils/StringHelperFuncti
import { arrayToString } from "../../utils/helpers/arrayToString";
import { Money } from "../React/Money";
import { MoneyRate } from "../React/MoneyRate";
import { RecentScript } from "../..//Netscript/RecentScripts";
import { RecentScript } from "../../Netscript/RecentScripts";
import { LogBoxEvents } from "../React/LogBoxManager";
const useStyles = makeStyles({

@ -1,6 +1,6 @@
import React, { useState, useEffect } from "react";
import { numeralWrapper } from "../ui/numeralFormat";
import { numeralWrapper } from "./numeralFormat";
import { convertTimeMsToTimeElapsedString } from "../utils/StringHelperFunctions";
import { BitNodeMultipliers } from "../BitNode/BitNodeMultipliers";
import { SourceFileFlags } from "../SourceFile/SourceFileFlags";

@ -44,7 +44,7 @@ import { CorporationRoot } from "../Corporation/ui/CorporationRoot";
import { InfiltrationRoot } from "../Infiltration/ui/InfiltrationRoot";
import { ResleeveRoot } from "../PersonObjects/Resleeving/ui/ResleeveRoot";
import { WorkInProgressRoot } from "./WorkInProgressRoot";
import { GameOptionsRoot } from "../ui/React/GameOptionsRoot";
import { GameOptionsRoot } from "./React/GameOptionsRoot";
import { SleeveRoot } from "../PersonObjects/Sleeve/ui/SleeveRoot";
import { HacknetRoot } from "../Hacknet/ui/HacknetRoot";
import { GenericLocation } from "../Locations/ui/GenericLocation";
@ -54,7 +54,7 @@ import { Root as ScriptEditorRoot } from "../ScriptEditor/ui/ScriptEditorRoot";
import { MilestonesRoot } from "../Milestones/ui/MilestonesRoot";
import { TerminalRoot } from "../Terminal/ui/TerminalRoot";
import { TutorialRoot } from "../Tutorial/ui/TutorialRoot";
import { ActiveScriptsRoot } from "../ui/ActiveScripts/ActiveScriptsRoot";
import { ActiveScriptsRoot } from "./ActiveScripts/ActiveScriptsRoot";
import { FactionsRoot } from "../Faction/ui/FactionsRoot";
import { FactionRoot } from "../Faction/ui/FactionRoot";
import { CharacterStats } from "./CharacterStats";

@ -1,6 +1,6 @@
import React, { useState, useEffect } from "react";
import { EventEmitter } from "../../utils/EventEmitter";
import { Modal } from "../../ui/React/Modal";
import { Modal } from "./Modal";
import Typography from "@mui/material/Typography";
import Box from "@mui/material/Box";
import {sha256} from "js-sha256";

@ -4,7 +4,7 @@ import React, { useState, useEffect } from "react";
import { Theme, useTheme } from "@mui/material/styles";
import makeStyles from "@mui/styles/makeStyles";
import createStyles from "@mui/styles/createStyles";
import { numeralWrapper } from "../../ui/numeralFormat";
import { numeralWrapper } from "../numeralFormat";
import { Reputation } from "./Reputation";
import { KillScriptsModal } from "./KillScriptsModal";
import { convertTimeMsToTimeElapsedString } from "../../utils/StringHelperFunctions";

@ -1,5 +1,5 @@
import * as React from "react";
import { numeralWrapper } from "../../ui/numeralFormat";
import { numeralWrapper } from "../numeralFormat";
import { Theme } from "@mui/material/styles";
import makeStyles from "@mui/styles/makeStyles";
import createStyles from "@mui/styles/createStyles";

@ -1,6 +1,6 @@
import React from "react";
import { numeralWrapper } from "../../ui/numeralFormat";
import { Hashes } from "../../ui/React/Hashes";
import { numeralWrapper } from "../numeralFormat";
import { Hashes } from "./Hashes";
export function HashRate({ hashes }: { hashes: number }): React.ReactElement {
return <Hashes hashes={`${numeralWrapper.formatHashes(hashes)} h / s`} />;

@ -1,5 +1,5 @@
import * as React from "react";
import { numeralWrapper } from "../../ui/numeralFormat";
import { numeralWrapper } from "../numeralFormat";
import { Theme } from "@mui/material/styles";
import makeStyles from "@mui/styles/makeStyles";
import createStyles from "@mui/styles/createStyles";

@ -1,5 +1,5 @@
import * as React from "react";
import { numeralWrapper } from "../../ui/numeralFormat";
import { numeralWrapper } from "../numeralFormat";
import { IPlayer } from "../../PersonObjects/IPlayer";
import { Theme } from "@mui/material/styles";
import makeStyles from "@mui/styles/makeStyles";

@ -1,6 +1,6 @@
import React from "react";
import { numeralWrapper } from "../../ui/numeralFormat";
import { Money } from "../../ui/React/Money";
import { numeralWrapper } from "../numeralFormat";
import { Money } from "./Money";
export function MoneyRate({ money }: { money: number }): JSX.Element {
return <Money money={`${numeralWrapper.formatMoney(money)} / sec`} />;

@ -1,6 +1,6 @@
import React, { useState, useEffect } from "react";
import { EventEmitter } from "../../utils/EventEmitter";
import { Modal } from "../../ui/React/Modal";
import { Modal } from "./Modal";
import Typography from "@mui/material/Typography";
import Button from "@mui/material/Button";

@ -1,5 +1,5 @@
import * as React from "react";
import { numeralWrapper } from "../../ui/numeralFormat";
import { numeralWrapper } from "../numeralFormat";
import { Theme } from "@mui/material/styles";
import makeStyles from "@mui/styles/makeStyles";
import createStyles from "@mui/styles/createStyles";

@ -1,6 +1,6 @@
import React from "react";
import { numeralWrapper } from "../../ui/numeralFormat";
import { Reputation } from "../../ui/React/Reputation";
import { numeralWrapper } from "../numeralFormat";
import { Reputation } from "./Reputation";
export function ReputationRate({ reputation }: { reputation: number }): React.ReactElement {
return <Reputation reputation={`${numeralWrapper.formatReputation(reputation)} / sec`} />;

@ -16,7 +16,6 @@ import "numeral/locales/ru";
import { Settings } from "../Settings/Settings";
/* eslint-disable class-methods-use-this */
const extraFormats = [1e15, 1e18, 1e21, 1e24, 1e27, 1e30];
const extraNotations = ["q", "Q", "s", "S", "o", "n"];

@ -1,4 +1,3 @@
/* eslint-disable spaced-comment */
module.exports = {
plugins: [
"stylelint-order" /*,

@ -15,7 +15,6 @@
/**
* @type {Cypress.PluginConfig}
*/
// eslint-disable-next-line no-unused-vars
module.exports = (/*on, config*/) => {
// `on` is used to hook into various events Cypress emits
// `config` is the resolved Cypress config

@ -1,4 +1,3 @@
// eslint-disable-next-line @typescript-eslint/no-unused-vars
import { jest, describe, expect } from "@jest/globals";
import { Player } from "../../../src/Player";

@ -1,3 +1,4 @@
/* eslint-disable no-await-in-loop */
import { Octokit } from "@octokit/rest";
import commandLineArgs from "command-line-args";
@ -32,10 +33,10 @@ class MergeChangelog {
sha: entry.sha,
url: entry.html_url,
user: {
id: entry.author.id,
login: entry.author.login,
avatar: entry.author.avatar_url,
url: entry.author.html_url,
id: entry.author?.id,
login: entry.author?.login,
avatar: entry.author?.avatar_url,
url: entry.author?.html_url,
},
commit_date: entry.commit.committer.date,
message: entry.commit.message,
@ -78,20 +79,19 @@ class MergeChangelog {
searchResults.push(...entries);
}
const pullRequestPromises = [];
const pulls = [];
for (const entry of searchResults) {
pullRequestPromises.push(
this.octokit.rest.pulls.get({
owner, repo,
pull_number: entry.number,
}).then((response) => ({
...entry,
merge_commit_sha: response.data.merge_commit_sha,
head_commit_sha: response.data.head.sha,
const r = await (this.octokit.rest.pulls.get({
owner, repo,
pull_number: entry.number,
}).then((response) => ({
...entry,
merge_commit_sha: response.data.merge_commit_sha,
head_commit_sha: response.data.head.sha,
})));
pulls.push(r);
await sleep(1000);
}
const pulls = await Promise.all(pullRequestPromises);
return pulls;
}
@ -128,8 +128,9 @@ class MergeChangelog {
const pullQuery = `user:${owner} repo:${repo} is:pr is:merged merged:"${from.date.toISOString()}..${to.date.toISOString()}"`;
const commits = await this.getCommitsSearchResults(commitQuery);
await sleep(5000)
const pulls = await this.getPullsSearchResults(pullQuery);
await sleep(5000)
// We only have the merge commit sha & the HEAD sha in this data, but it can exclude some entries
const pullsCommitSha = pulls.
map((p) => [p.merge_commit_sha, p.head_commit_sha]).
@ -234,6 +235,12 @@ ${commitLines.join('\n')}
}
}
const sleep = async (wait) => {
return new Promise((resolve) => {
setTimeout(resolve, wait)
})
}
const api = new MergeChangelog({ auth: process.env.GITHUB_API_TOKEN });
api.getChangelog(cliArgs.from, cliArgs.to, cliArgs.detailed).then((data) => {
console.log(data.log);