diff --git a/.github/PULL_REQUEST_TEMPLATE b/.github/PULL_REQUEST_TEMPLATE index fe4a745c6..5e99eddd2 100644 --- a/.github/PULL_REQUEST_TEMPLATE +++ b/.github/PULL_REQUEST_TEMPLATE @@ -5,16 +5,20 @@ # PR title Formatted as such: -SECTION: FIX #xzyw PLAYER DESCRIPTION +SECTION: PLAYER DESCRIPTION SECTION is something like "API", "UI", "MISC", "STANEK", "CORPORATION" -FIX #xyzw is the issue number, if any PLAYER DESCRIPTION is what you'd tell a non-contributor to convey what is changed. # Linked issues If your pull request is related to a git issue, please link it in the description using #xyz. -If your PR should close the issue when it is merged in, use `fixes #xyz` or `closes #xyz`. It'll automate the process. +If your PR should close the issue when it is merged in, use `fixes #xyz` or `closes #xyz` like this: + +closes #xxxx +closes #yyyy + +It'll automate the process. # Documentation diff --git a/markdown/bitburner.sleeve.settobladeburneraction.md b/markdown/bitburner.sleeve.settobladeburneraction.md index 3d9bf246c..02ae7c814 100644 --- a/markdown/bitburner.sleeve.settobladeburneraction.md +++ b/markdown/bitburner.sleeve.settobladeburneraction.md @@ -16,7 +16,7 @@ setToBladeburnerAction(sleeveNumber: number, action: string, contract?: string): | Parameter | Type | Description | | --- | --- | --- | -| sleeveNumber | number | Index of the sleeve to workout at the gym. | +| sleeveNumber | number | Index of the sleeve which will perform Action. | | action | string | Name of the action to be performed. | | contract | string | Name of the contract if applicable. | diff --git a/src/Augmentation/data/AugmentationCreator.tsx b/src/Augmentation/data/AugmentationCreator.tsx index e21aca702..19a086fc5 100644 --- a/src/Augmentation/data/AugmentationCreator.tsx +++ b/src/Augmentation/data/AugmentationCreator.tsx @@ -1661,17 +1661,17 @@ export const initGeneralAugmentations = (): Augmentation[] => [ }), // Sleeve exclusive augmentations - new Augmentation({ - name: AugmentationNames.UnnamedAug1, - isSpecial: true, - repCost: Infinity, - moneyCost: 1e12, - info: "This augmentation is exclusive to sleeves.", - stats: <>Allows sleeves to benefit from Stanek's Gift but it is less powerful if several are installed., - factions: [ - /*Technically in FactionNames.ChurchOfTheMachineGod but not really for display reasons */ - ], - }), + // new Augmentation({ + // name: AugmentationNames.UnnamedAug1, + // isSpecial: true, + // repCost: Infinity, + // moneyCost: 1e12, + // info: "This augmentation is exclusive to sleeves.", + // stats: <>Allows sleeves to benefit from Stanek's Gift but it is less powerful if several are installed., + // factions: [ + // /*Technically in FactionNames.ChurchOfTheMachineGod but not really for display reasons */ + // ], + // }), ]; export const initBladeburnerAugmentations = (): Augmentation[] => [ diff --git a/src/Corporation/Actions.ts b/src/Corporation/Actions.ts index fbcad46f3..bf53d1e2f 100644 --- a/src/Corporation/Actions.ts +++ b/src/Corporation/Actions.ts @@ -1,6 +1,8 @@ +import { Player } from "../Player"; import { IPlayer } from "src/PersonObjects/IPlayer"; import { MaterialSizes } from "./MaterialSizes"; import { ICorporation } from "./ICorporation"; +import { Corporation } from "./Corporation"; import { IIndustry } from "./IIndustry"; import { IndustryStartingCosts, IndustryResearchTrees } from "./IndustryData"; import { Industry } from "./Industry"; @@ -463,6 +465,23 @@ export function Research(division: IIndustry, researchName: string): void { // Get the Node from the Research Tree and set its 'researched' property researchTree.research(researchName); division.researched[researchName] = true; + + // I couldn't figure out where else to put this so that warehouse size would get updated instantly + // whether research is done by script or UI. All other stats gets calculated in every cycle + // Warehouse size gets updated only when something increases it. + if (researchName == "Drones - Transport") { + for (let i = 0; i < CorporationConstants.Cities.length; ++i) { + const city = CorporationConstants.Cities[i]; + const warehouse = division.warehouses[city]; + if (!(warehouse instanceof Warehouse)) { + continue; + } + if (Player.corporation instanceof Corporation) { + // Stores cycles in a "buffer". Processed separately using Engine Counters + warehouse.updateSize(Player.corporation, division); + } + } + } } export function ExportMaterial( diff --git a/src/Corporation/Corporation.tsx b/src/Corporation/Corporation.tsx index b6acdadfa..cf6ac9125 100644 --- a/src/Corporation/Corporation.tsx +++ b/src/Corporation/Corporation.tsx @@ -83,6 +83,10 @@ export class Corporation { const gameCycles = marketCycles * CorporationConstants.CyclesPerIndustryStateCycle; this.storedCycles -= gameCycles; + this.divisions.forEach((ind) => { + ind.resetImports(state); + }); + this.divisions.forEach((ind) => { ind.process(marketCycles, state, this); }); @@ -230,6 +234,7 @@ export class Corporation { let sharePrice = this.sharePrice; let sharesSold = 0; let profit = 0; + let targetPrice = this.getTargetSharePrice(); const maxIterations = Math.ceil(numShares / CorporationConstants.SHARESPERPRICEUPDATE); if (isNaN(maxIterations) || maxIterations > 10e6) { @@ -249,9 +254,13 @@ export class Corporation { sharesUntilUpdate = CorporationConstants.SHARESPERPRICEUPDATE; sharesTracker -= sharesUntilUpdate; sharesSold += sharesUntilUpdate; - + targetPrice = this.valuation / (2 * (this.totalShares + sharesSold - this.numShares)); // Calculate what new share price would be - sharePrice = this.valuation / (2 * (this.totalShares + sharesSold - this.numShares)); + if (sharePrice <= targetPrice) { + sharePrice *= 1 + 0.5 * 0.01; + } else { + sharePrice *= 1 - 0.5 * 0.01; + } } } diff --git a/src/Corporation/IIndustry.ts b/src/Corporation/IIndustry.ts index 463af4bdf..0ea8646a1 100644 --- a/src/Corporation/IIndustry.ts +++ b/src/Corporation/IIndustry.ts @@ -54,6 +54,7 @@ export interface IIndustry { processMaterials(marketCycles: number, corporation: ICorporation): [number, number]; processProducts(marketCycles: number, corporation: ICorporation): [number, number]; processProduct(marketCycles: number, product: Product, corporation: ICorporation): number; + resetImports(state: string): void; discontinueProduct(product: Product): void; getAdVertCost(): number; applyAdVert(corporation: ICorporation): void; diff --git a/src/Corporation/Industry.ts b/src/Corporation/Industry.ts index 083dd484a..8ec68f26f 100644 --- a/src/Corporation/Industry.ts +++ b/src/Corporation/Industry.ts @@ -523,24 +523,6 @@ export class Industry implements IIndustry { expenses = 0; this.calculateProductionFactors(); - //At the start of the export state, set the imports of everything to 0 - if (this.state === "EXPORT") { - for (let i = 0; i < CorporationConstants.Cities.length; ++i) { - const city = CorporationConstants.Cities[i]; - if (!(this.warehouses[city] instanceof Warehouse)) { - continue; - } - const warehouse = this.warehouses[city]; - if (warehouse === 0) continue; - for (const matName of Object.keys(warehouse.materials)) { - if (warehouse.materials.hasOwnProperty(matName)) { - const mat = warehouse.materials[matName]; - mat.imp = 0; - } - } - } - } - for (let i = 0; i < CorporationConstants.Cities.length; ++i) { const city = CorporationConstants.Cities[i]; const office = this.offices[city]; @@ -1236,6 +1218,26 @@ export class Industry implements IIndustry { return totalProfit; } + resetImports(state: string): void { + //At the start of the export state, set the imports of everything to 0 + if (state === "EXPORT") { + for (let i = 0; i < CorporationConstants.Cities.length; ++i) { + const city = CorporationConstants.Cities[i]; + if (!(this.warehouses[city] instanceof Warehouse)) { + continue; + } + const warehouse = this.warehouses[city]; + if (warehouse === 0) continue; + for (const matName of Object.keys(warehouse.materials)) { + if (warehouse.materials.hasOwnProperty(matName)) { + const mat = warehouse.materials[matName]; + mat.imp = 0; + } + } + } + } + } + discontinueProduct(product: Product): void { for (const productName of Object.keys(this.products)) { if (this.products.hasOwnProperty(productName)) { diff --git a/src/Corporation/ui/modals/IssueNewSharesModal.tsx b/src/Corporation/ui/modals/IssueNewSharesModal.tsx index eee79a300..85c7f8b97 100644 --- a/src/Corporation/ui/modals/IssueNewSharesModal.tsx +++ b/src/Corporation/ui/modals/IssueNewSharesModal.tsx @@ -110,7 +110,7 @@ export function IssueNewSharesModal(props: IProps): React.ReactElement { You can issue new equity shares (i.e. stocks) in order to raise capital for your corporation.

-  * You can issue at most {numeralWrapper.formatMoney(maxNewShares)} new shares +  * You can issue at most {numeralWrapper.format(maxNewShares, "0.000a")} new shares
 * New shares are sold at a 10% discount
diff --git a/src/NetscriptFunctions/Singularity.ts b/src/NetscriptFunctions/Singularity.ts index e5f51dd0f..c3b1adf16 100644 --- a/src/NetscriptFunctions/Singularity.ts +++ b/src/NetscriptFunctions/Singularity.ts @@ -954,7 +954,7 @@ export function NetscriptSingularity(): InternalAPI { // if the player is in a gang and the target faction is any of the gang faction, fail if (player.inGang() && faction.name === player.getGangFaction().name) { - helpers.log(ctx, () => `You can't work for '${facName}' because youre managing a gang for it`); + helpers.log(ctx, () => `You can't work for '${facName}' because you're managing a gang for it.`); return false; } diff --git a/src/PersonObjects/Sleeve/SleeveHelpers.ts b/src/PersonObjects/Sleeve/SleeveHelpers.ts index 279388968..8bdf95fcc 100644 --- a/src/PersonObjects/Sleeve/SleeveHelpers.ts +++ b/src/PersonObjects/Sleeve/SleeveHelpers.ts @@ -2,12 +2,14 @@ import { FactionNames } from "../../Faction/data/FactionNames"; import { Sleeve } from "./Sleeve"; import { IPlayer } from "../IPlayer"; +import { Player } from "../../Player"; import { Augmentation } from "../../Augmentation/Augmentation"; import { StaticAugmentations } from "../../Augmentation/StaticAugmentations"; import { Factions } from "../../Faction/Factions"; import { Multipliers } from "../Multipliers"; import { AugmentationNames } from "../../Augmentation/data/AugmentationNames"; +import { getFactionAugmentationsFiltered } from "../../Faction/FactionHelpers"; export function findSleevePurchasableAugs(sleeve: Sleeve, p: IPlayer): Augmentation[] { // You can only purchase Augmentations that are actually available from @@ -55,8 +57,9 @@ export function findSleevePurchasableAugs(sleeve: Sleeve, p: IPlayer): Augmentat // has enough reputation for (since that gang offers all augs) if (p.inGang()) { const fac = p.getGangFaction(); + const gangAugs = getFactionAugmentationsFiltered(Player, fac); - for (const augName of Object.keys(StaticAugmentations)) { + for (const augName of gangAugs) { const aug = StaticAugmentations[augName]; if (!isAvailableForSleeve(aug)) continue; diff --git a/src/PersonObjects/Sleeve/ui/FAQModal.tsx b/src/PersonObjects/Sleeve/ui/FAQModal.tsx index e796f46c2..47488c57b 100644 --- a/src/PersonObjects/Sleeve/ui/FAQModal.tsx +++ b/src/PersonObjects/Sleeve/ui/FAQModal.tsx @@ -71,15 +71,8 @@ export function FAQModal({ open, onClose }: IProps): React.ReactElement {
Only one of your sleeves can work for a given company/faction a time. To clarify further, if you have two - sleeves they can work for two different companies, but they cannot both work for the same company. - -
-
- Why did my Sleeve stop working? -
- - Sleeves are subject to the same time restrictions as you. This means that they automatically stop working at a - company after 8 hours, and stop working for a faction after 20 hours. + sleeves they can work for two different companies/factions, but they cannot both work for the same + company/faction.

@@ -92,13 +85,16 @@ export function FAQModal({ open, onClose }: IProps): React.ReactElement {
Certain Augmentations, like {FactionNames.Bladeburners}-specific ones and NeuroFlux Governor, are not - available for sleeves. + available for sleeves. You also need enough current reputation on some faction that offers that Augmentation.

Do sleeves get reset when installing Augmentations or switching BitNodes?
- Sleeves are reset when switching BitNodes, but not when installing Augmentations. + + Sleeves are reset when switching BitNodes, but not when installing Augmentations. However installing + Augmentations on a sleeve does reset their stats. +

What is Memory? diff --git a/src/ScriptEditor/NetscriptDefinitions.d.ts b/src/ScriptEditor/NetscriptDefinitions.d.ts index 3c2369282..5fa815893 100644 --- a/src/ScriptEditor/NetscriptDefinitions.d.ts +++ b/src/ScriptEditor/NetscriptDefinitions.d.ts @@ -2012,7 +2012,7 @@ export interface Singularity { * guarantee that your browser will follow that time limit. * * @param crime - Name of crime to attempt. - * @param focus - Acquire player focus on this program creation. Optional. Defaults to true. + * @param focus - Acquire player focus on this crime. Optional. Defaults to true. * @returns The number of milliseconds it takes to attempt the specified crime. */ commitCrime(crime: string, focus?: boolean): number; @@ -3511,7 +3511,7 @@ export interface Gang { * Ascend the specified Gang Member. * * @param memberName - Name of member to ascend. - * @returns Object with info about the ascension results. undefined if ascension did not occur. + * @returns Object with info about the ascension results. Undefined if ascension did not occur. */ ascendMember(memberName: string): GangMemberAscension | undefined; @@ -3523,7 +3523,7 @@ export interface Gang { * Get the result of an ascension without ascending. * * @param memberName - Name of member. - * @returns Object with info about the ascension results. undefined if ascension is impossible. + * @returns Object with info about the ascension results. Undefined if ascension is impossible. */ getAscensionResult(memberName: string): GangMemberAscension | undefined; @@ -7140,7 +7140,7 @@ interface CorporationInfo { numShares: number; /** Cooldown until shares can be sold again */ shareSaleCooldown: number; - /** Amount of shares issued */ + /** Amount of aqcuirable shares. */ issuedShares: number; /** Price of the shares */ sharePrice: number; diff --git a/src/Server/Server.ts b/src/Server/Server.ts index 442b6d461..427b879e3 100644 --- a/src/Server/Server.ts +++ b/src/Server/Server.ts @@ -75,10 +75,11 @@ export class Server extends BaseServer { this.moneyMax = 25 * this.moneyAvailable * BitNodeMultipliers.ServerMaxMoney; //Hack Difficulty is synonymous with server security. Base Difficulty = Starting difficulty - this.hackDifficulty = + const realDifficulty = params.hackDifficulty != null ? params.hackDifficulty * BitNodeMultipliers.ServerStartingSecurity : 1; + this.hackDifficulty = Math.min(realDifficulty, 100); this.baseDifficulty = this.hackDifficulty; - this.minDifficulty = Math.max(1, Math.round(this.hackDifficulty / 3)); + this.minDifficulty = Math.min(Math.max(1, Math.round(realDifficulty / 3)), 100); this.serverGrowth = params.serverGrowth != null ? params.serverGrowth : 1; //Integer from 0 to 100. Affects money increase from grow() //Port information, required for porthacking servers to get admin rights diff --git a/src/Terminal/ui/TerminalRoot.tsx b/src/Terminal/ui/TerminalRoot.tsx index a59ff4703..ef1e99662 100644 --- a/src/Terminal/ui/TerminalRoot.tsx +++ b/src/Terminal/ui/TerminalRoot.tsx @@ -125,7 +125,9 @@ export function TerminalRoot({ terminal, router, player }: IProps): React.ReactE paragraph={false} onClick={() => terminal.connectToServer(player, item.hostname)} > - {item.hostname} + + {item.hostname} + )} diff --git a/src/Work/CrimeWork.ts b/src/Work/CrimeWork.ts index 28a813ea1..d7876047d 100644 --- a/src/Work/CrimeWork.ts +++ b/src/Work/CrimeWork.ts @@ -108,7 +108,7 @@ export class CrimeWork extends Work { let karma = crime.karma; const success = determineCrimeSuccess(player, crime.type); if (success) { - player.gainMoney(gains.money * player.mults.crime_money, "crime"); + player.gainMoney(gains.money, "crime"); player.numPeopleKilled += crime.kills; player.gainIntelligenceExp(gains.intExp); } else { diff --git a/src/Work/formulas/Crime.ts b/src/Work/formulas/Crime.ts index 365bc7adc..af5d046d7 100644 --- a/src/Work/formulas/Crime.ts +++ b/src/Work/formulas/Crime.ts @@ -1,17 +1,18 @@ import { BitNodeMultipliers } from "../../BitNode/BitNodeMultipliers"; import { Crime } from "src/Crime/Crime"; import { newWorkStats, scaleWorkStats, WorkStats } from "../WorkStats"; +import { Player } from "../../Player"; export const calculateCrimeWorkStats = (crime: Crime): WorkStats => { const gains = scaleWorkStats( newWorkStats({ - money: crime.money, - hackExp: crime.hacking_exp * 2, - strExp: crime.strength_exp * 2, - defExp: crime.defense_exp * 2, - dexExp: crime.dexterity_exp * 2, - agiExp: crime.agility_exp * 2, - chaExp: crime.charisma_exp * 2, + money: crime.money * Player.mults.crime_money, + hackExp: crime.hacking_exp * 2 * Player.mults.hacking_exp, + strExp: crime.strength_exp * 2 * Player.mults.strength_exp, + defExp: crime.defense_exp * 2 * Player.mults.defense_exp, + dexExp: crime.dexterity_exp * 2 * Player.mults.dexterity_exp, + agiExp: crime.agility_exp * 2 * Player.mults.agility_exp, + chaExp: crime.charisma_exp * 2 * Player.mults.charisma_exp, intExp: crime.intelligence_exp * 2, }), BitNodeMultipliers.CrimeExpGain, diff --git a/src/engine.tsx b/src/engine.tsx index db143f9aa..f7037ee06 100644 --- a/src/engine.tsx +++ b/src/engine.tsx @@ -262,7 +262,7 @@ const Engine: { if (numCyclesOffline < 3000 * 100) { // if we have less than 100 rolls, just roll them exactly. for (let i = 0; i < numCyclesOffline / 3000; i++) { - if (Math.random() < 0.25) numContracts++; + if (Math.random() <= 0.25) numContracts++; } } else { // just average it. diff --git a/src/utils/StringHelperFunctions.ts b/src/utils/StringHelperFunctions.ts index 47f0db0e5..eecf5db15 100644 --- a/src/utils/StringHelperFunctions.ts +++ b/src/utils/StringHelperFunctions.ts @@ -38,15 +38,15 @@ function convertTimeMsToTimeElapsedString(time: number, showMilli = false): stri let res = ""; if (days > 0) { - res += `${days} days `; + res += `${days} day${days === 1 ? "" : "s"} `; } if (hours > 0 || (Settings.ShowMiddleNullTimeUnit && res != "")) { - res += `${hours} hours `; + res += `${hours} hour${hours === 1 ? "" : "s"} `; } if (minutes > 0 || (Settings.ShowMiddleNullTimeUnit && res != "")) { - res += `${minutes} minutes `; + res += `${minutes} minute${minutes === 1 ? "" : "s"} `; } - res += `${seconds} seconds`; + res += `${seconds} second${!showMilli && secTruncMinutes === 1 ? "" : "s"}`; return res; }