mirror of
https://github.com/bitburner-official/bitburner-src.git
synced 2024-12-27 00:17:32 +01:00
Merge branch 'dev' of github.com:danielyxie/bitburner into dev
This commit is contained in:
commit
444c74ccd9
@ -3,22 +3,22 @@
|
||||
## In General
|
||||
|
||||
The game is made better because the community as a whole speaks up about
|
||||
ways to improve the game. Here's some of the ways you can make your voice
|
||||
ways to improve the game. Here are some of the ways you can make your voice
|
||||
heard:
|
||||
|
||||
- [Discord](https://discord.gg/XKEGvHqVr3)
|
||||
- [Discord](https://discord.gg/XKEGvHqVr3).
|
||||
There is a dedicated Discord instance set up for more free-form chats
|
||||
between all members of the community. Regular players, heavy scripters,
|
||||
Bitburner contributors, and everyone in between can be found on the
|
||||
server.
|
||||
- [Github Issues](https://github.com/danielyxie/bitburner/issues)
|
||||
- [Github Issues](https://github.com/danielyxie/bitburner/issues).
|
||||
Although the term "issues" can have a negative connotation, they are a
|
||||
means of communicating with the community. A new Issue can be a
|
||||
means of communicating with the community. A new Issue can be an
|
||||
interesting new feature that you feel would improve the game. It could be
|
||||
an unexpected behavior within the game. Or because the game is about
|
||||
scripting perhaps there is something that is conflicting with the
|
||||
browser's Javascript interaction. So please do not be afraid to open a
|
||||
[new issue](https://github.com/danielyxie/bitburner/issues/new).
|
||||
browser's JavaScript interaction. So please do not be afraid to open a
|
||||
[new Issue](https://github.com/danielyxie/bitburner/issues/new).
|
||||
|
||||
## Reporting Bugs
|
||||
|
||||
@ -33,16 +33,17 @@ already been reported as an [Issue](https://github.com/danielyxie/bitburner/issu
|
||||
|
||||
#### How to Submit a Good Bug Report
|
||||
|
||||
- **Use a clear and descriptive title** for the issue
|
||||
- **State your browser, your browser's version, and your computer's OS**
|
||||
- **Attach your save file**, if you think it would help solve the issue
|
||||
- **Use a clear and descriptive title** for the Issue.
|
||||
- **State your browser, your browser's version, and your computer's OS.**
|
||||
- **Attach your save file**, if you think it would help solve the Issue.
|
||||
Zip your save file first, then attach the zipped save file.
|
||||
- **Provide instructions on how to reproduce the bug** in as much detail
|
||||
as possible. If you cannot reliably reproduce the bug, then just try
|
||||
your best to explain what was happening when the bug occurred
|
||||
- **Provide any scripts** that triggered the bug if the issue is Netscript-related
|
||||
your best to explain what was happening when the bug occurred.
|
||||
- **Provide any scripts** that triggered the bug if the Issue is Netscript-related.
|
||||
- **Open your browser's Dev Console and report any error-related output**
|
||||
that may be printed there. The Dev Console can be opened on most modern
|
||||
browsers by pressing F12
|
||||
browsers by pressing F12.
|
||||
|
||||
## As a Developer
|
||||
|
||||
@ -71,13 +72,13 @@ changes are okay to contribute:
|
||||
|
||||
##### Contributions that Will Most Likely Be Accepted
|
||||
|
||||
- Bug Fixes
|
||||
- Quality-of-Life Changes
|
||||
- Bug fixes
|
||||
- Quality-of-life changes
|
||||
- Adding a new, commonly-requested Netscript function
|
||||
- Fixing or improving UI elements
|
||||
- Adding game settings/options
|
||||
- Adding a new Terminal command
|
||||
- Code Refactors that conform to good/standard practices
|
||||
- Code refactors that conform to good/standard practices
|
||||
|
||||
##### Contributions that will not be Accepted without prior approval
|
||||
|
||||
@ -88,67 +89,108 @@ changes are okay to contribute:
|
||||
|
||||
## How to setup fork properly
|
||||
|
||||
Fork and clone the repo
|
||||
Clone and fork the game's repository by using one of these methods: web browser, GitHub
|
||||
Desktop, or command line.
|
||||
|
||||
```
|
||||
# This will add the game original code as a repo in your local copy
|
||||
$ git remote add danielyxie git@github.com:danielyxie/bitburner.git
|
||||
- Web browser. Log in to your GitHub account, navigate to the
|
||||
[game's repository](https://github.com/danielyxie/bitburner), and fork the
|
||||
repository. Refer to
|
||||
[this page](https://docs.github.com/en/get-started/quickstart/fork-a-repo) for more
|
||||
detail.
|
||||
- GitHub Desktop. Click on `File`, then click `Clone repository`. Click on the `URL`
|
||||
tab and type `danielyxie/bitburner` into the text box for repository URL. Choose
|
||||
the path where you want to clone the repository and click the `Clone` button.
|
||||
Refer to [this page](https://docs.github.com/en/desktop/contributing-and-collaborating-using-github-desktop/adding-and-cloning-repositories/cloning-and-forking-repositories-from-github-desktop)
|
||||
for more detail.
|
||||
- Command line.
|
||||
|
||||
# You can verify you did this right by doing the following command
|
||||
$ git remote show
|
||||
danielyxie
|
||||
origin
|
||||
```sh
|
||||
# This clones the game's code repository. The output you get might vary.
|
||||
$ git clone https://github.com/danielyxie/bitburner.git
|
||||
Cloning into 'bitburner'...
|
||||
remote: Enumerating objects: 57072, done.
|
||||
remote: Counting objects: 100% (404/404), done.
|
||||
remote: Compressing objects: 100% (205/205), done.
|
||||
remote: Total 57072 (delta 210), reused 375 (delta 199), pack-reused 56668
|
||||
Receiving objects: 100% (57072/57072), 339.11 MiB | 5.42 MiB/s, done.
|
||||
Resolving deltas: 100% (43708/43708), done.
|
||||
Updating files: 100% (2561/2561), done.
|
||||
|
||||
# Then download all the branches from the game. (there might be more branches)
|
||||
$ git fetch danielyxie
|
||||
From github.com:danielyxie/bitburner
|
||||
* [new branch] dev -> danielyxie/dev
|
||||
* [new branch] master -> danielyxie/master
|
||||
# Change to the directory that contains your local copy.
|
||||
$ cd bitburner
|
||||
|
||||
# Makes sure you always start from `danielyxie/dev` to avoid merge conflicts.
|
||||
# The upstream is the repository that contains the game's source code. The
|
||||
# upstream is also the place where proposed changes are merged into the game.
|
||||
$ git remote rename origin upstream
|
||||
Renaming remote references: 100% (8/8), done.
|
||||
|
||||
# The origin is your own copy or fork of the game's source code. Assume that
|
||||
# your fork will be on GitHub. Change "myname" to your GitHub username. Change
|
||||
# "myfork" to the name of your forked repository.
|
||||
$ git remote add origin https://github.com/myname/myfork
|
||||
|
||||
# Now "origin" is your fork and "upstream" is where changes should be merged.
|
||||
$ git remote show
|
||||
origin
|
||||
upstream
|
||||
|
||||
# You can now download all changes and branches from the upstream repository.
|
||||
# The output you get might vary.
|
||||
$ git fetch upstream
|
||||
|
||||
# Make sure you always start from "upstream/dev" to avoid merge conflicts.
|
||||
$ git branch
|
||||
* dev
|
||||
$ git branch -r
|
||||
upstream/BN14
|
||||
upstream/HEAD -> upstream/dev
|
||||
upstream/dev
|
||||
upstream/folders
|
||||
upstream/master
|
||||
```
|
||||
|
||||
## Development Workflow Best Practices
|
||||
|
||||
- Work in a new branch forked from the `dev` branch to isolate your new code
|
||||
- Work in a new branch forked from the `dev` branch to isolate your new code.
|
||||
- Keep code-changes on a branch as small as possible. This makes it easier for code review. Each branch should be its own independent feature.
|
||||
- Regularly rebase your branch against `dev` to make sure you have the latest updates pulled.
|
||||
- When merging, always merge your branch into `dev`. When releasing a new update, then merge `dev` into `master`
|
||||
- When merging, always merge your branch into `dev`. When releasing a new update, merge `dev` into `master`.
|
||||
|
||||
## Running locally.
|
||||
## Running locally
|
||||
|
||||
Install
|
||||
|
||||
- `npm` (maybe via `nvm`)
|
||||
- Github Desktop (windows only)
|
||||
- Visual Studio code (optional)
|
||||
- Github Desktop (Windows only)
|
||||
- Visual Studio Code (optional)
|
||||
|
||||
Inside the root of the repo run
|
||||
`npm install` to install all the dependencies
|
||||
`npm run start:dev` to launch the game in dev mode.
|
||||
Inside the root of the repository run:
|
||||
|
||||
- `npm install` to install all the dependencies; and
|
||||
- `npm run start:dev` to launch the game in dev mode.
|
||||
|
||||
After that you can open any browser and navigate to `localhost:8000` and play the game.
|
||||
Saving a file will reload the game automatically.
|
||||
|
||||
### How to build the electron app
|
||||
|
||||
Tested on Node v16.13.1 (LTS) on Windows
|
||||
These steps only work in a bash-like environment, like MinGW for Windows.
|
||||
Tested on Node v16.13.1 (LTS) on Windows.
|
||||
These steps only work in a Bash-like environment, like MinGW for Windows.
|
||||
|
||||
```sh
|
||||
# Install the main game dependencies & build the app in debug mode
|
||||
npm install
|
||||
npm run build:dev
|
||||
# Install the main game dependencies & build the app in debug mode.
|
||||
$ npm install
|
||||
$ npm run build:dev
|
||||
|
||||
# Use electron-packager to build the app to the .build/ folder
|
||||
npm run electron
|
||||
# Use electron-packager to build the app to the .build/ folder.
|
||||
$ npm run electron
|
||||
|
||||
# When launching the .exe directly, you'll need the steam_appid.txt file in the root
|
||||
# If not using windows, change this line accordingly
|
||||
cp .build/bitburner-win32-x64/resources/app/steam_appid.txt .build/bitburner-win32-x64/steam_appid.txt
|
||||
# When launching the .exe directly, you'll need the steam_appid.txt file in the root.
|
||||
# If not using Windows, change this line accordingly.
|
||||
$ cp .build/bitburner-win32-x64/resources/app/steam_appid.txt .build/bitburner-win32-x64/steam_appid.txt
|
||||
|
||||
# And run the game...
|
||||
.build/bitburner-win32-x64/bitburner.exe
|
||||
$ .build/bitburner-win32-x64/bitburner.exe
|
||||
```
|
||||
|
||||
### Submitting a Pull Request
|
||||
@ -156,15 +198,15 @@ cp .build/bitburner-win32-x64/resources/app/steam_appid.txt .build/bitburner-win
|
||||
When submitting a pull request with your code contributions, please abide by
|
||||
the following rules:
|
||||
|
||||
- Work in a branch forked from `dev` to isolate the new code
|
||||
- Ensure you have latest from the [game's main
|
||||
repository](danielyxie/bitburner@dev)
|
||||
- Rebase your branch if necessary
|
||||
- Run the game locally to test out your changes
|
||||
- Work in a branch forked from `dev` to isolate the new code.
|
||||
- Ensure you have the latest from the [game's main
|
||||
repository](../../../tree/dev).
|
||||
- Rebase your branch if necessary.
|
||||
- Run the game locally to test out your changes.
|
||||
- When submitting the pull request, make sure that the base fork is
|
||||
_danielyxie/bitburner_ and the base is _dev_.
|
||||
- If your changes affect the game's UI, attach some screenshots or GIFs showing
|
||||
the changes to the UI
|
||||
the changes to the UI.
|
||||
- If your changes affect Netscript, provide some
|
||||
scripts that can be used to test the Netscript changes.
|
||||
- Ensure you have run `npm run lint` to make sure your changes conform to the
|
||||
@ -174,23 +216,23 @@ the following rules:
|
||||
in the root of the repository. These will be updated as part of official
|
||||
releases.
|
||||
|
||||
## As a Documentor
|
||||
## As a Documenter
|
||||
|
||||
To contribute to and view your changes to the BitBurner documentation on [Read The
|
||||
Docs](http://bitburner.readthedocs.io/), you will
|
||||
need to have Python installed, along with [Sphinx](http://www.sphinx-doc.org).
|
||||
|
||||
To make change to the [in-game documentation](../markdown/bitburner.md), you will need to modify the [TypeScript definitions](../src/ScriptEditor/NetscriptDefinitions.d.ts), not the markdown files.
|
||||
To make change to the [in-game documentation](../markdown/bitburner.md), you will need to modify the [TypeScript definitions](../src/ScriptEditor/NetscriptDefinitions.d.ts), not the Markdown files.
|
||||
|
||||
We are using [API Extractor](https://api-extractor.com/pages/tsdoc/doc_comment_syntax/) (tsdoc hints) to generate the markdown doc. Make your changes to the TypeScript definitions and then run `npm run doc`.
|
||||
We are using [API Extractor](https://api-extractor.com/pages/tsdoc/doc_comment_syntax/) (tsdoc hints) to generate the Markdown doc. Make your changes to the TypeScript definitions and then run `npm run doc`.
|
||||
|
||||
Before submitting your code for a pull request, please try to follow these
|
||||
rules:
|
||||
|
||||
- Work in a branch forked from `dev` to isolate the new code
|
||||
- Ensure you have latest from the [game's main
|
||||
repository](danielyxie/bitburner@dev)
|
||||
- Rebase your branch if necessary
|
||||
- Work in a branch forked from `dev` to isolate the new code.
|
||||
- Ensure you have the latest from the [game's main
|
||||
repository](../../../tree/dev).
|
||||
- Rebase your branch if necessary.
|
||||
- When submitting the pull request, make sure that the base fork is
|
||||
_danielyxie/bitburner_ and the base is _dev_.
|
||||
- Do not check in any generated files under `doc\`. The documentation is built
|
||||
@ -204,5 +246,5 @@ Update the following
|
||||
- `package.json` `version`
|
||||
- `doc/source/conf.py` `version` and `release`
|
||||
- `doc/source/changelog.rst`
|
||||
- post to discord
|
||||
- post to Discord
|
||||
- post to reddit.com/r/Bitburner
|
||||
|
@ -347,18 +347,18 @@ export const achievements: IMap<Achievement> = {
|
||||
FIRST_HACKNET_NODE: {
|
||||
...achievementData["FIRST_HACKNET_NODE"],
|
||||
Icon: "node",
|
||||
Condition: () => !hasHacknetServers(Player) && Player.hacknetNodes.length > 0,
|
||||
Condition: () => !hasHacknetServers() && Player.hacknetNodes.length > 0,
|
||||
},
|
||||
"30_HACKNET_NODE": {
|
||||
...achievementData["30_HACKNET_NODE"],
|
||||
Icon: "hacknet-all",
|
||||
Condition: () => !hasHacknetServers(Player) && Player.hacknetNodes.length >= 30,
|
||||
Condition: () => !hasHacknetServers() && Player.hacknetNodes.length >= 30,
|
||||
},
|
||||
MAX_HACKNET_NODE: {
|
||||
...achievementData["MAX_HACKNET_NODE"],
|
||||
Icon: "hacknet-max",
|
||||
Condition: (): boolean => {
|
||||
if (hasHacknetServers(Player)) return false;
|
||||
if (hasHacknetServers()) return false;
|
||||
for (const h of Player.hacknetNodes) {
|
||||
if (!(h instanceof HacknetNode)) return false;
|
||||
if (
|
||||
@ -374,7 +374,7 @@ export const achievements: IMap<Achievement> = {
|
||||
HACKNET_NODE_10M: {
|
||||
...achievementData["HACKNET_NODE_10M"],
|
||||
Icon: "hacknet-10m",
|
||||
Condition: () => !hasHacknetServers(Player) && Player.moneySourceB.hacknet >= 10e6,
|
||||
Condition: () => !hasHacknetServers() && Player.moneySourceB.hacknet >= 10e6,
|
||||
},
|
||||
REPUTATION_10M: {
|
||||
...achievementData["REPUTATION_10M"],
|
||||
@ -515,14 +515,14 @@ export const achievements: IMap<Achievement> = {
|
||||
...achievementData["FIRST_HACKNET_SERVER"],
|
||||
Icon: "HASHNET",
|
||||
Visible: () => hasAccessToSF(Player, 9),
|
||||
Condition: () => hasHacknetServers(Player) && Player.hacknetNodes.length > 0,
|
||||
Condition: () => hasHacknetServers() && Player.hacknetNodes.length > 0,
|
||||
AdditionalUnlock: [achievementData.FIRST_HACKNET_NODE.ID],
|
||||
},
|
||||
ALL_HACKNET_SERVER: {
|
||||
...achievementData["ALL_HACKNET_SERVER"],
|
||||
Icon: "HASHNETALL",
|
||||
Visible: () => hasAccessToSF(Player, 9),
|
||||
Condition: () => hasHacknetServers(Player) && Player.hacknetNodes.length === HacknetServerConstants.MaxServers,
|
||||
Condition: () => hasHacknetServers() && Player.hacknetNodes.length === HacknetServerConstants.MaxServers,
|
||||
AdditionalUnlock: [achievementData["30_HACKNET_NODE"].ID],
|
||||
},
|
||||
MAX_HACKNET_SERVER: {
|
||||
@ -530,7 +530,7 @@ export const achievements: IMap<Achievement> = {
|
||||
Icon: "HASHNETALL",
|
||||
Visible: () => hasAccessToSF(Player, 9),
|
||||
Condition: (): boolean => {
|
||||
if (!hasHacknetServers(Player)) return false;
|
||||
if (!hasHacknetServers()) return false;
|
||||
for (const h of Player.hacknetNodes) {
|
||||
if (typeof h !== "string") return false;
|
||||
const hs = GetServer(h);
|
||||
@ -551,7 +551,7 @@ export const achievements: IMap<Achievement> = {
|
||||
...achievementData["HACKNET_SERVER_1B"],
|
||||
Icon: "HASHNETMONEY",
|
||||
Visible: () => hasAccessToSF(Player, 9),
|
||||
Condition: () => hasHacknetServers(Player) && Player.moneySourceB.hacknet >= 1e9,
|
||||
Condition: () => hasHacknetServers() && Player.moneySourceB.hacknet >= 1e9,
|
||||
AdditionalUnlock: [achievementData.HACKNET_NODE_10M.ID],
|
||||
},
|
||||
MAX_CACHE: {
|
||||
@ -559,7 +559,7 @@ export const achievements: IMap<Achievement> = {
|
||||
Icon: "HASHNETCAP",
|
||||
Visible: () => hasAccessToSF(Player, 9),
|
||||
Condition: () =>
|
||||
hasHacknetServers(Player) &&
|
||||
hasHacknetServers() &&
|
||||
Player.hashManager.hashes === Player.hashManager.capacity &&
|
||||
Player.hashManager.capacity > 0,
|
||||
},
|
||||
|
@ -2,7 +2,7 @@ import React, { useState } from "react";
|
||||
import { BBCabinetRoot } from "./BBCabinet";
|
||||
|
||||
import Button from "@mui/material/Button";
|
||||
import { use } from "../../ui/Context";
|
||||
import { Player } from "../../Player";
|
||||
import { AlertEvents } from "../../ui/React/AlertManager";
|
||||
|
||||
enum Page {
|
||||
@ -11,11 +11,10 @@ enum Page {
|
||||
}
|
||||
|
||||
export function ArcadeRoot(): React.ReactElement {
|
||||
const player = use.Player();
|
||||
const [page, setPage] = useState(Page.None);
|
||||
|
||||
function mbBurner2000(): void {
|
||||
if (player.sourceFileLvl(1) === 0) {
|
||||
if (Player.sourceFileLvl(1) === 0) {
|
||||
AlertEvents.emit("This machine is broken.");
|
||||
} else {
|
||||
setPage(Page.Megabyteburner2000);
|
||||
|
@ -1,6 +1,6 @@
|
||||
import React, { useEffect } from "react";
|
||||
import Typography from "@mui/material/Typography";
|
||||
import { use } from "../../ui/Context";
|
||||
import { Player } from "../../Player";
|
||||
import { Exploit } from "../../Exploits/Exploit";
|
||||
|
||||
const metaBB = "https://bitburner-official.github.io/bitburner-legacy/";
|
||||
@ -12,11 +12,10 @@ const style = {
|
||||
};
|
||||
|
||||
export function BBCabinetRoot(): React.ReactElement {
|
||||
const player = use.Player();
|
||||
useEffect(() => {
|
||||
window.addEventListener("message", function (this: Window, ev: MessageEvent<boolean>) {
|
||||
if (ev.isTrusted && ev.origin == "https://bitburner-official.github.io" && ev.data) {
|
||||
player.giveExploit(Exploit.TrueRecursion);
|
||||
Player.giveExploit(Exploit.TrueRecursion);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
@ -8,7 +8,7 @@ import { Money } from "../ui/React/Money";
|
||||
|
||||
import { Generic_fromJSON, Generic_toJSON, IReviverValue, Reviver } from "../utils/JSONReviver";
|
||||
import { FactionNames } from "../Faction/data/FactionNames";
|
||||
import { IPlayer } from "../PersonObjects/IPlayer";
|
||||
import { Player } from "../Player";
|
||||
import { AugmentationNames } from "./data/AugmentationNames";
|
||||
import { CONSTANTS } from "../Constants";
|
||||
import { StaticAugmentations } from "./StaticAugmentations";
|
||||
@ -531,26 +531,26 @@ export class Augmentation {
|
||||
}
|
||||
}
|
||||
|
||||
getCost(player: IPlayer): AugmentationCosts {
|
||||
getCost(): AugmentationCosts {
|
||||
const augmentationReference = StaticAugmentations[this.name];
|
||||
let moneyCost = augmentationReference.baseCost;
|
||||
let repCost = augmentationReference.baseRepRequirement;
|
||||
|
||||
if (augmentationReference.name === AugmentationNames.NeuroFluxGovernor) {
|
||||
let nextLevel = this.getLevel(player);
|
||||
let nextLevel = this.getLevel();
|
||||
--nextLevel;
|
||||
const multiplier = Math.pow(CONSTANTS.NeuroFluxGovernorLevelMult, nextLevel);
|
||||
repCost = augmentationReference.baseRepRequirement * multiplier * BitNodeMultipliers.AugmentationRepCost;
|
||||
moneyCost = augmentationReference.baseCost * multiplier * BitNodeMultipliers.AugmentationMoneyCost;
|
||||
|
||||
for (let i = 0; i < player.queuedAugmentations.length; ++i) {
|
||||
for (let i = 0; i < Player.queuedAugmentations.length; ++i) {
|
||||
moneyCost *= getBaseAugmentationPriceMultiplier();
|
||||
}
|
||||
} else if (augmentationReference.factions.includes(FactionNames.ShadowsOfAnarchy)) {
|
||||
const soaAugmentationNames = initSoAAugmentations().map((augmentation) => augmentation.name);
|
||||
const soaMultiplier = Math.pow(
|
||||
CONSTANTS.SoACostMult,
|
||||
soaAugmentationNames.filter((augmentationName) => player.hasAugmentation(augmentationName)).length,
|
||||
soaAugmentationNames.filter((augmentationName) => Player.hasAugmentation(augmentationName)).length,
|
||||
);
|
||||
moneyCost = augmentationReference.baseCost * soaMultiplier;
|
||||
if (soaAugmentationNames.find((augmentationName) => augmentationName === augmentationReference.name)) {
|
||||
@ -566,19 +566,19 @@ export class Augmentation {
|
||||
return { moneyCost, repCost };
|
||||
}
|
||||
|
||||
getLevel(player: IPlayer): number {
|
||||
getLevel(): number {
|
||||
// Get current Neuroflux level based on Player's augmentations
|
||||
if (this.name === AugmentationNames.NeuroFluxGovernor) {
|
||||
let currLevel = 0;
|
||||
for (let i = 0; i < player.augmentations.length; ++i) {
|
||||
if (player.augmentations[i].name === AugmentationNames.NeuroFluxGovernor) {
|
||||
currLevel = player.augmentations[i].level;
|
||||
for (let i = 0; i < Player.augmentations.length; ++i) {
|
||||
if (Player.augmentations[i].name === AugmentationNames.NeuroFluxGovernor) {
|
||||
currLevel = Player.augmentations[i].level;
|
||||
}
|
||||
}
|
||||
|
||||
// Account for purchased but uninstalled Augmentations
|
||||
for (let i = 0; i < player.queuedAugmentations.length; ++i) {
|
||||
if (player.queuedAugmentations[i].name == AugmentationNames.NeuroFluxGovernor) {
|
||||
for (let i = 0; i < Player.queuedAugmentations.length; ++i) {
|
||||
if (Player.queuedAugmentations[i].name == AugmentationNames.NeuroFluxGovernor) {
|
||||
++currLevel;
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
import { Augmentation } from "./Augmentation";
|
||||
import { StaticAugmentations } from "./StaticAugmentations";
|
||||
import { PlayerOwnedAugmentation, IPlayerOwnedAugmentation } from "./PlayerOwnedAugmentation";
|
||||
import { PlayerOwnedAugmentation } from "./PlayerOwnedAugmentation";
|
||||
import { AugmentationNames } from "./data/AugmentationNames";
|
||||
|
||||
import { CONSTANTS } from "../Constants";
|
||||
@ -21,7 +21,7 @@ import {
|
||||
initUnstableCircadianModulator,
|
||||
} from "./data/AugmentationCreator";
|
||||
import { Router } from "../ui/GameRoot";
|
||||
import { mergeAugmentation } from "../PersonObjects/Multipliers";
|
||||
import { mergeMultipliers } from "../PersonObjects/Multipliers";
|
||||
|
||||
export function AddToStaticAugmentations(aug: Augmentation): void {
|
||||
const name = aug.name;
|
||||
@ -71,11 +71,11 @@ function resetAugmentation(aug: Augmentation): void {
|
||||
AddToStaticAugmentations(aug);
|
||||
}
|
||||
|
||||
function applyAugmentation(aug: IPlayerOwnedAugmentation, reapply = false): void {
|
||||
function applyAugmentation(aug: PlayerOwnedAugmentation, reapply = false): void {
|
||||
const staticAugmentation = StaticAugmentations[aug.name];
|
||||
|
||||
// Apply multipliers
|
||||
Player.mults = mergeAugmentation(Player.mults, staticAugmentation.mults);
|
||||
Player.mults = mergeMultipliers(Player.mults, staticAugmentation.mults);
|
||||
|
||||
// Special logic for Congruity Implant
|
||||
if (aug.name === AugmentationNames.CongruityImplant && !reapply) {
|
||||
@ -126,15 +126,15 @@ function installAugmentations(force?: boolean): boolean {
|
||||
if (ownedAug.name === AugmentationNames.NeuroFluxGovernor) {
|
||||
level = ` - ${ownedAug.level}`;
|
||||
}
|
||||
augmentationList += aug.name + level + "<br>";
|
||||
augmentationList += aug.name + level + "\n";
|
||||
}
|
||||
Player.queuedAugmentations = [];
|
||||
if (!force) {
|
||||
dialogBoxCreate(
|
||||
"You slowly drift to sleep as scientists put you under in order " +
|
||||
"to install the following Augmentations:<br>" +
|
||||
"to install the following Augmentations:\n" +
|
||||
augmentationList +
|
||||
"<br>You wake up in your home...you feel different...",
|
||||
"\nYou wake up in your home...you feel different...",
|
||||
);
|
||||
}
|
||||
prestigeAugmentation();
|
||||
@ -146,8 +146,8 @@ function augmentationExists(name: string): boolean {
|
||||
return StaticAugmentations.hasOwnProperty(name);
|
||||
}
|
||||
|
||||
export function isRepeatableAug(aug: Augmentation): boolean {
|
||||
const augName = aug instanceof Augmentation ? aug.name : aug;
|
||||
export function isRepeatableAug(aug: Augmentation | string): boolean {
|
||||
const augName = typeof aug === "string" ? aug : aug.name;
|
||||
return augName === AugmentationNames.NeuroFluxGovernor;
|
||||
}
|
||||
|
||||
|
@ -6,8 +6,3 @@ export class PlayerOwnedAugmentation {
|
||||
this.name = name;
|
||||
}
|
||||
}
|
||||
|
||||
export interface IPlayerOwnedAugmentation {
|
||||
level: number;
|
||||
name: string;
|
||||
}
|
||||
|
@ -6,7 +6,6 @@ import { WHRNG } from "../../Casino/RNG";
|
||||
import React from "react";
|
||||
import { FactionNames } from "../../Faction/data/FactionNames";
|
||||
import { CONSTANTS } from "../../Constants";
|
||||
import { Faction } from "src/Faction/Faction";
|
||||
|
||||
interface CircadianBonus {
|
||||
bonuses: {
|
||||
|
@ -10,8 +10,6 @@ import { PurchasedAugmentations } from "./PurchasedAugmentations";
|
||||
import { SourceFilesElement } from "./SourceFiles";
|
||||
|
||||
import { canGetBonus } from "../../ExportBonus";
|
||||
import { use } from "../../ui/Context";
|
||||
|
||||
import Typography from "@mui/material/Typography";
|
||||
import Button from "@mui/material/Button";
|
||||
import Tooltip from "@mui/material/Tooltip";
|
||||
@ -20,7 +18,7 @@ import Paper from "@mui/material/Paper";
|
||||
import Container from "@mui/material/Container";
|
||||
import { Settings } from "../../Settings/Settings";
|
||||
import { ConfirmationModal } from "../../ui/React/ConfirmationModal";
|
||||
import { IPlayer } from "../../PersonObjects/IPlayer";
|
||||
import { Player } from "../../Player";
|
||||
import { AugmentationNames } from "../data/AugmentationNames";
|
||||
import { StaticAugmentations } from "../StaticAugmentations";
|
||||
import { CONSTANTS } from "../../Constants";
|
||||
@ -29,12 +27,8 @@ import { Info } from "@mui/icons-material";
|
||||
import { Link } from "@mui/material";
|
||||
import { AlertEvents } from "../../ui/React/AlertManager";
|
||||
|
||||
interface NFGDisplayProps {
|
||||
player: IPlayer;
|
||||
}
|
||||
|
||||
const NeuroFluxDisplay = ({ player }: NFGDisplayProps): React.ReactElement => {
|
||||
const level = player.augmentations.find((e) => e.name === AugmentationNames.NeuroFluxGovernor)?.level ?? 0;
|
||||
const NeuroFluxDisplay = (): React.ReactElement => {
|
||||
const level = Player.augmentations.find((e) => e.name === AugmentationNames.NeuroFluxGovernor)?.level ?? 0;
|
||||
|
||||
const openBloodDonation = () => {
|
||||
AlertEvents.emit(
|
||||
@ -67,18 +61,14 @@ const NeuroFluxDisplay = ({ player }: NFGDisplayProps): React.ReactElement => {
|
||||
);
|
||||
};
|
||||
|
||||
interface EntropyDisplayProps {
|
||||
player: IPlayer;
|
||||
}
|
||||
|
||||
const EntropyDisplay = ({ player }: EntropyDisplayProps): React.ReactElement => {
|
||||
return player.entropy > 0 ? (
|
||||
const EntropyDisplay = (): React.ReactElement => {
|
||||
return Player.entropy > 0 ? (
|
||||
<Paper sx={{ p: 1 }}>
|
||||
<Typography variant="h5" color={Settings.theme.error}>
|
||||
Entropy Virus - Level {player.entropy}
|
||||
Entropy Virus - Level {Player.entropy}
|
||||
</Typography>
|
||||
<Typography color={Settings.theme.error}>
|
||||
<b>All multipliers decreased by:</b> {formatNumber((1 - CONSTANTS.EntropyEffect ** player.entropy) * 100, 3)}%
|
||||
<b>All multipliers decreased by:</b> {formatNumber((1 - CONSTANTS.EntropyEffect ** Player.entropy) * 100, 3)}%
|
||||
(multiplicative)
|
||||
</Typography>
|
||||
</Paper>
|
||||
@ -94,7 +84,6 @@ interface IProps {
|
||||
|
||||
export function AugmentationsRoot(props: IProps): React.ReactElement {
|
||||
const [installOpen, setInstallOpen] = useState(false);
|
||||
const player = use.Player();
|
||||
const setRerender = useState(false)[1];
|
||||
function rerender(): void {
|
||||
setRerender((o) => !o);
|
||||
@ -187,7 +176,7 @@ export function AugmentationsRoot(props: IProps): React.ReactElement {
|
||||
<Box sx={{ display: "grid", width: "100%", gridTemplateColumns: "1fr 1fr" }}>
|
||||
<Tooltip title={<Typography>'I never asked for this'</Typography>}>
|
||||
<span>
|
||||
<Button sx={{ width: "100%" }} disabled={player.queuedAugmentations.length === 0} onClick={doInstall}>
|
||||
<Button sx={{ width: "100%" }} disabled={Player.queuedAugmentations.length === 0} onClick={doInstall}>
|
||||
Install Augmentations
|
||||
</Button>
|
||||
</span>
|
||||
@ -199,7 +188,7 @@ export function AugmentationsRoot(props: IProps): React.ReactElement {
|
||||
</Tooltip>
|
||||
</Box>
|
||||
</Paper>
|
||||
{player.queuedAugmentations.length > 0 ? (
|
||||
{Player.queuedAugmentations.length > 0 ? (
|
||||
<Box sx={{ display: "grid", gridTemplateColumns: "1fr 3fr" }}>
|
||||
<PurchasedAugmentations />
|
||||
<PlayerMultipliers />
|
||||
@ -216,14 +205,14 @@ export function AugmentationsRoot(props: IProps): React.ReactElement {
|
||||
my: 1,
|
||||
display: "grid",
|
||||
gridTemplateColumns: `repeat(${
|
||||
+!!((player.augmentations.find((e) => e.name === AugmentationNames.NeuroFluxGovernor)?.level ?? 0) > 0) +
|
||||
+!!(player.entropy > 0)
|
||||
+!!((Player.augmentations.find((e) => e.name === AugmentationNames.NeuroFluxGovernor)?.level ?? 0) > 0) +
|
||||
+!!(Player.entropy > 0)
|
||||
}, 1fr)`,
|
||||
gap: 1,
|
||||
}}
|
||||
>
|
||||
<NeuroFluxDisplay player={player} />
|
||||
<EntropyDisplay player={player} />
|
||||
<NeuroFluxDisplay />
|
||||
<EntropyDisplay />
|
||||
</Box>
|
||||
|
||||
<Box>
|
||||
|
@ -12,14 +12,13 @@ import Tooltip from "@mui/material/Tooltip";
|
||||
import React, { useState } from "react";
|
||||
import { OwnedAugmentationsOrderSetting } from "../../Settings/SettingEnums";
|
||||
import { Settings } from "../../Settings/Settings";
|
||||
import { use } from "../../ui/Context";
|
||||
import { Player } from "../../Player";
|
||||
import { StaticAugmentations } from "../StaticAugmentations";
|
||||
import { AugmentationNames } from "../data/AugmentationNames";
|
||||
|
||||
export function InstalledAugmentations(): React.ReactElement {
|
||||
const setRerender = useState(true)[1];
|
||||
const player = use.Player();
|
||||
const sourceAugs = player.augmentations.slice().filter((aug) => aug.name !== AugmentationNames.NeuroFluxGovernor);
|
||||
const sourceAugs = Player.augmentations.slice().filter((aug) => aug.name !== AugmentationNames.NeuroFluxGovernor);
|
||||
|
||||
const [selectedAug, setSelectedAug] = useState(sourceAugs[0]);
|
||||
|
||||
|
@ -4,7 +4,7 @@
|
||||
import { DoubleArrow } from "@mui/icons-material";
|
||||
import { List, ListItem, ListItemText, Paper, Typography } from "@mui/material";
|
||||
import * as React from "react";
|
||||
import { Multipliers, defaultMultipliers, mergeAugmentation } from "../../PersonObjects/Multipliers";
|
||||
import { Multipliers, defaultMultipliers, mergeMultipliers } from "../../PersonObjects/Multipliers";
|
||||
import { BitNodeMultipliers } from "../../BitNode/BitNodeMultipliers";
|
||||
import { Player } from "../../Player";
|
||||
import { Settings } from "../../Settings/Settings";
|
||||
@ -15,7 +15,7 @@ function calculateAugmentedStats(): Multipliers {
|
||||
let augP: Multipliers = defaultMultipliers();
|
||||
for (const aug of Player.queuedAugmentations) {
|
||||
const augObj = StaticAugmentations[aug.name];
|
||||
augP = mergeAugmentation(augP, augObj.mults);
|
||||
augP = mergeMultipliers(augP, augObj.mults);
|
||||
}
|
||||
return augP;
|
||||
}
|
||||
|
@ -6,7 +6,7 @@ import { CheckBox, CheckBoxOutlineBlank, CheckCircle, NewReleases, Report } from
|
||||
import { Box, Button, Container, Paper, Tooltip, Typography } from "@mui/material";
|
||||
import React, { useState } from "react";
|
||||
import { Faction } from "../../Faction/Faction";
|
||||
import { IPlayer } from "../../PersonObjects/IPlayer";
|
||||
import { Player } from "../../Player";
|
||||
import { Settings } from "../../Settings/Settings";
|
||||
import { numeralWrapper } from "../../ui/numeralFormat";
|
||||
import { Augmentation } from "../Augmentation";
|
||||
@ -15,12 +15,11 @@ import { StaticAugmentations } from "../StaticAugmentations";
|
||||
import { PurchaseAugmentationModal } from "./PurchaseAugmentationModal";
|
||||
|
||||
interface IPreReqsProps {
|
||||
player: IPlayer;
|
||||
aug: Augmentation;
|
||||
}
|
||||
|
||||
const PreReqs = (props: IPreReqsProps): React.ReactElement => {
|
||||
const ownedPreReqs = props.aug.prereqs.filter((aug) => props.player.hasAugmentation(aug));
|
||||
const ownedPreReqs = props.aug.prereqs.filter((aug) => Player.hasAugmentation(aug));
|
||||
const hasPreReqs = props.aug.prereqs.length > 0 && ownedPreReqs.length === props.aug.prereqs.length;
|
||||
|
||||
return (
|
||||
@ -32,7 +31,7 @@ const PreReqs = (props: IPreReqsProps): React.ReactElement => {
|
||||
</Typography>
|
||||
{props.aug.prereqs.map((preAug) => (
|
||||
<Requirement
|
||||
fulfilled={props.player.hasAugmentation(preAug)}
|
||||
fulfilled={Player.hasAugmentation(preAug)}
|
||||
value={preAug}
|
||||
color={Settings.theme.money}
|
||||
key={preAug}
|
||||
@ -68,7 +67,6 @@ const PreReqs = (props: IPreReqsProps): React.ReactElement => {
|
||||
};
|
||||
|
||||
interface IExclusiveProps {
|
||||
player: IPlayer;
|
||||
aug: Augmentation;
|
||||
}
|
||||
|
||||
@ -85,18 +83,16 @@ const Exclusive = (props: IExclusiveProps): React.ReactElement => {
|
||||
<li>
|
||||
<b>{props.aug.factions[0]}</b> faction
|
||||
</li>
|
||||
{props.player.isAwareOfGang() && !props.aug.isSpecial && (
|
||||
{Player.isAwareOfGang() && !props.aug.isSpecial && (
|
||||
<li>
|
||||
Certain <b>gangs</b>
|
||||
</li>
|
||||
)}
|
||||
{props.player.canAccessGrafting() &&
|
||||
!props.aug.isSpecial &&
|
||||
props.aug.name !== AugmentationNames.TheRedPill && (
|
||||
<li>
|
||||
<b>Grafting</b>
|
||||
</li>
|
||||
)}
|
||||
{Player.canAccessGrafting() && !props.aug.isSpecial && props.aug.name !== AugmentationNames.TheRedPill && (
|
||||
<li>
|
||||
<b>Grafting</b>
|
||||
</li>
|
||||
)}
|
||||
</Typography>
|
||||
</ul>
|
||||
</>
|
||||
@ -130,10 +126,9 @@ const Requirement = (props: IReqProps): React.ReactElement => {
|
||||
interface IPurchasableAugsProps {
|
||||
augNames: string[];
|
||||
ownedAugNames: string[];
|
||||
player: IPlayer;
|
||||
|
||||
canPurchase: (player: IPlayer, aug: Augmentation) => boolean;
|
||||
purchaseAugmentation: (player: IPlayer, aug: Augmentation, showModal: (open: boolean) => void) => void;
|
||||
canPurchase: (aug: Augmentation) => boolean;
|
||||
purchaseAugmentation: (aug: Augmentation, showModal: (open: boolean) => void) => void;
|
||||
|
||||
rep?: number;
|
||||
sleeveAugs?: boolean;
|
||||
@ -167,7 +162,7 @@ export function PurchasableAugmentation(props: IPurchasableAugProps): React.Reac
|
||||
const [open, setOpen] = useState(false);
|
||||
|
||||
const aug = StaticAugmentations[props.augName];
|
||||
const augCosts = aug.getCost(props.parent.player);
|
||||
const augCosts = aug.getCost();
|
||||
const cost = props.parent.sleeveAugs ? aug.baseCost : augCosts.moneyCost;
|
||||
const repCost = augCosts.repCost;
|
||||
const info = typeof aug.info === "string" ? <span>{aug.info}</span> : aug.info;
|
||||
@ -195,11 +190,11 @@ export function PurchasableAugmentation(props: IPurchasableAugProps): React.Reac
|
||||
<Box sx={{ display: "flex", alignItems: "center" }}>
|
||||
<Button
|
||||
onClick={() =>
|
||||
props.parent.purchaseAugmentation(props.parent.player, aug, (open): void => {
|
||||
props.parent.purchaseAugmentation(aug, (open): void => {
|
||||
setOpen(open);
|
||||
})
|
||||
}
|
||||
disabled={!props.parent.canPurchase(props.parent.player, aug) || props.owned}
|
||||
disabled={!props.parent.canPurchase(aug) || props.owned}
|
||||
sx={{ width: "48px", height: "36px", float: "left", clear: "none", mr: 1 }}
|
||||
>
|
||||
{props.owned ? "Owned" : "Buy"}
|
||||
@ -212,8 +207,7 @@ export function PurchasableAugmentation(props: IPurchasableAugProps): React.Reac
|
||||
<>
|
||||
<Typography variant="h5">
|
||||
{props.augName}
|
||||
{props.augName === AugmentationNames.NeuroFluxGovernor &&
|
||||
` - Level ${aug.getLevel(props.parent.player)}`}
|
||||
{props.augName === AugmentationNames.NeuroFluxGovernor && ` - Level ${aug.getLevel()}`}
|
||||
</Typography>
|
||||
<Typography>{description}</Typography>
|
||||
</>
|
||||
@ -226,20 +220,16 @@ export function PurchasableAugmentation(props: IPurchasableAugProps): React.Reac
|
||||
whiteSpace: "nowrap",
|
||||
overflow: "hidden",
|
||||
color:
|
||||
props.owned || !props.parent.canPurchase(props.parent.player, aug)
|
||||
? Settings.theme.disabled
|
||||
: Settings.theme.primary,
|
||||
props.owned || !props.parent.canPurchase(aug) ? Settings.theme.disabled : Settings.theme.primary,
|
||||
}}
|
||||
>
|
||||
{aug.name}
|
||||
{aug.name === AugmentationNames.NeuroFluxGovernor && ` - Level ${aug.getLevel(props.parent.player)}`}
|
||||
{aug.name === AugmentationNames.NeuroFluxGovernor && ` - Level ${aug.getLevel()}`}
|
||||
</Typography>
|
||||
</Tooltip>
|
||||
|
||||
{aug.factions.length === 1 && !props.parent.sleeveAugs && (
|
||||
<Exclusive player={props.parent.player} aug={aug} />
|
||||
)}
|
||||
{aug.prereqs.length > 0 && !props.parent.sleeveAugs && <PreReqs player={props.parent.player} aug={aug} />}
|
||||
{aug.factions.length === 1 && !props.parent.sleeveAugs && <Exclusive aug={aug} />}
|
||||
{aug.prereqs.length > 0 && !props.parent.sleeveAugs && <PreReqs aug={aug} />}
|
||||
</Box>
|
||||
</Box>
|
||||
</Box>
|
||||
@ -247,7 +237,7 @@ export function PurchasableAugmentation(props: IPurchasableAugProps): React.Reac
|
||||
{props.owned || (
|
||||
<Box sx={{ display: "grid", alignItems: "center", gridTemplateColumns: "1fr 1fr" }}>
|
||||
<Requirement
|
||||
fulfilled={cost === 0 || props.parent.player.money > cost}
|
||||
fulfilled={cost === 0 || Player.money > cost}
|
||||
value={numeralWrapper.formatMoney(cost)}
|
||||
color={Settings.theme.money}
|
||||
/>
|
||||
|
@ -6,7 +6,7 @@ import { purchaseAugmentation } from "../../Faction/FactionHelpers";
|
||||
import { isRepeatableAug } from "../AugmentationHelpers";
|
||||
import { Money } from "../../ui/React/Money";
|
||||
import { Modal } from "../../ui/React/Modal";
|
||||
import { use } from "../../ui/Context";
|
||||
import { Player } from "../../Player";
|
||||
import Typography from "@mui/material/Typography";
|
||||
import Button from "@mui/material/Button";
|
||||
|
||||
@ -18,14 +18,12 @@ interface IProps {
|
||||
}
|
||||
|
||||
export function PurchaseAugmentationModal(props: IProps): React.ReactElement {
|
||||
if (typeof props.aug === "undefined" || typeof props.faction === "undefined") {
|
||||
if (!props.aug || !props.faction) {
|
||||
return <></>;
|
||||
}
|
||||
|
||||
const player = use.Player();
|
||||
|
||||
function buy(): void {
|
||||
if (!isRepeatableAug(props.aug as Augmentation) && player.hasAugmentation(props.aug as Augmentation)) {
|
||||
if (!props.aug || (!isRepeatableAug(props.aug) && Player.hasAugmentation(props.aug.name))) {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -44,7 +42,7 @@ export function PurchaseAugmentationModal(props: IProps): React.ReactElement {
|
||||
<br />
|
||||
<br />
|
||||
Would you like to purchase the {props.aug.name} Augmentation for
|
||||
<Money money={props.aug.getCost(player).moneyCost} />?
|
||||
<Money money={props.aug.getCost().moneyCost} />?
|
||||
<br />
|
||||
<br />
|
||||
</Typography>
|
||||
|
@ -1,6 +1,6 @@
|
||||
import React from "react";
|
||||
import { BitNodeMultipliers, IBitNodeMultipliers } from "./BitNodeMultipliers";
|
||||
import { IPlayer } from "../PersonObjects/IPlayer";
|
||||
import { Player } from "../Player";
|
||||
import { IMap } from "../types";
|
||||
import { FactionNames } from "../Faction/data/FactionNames";
|
||||
import { CityName } from "../Locations/data/CityNames";
|
||||
@ -876,6 +876,6 @@ export function getBitNodeMultipliers(n: number, lvl: number): IBitNodeMultiplie
|
||||
}
|
||||
}
|
||||
|
||||
export function initBitNodeMultipliers(p: IPlayer): void {
|
||||
Object.assign(BitNodeMultipliers, getBitNodeMultipliers(p.bitNodeN, p.sourceFileLvl(p.bitNodeN)));
|
||||
export function initBitNodeMultipliers(): void {
|
||||
Object.assign(BitNodeMultipliers, getBitNodeMultipliers(Player.bitNodeN, Player.sourceFileLvl(Player.bitNodeN)));
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
import React, { useState, useEffect } from "react";
|
||||
import { Modal } from "../../ui/React/Modal";
|
||||
import { use } from "../../ui/Context";
|
||||
import { Router } from "../../ui/GameRoot";
|
||||
import { EventEmitter } from "../../utils/EventEmitter";
|
||||
import Typography from "@mui/material/Typography";
|
||||
import Button from "@mui/material/Button";
|
||||
@ -8,10 +8,9 @@ import Button from "@mui/material/Button";
|
||||
export const BitFlumeEvent = new EventEmitter<[]>();
|
||||
|
||||
export function BitFlumeModal(): React.ReactElement {
|
||||
const router = use.Router();
|
||||
const [open, setOpen] = useState(false);
|
||||
function flume(): void {
|
||||
router.toBitVerse(true, false);
|
||||
Router.toBitVerse(true, false);
|
||||
setOpen(false);
|
||||
}
|
||||
|
||||
|
@ -5,7 +5,7 @@ import { uniqueId } from "lodash";
|
||||
import React from "react";
|
||||
import { SpecialServers } from "../../Server/data/SpecialServers";
|
||||
import { Settings } from "../../Settings/Settings";
|
||||
import { use } from "../../ui/Context";
|
||||
import { Player } from "../../Player";
|
||||
import { StatsRow } from "../../ui/React/StatsRow";
|
||||
import { defaultMultipliers, getBitNodeMultipliers } from "../BitNode";
|
||||
import { IBitNodeMultipliers } from "../BitNodeMultipliers";
|
||||
@ -33,13 +33,12 @@ export function BitnodeMultiplierDescription({ n, level }: IProps): React.ReactE
|
||||
}
|
||||
|
||||
export const BitNodeMultipliersDisplay = ({ n, level }: IProps): React.ReactElement => {
|
||||
const player = use.Player();
|
||||
// If a level argument has been provided, use that as the multiplier level
|
||||
// If not, then we have to assume that we want the next level up from the
|
||||
// current node's source file, so we get the min of that, the SF's max level,
|
||||
// or if it's BN12, ∞
|
||||
const maxSfLevel = n === 12 ? Infinity : 3;
|
||||
const mults = getBitNodeMultipliers(n, level ?? Math.min(player.sourceFileLvl(n) + 1, maxSfLevel));
|
||||
const mults = getBitNodeMultipliers(n, level ?? Math.min(Player.sourceFileLvl(n) + 1, maxSfLevel));
|
||||
|
||||
return (
|
||||
<Box sx={{ columnCount: 2, columnGap: 1, mb: -2 }}>
|
||||
@ -277,8 +276,7 @@ function InfiltrationMults({ mults }: IMultsProps): React.ReactElement {
|
||||
}
|
||||
|
||||
function BladeburnerMults({ mults }: IMultsProps): React.ReactElement {
|
||||
const player = use.Player();
|
||||
if (!player.canAccessBladeburner()) return <></>;
|
||||
if (!Player.canAccessBladeburner()) return <></>;
|
||||
|
||||
if (mults.BladeburnerRank === 0) {
|
||||
const rows: IBNMultRows = {
|
||||
@ -297,8 +295,7 @@ function BladeburnerMults({ mults }: IMultsProps): React.ReactElement {
|
||||
}
|
||||
|
||||
function StanekMults({ mults }: IMultsProps): React.ReactElement {
|
||||
const player = use.Player();
|
||||
if (!player.canAccessCotMG()) return <></>;
|
||||
if (!Player.canAccessCotMG()) return <></>;
|
||||
|
||||
const extraSize = mults.StaneksGiftExtraSize.toFixed(3);
|
||||
const rows: IBNMultRows = {
|
||||
@ -313,8 +310,7 @@ function StanekMults({ mults }: IMultsProps): React.ReactElement {
|
||||
}
|
||||
|
||||
function GangMults({ mults }: IMultsProps): React.ReactElement {
|
||||
const player = use.Player();
|
||||
if (player.bitNodeN !== 2 && player.sourceFileLvl(2) <= 0) return <></>;
|
||||
if (Player.bitNodeN !== 2 && Player.sourceFileLvl(2) <= 0) return <></>;
|
||||
|
||||
const rows: IBNMultRows = {
|
||||
GangSoftcap: {
|
||||
@ -328,8 +324,7 @@ function GangMults({ mults }: IMultsProps): React.ReactElement {
|
||||
}
|
||||
|
||||
function CorporationMults({ mults }: IMultsProps): React.ReactElement {
|
||||
const player = use.Player();
|
||||
if (!player.canAccessCorporation()) return <></>;
|
||||
if (!Player.canAccessCorporation()) return <></>;
|
||||
|
||||
if (mults.CorporationSoftcap < 0.15) {
|
||||
const rows: IBNMultRows = {
|
||||
|
@ -1,10 +1,8 @@
|
||||
import React, { useState } from "react";
|
||||
import { IRouter } from "../../ui/Router";
|
||||
import { BitNodes } from "../BitNode";
|
||||
import { enterBitNode } from "../../RedPill";
|
||||
import { PortalModal } from "./PortalModal";
|
||||
import { CinematicText } from "../../ui/React/CinematicText";
|
||||
import { use } from "../../ui/Context";
|
||||
import { Player } from "../../Player";
|
||||
import makeStyles from "@mui/styles/makeStyles";
|
||||
import createStyles from "@mui/styles/createStyles";
|
||||
import IconButton from "@mui/material/IconButton";
|
||||
@ -46,7 +44,6 @@ interface IPortalProps {
|
||||
level: number;
|
||||
destroyedBitNode: number;
|
||||
flume: boolean;
|
||||
enter: (router: IRouter, flume: boolean, destroyedBitNode: number, newBitNode: number) => void;
|
||||
}
|
||||
function BitNodePortal(props: IPortalProps): React.ReactElement {
|
||||
const [portalOpen, setPortalOpen] = useState(false);
|
||||
@ -105,7 +102,6 @@ function BitNodePortal(props: IPortalProps): React.ReactElement {
|
||||
onClose={() => setPortalOpen(false)}
|
||||
n={props.n}
|
||||
level={props.level}
|
||||
enter={props.enter}
|
||||
destroyedBitNode={props.destroyedBitNode}
|
||||
flume={props.flume}
|
||||
/>
|
||||
@ -118,13 +114,10 @@ function BitNodePortal(props: IPortalProps): React.ReactElement {
|
||||
interface IProps {
|
||||
flume: boolean;
|
||||
quick: boolean;
|
||||
enter: (router: IRouter, flume: boolean, destroyedBitNode: number, newBitNode: number) => void;
|
||||
}
|
||||
|
||||
export function BitverseRoot(props: IProps): React.ReactElement {
|
||||
const player = use.Player();
|
||||
const enter = enterBitNode;
|
||||
const destroyed = player.bitNodeN;
|
||||
const destroyed = Player.bitNodeN;
|
||||
const [destroySequence, setDestroySequence] = useState(!props.quick);
|
||||
|
||||
if (destroySequence) {
|
||||
@ -158,7 +151,7 @@ export function BitverseRoot(props: IProps): React.ReactElement {
|
||||
}
|
||||
|
||||
const nextSourceFileLvl = (n: number): number => {
|
||||
const lvl = player.sourceFileLvl(n);
|
||||
const lvl = Player.sourceFileLvl(n);
|
||||
if (n !== destroyed) {
|
||||
return lvl;
|
||||
}
|
||||
@ -181,7 +174,6 @@ export function BitverseRoot(props: IProps): React.ReactElement {
|
||||
key={node.number}
|
||||
n={node.number}
|
||||
level={nextSourceFileLvl(node.number)}
|
||||
enter={enter}
|
||||
flume={props.flume}
|
||||
destroyedBitNode={destroyed}
|
||||
/>
|
||||
@ -234,19 +226,19 @@ export function BitverseRoot(props: IProps): React.ReactElement {
|
||||
<Typography sx={{lineHeight: '1em',whiteSpace: 'pre'}}>O | | | \| | O / _/ | / O | |/ | | | O</Typography>
|
||||
<Typography sx={{lineHeight: '1em',whiteSpace: 'pre'}}>| | | |O / | | O / | O O | | \ O| | | |</Typography>
|
||||
<Typography sx={{lineHeight: '1em',whiteSpace: 'pre'}}>| | |/ \/ / __| | |/ \ | \ | |__ \ \/ \| | |</Typography>
|
||||
<Typography sx={{lineHeight: '1em',whiteSpace: 'pre'}}> \| O | |_/ |\| \ <BitNodePortal n={13} level={n(13)} enter={enter} flume={props.flume} destroyedBitNode={destroyed} /> \__| \_| | O |/ </Typography>
|
||||
<Typography sx={{lineHeight: '1em',whiteSpace: 'pre'}}> \| O | |_/ |\| \ <BitNodePortal n={13} level={n(13)} flume={props.flume} destroyedBitNode={destroyed} /> \__| \_| | O |/ </Typography>
|
||||
<Typography sx={{lineHeight: '1em',whiteSpace: 'pre'}}> | | |_/ | | \| / | \_| | | </Typography>
|
||||
<Typography sx={{lineHeight: '1em',whiteSpace: 'pre'}}> \| / \| | / / \ |/ </Typography>
|
||||
<Typography sx={{lineHeight: '1em',whiteSpace: 'pre'}}> | <BitNodePortal n={10} level={n(10)} enter={enter} flume={props.flume} destroyedBitNode={destroyed} /> | | / | <BitNodePortal n={11} level={n(11)} enter={enter} flume={props.flume} destroyedBitNode={destroyed} /> | </Typography>
|
||||
<Typography sx={{lineHeight: '1em',whiteSpace: 'pre'}}> <BitNodePortal n={9} level={n(9)} enter={enter} flume={props.flume} destroyedBitNode={destroyed} /> | | | | | | | <BitNodePortal n={12} level={n(12)} enter={enter} flume={props.flume} destroyedBitNode={destroyed} /> </Typography>
|
||||
<Typography sx={{lineHeight: '1em',whiteSpace: 'pre'}}> | <BitNodePortal n={10} level={n(10)} flume={props.flume} destroyedBitNode={destroyed} /> | | / | <BitNodePortal n={11} level={n(11)} flume={props.flume} destroyedBitNode={destroyed} /> | </Typography>
|
||||
<Typography sx={{lineHeight: '1em',whiteSpace: 'pre'}}> <BitNodePortal n={9} level={n(9)} flume={props.flume} destroyedBitNode={destroyed} /> | | | | | | | <BitNodePortal n={12} level={n(12)} flume={props.flume} destroyedBitNode={destroyed} /> </Typography>
|
||||
<Typography sx={{lineHeight: '1em',whiteSpace: 'pre'}}> | | | / / \ \ | | | </Typography>
|
||||
<Typography sx={{lineHeight: '1em',whiteSpace: 'pre'}}> \| | / <BitNodePortal n={7} level={n(7)} enter={enter} flume={props.flume} destroyedBitNode={destroyed} /> / \ <BitNodePortal n={8} level={n(8)} enter={enter} flume={props.flume} destroyedBitNode={destroyed} /> \ | |/ </Typography>
|
||||
<Typography sx={{lineHeight: '1em',whiteSpace: 'pre'}}> \| | / <BitNodePortal n={7} level={n(7)} flume={props.flume} destroyedBitNode={destroyed} /> / \ <BitNodePortal n={8} level={n(8)} flume={props.flume} destroyedBitNode={destroyed} /> \ | |/ </Typography>
|
||||
<Typography sx={{lineHeight: '1em',whiteSpace: 'pre'}}> \ | / / | | \ \ | / </Typography>
|
||||
<Typography sx={{lineHeight: '1em',whiteSpace: 'pre'}}> \ \JUMP <BitNodePortal n={5} level={n(5)} enter={enter} flume={props.flume} destroyedBitNode={destroyed} />3R | | | | | | R3<BitNodePortal n={6} level={n(6)} enter={enter} flume={props.flume} destroyedBitNode={destroyed} /> PMUJ/ / </Typography>
|
||||
<Typography sx={{lineHeight: '1em',whiteSpace: 'pre'}}> \ \JUMP <BitNodePortal n={5} level={n(5)} flume={props.flume} destroyedBitNode={destroyed} />3R | | | | | | R3<BitNodePortal n={6} level={n(6)} flume={props.flume} destroyedBitNode={destroyed} /> PMUJ/ / </Typography>
|
||||
<Typography sx={{lineHeight: '1em',whiteSpace: 'pre'}}> \|| | | | | | | | | ||/ </Typography>
|
||||
<Typography sx={{lineHeight: '1em',whiteSpace: 'pre'}}> \| \_ | | | | | | _/ |/ </Typography>
|
||||
<Typography sx={{lineHeight: '1em',whiteSpace: 'pre'}}> \ \| / \ / \ |/ / </Typography>
|
||||
<Typography sx={{lineHeight: '1em',whiteSpace: 'pre'}}> <BitNodePortal n={1} level={n(1)} enter={enter} flume={props.flume} destroyedBitNode={destroyed} /> |/ <BitNodePortal n={2} level={n(2)} enter={enter} flume={props.flume} destroyedBitNode={destroyed} /> | | <BitNodePortal n={3} level={n(3)} enter={enter} flume={props.flume} destroyedBitNode={destroyed} /> \| <BitNodePortal n={4} level={n(4)} enter={enter} flume={props.flume} destroyedBitNode={destroyed} /> </Typography>
|
||||
<Typography sx={{lineHeight: '1em',whiteSpace: 'pre'}}> <BitNodePortal n={1} level={n(1)} flume={props.flume} destroyedBitNode={destroyed} /> |/ <BitNodePortal n={2} level={n(2)} flume={props.flume} destroyedBitNode={destroyed} /> | | <BitNodePortal n={3} level={n(3)} flume={props.flume} destroyedBitNode={destroyed} /> \| <BitNodePortal n={4} level={n(4)} flume={props.flume} destroyedBitNode={destroyed} /> </Typography>
|
||||
<Typography sx={{lineHeight: '1em',whiteSpace: 'pre'}}> | | | | | | | | </Typography>
|
||||
<Typography sx={{lineHeight: '1em',whiteSpace: 'pre'}}> \JUMP3R|JUMP|3R| |R3|PMUJ|R3PMUJ/ </Typography>
|
||||
<br />
|
||||
|
@ -1,8 +1,7 @@
|
||||
import React from "react";
|
||||
|
||||
import { enterBitNode } from "../../RedPill";
|
||||
import { BitNodes } from "../BitNode";
|
||||
import { IRouter } from "../../ui/Router";
|
||||
import { use } from "../../ui/Context";
|
||||
import { Modal } from "../../ui/React/Modal";
|
||||
import Typography from "@mui/material/Typography";
|
||||
import Button from "@mui/material/Button";
|
||||
@ -15,11 +14,9 @@ interface IProps {
|
||||
level: number;
|
||||
destroyedBitNode: number;
|
||||
flume: boolean;
|
||||
enter: (router: IRouter, flume: boolean, destroyedBitNode: number, newBitNode: number) => void;
|
||||
}
|
||||
|
||||
export function PortalModal(props: IProps): React.ReactElement {
|
||||
const router = use.Router();
|
||||
const bitNodeKey = "BitNode" + props.n;
|
||||
const bitNode = BitNodes[bitNodeKey];
|
||||
if (bitNode == null) throw new Error(`Could not find BitNode object for number: ${props.n}`);
|
||||
@ -48,7 +45,7 @@ export function PortalModal(props: IProps): React.ReactElement {
|
||||
aria-label={`enter-bitnode-${bitNode.number.toString()}`}
|
||||
autoFocus={true}
|
||||
onClick={() => {
|
||||
props.enter(router, props.flume, props.destroyedBitNode, props.n);
|
||||
enterBitNode(props.flume, props.destroyedBitNode, props.n);
|
||||
props.onClose();
|
||||
}}
|
||||
>
|
||||
|
@ -3,9 +3,12 @@ import { getRandomInt } from "../utils/helpers/getRandomInt";
|
||||
import { addOffset } from "../utils/helpers/addOffset";
|
||||
import { Generic_fromJSON, Generic_toJSON, IReviverValue, Reviver } from "../utils/JSONReviver";
|
||||
import { BladeburnerConstants } from "./data/Constants";
|
||||
import { IBladeburner } from "./IBladeburner";
|
||||
import { IAction, ISuccessChanceParams } from "./IAction";
|
||||
import { IPerson } from "../PersonObjects/IPerson";
|
||||
import { Bladeburner } from "./Bladeburner";
|
||||
import { Person } from "../PersonObjects/Person";
|
||||
|
||||
interface ISuccessChanceParams {
|
||||
est: boolean;
|
||||
}
|
||||
|
||||
class StatsMultiplier {
|
||||
[key: string]: number;
|
||||
@ -41,7 +44,7 @@ export interface IActionParams {
|
||||
teamCount?: number;
|
||||
}
|
||||
|
||||
export class Action implements IAction {
|
||||
export class Action {
|
||||
name = "";
|
||||
|
||||
// Difficulty scales with level. See getDifficulty() method
|
||||
@ -153,7 +156,7 @@ export class Action implements IAction {
|
||||
* Tests for success. Should be called when an action has completed
|
||||
* @param inst {Bladeburner} - Bladeburner instance
|
||||
*/
|
||||
attempt(inst: IBladeburner, person: IPerson): boolean {
|
||||
attempt(inst: Bladeburner, person: Person): boolean {
|
||||
return Math.random() < this.getSuccessChance(inst, person);
|
||||
}
|
||||
|
||||
@ -162,7 +165,7 @@ export class Action implements IAction {
|
||||
return 1;
|
||||
}
|
||||
|
||||
getActionTime(inst: IBladeburner, person: IPerson): number {
|
||||
getActionTime(inst: Bladeburner, person: Person): number {
|
||||
const difficulty = this.getDifficulty();
|
||||
let baseTime = difficulty / BladeburnerConstants.DifficultyToTimeFactor;
|
||||
const skillFac = inst.skillMultipliers.actionTime; // Always < 1
|
||||
@ -183,16 +186,16 @@ export class Action implements IAction {
|
||||
|
||||
// For actions that have teams. To be implemented by subtypes.
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
getTeamSuccessBonus(inst: IBladeburner): number {
|
||||
getTeamSuccessBonus(inst: Bladeburner): number {
|
||||
return 1;
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
getActionTypeSkillSuccessBonus(inst: IBladeburner): number {
|
||||
getActionTypeSkillSuccessBonus(inst: Bladeburner): number {
|
||||
return 1;
|
||||
}
|
||||
|
||||
getChaosCompetencePenalty(inst: IBladeburner, params: ISuccessChanceParams): number {
|
||||
getChaosCompetencePenalty(inst: Bladeburner, params: ISuccessChanceParams): number {
|
||||
const city = inst.getCurrentCity();
|
||||
if (params.est) {
|
||||
return Math.pow(city.popEst / BladeburnerConstants.PopulationThreshold, BladeburnerConstants.PopulationExponent);
|
||||
@ -201,7 +204,7 @@ export class Action implements IAction {
|
||||
}
|
||||
}
|
||||
|
||||
getChaosDifficultyBonus(inst: IBladeburner /*, params: ISuccessChanceParams*/): number {
|
||||
getChaosDifficultyBonus(inst: Bladeburner /*, params: ISuccessChanceParams*/): number {
|
||||
const city = inst.getCurrentCity();
|
||||
if (city.chaos > BladeburnerConstants.ChaosThreshold) {
|
||||
const diff = 1 + (city.chaos - BladeburnerConstants.ChaosThreshold);
|
||||
@ -212,7 +215,7 @@ export class Action implements IAction {
|
||||
return 1;
|
||||
}
|
||||
|
||||
getEstSuccessChance(inst: IBladeburner, person: IPerson): [number, number] {
|
||||
getEstSuccessChance(inst: Bladeburner, person: Person): [number, number] {
|
||||
function clamp(x: number): number {
|
||||
return Math.max(0, Math.min(x, 1));
|
||||
}
|
||||
@ -233,7 +236,7 @@ export class Action implements IAction {
|
||||
* @params - options:
|
||||
* est (bool): Get success chance estimate instead of real success chance
|
||||
*/
|
||||
getSuccessChance(inst: IBladeburner, person: IPerson, params: ISuccessChanceParams = { est: false }): number {
|
||||
getSuccessChance(inst: Bladeburner, person: Person, params: ISuccessChanceParams = { est: false }): number {
|
||||
if (inst == null) {
|
||||
throw new Error("Invalid Bladeburner instance passed into Action.getSuccessChance");
|
||||
}
|
||||
|
@ -1,4 +1,3 @@
|
||||
import { IActionIdentifier } from "./IActionIdentifier";
|
||||
import { Generic_fromJSON, Generic_toJSON, IReviverValue, Reviver } from "../utils/JSONReviver";
|
||||
|
||||
interface IParams {
|
||||
@ -6,7 +5,7 @@ interface IParams {
|
||||
type?: number;
|
||||
}
|
||||
|
||||
export class ActionIdentifier implements IActionIdentifier {
|
||||
export class ActionIdentifier {
|
||||
name = "";
|
||||
type = -1;
|
||||
|
||||
|
@ -12,11 +12,11 @@ export class BlackOperation extends Operation {
|
||||
return 1.5;
|
||||
}
|
||||
|
||||
getChaosCompetencePenalty(/*inst: IBladeburner, params: ISuccessChanceParams*/): number {
|
||||
getChaosCompetencePenalty(/*inst: Bladeburner, params: ISuccessChanceParams*/): number {
|
||||
return 1;
|
||||
}
|
||||
|
||||
getChaosDifficultyBonus(/*inst: IBladeburner, params: ISuccessChanceParams*/): number {
|
||||
getChaosDifficultyBonus(/*inst: Bladeburner, params: ISuccessChanceParams*/): number {
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
@ -1,6 +1,4 @@
|
||||
import { Reviver, Generic_toJSON, Generic_fromJSON, IReviverValue } from "../utils/JSONReviver";
|
||||
import { IBladeburner } from "./IBladeburner";
|
||||
import { IActionIdentifier } from "./IActionIdentifier";
|
||||
import { ActionIdentifier } from "./ActionIdentifier";
|
||||
import { ActionTypes } from "./data/ActionTypes";
|
||||
import { Growths } from "./data/Growths";
|
||||
@ -13,11 +11,11 @@ import { formatNumber } from "../utils/StringHelperFunctions";
|
||||
import { Skills } from "./Skills";
|
||||
import { Skill } from "./Skill";
|
||||
import { City } from "./City";
|
||||
import { IAction } from "./IAction";
|
||||
import { IPlayer } from "../PersonObjects/IPlayer";
|
||||
import { Action } from "./Action";
|
||||
import { Player } from "../Player";
|
||||
import { createTaskTracker, ITaskTracker } from "../PersonObjects/ITaskTracker";
|
||||
import { IPerson } from "../PersonObjects/IPerson";
|
||||
import { IRouter } from "../ui/Router";
|
||||
import { Person } from "../PersonObjects/Person";
|
||||
import { Router } from "../ui/GameRoot";
|
||||
import { ConsoleHelpText } from "./data/Help";
|
||||
import { exceptionAlert } from "../utils/helpers/exceptionAlert";
|
||||
import { getRandomInt } from "../utils/helpers/getRandomInt";
|
||||
@ -25,7 +23,6 @@ import { BladeburnerConstants } from "./data/Constants";
|
||||
import { numeralWrapper } from "../ui/numeralFormat";
|
||||
import { BitNodeMultipliers } from "../BitNode/BitNodeMultipliers";
|
||||
import { addOffset } from "../utils/helpers/addOffset";
|
||||
import { Faction } from "../Faction/Faction";
|
||||
import { Factions, factionExists } from "../Faction/Factions";
|
||||
import { calculateHospitalizationCost } from "../Hospital/Hospital";
|
||||
import { dialogBoxCreate } from "../ui/React/DialogBox";
|
||||
@ -39,13 +36,13 @@ import { KEY } from "../utils/helpers/keyCodes";
|
||||
import { isSleeveInfiltrateWork } from "../PersonObjects/Sleeve/Work/SleeveInfiltrateWork";
|
||||
import { isSleeveSupportWork } from "../PersonObjects/Sleeve/Work/SleeveSupportWork";
|
||||
|
||||
interface BlackOpsAttempt {
|
||||
export interface BlackOpsAttempt {
|
||||
error?: string;
|
||||
isAvailable?: boolean;
|
||||
action?: BlackOperation;
|
||||
}
|
||||
|
||||
export class Bladeburner implements IBladeburner {
|
||||
export class Bladeburner {
|
||||
numHosp = 0;
|
||||
moneyLost = 0;
|
||||
rank = 0;
|
||||
@ -67,7 +64,7 @@ export class Bladeburner implements IBladeburner {
|
||||
actionTimeCurrent = 0;
|
||||
actionTimeOverflow = 0;
|
||||
|
||||
action: IActionIdentifier = new ActionIdentifier({
|
||||
action: ActionIdentifier = new ActionIdentifier({
|
||||
type: ActionTypes["Idle"],
|
||||
});
|
||||
|
||||
@ -89,18 +86,18 @@ export class Bladeburner implements IBladeburner {
|
||||
events: true,
|
||||
};
|
||||
automateEnabled = false;
|
||||
automateActionHigh: IActionIdentifier = new ActionIdentifier({
|
||||
automateActionHigh: ActionIdentifier = new ActionIdentifier({
|
||||
type: ActionTypes["Idle"],
|
||||
});
|
||||
automateThreshHigh = 0;
|
||||
automateActionLow: IActionIdentifier = new ActionIdentifier({
|
||||
automateActionLow: ActionIdentifier = new ActionIdentifier({
|
||||
type: ActionTypes["Idle"],
|
||||
});
|
||||
automateThreshLow = 0;
|
||||
consoleHistory: string[] = [];
|
||||
consoleLogs: string[] = ["Bladeburner Console", "Type 'help' to see console commands"];
|
||||
|
||||
constructor(player?: IPlayer) {
|
||||
constructor() {
|
||||
for (let i = 0; i < BladeburnerConstants.CityNames.length; ++i) {
|
||||
this.cities[BladeburnerConstants.CityNames[i]] = new City(BladeburnerConstants.CityNames[i]);
|
||||
}
|
||||
@ -108,16 +105,14 @@ export class Bladeburner implements IBladeburner {
|
||||
this.updateSkillMultipliers(); // Calls resetSkillMultipliers()
|
||||
|
||||
// Max Stamina is based on stats and Bladeburner-specific bonuses
|
||||
if (player) this.calculateMaxStamina(player);
|
||||
this.calculateMaxStamina();
|
||||
this.stamina = this.maxStamina;
|
||||
this.create();
|
||||
}
|
||||
|
||||
getCurrentCity(): City {
|
||||
const city = this.cities[this.city];
|
||||
if (!(city instanceof City)) {
|
||||
throw new Error("Bladeburner.getCurrentCity() did not properly return a City object");
|
||||
}
|
||||
if (!city) throw new Error("Invalid city in Bladeburner.getCurrentCity()");
|
||||
return city;
|
||||
}
|
||||
|
||||
@ -125,7 +120,7 @@ export class Bladeburner implements IBladeburner {
|
||||
return Math.min(1, this.stamina / (0.5 * this.maxStamina));
|
||||
}
|
||||
|
||||
canAttemptBlackOp(actionId: IActionIdentifier): BlackOpsAttempt {
|
||||
canAttemptBlackOp(actionId: ActionIdentifier): BlackOpsAttempt {
|
||||
// Safety measure - don't repeat BlackOps that are already done
|
||||
if (this.blackops[actionId.name] != null) {
|
||||
return { error: "Tried to start a Black Operation that had already been completed" };
|
||||
@ -162,7 +157,8 @@ export class Bladeburner implements IBladeburner {
|
||||
return { isAvailable: true, action };
|
||||
}
|
||||
|
||||
startAction(person: IPerson, actionId: IActionIdentifier): void {
|
||||
/** This function is only for the player. Sleeves use their own functions to perform blade work. */
|
||||
startAction(actionId: ActionIdentifier): void {
|
||||
if (actionId == null) return;
|
||||
this.action = actionId;
|
||||
this.actionTimeCurrent = 0;
|
||||
@ -179,7 +175,7 @@ export class Bladeburner implements IBladeburner {
|
||||
if (action.count < 1) {
|
||||
return this.resetAction();
|
||||
}
|
||||
this.actionTimeToComplete = action.getActionTime(this, person);
|
||||
this.actionTimeToComplete = action.getActionTime(this, Player);
|
||||
} catch (e: unknown) {
|
||||
exceptionAlert(e);
|
||||
}
|
||||
@ -196,7 +192,7 @@ export class Bladeburner implements IBladeburner {
|
||||
if (actionId.name === "Raid" && this.getCurrentCity().comms === 0) {
|
||||
return this.resetAction();
|
||||
}
|
||||
this.actionTimeToComplete = action.getActionTime(this, person);
|
||||
this.actionTimeToComplete = action.getActionTime(this, Player);
|
||||
} catch (e: unknown) {
|
||||
exceptionAlert(e);
|
||||
}
|
||||
@ -214,14 +210,14 @@ export class Bladeburner implements IBladeburner {
|
||||
if (testBlackOp.action === undefined) {
|
||||
throw new Error("action should not be null");
|
||||
}
|
||||
this.actionTimeToComplete = testBlackOp.action.getActionTime(this, person);
|
||||
this.actionTimeToComplete = testBlackOp.action.getActionTime(this, Player);
|
||||
} catch (e: unknown) {
|
||||
exceptionAlert(e);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case ActionTypes["Recruitment"]:
|
||||
this.actionTimeToComplete = this.getRecruitmentTime(person);
|
||||
this.actionTimeToComplete = this.getRecruitmentTime(Player);
|
||||
break;
|
||||
case ActionTypes["Training"]:
|
||||
case ActionTypes["FieldAnalysis"]:
|
||||
@ -234,7 +230,7 @@ export class Bladeburner implements IBladeburner {
|
||||
this.actionTimeToComplete = 60;
|
||||
break;
|
||||
default:
|
||||
throw new Error("Invalid Action Type in startAction(Bladeburner,player, ): " + actionId.type);
|
||||
throw new Error("Invalid Action Type in bladeburner.startAction(): " + actionId.type);
|
||||
}
|
||||
}
|
||||
|
||||
@ -252,7 +248,7 @@ export class Bladeburner implements IBladeburner {
|
||||
this.updateSkillMultipliers();
|
||||
}
|
||||
|
||||
executeConsoleCommands(player: IPlayer, commands: string): void {
|
||||
executeConsoleCommands(commands: string): void {
|
||||
try {
|
||||
// Console History
|
||||
if (this.consoleHistory[this.consoleHistory.length - 1] != commands) {
|
||||
@ -264,7 +260,7 @@ export class Bladeburner implements IBladeburner {
|
||||
|
||||
const arrayOfCommands = commands.split(";");
|
||||
for (let i = 0; i < arrayOfCommands.length; ++i) {
|
||||
this.executeConsoleCommand(player, arrayOfCommands[i]);
|
||||
this.executeConsoleCommand(arrayOfCommands[i]);
|
||||
}
|
||||
} catch (e: unknown) {
|
||||
exceptionAlert(e);
|
||||
@ -309,7 +305,7 @@ export class Bladeburner implements IBladeburner {
|
||||
}
|
||||
|
||||
// working on
|
||||
getActionIdFromTypeAndName(type = "", name = ""): IActionIdentifier | null {
|
||||
getActionIdFromTypeAndName(type = "", name = ""): ActionIdentifier | null {
|
||||
if (type === "" || name === "") {
|
||||
return null;
|
||||
}
|
||||
@ -394,7 +390,7 @@ export class Bladeburner implements IBladeburner {
|
||||
return null;
|
||||
}
|
||||
|
||||
executeStartConsoleCommand(player: IPlayer, args: string[]): void {
|
||||
executeStartConsoleCommand(args: string[]): void {
|
||||
if (args.length !== 3) {
|
||||
this.postToConsole("Invalid usage of 'start' console command: start [type] [name]");
|
||||
this.postToConsole("Use 'help start' for more info");
|
||||
@ -407,7 +403,7 @@ export class Bladeburner implements IBladeburner {
|
||||
if (GeneralActions[name] != null) {
|
||||
this.action.type = ActionTypes[name];
|
||||
this.action.name = name;
|
||||
this.startAction(player, this.action);
|
||||
this.startAction(this.action);
|
||||
} else {
|
||||
this.postToConsole("Invalid action name specified: " + args[2]);
|
||||
}
|
||||
@ -417,7 +413,7 @@ export class Bladeburner implements IBladeburner {
|
||||
if (this.contracts[name] != null) {
|
||||
this.action.type = ActionTypes.Contract;
|
||||
this.action.name = name;
|
||||
this.startAction(player, this.action);
|
||||
this.startAction(this.action);
|
||||
} else {
|
||||
this.postToConsole("Invalid contract name specified: " + args[2]);
|
||||
}
|
||||
@ -429,7 +425,7 @@ export class Bladeburner implements IBladeburner {
|
||||
if (this.operations[name] != null) {
|
||||
this.action.type = ActionTypes.Operation;
|
||||
this.action.name = name;
|
||||
this.startAction(player, this.action);
|
||||
this.startAction(this.action);
|
||||
} else {
|
||||
this.postToConsole("Invalid Operation name specified: " + args[2]);
|
||||
}
|
||||
@ -441,7 +437,7 @@ export class Bladeburner implements IBladeburner {
|
||||
if (BlackOperations[name] != null) {
|
||||
this.action.type = ActionTypes.BlackOperation;
|
||||
this.action.name = name;
|
||||
this.startAction(player, this.action);
|
||||
this.startAction(this.action);
|
||||
} else {
|
||||
this.postToConsole("Invalid BlackOp name specified: " + args[2]);
|
||||
}
|
||||
@ -542,7 +538,7 @@ export class Bladeburner implements IBladeburner {
|
||||
case 3: {
|
||||
const skillName = args[2];
|
||||
const skill = Skills[skillName];
|
||||
if (skill == null || !(skill instanceof Skill)) {
|
||||
if (!skill) {
|
||||
this.postToConsole("Invalid skill name (Note that it is case-sensitive): " + skillName);
|
||||
break;
|
||||
}
|
||||
@ -684,10 +680,7 @@ export class Bladeburner implements IBladeburner {
|
||||
".",
|
||||
);
|
||||
} else if (flag.toLowerCase().includes("en")) {
|
||||
if (
|
||||
!(this.automateActionLow instanceof ActionIdentifier) ||
|
||||
!(this.automateActionHigh instanceof ActionIdentifier)
|
||||
) {
|
||||
if (!this.automateActionLow || !this.automateActionHigh) {
|
||||
return this.log("Failed to enable automation. Actions were not set");
|
||||
}
|
||||
this.automateEnabled = true;
|
||||
@ -820,7 +813,7 @@ export class Bladeburner implements IBladeburner {
|
||||
return args;
|
||||
}
|
||||
|
||||
executeConsoleCommand(player: IPlayer, command: string): void {
|
||||
executeConsoleCommand(command: string): void {
|
||||
command = command.trim();
|
||||
command = command.replace(/\s\s+/g, " "); // Replace all whitespace w/ a single space
|
||||
|
||||
@ -845,7 +838,7 @@ export class Bladeburner implements IBladeburner {
|
||||
this.executeSkillConsoleCommand(args);
|
||||
break;
|
||||
case "start":
|
||||
this.executeStartConsoleCommand(player, args);
|
||||
this.executeStartConsoleCommand(args);
|
||||
break;
|
||||
case "stop":
|
||||
this.resetAction();
|
||||
@ -898,9 +891,7 @@ export class Bladeburner implements IBladeburner {
|
||||
// Choose random source/destination city for events
|
||||
const sourceCityName = BladeburnerConstants.CityNames[getRandomInt(0, 5)];
|
||||
const sourceCity = this.cities[sourceCityName];
|
||||
if (!(sourceCity instanceof City)) {
|
||||
throw new Error("sourceCity was not a City object in Bladeburner.randomEvent()");
|
||||
}
|
||||
if (!sourceCity) throw new Error("Invalid sourceCity in Bladeburner.randomEvent()");
|
||||
|
||||
let destCityName = BladeburnerConstants.CityNames[getRandomInt(0, 5)];
|
||||
while (destCityName === sourceCityName) {
|
||||
@ -908,9 +899,7 @@ export class Bladeburner implements IBladeburner {
|
||||
}
|
||||
const destCity = this.cities[destCityName];
|
||||
|
||||
if (!(sourceCity instanceof City) || !(destCity instanceof City)) {
|
||||
throw new Error("sourceCity/destCity was not a City object in Bladeburner.randomEvent()");
|
||||
}
|
||||
if (!sourceCity || !destCity) throw new Error("Invalid sourceCity or destCity in Bladeburner.randomEvent()");
|
||||
|
||||
if (chance <= 0.05) {
|
||||
// New Synthoid Community, 5%
|
||||
@ -994,7 +983,7 @@ export class Bladeburner implements IBladeburner {
|
||||
* @param action(Action obj) - Derived action class
|
||||
* @param success(bool) - Whether action was successful
|
||||
*/
|
||||
getActionStats(action: IAction, person: IPerson, success: boolean): ITaskTracker {
|
||||
getActionStats(action: Action, person: Person, success: boolean): ITaskTracker {
|
||||
const difficulty = action.getDifficulty();
|
||||
|
||||
/**
|
||||
@ -1024,7 +1013,7 @@ export class Bladeburner implements IBladeburner {
|
||||
};
|
||||
}
|
||||
|
||||
getDiplomacyEffectiveness(person: IPerson): number {
|
||||
getDiplomacyEffectiveness(person: Person): number {
|
||||
// Returns a decimal by which the city's chaos level should be multiplied (e.g. 0.98)
|
||||
const CharismaLinearFactor = 1e3;
|
||||
const CharismaExponentialFactor = 0.045;
|
||||
@ -1034,11 +1023,11 @@ export class Bladeburner implements IBladeburner {
|
||||
return (100 - charismaEff) / 100;
|
||||
}
|
||||
|
||||
getRecruitmentSuccessChance(person: IPerson): number {
|
||||
getRecruitmentSuccessChance(person: Person): number {
|
||||
return Math.pow(person.skills.charisma, 0.45) / (this.teamSize - this.sleeveSize + 1);
|
||||
}
|
||||
|
||||
getRecruitmentTime(person: IPerson): number {
|
||||
getRecruitmentTime(person: Person): number {
|
||||
const effCharisma = person.skills.charisma * this.skillMultipliers.effCha;
|
||||
const charismaFactor = Math.pow(effCharisma, 0.81) + effCharisma / 90;
|
||||
return Math.max(10, Math.round(BladeburnerConstants.BaseRecruitmentTimeNeeded - charismaFactor));
|
||||
@ -1105,7 +1094,7 @@ export class Bladeburner implements IBladeburner {
|
||||
}
|
||||
}
|
||||
|
||||
completeOperation(success: boolean, player: IPlayer): void {
|
||||
completeOperation(success: boolean): void {
|
||||
if (this.action.type !== ActionTypes.Operation) {
|
||||
throw new Error("completeOperation() called even though current action is not an Operation");
|
||||
}
|
||||
@ -1126,7 +1115,7 @@ export class Bladeburner implements IBladeburner {
|
||||
const losses = getRandomInt(0, max);
|
||||
this.teamSize -= losses;
|
||||
if (this.teamSize < this.sleeveSize) {
|
||||
const sup = player.sleeves.filter((x) => isSleeveSupportWork(x.currentWork));
|
||||
const sup = Player.sleeves.filter((x) => isSleeveSupportWork(x.currentWork));
|
||||
for (let i = 0; i > this.teamSize - this.sleeveSize; i--) {
|
||||
const r = Math.floor(Math.random() * sup.length);
|
||||
sup[r].takeDamage(sup[r].hp.max);
|
||||
@ -1201,7 +1190,7 @@ export class Bladeburner implements IBladeburner {
|
||||
}
|
||||
}
|
||||
|
||||
getActionObject(actionId: IActionIdentifier): IAction | null {
|
||||
getActionObject(actionId: ActionIdentifier): Action | null {
|
||||
/**
|
||||
* Given an ActionIdentifier object, returns the corresponding
|
||||
* GeneralAction, Contract, Operation, or BlackOperation object
|
||||
@ -1231,7 +1220,7 @@ export class Bladeburner implements IBladeburner {
|
||||
}
|
||||
}
|
||||
|
||||
completeContract(success: boolean, actionIdent: IActionIdentifier): void {
|
||||
completeContract(success: boolean, actionIdent: ActionIdentifier): void {
|
||||
if (actionIdent.type !== ActionTypes.Contract) {
|
||||
throw new Error("completeContract() called even though current action is not a Contract");
|
||||
}
|
||||
@ -1256,7 +1245,7 @@ export class Bladeburner implements IBladeburner {
|
||||
}
|
||||
}
|
||||
|
||||
completeAction(player: IPlayer, person: IPerson, actionIdent: IActionIdentifier, isPlayer = true): ITaskTracker {
|
||||
completeAction(person: Person, actionIdent: ActionIdentifier, isPlayer = true): ITaskTracker {
|
||||
let retValue = createTaskTracker();
|
||||
switch (actionIdent.type) {
|
||||
case ActionTypes["Contract"]:
|
||||
@ -1304,24 +1293,16 @@ export class Bladeburner implements IBladeburner {
|
||||
this.changeRank(person, gain);
|
||||
if (isOperation && this.logging.ops) {
|
||||
this.log(
|
||||
`${person.whoAmI()}: ` +
|
||||
action.name +
|
||||
" successfully completed! Gained " +
|
||||
formatNumber(gain, 3) +
|
||||
" rank",
|
||||
`${person.whoAmI()}: ${action.name} successfully completed! Gained ${formatNumber(gain, 3)} rank`,
|
||||
);
|
||||
} else if (!isOperation && this.logging.contracts) {
|
||||
this.log(
|
||||
`${person.whoAmI()}: ` +
|
||||
action.name +
|
||||
" contract successfully completed! Gained " +
|
||||
formatNumber(gain, 3) +
|
||||
" rank and " +
|
||||
numeralWrapper.formatMoney(moneyGain),
|
||||
`${person.whoAmI()}: ${action.name} contract successfully completed! Gained ` +
|
||||
`${formatNumber(gain, 3)} rank and ${numeralWrapper.formatMoney(moneyGain)}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
isOperation ? this.completeOperation(true, player) : this.completeContract(true, actionIdent);
|
||||
isOperation ? this.completeOperation(true) : this.completeContract(true, actionIdent);
|
||||
} else {
|
||||
retValue = this.getActionStats(action, person, false);
|
||||
++action.failures;
|
||||
@ -1335,7 +1316,7 @@ export class Bladeburner implements IBladeburner {
|
||||
damage = action.hpLoss * difficultyMultiplier;
|
||||
damage = Math.ceil(addOffset(damage, 10));
|
||||
this.hpLost += damage;
|
||||
const cost = calculateHospitalizationCost(player, damage);
|
||||
const cost = calculateHospitalizationCost(damage);
|
||||
if (person.takeDamage(damage)) {
|
||||
++this.numHosp;
|
||||
this.moneyLost += cost;
|
||||
@ -1353,7 +1334,7 @@ export class Bladeburner implements IBladeburner {
|
||||
} else if (!isOperation && this.logging.contracts) {
|
||||
this.log(`${person.whoAmI()}: ` + action.name + " contract failed! " + logLossText);
|
||||
}
|
||||
isOperation ? this.completeOperation(false, player) : this.completeContract(false, actionIdent);
|
||||
isOperation ? this.completeOperation(false) : this.completeContract(false, actionIdent);
|
||||
}
|
||||
if (action.autoLevel) {
|
||||
action.level = action.maxLevel;
|
||||
@ -1412,7 +1393,7 @@ export class Bladeburner implements IBladeburner {
|
||||
if (action.hpLoss) {
|
||||
damage = action.hpLoss * difficultyMultiplier;
|
||||
damage = Math.ceil(addOffset(damage, 10));
|
||||
const cost = calculateHospitalizationCost(player, damage);
|
||||
const cost = calculateHospitalizationCost(damage);
|
||||
if (person.takeDamage(damage)) {
|
||||
++this.numHosp;
|
||||
this.moneyLost += cost;
|
||||
@ -1440,7 +1421,7 @@ export class Bladeburner implements IBladeburner {
|
||||
const losses = getRandomInt(1, teamLossMax);
|
||||
this.teamSize -= losses;
|
||||
if (this.teamSize < this.sleeveSize) {
|
||||
const sup = player.sleeves.filter((x) => isSleeveSupportWork(x.currentWork));
|
||||
const sup = Player.sleeves.filter((x) => isSleeveSupportWork(x.currentWork));
|
||||
for (let i = 0; i > this.teamSize - this.sleeveSize; i--) {
|
||||
const r = Math.floor(Math.random() * sup.length);
|
||||
sup[r].takeDamage(sup[r].hp.max);
|
||||
@ -1603,8 +1584,8 @@ export class Bladeburner implements IBladeburner {
|
||||
return retValue;
|
||||
}
|
||||
|
||||
infiltrateSynthoidCommunities(p: IPlayer): void {
|
||||
const infilSleeves = p.sleeves.filter((s) => isSleeveInfiltrateWork(s.currentWork)).length;
|
||||
infiltrateSynthoidCommunities(): void {
|
||||
const infilSleeves = Player.sleeves.filter((s) => isSleeveInfiltrateWork(s.currentWork)).length;
|
||||
const amt = Math.pow(infilSleeves, -0.5) / 2;
|
||||
for (const contract of Object.keys(this.contracts)) {
|
||||
this.contracts[contract].count += amt;
|
||||
@ -1617,7 +1598,7 @@ export class Bladeburner implements IBladeburner {
|
||||
}
|
||||
}
|
||||
|
||||
changeRank(person: IPerson, change: number): void {
|
||||
changeRank(person: Person, change: number): void {
|
||||
if (isNaN(change)) {
|
||||
throw new Error("NaN passed into Bladeburner.changeRank()");
|
||||
}
|
||||
@ -1630,7 +1611,7 @@ export class Bladeburner implements IBladeburner {
|
||||
const bladeburnersFactionName = FactionNames.Bladeburners;
|
||||
if (factionExists(bladeburnersFactionName)) {
|
||||
const bladeburnerFac = Factions[bladeburnersFactionName];
|
||||
if (!(bladeburnerFac instanceof Faction)) {
|
||||
if (!bladeburnerFac) {
|
||||
throw new Error(
|
||||
`Could not properly get ${FactionNames.Bladeburners} Faction object in ${FactionNames.Bladeburners} UI Overview Faction button`,
|
||||
);
|
||||
@ -1654,12 +1635,12 @@ export class Bladeburner implements IBladeburner {
|
||||
}
|
||||
}
|
||||
|
||||
processAction(router: IRouter, player: IPlayer, seconds: number): void {
|
||||
processAction(seconds: number): void {
|
||||
if (this.action.type === ActionTypes["Idle"]) return;
|
||||
if (this.actionTimeToComplete <= 0) {
|
||||
throw new Error(`Invalid actionTimeToComplete value: ${this.actionTimeToComplete}, type; ${this.action.type}`);
|
||||
}
|
||||
if (!(this.action instanceof ActionIdentifier)) {
|
||||
if (!this.action) {
|
||||
throw new Error("Bladeburner.action is not an ActionIdentifier Object");
|
||||
}
|
||||
|
||||
@ -1670,31 +1651,31 @@ export class Bladeburner implements IBladeburner {
|
||||
if (this.actionTimeCurrent >= this.actionTimeToComplete) {
|
||||
this.actionTimeOverflow = this.actionTimeCurrent - this.actionTimeToComplete;
|
||||
const action = this.getActionObject(this.action);
|
||||
const retValue = this.completeAction(player, player, this.action);
|
||||
player.gainMoney(retValue.money, "bladeburner");
|
||||
player.gainStats(retValue);
|
||||
const retValue = this.completeAction(Player, this.action);
|
||||
Player.gainMoney(retValue.money, "bladeburner");
|
||||
Player.gainStats(retValue);
|
||||
// Operation Daedalus
|
||||
if (action == null) {
|
||||
throw new Error("Failed to get BlackOperation Object for: " + this.action.name);
|
||||
} else if (this.action.type != ActionTypes["BlackOperation"] && this.action.type != ActionTypes["BlackOp"]) {
|
||||
this.startAction(player, this.action); // Repeat action
|
||||
this.startAction(this.action); // Repeat action
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
calculateStaminaGainPerSecond(player: IPlayer): number {
|
||||
const effAgility = player.skills.agility * this.skillMultipliers.effAgi;
|
||||
calculateStaminaGainPerSecond(): number {
|
||||
const effAgility = Player.skills.agility * this.skillMultipliers.effAgi;
|
||||
const maxStaminaBonus = this.maxStamina / BladeburnerConstants.MaxStaminaToGainFactor;
|
||||
const gain = (BladeburnerConstants.StaminaGainPerSecond + maxStaminaBonus) * Math.pow(effAgility, 0.17);
|
||||
return gain * (this.skillMultipliers.stamina * player.mults.bladeburner_stamina_gain);
|
||||
return gain * (this.skillMultipliers.stamina * Player.mults.bladeburner_stamina_gain);
|
||||
}
|
||||
|
||||
calculateMaxStamina(player: IPlayer): void {
|
||||
const effAgility = player.skills.agility * this.skillMultipliers.effAgi;
|
||||
calculateMaxStamina(): void {
|
||||
const effAgility = Player.skills.agility * this.skillMultipliers.effAgi;
|
||||
const maxStamina =
|
||||
(Math.pow(effAgility, 0.8) + this.staminaBonus) *
|
||||
this.skillMultipliers.stamina *
|
||||
player.mults.bladeburner_max_stamina;
|
||||
Player.mults.bladeburner_max_stamina;
|
||||
if (this.maxStamina !== maxStamina) {
|
||||
const oldMax = this.maxStamina;
|
||||
this.maxStamina = maxStamina;
|
||||
@ -1974,12 +1955,12 @@ export class Bladeburner implements IBladeburner {
|
||||
});
|
||||
}
|
||||
|
||||
process(router: IRouter, player: IPlayer): void {
|
||||
process(): void {
|
||||
// Edge race condition when the engine checks the processing counters and attempts to route before the router is initialized.
|
||||
if (!router.isInitialized) return;
|
||||
if (!Router.isInitialized) return;
|
||||
|
||||
// If the Player starts doing some other actions, set action to idle and alert
|
||||
if (!player.hasAugmentation(AugmentationNames.BladesSimulacrum, true) && player.currentWork) {
|
||||
if (!Player.hasAugmentation(AugmentationNames.BladesSimulacrum, true) && Player.currentWork) {
|
||||
if (this.action.type !== ActionTypes["Idle"]) {
|
||||
let msg = "Your Bladeburner action was cancelled because you started doing something else.";
|
||||
if (this.automateEnabled) {
|
||||
@ -2006,8 +1987,8 @@ export class Bladeburner implements IBladeburner {
|
||||
this.storedCycles -= seconds * BladeburnerConstants.CyclesPerSecond;
|
||||
|
||||
// Stamina
|
||||
this.calculateMaxStamina(player);
|
||||
this.stamina += this.calculateStaminaGainPerSecond(player) * seconds;
|
||||
this.calculateMaxStamina();
|
||||
this.stamina += this.calculateStaminaGainPerSecond() * seconds;
|
||||
this.stamina = Math.min(this.maxStamina, this.stamina);
|
||||
|
||||
// Count increase for contracts/operations
|
||||
@ -2027,9 +2008,7 @@ export class Bladeburner implements IBladeburner {
|
||||
// Chaos goes down very slowly
|
||||
for (const cityName of BladeburnerConstants.CityNames) {
|
||||
const city = this.cities[cityName];
|
||||
if (!(city instanceof City)) {
|
||||
throw new Error("Invalid City object when processing passive chaos reduction in Bladeburner.process");
|
||||
}
|
||||
if (!city) throw new Error("Invalid city when processing passive chaos reduction in Bladeburner.process");
|
||||
city.chaos -= 0.0001 * seconds;
|
||||
city.chaos = Math.max(0, city.chaos);
|
||||
}
|
||||
@ -2042,7 +2021,7 @@ export class Bladeburner implements IBladeburner {
|
||||
this.randomEventCounter += getRandomInt(240, 600);
|
||||
}
|
||||
|
||||
this.processAction(router, player, seconds);
|
||||
this.processAction(seconds);
|
||||
|
||||
// Automation
|
||||
if (this.automateEnabled) {
|
||||
@ -2053,7 +2032,7 @@ export class Bladeburner implements IBladeburner {
|
||||
type: this.automateActionLow.type,
|
||||
name: this.automateActionLow.name,
|
||||
});
|
||||
this.startAction(player, this.action);
|
||||
this.startAction(this.action);
|
||||
}
|
||||
} else if (this.stamina >= this.automateThreshHigh) {
|
||||
if (this.action.name !== this.automateActionHigh.name || this.action.type !== this.automateActionHigh.type) {
|
||||
@ -2061,14 +2040,14 @@ export class Bladeburner implements IBladeburner {
|
||||
type: this.automateActionHigh.type,
|
||||
name: this.automateActionHigh.name,
|
||||
});
|
||||
this.startAction(player, this.action);
|
||||
this.startAction(this.action);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
getTypeAndNameFromActionId(actionId: IActionIdentifier): {
|
||||
getTypeAndNameFromActionId(actionId: ActionIdentifier): {
|
||||
type: string;
|
||||
name: string;
|
||||
} {
|
||||
@ -2121,7 +2100,7 @@ export class Bladeburner implements IBladeburner {
|
||||
return Object.keys(Skills);
|
||||
}
|
||||
|
||||
startActionNetscriptFn(player: IPlayer, type: string, name: string, workerScript: WorkerScript): boolean {
|
||||
startActionNetscriptFn(type: string, name: string, workerScript: WorkerScript): boolean {
|
||||
const errorLogText = `Invalid action: type='${type}' name='${name}'`;
|
||||
const actionId = this.getActionIdFromTypeAndName(type, name);
|
||||
if (actionId == null) {
|
||||
@ -2139,7 +2118,7 @@ export class Bladeburner implements IBladeburner {
|
||||
}
|
||||
|
||||
try {
|
||||
this.startAction(player, actionId);
|
||||
this.startAction(actionId);
|
||||
workerScript.log(
|
||||
"bladeburner.startAction",
|
||||
() => `Starting bladeburner action with type '${type}' and name '${name}'`,
|
||||
@ -2153,7 +2132,7 @@ export class Bladeburner implements IBladeburner {
|
||||
}
|
||||
}
|
||||
|
||||
getActionTimeNetscriptFn(person: IPerson, type: string, name: string): number | string {
|
||||
getActionTimeNetscriptFn(person: Person, type: string, name: string): number | string {
|
||||
const actionId = this.getActionIdFromTypeAndName(type, name);
|
||||
if (actionId == null) {
|
||||
return "bladeburner.getActionTime";
|
||||
@ -2184,7 +2163,7 @@ export class Bladeburner implements IBladeburner {
|
||||
}
|
||||
}
|
||||
|
||||
getActionEstimatedSuccessChanceNetscriptFn(person: IPerson, type: string, name: string): [number, number] | string {
|
||||
getActionEstimatedSuccessChanceNetscriptFn(person: Person, type: string, name: string): [number, number] | string {
|
||||
const actionId = this.getActionIdFromTypeAndName(type, name);
|
||||
if (actionId == null) {
|
||||
return "bladeburner.getActionEstimatedSuccessChance";
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { IBladeburner } from "./IBladeburner";
|
||||
import { Bladeburner } from "./Bladeburner";
|
||||
import { Action, IActionParams } from "./Action";
|
||||
import { Generic_fromJSON, Generic_toJSON, IReviverValue, Reviver } from "../utils/JSONReviver";
|
||||
|
||||
@ -7,7 +7,7 @@ export class Contract extends Action {
|
||||
super(params);
|
||||
}
|
||||
|
||||
getActionTypeSkillSuccessBonus(inst: IBladeburner): number {
|
||||
getActionTypeSkillSuccessBonus(inst: Bladeburner): number {
|
||||
return inst.skillMultipliers.successChanceContract;
|
||||
}
|
||||
|
||||
|
@ -1,72 +0,0 @@
|
||||
import { IReviverValue } from "../utils/JSONReviver";
|
||||
import { IPerson } from "../PersonObjects/IPerson";
|
||||
import { IBladeburner } from "./IBladeburner";
|
||||
|
||||
interface IStatsMultiplier {
|
||||
[key: string]: number;
|
||||
|
||||
hack: number;
|
||||
str: number;
|
||||
def: number;
|
||||
dex: number;
|
||||
agi: number;
|
||||
cha: number;
|
||||
int: number;
|
||||
}
|
||||
|
||||
export interface ISuccessChanceParams {
|
||||
est: boolean;
|
||||
}
|
||||
|
||||
export interface IAction {
|
||||
name: string;
|
||||
|
||||
// Difficulty scales with level. See getDifficulty() method
|
||||
level: number;
|
||||
maxLevel: number;
|
||||
autoLevel: boolean;
|
||||
baseDifficulty: number;
|
||||
difficultyFac: number;
|
||||
|
||||
// Rank increase/decrease is affected by this exponent
|
||||
rewardFac: number;
|
||||
|
||||
successes: number;
|
||||
failures: number;
|
||||
|
||||
// All of these scale with level/difficulty
|
||||
rankGain: number;
|
||||
rankLoss: number;
|
||||
hpLoss: number;
|
||||
hpLost: number;
|
||||
|
||||
// Action Category. Current categories are stealth and kill
|
||||
isStealth: boolean;
|
||||
isKill: boolean;
|
||||
|
||||
/**
|
||||
* Number of this contract remaining, and its growth rate
|
||||
* Growth rate is an integer and the count will increase by that integer every "cycle"
|
||||
*/
|
||||
count: number;
|
||||
|
||||
// Weighting of each stat in determining action success rate
|
||||
weights: IStatsMultiplier;
|
||||
// Diminishing returns of stats (stat ^ decay where 0 <= decay <= 1)
|
||||
decays: IStatsMultiplier;
|
||||
teamCount: number;
|
||||
|
||||
getDifficulty(): number;
|
||||
attempt(inst: IBladeburner, person: IPerson): boolean;
|
||||
getActionTimePenalty(): number;
|
||||
getActionTime(inst: IBladeburner, person: IPerson): number;
|
||||
getTeamSuccessBonus(inst: IBladeburner): number;
|
||||
getActionTypeSkillSuccessBonus(inst: IBladeburner): number;
|
||||
getChaosCompetencePenalty(inst: IBladeburner, params: ISuccessChanceParams): number;
|
||||
getChaosDifficultyBonus(inst: IBladeburner): number;
|
||||
getEstSuccessChance(inst: IBladeburner, person: IPerson): [number, number];
|
||||
getSuccessChance(inst: IBladeburner, person: IPerson, params: ISuccessChanceParams): number;
|
||||
getSuccessesNeededForNextLevel(baseSuccessesPerLevel: number): number;
|
||||
setMaxLevel(baseSuccessesPerLevel: number): void;
|
||||
toJSON(): IReviverValue;
|
||||
}
|
@ -1,4 +0,0 @@
|
||||
export interface IActionIdentifier {
|
||||
name: string;
|
||||
type: number;
|
||||
}
|
@ -1,121 +0,0 @@
|
||||
import { IActionIdentifier } from "./IActionIdentifier";
|
||||
import { City } from "./City";
|
||||
import { Skill } from "./Skill";
|
||||
import { IAction } from "./IAction";
|
||||
import { IPlayer } from "../PersonObjects/IPlayer";
|
||||
import { IPerson } from "../PersonObjects/IPerson";
|
||||
import { ITaskTracker } from "../PersonObjects/ITaskTracker";
|
||||
import { IRouter } from "../ui/Router";
|
||||
import { WorkerScript } from "../Netscript/WorkerScript";
|
||||
import { Contract } from "./Contract";
|
||||
import { Operation } from "./Operation";
|
||||
|
||||
export interface IBladeburner {
|
||||
numHosp: number;
|
||||
moneyLost: number;
|
||||
rank: number;
|
||||
maxRank: number;
|
||||
|
||||
skillPoints: number;
|
||||
totalSkillPoints: number;
|
||||
|
||||
teamSize: number;
|
||||
teamLost: number;
|
||||
hpLost: number;
|
||||
|
||||
storedCycles: number;
|
||||
|
||||
randomEventCounter: number;
|
||||
|
||||
actionTimeToComplete: number;
|
||||
actionTimeCurrent: number;
|
||||
actionTimeOverflow: number;
|
||||
|
||||
action: IActionIdentifier;
|
||||
|
||||
cities: Record<string, City>;
|
||||
city: string;
|
||||
skills: Record<string, number>;
|
||||
skillMultipliers: Record<string, number>;
|
||||
staminaBonus: number;
|
||||
maxStamina: number;
|
||||
stamina: number;
|
||||
contracts: Record<string, Contract>;
|
||||
operations: Record<string, Operation>;
|
||||
blackops: Record<string, boolean>;
|
||||
logging: {
|
||||
general: boolean;
|
||||
contracts: boolean;
|
||||
ops: boolean;
|
||||
blackops: boolean;
|
||||
events: boolean;
|
||||
};
|
||||
automateEnabled: boolean;
|
||||
automateActionHigh: IActionIdentifier;
|
||||
automateThreshHigh: number;
|
||||
automateActionLow: IActionIdentifier;
|
||||
automateThreshLow: number;
|
||||
consoleHistory: string[];
|
||||
consoleLogs: string[];
|
||||
|
||||
getCurrentCity(): City;
|
||||
calculateStaminaPenalty(): number;
|
||||
startAction(player: IPlayer, action: IActionIdentifier): void;
|
||||
upgradeSkill(skill: Skill): void;
|
||||
executeConsoleCommands(player: IPlayer, command: string): void;
|
||||
postToConsole(input: string, saveToLogs?: boolean): void;
|
||||
log(input: string): void;
|
||||
resetAction(): void;
|
||||
clearConsole(): void;
|
||||
|
||||
prestige(): void;
|
||||
storeCycles(numCycles?: number): void;
|
||||
getTypeAndNameFromActionId(actionId: IActionIdentifier): {
|
||||
type: string;
|
||||
name: string;
|
||||
};
|
||||
getContractNamesNetscriptFn(): string[];
|
||||
getOperationNamesNetscriptFn(): string[];
|
||||
getBlackOpNamesNetscriptFn(): string[];
|
||||
getGeneralActionNamesNetscriptFn(): string[];
|
||||
getSkillNamesNetscriptFn(): string[];
|
||||
startActionNetscriptFn(player: IPlayer, type: string, name: string, workerScript: WorkerScript): boolean;
|
||||
getActionTimeNetscriptFn(person: IPerson, type: string, name: string): number | string;
|
||||
getActionEstimatedSuccessChanceNetscriptFn(person: IPerson, type: string, name: string): [number, number] | string;
|
||||
getActionCountRemainingNetscriptFn(type: string, name: string, workerScript: WorkerScript): number;
|
||||
getSkillLevelNetscriptFn(skillName: string, workerScript: WorkerScript): number;
|
||||
getSkillUpgradeCostNetscriptFn(skillName: string, count: number, workerScript: WorkerScript): number;
|
||||
upgradeSkillNetscriptFn(skillName: string, count: number, workerScript: WorkerScript): boolean;
|
||||
getTeamSizeNetscriptFn(type: string, name: string, workerScript: WorkerScript): number;
|
||||
setTeamSizeNetscriptFn(type: string, name: string, size: number, workerScript: WorkerScript): number;
|
||||
joinBladeburnerFactionNetscriptFn(workerScript: WorkerScript): boolean;
|
||||
getActionIdFromTypeAndName(type: string, name: string): IActionIdentifier | null;
|
||||
executeStartConsoleCommand(player: IPlayer, args: string[]): void;
|
||||
executeSkillConsoleCommand(args: string[]): void;
|
||||
executeLogConsoleCommand(args: string[]): void;
|
||||
executeHelpConsoleCommand(args: string[]): void;
|
||||
executeAutomateConsoleCommand(args: string[]): void;
|
||||
parseCommandArguments(command: string): string[];
|
||||
executeConsoleCommand(player: IPlayer, command: string): void;
|
||||
triggerMigration(sourceCityName: string): void;
|
||||
triggerPotentialMigration(sourceCityName: string, chance: number): void;
|
||||
randomEvent(): void;
|
||||
getDiplomacyEffectiveness(player: IPlayer): number;
|
||||
getRecruitmentSuccessChance(player: IPerson): number;
|
||||
getRecruitmentTime(player: IPerson): number;
|
||||
resetSkillMultipliers(): void;
|
||||
updateSkillMultipliers(): void;
|
||||
completeOperation(success: boolean, player: IPlayer): void;
|
||||
getActionObject(actionId: IActionIdentifier): IAction | null;
|
||||
completeContract(success: boolean, actionIdent: IActionIdentifier): void;
|
||||
completeAction(player: IPlayer, person: IPerson, actionIdent: IActionIdentifier, isPlayer?: boolean): ITaskTracker;
|
||||
infiltrateSynthoidCommunities(p: IPlayer): void;
|
||||
changeRank(player: IPlayer, change: number): void;
|
||||
processAction(router: IRouter, player: IPlayer, seconds: number): void;
|
||||
calculateStaminaGainPerSecond(player: IPlayer): number;
|
||||
calculateMaxStamina(player: IPlayer): void;
|
||||
create(): void;
|
||||
process(router: IRouter, player: IPlayer): void;
|
||||
getActionStats(action: IAction, person: IPerson, success: boolean): ITaskTracker;
|
||||
sleeveSupport(joining: boolean): void;
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
import { IBladeburner } from "./IBladeburner";
|
||||
import { Bladeburner } from "./Bladeburner";
|
||||
import { BladeburnerConstants } from "./data/Constants";
|
||||
import { Action, IActionParams } from "./Action";
|
||||
import { Generic_fromJSON, Generic_toJSON, IReviverValue, Reviver } from "../utils/JSONReviver";
|
||||
@ -19,7 +19,7 @@ export class Operation extends Action {
|
||||
}
|
||||
|
||||
// For actions that have teams. To be implemented by subtypes.
|
||||
getTeamSuccessBonus(inst: IBladeburner): number {
|
||||
getTeamSuccessBonus(inst: Bladeburner): number {
|
||||
if (this.teamCount && this.teamCount > 0) {
|
||||
this.teamCount = Math.min(this.teamCount, inst.teamSize);
|
||||
const teamMultiplier = Math.pow(this.teamCount, 0.05);
|
||||
@ -29,11 +29,11 @@ export class Operation extends Action {
|
||||
return 1;
|
||||
}
|
||||
|
||||
getActionTypeSkillSuccessBonus(inst: IBladeburner): number {
|
||||
getActionTypeSkillSuccessBonus(inst: Bladeburner): number {
|
||||
return inst.skillMultipliers.successChanceOperation;
|
||||
}
|
||||
|
||||
getChaosDifficultyBonus(inst: IBladeburner /*, params: ISuccessChanceParams*/): number {
|
||||
getChaosDifficultyBonus(inst: Bladeburner /*, params: ISuccessChanceParams*/): number {
|
||||
const city = inst.getCurrentCity();
|
||||
if (city.chaos > BladeburnerConstants.ChaosThreshold) {
|
||||
const diff = 1 + (city.chaos - BladeburnerConstants.ChaosThreshold);
|
||||
|
@ -1,33 +1,5 @@
|
||||
import { CityName } from "./../../Locations/data/CityNames";
|
||||
export const BladeburnerConstants: {
|
||||
CityNames: string[];
|
||||
CyclesPerSecond: number;
|
||||
StaminaGainPerSecond: number;
|
||||
BaseStaminaLoss: number;
|
||||
MaxStaminaToGainFactor: number;
|
||||
DifficultyToTimeFactor: number;
|
||||
DiffMultExponentialFactor: number;
|
||||
DiffMultLinearFactor: number;
|
||||
EffAgiLinearFactor: number;
|
||||
EffDexLinearFactor: number;
|
||||
EffAgiExponentialFactor: number;
|
||||
EffDexExponentialFactor: number;
|
||||
BaseRecruitmentTimeNeeded: number;
|
||||
PopulationThreshold: number;
|
||||
PopulationExponent: number;
|
||||
ChaosThreshold: number;
|
||||
BaseStatGain: number;
|
||||
BaseIntGain: number;
|
||||
ActionCountGrowthPeriod: number;
|
||||
RankToFactionRepFactor: number;
|
||||
RankNeededForFaction: number;
|
||||
ContractSuccessesPerLevel: number;
|
||||
OperationSuccessesPerLevel: number;
|
||||
RanksPerSkillPoint: number;
|
||||
ContractBaseMoneyGain: number;
|
||||
HrcHpGain: number;
|
||||
HrcStaminaGain: number;
|
||||
} = {
|
||||
export const BladeburnerConstants = {
|
||||
CityNames: [
|
||||
CityName.Aevum,
|
||||
CityName.Chongqing,
|
||||
|
@ -1,19 +1,4 @@
|
||||
export const SkillNames: {
|
||||
BladesIntuition: string;
|
||||
Cloak: string;
|
||||
Marksman: string;
|
||||
WeaponProficiency: string;
|
||||
ShortCircuit: string;
|
||||
DigitalObserver: string;
|
||||
Tracer: string;
|
||||
Overclock: string;
|
||||
Reaper: string;
|
||||
EvasiveSystem: string;
|
||||
Datamancer: string;
|
||||
CybersEdge: string;
|
||||
HandsOfMidas: string;
|
||||
Hyperdrive: string;
|
||||
} = {
|
||||
export const SkillNames = {
|
||||
BladesIntuition: "Blade's Intuition",
|
||||
Cloak: "Cloak",
|
||||
Marksman: "Marksman",
|
||||
|
@ -1,8 +1,7 @@
|
||||
import React from "react";
|
||||
import { IAction } from "../IAction";
|
||||
import { IBladeburner } from "../IBladeburner";
|
||||
import { Action } from "../Action";
|
||||
import { Bladeburner } from "../Bladeburner";
|
||||
import { BladeburnerConstants } from "../data/Constants";
|
||||
import { use } from "../../ui/Context";
|
||||
|
||||
import Typography from "@mui/material/Typography";
|
||||
import Tooltip from "@mui/material/Tooltip";
|
||||
@ -12,29 +11,27 @@ import ArrowDropUpIcon from "@mui/icons-material/ArrowDropUp";
|
||||
import ArrowDropDownIcon from "@mui/icons-material/ArrowDropDown";
|
||||
|
||||
interface IProps {
|
||||
action: IAction;
|
||||
action: Action;
|
||||
isActive: boolean;
|
||||
bladeburner: IBladeburner;
|
||||
bladeburner: Bladeburner;
|
||||
rerender: () => void;
|
||||
}
|
||||
|
||||
export function ActionLevel({ action, isActive, bladeburner, rerender }: IProps): React.ReactElement {
|
||||
const player = use.Player();
|
||||
|
||||
const canIncrease = action.level < action.maxLevel;
|
||||
const canDecrease = action.level > 1;
|
||||
|
||||
function increaseLevel(): void {
|
||||
if (!canIncrease) return;
|
||||
++action.level;
|
||||
if (isActive) bladeburner.startAction(player, bladeburner.action);
|
||||
if (isActive) bladeburner.startAction(bladeburner.action);
|
||||
rerender();
|
||||
}
|
||||
|
||||
function decreaseLevel(): void {
|
||||
if (!canDecrease) return;
|
||||
--action.level;
|
||||
if (isActive) bladeburner.startAction(player, bladeburner.action);
|
||||
if (isActive) bladeburner.startAction(bladeburner.action);
|
||||
rerender();
|
||||
}
|
||||
|
||||
|
@ -4,16 +4,14 @@ import { ContractPage } from "./ContractPage";
|
||||
import { OperationPage } from "./OperationPage";
|
||||
import { BlackOpPage } from "./BlackOpPage";
|
||||
import { SkillPage } from "./SkillPage";
|
||||
import { IBladeburner } from "../IBladeburner";
|
||||
import { IPlayer } from "../../PersonObjects/IPlayer";
|
||||
import { Bladeburner } from "../Bladeburner";
|
||||
|
||||
import Tabs from "@mui/material/Tabs";
|
||||
import Tab from "@mui/material/Tab";
|
||||
import Box from "@mui/material/Box";
|
||||
|
||||
interface IProps {
|
||||
bladeburner: IBladeburner;
|
||||
player: IPlayer;
|
||||
bladeburner: Bladeburner;
|
||||
}
|
||||
|
||||
export function AllPages(props: IProps): React.ReactElement {
|
||||
@ -33,10 +31,10 @@ export function AllPages(props: IProps): React.ReactElement {
|
||||
<Tab label="Skills" />
|
||||
</Tabs>
|
||||
<Box sx={{ p: 1 }}>
|
||||
{value === 0 && <GeneralActionPage bladeburner={props.bladeburner} player={props.player} />}
|
||||
{value === 1 && <ContractPage bladeburner={props.bladeburner} player={props.player} />}
|
||||
{value === 2 && <OperationPage bladeburner={props.bladeburner} player={props.player} />}
|
||||
{value === 3 && <BlackOpPage bladeburner={props.bladeburner} player={props.player} />}
|
||||
{value === 0 && <GeneralActionPage bladeburner={props.bladeburner} />}
|
||||
{value === 1 && <ContractPage bladeburner={props.bladeburner} />}
|
||||
{value === 2 && <OperationPage bladeburner={props.bladeburner} />}
|
||||
{value === 3 && <BlackOpPage bladeburner={props.bladeburner} />}
|
||||
{value === 4 && <SkillPage bladeburner={props.bladeburner} />}
|
||||
</Box>
|
||||
</>
|
||||
|
@ -1,12 +1,12 @@
|
||||
import React from "react";
|
||||
import { IAction } from "../IAction";
|
||||
import { Action } from "../Action";
|
||||
import Typography from "@mui/material/Typography";
|
||||
import Tooltip from "@mui/material/Tooltip";
|
||||
import Box from "@mui/material/Box";
|
||||
import Switch from "@mui/material/Switch";
|
||||
|
||||
interface IProps {
|
||||
action: IAction;
|
||||
action: Action;
|
||||
rerender: () => void;
|
||||
}
|
||||
|
||||
|
@ -3,10 +3,10 @@ import { formatNumber, convertTimeMsToTimeElapsedString } from "../../utils/Stri
|
||||
import { ActionTypes } from "../data/ActionTypes";
|
||||
import { createProgressBarText } from "../../utils/helpers/createProgressBarText";
|
||||
import { TeamSizeButton } from "./TeamSizeButton";
|
||||
import { IBladeburner } from "../IBladeburner";
|
||||
import { Bladeburner } from "../Bladeburner";
|
||||
import { BlackOperation } from "../BlackOperation";
|
||||
import { BlackOperations } from "../data/BlackOperations";
|
||||
import { IPlayer } from "../../PersonObjects/IPlayer";
|
||||
import { Player } from "../../Player";
|
||||
import { CopyableText } from "../../ui/React/CopyableText";
|
||||
import { SuccessChance } from "./SuccessChance";
|
||||
import { StartButton } from "./StartButton";
|
||||
@ -15,8 +15,7 @@ import Typography from "@mui/material/Typography";
|
||||
import Paper from "@mui/material/Paper";
|
||||
|
||||
interface IProps {
|
||||
bladeburner: IBladeburner;
|
||||
player: IPlayer;
|
||||
bladeburner: Bladeburner;
|
||||
action: BlackOperation;
|
||||
}
|
||||
|
||||
@ -37,7 +36,7 @@ export function BlackOpElem(props: IProps): React.ReactElement {
|
||||
const isActive =
|
||||
props.bladeburner.action.type === ActionTypes["BlackOperation"] &&
|
||||
props.action.name === props.bladeburner.action.name;
|
||||
const actionTime = props.action.getActionTime(props.bladeburner, props.player);
|
||||
const actionTime = props.action.getActionTime(props.bladeburner, Player);
|
||||
const hasReqdRank = props.bladeburner.rank >= props.action.reqdRank;
|
||||
const computedActionTimeCurrent = Math.min(
|
||||
props.bladeburner.actionTimeCurrent + props.bladeburner.actionTimeOverflow,
|
||||
|
@ -2,12 +2,10 @@ import React from "react";
|
||||
import { BlackOperations } from "../BlackOperations";
|
||||
import { BlackOperation } from "../BlackOperation";
|
||||
import { BlackOpElem } from "./BlackOpElem";
|
||||
import { IBladeburner } from "../IBladeburner";
|
||||
import { IPlayer } from "../../PersonObjects/IPlayer";
|
||||
import { Bladeburner } from "../Bladeburner";
|
||||
|
||||
interface IProps {
|
||||
bladeburner: IBladeburner;
|
||||
player: IPlayer;
|
||||
bladeburner: Bladeburner;
|
||||
}
|
||||
|
||||
export function BlackOpList(props: IProps): React.ReactElement {
|
||||
@ -35,7 +33,7 @@ export function BlackOpList(props: IProps): React.ReactElement {
|
||||
return (
|
||||
<>
|
||||
{blackops.map((blackop: BlackOperation) => (
|
||||
<BlackOpElem key={blackop.name} bladeburner={props.bladeburner} action={blackop} player={props.player} />
|
||||
<BlackOpElem key={blackop.name} bladeburner={props.bladeburner} action={blackop} />
|
||||
))}
|
||||
</>
|
||||
);
|
||||
|
@ -1,21 +1,18 @@
|
||||
import * as React from "react";
|
||||
import { BlackOpList } from "./BlackOpList";
|
||||
import { IBladeburner } from "../IBladeburner";
|
||||
import { IPlayer } from "../../PersonObjects/IPlayer";
|
||||
import { Bladeburner } from "../Bladeburner";
|
||||
import Typography from "@mui/material/Typography";
|
||||
import { FactionNames } from "../../Faction/data/FactionNames";
|
||||
import { use } from "../../ui/Context";
|
||||
import { Router } from "../../ui/GameRoot";
|
||||
import { BlackOperationNames } from "../data/BlackOperationNames";
|
||||
import { Button } from "@mui/material";
|
||||
import { CorruptableText } from "../../ui/React/CorruptableText";
|
||||
|
||||
interface IProps {
|
||||
bladeburner: IBladeburner;
|
||||
player: IPlayer;
|
||||
bladeburner: Bladeburner;
|
||||
}
|
||||
|
||||
export function BlackOpPage(props: IProps): React.ReactElement {
|
||||
const router = use.Router();
|
||||
return (
|
||||
<>
|
||||
<Typography>
|
||||
@ -33,11 +30,11 @@ export function BlackOpPage(props: IProps): React.ReactElement {
|
||||
losses.
|
||||
</Typography>
|
||||
{props.bladeburner.blackops[BlackOperationNames.OperationDaedalus] ? (
|
||||
<Button sx={{ my: 1, p: 1 }} onClick={() => router.toBitVerse(false, false)}>
|
||||
<Button sx={{ my: 1, p: 1 }} onClick={() => Router.toBitVerse(false, false)}>
|
||||
<CorruptableText content="Destroy w0rld_d34mon"></CorruptableText>
|
||||
</Button>
|
||||
) : (
|
||||
<BlackOpList bladeburner={props.bladeburner} player={props.player} />
|
||||
<BlackOpList bladeburner={props.bladeburner} />
|
||||
)}
|
||||
</>
|
||||
);
|
||||
|
@ -1,11 +1,10 @@
|
||||
import React from "react";
|
||||
import { FactionNames } from "../../Faction/data/FactionNames";
|
||||
import { use } from "../../ui/Context";
|
||||
import { Router } from "../../ui/GameRoot";
|
||||
import { CinematicText } from "../../ui/React/CinematicText";
|
||||
import { dialogBoxCreate } from "../../ui/React/DialogBox";
|
||||
|
||||
export function BladeburnerCinematic(): React.ReactElement {
|
||||
const router = use.Router();
|
||||
return (
|
||||
<CinematicText
|
||||
lines={[
|
||||
@ -32,7 +31,7 @@ export function BladeburnerCinematic(): React.ReactElement {
|
||||
"investigating and dealing with Synthoid threats.",
|
||||
]}
|
||||
onDone={() => {
|
||||
router.toTerminal();
|
||||
Router.toTerminal();
|
||||
dialogBoxCreate(
|
||||
`Visit the National Security Agency (NSA) to apply for their ${FactionNames.Bladeburners} ` +
|
||||
"division! You will need 100 of each combat stat before doing this.",
|
||||
|
@ -3,12 +3,10 @@ import { Stats } from "./Stats";
|
||||
import { Console } from "./Console";
|
||||
import { AllPages } from "./AllPages";
|
||||
|
||||
import { use } from "../../ui/Context";
|
||||
import { Player } from "../../Player";
|
||||
import Box from "@mui/material/Box";
|
||||
|
||||
export function BladeburnerRoot(): React.ReactElement {
|
||||
const player = use.Player();
|
||||
const router = use.Router();
|
||||
const setRerender = useState(false)[1];
|
||||
function rerender(): void {
|
||||
setRerender((old) => !old);
|
||||
@ -19,16 +17,16 @@ export function BladeburnerRoot(): React.ReactElement {
|
||||
return () => clearInterval(id);
|
||||
}, []);
|
||||
|
||||
const bladeburner = player.bladeburner;
|
||||
if (bladeburner === null) return <></>;
|
||||
const bladeburner = Player.bladeburner;
|
||||
if (!bladeburner) return <></>;
|
||||
return (
|
||||
<Box display="flex" flexDirection="column">
|
||||
<Box sx={{ display: "grid", gridTemplateColumns: "4fr 8fr", p: 1 }}>
|
||||
<Stats bladeburner={bladeburner} player={player} router={router} />
|
||||
<Console bladeburner={bladeburner} player={player} />
|
||||
<Stats bladeburner={bladeburner} />
|
||||
<Console bladeburner={bladeburner} />
|
||||
</Box>
|
||||
|
||||
<AllPages bladeburner={bladeburner} player={player} />
|
||||
<AllPages bladeburner={bladeburner} />
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
|
@ -1,8 +1,7 @@
|
||||
import React, { useState, useRef, useEffect } from "react";
|
||||
import { IBladeburner } from "../IBladeburner";
|
||||
import { Bladeburner } from "../Bladeburner";
|
||||
import { KEY } from "../../utils/helpers/keyCodes";
|
||||
|
||||
import { IPlayer } from "../../PersonObjects/IPlayer";
|
||||
import Paper from "@mui/material/Paper";
|
||||
import List from "@mui/material/List";
|
||||
import ListItem from "@mui/material/ListItem";
|
||||
@ -49,8 +48,7 @@ function Line(props: ILineProps): React.ReactElement {
|
||||
}
|
||||
|
||||
interface IProps {
|
||||
bladeburner: IBladeburner;
|
||||
player: IPlayer;
|
||||
bladeburner: Bladeburner;
|
||||
}
|
||||
|
||||
export function Console(props: IProps): React.ReactElement {
|
||||
@ -81,7 +79,7 @@ export function Console(props: IProps): React.ReactElement {
|
||||
event.preventDefault();
|
||||
if (command.length > 0) {
|
||||
props.bladeburner.postToConsole("> " + command);
|
||||
props.bladeburner.executeConsoleCommands(props.player, command);
|
||||
props.bladeburner.executeConsoleCommands(command);
|
||||
setConsoleHistoryIndex(props.bladeburner.consoleHistory.length);
|
||||
setCommand("");
|
||||
}
|
||||
|
@ -3,9 +3,9 @@ import { ActionTypes } from "../data/ActionTypes";
|
||||
import { createProgressBarText } from "../../utils/helpers/createProgressBarText";
|
||||
import { formatNumber, convertTimeMsToTimeElapsedString } from "../../utils/StringHelperFunctions";
|
||||
import { Contracts } from "../data/Contracts";
|
||||
import { IBladeburner } from "../IBladeburner";
|
||||
import { IAction } from "../IAction";
|
||||
import { IPlayer } from "../../PersonObjects/IPlayer";
|
||||
import { Bladeburner } from "../Bladeburner";
|
||||
import { Action } from "../Action";
|
||||
import { Player } from "../../Player";
|
||||
import { SuccessChance } from "./SuccessChance";
|
||||
import { CopyableText } from "../../ui/React/CopyableText";
|
||||
import { ActionLevel } from "./ActionLevel";
|
||||
@ -16,9 +16,8 @@ import Typography from "@mui/material/Typography";
|
||||
import Paper from "@mui/material/Paper";
|
||||
|
||||
interface IProps {
|
||||
bladeburner: IBladeburner;
|
||||
player: IPlayer;
|
||||
action: IAction;
|
||||
bladeburner: Bladeburner;
|
||||
action: Action;
|
||||
}
|
||||
|
||||
export function ContractElem(props: IProps): React.ReactElement {
|
||||
@ -32,7 +31,7 @@ export function ContractElem(props: IProps): React.ReactElement {
|
||||
props.bladeburner.actionTimeCurrent + props.bladeburner.actionTimeOverflow,
|
||||
props.bladeburner.actionTimeToComplete,
|
||||
);
|
||||
const actionTime = props.action.getActionTime(props.bladeburner, props.player);
|
||||
const actionTime = props.action.getActionTime(props.bladeburner, Player);
|
||||
|
||||
const actionData = Contracts[props.action.name];
|
||||
if (actionData === undefined) {
|
||||
|
@ -1,11 +1,9 @@
|
||||
import React from "react";
|
||||
import { ContractElem } from "./ContractElem";
|
||||
import { IBladeburner } from "../IBladeburner";
|
||||
import { IPlayer } from "../../PersonObjects/IPlayer";
|
||||
import { Bladeburner } from "../Bladeburner";
|
||||
|
||||
interface IProps {
|
||||
bladeburner: IBladeburner;
|
||||
player: IPlayer;
|
||||
bladeburner: Bladeburner;
|
||||
}
|
||||
|
||||
export function ContractList(props: IProps): React.ReactElement {
|
||||
@ -14,7 +12,7 @@ export function ContractList(props: IProps): React.ReactElement {
|
||||
return (
|
||||
<>
|
||||
{names.map((name: string) => (
|
||||
<ContractElem key={name} bladeburner={props.bladeburner} action={contracts[name]} player={props.player} />
|
||||
<ContractElem key={name} bladeburner={props.bladeburner} action={contracts[name]} />
|
||||
))}
|
||||
</>
|
||||
);
|
||||
|
@ -1,12 +1,10 @@
|
||||
import * as React from "react";
|
||||
import { ContractList } from "./ContractList";
|
||||
import { IBladeburner } from "../IBladeburner";
|
||||
import { IPlayer } from "../../PersonObjects/IPlayer";
|
||||
import { Bladeburner } from "../Bladeburner";
|
||||
import Typography from "@mui/material/Typography";
|
||||
|
||||
interface IProps {
|
||||
bladeburner: IBladeburner;
|
||||
player: IPlayer;
|
||||
bladeburner: Bladeburner;
|
||||
}
|
||||
|
||||
export function ContractPage(props: IProps): React.ReactElement {
|
||||
@ -20,7 +18,7 @@ export function ContractPage(props: IProps): React.ReactElement {
|
||||
You can unlock higher-level contracts by successfully completing them. Higher-level contracts are more
|
||||
difficult, but grant more rank, experience, and money.
|
||||
</Typography>
|
||||
<ContractList bladeburner={props.bladeburner} player={props.player} />
|
||||
<ContractList bladeburner={props.bladeburner} />
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
@ -2,10 +2,10 @@ import React, { useState } from "react";
|
||||
import { ActionTypes } from "../data/ActionTypes";
|
||||
import { createProgressBarText } from "../../utils/helpers/createProgressBarText";
|
||||
import { formatNumber, convertTimeMsToTimeElapsedString } from "../../utils/StringHelperFunctions";
|
||||
import { IBladeburner } from "../IBladeburner";
|
||||
import { IAction } from "../IAction";
|
||||
import { Bladeburner } from "../Bladeburner";
|
||||
import { Action } from "../Action";
|
||||
import { GeneralActions } from "../data/GeneralActions";
|
||||
import { IPlayer } from "../../PersonObjects/IPlayer";
|
||||
import { Player } from "../../Player";
|
||||
import { CopyableText } from "../../ui/React/CopyableText";
|
||||
|
||||
import { StartButton } from "./StartButton";
|
||||
@ -15,9 +15,8 @@ import Box from "@mui/material/Box";
|
||||
import Paper from "@mui/material/Paper";
|
||||
|
||||
interface IProps {
|
||||
bladeburner: IBladeburner;
|
||||
player: IPlayer;
|
||||
action: IAction;
|
||||
bladeburner: Bladeburner;
|
||||
action: Action;
|
||||
}
|
||||
|
||||
export function GeneralActionElem(props: IProps): React.ReactElement {
|
||||
@ -40,13 +39,13 @@ export function GeneralActionElem(props: IProps): React.ReactElement {
|
||||
case "Incite Violence":
|
||||
return 60;
|
||||
case "Recruitment":
|
||||
return props.bladeburner.getRecruitmentTime(props.player);
|
||||
return props.bladeburner.getRecruitmentTime(Player);
|
||||
}
|
||||
return -1; // dead code
|
||||
})();
|
||||
const successChance =
|
||||
props.action.name === "Recruitment"
|
||||
? Math.max(0, Math.min(props.bladeburner.getRecruitmentSuccessChance(props.player), 1))
|
||||
? Math.max(0, Math.min(props.bladeburner.getRecruitmentSuccessChance(Player), 1))
|
||||
: -1;
|
||||
|
||||
const actionData = GeneralActions[props.action.name];
|
||||
|
@ -2,12 +2,10 @@ import React from "react";
|
||||
import { GeneralActionElem } from "./GeneralActionElem";
|
||||
import { Action } from "../Action";
|
||||
import { GeneralActions } from "../GeneralActions";
|
||||
import { IBladeburner } from "../IBladeburner";
|
||||
import { IPlayer } from "../../PersonObjects/IPlayer";
|
||||
import { Bladeburner } from "../Bladeburner";
|
||||
|
||||
interface IProps {
|
||||
bladeburner: IBladeburner;
|
||||
player: IPlayer;
|
||||
bladeburner: Bladeburner;
|
||||
}
|
||||
|
||||
export function GeneralActionList(props: IProps): React.ReactElement {
|
||||
@ -20,7 +18,7 @@ export function GeneralActionList(props: IProps): React.ReactElement {
|
||||
return (
|
||||
<>
|
||||
{actions.map((action: Action) => (
|
||||
<GeneralActionElem key={action.name} bladeburner={props.bladeburner} action={action} player={props.player} />
|
||||
<GeneralActionElem key={action.name} bladeburner={props.bladeburner} action={action} />
|
||||
))}
|
||||
</>
|
||||
);
|
||||
|
@ -1,19 +1,17 @@
|
||||
import * as React from "react";
|
||||
import { GeneralActionList } from "./GeneralActionList";
|
||||
import { IBladeburner } from "../IBladeburner";
|
||||
import { IPlayer } from "../../PersonObjects/IPlayer";
|
||||
import { Bladeburner } from "../Bladeburner";
|
||||
import Typography from "@mui/material/Typography";
|
||||
|
||||
interface IProps {
|
||||
bladeburner: IBladeburner;
|
||||
player: IPlayer;
|
||||
bladeburner: Bladeburner;
|
||||
}
|
||||
|
||||
export function GeneralActionPage(props: IProps): React.ReactElement {
|
||||
return (
|
||||
<>
|
||||
<Typography>These are generic actions that will assist you in your Bladeburner duties.</Typography>
|
||||
<GeneralActionList bladeburner={props.bladeburner} player={props.player} />
|
||||
<GeneralActionList bladeburner={props.bladeburner} />
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
@ -7,18 +7,17 @@ import { ActionLevel } from "./ActionLevel";
|
||||
import { Autolevel } from "./Autolevel";
|
||||
import { StartButton } from "./StartButton";
|
||||
import { TeamSizeButton } from "./TeamSizeButton";
|
||||
import { IBladeburner } from "../IBladeburner";
|
||||
import { Bladeburner } from "../Bladeburner";
|
||||
import { Operation } from "../Operation";
|
||||
import { Operations } from "../data/Operations";
|
||||
import { IPlayer } from "../../PersonObjects/IPlayer";
|
||||
import { Player } from "../../Player";
|
||||
import { CopyableText } from "../../ui/React/CopyableText";
|
||||
|
||||
import Typography from "@mui/material/Typography";
|
||||
import Paper from "@mui/material/Paper";
|
||||
|
||||
interface IProps {
|
||||
bladeburner: IBladeburner;
|
||||
player: IPlayer;
|
||||
bladeburner: Bladeburner;
|
||||
action: Operation;
|
||||
}
|
||||
|
||||
@ -33,7 +32,7 @@ export function OperationElem(props: IProps): React.ReactElement {
|
||||
props.bladeburner.actionTimeCurrent + props.bladeburner.actionTimeOverflow,
|
||||
props.bladeburner.actionTimeToComplete,
|
||||
);
|
||||
const actionTime = props.action.getActionTime(props.bladeburner, props.player);
|
||||
const actionTime = props.action.getActionTime(props.bladeburner, Player);
|
||||
|
||||
const actionData = Operations[props.action.name];
|
||||
if (actionData === undefined) {
|
||||
|
@ -1,11 +1,9 @@
|
||||
import React from "react";
|
||||
import { OperationElem } from "./OperationElem";
|
||||
import { IBladeburner } from "../IBladeburner";
|
||||
import { IPlayer } from "../../PersonObjects/IPlayer";
|
||||
import { Bladeburner } from "../Bladeburner";
|
||||
|
||||
interface IProps {
|
||||
bladeburner: IBladeburner;
|
||||
player: IPlayer;
|
||||
bladeburner: Bladeburner;
|
||||
}
|
||||
|
||||
export function OperationList(props: IProps): React.ReactElement {
|
||||
@ -14,7 +12,7 @@ export function OperationList(props: IProps): React.ReactElement {
|
||||
return (
|
||||
<>
|
||||
{names.map((name: string) => (
|
||||
<OperationElem key={name} bladeburner={props.bladeburner} action={operations[name]} player={props.player} />
|
||||
<OperationElem key={name} bladeburner={props.bladeburner} action={operations[name]} />
|
||||
))}
|
||||
</>
|
||||
);
|
||||
|
@ -1,12 +1,10 @@
|
||||
import * as React from "react";
|
||||
import { OperationList } from "./OperationList";
|
||||
import { IBladeburner } from "../IBladeburner";
|
||||
import { IPlayer } from "../../PersonObjects/IPlayer";
|
||||
import { Bladeburner } from "../Bladeburner";
|
||||
import Typography from "@mui/material/Typography";
|
||||
|
||||
interface IProps {
|
||||
bladeburner: IBladeburner;
|
||||
player: IPlayer;
|
||||
bladeburner: Bladeburner;
|
||||
}
|
||||
|
||||
export function OperationPage(props: IProps): React.ReactElement {
|
||||
@ -29,7 +27,7 @@ export function OperationPage(props: IProps): React.ReactElement {
|
||||
You can unlock higher-level operations by successfully completing them. Higher-level operations are more
|
||||
difficult, but grant more rank and experience.
|
||||
</Typography>
|
||||
<OperationList bladeburner={props.bladeburner} player={props.player} />
|
||||
<OperationList bladeburner={props.bladeburner} />
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
import React from "react";
|
||||
import { CopyableText } from "../../ui/React/CopyableText";
|
||||
import { formatNumber } from "../../utils/StringHelperFunctions";
|
||||
import { IBladeburner } from "../IBladeburner";
|
||||
import { Bladeburner } from "../Bladeburner";
|
||||
|
||||
import Typography from "@mui/material/Typography";
|
||||
import IconButton from "@mui/material/IconButton";
|
||||
@ -13,7 +13,7 @@ import { Skill } from "../Skill";
|
||||
|
||||
interface IProps {
|
||||
skill: Skill;
|
||||
bladeburner: IBladeburner;
|
||||
bladeburner: Bladeburner;
|
||||
onUpgrade: () => void;
|
||||
}
|
||||
|
||||
|
@ -1,10 +1,10 @@
|
||||
import * as React from "react";
|
||||
import { SkillElem } from "./SkillElem";
|
||||
import { Skills } from "../Skills";
|
||||
import { IBladeburner } from "../IBladeburner";
|
||||
import { Bladeburner } from "../Bladeburner";
|
||||
|
||||
interface IProps {
|
||||
bladeburner: IBladeburner;
|
||||
bladeburner: Bladeburner;
|
||||
onUpgrade: () => void;
|
||||
}
|
||||
|
||||
|
@ -2,10 +2,10 @@ import React, { useState } from "react";
|
||||
import { SkillList } from "./SkillList";
|
||||
import { BladeburnerConstants } from "../data/Constants";
|
||||
import { formatNumber } from "../../utils/StringHelperFunctions";
|
||||
import { IBladeburner } from "../IBladeburner";
|
||||
import { Bladeburner } from "../Bladeburner";
|
||||
import Typography from "@mui/material/Typography";
|
||||
interface IProps {
|
||||
bladeburner: IBladeburner;
|
||||
bladeburner: Bladeburner;
|
||||
}
|
||||
|
||||
export function SkillPage(props: IProps): React.ReactElement {
|
||||
|
@ -1,20 +1,20 @@
|
||||
import React from "react";
|
||||
|
||||
import { IBladeburner } from "../IBladeburner";
|
||||
import { Bladeburner } from "../Bladeburner";
|
||||
import { BlackOperation } from "../BlackOperation";
|
||||
import { use } from "../../ui/Context";
|
||||
import { Player } from "../../Player";
|
||||
import Button from "@mui/material/Button";
|
||||
import { AugmentationNames } from "../../Augmentation/data/AugmentationNames";
|
||||
import { ActionIdentifier } from "../ActionIdentifier";
|
||||
|
||||
interface IProps {
|
||||
bladeburner: IBladeburner;
|
||||
bladeburner: Bladeburner;
|
||||
type: number;
|
||||
name: string;
|
||||
rerender: () => void;
|
||||
}
|
||||
export function StartButton(props: IProps): React.ReactElement {
|
||||
const player = use.Player();
|
||||
const action = props.bladeburner.getActionObject({ name: props.name, type: props.type });
|
||||
const action = props.bladeburner.getActionObject(new ActionIdentifier({ name: props.name, type: props.type }));
|
||||
if (action == null) {
|
||||
throw new Error("Failed to get Operation Object for: " + props.name);
|
||||
}
|
||||
@ -33,8 +33,8 @@ export function StartButton(props: IProps): React.ReactElement {
|
||||
if (disabled) return;
|
||||
props.bladeburner.action.type = props.type;
|
||||
props.bladeburner.action.name = props.name;
|
||||
if (!player.hasAugmentation(AugmentationNames.BladesSimulacrum, true)) player.finishWork(true);
|
||||
props.bladeburner.startAction(player, props.bladeburner.action);
|
||||
if (!Player.hasAugmentation(AugmentationNames.BladesSimulacrum, true)) Player.finishWork(true);
|
||||
props.bladeburner.startAction(props.bladeburner.action);
|
||||
props.rerender();
|
||||
}
|
||||
|
||||
|
@ -1,13 +1,13 @@
|
||||
import React, { useState, useEffect } from "react";
|
||||
import { formatNumber, convertTimeMsToTimeElapsedString } from "../../utils/StringHelperFunctions";
|
||||
import { BladeburnerConstants } from "../data/Constants";
|
||||
import { IPlayer } from "../../PersonObjects/IPlayer";
|
||||
import { Player } from "../../Player";
|
||||
import { Money } from "../../ui/React/Money";
|
||||
import { numeralWrapper } from "../../ui/numeralFormat";
|
||||
import { Factions } from "../../Faction/Factions";
|
||||
import { IRouter } from "../../ui/Router";
|
||||
import { Router } from "../../ui/GameRoot";
|
||||
import { joinFaction } from "../../Faction/FactionHelpers";
|
||||
import { IBladeburner } from "../IBladeburner";
|
||||
import { Bladeburner } from "../Bladeburner";
|
||||
|
||||
import { TravelModal } from "./TravelModal";
|
||||
import Typography from "@mui/material/Typography";
|
||||
@ -18,9 +18,7 @@ import Paper from "@mui/material/Paper";
|
||||
import { FactionNames } from "../../Faction/data/FactionNames";
|
||||
|
||||
interface IProps {
|
||||
bladeburner: IBladeburner;
|
||||
router: IRouter;
|
||||
player: IPlayer;
|
||||
bladeburner: Bladeburner;
|
||||
}
|
||||
|
||||
export function Stats(props: IProps): React.ReactElement {
|
||||
@ -40,7 +38,7 @@ export function Stats(props: IProps): React.ReactElement {
|
||||
joinFaction(faction);
|
||||
}
|
||||
|
||||
props.router.toFaction(faction);
|
||||
Router.toFaction(faction);
|
||||
}
|
||||
|
||||
return (
|
||||
@ -170,13 +168,13 @@ export function Stats(props: IProps): React.ReactElement {
|
||||
<Typography>Skill Points: {formatNumber(props.bladeburner.skillPoints, 0)}</Typography>
|
||||
<br />
|
||||
<Typography>
|
||||
Aug. Success Chance mult: {formatNumber(props.player.mults.bladeburner_success_chance * 100, 1)}%
|
||||
Aug. Success Chance mult: {formatNumber(Player.mults.bladeburner_success_chance * 100, 1)}%
|
||||
<br />
|
||||
Aug. Max Stamina mult: {formatNumber(props.player.mults.bladeburner_max_stamina * 100, 1)}%
|
||||
Aug. Max Stamina mult: {formatNumber(Player.mults.bladeburner_max_stamina * 100, 1)}%
|
||||
<br />
|
||||
Aug. Stamina Gain mult: {formatNumber(props.player.mults.bladeburner_stamina_gain * 100, 1)}%
|
||||
Aug. Stamina Gain mult: {formatNumber(Player.mults.bladeburner_stamina_gain * 100, 1)}%
|
||||
<br />
|
||||
Aug. Field Analysis mult: {formatNumber(props.player.mults.bladeburner_analysis * 100, 1)}%
|
||||
Aug. Field Analysis mult: {formatNumber(Player.mults.bladeburner_analysis * 100, 1)}%
|
||||
</Typography>
|
||||
</Box>
|
||||
</Paper>
|
||||
|
@ -2,13 +2,13 @@ import React from "react";
|
||||
import { formatNumber } from "../../utils/StringHelperFunctions";
|
||||
import { StealthIcon } from "./StealthIcon";
|
||||
import { KillIcon } from "./KillIcon";
|
||||
import { IAction } from "../IAction";
|
||||
import { IBladeburner } from "../IBladeburner";
|
||||
import { Action } from "../Action";
|
||||
import { Bladeburner } from "../Bladeburner";
|
||||
import { Player } from "../../Player";
|
||||
|
||||
interface IProps {
|
||||
bladeburner: IBladeburner;
|
||||
action: IAction;
|
||||
bladeburner: Bladeburner;
|
||||
action: Action;
|
||||
}
|
||||
|
||||
export function SuccessChance(props: IProps): React.ReactElement {
|
||||
|
@ -1,12 +1,12 @@
|
||||
import React, { useState } from "react";
|
||||
import { Operation } from "../Operation";
|
||||
import { IBladeburner } from "../IBladeburner";
|
||||
import { Bladeburner } from "../Bladeburner";
|
||||
import { TeamSizeModal } from "./TeamSizeModal";
|
||||
import { formatNumber } from "../../utils/StringHelperFunctions";
|
||||
import Button from "@mui/material/Button";
|
||||
interface IProps {
|
||||
action: Operation;
|
||||
bladeburner: IBladeburner;
|
||||
bladeburner: Bladeburner;
|
||||
}
|
||||
export function TeamSizeButton(props: IProps): React.ReactElement {
|
||||
const [open, setOpen] = useState(false);
|
||||
|
@ -2,13 +2,13 @@ import React, { useState } from "react";
|
||||
import { dialogBoxCreate } from "../../ui/React/DialogBox";
|
||||
import { Modal } from "../../ui/React/Modal";
|
||||
import { Action } from "../Action";
|
||||
import { IBladeburner } from "../IBladeburner";
|
||||
import { Bladeburner } from "../Bladeburner";
|
||||
import Typography from "@mui/material/Typography";
|
||||
import Button from "@mui/material/Button";
|
||||
import TextField from "@mui/material/TextField";
|
||||
|
||||
interface IProps {
|
||||
bladeburner: IBladeburner;
|
||||
bladeburner: Bladeburner;
|
||||
action: Action;
|
||||
open: boolean;
|
||||
onClose: () => void;
|
||||
|
@ -1,5 +1,5 @@
|
||||
import React from "react";
|
||||
import { IBladeburner } from "../IBladeburner";
|
||||
import { Bladeburner } from "../Bladeburner";
|
||||
import { WorldMap } from "../../ui/React/WorldMap";
|
||||
import { Modal } from "../../ui/React/Modal";
|
||||
import { CityName } from "../../Locations/data/CityNames";
|
||||
@ -8,7 +8,7 @@ import Typography from "@mui/material/Typography";
|
||||
import Button from "@mui/material/Button";
|
||||
|
||||
interface IProps {
|
||||
bladeburner: IBladeburner;
|
||||
bladeburner: Bladeburner;
|
||||
open: boolean;
|
||||
onClose: () => void;
|
||||
}
|
||||
|
@ -1,8 +1,8 @@
|
||||
import * as React from "react";
|
||||
|
||||
import { IPlayer } from "../PersonObjects/IPlayer";
|
||||
import { Player } from "../Player";
|
||||
import { Money } from "../ui/React/Money";
|
||||
import { Game, reachedLimit } from "./Game";
|
||||
import { win, reachedLimit } from "./Game";
|
||||
import { Deck } from "./CardDeck/Deck";
|
||||
import { Hand } from "./CardDeck/Hand";
|
||||
import { InputAdornment } from "@mui/material";
|
||||
@ -24,10 +24,6 @@ enum Result {
|
||||
Tie = "Push! (Tie)",
|
||||
}
|
||||
|
||||
type Props = {
|
||||
p: IPlayer;
|
||||
};
|
||||
|
||||
type State = {
|
||||
playerHand: Hand;
|
||||
dealerHand: Hand;
|
||||
@ -40,11 +36,11 @@ type State = {
|
||||
wagerInvalidHelperText: string;
|
||||
};
|
||||
|
||||
export class Blackjack extends Game<Props, State> {
|
||||
export class Blackjack extends React.Component<Record<string, never>, State> {
|
||||
deck: Deck;
|
||||
|
||||
constructor(props: Props) {
|
||||
super(props);
|
||||
constructor() {
|
||||
super({});
|
||||
|
||||
this.deck = new Deck(DECK_COUNT);
|
||||
|
||||
@ -64,20 +60,19 @@ export class Blackjack extends Game<Props, State> {
|
||||
}
|
||||
|
||||
canStartGame = (): boolean => {
|
||||
const { p } = this.props;
|
||||
const { bet } = this.state;
|
||||
|
||||
return p.canAfford(bet);
|
||||
return Player.canAfford(bet);
|
||||
};
|
||||
|
||||
startGame = (): void => {
|
||||
if (!this.canStartGame() || reachedLimit(this.props.p)) {
|
||||
if (!this.canStartGame() || reachedLimit()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Take money from player right away so that player's dont just "leave" to avoid the loss (I mean they could
|
||||
// always reload without saving but w.e) TODO: Save/Restore the RNG state to limit the value of save-scumming.
|
||||
this.props.p.loseMoney(this.state.bet, "casino");
|
||||
win(-this.state.bet);
|
||||
|
||||
const playerHand = new Hand([this.deck.safeDrawCard(), this.deck.safeDrawCard()]);
|
||||
const dealerHand = new Hand([this.deck.safeDrawCard(), this.deck.safeDrawCard()]);
|
||||
@ -230,7 +225,7 @@ export class Blackjack extends Game<Props, State> {
|
||||
: (() => {
|
||||
throw new Error(`Unexpected result: ${result}`);
|
||||
})(); // This can't happen, right?
|
||||
this.win(this.props.p, gains);
|
||||
win(gains);
|
||||
this.setState({
|
||||
gameInProgress: false,
|
||||
result,
|
||||
@ -239,7 +234,6 @@ export class Blackjack extends Game<Props, State> {
|
||||
};
|
||||
|
||||
wagerOnChange = (event: React.ChangeEvent<HTMLInputElement>): void => {
|
||||
const { p } = this.props;
|
||||
const betInput = event.target.value;
|
||||
const wager = Math.round(parseFloat(betInput));
|
||||
if (isNaN(wager)) {
|
||||
@ -263,7 +257,7 @@ export class Blackjack extends Game<Props, State> {
|
||||
wagerInvalid: true,
|
||||
wagerInvalidHelperText: "Exceeds max bet",
|
||||
});
|
||||
} else if (!p.canAfford(wager)) {
|
||||
} else if (!Player.canAfford(wager)) {
|
||||
this.setState({
|
||||
bet: 0,
|
||||
betInput,
|
||||
|
@ -5,7 +5,6 @@
|
||||
*/
|
||||
import React, { useState } from "react";
|
||||
|
||||
import { IPlayer } from "../PersonObjects/IPlayer";
|
||||
import { BadRNG } from "./RNG";
|
||||
import { win, reachedLimit } from "./Game";
|
||||
import { trusted } from "./utils";
|
||||
@ -15,14 +14,10 @@ import TextField from "@mui/material/TextField";
|
||||
import Button from "@mui/material/Button";
|
||||
import Box from "@mui/material/Box";
|
||||
|
||||
type IProps = {
|
||||
p: IPlayer;
|
||||
};
|
||||
|
||||
const minPlay = 0;
|
||||
const maxPlay = 10e3;
|
||||
|
||||
export function CoinFlip(props: IProps): React.ReactElement {
|
||||
export function CoinFlip(): React.ReactElement {
|
||||
const [investment, setInvestment] = useState(1000);
|
||||
const [result, setResult] = useState(<span> </span>);
|
||||
const [status, setStatus] = useState("");
|
||||
@ -43,7 +38,7 @@ export function CoinFlip(props: IProps): React.ReactElement {
|
||||
}
|
||||
|
||||
function play(guess: string): void {
|
||||
if (reachedLimit(props.p)) return;
|
||||
if (reachedLimit()) return;
|
||||
const v = BadRNG.random();
|
||||
let letter: string;
|
||||
if (v < 0.5) {
|
||||
@ -65,11 +60,11 @@ export function CoinFlip(props: IProps): React.ReactElement {
|
||||
|
||||
setTimeout(() => setPlayLock(false), 250);
|
||||
if (correct) {
|
||||
win(props.p, investment);
|
||||
win(investment);
|
||||
} else {
|
||||
win(props.p, -investment);
|
||||
win(-investment);
|
||||
}
|
||||
if (reachedLimit(props.p)) return;
|
||||
if (reachedLimit()) return;
|
||||
}
|
||||
|
||||
return (
|
||||
|
16
src/Casino/Game.ts
Normal file
16
src/Casino/Game.ts
Normal file
@ -0,0 +1,16 @@
|
||||
import { Player } from "../Player";
|
||||
import { dialogBoxCreate } from "../ui/React/DialogBox";
|
||||
|
||||
const gainLimit = 10e9;
|
||||
|
||||
export function win(n: number): void {
|
||||
Player.gainMoney(n, "casino");
|
||||
}
|
||||
|
||||
export function reachedLimit(): boolean {
|
||||
const reached = Player.getCasinoWinnings() > gainLimit;
|
||||
if (reached) {
|
||||
dialogBoxCreate("Alright cheater get out of here. You're not allowed here anymore.");
|
||||
}
|
||||
return reached;
|
||||
}
|
@ -1,31 +0,0 @@
|
||||
import * as React from "react";
|
||||
import { IPlayer } from "../PersonObjects/IPlayer";
|
||||
import { dialogBoxCreate } from "../ui/React/DialogBox";
|
||||
|
||||
const gainLimit = 10e9;
|
||||
|
||||
export function win(p: IPlayer, n: number): void {
|
||||
p.gainMoney(n, "casino");
|
||||
}
|
||||
|
||||
export function reachedLimit(p: IPlayer): boolean {
|
||||
const reached = p.getCasinoWinnings() > gainLimit;
|
||||
if (reached) {
|
||||
dialogBoxCreate(<>Alright cheater get out of here. You're not allowed here anymore.</>);
|
||||
}
|
||||
return reached;
|
||||
}
|
||||
|
||||
export class Game<T, U> extends React.Component<T, U> {
|
||||
win(p: IPlayer, n: number): void {
|
||||
p.gainMoney(n, "casino");
|
||||
}
|
||||
|
||||
reachedLimit(p: IPlayer): boolean {
|
||||
const reached = p.getCasinoWinnings() > gainLimit;
|
||||
if (reached) {
|
||||
dialogBoxCreate(<>Alright cheater get out of here. You're not allowed here anymore.</>);
|
||||
}
|
||||
return reached;
|
||||
}
|
||||
}
|
@ -1,6 +1,5 @@
|
||||
import React, { useState, useEffect } from "react";
|
||||
|
||||
import { IPlayer } from "../PersonObjects/IPlayer";
|
||||
import { Money } from "../ui/React/Money";
|
||||
import { win, reachedLimit } from "./Game";
|
||||
import { WHRNG } from "./RNG";
|
||||
@ -9,10 +8,6 @@ import Typography from "@mui/material/Typography";
|
||||
import Button from "@mui/material/Button";
|
||||
import TextField from "@mui/material/TextField";
|
||||
|
||||
type IProps = {
|
||||
p: IPlayer;
|
||||
};
|
||||
|
||||
const minPlay = 0;
|
||||
const maxPlay = 1e7;
|
||||
|
||||
@ -111,7 +106,7 @@ function Single(s: number): Strategy {
|
||||
};
|
||||
}
|
||||
|
||||
export function Roulette(props: IProps): React.ReactElement {
|
||||
export function Roulette(): React.ReactElement {
|
||||
const [rng] = useState(new WHRNG(new Date().getTime()));
|
||||
const [investment, setInvestment] = useState(1000);
|
||||
const [canPlay, setCanPlay] = useState(true);
|
||||
@ -151,7 +146,7 @@ export function Roulette(props: IProps): React.ReactElement {
|
||||
}
|
||||
|
||||
function play(strategy: Strategy): void {
|
||||
if (reachedLimit(props.p)) return;
|
||||
if (reachedLimit()) return;
|
||||
|
||||
setCanPlay(false);
|
||||
setLock(false);
|
||||
@ -184,14 +179,14 @@ export function Roulette(props: IProps): React.ReactElement {
|
||||
</>
|
||||
);
|
||||
}
|
||||
win(props.p, gain);
|
||||
win(gain);
|
||||
|
||||
setCanPlay(true);
|
||||
setLock(true);
|
||||
setStatus(status);
|
||||
setN(n);
|
||||
|
||||
reachedLimit(props.p);
|
||||
reachedLimit();
|
||||
}, 1600);
|
||||
}
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
import React, { useState, useEffect } from "react";
|
||||
|
||||
import { IPlayer } from "../PersonObjects/IPlayer";
|
||||
import { Player } from "../Player";
|
||||
import { Money } from "../ui/React/Money";
|
||||
import { WHRNG } from "./RNG";
|
||||
import { win, reachedLimit } from "./Game";
|
||||
@ -9,10 +9,6 @@ import Typography from "@mui/material/Typography";
|
||||
import TextField from "@mui/material/TextField";
|
||||
import Button from "@mui/material/Button";
|
||||
|
||||
type IProps = {
|
||||
p: IPlayer;
|
||||
};
|
||||
|
||||
// statically shuffled array of symbols.
|
||||
const symbols = [
|
||||
"D",
|
||||
@ -141,8 +137,8 @@ const payLines = [
|
||||
const minPlay = 0;
|
||||
const maxPlay = 1e6;
|
||||
|
||||
export function SlotMachine(props: IProps): React.ReactElement {
|
||||
const [rng] = useState(new WHRNG(props.p.totalPlaytime));
|
||||
export function SlotMachine(): React.ReactElement {
|
||||
const [rng] = useState(new WHRNG(Player.totalPlaytime));
|
||||
const [index, setIndex] = useState<number[]>([0, 0, 0, 0, 0]);
|
||||
const [locks, setLocks] = useState<number[]>([0, 0, 0, 0, 0]);
|
||||
const [investment, setInvestment] = useState(1000);
|
||||
@ -191,9 +187,9 @@ export function SlotMachine(props: IProps): React.ReactElement {
|
||||
}
|
||||
|
||||
function play(): void {
|
||||
if (reachedLimit(props.p)) return;
|
||||
if (reachedLimit()) return;
|
||||
setStatus("playing");
|
||||
win(props.p, -investment);
|
||||
win(-investment);
|
||||
if (!canPlay) return;
|
||||
unlock();
|
||||
setTimeout(lock, rng.random() * 2000 + 1000);
|
||||
@ -235,7 +231,7 @@ export function SlotMachine(props: IProps): React.ReactElement {
|
||||
if (count < 3) continue;
|
||||
const payout = getPayout(data[0], count - 3);
|
||||
gains += investment * payout;
|
||||
win(props.p, investment * payout);
|
||||
win(investment * payout);
|
||||
}
|
||||
|
||||
setStatus(
|
||||
@ -244,7 +240,7 @@ export function SlotMachine(props: IProps): React.ReactElement {
|
||||
</>,
|
||||
);
|
||||
setCanPlay(true);
|
||||
if (reachedLimit(props.p)) return;
|
||||
if (reachedLimit()) return;
|
||||
}
|
||||
|
||||
function unlock(): void {
|
||||
|
@ -191,7 +191,8 @@ function getRandomFilename(server: BaseServer, reward: ICodingContractReward): s
|
||||
}
|
||||
|
||||
if (reward.name) {
|
||||
contractFn += `-${reward.name.replace(/\s/g, "")}`;
|
||||
// Only alphanumeric characters in the reward name.
|
||||
contractFn += `-${reward.name.replace(/[^a-zA-Z0-9]/g, "")}`;
|
||||
}
|
||||
|
||||
return contractFn;
|
||||
|
@ -29,7 +29,7 @@ export function initCompanies(): void {
|
||||
for (const companyName of Object.keys(Companies)) {
|
||||
const company = Companies[companyName];
|
||||
const oldCompany = oldCompanies[companyName];
|
||||
if (!(oldCompany instanceof Company)) {
|
||||
if (!oldCompany) {
|
||||
// New game, so no OldCompanies data
|
||||
company.favor = 0;
|
||||
} else {
|
||||
|
@ -88,11 +88,7 @@ export class Company {
|
||||
}
|
||||
|
||||
hasPosition(pos: CompanyPosition | string): boolean {
|
||||
if (pos instanceof CompanyPosition) {
|
||||
return this.companyPositions[pos.name] != null;
|
||||
} else {
|
||||
return this.companyPositions[pos] != null;
|
||||
}
|
||||
return this.companyPositions[typeof pos === "string" ? pos : pos.name] != null;
|
||||
}
|
||||
|
||||
hasAgentPositions(): boolean {
|
||||
|
@ -1,6 +1,6 @@
|
||||
import React from "react";
|
||||
import { Company } from "../Company";
|
||||
import { use } from "../../ui/Context";
|
||||
import { Player } from "../../Player";
|
||||
import { Modal } from "../../ui/React/Modal";
|
||||
import Typography from "@mui/material/Typography";
|
||||
import Button from "@mui/material/Button";
|
||||
@ -14,9 +14,8 @@ interface IProps {
|
||||
}
|
||||
|
||||
export function QuitJobModal(props: IProps): React.ReactElement {
|
||||
const player = use.Player();
|
||||
function quit(): void {
|
||||
player.quitJob(props.locName);
|
||||
Player.quitJob(props.locName);
|
||||
props.onQuit();
|
||||
props.onClose();
|
||||
}
|
||||
|
@ -1,9 +1,6 @@
|
||||
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";
|
||||
import { CorporationConstants } from "./data/Constants";
|
||||
@ -18,7 +15,7 @@ import { EmployeePositions } from "./EmployeePositions";
|
||||
import { ResearchMap } from "./ResearchMap";
|
||||
import { isRelevantMaterial } from "./ui/Helpers";
|
||||
|
||||
export function NewIndustry(corporation: ICorporation, industry: string, name: string): void {
|
||||
export function NewIndustry(corporation: Corporation, industry: string, name: string): void {
|
||||
if (corporation.divisions.find(({ type }) => industry == type))
|
||||
throw new Error(`You have already expanded into the ${industry} industry!`);
|
||||
|
||||
@ -48,7 +45,7 @@ export function NewIndustry(corporation: ICorporation, industry: string, name: s
|
||||
}
|
||||
}
|
||||
|
||||
export function NewCity(corporation: ICorporation, division: IIndustry, city: string): void {
|
||||
export function NewCity(corporation: Corporation, division: Industry, city: string): void {
|
||||
if (corporation.funds < CorporationConstants.OfficeInitialCost) {
|
||||
throw new Error("You don't have enough company funds to open a new office!");
|
||||
}
|
||||
@ -62,7 +59,7 @@ export function NewCity(corporation: ICorporation, division: IIndustry, city: st
|
||||
});
|
||||
}
|
||||
|
||||
export function UnlockUpgrade(corporation: ICorporation, upgrade: CorporationUnlockUpgrade): void {
|
||||
export function UnlockUpgrade(corporation: Corporation, upgrade: CorporationUnlockUpgrade): void {
|
||||
if (corporation.funds < upgrade.price) {
|
||||
throw new Error("Insufficient funds");
|
||||
}
|
||||
@ -72,7 +69,7 @@ export function UnlockUpgrade(corporation: ICorporation, upgrade: CorporationUnl
|
||||
corporation.unlock(upgrade);
|
||||
}
|
||||
|
||||
export function LevelUpgrade(corporation: ICorporation, upgrade: CorporationUpgrade): void {
|
||||
export function LevelUpgrade(corporation: Corporation, upgrade: CorporationUpgrade): void {
|
||||
const baseCost = upgrade.basePrice;
|
||||
const priceMult = upgrade.priceMult;
|
||||
const level = corporation.upgrades[upgrade.index];
|
||||
@ -84,7 +81,7 @@ export function LevelUpgrade(corporation: ICorporation, upgrade: CorporationUpgr
|
||||
}
|
||||
}
|
||||
|
||||
export function IssueDividends(corporation: ICorporation, rate: number): void {
|
||||
export function IssueDividends(corporation: Corporation, rate: number): void {
|
||||
if (isNaN(rate) || rate < 0 || rate > CorporationConstants.DividendMaxRate) {
|
||||
throw new Error(`Invalid value. Must be an number between 0 and ${CorporationConstants.DividendMaxRate}`);
|
||||
}
|
||||
@ -253,7 +250,7 @@ export function BuyMaterial(material: Material, amt: number): void {
|
||||
material.buy = amt;
|
||||
}
|
||||
|
||||
export function BulkPurchase(corp: ICorporation, warehouse: Warehouse, material: Material, amt: number): void {
|
||||
export function BulkPurchase(corp: Corporation, warehouse: Warehouse, material: Material, amt: number): void {
|
||||
const matSize = MaterialSizes[material.name];
|
||||
const maxAmount = (warehouse.size - warehouse.sizeUsed) / matSize;
|
||||
if (isNaN(amt) || amt < 0) {
|
||||
@ -271,7 +268,7 @@ export function BulkPurchase(corp: ICorporation, warehouse: Warehouse, material:
|
||||
}
|
||||
}
|
||||
|
||||
export function SellShares(corporation: ICorporation, player: IPlayer, numShares: number): number {
|
||||
export function SellShares(corporation: Corporation, numShares: number): number {
|
||||
if (isNaN(numShares)) throw new Error("Invalid value for number of shares");
|
||||
if (numShares < 0) throw new Error("Invalid value for number of shares");
|
||||
if (numShares > corporation.numShares) throw new Error("You don't have that many shares to sell!");
|
||||
@ -287,20 +284,20 @@ export function SellShares(corporation: ICorporation, player: IPlayer, numShares
|
||||
corporation.sharePrice = newSharePrice;
|
||||
corporation.shareSalesUntilPriceUpdate = newSharesUntilUpdate;
|
||||
corporation.shareSaleCooldown = CorporationConstants.SellSharesCooldown;
|
||||
player.gainMoney(profit, "corporation");
|
||||
Player.gainMoney(profit, "corporation");
|
||||
return profit;
|
||||
}
|
||||
|
||||
export function BuyBackShares(corporation: ICorporation, player: IPlayer, numShares: number): boolean {
|
||||
export function BuyBackShares(corporation: Corporation, numShares: number): boolean {
|
||||
if (isNaN(numShares)) throw new Error("Invalid value for number of shares");
|
||||
if (numShares < 0) throw new Error("Invalid value for number of shares");
|
||||
if (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!");
|
||||
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");
|
||||
Player.loseMoney(numShares * buybackPrice, "corporation");
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -319,7 +316,7 @@ export function AutoAssignJob(office: OfficeSpace, job: string, count: number):
|
||||
return office.autoAssignJob(job, count);
|
||||
}
|
||||
|
||||
export function UpgradeOfficeSize(corp: ICorporation, office: OfficeSpace, size: number): void {
|
||||
export function UpgradeOfficeSize(corp: Corporation, office: OfficeSpace, size: number): void {
|
||||
const initialPriceMult = Math.round(office.size / CorporationConstants.OfficeInitialSize);
|
||||
const costMultiplier = 1.09;
|
||||
// Calculate cost to upgrade size by 15 employees
|
||||
@ -333,7 +330,7 @@ export function UpgradeOfficeSize(corp: ICorporation, office: OfficeSpace, size:
|
||||
corp.funds = corp.funds - cost;
|
||||
}
|
||||
|
||||
export function BuyCoffee(corp: ICorporation, office: OfficeSpace): boolean {
|
||||
export function BuyCoffee(corp: Corporation, office: OfficeSpace): boolean {
|
||||
const cost = office.getCoffeeCost();
|
||||
if (corp.funds < cost) {
|
||||
return false;
|
||||
@ -347,7 +344,7 @@ export function BuyCoffee(corp: ICorporation, office: OfficeSpace): boolean {
|
||||
return true;
|
||||
}
|
||||
|
||||
export function ThrowParty(corp: ICorporation, office: OfficeSpace, costPerEmployee: number): number {
|
||||
export function ThrowParty(corp: Corporation, office: OfficeSpace, costPerEmployee: number): number {
|
||||
const mult = 1 + costPerEmployee / 10e6;
|
||||
const cost = costPerEmployee * office.employees.length;
|
||||
if (corp.funds < cost) {
|
||||
@ -362,9 +359,9 @@ export function ThrowParty(corp: ICorporation, office: OfficeSpace, costPerEmplo
|
||||
return mult;
|
||||
}
|
||||
|
||||
export function PurchaseWarehouse(corp: ICorporation, division: IIndustry, city: string): void {
|
||||
export function PurchaseWarehouse(corp: Corporation, division: Industry, city: string): void {
|
||||
if (corp.funds < CorporationConstants.WarehouseInitialCost) return;
|
||||
if (division.warehouses[city] instanceof Warehouse) return;
|
||||
if (division.warehouses[city]) return;
|
||||
division.warehouses[city] = new Warehouse({
|
||||
corp: corp,
|
||||
industry: division,
|
||||
@ -381,7 +378,7 @@ export function UpgradeWarehouseCost(warehouse: Warehouse, amt: number): number
|
||||
);
|
||||
}
|
||||
|
||||
export function UpgradeWarehouse(corp: ICorporation, division: IIndustry, warehouse: Warehouse, amt = 1): void {
|
||||
export function UpgradeWarehouse(corp: Corporation, division: Industry, warehouse: Warehouse, amt = 1): void {
|
||||
const sizeUpgradeCost = UpgradeWarehouseCost(warehouse, amt);
|
||||
if (corp.funds < sizeUpgradeCost) return;
|
||||
warehouse.level += amt;
|
||||
@ -389,7 +386,7 @@ export function UpgradeWarehouse(corp: ICorporation, division: IIndustry, wareho
|
||||
corp.funds = corp.funds - sizeUpgradeCost;
|
||||
}
|
||||
|
||||
export function HireAdVert(corp: ICorporation, division: IIndustry): void {
|
||||
export function HireAdVert(corp: Corporation, division: Industry): void {
|
||||
const cost = division.getAdVertCost();
|
||||
if (corp.funds < cost) return;
|
||||
corp.funds = corp.funds - cost;
|
||||
@ -397,8 +394,8 @@ export function HireAdVert(corp: ICorporation, division: IIndustry): void {
|
||||
}
|
||||
|
||||
export function MakeProduct(
|
||||
corp: ICorporation,
|
||||
division: IIndustry,
|
||||
corp: Corporation,
|
||||
division: Industry,
|
||||
city: string,
|
||||
productName: string,
|
||||
designInvest: number,
|
||||
@ -442,7 +439,7 @@ export function MakeProduct(
|
||||
designCost: designInvest,
|
||||
advCost: marketingInvest,
|
||||
});
|
||||
if (products[product.name] instanceof Product) {
|
||||
if (products[product.name]) {
|
||||
throw new Error(`You already have a product with this name!`);
|
||||
}
|
||||
|
||||
@ -450,7 +447,7 @@ export function MakeProduct(
|
||||
products[product.name] = product;
|
||||
}
|
||||
|
||||
export function Research(division: IIndustry, researchName: string): void {
|
||||
export function Research(division: Industry, researchName: string): void {
|
||||
const researchTree = IndustryResearchTrees[division.type];
|
||||
if (researchTree === undefined) throw new Error(`No research tree for industry '${division.type}'`);
|
||||
const allResearch = researchTree.getAllNodes();
|
||||
@ -473,10 +470,10 @@ export function Research(division: IIndustry, researchName: string): void {
|
||||
for (let i = 0; i < CorporationConstants.Cities.length; ++i) {
|
||||
const city = CorporationConstants.Cities[i];
|
||||
const warehouse = division.warehouses[city];
|
||||
if (!(warehouse instanceof Warehouse)) {
|
||||
if (!warehouse) {
|
||||
continue;
|
||||
}
|
||||
if (Player.corporation instanceof Corporation) {
|
||||
if (Player.corporation) {
|
||||
// Stores cycles in a "buffer". Processed separately using Engine Counters
|
||||
warehouse.updateSize(Player.corporation, division);
|
||||
}
|
||||
|
@ -1,14 +1,13 @@
|
||||
import { CorporationState } from "./CorporationState";
|
||||
import { CorporationUnlockUpgrade, CorporationUnlockUpgrades } from "./data/CorporationUnlockUpgrades";
|
||||
import { CorporationUpgrade, CorporationUpgrades } from "./data/CorporationUpgrades";
|
||||
import { Warehouse } from "./Warehouse";
|
||||
import { CorporationConstants } from "./data/Constants";
|
||||
import { Industry } from "./Industry";
|
||||
|
||||
import { BitNodeMultipliers } from "../BitNode/BitNodeMultipliers";
|
||||
import { showLiterature } from "../Literature/LiteratureHelpers";
|
||||
import { LiteratureNames } from "../Literature/data/LiteratureNames";
|
||||
import { IPlayer } from "../PersonObjects/IPlayer";
|
||||
import { Player } from "../Player";
|
||||
|
||||
import { dialogBoxCreate } from "../ui/React/DialogBox";
|
||||
import { Reviver, Generic_toJSON, Generic_fromJSON, IReviverValue } from "../utils/JSONReviver";
|
||||
@ -76,7 +75,7 @@ export class Corporation {
|
||||
this.storedCycles += numCycles;
|
||||
}
|
||||
|
||||
process(player: IPlayer): void {
|
||||
process(): void {
|
||||
if (this.storedCycles >= CorporationConstants.CyclesPerIndustryStateCycle) {
|
||||
const state = this.getState();
|
||||
const marketCycles = 1;
|
||||
@ -120,7 +119,7 @@ export class Corporation {
|
||||
if (isNaN(this.funds) || this.funds === Infinity || this.funds === -Infinity) {
|
||||
dialogBoxCreate(
|
||||
"There was an error calculating your Corporations funds and they got reset to 0. " +
|
||||
"This is a bug. Please report to game developer.<br><br>" +
|
||||
"This is a bug. Please report to game developer.\n\n" +
|
||||
"(Your funds have been set to $150b for the inconvenience)",
|
||||
);
|
||||
this.funds = 150e9;
|
||||
@ -139,7 +138,7 @@ export class Corporation {
|
||||
} else {
|
||||
const totalDividends = this.dividendRate * cycleProfit;
|
||||
const retainedEarnings = cycleProfit - totalDividends;
|
||||
player.gainMoney(this.getCycleDividends(), "corporation");
|
||||
Player.gainMoney(this.getCycleDividends(), "corporation");
|
||||
this.addFunds(retainedEarnings);
|
||||
}
|
||||
} else {
|
||||
@ -331,7 +330,7 @@ export class Corporation {
|
||||
for (const city of Object.keys(industry.warehouses)) {
|
||||
const warehouse = industry.warehouses[city];
|
||||
if (warehouse === 0) continue;
|
||||
if (industry.warehouses.hasOwnProperty(city) && warehouse instanceof Warehouse) {
|
||||
if (industry.warehouses.hasOwnProperty(city) && warehouse) {
|
||||
warehouse.updateSize(this, industry);
|
||||
}
|
||||
}
|
||||
@ -428,9 +427,9 @@ export class Corporation {
|
||||
// Adds the Corporation Handbook (Starter Guide) to the player's home computer.
|
||||
// This is a lit file that gives introductory info to the player
|
||||
// This occurs when the player clicks the "Getting Started Guide" button on the overview panel
|
||||
getStarterGuide(player: IPlayer): void {
|
||||
getStarterGuide(): void {
|
||||
// Check if player already has Corporation Handbook
|
||||
const homeComp = player.getHomeComputer();
|
||||
const homeComp = Player.getHomeComputer();
|
||||
let hasHandbook = false;
|
||||
const handbookFn = LiteratureNames.CorporationManagementHandbook;
|
||||
for (let i = 0; i < homeComp.messages.length; ++i) {
|
||||
|
@ -2,8 +2,8 @@ import { CorporationConstants } from "./data/Constants";
|
||||
import { getRandomInt } from "../utils/helpers/getRandomInt";
|
||||
import { Generic_fromJSON, Generic_toJSON, IReviverValue, Reviver } from "../utils/JSONReviver";
|
||||
import { EmployeePositions } from "./EmployeePositions";
|
||||
import { ICorporation } from "./ICorporation";
|
||||
import { IIndustry } from "./IIndustry";
|
||||
import { Corporation } from "./Corporation";
|
||||
import { Industry } from "./Industry";
|
||||
|
||||
interface IParams {
|
||||
name?: string;
|
||||
@ -77,7 +77,7 @@ export class Employee {
|
||||
return salary;
|
||||
}
|
||||
|
||||
calculateProductivity(corporation: ICorporation, industry: IIndustry): number {
|
||||
calculateProductivity(corporation: Corporation, industry: Industry): number {
|
||||
const effCre = this.cre * corporation.getEmployeeCreMultiplier() * industry.getEmployeeCreMultiplier(),
|
||||
effCha = this.cha * corporation.getEmployeeChaMultiplier() * industry.getEmployeeChaMultiplier(),
|
||||
effInt = this.int * corporation.getEmployeeIntMultiplier() * industry.getEmployeeIntMultiplier(),
|
||||
|
@ -1,63 +0,0 @@
|
||||
import { Industry } from "./Industry";
|
||||
import { IPlayer } from "../PersonObjects/IPlayer";
|
||||
import { CorporationUnlockUpgrade } from "./data/CorporationUnlockUpgrades";
|
||||
import { CorporationUpgrade } from "./data/CorporationUpgrades";
|
||||
import { CorporationState } from "./CorporationState";
|
||||
import { IReviverValue } from "../utils/JSONReviver";
|
||||
|
||||
export interface ICorporation {
|
||||
name: string;
|
||||
|
||||
divisions: Industry[];
|
||||
|
||||
funds: number;
|
||||
revenue: number;
|
||||
expenses: number;
|
||||
fundingRound: number;
|
||||
public: boolean;
|
||||
totalShares: number;
|
||||
numShares: number;
|
||||
shareSalesUntilPriceUpdate: number;
|
||||
shareSaleCooldown: number;
|
||||
issueNewSharesCooldown: number;
|
||||
dividendRate: number;
|
||||
dividendTax: number;
|
||||
issuedShares: number;
|
||||
sharePrice: number;
|
||||
storedCycles: number;
|
||||
valuation: number;
|
||||
|
||||
unlockUpgrades: number[];
|
||||
upgrades: number[];
|
||||
upgradeMultipliers: number[];
|
||||
|
||||
state: CorporationState;
|
||||
|
||||
addFunds(amt: number): void;
|
||||
getState(): string;
|
||||
storeCycles(numCycles: number): void;
|
||||
process(player: IPlayer): void;
|
||||
determineValuation(): void;
|
||||
determineCycleValuation(): number;
|
||||
getTargetSharePrice(): number;
|
||||
updateSharePrice(): void;
|
||||
immediatelyUpdateSharePrice(): void;
|
||||
calculateShareSale(numShares: number): [number, number, number];
|
||||
convertCooldownToString(cd: number): string;
|
||||
unlock(upgrade: CorporationUnlockUpgrade): void;
|
||||
upgrade(upgrade: CorporationUpgrade): void;
|
||||
getProductionMultiplier(): number;
|
||||
getStorageMultiplier(): number;
|
||||
getDreamSenseGain(): number;
|
||||
getAdvertisingMultiplier(): number;
|
||||
getEmployeeCreMultiplier(): number;
|
||||
getEmployeeChaMultiplier(): number;
|
||||
getEmployeeIntMultiplier(): number;
|
||||
getEmployeeEffMultiplier(): number;
|
||||
getSalesMultiplier(): number;
|
||||
getScientificResearchMultiplier(): number;
|
||||
getStarterGuide(player: IPlayer): void;
|
||||
updateDividendTax(): void;
|
||||
getCycleDividends(): number;
|
||||
toJSON(): IReviverValue;
|
||||
}
|
@ -1,78 +0,0 @@
|
||||
import { Material } from "./Material";
|
||||
import { Warehouse } from "./Warehouse";
|
||||
import { ICorporation } from "./ICorporation";
|
||||
import { OfficeSpace } from "./OfficeSpace";
|
||||
import { Product } from "./Product";
|
||||
import { IReviverValue } from "../utils/JSONReviver";
|
||||
|
||||
export interface IIndustry {
|
||||
name: string;
|
||||
type: string;
|
||||
sciResearch: Material;
|
||||
researched: { [key: string]: boolean | undefined };
|
||||
reqMats: { [key: string]: number | undefined };
|
||||
|
||||
prodMats: string[];
|
||||
|
||||
products: { [key: string]: Product | undefined };
|
||||
makesProducts: boolean;
|
||||
|
||||
awareness: number;
|
||||
popularity: number;
|
||||
startingCost: number;
|
||||
|
||||
reFac: number;
|
||||
sciFac: number;
|
||||
hwFac: number;
|
||||
robFac: number;
|
||||
aiFac: number;
|
||||
advFac: number;
|
||||
|
||||
prodMult: number;
|
||||
|
||||
// Decimal
|
||||
lastCycleRevenue: number;
|
||||
lastCycleExpenses: number;
|
||||
thisCycleRevenue: number;
|
||||
thisCycleExpenses: number;
|
||||
|
||||
state: string;
|
||||
newInd: boolean;
|
||||
warehouses: { [key: string]: Warehouse | 0 };
|
||||
offices: { [key: string]: OfficeSpace | 0 };
|
||||
numAdVerts: number;
|
||||
|
||||
init(): void;
|
||||
getProductDescriptionText(): string;
|
||||
getMaximumNumberProducts(): number;
|
||||
hasMaximumNumberProducts(): boolean;
|
||||
calculateProductionFactors(): void;
|
||||
updateWarehouseSizeUsed(warehouse: Warehouse): void;
|
||||
process(marketCycles: number, state: string, corporation: ICorporation): void;
|
||||
processMaterialMarket(): void;
|
||||
processProductMarket(marketCycles: number): void;
|
||||
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;
|
||||
getOfficeProductivity(office: OfficeSpace, params?: { forProduct?: boolean }): number;
|
||||
getBusinessFactor(office: OfficeSpace): number;
|
||||
getAdvertisingFactors(): [number, number, number, number];
|
||||
getMarketFactor(mat: { dmd: number; cmp: number }): number;
|
||||
hasResearch(name: string): boolean;
|
||||
updateResearchTree(): void;
|
||||
getAdvertisingMultiplier(): number;
|
||||
getEmployeeChaMultiplier(): number;
|
||||
getEmployeeCreMultiplier(): number;
|
||||
getEmployeeEffMultiplier(): number;
|
||||
getEmployeeIntMultiplier(): number;
|
||||
getProductionMultiplier(): number;
|
||||
getProductProductionMultiplier(): number;
|
||||
getSalesMultiplier(): number;
|
||||
getScientificResearchMultiplier(): number;
|
||||
getStorageMultiplier(): number;
|
||||
toJSON(): IReviverValue;
|
||||
}
|
@ -12,16 +12,15 @@ import { dialogBoxCreate } from "../ui/React/DialogBox";
|
||||
import { isString } from "../utils/helpers/isString";
|
||||
import { MaterialSizes } from "./MaterialSizes";
|
||||
import { Warehouse } from "./Warehouse";
|
||||
import { ICorporation } from "./ICorporation";
|
||||
import { IIndustry } from "./IIndustry";
|
||||
import { Corporation } from "./Corporation";
|
||||
|
||||
interface IParams {
|
||||
name?: string;
|
||||
corp?: ICorporation;
|
||||
corp?: Corporation;
|
||||
type?: string;
|
||||
}
|
||||
|
||||
export class Industry implements IIndustry {
|
||||
export class Industry {
|
||||
name = "";
|
||||
type = Industries.Agriculture;
|
||||
sciResearch = new Material({ name: "Scientific Research" });
|
||||
@ -356,9 +355,7 @@ export class Industry implements IIndustry {
|
||||
for (let i = 0; i < CorporationConstants.Cities.length; ++i) {
|
||||
const city = CorporationConstants.Cities[i];
|
||||
const warehouse = this.warehouses[city];
|
||||
if (!(warehouse instanceof Warehouse)) {
|
||||
continue;
|
||||
}
|
||||
if (!warehouse) continue;
|
||||
|
||||
const materials = warehouse.materials;
|
||||
|
||||
@ -385,7 +382,7 @@ export class Industry implements IIndustry {
|
||||
}
|
||||
}
|
||||
|
||||
process(marketCycles = 1, state: string, corporation: ICorporation): void {
|
||||
process(marketCycles = 1, state: string, corporation: Corporation): void {
|
||||
this.state = state;
|
||||
|
||||
//At the start of a cycle, store and reset revenue/expenses
|
||||
@ -414,10 +411,7 @@ export class Industry implements IIndustry {
|
||||
let employeeSalary = 0;
|
||||
for (const officeLoc of Object.keys(this.offices)) {
|
||||
const office = this.offices[officeLoc];
|
||||
if (office === 0) continue;
|
||||
if (office instanceof OfficeSpace) {
|
||||
employeeSalary += office.process(marketCycles, corporation, this);
|
||||
}
|
||||
if (office) employeeSalary += office.process(marketCycles, corporation, this);
|
||||
}
|
||||
this.thisCycleExpenses = this.thisCycleExpenses + employeeSalary;
|
||||
|
||||
@ -468,7 +462,7 @@ export class Industry implements IIndustry {
|
||||
for (let i = 0; i < CorporationConstants.Cities.length; ++i) {
|
||||
//If this industry has a warehouse in this city, process the market
|
||||
//for every material this industry requires or produces
|
||||
if (this.warehouses[CorporationConstants.Cities[i]] instanceof Warehouse) {
|
||||
if (this.warehouses[CorporationConstants.Cities[i]]) {
|
||||
const wh = this.warehouses[CorporationConstants.Cities[i]];
|
||||
if (wh === 0) continue;
|
||||
for (const name of Object.keys(reqMats)) {
|
||||
@ -518,7 +512,7 @@ export class Industry implements IIndustry {
|
||||
}
|
||||
|
||||
//Process production, purchase, and import/export of materials
|
||||
processMaterials(marketCycles = 1, corporation: ICorporation): [number, number] {
|
||||
processMaterials(marketCycles = 1, corporation: Corporation): [number, number] {
|
||||
let revenue = 0,
|
||||
expenses = 0;
|
||||
this.calculateProductionFactors();
|
||||
@ -528,7 +522,7 @@ export class Industry implements IIndustry {
|
||||
const office = this.offices[city];
|
||||
if (office === 0) continue;
|
||||
|
||||
if (this.warehouses[city] instanceof Warehouse) {
|
||||
if (this.warehouses[city]) {
|
||||
const warehouse = this.warehouses[city];
|
||||
if (warehouse === 0) continue;
|
||||
|
||||
@ -825,14 +819,7 @@ export class Industry implements IIndustry {
|
||||
sellAmt = eval(tmp);
|
||||
} catch (e) {
|
||||
dialogBoxCreate(
|
||||
"Error evaluating your sell amount for material " +
|
||||
mat.name +
|
||||
" in " +
|
||||
this.name +
|
||||
"'s " +
|
||||
city +
|
||||
" office. The sell amount " +
|
||||
"is being set to zero",
|
||||
`Error evaluating your sell amount for material ${mat.name} in ${this.name}'s ${city} office. The sell amount is being set to zero`,
|
||||
);
|
||||
sellAmt = 0;
|
||||
}
|
||||
@ -879,27 +866,13 @@ export class Industry implements IIndustry {
|
||||
amt = eval(amtStr);
|
||||
} catch (e) {
|
||||
dialogBoxCreate(
|
||||
"Calculating export for " +
|
||||
mat.name +
|
||||
" in " +
|
||||
this.name +
|
||||
"'s " +
|
||||
city +
|
||||
" division failed with " +
|
||||
"error: " +
|
||||
e,
|
||||
`Calculating export for ${mat.name} in ${this.name}'s ${city} division failed with error: ${e}`,
|
||||
);
|
||||
continue;
|
||||
}
|
||||
if (isNaN(amt)) {
|
||||
dialogBoxCreate(
|
||||
"Error calculating export amount for " +
|
||||
mat.name +
|
||||
" in " +
|
||||
this.name +
|
||||
"'s " +
|
||||
city +
|
||||
" division.",
|
||||
`Error calculating export amount for ${mat.name} in ${this.name}'s ${city} division.`,
|
||||
);
|
||||
continue;
|
||||
}
|
||||
@ -915,7 +888,7 @@ export class Industry implements IIndustry {
|
||||
if (corporation.divisions[foo].name === exp.ind) {
|
||||
const expIndustry = corporation.divisions[foo];
|
||||
const expWarehouse = expIndustry.warehouses[exp.city];
|
||||
if (!(expWarehouse instanceof Warehouse)) {
|
||||
if (!expWarehouse) {
|
||||
console.error(`Invalid export! ${expIndustry.name} ${exp.city}`);
|
||||
break;
|
||||
}
|
||||
@ -958,7 +931,7 @@ export class Industry implements IIndustry {
|
||||
|
||||
//Produce Scientific Research based on R&D employees
|
||||
//Scientific Research can be produced without a warehouse
|
||||
if (office instanceof OfficeSpace) {
|
||||
if (office) {
|
||||
this.sciResearch.qty +=
|
||||
0.004 *
|
||||
Math.pow(office.employeeProd[EmployeePositions.RandD], 0.5) *
|
||||
@ -970,7 +943,7 @@ export class Industry implements IIndustry {
|
||||
}
|
||||
|
||||
//Process production & sale of this industry's FINISHED products (including all of their stats)
|
||||
processProducts(marketCycles = 1, corporation: ICorporation): [number, number] {
|
||||
processProducts(marketCycles = 1, corporation: Corporation): [number, number] {
|
||||
let revenue = 0;
|
||||
const expenses = 0;
|
||||
|
||||
@ -997,7 +970,7 @@ export class Industry implements IIndustry {
|
||||
for (const prodName of Object.keys(this.products)) {
|
||||
if (this.products.hasOwnProperty(prodName)) {
|
||||
const prod = this.products[prodName];
|
||||
if (prod instanceof Product && prod.fin) {
|
||||
if (prod && prod.fin) {
|
||||
revenue += this.processProduct(marketCycles, prod, corporation);
|
||||
}
|
||||
}
|
||||
@ -1006,14 +979,14 @@ export class Industry implements IIndustry {
|
||||
}
|
||||
|
||||
//Processes FINISHED products
|
||||
processProduct(marketCycles = 1, product: Product, corporation: ICorporation): number {
|
||||
processProduct(marketCycles = 1, product: Product, corporation: Corporation): number {
|
||||
let totalProfit = 0;
|
||||
for (let i = 0; i < CorporationConstants.Cities.length; ++i) {
|
||||
const city = CorporationConstants.Cities[i];
|
||||
const office = this.offices[city];
|
||||
if (office === 0) continue;
|
||||
const warehouse = this.warehouses[city];
|
||||
if (warehouse instanceof Warehouse) {
|
||||
if (warehouse) {
|
||||
switch (this.state) {
|
||||
case "PRODUCTION": {
|
||||
//Calculate the maximum production of this material based
|
||||
@ -1172,13 +1145,7 @@ export class Industry implements IIndustry {
|
||||
tmp = eval(tmp);
|
||||
} catch (e) {
|
||||
dialogBoxCreate(
|
||||
"Error evaluating your sell price expression for " +
|
||||
product.name +
|
||||
" in " +
|
||||
this.name +
|
||||
"'s " +
|
||||
city +
|
||||
" office. Sell price is being set to MAX",
|
||||
`Error evaluating your sell price expression for ${product.name} in ${this.name}'s ${city} office. Sell price is being set to MAX`,
|
||||
);
|
||||
tmp = product.maxsll;
|
||||
}
|
||||
@ -1223,7 +1190,7 @@ export class Industry implements IIndustry {
|
||||
if (state === "EXPORT") {
|
||||
for (let i = 0; i < CorporationConstants.Cities.length; ++i) {
|
||||
const city = CorporationConstants.Cities[i];
|
||||
if (!(this.warehouses[city] instanceof Warehouse)) {
|
||||
if (!this.warehouses[city]) {
|
||||
continue;
|
||||
}
|
||||
const warehouse = this.warehouses[city];
|
||||
@ -1252,7 +1219,7 @@ export class Industry implements IIndustry {
|
||||
return 1e9 * Math.pow(1.06, this.numAdVerts);
|
||||
}
|
||||
|
||||
applyAdVert(corporation: ICorporation): void {
|
||||
applyAdVert(corporation: Corporation): void {
|
||||
const advMult = corporation.getAdvertisingMultiplier() * this.getAdvertisingMultiplier();
|
||||
const awareness = (this.awareness + 3 * advMult) * (1.01 * advMult);
|
||||
this.awareness = Math.min(awareness, Number.MAX_VALUE);
|
||||
|
@ -1,6 +1,6 @@
|
||||
import React from "react";
|
||||
import { ResearchTree } from "./ResearchTree";
|
||||
import { ICorporation } from "./ICorporation";
|
||||
import { Corporation } from "./Corporation";
|
||||
import { getBaseResearchTreeCopy, getProductIndustryResearchTreeCopy } from "./data/BaseResearchTree";
|
||||
import { MoneyCost } from "./ui/MoneyCost";
|
||||
|
||||
@ -59,8 +59,8 @@ export const IndustryStartingCosts: IIndustryMap<number> = {
|
||||
};
|
||||
|
||||
// Map of description for each industry
|
||||
export const IndustryDescriptions: IIndustryMap<(corp: ICorporation) => React.ReactElement> = {
|
||||
Energy: (corp: ICorporation) => (
|
||||
export const IndustryDescriptions: IIndustryMap<(corp: Corporation) => React.ReactElement> = {
|
||||
Energy: (corp: Corporation) => (
|
||||
<>
|
||||
Engage in the production and distribution of energy.
|
||||
<br />
|
||||
@ -70,7 +70,7 @@ export const IndustryDescriptions: IIndustryMap<(corp: ICorporation) => React.Re
|
||||
Recommended starting Industry: NO
|
||||
</>
|
||||
),
|
||||
Utilities: (corp: ICorporation) => (
|
||||
Utilities: (corp: Corporation) => (
|
||||
<>
|
||||
Distribute water and provide wastewater services.
|
||||
<br />
|
||||
@ -80,7 +80,7 @@ export const IndustryDescriptions: IIndustryMap<(corp: ICorporation) => React.Re
|
||||
Recommended starting Industry: NO
|
||||
</>
|
||||
),
|
||||
Agriculture: (corp: ICorporation) => (
|
||||
Agriculture: (corp: Corporation) => (
|
||||
<>
|
||||
Cultivate crops and breed livestock to produce food.
|
||||
<br />
|
||||
@ -90,7 +90,7 @@ export const IndustryDescriptions: IIndustryMap<(corp: ICorporation) => React.Re
|
||||
Recommended starting Industry: YES
|
||||
</>
|
||||
),
|
||||
Fishing: (corp: ICorporation) => (
|
||||
Fishing: (corp: Corporation) => (
|
||||
<>
|
||||
Produce food through the breeding and processing of fish and fish products.
|
||||
<br />
|
||||
@ -100,7 +100,7 @@ export const IndustryDescriptions: IIndustryMap<(corp: ICorporation) => React.Re
|
||||
Recommended starting Industry: NO
|
||||
</>
|
||||
),
|
||||
Mining: (corp: ICorporation) => (
|
||||
Mining: (corp: Corporation) => (
|
||||
<>
|
||||
Extract and process metals from the earth.
|
||||
<br />
|
||||
@ -110,7 +110,7 @@ export const IndustryDescriptions: IIndustryMap<(corp: ICorporation) => React.Re
|
||||
Recommended starting Industry: NO
|
||||
</>
|
||||
),
|
||||
Food: (corp: ICorporation) => (
|
||||
Food: (corp: Corporation) => (
|
||||
<>
|
||||
Create your own restaurants all around the world.
|
||||
<br />
|
||||
@ -120,7 +120,7 @@ export const IndustryDescriptions: IIndustryMap<(corp: ICorporation) => React.Re
|
||||
Recommended starting Industry: YES
|
||||
</>
|
||||
),
|
||||
Tobacco: (corp: ICorporation) => (
|
||||
Tobacco: (corp: Corporation) => (
|
||||
<>
|
||||
Create and distribute tobacco and tobacco-related products.
|
||||
<br />
|
||||
@ -130,7 +130,7 @@ export const IndustryDescriptions: IIndustryMap<(corp: ICorporation) => React.Re
|
||||
Recommended starting Industry: YES
|
||||
</>
|
||||
),
|
||||
Chemical: (corp: ICorporation) => (
|
||||
Chemical: (corp: Corporation) => (
|
||||
<>
|
||||
Produce industrial chemicals.
|
||||
<br />
|
||||
@ -140,7 +140,7 @@ export const IndustryDescriptions: IIndustryMap<(corp: ICorporation) => React.Re
|
||||
Recommended starting Industry: NO
|
||||
</>
|
||||
),
|
||||
Pharmaceutical: (corp: ICorporation) => (
|
||||
Pharmaceutical: (corp: Corporation) => (
|
||||
<>
|
||||
Discover, develop, and create new pharmaceutical drugs.
|
||||
<br />
|
||||
@ -150,7 +150,7 @@ export const IndustryDescriptions: IIndustryMap<(corp: ICorporation) => React.Re
|
||||
Recommended starting Industry: NO
|
||||
</>
|
||||
),
|
||||
Computer: (corp: ICorporation) => (
|
||||
Computer: (corp: Corporation) => (
|
||||
<>
|
||||
Develop and manufacture new computer hardware and networking infrastructures.
|
||||
<br />
|
||||
@ -160,7 +160,7 @@ export const IndustryDescriptions: IIndustryMap<(corp: ICorporation) => React.Re
|
||||
Recommended starting Industry: NO
|
||||
</>
|
||||
),
|
||||
Robotics: (corp: ICorporation) => (
|
||||
Robotics: (corp: Corporation) => (
|
||||
<>
|
||||
Develop and create robots.
|
||||
<br />
|
||||
@ -170,7 +170,7 @@ export const IndustryDescriptions: IIndustryMap<(corp: ICorporation) => React.Re
|
||||
Recommended starting Industry: NO
|
||||
</>
|
||||
),
|
||||
Software: (corp: ICorporation) => (
|
||||
Software: (corp: Corporation) => (
|
||||
<>
|
||||
Develop computer software and create AI Cores.
|
||||
<br />
|
||||
@ -180,7 +180,7 @@ export const IndustryDescriptions: IIndustryMap<(corp: ICorporation) => React.Re
|
||||
Recommended starting Industry: YES
|
||||
</>
|
||||
),
|
||||
Healthcare: (corp: ICorporation) => (
|
||||
Healthcare: (corp: Corporation) => (
|
||||
<>
|
||||
Create and manage hospitals.
|
||||
<br />
|
||||
@ -190,7 +190,7 @@ export const IndustryDescriptions: IIndustryMap<(corp: ICorporation) => React.Re
|
||||
Recommended starting Industry: NO
|
||||
</>
|
||||
),
|
||||
RealEstate: (corp: ICorporation) => (
|
||||
RealEstate: (corp: Corporation) => (
|
||||
<>
|
||||
Develop and manage real estate properties.
|
||||
<br />
|
||||
|
@ -4,8 +4,8 @@ import { getRandomInt } from "../utils/helpers/getRandomInt";
|
||||
import { generateRandomString } from "../utils/StringHelperFunctions";
|
||||
import { Generic_fromJSON, Generic_toJSON, IReviverValue, Reviver } from "../utils/JSONReviver";
|
||||
import { Employee } from "./Employee";
|
||||
import { IIndustry } from "./IIndustry";
|
||||
import { ICorporation } from "./ICorporation";
|
||||
import { Industry } from "./Industry";
|
||||
import { Corporation } from "./Corporation";
|
||||
|
||||
interface IParams {
|
||||
loc?: string;
|
||||
@ -68,7 +68,7 @@ export class OfficeSpace {
|
||||
return this.employees.length >= this.size;
|
||||
}
|
||||
|
||||
process(marketCycles = 1, corporation: ICorporation, industry: IIndustry): number {
|
||||
process(marketCycles = 1, corporation: Corporation, industry: Industry): number {
|
||||
// HRBuddy AutoRecruitment and training
|
||||
if (industry.hasResearch("HRBuddy-Recruitment") && !this.atCapacity()) {
|
||||
const emp = this.hireRandomEmployee();
|
||||
@ -177,7 +177,7 @@ export class OfficeSpace {
|
||||
}
|
||||
}
|
||||
|
||||
calculateEmployeeProductivity(corporation: ICorporation, industry: IIndustry): void {
|
||||
calculateEmployeeProductivity(corporation: Corporation, industry: Industry): void {
|
||||
//Reset
|
||||
for (const name of Object.keys(this.employeeProd)) {
|
||||
this.employeeProd[name] = 0;
|
||||
|
@ -1,6 +1,6 @@
|
||||
import { EmployeePositions } from "./EmployeePositions";
|
||||
import { MaterialSizes } from "./MaterialSizes";
|
||||
import { IIndustry } from "./IIndustry";
|
||||
import { Industry } from "./Industry";
|
||||
import { ProductRatingWeights, IProductRatingWeight } from "./ProductRatingWeights";
|
||||
|
||||
import { createCityMap } from "../Locations/createCityMap";
|
||||
@ -157,7 +157,7 @@ export class Product {
|
||||
}
|
||||
|
||||
// @param industry - Industry object. Reference to industry that makes this Product
|
||||
finishProduct(industry: IIndustry): void {
|
||||
finishProduct(industry: Industry): void {
|
||||
this.fin = true;
|
||||
|
||||
// Calculate properties
|
||||
@ -248,7 +248,7 @@ export class Product {
|
||||
}
|
||||
}
|
||||
|
||||
calculateRating(industry: IIndustry): void {
|
||||
calculateRating(industry: Industry): void {
|
||||
const weights: IProductRatingWeight = ProductRatingWeights[industry.type];
|
||||
if (weights == null) {
|
||||
console.error(`Could not find product rating weights for: ${industry}`);
|
||||
|
@ -1,14 +1,14 @@
|
||||
import { Material } from "./Material";
|
||||
import { ICorporation } from "./ICorporation";
|
||||
import { IIndustry } from "./IIndustry";
|
||||
import { Corporation } from "./Corporation";
|
||||
import { Industry } from "./Industry";
|
||||
import { MaterialSizes } from "./MaterialSizes";
|
||||
import { IMap } from "../types";
|
||||
import { Generic_fromJSON, Generic_toJSON, IReviverValue, Reviver } from "../utils/JSONReviver";
|
||||
import { exceptionAlert } from "../utils/helpers/exceptionAlert";
|
||||
|
||||
interface IConstructorParams {
|
||||
corp?: ICorporation;
|
||||
industry?: IIndustry;
|
||||
corp?: Corporation;
|
||||
industry?: Industry;
|
||||
loc?: string;
|
||||
size?: number;
|
||||
}
|
||||
@ -96,7 +96,7 @@ export class Warehouse {
|
||||
}
|
||||
}
|
||||
|
||||
updateSize(corporation: ICorporation, industry: IIndustry): void {
|
||||
updateSize(corporation: Corporation, industry: Industry): void {
|
||||
try {
|
||||
this.size = this.level * 100 * corporation.getStorageMultiplier() * industry.getStorageMultiplier();
|
||||
} catch (e: unknown) {
|
||||
|
@ -1,39 +1,7 @@
|
||||
import { CityName } from "./../../Locations/data/CityNames";
|
||||
const CyclesPerMarketCycle = 50;
|
||||
const AllCorporationStates = ["START", "PURCHASE", "PRODUCTION", "SALE", "EXPORT"];
|
||||
export const CorporationConstants: {
|
||||
INITIALSHARES: number;
|
||||
SHARESPERPRICEUPDATE: number;
|
||||
IssueNewSharesCooldown: number;
|
||||
SellSharesCooldown: number;
|
||||
CyclesPerMarketCycle: number;
|
||||
CyclesPerIndustryStateCycle: number;
|
||||
SecsPerMarketCycle: number;
|
||||
Cities: string[];
|
||||
WarehouseInitialCost: number;
|
||||
WarehouseInitialSize: number;
|
||||
WarehouseUpgradeBaseCost: number;
|
||||
OfficeInitialCost: number;
|
||||
OfficeInitialSize: number;
|
||||
OfficeUpgradeBaseCost: number;
|
||||
BribeThreshold: number;
|
||||
BribeToRepRatio: number;
|
||||
ProductProductionCostRatio: number;
|
||||
DividendMaxRate: number;
|
||||
EmployeeSalaryMultiplier: number;
|
||||
CyclesPerEmployeeRaise: number;
|
||||
EmployeeRaiseAmount: number;
|
||||
BaseMaxProducts: number;
|
||||
AllCorporationStates: string[];
|
||||
AllMaterials: string[];
|
||||
AllIndustryTypes: string[];
|
||||
AllUnlocks: string[];
|
||||
AllUpgrades: string[];
|
||||
AllResearch: string[];
|
||||
FundingRoundShares: number[];
|
||||
FundingRoundMultiplier: number[];
|
||||
ValuationLength: number;
|
||||
} = {
|
||||
export const CorporationConstants = {
|
||||
INITIALSHARES: 1e9, //Total number of shares you have at your company
|
||||
SHARESPERPRICEUPDATE: 1e6, //When selling large number of shares, price is dynamically updated for every batch of this amount
|
||||
IssueNewSharesCooldown: 216e3, // 12 Hour in terms of game cycles
|
||||
@ -96,7 +64,7 @@ export const CorporationConstants: {
|
||||
"Tobacco",
|
||||
"Chemical",
|
||||
"Pharmaceutical",
|
||||
"Hardware",
|
||||
"Computers",
|
||||
"Robotics",
|
||||
"Software",
|
||||
"Healthcare",
|
||||
|
@ -1,14 +1,11 @@
|
||||
import React, { useContext } from "react";
|
||||
import { ICorporation } from "../ICorporation";
|
||||
import { IIndustry } from "../IIndustry";
|
||||
import { Corporation } from "../Corporation";
|
||||
import { Industry } from "../Industry";
|
||||
|
||||
export const Context: {
|
||||
Corporation: React.Context<ICorporation>;
|
||||
Division: React.Context<IIndustry>;
|
||||
} = {
|
||||
Corporation: React.createContext<ICorporation>({} as ICorporation),
|
||||
Division: React.createContext<IIndustry>({} as IIndustry),
|
||||
export const Context = {
|
||||
Corporation: React.createContext<Corporation>({} as Corporation),
|
||||
Division: React.createContext<Industry>({} as Industry),
|
||||
};
|
||||
|
||||
export const useCorporation = (): ICorporation => useContext(Context.Corporation);
|
||||
export const useDivision = (): IIndustry => useContext(Context.Division);
|
||||
export const useCorporation = (): Corporation => useContext(Context.Corporation);
|
||||
export const useDivision = (): Industry => useContext(Context.Division);
|
||||
|
@ -2,11 +2,11 @@
|
||||
// These are the tabs at the top of the UI that let you switch to different
|
||||
// divisions, see an overview of your corporation, or create a new industry
|
||||
import React, { useState, useEffect } from "react";
|
||||
import { IIndustry } from "../IIndustry";
|
||||
import { Industry } from "../Industry";
|
||||
import { MainPanel } from "./MainPanel";
|
||||
import { Industries } from "../IndustryData";
|
||||
import { ExpandIndustryTab } from "./ExpandIndustryTab";
|
||||
import { use } from "../../ui/Context";
|
||||
import { Player } from "../../Player";
|
||||
import { Context } from "./Context";
|
||||
import { Overview } from "./Overview";
|
||||
|
||||
@ -14,8 +14,7 @@ import Tabs from "@mui/material/Tabs";
|
||||
import Tab from "@mui/material/Tab";
|
||||
|
||||
export function CorporationRoot(): React.ReactElement {
|
||||
const player = use.Player();
|
||||
const corporation = player.corporation;
|
||||
const corporation = Player.corporation;
|
||||
if (corporation === null) return <></>;
|
||||
const setRerender = useState(false)[1];
|
||||
function rerender(): void {
|
||||
@ -33,7 +32,7 @@ export function CorporationRoot(): React.ReactElement {
|
||||
const canExpand =
|
||||
Object.keys(Industries).filter(
|
||||
(industryType: string) =>
|
||||
corporation.divisions.find((division: IIndustry) => division.type === industryType) === undefined,
|
||||
corporation.divisions.find((division: Industry) => division.type === industryType) === undefined,
|
||||
).length > 0;
|
||||
|
||||
return (
|
||||
|
@ -2,7 +2,7 @@ import React, { useState } from "react";
|
||||
import { dialogBoxCreate } from "../../ui/React/DialogBox";
|
||||
import { IndustryStartingCosts, Industries, IndustryDescriptions } from "../IndustryData";
|
||||
import { useCorporation } from "./Context";
|
||||
import { IIndustry } from "../IIndustry";
|
||||
import { Industry } from "../Industry";
|
||||
import { NewIndustry } from "../Actions";
|
||||
|
||||
import Typography from "@mui/material/Typography";
|
||||
@ -23,7 +23,7 @@ export function ExpandIndustryTab(props: IProps): React.ReactElement {
|
||||
const possibleIndustries = allIndustries
|
||||
.filter(
|
||||
(industryType: string) =>
|
||||
corp.divisions.find((division: IIndustry) => division.type === industryType) === undefined,
|
||||
corp.divisions.find((division: Industry) => division.type === industryType) === undefined,
|
||||
)
|
||||
.sort();
|
||||
const [industry, setIndustry] = useState(possibleIndustries.length > 0 ? possibleIndustries[0] : "");
|
||||
|
@ -1,8 +1,8 @@
|
||||
import { IIndustry } from "../IIndustry";
|
||||
import { Industry } from "../Industry";
|
||||
|
||||
// Returns a boolean indicating whether the given material is relevant for the
|
||||
// current industry.
|
||||
export function isRelevantMaterial(matName: string, division: IIndustry): boolean {
|
||||
export function isRelevantMaterial(matName: string, division: Industry): boolean {
|
||||
// Materials that affect Production multiplier
|
||||
const prodMultiplierMats = ["Hardware", "Robots", "AICores", "RealEstate", "AI Cores", "Real Estate"];
|
||||
|
||||
|
@ -7,7 +7,6 @@ import { IndustryOverview } from "./IndustryOverview";
|
||||
import { IndustryWarehouse } from "./IndustryWarehouse";
|
||||
import { Warehouse } from "../Warehouse";
|
||||
import { OfficeSpace } from "../OfficeSpace";
|
||||
import { use } from "../../ui/Context";
|
||||
import { useCorporation, useDivision } from "./Context";
|
||||
import Box from "@mui/material/Box";
|
||||
|
||||
@ -19,7 +18,6 @@ interface IProps {
|
||||
}
|
||||
|
||||
export function Industry(props: IProps): React.ReactElement {
|
||||
const player = use.Player();
|
||||
const corp = useCorporation();
|
||||
const division = useDivision();
|
||||
return (
|
||||
@ -31,7 +29,6 @@ export function Industry(props: IProps): React.ReactElement {
|
||||
<Box sx={{ width: "50%" }}>
|
||||
<IndustryWarehouse
|
||||
rerender={props.rerender}
|
||||
player={player}
|
||||
corp={corp}
|
||||
currentCity={props.city}
|
||||
division={division}
|
||||
|
@ -1,9 +1,9 @@
|
||||
import React from "react";
|
||||
import { IIndustry } from "../IIndustry";
|
||||
import { Industry } from "../Industry";
|
||||
import { MathJaxWrapper } from "../../MathJaxWrapper";
|
||||
|
||||
interface IProps {
|
||||
division: IIndustry;
|
||||
division: Industry;
|
||||
}
|
||||
|
||||
export function IndustryProductEquation(props: IProps): React.ReactElement {
|
||||
|
@ -3,8 +3,6 @@
|
||||
import React, { useState } from "react";
|
||||
|
||||
import { CorporationConstants } from "../data/Constants";
|
||||
import { Material } from "../Material";
|
||||
import { Product } from "../Product";
|
||||
import { Warehouse } from "../Warehouse";
|
||||
import { SmartSupplyModal } from "./modals/SmartSupplyModal";
|
||||
import { ProductElem } from "./ProductElem";
|
||||
@ -13,9 +11,8 @@ import { MaterialSizes } from "../MaterialSizes";
|
||||
|
||||
import { numeralWrapper } from "../../ui/numeralFormat";
|
||||
|
||||
import { ICorporation } from "../ICorporation";
|
||||
import { IIndustry } from "../IIndustry";
|
||||
import { IPlayer } from "../../PersonObjects/IPlayer";
|
||||
import { Corporation } from "../Corporation";
|
||||
import { Industry } from "../Industry";
|
||||
import { MoneyCost } from "./MoneyCost";
|
||||
import { isRelevantMaterial } from "./Helpers";
|
||||
import { IndustryProductEquation } from "./IndustryProductEquation";
|
||||
@ -31,11 +28,10 @@ import makeStyles from "@mui/styles/makeStyles";
|
||||
import createStyles from "@mui/styles/createStyles";
|
||||
|
||||
interface IProps {
|
||||
corp: ICorporation;
|
||||
division: IIndustry;
|
||||
corp: Corporation;
|
||||
division: Industry;
|
||||
warehouse: Warehouse | 0;
|
||||
currentCity: string;
|
||||
player: IPlayer;
|
||||
rerender: () => void;
|
||||
}
|
||||
|
||||
@ -94,7 +90,7 @@ function WarehouseRoot(props: IProps): React.ReactElement {
|
||||
// Create React components for materials
|
||||
const mats = [];
|
||||
for (const matName of Object.keys(props.warehouse.materials)) {
|
||||
if (!(props.warehouse.materials[matName] instanceof Material)) continue;
|
||||
if (!props.warehouse.materials[matName]) continue;
|
||||
// Only create UI for materials that are relevant for the industry or in stock
|
||||
const isInStock = props.warehouse.materials[matName].qty > 0;
|
||||
const isRelevant = isRelevantMaterial(matName, division);
|
||||
@ -115,7 +111,7 @@ function WarehouseRoot(props: IProps): React.ReactElement {
|
||||
if (division.makesProducts && Object.keys(division.products).length > 0) {
|
||||
for (const productName of Object.keys(division.products)) {
|
||||
const product = division.products[productName];
|
||||
if (!(product instanceof Product)) continue;
|
||||
if (!product) continue;
|
||||
products.push(
|
||||
<ProductElem rerender={props.rerender} city={props.currentCity} key={productName} product={product} />,
|
||||
);
|
||||
@ -219,7 +215,7 @@ function WarehouseRoot(props: IProps): React.ReactElement {
|
||||
}
|
||||
|
||||
export function IndustryWarehouse(props: IProps): React.ReactElement {
|
||||
if (props.warehouse instanceof Warehouse) {
|
||||
if (props.warehouse) {
|
||||
return <WarehouseRoot {...props} />;
|
||||
} else {
|
||||
return <EmptyWarehouse rerender={props.rerender} city={props.currentCity} />;
|
||||
|
@ -4,7 +4,7 @@
|
||||
import React from "react";
|
||||
|
||||
import { CityTabs } from "./CityTabs";
|
||||
import { IIndustry } from "../IIndustry";
|
||||
import { Industry } from "../Industry";
|
||||
import { Context, useCorporation } from "./Context";
|
||||
|
||||
import { CityName } from "../../Locations/data/CityNames";
|
||||
@ -18,7 +18,7 @@ export function MainPanel(props: IProps): React.ReactElement {
|
||||
const corp = useCorporation();
|
||||
const division =
|
||||
props.divisionName !== "Overview"
|
||||
? corp.divisions.find((division: IIndustry) => division.name === props.divisionName)
|
||||
? corp.divisions.find((division: Industry) => division.name === props.divisionName)
|
||||
: undefined; // use undefined because find returns undefined
|
||||
|
||||
if (division === undefined) throw new Error("Cannot find division");
|
||||
|
@ -2,7 +2,6 @@
|
||||
// (right-side panel in the Industry UI)
|
||||
import React, { useState } from "react";
|
||||
|
||||
import { OfficeSpace } from "../OfficeSpace";
|
||||
import { Material } from "../Material";
|
||||
import { Warehouse } from "../Warehouse";
|
||||
import { ExportModal } from "./modals/ExportModal";
|
||||
@ -45,7 +44,7 @@ export function MaterialElem(props: IMaterialProps): React.ReactElement {
|
||||
const mat = props.mat;
|
||||
const markupLimit = mat.getMarkupLimit();
|
||||
const office = division.offices[city];
|
||||
if (!(office instanceof OfficeSpace)) {
|
||||
if (!office) {
|
||||
throw new Error(`Could not get OfficeSpace object for this city (${city})`);
|
||||
}
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
import * as React from "react";
|
||||
import { numeralWrapper } from "../../ui/numeralFormat";
|
||||
import { ICorporation } from "../ICorporation";
|
||||
import { Corporation } from "../Corporation";
|
||||
import { Theme } from "@mui/material/styles";
|
||||
import makeStyles from "@mui/styles/makeStyles";
|
||||
import createStyles from "@mui/styles/createStyles";
|
||||
@ -18,7 +18,7 @@ const useStyles = makeStyles((theme: Theme) =>
|
||||
|
||||
interface IProps {
|
||||
money: number;
|
||||
corp: ICorporation;
|
||||
corp: Corporation;
|
||||
}
|
||||
|
||||
export function MoneyCost(props: IProps): React.ReactElement {
|
||||
|
@ -21,7 +21,7 @@ import { convertTimeMsToTimeElapsedString } from "../../utils/StringHelperFuncti
|
||||
import { Money } from "../../ui/React/Money";
|
||||
import { MoneyRate } from "../../ui/React/MoneyRate";
|
||||
import { StatsTable } from "../../ui/React/StatsTable";
|
||||
import { use } from "../../ui/Context";
|
||||
import { Player } from "../../Player";
|
||||
import { useCorporation } from "./Context";
|
||||
import Typography from "@mui/material/Typography";
|
||||
import Tooltip from "@mui/material/Tooltip";
|
||||
@ -34,7 +34,6 @@ interface IProps {
|
||||
rerender: () => void;
|
||||
}
|
||||
export function Overview({ rerender }: IProps): React.ReactElement {
|
||||
const player = use.Player();
|
||||
const corp = useCorporation();
|
||||
const profit: number = corp.revenue - corp.expenses;
|
||||
|
||||
@ -100,7 +99,7 @@ export function Overview({ rerender }: IProps): React.ReactElement {
|
||||
</Typography>
|
||||
}
|
||||
>
|
||||
<Button onClick={() => corp.getStarterGuide(player)}>Getting Started Guide</Button>
|
||||
<Button onClick={() => corp.getStarterGuide()}>Getting Started Guide</Button>
|
||||
</Tooltip>
|
||||
{corp.public ? <PublicButtons rerender={rerender} /> : <PrivateButtons rerender={rerender} />}
|
||||
<BribeButton />
|
||||
@ -240,12 +239,11 @@ function PublicButtons({ rerender }: IPublicButtonsProps): React.ReactElement {
|
||||
}
|
||||
|
||||
function BribeButton(): React.ReactElement {
|
||||
const player = use.Player();
|
||||
const corp = useCorporation();
|
||||
const [open, setOpen] = useState(false);
|
||||
const canBribe =
|
||||
corp.valuation >= CorporationConstants.BribeThreshold &&
|
||||
player.factions.filter((f) => Factions[f].getInfo().offersWork()).length > 0;
|
||||
Player.factions.filter((f) => Factions[f].getInfo().offersWork()).length > 0;
|
||||
|
||||
function openBribe(): void {
|
||||
if (!canBribe) return;
|
||||
|
@ -4,7 +4,7 @@ import { CorporationConstants } from "../../data/Constants";
|
||||
import { numeralWrapper } from "../../../ui/numeralFormat";
|
||||
import { dialogBoxCreate } from "../../../ui/React/DialogBox";
|
||||
import { Modal } from "../../../ui/React/Modal";
|
||||
import { use } from "../../../ui/Context";
|
||||
import { Player } from "../../../Player";
|
||||
import { useCorporation } from "../Context";
|
||||
import Typography from "@mui/material/Typography";
|
||||
import Button from "@mui/material/Button";
|
||||
@ -19,11 +19,10 @@ interface IProps {
|
||||
}
|
||||
|
||||
export function BribeFactionModal(props: IProps): React.ReactElement {
|
||||
const player = use.Player();
|
||||
const factions = player.factions.filter((name: string) => {
|
||||
const factions = Player.factions.filter((name: string) => {
|
||||
const info = Factions[name].getInfo();
|
||||
if (!info.offersWork()) return false;
|
||||
if (player.hasGangWith(name)) return false;
|
||||
if (Player.hasGangWith(name)) return false;
|
||||
return true;
|
||||
});
|
||||
const corp = useCorporation();
|
||||
@ -60,9 +59,7 @@ export function BribeFactionModal(props: IProps): React.ReactElement {
|
||||
const fac = Factions[selectedFaction];
|
||||
if (disabled) return;
|
||||
const rep = repGain(money);
|
||||
dialogBoxCreate(
|
||||
"You gained " + numeralWrapper.formatReputation(rep) + " reputation with " + fac.name + " by bribing them.",
|
||||
);
|
||||
dialogBoxCreate(`You gained ${numeralWrapper.formatReputation(rep)} reputation with ${fac.name} by bribing them.`);
|
||||
fac.playerReputation += rep;
|
||||
corp.funds = corp.funds - money;
|
||||
props.onClose();
|
||||
@ -79,7 +76,7 @@ export function BribeFactionModal(props: IProps): React.ReactElement {
|
||||
{factions.map((name: string) => {
|
||||
const info = Factions[name].getInfo();
|
||||
if (!info.offersWork()) return;
|
||||
if (player.hasGangWith(name)) return;
|
||||
if (Player.hasGangWith(name)) return;
|
||||
return (
|
||||
<MenuItem key={name} value={name}>
|
||||
{name}
|
||||
|
@ -1,7 +1,7 @@
|
||||
import React, { useState } from "react";
|
||||
import { Modal } from "../../../ui/React/Modal";
|
||||
import { numeralWrapper } from "../../../ui/numeralFormat";
|
||||
import { use } from "../../../ui/Context";
|
||||
import { Player } from "../../../Player";
|
||||
import { useCorporation } from "../Context";
|
||||
import Typography from "@mui/material/Typography";
|
||||
import Button from "@mui/material/Button";
|
||||
@ -19,7 +19,6 @@ interface IProps {
|
||||
// Create a popup that lets the player buyback shares
|
||||
// This is created when the player clicks the "Buyback Shares" button in the overview panel
|
||||
export function BuybackSharesModal(props: IProps): React.ReactElement {
|
||||
const player = use.Player();
|
||||
const corp = useCorporation();
|
||||
const [shares, setShares] = useState<number>(NaN);
|
||||
|
||||
@ -30,12 +29,12 @@ export function BuybackSharesModal(props: IProps): React.ReactElement {
|
||||
isNaN(shares) ||
|
||||
shares <= 0 ||
|
||||
shares > corp.issuedShares ||
|
||||
shares * buybackPrice > player.money;
|
||||
shares * buybackPrice > Player.money;
|
||||
|
||||
function buy(): void {
|
||||
if (disabled) return;
|
||||
try {
|
||||
BuyBackShares(corp, player, shares);
|
||||
BuyBackShares(corp, shares);
|
||||
} catch (err) {
|
||||
dialogBoxCreate(err + "");
|
||||
}
|
||||
|
@ -2,7 +2,8 @@ import React, { useState } from "react";
|
||||
|
||||
import { Money } from "../../../ui/React/Money";
|
||||
import { Modal } from "../../../ui/React/Modal";
|
||||
import { use } from "../../../ui/Context";
|
||||
import { Router } from "../../../ui/GameRoot";
|
||||
import { Player } from "../../../Player";
|
||||
import Typography from "@mui/material/Typography";
|
||||
import Button from "@mui/material/Button";
|
||||
import TextField from "@mui/material/TextField";
|
||||
@ -13,10 +14,8 @@ interface IProps {
|
||||
}
|
||||
|
||||
export function CreateCorporationModal(props: IProps): React.ReactElement {
|
||||
const player = use.Player();
|
||||
const router = use.Router();
|
||||
const canSelfFund = player.canAfford(150e9);
|
||||
if (!player.canAccessCorporation() || player.hasCorporation()) {
|
||||
const canSelfFund = Player.canAfford(150e9);
|
||||
if (!Player.canAccessCorporation() || Player.hasCorporation()) {
|
||||
props.onClose();
|
||||
return <></>;
|
||||
}
|
||||
@ -35,11 +34,11 @@ export function CreateCorporationModal(props: IProps): React.ReactElement {
|
||||
return;
|
||||
}
|
||||
|
||||
player.startCorporation(name);
|
||||
player.loseMoney(150e9, "corporation");
|
||||
Player.startCorporation(name);
|
||||
Player.loseMoney(150e9, "corporation");
|
||||
|
||||
props.onClose();
|
||||
router.toCorporation();
|
||||
Router.toCorporation();
|
||||
}
|
||||
|
||||
function seed(): void {
|
||||
@ -47,17 +46,17 @@ export function CreateCorporationModal(props: IProps): React.ReactElement {
|
||||
return;
|
||||
}
|
||||
|
||||
player.startCorporation(name, 500e6);
|
||||
Player.startCorporation(name, 500e6);
|
||||
|
||||
props.onClose();
|
||||
router.toCorporation();
|
||||
Router.toCorporation();
|
||||
}
|
||||
|
||||
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 &&
|
||||
{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`}
|
||||
@ -66,13 +65,13 @@ export function CreateCorporationModal(props: IProps): React.ReactElement {
|
||||
If you would like to start one, please enter a name for your corporation below:
|
||||
</Typography>
|
||||
<TextField autoFocus={true} placeholder="Corporation Name" onChange={onChange} value={name} />
|
||||
{player.bitNodeN === 3 && (
|
||||
{Player.bitNodeN === 3 && (
|
||||
<Button onClick={seed} disabled={name == ""}>
|
||||
Use seed money
|
||||
</Button>
|
||||
)}
|
||||
<Button onClick={selfFund} disabled={name == "" || !canSelfFund}>
|
||||
Self-Fund (<Money money={150e9} player={player} />)
|
||||
Self-Fund (<Money money={150e9} forPurchase={true} />)
|
||||
</Button>
|
||||
</Modal>
|
||||
);
|
||||
|
@ -2,7 +2,7 @@ import React, { useState } from "react";
|
||||
import { dialogBoxCreate } from "../../../ui/React/DialogBox";
|
||||
import { Material } from "../../Material";
|
||||
import { Export } from "../../Export";
|
||||
import { IIndustry } from "../../IIndustry";
|
||||
import { Industry } from "../../Industry";
|
||||
import { ExportMaterial } from "../../Actions";
|
||||
import { Modal } from "../../../ui/React/Modal";
|
||||
import { useCorporation } from "../Context";
|
||||
@ -23,9 +23,7 @@ interface IProps {
|
||||
// Create a popup that lets the player manage exports
|
||||
export function ExportModal(props: IProps): React.ReactElement {
|
||||
const corp = useCorporation();
|
||||
const possibleDivisions = corp.divisions.filter((division: IIndustry) =>
|
||||
isRelevantMaterial(props.mat.name, division),
|
||||
);
|
||||
const possibleDivisions = corp.divisions.filter((division: Industry) => isRelevantMaterial(props.mat.name, division));
|
||||
if (possibleDivisions.length === 0) throw new Error("Export popup created with no divisions.");
|
||||
const defaultDivision = possibleDivisions[0];
|
||||
if (Object.keys(defaultDivision.warehouses).length === 0)
|
||||
@ -72,7 +70,7 @@ export function ExportModal(props: IProps): React.ReactElement {
|
||||
rerender();
|
||||
}
|
||||
|
||||
const currentDivision = corp.divisions.find((division: IIndustry) => division.name === industry);
|
||||
const currentDivision = corp.divisions.find((division: Industry) => division.name === industry);
|
||||
if (currentDivision === undefined)
|
||||
throw new Error(`Export popup somehow ended up with undefined division '${currentDivision}'`);
|
||||
const possibleCities = Object.keys(currentDivision.warehouses).filter(
|
||||
@ -90,8 +88,8 @@ export function ExportModal(props: IProps): React.ReactElement {
|
||||
</Typography>
|
||||
<Select onChange={onIndustryChange} value={industry}>
|
||||
{corp.divisions
|
||||
.filter((division: IIndustry) => isRelevantMaterial(props.mat.name, division))
|
||||
.map((division: IIndustry) => (
|
||||
.filter((division: Industry) => isRelevantMaterial(props.mat.name, division))
|
||||
.map((division: Industry) => (
|
||||
<MenuItem key={division.name} value={division.name}>
|
||||
{division.name}
|
||||
</MenuItem>
|
||||
|
@ -89,14 +89,11 @@ export function IssueNewSharesModal(props: IProps): React.ReactElement {
|
||||
|
||||
let dialogContents =
|
||||
`Issued ${numeralWrapper.format(newShares, "0.000a")} new shares` +
|
||||
` and raised ${numeralWrapper.formatMoney(profit)}.`;
|
||||
if (privateShares > 0) {
|
||||
dialogContents += `<br>${numeralWrapper.format(
|
||||
privateShares,
|
||||
"0.000a",
|
||||
)} of these shares were bought by private investors.`;
|
||||
}
|
||||
dialogContents += `<br><br>Stock price decreased to ${numeralWrapper.formatMoney(corp.sharePrice)}`;
|
||||
` and raised ${numeralWrapper.formatMoney(profit)}.` +
|
||||
(privateShares > 0)
|
||||
? "\n" + numeralWrapper.format(privateShares, "0.000a") + "of these shares were bought by private investors."
|
||||
: "";
|
||||
dialogContents += `\n\nStock price decreased to ${numeralWrapper.formatMoney(corp.sharePrice)}`;
|
||||
dialogBoxCreate(dialogContents);
|
||||
}
|
||||
|
||||
|
@ -2,7 +2,7 @@ import React, { useState } from "react";
|
||||
import { Modal } from "../../../ui/React/Modal";
|
||||
import { IndustryResearchTrees } from "../../IndustryData";
|
||||
import { CorporationConstants } from "../../data/Constants";
|
||||
import { IIndustry } from "../../IIndustry";
|
||||
import { Industry } from "../../Industry";
|
||||
import { Research } from "../../Actions";
|
||||
import { Node } from "../../ResearchTree";
|
||||
import { ResearchMap } from "../../ResearchMap";
|
||||
@ -20,7 +20,7 @@ import CheckIcon from "@mui/icons-material/Check";
|
||||
|
||||
interface INodeProps {
|
||||
n: Node | null;
|
||||
division: IIndustry;
|
||||
division: Industry;
|
||||
}
|
||||
function Upgrade({ n, division }: INodeProps): React.ReactElement {
|
||||
const [open, setOpen] = useState(false);
|
||||
@ -42,9 +42,7 @@ function Upgrade({ n, division }: INodeProps): React.ReactElement {
|
||||
}
|
||||
|
||||
dialogBoxCreate(
|
||||
`Researched ${n.text}. It may take a market cycle ` +
|
||||
`(~${CorporationConstants.SecsPerMarketCycle} seconds) before the effects of ` +
|
||||
`the Research apply.`,
|
||||
`Researched ${n.text}. It may take a market cycle (~${CorporationConstants.SecsPerMarketCycle} seconds) before the effects of the Research apply.`,
|
||||
);
|
||||
}
|
||||
|
||||
@ -131,7 +129,7 @@ function Upgrade({ n, division }: INodeProps): React.ReactElement {
|
||||
interface IProps {
|
||||
open: boolean;
|
||||
onClose: () => void;
|
||||
industry: IIndustry;
|
||||
industry: Industry;
|
||||
}
|
||||
|
||||
// Create the Research Tree UI for this Industry
|
||||
|
@ -2,9 +2,8 @@ import React, { useState } from "react";
|
||||
import { numeralWrapper } from "../../../ui/numeralFormat";
|
||||
import { dialogBoxCreate } from "../../../ui/React/DialogBox";
|
||||
import { Modal } from "../../../ui/React/Modal";
|
||||
import { use } from "../../../ui/Context";
|
||||
import { useCorporation } from "../Context";
|
||||
import { ICorporation } from "../../ICorporation";
|
||||
import { Corporation } from "../../Corporation";
|
||||
import Typography from "@mui/material/Typography";
|
||||
import Button from "@mui/material/Button";
|
||||
import { Money } from "../../../ui/React/Money";
|
||||
@ -20,13 +19,12 @@ interface IProps {
|
||||
// Create a popup that lets the player sell Corporation shares
|
||||
// This is created when the player clicks the "Sell Shares" button in the overview panel
|
||||
export function SellSharesModal(props: IProps): React.ReactElement {
|
||||
const player = use.Player();
|
||||
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: ICorporation }): React.ReactElement {
|
||||
function ProfitIndicator(props: { shares: number | null; corp: Corporation }): React.ReactElement {
|
||||
if (props.shares === null) return <></>;
|
||||
let text = "";
|
||||
if (isNaN(props.shares) || props.shares <= 0) {
|
||||
@ -49,7 +47,7 @@ export function SellSharesModal(props: IProps): React.ReactElement {
|
||||
function sell(): void {
|
||||
if (disabled) return;
|
||||
try {
|
||||
const profit = SellShares(corp, player, shares);
|
||||
const profit = SellShares(corp, shares);
|
||||
props.onClose();
|
||||
dialogBoxCreate(
|
||||
<>
|
||||
|
@ -2,7 +2,6 @@ import React, { useState } from "react";
|
||||
|
||||
import { Warehouse } from "../../Warehouse";
|
||||
import { SetSmartSupply, SetSmartSupplyUseLeftovers } from "../../Actions";
|
||||
import { Material } from "../../Material";
|
||||
import { dialogBoxCreate } from "../../../ui/React/DialogBox";
|
||||
import { Modal } from "../../../ui/React/Modal";
|
||||
import { useDivision } from "../Context";
|
||||
@ -62,7 +61,7 @@ export function SmartSupplyModal(props: IProps): React.ReactElement {
|
||||
// Create React components for materials
|
||||
const mats = [];
|
||||
for (const matName of Object.keys(props.warehouse.materials)) {
|
||||
if (!(props.warehouse.materials[matName] instanceof Material)) continue;
|
||||
if (!props.warehouse.materials[matName]) continue;
|
||||
if (!Object.keys(division.reqMats).includes(matName)) continue;
|
||||
mats.push(<Leftover key={matName} warehouse={props.warehouse} matName={matName} />);
|
||||
}
|
||||
|
@ -41,8 +41,7 @@ export function ThrowPartyModal(props: IProps): React.ReactElement {
|
||||
|
||||
if (mult > 0) {
|
||||
dialogBoxCreate(
|
||||
"You threw a party for the office! The morale and happiness " +
|
||||
"of each employee increased by " +
|
||||
"You threw a party for the office! The morale and happiness of each employee increased by " +
|
||||
numeralWrapper.formatPercentage(mult - 1),
|
||||
);
|
||||
}
|
||||
|
@ -2,7 +2,7 @@ import React from "react";
|
||||
import { numeralWrapper } from "../../../ui/numeralFormat";
|
||||
import { CorporationConstants } from "../../data/Constants";
|
||||
import { OfficeSpace } from "../../OfficeSpace";
|
||||
import { ICorporation } from "../../ICorporation";
|
||||
import { Corporation } from "../../Corporation";
|
||||
import { UpgradeOfficeSize } from "../../Actions";
|
||||
import { Modal } from "../../../ui/React/Modal";
|
||||
import { useCorporation } from "../Context";
|
||||
@ -14,7 +14,7 @@ import Box from "@mui/material/Box";
|
||||
interface IUpgradeButton {
|
||||
cost: number;
|
||||
size: number;
|
||||
corp: ICorporation;
|
||||
corp: Corporation;
|
||||
office: OfficeSpace;
|
||||
onClose: () => void;
|
||||
rerender: () => void;
|
||||
|
29
src/CotMG/BaseGift.ts
Normal file
29
src/CotMG/BaseGift.ts
Normal file
@ -0,0 +1,29 @@
|
||||
import { ActiveFragment } from "./ActiveFragment";
|
||||
|
||||
export class BaseGift {
|
||||
fragments: ActiveFragment[];
|
||||
_width?: number;
|
||||
_height?: number;
|
||||
|
||||
constructor(width?: number, height?: number, fragments: ActiveFragment[] = []) {
|
||||
this.fragments = fragments;
|
||||
this._width = width;
|
||||
this._height = height;
|
||||
}
|
||||
|
||||
width(): number {
|
||||
return this._width || 4;
|
||||
}
|
||||
height(): number {
|
||||
return this._height || 4;
|
||||
}
|
||||
fragmentAt(worldX: number, worldY: number): ActiveFragment | undefined {
|
||||
for (const aFrag of this.fragments) {
|
||||
if (aFrag.fullAt(worldX, worldY)) {
|
||||
return aFrag;
|
||||
}
|
||||
}
|
||||
|
||||
return undefined;
|
||||
}
|
||||
}
|
@ -1,67 +0,0 @@
|
||||
import { ActiveFragment } from "./ActiveFragment";
|
||||
import { IStaneksGift } from "./IStaneksGift";
|
||||
|
||||
export class DummyGift implements IStaneksGift {
|
||||
storedCycles = 0;
|
||||
fragments: ActiveFragment[] = [];
|
||||
_width: number;
|
||||
_height: number;
|
||||
|
||||
constructor(width: number, height: number, fragments: ActiveFragment[]) {
|
||||
this.fragments = fragments;
|
||||
this._width = width;
|
||||
this._height = height;
|
||||
}
|
||||
|
||||
width(): number {
|
||||
return this._width;
|
||||
}
|
||||
height(): number {
|
||||
return this._height;
|
||||
}
|
||||
charge(): void {
|
||||
throw new Error("unimplemented for dummy gift");
|
||||
}
|
||||
process(): void {
|
||||
throw new Error("unimplemented for dummy gift");
|
||||
}
|
||||
effect(): number {
|
||||
throw new Error("unimplemented for dummy gift");
|
||||
}
|
||||
canPlace(): boolean {
|
||||
throw new Error("unimplemented for dummy gift");
|
||||
}
|
||||
place(): boolean {
|
||||
throw new Error("unimplemented for dummy gift");
|
||||
}
|
||||
findFragment(): ActiveFragment | undefined {
|
||||
throw new Error("unimplemented for dummy gift");
|
||||
}
|
||||
fragmentAt(worldX: number, worldY: number): ActiveFragment | undefined {
|
||||
for (const aFrag of this.fragments) {
|
||||
if (aFrag.fullAt(worldX, worldY)) {
|
||||
return aFrag;
|
||||
}
|
||||
}
|
||||
|
||||
return undefined;
|
||||
}
|
||||
delete(): boolean {
|
||||
throw new Error("unimplemented for dummy gift");
|
||||
}
|
||||
clear(): void {
|
||||
throw new Error("unimplemented for dummy gift");
|
||||
}
|
||||
count(): number {
|
||||
throw new Error("unimplemented for dummy gift");
|
||||
}
|
||||
inBonus(): boolean {
|
||||
throw new Error("unimplemented for dummy gift");
|
||||
}
|
||||
prestigeAugmentation(): void {
|
||||
throw new Error("unimplemented for dummy gift");
|
||||
}
|
||||
prestigeSourceFile(): void {
|
||||
throw new Error("unimplemented for dummy gift");
|
||||
}
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user