mirror of
https://github.com/bitburner-official/bitburner-src.git
synced 2025-01-03 11:57:34 +01:00
Merge remote-tracking branch 'upstream/dev' into dev
This commit is contained in:
commit
77073836cb
4
dist/main.bundle.js
vendored
4
dist/main.bundle.js
vendored
File diff suppressed because one or more lines are too long
2
dist/main.bundle.js.map
vendored
2
dist/main.bundle.js.map
vendored
File diff suppressed because one or more lines are too long
42
dist/vendor.bundle.js
vendored
42
dist/vendor.bundle.js
vendored
File diff suppressed because one or more lines are too long
2
dist/vendor.bundle.js.map
vendored
2
dist/vendor.bundle.js.map
vendored
File diff suppressed because one or more lines are too long
@ -336,12 +336,12 @@ The list contains the name of (i.e. the value returned by
|
|||||||
| | | |
|
| | | |
|
||||||
| | | You are given an LZ-encoded string. Decode it and output the original string. |
|
| | | You are given an LZ-encoded string. Decode it and output the original string. |
|
||||||
| | | |
|
| | | |
|
||||||
| | | Example: decoding '5aaabc340533bca' chunk-by-chunk |
|
| | | Example: decoding '5aaabb450723abb' chunk-by-chunk |
|
||||||
| | | 5aaabc -> aaabc |
|
| | | 5aaabb -> aaabb |
|
||||||
| | | 5aaabc34 -> aaabcaab |
|
| | | 5aaabb45 -> aaabbaaab |
|
||||||
| | | 5aaabc340 -> aaabcaab |
|
| | | 5aaabb450 -> aaabbaaab |
|
||||||
| | | 5aaabc34053 -> aaabcaabaabaa |
|
| | | 5aaabb45072 -> aaabbaaababababa |
|
||||||
| | | 5aaabc340533bca -> aaabcaabaabaabca |
|
| | | 5aaabb450723abb -> aaabbaaababababaabb |
|
||||||
+-----------------------------------------+------------------------------------------------------------------------------------------+
|
+-----------------------------------------+------------------------------------------------------------------------------------------+
|
||||||
| Compression III: LZ Compression | | Lempel-Ziv (LZ) compression is a data compression technique which encodes data using |
|
| Compression III: LZ Compression | | Lempel-Ziv (LZ) compression is a data compression technique which encodes data using |
|
||||||
| | | references to earlier parts of the data. In this variant of LZ, data is encoded in two |
|
| | | references to earlier parts of the data. In this variant of LZ, data is encoded in two |
|
||||||
@ -361,12 +361,12 @@ The list contains the name of (i.e. the value returned by
|
|||||||
| | | possible output length. |
|
| | | possible output length. |
|
||||||
| | | |
|
| | | |
|
||||||
| | | Examples (some have other possible encodings of minimal length): |
|
| | | Examples (some have other possible encodings of minimal length): |
|
||||||
| | | abracadabra -> 7abracad47 |
|
| | | abracadabra -> 7abracad47 |
|
||||||
| | | mississippi -> 4miss433ppi |
|
| | | mississippi -> 4miss433ppi |
|
||||||
| | | aAAaAAaAaAA -> 3aAA53035 |
|
| | | aAAaAAaAaAA -> 3aAA53035 |
|
||||||
| | | 2718281828 -> 627182844 |
|
| | | 2718281828 -> 627182844 |
|
||||||
| | | abcdefghijk -> 9abcdefghi02jk |
|
| | | abcdefghijk -> 9abcdefghi02jk |
|
||||||
| | | aaaaaaaaaaa -> 1a911a |
|
| | | aaaaaaaaaaaa -> 3aaa91 |
|
||||||
| | | aaaaaaaaaaaa -> 1a912aa |
|
| | | aaaaaaaaaaaaa -> 1a91031 |
|
||||||
| | | aaaaaaaaaaaaa -> 1a91031 |
|
| | | aaaaaaaaaaaaaa -> 1a91041 |
|
||||||
+-----------------------------------------+------------------------------------------------------------------------------------------+
|
+-----------------------------------------+------------------------------------------------------------------------------------------+
|
||||||
|
@ -334,7 +334,7 @@
|
|||||||
},
|
},
|
||||||
"BLADEBURNER_UNSPENT_100000": {
|
"BLADEBURNER_UNSPENT_100000": {
|
||||||
"ID": "BLADEBURNER_UNSPENT_100000",
|
"ID": "BLADEBURNER_UNSPENT_100000",
|
||||||
"Name": "You should really spent those.",
|
"Name": "You should really spend those.",
|
||||||
"Description": "Have 100 000 unspent bladeburner skill points."
|
"Description": "Have 100 000 unspent bladeburner skill points."
|
||||||
},
|
},
|
||||||
"4S": {
|
"4S": {
|
||||||
|
@ -24,6 +24,7 @@ import { IMap } from "../types";
|
|||||||
import * as data from "./AchievementData.json";
|
import * as data from "./AchievementData.json";
|
||||||
import { FactionNames } from "../Faction/data/FactionNames";
|
import { FactionNames } from "../Faction/data/FactionNames";
|
||||||
import { BlackOperationNames } from "../Bladeburner/data/BlackOperationNames";
|
import { BlackOperationNames } from "../Bladeburner/data/BlackOperationNames";
|
||||||
|
import { ClassType } from "../utils/WorkType";
|
||||||
|
|
||||||
// Unable to correctly cast the JSON data into AchievementDataJson type otherwise...
|
// Unable to correctly cast the JSON data into AchievementDataJson type otherwise...
|
||||||
const achievementData = (<AchievementDataJson>(<unknown>data)).achievements;
|
const achievementData = (<AchievementDataJson>(<unknown>data)).achievements;
|
||||||
@ -391,12 +392,9 @@ export const achievements: IMap<Achievement> = {
|
|||||||
...achievementData["WORKOUT"],
|
...achievementData["WORKOUT"],
|
||||||
Icon: "WORKOUT",
|
Icon: "WORKOUT",
|
||||||
Condition: () =>
|
Condition: () =>
|
||||||
[
|
[ClassType.GymStrength, ClassType.GymDefense, ClassType.GymDexterity, ClassType.GymAgility].includes(
|
||||||
CONSTANTS.ClassGymStrength,
|
Player.className,
|
||||||
CONSTANTS.ClassGymDefense,
|
),
|
||||||
CONSTANTS.ClassGymDexterity,
|
|
||||||
CONSTANTS.ClassGymAgility,
|
|
||||||
].includes(Player.className),
|
|
||||||
},
|
},
|
||||||
TOR: {
|
TOR: {
|
||||||
...achievementData["TOR"],
|
...achievementData["TOR"],
|
||||||
|
@ -9,6 +9,18 @@ import { Money } from "../ui/React/Money";
|
|||||||
|
|
||||||
import { Generic_fromJSON, Generic_toJSON, Reviver } from "../utils/JSONReviver";
|
import { Generic_fromJSON, Generic_toJSON, Reviver } from "../utils/JSONReviver";
|
||||||
import { FactionNames } from "../Faction/data/FactionNames";
|
import { FactionNames } from "../Faction/data/FactionNames";
|
||||||
|
import { IPlayer } from "../PersonObjects/IPlayer";
|
||||||
|
import { AugmentationNames } from "./data/AugmentationNames";
|
||||||
|
import { CONSTANTS } from "../Constants";
|
||||||
|
import { StaticAugmentations } from "./StaticAugmentations";
|
||||||
|
import { BitNodeMultipliers } from "../BitNode/BitNodeMultipliers";
|
||||||
|
import { getBaseAugmentationPriceMultiplier, getGenericAugmentationPriceMultiplier } from "./AugmentationHelpers";
|
||||||
|
import { initSoAAugmentations } from "./data/AugmentationCreator";
|
||||||
|
|
||||||
|
export interface AugmentationCosts {
|
||||||
|
moneyCost: number;
|
||||||
|
repCost: number;
|
||||||
|
}
|
||||||
|
|
||||||
export interface IConstructorParams {
|
export interface IConstructorParams {
|
||||||
info: string | JSX.Element;
|
info: string | JSX.Element;
|
||||||
@ -410,10 +422,10 @@ function generateStatsDescription(mults: IMap<number>, programs?: string[], star
|
|||||||
}
|
}
|
||||||
|
|
||||||
export class Augmentation {
|
export class Augmentation {
|
||||||
// How much money this costs to buy
|
// How much money this costs to buy before multipliers
|
||||||
baseCost = 0;
|
baseCost = 0;
|
||||||
|
|
||||||
// How much faction reputation is required to unlock this
|
// How much faction reputation is required to unlock this before multipliers
|
||||||
baseRepRequirement = 0;
|
baseRepRequirement = 0;
|
||||||
|
|
||||||
// Description of what this Aug is and what it does
|
// Description of what this Aug is and what it does
|
||||||
@ -425,9 +437,6 @@ export class Augmentation {
|
|||||||
// Any Augmentation not immediately available in BitNode-1 is special (e.g. Bladeburner augs)
|
// Any Augmentation not immediately available in BitNode-1 is special (e.g. Bladeburner augs)
|
||||||
isSpecial = false;
|
isSpecial = false;
|
||||||
|
|
||||||
// Augmentation level - for repeatable Augs like NeuroFlux Governor
|
|
||||||
level = 0;
|
|
||||||
|
|
||||||
// Name of Augmentation
|
// Name of Augmentation
|
||||||
name = "";
|
name = "";
|
||||||
|
|
||||||
@ -438,12 +447,6 @@ export class Augmentation {
|
|||||||
// The Player/Person classes
|
// The Player/Person classes
|
||||||
mults: IMap<number> = {};
|
mults: IMap<number> = {};
|
||||||
|
|
||||||
// Initial cost. Doesn't change when you purchase multiple Augmentation
|
|
||||||
startingCost = 0;
|
|
||||||
|
|
||||||
// Initial rep requirement. Doesn't change when you purchase multiple Augmentation
|
|
||||||
startingRepRequirement = 0;
|
|
||||||
|
|
||||||
// Factions that offer this aug.
|
// Factions that offer this aug.
|
||||||
factions: string[] = [];
|
factions: string[] = [];
|
||||||
|
|
||||||
@ -461,17 +464,15 @@ export class Augmentation {
|
|||||||
this.prereqs = params.prereqs ? params.prereqs : [];
|
this.prereqs = params.prereqs ? params.prereqs : [];
|
||||||
|
|
||||||
this.baseRepRequirement = params.repCost;
|
this.baseRepRequirement = params.repCost;
|
||||||
|
Object.freeze(this.baseRepRequirement);
|
||||||
this.baseCost = params.moneyCost;
|
this.baseCost = params.moneyCost;
|
||||||
this.startingCost = this.baseCost;
|
Object.freeze(this.baseCost);
|
||||||
this.startingRepRequirement = this.baseRepRequirement;
|
|
||||||
this.factions = params.factions;
|
this.factions = params.factions;
|
||||||
|
|
||||||
if (params.isSpecial) {
|
if (params.isSpecial) {
|
||||||
this.isSpecial = true;
|
this.isSpecial = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.level = 0;
|
|
||||||
|
|
||||||
// Set multipliers
|
// Set multipliers
|
||||||
if (params.hacking_mult) {
|
if (params.hacking_mult) {
|
||||||
this.mults.hacking_mult = params.hacking_mult;
|
this.mults.hacking_mult = params.hacking_mult;
|
||||||
@ -600,6 +601,61 @@ export class Augmentation {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getCost(player: IPlayer): AugmentationCosts {
|
||||||
|
const augmentationReference = StaticAugmentations[this.name];
|
||||||
|
let moneyCost = augmentationReference.baseCost;
|
||||||
|
let repCost = augmentationReference.baseRepRequirement;
|
||||||
|
|
||||||
|
if (augmentationReference.name === AugmentationNames.NeuroFluxGovernor) {
|
||||||
|
let nextLevel = this.getLevel(player);
|
||||||
|
--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) {
|
||||||
|
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,
|
||||||
|
);
|
||||||
|
moneyCost = augmentationReference.baseCost * soaMultiplier;
|
||||||
|
if (soaAugmentationNames.find((augmentationName) => augmentationName === augmentationReference.name)) {
|
||||||
|
repCost = augmentationReference.baseRepRequirement * soaMultiplier;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
moneyCost =
|
||||||
|
augmentationReference.baseCost *
|
||||||
|
getGenericAugmentationPriceMultiplier() *
|
||||||
|
BitNodeMultipliers.AugmentationMoneyCost;
|
||||||
|
}
|
||||||
|
return { moneyCost, repCost };
|
||||||
|
}
|
||||||
|
|
||||||
|
getLevel(player: IPlayer): 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Account for purchased but uninstalled Augmentations
|
||||||
|
for (let i = 0; i < player.queuedAugmentations.length; ++i) {
|
||||||
|
if (player.queuedAugmentations[i].name == AugmentationNames.NeuroFluxGovernor) {
|
||||||
|
++currLevel;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return currLevel + 1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
// Adds this Augmentation to all Factions
|
// Adds this Augmentation to all Factions
|
||||||
addToAllFactions(): void {
|
addToAllFactions(): void {
|
||||||
for (const fac of Object.keys(Factions)) {
|
for (const fac of Object.keys(Factions)) {
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import { Augmentation } from "./Augmentation";
|
import { Augmentation } from "./Augmentation";
|
||||||
import { Augmentations } from "./Augmentations";
|
import { StaticAugmentations } from "./StaticAugmentations";
|
||||||
import { PlayerOwnedAugmentation, IPlayerOwnedAugmentation } from "./PlayerOwnedAugmentation";
|
import { PlayerOwnedAugmentation, IPlayerOwnedAugmentation } from "./PlayerOwnedAugmentation";
|
||||||
import { AugmentationNames } from "./data/AugmentationNames";
|
import { AugmentationNames } from "./data/AugmentationNames";
|
||||||
|
|
||||||
@ -20,30 +20,11 @@ import {
|
|||||||
initNeuroFluxGovernor,
|
initNeuroFluxGovernor,
|
||||||
initUnstableCircadianModulator,
|
initUnstableCircadianModulator,
|
||||||
} from "./data/AugmentationCreator";
|
} from "./data/AugmentationCreator";
|
||||||
import { BitNodeMultipliers } from "../BitNode/BitNodeMultipliers";
|
|
||||||
import { Router } from "../ui/GameRoot";
|
import { Router } from "../ui/GameRoot";
|
||||||
|
|
||||||
export function AddToAugmentations(aug: Augmentation): void {
|
export function AddToStaticAugmentations(aug: Augmentation): void {
|
||||||
const name = aug.name;
|
const name = aug.name;
|
||||||
Augmentations[name] = aug;
|
StaticAugmentations[name] = aug;
|
||||||
}
|
|
||||||
|
|
||||||
export function getNextNeuroFluxLevel(): number {
|
|
||||||
// Get current Neuroflux level based on Player's augmentations
|
|
||||||
let currLevel = 0;
|
|
||||||
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) {
|
|
||||||
++currLevel;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return currLevel + 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function createAugmentations(): void {
|
function createAugmentations(): void {
|
||||||
@ -67,105 +48,54 @@ function resetFactionAugmentations(): void {
|
|||||||
|
|
||||||
function initAugmentations(): void {
|
function initAugmentations(): void {
|
||||||
resetFactionAugmentations();
|
resetFactionAugmentations();
|
||||||
clearObject(Augmentations);
|
clearObject(StaticAugmentations);
|
||||||
createAugmentations();
|
createAugmentations();
|
||||||
updateAugmentationCosts();
|
|
||||||
Player.reapplyAllAugmentations();
|
Player.reapplyAllAugmentations();
|
||||||
}
|
}
|
||||||
|
|
||||||
function getBaseAugmentationPriceMultiplier(): number {
|
export function getBaseAugmentationPriceMultiplier(): number {
|
||||||
return CONSTANTS.MultipleAugMultiplier * [1, 0.96, 0.94, 0.93][Player.sourceFileLvl(11)];
|
return CONSTANTS.MultipleAugMultiplier * [1, 0.96, 0.94, 0.93][Player.sourceFileLvl(11)];
|
||||||
}
|
}
|
||||||
export function getGenericAugmentationPriceMultiplier(): number {
|
export function getGenericAugmentationPriceMultiplier(): number {
|
||||||
return Math.pow(getBaseAugmentationPriceMultiplier(), Player.queuedAugmentations.length);
|
return Math.pow(getBaseAugmentationPriceMultiplier(), Player.queuedAugmentations.length);
|
||||||
}
|
}
|
||||||
|
|
||||||
function updateNeuroFluxGovernorCosts(neuroFluxGovernorAugmentation: Augmentation): void {
|
|
||||||
let nextLevel = getNextNeuroFluxLevel();
|
|
||||||
--nextLevel;
|
|
||||||
const multiplier = Math.pow(CONSTANTS.NeuroFluxGovernorLevelMult, nextLevel);
|
|
||||||
neuroFluxGovernorAugmentation.baseRepRequirement =
|
|
||||||
neuroFluxGovernorAugmentation.startingRepRequirement * multiplier * BitNodeMultipliers.AugmentationRepCost;
|
|
||||||
neuroFluxGovernorAugmentation.baseCost =
|
|
||||||
neuroFluxGovernorAugmentation.startingCost * multiplier * BitNodeMultipliers.AugmentationMoneyCost;
|
|
||||||
|
|
||||||
for (let i = 0; i < Player.queuedAugmentations.length; ++i) {
|
|
||||||
neuroFluxGovernorAugmentation.baseCost *= getBaseAugmentationPriceMultiplier();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function updateSoACosts(soaAugmentation: Augmentation): void {
|
|
||||||
const soaAugmentationNames = initSoAAugmentations().map((augmentation) => augmentation.name);
|
|
||||||
const soaAugCount = soaAugmentationNames.filter((augmentationName) =>
|
|
||||||
Player.hasAugmentation(augmentationName),
|
|
||||||
).length;
|
|
||||||
soaAugmentation.baseCost = soaAugmentation.startingCost * Math.pow(CONSTANTS.SoACostMult, soaAugCount);
|
|
||||||
if (soaAugmentationNames.find((augmentationName) => augmentationName === soaAugmentation.name)) {
|
|
||||||
soaAugmentation.baseRepRequirement =
|
|
||||||
soaAugmentation.startingRepRequirement * Math.pow(CONSTANTS.SoARepMult, soaAugCount);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export function updateAugmentationCosts(): void {
|
|
||||||
for (const name of Object.keys(Augmentations)) {
|
|
||||||
if (Augmentations.hasOwnProperty(name)) {
|
|
||||||
const augmentationToUpdate = Augmentations[name];
|
|
||||||
if (augmentationToUpdate.name === AugmentationNames.NeuroFluxGovernor) {
|
|
||||||
updateNeuroFluxGovernorCosts(augmentationToUpdate);
|
|
||||||
} else if (augmentationToUpdate.factions.includes(FactionNames.ShadowsOfAnarchy)) {
|
|
||||||
updateSoACosts(augmentationToUpdate);
|
|
||||||
} else {
|
|
||||||
augmentationToUpdate.baseCost =
|
|
||||||
augmentationToUpdate.startingCost *
|
|
||||||
getGenericAugmentationPriceMultiplier() *
|
|
||||||
BitNodeMultipliers.AugmentationMoneyCost;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//Resets an Augmentation during (re-initizliation)
|
//Resets an Augmentation during (re-initizliation)
|
||||||
function resetAugmentation(aug: Augmentation): void {
|
function resetAugmentation(aug: Augmentation): void {
|
||||||
aug.addToFactions(aug.factions);
|
aug.addToFactions(aug.factions);
|
||||||
const name = aug.name;
|
const name = aug.name;
|
||||||
if (augmentationExists(name)) {
|
if (augmentationExists(name)) {
|
||||||
delete Augmentations[name];
|
delete StaticAugmentations[name];
|
||||||
}
|
}
|
||||||
AddToAugmentations(aug);
|
AddToStaticAugmentations(aug);
|
||||||
}
|
}
|
||||||
|
|
||||||
function applyAugmentation(aug: IPlayerOwnedAugmentation, reapply = false): void {
|
function applyAugmentation(aug: IPlayerOwnedAugmentation, reapply = false): void {
|
||||||
const augObj = Augmentations[aug.name];
|
const staticAugmentation = StaticAugmentations[aug.name];
|
||||||
|
|
||||||
// Apply multipliers
|
// Apply multipliers
|
||||||
for (const mult of Object.keys(augObj.mults)) {
|
for (const mult of Object.keys(staticAugmentation.mults)) {
|
||||||
const v = Player.getMult(mult) * augObj.mults[mult];
|
const v = Player.getMult(mult) * staticAugmentation.mults[mult];
|
||||||
Player.setMult(mult, v);
|
Player.setMult(mult, v);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Special logic for NeuroFlux Governor
|
|
||||||
if (aug.name === AugmentationNames.NeuroFluxGovernor) {
|
|
||||||
if (!reapply) {
|
|
||||||
Augmentations[aug.name].level = aug.level;
|
|
||||||
for (let i = 0; i < Player.augmentations.length; ++i) {
|
|
||||||
if (Player.augmentations[i].name == AugmentationNames.NeuroFluxGovernor) {
|
|
||||||
Player.augmentations[i].level = aug.level;
|
|
||||||
return;
|
|
||||||
// break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Special logic for Congruity Implant
|
// Special logic for Congruity Implant
|
||||||
if (aug.name === AugmentationNames.CongruityImplant && !reapply) {
|
if (aug.name === AugmentationNames.CongruityImplant && !reapply) {
|
||||||
Player.entropy = 0;
|
Player.entropy = 0;
|
||||||
Player.applyEntropy(Player.entropy);
|
Player.applyEntropy(Player.entropy);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Special logic for NeuroFlux Governor
|
||||||
|
const ownedNfg = Player.augmentations.find((pAug) => pAug.name === AugmentationNames.NeuroFluxGovernor);
|
||||||
|
if (aug.name === AugmentationNames.NeuroFluxGovernor && !reapply && ownedNfg) {
|
||||||
|
ownedNfg.level = aug.level;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// Push onto Player's Augmentation list
|
// Push onto Player's Augmentation list
|
||||||
if (!reapply) {
|
if (!reapply) {
|
||||||
const ownedAug = new PlayerOwnedAugmentation(aug.name);
|
const ownedAug = new PlayerOwnedAugmentation(aug.name);
|
||||||
|
|
||||||
Player.augmentations.push(ownedAug);
|
Player.augmentations.push(ownedAug);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -185,7 +115,7 @@ function installAugmentations(force?: boolean): boolean {
|
|||||||
}
|
}
|
||||||
for (let i = 0; i < Player.queuedAugmentations.length; ++i) {
|
for (let i = 0; i < Player.queuedAugmentations.length; ++i) {
|
||||||
const ownedAug = Player.queuedAugmentations[i];
|
const ownedAug = Player.queuedAugmentations[i];
|
||||||
const aug = Augmentations[ownedAug.name];
|
const aug = StaticAugmentations[ownedAug.name];
|
||||||
if (aug == null) {
|
if (aug == null) {
|
||||||
console.error(`Invalid augmentation: ${ownedAug.name}`);
|
console.error(`Invalid augmentation: ${ownedAug.name}`);
|
||||||
continue;
|
continue;
|
||||||
@ -215,7 +145,7 @@ function installAugmentations(force?: boolean): boolean {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function augmentationExists(name: string): boolean {
|
function augmentationExists(name: string): boolean {
|
||||||
return Augmentations.hasOwnProperty(name);
|
return StaticAugmentations.hasOwnProperty(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function isRepeatableAug(aug: Augmentation): boolean {
|
export function isRepeatableAug(aug: Augmentation): boolean {
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { Augmentation } from "./Augmentation";
|
import { Augmentation } from "./Augmentation";
|
||||||
import { IMap } from "../types";
|
import { IMap } from "../types";
|
||||||
|
|
||||||
export const Augmentations: IMap<Augmentation> = {};
|
export const StaticAugmentations: IMap<Augmentation> = {};
|
@ -114,17 +114,6 @@ export enum AugmentationNames {
|
|||||||
StaneksGift2 = "Stanek's Gift - Awakening",
|
StaneksGift2 = "Stanek's Gift - Awakening",
|
||||||
StaneksGift3 = "Stanek's Gift - Serenity",
|
StaneksGift3 = "Stanek's Gift - Serenity",
|
||||||
|
|
||||||
/*
|
|
||||||
MightOfAres = "Might of Ares", // slash
|
|
||||||
WisdomOfAthena = "Wisdom of Athena", // bracket
|
|
||||||
TrickeryOfHermes = "Trickery of Hermes", // cheatcode
|
|
||||||
BeautyOfAphrodite = "Beauty of Aphrodite", // bribe
|
|
||||||
ChaosOfDionysus = "Chaos of Dionysus", // reverse
|
|
||||||
FloodOfPoseidon = "Flood of Poseidon", // hex
|
|
||||||
HuntOfArtemis = "Hunt of Artemis", // mine
|
|
||||||
KnowledgeOfApollo = "Knowledge of Apollo", // wire
|
|
||||||
*/
|
|
||||||
|
|
||||||
// Infiltrators MiniGames
|
// Infiltrators MiniGames
|
||||||
MightOfAres = "SoA - Might of Ares", // slash
|
MightOfAres = "SoA - Might of Ares", // slash
|
||||||
WisdomOfAthena = "SoA - Wisdom of Athena", // bracket
|
WisdomOfAthena = "SoA - Wisdom of Athena", // bracket
|
||||||
@ -135,10 +124,4 @@ export enum AugmentationNames {
|
|||||||
HuntOfArtemis = "SoA - Hunt of Artemis", // mine
|
HuntOfArtemis = "SoA - Hunt of Artemis", // mine
|
||||||
KnowledgeOfApollo = "SoA - Knowledge of Apollo", // wire
|
KnowledgeOfApollo = "SoA - Knowledge of Apollo", // wire
|
||||||
WKSharmonizer = "SoA - phyzical WKS harmonizer",
|
WKSharmonizer = "SoA - phyzical WKS harmonizer",
|
||||||
|
|
||||||
//Wasteland Augs
|
|
||||||
//PepBoy: "P.E.P-Boy", Plasma Energy Projection System
|
|
||||||
//PepBoyForceField Generates plasma force fields
|
|
||||||
//PepBoyBlasts Generate high density plasma concussive blasts
|
|
||||||
//PepBoyDataStorage STore more data on pep boy,
|
|
||||||
}
|
}
|
||||||
|
@ -22,7 +22,7 @@ import { Settings } from "../../Settings/Settings";
|
|||||||
import { ConfirmationModal } from "../../ui/React/ConfirmationModal";
|
import { ConfirmationModal } from "../../ui/React/ConfirmationModal";
|
||||||
import { IPlayer } from "../../PersonObjects/IPlayer";
|
import { IPlayer } from "../../PersonObjects/IPlayer";
|
||||||
import { AugmentationNames } from "../data/AugmentationNames";
|
import { AugmentationNames } from "../data/AugmentationNames";
|
||||||
import { Augmentations } from "../Augmentations";
|
import { StaticAugmentations } from "../StaticAugmentations";
|
||||||
import { CONSTANTS } from "../../Constants";
|
import { CONSTANTS } from "../../Constants";
|
||||||
import { formatNumber } from "../../utils/StringHelperFunctions";
|
import { formatNumber } from "../../utils/StringHelperFunctions";
|
||||||
import { Info } from "@mui/icons-material";
|
import { Info } from "@mui/icons-material";
|
||||||
@ -39,7 +39,9 @@ const NeuroFluxDisplay = ({ player }: NFGDisplayProps): React.ReactElement => {
|
|||||||
<Typography variant="h5" color={Settings.theme.info}>
|
<Typography variant="h5" color={Settings.theme.info}>
|
||||||
NeuroFlux Governor - Level {level}
|
NeuroFlux Governor - Level {level}
|
||||||
</Typography>
|
</Typography>
|
||||||
<Typography color={Settings.theme.info}>{Augmentations[AugmentationNames.NeuroFluxGovernor].stats}</Typography>
|
<Typography color={Settings.theme.info}>
|
||||||
|
{StaticAugmentations[AugmentationNames.NeuroFluxGovernor].stats}
|
||||||
|
</Typography>
|
||||||
</Paper>
|
</Paper>
|
||||||
) : (
|
) : (
|
||||||
<></>
|
<></>
|
||||||
|
@ -13,7 +13,7 @@ import React, { useState } from "react";
|
|||||||
import { OwnedAugmentationsOrderSetting } from "../../Settings/SettingEnums";
|
import { OwnedAugmentationsOrderSetting } from "../../Settings/SettingEnums";
|
||||||
import { Settings } from "../../Settings/Settings";
|
import { Settings } from "../../Settings/Settings";
|
||||||
import { use } from "../../ui/Context";
|
import { use } from "../../ui/Context";
|
||||||
import { Augmentations } from "../Augmentations";
|
import { StaticAugmentations } from "../StaticAugmentations";
|
||||||
import { AugmentationNames } from "../data/AugmentationNames";
|
import { AugmentationNames } from "../data/AugmentationNames";
|
||||||
|
|
||||||
export function InstalledAugmentations(): React.ReactElement {
|
export function InstalledAugmentations(): React.ReactElement {
|
||||||
@ -77,7 +77,7 @@ export function InstalledAugmentations(): React.ReactElement {
|
|||||||
</Typography>
|
</Typography>
|
||||||
<Typography sx={{ maxHeight: 350, overflowY: "scroll" }}>
|
<Typography sx={{ maxHeight: 350, overflowY: "scroll" }}>
|
||||||
{(() => {
|
{(() => {
|
||||||
const aug = Augmentations[selectedAug.name];
|
const aug = StaticAugmentations[selectedAug.name];
|
||||||
|
|
||||||
const info = typeof aug.info === "string" ? <span>{aug.info}</span> : aug.info;
|
const info = typeof aug.info === "string" ? <span>{aug.info}</span> : aug.info;
|
||||||
const tooltip = (
|
const tooltip = (
|
||||||
|
@ -8,7 +8,7 @@ import { BitNodeMultipliers } from "../../BitNode/BitNodeMultipliers";
|
|||||||
import { Player } from "../../Player";
|
import { Player } from "../../Player";
|
||||||
import { Settings } from "../../Settings/Settings";
|
import { Settings } from "../../Settings/Settings";
|
||||||
import { numeralWrapper } from "../../ui/numeralFormat";
|
import { numeralWrapper } from "../../ui/numeralFormat";
|
||||||
import { Augmentations } from "../Augmentations";
|
import { StaticAugmentations } from "../StaticAugmentations";
|
||||||
|
|
||||||
interface IAugmentedStats {
|
interface IAugmentedStats {
|
||||||
[index: string]: number;
|
[index: string]: number;
|
||||||
@ -17,7 +17,7 @@ interface IAugmentedStats {
|
|||||||
function calculateAugmentedStats(): IAugmentedStats {
|
function calculateAugmentedStats(): IAugmentedStats {
|
||||||
const augP: IAugmentedStats = {};
|
const augP: IAugmentedStats = {};
|
||||||
for (const aug of Player.queuedAugmentations) {
|
for (const aug of Player.queuedAugmentations) {
|
||||||
const augObj = Augmentations[aug.name];
|
const augObj = StaticAugmentations[aug.name];
|
||||||
for (const mult of Object.keys(augObj.mults)) {
|
for (const mult of Object.keys(augObj.mults)) {
|
||||||
const v = augP[mult] ? augP[mult] : 1;
|
const v = augP[mult] ? augP[mult] : 1;
|
||||||
augP[mult] = v * augObj.mults[mult];
|
augP[mult] = v * augObj.mults[mult];
|
||||||
|
@ -5,15 +5,14 @@
|
|||||||
import { CheckBox, CheckBoxOutlineBlank, CheckCircle, Info, NewReleases, Report } from "@mui/icons-material";
|
import { CheckBox, CheckBoxOutlineBlank, CheckCircle, Info, NewReleases, Report } from "@mui/icons-material";
|
||||||
import { Box, Button, Container, Paper, Tooltip, Typography } from "@mui/material";
|
import { Box, Button, Container, Paper, Tooltip, Typography } from "@mui/material";
|
||||||
import React, { useState } from "react";
|
import React, { useState } from "react";
|
||||||
import { getNextNeuroFluxLevel } from "../AugmentationHelpers";
|
|
||||||
import { Faction } from "../../Faction/Faction";
|
import { Faction } from "../../Faction/Faction";
|
||||||
import { IPlayer } from "../../PersonObjects/IPlayer";
|
import { IPlayer } from "../../PersonObjects/IPlayer";
|
||||||
import { Settings } from "../../Settings/Settings";
|
import { Settings } from "../../Settings/Settings";
|
||||||
import { numeralWrapper } from "../../ui/numeralFormat";
|
import { numeralWrapper } from "../../ui/numeralFormat";
|
||||||
import { Augmentation } from "../Augmentation";
|
import { Augmentation } from "../Augmentation";
|
||||||
import { Augmentations } from "../Augmentations";
|
|
||||||
import { AugmentationNames } from "../data/AugmentationNames";
|
import { AugmentationNames } from "../data/AugmentationNames";
|
||||||
import { PurchaseAugmentationModal } from "./PurchaseAugmentationModal";
|
import { PurchaseAugmentationModal } from "./PurchaseAugmentationModal";
|
||||||
|
import { StaticAugmentations } from "../StaticAugmentations";
|
||||||
|
|
||||||
interface IPreReqsProps {
|
interface IPreReqsProps {
|
||||||
player: IPlayer;
|
player: IPlayer;
|
||||||
@ -160,10 +159,10 @@ interface IPurchasableAugProps {
|
|||||||
export function PurchasableAugmentation(props: IPurchasableAugProps): React.ReactElement {
|
export function PurchasableAugmentation(props: IPurchasableAugProps): React.ReactElement {
|
||||||
const [open, setOpen] = useState(false);
|
const [open, setOpen] = useState(false);
|
||||||
|
|
||||||
const aug = Augmentations[props.augName];
|
const aug = StaticAugmentations[props.augName];
|
||||||
|
const augCosts = aug.getCost(props.parent.player);
|
||||||
const cost = props.parent.sleeveAugs ? aug.startingCost : aug.baseCost;
|
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;
|
const info = typeof aug.info === "string" ? <span>{aug.info}</span> : aug.info;
|
||||||
const description = (
|
const description = (
|
||||||
<>
|
<>
|
||||||
@ -205,7 +204,8 @@ export function PurchasableAugmentation(props: IPurchasableAugProps): React.Reac
|
|||||||
<>
|
<>
|
||||||
<Typography variant="h5">
|
<Typography variant="h5">
|
||||||
{props.augName}
|
{props.augName}
|
||||||
{props.augName === AugmentationNames.NeuroFluxGovernor && ` - Level ${getNextNeuroFluxLevel()}`}
|
{props.augName === AugmentationNames.NeuroFluxGovernor &&
|
||||||
|
` - Level ${aug.getLevel(props.parent.player)}`}
|
||||||
</Typography>
|
</Typography>
|
||||||
<Typography>{description}</Typography>
|
<Typography>{description}</Typography>
|
||||||
</>
|
</>
|
||||||
@ -219,10 +219,11 @@ export function PurchasableAugmentation(props: IPurchasableAugProps): React.Reac
|
|||||||
textOverflow: "ellipsis",
|
textOverflow: "ellipsis",
|
||||||
whiteSpace: "nowrap",
|
whiteSpace: "nowrap",
|
||||||
overflow: "hidden",
|
overflow: "hidden",
|
||||||
|
color: props.owned ? Settings.theme.disabled : Settings.theme.primary,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{aug.name}
|
{aug.name}
|
||||||
{aug.name === AugmentationNames.NeuroFluxGovernor && ` - Level ${getNextNeuroFluxLevel()}`}
|
{aug.name === AugmentationNames.NeuroFluxGovernor && ` - Level ${aug.getLevel(props.parent.player)}`}
|
||||||
</Typography>
|
</Typography>
|
||||||
{aug.factions.length === 1 && !props.parent.sleeveAugs && (
|
{aug.factions.length === 1 && !props.parent.sleeveAugs && (
|
||||||
<Exclusive player={props.parent.player} aug={aug} />
|
<Exclusive player={props.parent.player} aug={aug} />
|
||||||
@ -236,14 +237,14 @@ export function PurchasableAugmentation(props: IPurchasableAugProps): React.Reac
|
|||||||
{props.owned || (
|
{props.owned || (
|
||||||
<Box sx={{ display: "grid", alignItems: "center", justifyItems: "left" }}>
|
<Box sx={{ display: "grid", alignItems: "center", justifyItems: "left" }}>
|
||||||
<Requirement
|
<Requirement
|
||||||
fulfilled={aug.baseCost === 0 || props.parent.player.money > cost}
|
fulfilled={cost === 0 || props.parent.player.money > cost}
|
||||||
value={numeralWrapper.formatMoney(cost)}
|
value={numeralWrapper.formatMoney(cost)}
|
||||||
color={Settings.theme.money}
|
color={Settings.theme.money}
|
||||||
/>
|
/>
|
||||||
{props.parent.rep !== undefined && (
|
{props.parent.rep !== undefined && (
|
||||||
<Requirement
|
<Requirement
|
||||||
fulfilled={props.parent.rep >= aug.baseRepRequirement}
|
fulfilled={props.parent.rep >= repCost}
|
||||||
value={`${numeralWrapper.formatReputation(aug.baseRepRequirement)} rep`}
|
value={`${numeralWrapper.formatReputation(repCost)} rep`}
|
||||||
color={Settings.theme.rep}
|
color={Settings.theme.rep}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
@ -44,7 +44,7 @@ export function PurchaseAugmentationModal(props: IProps): React.ReactElement {
|
|||||||
<br />
|
<br />
|
||||||
<br />
|
<br />
|
||||||
Would you like to purchase the {props.aug.name} Augmentation for
|
Would you like to purchase the {props.aug.name} Augmentation for
|
||||||
<Money money={props.aug.baseCost} />?
|
<Money money={props.aug.getCost(player).moneyCost} />?
|
||||||
<br />
|
<br />
|
||||||
<br />
|
<br />
|
||||||
</Typography>
|
</Typography>
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
import { List, ListItemText, Paper, Tooltip, Typography } from "@mui/material";
|
import { List, ListItemText, Paper, Tooltip, Typography } from "@mui/material";
|
||||||
import * as React from "react";
|
import * as React from "react";
|
||||||
import { Player } from "../../Player";
|
import { Player } from "../../Player";
|
||||||
import { Augmentations } from "../Augmentations";
|
import { StaticAugmentations } from "../StaticAugmentations";
|
||||||
import { AugmentationNames } from "../data/AugmentationNames";
|
import { AugmentationNames } from "../data/AugmentationNames";
|
||||||
|
|
||||||
export function PurchasedAugmentations(): React.ReactElement {
|
export function PurchasedAugmentations(): React.ReactElement {
|
||||||
@ -23,7 +23,7 @@ export function PurchasedAugmentations(): React.ReactElement {
|
|||||||
let displayName = ownedAug.name;
|
let displayName = ownedAug.name;
|
||||||
|
|
||||||
if (ownedAug.name === AugmentationNames.NeuroFluxGovernor && i !== nfgIndex) continue;
|
if (ownedAug.name === AugmentationNames.NeuroFluxGovernor && i !== nfgIndex) continue;
|
||||||
const aug = Augmentations[ownedAug.name];
|
const aug = StaticAugmentations[ownedAug.name];
|
||||||
|
|
||||||
let level = null;
|
let level = null;
|
||||||
if (ownedAug.name === AugmentationNames.NeuroFluxGovernor) {
|
if (ownedAug.name === AugmentationNames.NeuroFluxGovernor) {
|
||||||
|
@ -63,26 +63,6 @@ export const CONSTANTS: {
|
|||||||
GameCyclesPerQuarterHour: number;
|
GameCyclesPerQuarterHour: number;
|
||||||
MillisecondsPerFiveMinutes: number;
|
MillisecondsPerFiveMinutes: number;
|
||||||
GameCyclesPerFiveMinutes: number;
|
GameCyclesPerFiveMinutes: number;
|
||||||
FactionWorkHacking: string;
|
|
||||||
FactionWorkField: string;
|
|
||||||
FactionWorkSecurity: string;
|
|
||||||
WorkTypeCompany: string;
|
|
||||||
WorkTypeCompanyPartTime: string;
|
|
||||||
WorkTypeFaction: string;
|
|
||||||
WorkTypeCreateProgram: string;
|
|
||||||
WorkTypeStudyClass: string;
|
|
||||||
WorkTypeCrime: string;
|
|
||||||
WorkTypeGraftAugmentation: string;
|
|
||||||
ClassStudyComputerScience: string;
|
|
||||||
ClassDataStructures: string;
|
|
||||||
ClassNetworks: string;
|
|
||||||
ClassAlgorithms: string;
|
|
||||||
ClassManagement: string;
|
|
||||||
ClassLeadership: string;
|
|
||||||
ClassGymStrength: string;
|
|
||||||
ClassGymDefense: string;
|
|
||||||
ClassGymDexterity: string;
|
|
||||||
ClassGymAgility: string;
|
|
||||||
ClassDataStructuresBaseCost: number;
|
ClassDataStructuresBaseCost: number;
|
||||||
ClassNetworksBaseCost: number;
|
ClassNetworksBaseCost: number;
|
||||||
ClassAlgorithmsBaseCost: number;
|
ClassAlgorithmsBaseCost: number;
|
||||||
@ -95,18 +75,6 @@ export const CONSTANTS: {
|
|||||||
ClassAlgorithmsBaseExp: number;
|
ClassAlgorithmsBaseExp: number;
|
||||||
ClassManagementBaseExp: number;
|
ClassManagementBaseExp: number;
|
||||||
ClassLeadershipBaseExp: number;
|
ClassLeadershipBaseExp: number;
|
||||||
CrimeShoplift: string;
|
|
||||||
CrimeRobStore: string;
|
|
||||||
CrimeMug: string;
|
|
||||||
CrimeLarceny: string;
|
|
||||||
CrimeDrugs: string;
|
|
||||||
CrimeBondForgery: string;
|
|
||||||
CrimeTraffickArms: string;
|
|
||||||
CrimeHomicide: string;
|
|
||||||
CrimeGrandTheftAuto: string;
|
|
||||||
CrimeKidnap: string;
|
|
||||||
CrimeAssassination: string;
|
|
||||||
CrimeHeist: string;
|
|
||||||
CodingContractBaseFactionRepGain: number;
|
CodingContractBaseFactionRepGain: number;
|
||||||
CodingContractBaseCompanyRepGain: number;
|
CodingContractBaseCompanyRepGain: number;
|
||||||
CodingContractBaseMoneyGain: number;
|
CodingContractBaseMoneyGain: number;
|
||||||
@ -120,7 +88,7 @@ export const CONSTANTS: {
|
|||||||
LatestUpdate: string;
|
LatestUpdate: string;
|
||||||
} = {
|
} = {
|
||||||
VersionString: "1.6.4",
|
VersionString: "1.6.4",
|
||||||
VersionNumber: 16,
|
VersionNumber: 17,
|
||||||
|
|
||||||
// Speed (in ms) at which the main loop is updated
|
// Speed (in ms) at which the main loop is updated
|
||||||
_idleSpeed: 200,
|
_idleSpeed: 200,
|
||||||
@ -223,28 +191,6 @@ export const CONSTANTS: {
|
|||||||
|
|
||||||
// Player Work & Action
|
// Player Work & Action
|
||||||
BaseFocusBonus: 0.8,
|
BaseFocusBonus: 0.8,
|
||||||
FactionWorkHacking: "Faction Hacking Work",
|
|
||||||
FactionWorkField: "Faction Field Work",
|
|
||||||
FactionWorkSecurity: "Faction Security Work",
|
|
||||||
|
|
||||||
WorkTypeCompany: "Working for Company",
|
|
||||||
WorkTypeCompanyPartTime: "Working for Company part-time",
|
|
||||||
WorkTypeFaction: "Working for Faction",
|
|
||||||
WorkTypeCreateProgram: "Working on Create a Program",
|
|
||||||
WorkTypeStudyClass: "Studying or Taking a class at university",
|
|
||||||
WorkTypeCrime: "Committing a crime",
|
|
||||||
WorkTypeGraftAugmentation: "Grafting an Augmentation",
|
|
||||||
|
|
||||||
ClassStudyComputerScience: "studying Computer Science",
|
|
||||||
ClassDataStructures: "taking a Data Structures course",
|
|
||||||
ClassNetworks: "taking a Networks course",
|
|
||||||
ClassAlgorithms: "taking an Algorithms course",
|
|
||||||
ClassManagement: "taking a Management course",
|
|
||||||
ClassLeadership: "taking a Leadership course",
|
|
||||||
ClassGymStrength: "training your strength at a gym",
|
|
||||||
ClassGymDefense: "training your defense at a gym",
|
|
||||||
ClassGymDexterity: "training your dexterity at a gym",
|
|
||||||
ClassGymAgility: "training your agility at a gym",
|
|
||||||
|
|
||||||
ClassDataStructuresBaseCost: 40,
|
ClassDataStructuresBaseCost: 40,
|
||||||
ClassNetworksBaseCost: 80,
|
ClassNetworksBaseCost: 80,
|
||||||
@ -260,19 +206,6 @@ export const CONSTANTS: {
|
|||||||
ClassManagementBaseExp: 2,
|
ClassManagementBaseExp: 2,
|
||||||
ClassLeadershipBaseExp: 4,
|
ClassLeadershipBaseExp: 4,
|
||||||
|
|
||||||
CrimeShoplift: "shoplift",
|
|
||||||
CrimeRobStore: "rob a store",
|
|
||||||
CrimeMug: "mug someone",
|
|
||||||
CrimeLarceny: "commit larceny",
|
|
||||||
CrimeDrugs: "deal drugs",
|
|
||||||
CrimeBondForgery: "forge corporate bonds",
|
|
||||||
CrimeTraffickArms: "traffick illegal arms",
|
|
||||||
CrimeHomicide: "commit homicide",
|
|
||||||
CrimeGrandTheftAuto: "commit grand theft auto",
|
|
||||||
CrimeKidnap: "kidnap someone for ransom",
|
|
||||||
CrimeAssassination: "assassinate a high-profile target",
|
|
||||||
CrimeHeist: "pull off the ultimate heist",
|
|
||||||
|
|
||||||
// Coding Contract
|
// Coding Contract
|
||||||
// TODO: Move this into Coding contract implementation?
|
// TODO: Move this into Coding contract implementation?
|
||||||
CodingContractBaseFactionRepGain: 2500,
|
CodingContractBaseFactionRepGain: 2500,
|
||||||
@ -293,7 +226,7 @@ export const CONSTANTS: {
|
|||||||
// BitNode/Source-File related stuff
|
// BitNode/Source-File related stuff
|
||||||
TotalNumBitNodes: 24,
|
TotalNumBitNodes: 24,
|
||||||
|
|
||||||
Donations: 6,
|
Donations: 7,
|
||||||
|
|
||||||
LatestUpdate: `
|
LatestUpdate: `
|
||||||
v1.6.3 - 2022-04-01 Few stanek fixes
|
v1.6.3 - 2022-04-01 Few stanek fixes
|
||||||
|
@ -162,11 +162,7 @@ export function MaterialElem(props: IMaterialProps): React.ReactElement {
|
|||||||
<Tooltip
|
<Tooltip
|
||||||
title={tutorial ? <Typography>Purchase your required materials to get production started!</Typography> : ""}
|
title={tutorial ? <Typography>Purchase your required materials to get production started!</Typography> : ""}
|
||||||
>
|
>
|
||||||
<Button
|
<Button color={tutorial ? "error" : "primary"} onClick={() => setPurchaseMaterialOpen(true)}>
|
||||||
color={tutorial ? "error" : "primary"}
|
|
||||||
onClick={() => setPurchaseMaterialOpen(true)}
|
|
||||||
disabled={props.warehouse.smartSupplyEnabled && Object.keys(division.reqMats).includes(props.mat.name)}
|
|
||||||
>
|
|
||||||
{purchaseButtonText}
|
{purchaseButtonText}
|
||||||
</Button>
|
</Button>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
@ -174,6 +170,9 @@ export function MaterialElem(props: IMaterialProps): React.ReactElement {
|
|||||||
mat={mat}
|
mat={mat}
|
||||||
warehouse={warehouse}
|
warehouse={warehouse}
|
||||||
open={purchaseMaterialOpen}
|
open={purchaseMaterialOpen}
|
||||||
|
disablePurchaseLimit={
|
||||||
|
props.warehouse.smartSupplyEnabled && Object.keys(division.reqMats).includes(props.mat.name)
|
||||||
|
}
|
||||||
onClose={() => setPurchaseMaterialOpen(false)}
|
onClose={() => setPurchaseMaterialOpen(false)}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
@ -106,6 +106,7 @@ interface IProps {
|
|||||||
onClose: () => void;
|
onClose: () => void;
|
||||||
mat: Material;
|
mat: Material;
|
||||||
warehouse: Warehouse;
|
warehouse: Warehouse;
|
||||||
|
disablePurchaseLimit: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create a popup that lets the player purchase a Material
|
// Create a popup that lets the player purchase a Material
|
||||||
@ -143,6 +144,7 @@ export function PurchaseMaterialModal(props: IProps): React.ReactElement {
|
|||||||
<Typography>
|
<Typography>
|
||||||
Enter the amount of {props.mat.name} you would like to purchase per second. This material's cost changes
|
Enter the amount of {props.mat.name} you would like to purchase per second. This material's cost changes
|
||||||
constantly.
|
constantly.
|
||||||
|
{props.disablePurchaseLimit ? "Note: Purchase amount is disabled as smart supply is enabled" : ""}
|
||||||
</Typography>
|
</Typography>
|
||||||
<TextField
|
<TextField
|
||||||
value={buyAmt}
|
value={buyAmt}
|
||||||
@ -150,10 +152,15 @@ export function PurchaseMaterialModal(props: IProps): React.ReactElement {
|
|||||||
autoFocus={true}
|
autoFocus={true}
|
||||||
placeholder="Purchase amount"
|
placeholder="Purchase amount"
|
||||||
type="number"
|
type="number"
|
||||||
|
disabled={props.disablePurchaseLimit}
|
||||||
onKeyDown={onKeyDown}
|
onKeyDown={onKeyDown}
|
||||||
/>
|
/>
|
||||||
<Button onClick={purchaseMaterial}>Confirm</Button>
|
<Button disabled={props.disablePurchaseLimit} onClick={purchaseMaterial}>
|
||||||
<Button onClick={clearPurchase}>Clear Purchase</Button>
|
Confirm
|
||||||
|
</Button>
|
||||||
|
<Button disabled={props.disablePurchaseLimit} onClick={clearPurchase}>
|
||||||
|
Clear Purchase
|
||||||
|
</Button>
|
||||||
{division.hasResearch("Bulk Purchasing") && (
|
{division.hasResearch("Bulk Purchasing") && (
|
||||||
<BulkPurchaseSection onClose={props.onClose} mat={props.mat} warehouse={props.warehouse} />
|
<BulkPurchaseSection onClose={props.onClose} mat={props.mat} warehouse={props.warehouse} />
|
||||||
)}
|
)}
|
||||||
|
@ -3,6 +3,7 @@ import { IPlayer } from "../PersonObjects/IPlayer";
|
|||||||
import { IPerson } from "../PersonObjects/IPerson";
|
import { IPerson } from "../PersonObjects/IPerson";
|
||||||
import { IRouter } from "../ui/Router";
|
import { IRouter } from "../ui/Router";
|
||||||
import { WorkerScript } from "../Netscript/WorkerScript";
|
import { WorkerScript } from "../Netscript/WorkerScript";
|
||||||
|
import { CrimeType } from "../utils/WorkType";
|
||||||
|
|
||||||
interface IConstructorParams {
|
interface IConstructorParams {
|
||||||
hacking_success_weight?: number;
|
hacking_success_weight?: number;
|
||||||
@ -42,7 +43,7 @@ export class Crime {
|
|||||||
time = 0;
|
time = 0;
|
||||||
|
|
||||||
// Corresponding type in CONSTANTS. Contains a description for the crime activity
|
// Corresponding type in CONSTANTS. Contains a description for the crime activity
|
||||||
type = "";
|
type: CrimeType;
|
||||||
|
|
||||||
// Weighting factors that determine how stats affect the success rate of this crime
|
// Weighting factors that determine how stats affect the success rate of this crime
|
||||||
hacking_success_weight = 0;
|
hacking_success_weight = 0;
|
||||||
@ -61,7 +62,15 @@ export class Crime {
|
|||||||
charisma_exp = 0;
|
charisma_exp = 0;
|
||||||
intelligence_exp = 0;
|
intelligence_exp = 0;
|
||||||
|
|
||||||
constructor(name = "", type = "", time = 0, money = 0, difficulty = 0, karma = 0, params: IConstructorParams = {}) {
|
constructor(
|
||||||
|
name = "",
|
||||||
|
type: CrimeType,
|
||||||
|
time = 0,
|
||||||
|
money = 0,
|
||||||
|
difficulty = 0,
|
||||||
|
karma = 0,
|
||||||
|
params: IConstructorParams = {},
|
||||||
|
) {
|
||||||
this.name = name;
|
this.name = name;
|
||||||
this.type = type;
|
this.type = type;
|
||||||
this.time = time;
|
this.time = time;
|
||||||
|
@ -9,7 +9,7 @@ export function determineCrimeSuccess(p: IPlayer, type: string): boolean {
|
|||||||
let found = false;
|
let found = false;
|
||||||
for (const i of Object.keys(Crimes)) {
|
for (const i of Object.keys(Crimes)) {
|
||||||
const crime = Crimes[i];
|
const crime = Crimes[i];
|
||||||
if (crime.type == type) {
|
if (crime.type === type) {
|
||||||
chance = crime.successRate(p);
|
chance = crime.successRate(p);
|
||||||
found = true;
|
found = true;
|
||||||
break;
|
break;
|
||||||
|
@ -3,8 +3,10 @@ import { Crime } from "./Crime";
|
|||||||
import { CONSTANTS } from "../Constants";
|
import { CONSTANTS } from "../Constants";
|
||||||
import { IMap } from "../types";
|
import { IMap } from "../types";
|
||||||
|
|
||||||
|
import { CrimeType } from "../utils/WorkType";
|
||||||
|
|
||||||
export const Crimes: IMap<Crime> = {
|
export const Crimes: IMap<Crime> = {
|
||||||
Shoplift: new Crime("Shoplift", CONSTANTS.CrimeShoplift, 2e3, 15e3, 1 / 20, 0.1, {
|
Shoplift: new Crime("Shoplift", CrimeType.Shoplift, 2e3, 15e3, 1 / 20, 0.1, {
|
||||||
dexterity_success_weight: 1,
|
dexterity_success_weight: 1,
|
||||||
agility_success_weight: 1,
|
agility_success_weight: 1,
|
||||||
|
|
||||||
@ -12,7 +14,7 @@ export const Crimes: IMap<Crime> = {
|
|||||||
agility_exp: 2,
|
agility_exp: 2,
|
||||||
}),
|
}),
|
||||||
|
|
||||||
RobStore: new Crime("Rob Store", CONSTANTS.CrimeRobStore, 60e3, 400e3, 1 / 5, 0.5, {
|
RobStore: new Crime("Rob Store", CrimeType.RobStore, 60e3, 400e3, 1 / 5, 0.5, {
|
||||||
hacking_exp: 30,
|
hacking_exp: 30,
|
||||||
dexterity_exp: 45,
|
dexterity_exp: 45,
|
||||||
agility_exp: 45,
|
agility_exp: 45,
|
||||||
@ -24,7 +26,7 @@ export const Crimes: IMap<Crime> = {
|
|||||||
intelligence_exp: 7.5 * CONSTANTS.IntelligenceCrimeBaseExpGain,
|
intelligence_exp: 7.5 * CONSTANTS.IntelligenceCrimeBaseExpGain,
|
||||||
}),
|
}),
|
||||||
|
|
||||||
Mug: new Crime("Mug", CONSTANTS.CrimeMug, 4e3, 36e3, 1 / 5, 0.25, {
|
Mug: new Crime("Mug", CrimeType.Mug, 4e3, 36e3, 1 / 5, 0.25, {
|
||||||
strength_exp: 3,
|
strength_exp: 3,
|
||||||
defense_exp: 3,
|
defense_exp: 3,
|
||||||
dexterity_exp: 3,
|
dexterity_exp: 3,
|
||||||
@ -36,7 +38,7 @@ export const Crimes: IMap<Crime> = {
|
|||||||
agility_success_weight: 0.5,
|
agility_success_weight: 0.5,
|
||||||
}),
|
}),
|
||||||
|
|
||||||
Larceny: new Crime("Larceny", CONSTANTS.CrimeLarceny, 90e3, 800e3, 1 / 3, 1.5, {
|
Larceny: new Crime("Larceny", CrimeType.Larceny, 90e3, 800e3, 1 / 3, 1.5, {
|
||||||
hacking_exp: 45,
|
hacking_exp: 45,
|
||||||
dexterity_exp: 60,
|
dexterity_exp: 60,
|
||||||
agility_exp: 60,
|
agility_exp: 60,
|
||||||
@ -48,7 +50,7 @@ export const Crimes: IMap<Crime> = {
|
|||||||
intelligence_exp: 15 * CONSTANTS.IntelligenceCrimeBaseExpGain,
|
intelligence_exp: 15 * CONSTANTS.IntelligenceCrimeBaseExpGain,
|
||||||
}),
|
}),
|
||||||
|
|
||||||
DealDrugs: new Crime("Deal Drugs", CONSTANTS.CrimeDrugs, 10e3, 120e3, 1, 0.5, {
|
DealDrugs: new Crime("Deal Drugs", CrimeType.Drugs, 10e3, 120e3, 1, 0.5, {
|
||||||
dexterity_exp: 5,
|
dexterity_exp: 5,
|
||||||
agility_exp: 5,
|
agility_exp: 5,
|
||||||
charisma_exp: 10,
|
charisma_exp: 10,
|
||||||
@ -58,7 +60,7 @@ export const Crimes: IMap<Crime> = {
|
|||||||
agility_success_weight: 1,
|
agility_success_weight: 1,
|
||||||
}),
|
}),
|
||||||
|
|
||||||
BondForgery: new Crime("Bond Forgery", CONSTANTS.CrimeBondForgery, 300e3, 4.5e6, 1 / 2, 0.1, {
|
BondForgery: new Crime("Bond Forgery", CrimeType.BondForgery, 300e3, 4.5e6, 1 / 2, 0.1, {
|
||||||
hacking_exp: 100,
|
hacking_exp: 100,
|
||||||
dexterity_exp: 150,
|
dexterity_exp: 150,
|
||||||
charisma_exp: 15,
|
charisma_exp: 15,
|
||||||
@ -69,7 +71,7 @@ export const Crimes: IMap<Crime> = {
|
|||||||
intelligence_exp: 60 * CONSTANTS.IntelligenceCrimeBaseExpGain,
|
intelligence_exp: 60 * CONSTANTS.IntelligenceCrimeBaseExpGain,
|
||||||
}),
|
}),
|
||||||
|
|
||||||
TraffickArms: new Crime("Traffick Arms", CONSTANTS.CrimeTraffickArms, 40e3, 600e3, 2, 1, {
|
TraffickArms: new Crime("Traffick Arms", CrimeType.TraffickArms, 40e3, 600e3, 2, 1, {
|
||||||
strength_exp: 20,
|
strength_exp: 20,
|
||||||
defense_exp: 20,
|
defense_exp: 20,
|
||||||
dexterity_exp: 20,
|
dexterity_exp: 20,
|
||||||
@ -83,7 +85,7 @@ export const Crimes: IMap<Crime> = {
|
|||||||
agility_success_weight: 1,
|
agility_success_weight: 1,
|
||||||
}),
|
}),
|
||||||
|
|
||||||
Homicide: new Crime("Homicide", CONSTANTS.CrimeHomicide, 3e3, 45e3, 1, 3, {
|
Homicide: new Crime("Homicide", CrimeType.Homicide, 3e3, 45e3, 1, 3, {
|
||||||
strength_exp: 2,
|
strength_exp: 2,
|
||||||
defense_exp: 2,
|
defense_exp: 2,
|
||||||
dexterity_exp: 2,
|
dexterity_exp: 2,
|
||||||
@ -97,7 +99,7 @@ export const Crimes: IMap<Crime> = {
|
|||||||
kills: 1,
|
kills: 1,
|
||||||
}),
|
}),
|
||||||
|
|
||||||
GrandTheftAuto: new Crime("Grand Theft Auto", CONSTANTS.CrimeGrandTheftAuto, 80e3, 1.6e6, 8, 5, {
|
GrandTheftAuto: new Crime("Grand Theft Auto", CrimeType.GrandTheftAuto, 80e3, 1.6e6, 8, 5, {
|
||||||
strength_exp: 20,
|
strength_exp: 20,
|
||||||
defense_exp: 20,
|
defense_exp: 20,
|
||||||
dexterity_exp: 20,
|
dexterity_exp: 20,
|
||||||
@ -113,7 +115,7 @@ export const Crimes: IMap<Crime> = {
|
|||||||
intelligence_exp: 16 * CONSTANTS.IntelligenceCrimeBaseExpGain,
|
intelligence_exp: 16 * CONSTANTS.IntelligenceCrimeBaseExpGain,
|
||||||
}),
|
}),
|
||||||
|
|
||||||
Kidnap: new Crime("Kidnap", CONSTANTS.CrimeKidnap, 120e3, 3.6e6, 5, 6, {
|
Kidnap: new Crime("Kidnap", CrimeType.Kidnap, 120e3, 3.6e6, 5, 6, {
|
||||||
strength_exp: 80,
|
strength_exp: 80,
|
||||||
defense_exp: 80,
|
defense_exp: 80,
|
||||||
dexterity_exp: 80,
|
dexterity_exp: 80,
|
||||||
@ -128,7 +130,7 @@ export const Crimes: IMap<Crime> = {
|
|||||||
intelligence_exp: 26 * CONSTANTS.IntelligenceCrimeBaseExpGain,
|
intelligence_exp: 26 * CONSTANTS.IntelligenceCrimeBaseExpGain,
|
||||||
}),
|
}),
|
||||||
|
|
||||||
Assassination: new Crime("Assassination", CONSTANTS.CrimeAssassination, 300e3, 12e6, 8, 10, {
|
Assassination: new Crime("Assassination", CrimeType.Assassination, 300e3, 12e6, 8, 10, {
|
||||||
strength_exp: 300,
|
strength_exp: 300,
|
||||||
defense_exp: 300,
|
defense_exp: 300,
|
||||||
dexterity_exp: 300,
|
dexterity_exp: 300,
|
||||||
@ -143,7 +145,7 @@ export const Crimes: IMap<Crime> = {
|
|||||||
kills: 1,
|
kills: 1,
|
||||||
}),
|
}),
|
||||||
|
|
||||||
Heist: new Crime("Heist", CONSTANTS.CrimeHeist, 600e3, 120e6, 18, 15, {
|
Heist: new Crime("Heist", CrimeType.Heist, 600e3, 120e6, 18, 15, {
|
||||||
hacking_exp: 450,
|
hacking_exp: 450,
|
||||||
strength_exp: 450,
|
strength_exp: 450,
|
||||||
defense_exp: 450,
|
defense_exp: 450,
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { Augmentations } from "../Augmentation/Augmentations";
|
import { StaticAugmentations } from "../Augmentation/StaticAugmentations";
|
||||||
import { Augmentation } from "../Augmentation/Augmentation";
|
import { Augmentation } from "../Augmentation/Augmentation";
|
||||||
import { PlayerOwnedAugmentation } from "../Augmentation/PlayerOwnedAugmentation";
|
import { PlayerOwnedAugmentation } from "../Augmentation/PlayerOwnedAugmentation";
|
||||||
import { AugmentationNames } from "../Augmentation/data/AugmentationNames";
|
import { AugmentationNames } from "../Augmentation/data/AugmentationNames";
|
||||||
@ -18,7 +18,6 @@ import {
|
|||||||
import { dialogBoxCreate } from "../ui/React/DialogBox";
|
import { dialogBoxCreate } from "../ui/React/DialogBox";
|
||||||
import { InvitationEvent } from "./ui/InvitationModal";
|
import { InvitationEvent } from "./ui/InvitationModal";
|
||||||
import { FactionNames } from "./data/FactionNames";
|
import { FactionNames } from "./data/FactionNames";
|
||||||
import { updateAugmentationCosts, getNextNeuroFluxLevel } from "../Augmentation/AugmentationHelpers";
|
|
||||||
import { SFC32RNG } from "../Casino/RNG";
|
import { SFC32RNG } from "../Casino/RNG";
|
||||||
|
|
||||||
export function inviteToFaction(faction: Faction): void {
|
export function inviteToFaction(faction: Faction): void {
|
||||||
@ -59,6 +58,7 @@ export function hasAugmentationPrereqs(aug: Augmentation): boolean {
|
|||||||
|
|
||||||
export function purchaseAugmentation(aug: Augmentation, fac: Faction, sing = false): string {
|
export function purchaseAugmentation(aug: Augmentation, fac: Faction, sing = false): string {
|
||||||
const hasPrereqs = hasAugmentationPrereqs(aug);
|
const hasPrereqs = hasAugmentationPrereqs(aug);
|
||||||
|
const augCosts = aug.getCost(Player);
|
||||||
if (!hasPrereqs) {
|
if (!hasPrereqs) {
|
||||||
const txt = `You must first purchase or install ${aug.prereqs
|
const txt = `You must first purchase or install ${aug.prereqs
|
||||||
.filter((req) => !Player.hasAugmentation(req))
|
.filter((req) => !Player.hasAugmentation(req))
|
||||||
@ -68,28 +68,26 @@ export function purchaseAugmentation(aug: Augmentation, fac: Faction, sing = fal
|
|||||||
} else {
|
} else {
|
||||||
dialogBoxCreate(txt);
|
dialogBoxCreate(txt);
|
||||||
}
|
}
|
||||||
} else if (aug.baseCost !== 0 && Player.money < aug.baseCost) {
|
} else if (augCosts.moneyCost !== 0 && Player.money < augCosts.moneyCost) {
|
||||||
const txt = "You don't have enough money to purchase " + aug.name;
|
const txt = "You don't have enough money to purchase " + aug.name;
|
||||||
if (sing) {
|
if (sing) {
|
||||||
return txt;
|
return txt;
|
||||||
}
|
}
|
||||||
dialogBoxCreate(txt);
|
dialogBoxCreate(txt);
|
||||||
} else if (fac.playerReputation < aug.baseRepRequirement) {
|
} else if (fac.playerReputation < augCosts.repCost) {
|
||||||
const txt = "You don't have enough faction reputation to purchase " + aug.name;
|
const txt = "You don't have enough faction reputation to purchase " + aug.name;
|
||||||
if (sing) {
|
if (sing) {
|
||||||
return txt;
|
return txt;
|
||||||
}
|
}
|
||||||
dialogBoxCreate(txt);
|
dialogBoxCreate(txt);
|
||||||
} else if (aug.baseCost === 0 || Player.money >= aug.baseCost) {
|
} else if (augCosts.moneyCost === 0 || Player.money >= augCosts.moneyCost) {
|
||||||
const queuedAugmentation = new PlayerOwnedAugmentation(aug.name);
|
const queuedAugmentation = new PlayerOwnedAugmentation(aug.name);
|
||||||
if (aug.name == AugmentationNames.NeuroFluxGovernor) {
|
if (aug.name == AugmentationNames.NeuroFluxGovernor) {
|
||||||
queuedAugmentation.level = getNextNeuroFluxLevel();
|
queuedAugmentation.level = aug.getLevel(Player);
|
||||||
}
|
}
|
||||||
Player.queuedAugmentations.push(queuedAugmentation);
|
Player.queuedAugmentations.push(queuedAugmentation);
|
||||||
|
|
||||||
Player.loseMoney(aug.baseCost, "augmentations");
|
Player.loseMoney(augCosts.moneyCost, "augmentations");
|
||||||
|
|
||||||
updateAugmentationCosts();
|
|
||||||
|
|
||||||
if (sing) {
|
if (sing) {
|
||||||
return "You purchased " + aug.name;
|
return "You purchased " + aug.name;
|
||||||
@ -141,14 +139,14 @@ export function processPassiveFactionRepGain(numCycles: number): void {
|
|||||||
export const getFactionAugmentationsFiltered = (player: IPlayer, faction: Faction): string[] => {
|
export const getFactionAugmentationsFiltered = (player: IPlayer, faction: Faction): string[] => {
|
||||||
// If player has a gang with this faction, return (almost) all augmentations
|
// If player has a gang with this faction, return (almost) all augmentations
|
||||||
if (player.hasGangWith(faction.name)) {
|
if (player.hasGangWith(faction.name)) {
|
||||||
let augs = Object.values(Augmentations);
|
let augs = Object.values(StaticAugmentations);
|
||||||
|
|
||||||
// Remove special augs
|
// Remove special augs
|
||||||
augs = augs.filter((a) => !a.isSpecial || a.name != AugmentationNames.CongruityImplant);
|
augs = augs.filter((a) => !a.isSpecial && a.name !== AugmentationNames.CongruityImplant);
|
||||||
|
|
||||||
if (player.bitNodeN === 2) {
|
if (player.bitNodeN === 2) {
|
||||||
// TRP is not available outside of BN2 for Gangs
|
// TRP is not available outside of BN2 for Gangs
|
||||||
augs.push(Augmentations[AugmentationNames.TheRedPill]);
|
augs.push(StaticAugmentations[AugmentationNames.TheRedPill]);
|
||||||
}
|
}
|
||||||
|
|
||||||
const rng = SFC32RNG(`BN${player.bitNodeN}.${player.sourceFileLvl(player.bitNodeN)}`);
|
const rng = SFC32RNG(`BN${player.bitNodeN}.${player.sourceFileLvl(player.bitNodeN)}`);
|
||||||
|
@ -3,8 +3,9 @@
|
|||||||
*/
|
*/
|
||||||
import { Box, Button, Tooltip, Typography, Paper, Container } from "@mui/material";
|
import { Box, Button, Tooltip, Typography, Paper, Container } from "@mui/material";
|
||||||
import React, { useState } from "react";
|
import React, { useState } from "react";
|
||||||
|
|
||||||
|
import { StaticAugmentations } from "../../Augmentation/StaticAugmentations";
|
||||||
import { getGenericAugmentationPriceMultiplier } from "../../Augmentation/AugmentationHelpers";
|
import { getGenericAugmentationPriceMultiplier } from "../../Augmentation/AugmentationHelpers";
|
||||||
import { Augmentations } from "../../Augmentation/Augmentations";
|
|
||||||
import { AugmentationNames } from "../../Augmentation/data/AugmentationNames";
|
import { AugmentationNames } from "../../Augmentation/data/AugmentationNames";
|
||||||
import { PurchasableAugmentations } from "../../Augmentation/ui/PurchasableAugmentations";
|
import { PurchasableAugmentations } from "../../Augmentation/ui/PurchasableAugmentations";
|
||||||
import { PurchaseAugmentationsOrderSetting } from "../../Settings/SettingEnums";
|
import { PurchaseAugmentationsOrderSetting } from "../../Settings/SettingEnums";
|
||||||
@ -54,13 +55,13 @@ export function AugmentationsPage(props: IProps): React.ReactElement {
|
|||||||
function getAugsSortedByCost(): string[] {
|
function getAugsSortedByCost(): string[] {
|
||||||
const augs = getAugs();
|
const augs = getAugs();
|
||||||
augs.sort((augName1, augName2) => {
|
augs.sort((augName1, augName2) => {
|
||||||
const aug1 = Augmentations[augName1],
|
const aug1 = StaticAugmentations[augName1],
|
||||||
aug2 = Augmentations[augName2];
|
aug2 = StaticAugmentations[augName2];
|
||||||
if (aug1 == null || aug2 == null) {
|
if (aug1 == null || aug2 == null) {
|
||||||
throw new Error("Invalid Augmentation Names");
|
throw new Error("Invalid Augmentation Names");
|
||||||
}
|
}
|
||||||
|
|
||||||
return aug1.baseCost - aug2.baseCost;
|
return aug1.getCost(player).moneyCost - aug2.getCost(player).moneyCost;
|
||||||
});
|
});
|
||||||
|
|
||||||
return augs;
|
return augs;
|
||||||
@ -69,31 +70,32 @@ export function AugmentationsPage(props: IProps): React.ReactElement {
|
|||||||
function getAugsSortedByPurchasable(): string[] {
|
function getAugsSortedByPurchasable(): string[] {
|
||||||
const augs = getAugs();
|
const augs = getAugs();
|
||||||
function canBuy(augName: string): boolean {
|
function canBuy(augName: string): boolean {
|
||||||
const aug = Augmentations[augName];
|
const aug = StaticAugmentations[augName];
|
||||||
const repCost = aug.baseRepRequirement;
|
const augCosts = aug.getCost(player);
|
||||||
|
const repCost = augCosts.repCost;
|
||||||
const hasReq = props.faction.playerReputation >= repCost;
|
const hasReq = props.faction.playerReputation >= repCost;
|
||||||
const hasRep = hasAugmentationPrereqs(aug);
|
const hasRep = hasAugmentationPrereqs(aug);
|
||||||
const hasCost = aug.baseCost !== 0 && player.money > aug.baseCost;
|
const hasCost = augCosts.moneyCost !== 0 && player.money > augCosts.moneyCost;
|
||||||
return hasCost && hasReq && hasRep;
|
return hasCost && hasReq && hasRep;
|
||||||
}
|
}
|
||||||
const buy = augs.filter(canBuy).sort((augName1, augName2) => {
|
const buy = augs.filter(canBuy).sort((augName1, augName2) => {
|
||||||
const aug1 = Augmentations[augName1],
|
const aug1 = StaticAugmentations[augName1],
|
||||||
aug2 = Augmentations[augName2];
|
aug2 = StaticAugmentations[augName2];
|
||||||
if (aug1 == null || aug2 == null) {
|
if (aug1 == null || aug2 == null) {
|
||||||
throw new Error("Invalid Augmentation Names");
|
throw new Error("Invalid Augmentation Names");
|
||||||
}
|
}
|
||||||
|
|
||||||
return aug1.baseCost - aug2.baseCost;
|
return aug1.getCost(player).moneyCost - aug2.getCost(player).moneyCost;
|
||||||
});
|
});
|
||||||
const cantBuy = augs
|
const cantBuy = augs
|
||||||
.filter((aug) => !canBuy(aug))
|
.filter((aug) => !canBuy(aug))
|
||||||
.sort((augName1, augName2) => {
|
.sort((augName1, augName2) => {
|
||||||
const aug1 = Augmentations[augName1],
|
const aug1 = StaticAugmentations[augName1],
|
||||||
aug2 = Augmentations[augName2];
|
aug2 = StaticAugmentations[augName2];
|
||||||
if (aug1 == null || aug2 == null) {
|
if (aug1 == null || aug2 == null) {
|
||||||
throw new Error("Invalid Augmentation Names");
|
throw new Error("Invalid Augmentation Names");
|
||||||
}
|
}
|
||||||
return aug1.baseRepRequirement - aug2.baseRepRequirement;
|
return aug1.getCost(player).repCost - aug2.getCost(player).repCost;
|
||||||
});
|
});
|
||||||
|
|
||||||
return buy.concat(cantBuy);
|
return buy.concat(cantBuy);
|
||||||
@ -102,12 +104,12 @@ export function AugmentationsPage(props: IProps): React.ReactElement {
|
|||||||
function getAugsSortedByReputation(): string[] {
|
function getAugsSortedByReputation(): string[] {
|
||||||
const augs = getAugs();
|
const augs = getAugs();
|
||||||
augs.sort((augName1, augName2) => {
|
augs.sort((augName1, augName2) => {
|
||||||
const aug1 = Augmentations[augName1],
|
const aug1 = StaticAugmentations[augName1],
|
||||||
aug2 = Augmentations[augName2];
|
aug2 = StaticAugmentations[augName2];
|
||||||
if (aug1 == null || aug2 == null) {
|
if (aug1 == null || aug2 == null) {
|
||||||
throw new Error("Invalid Augmentation Names");
|
throw new Error("Invalid Augmentation Names");
|
||||||
}
|
}
|
||||||
return aug1.baseRepRequirement - aug2.baseRepRequirement;
|
return aug1.getCost(player).repCost - aug2.getCost(player).repCost;
|
||||||
});
|
});
|
||||||
|
|
||||||
return augs;
|
return augs;
|
||||||
@ -143,7 +145,7 @@ export function AugmentationsPage(props: IProps): React.ReactElement {
|
|||||||
<>
|
<>
|
||||||
<Container disableGutters maxWidth="lg" sx={{ mx: 0 }}>
|
<Container disableGutters maxWidth="lg" sx={{ mx: 0 }}>
|
||||||
<Button onClick={props.routeToMainPage}>Back</Button>
|
<Button onClick={props.routeToMainPage}>Back</Button>
|
||||||
<Typography variant="h4">Faction Augmentations</Typography>
|
<Typography variant="h4">Faction Augmentations - {props.faction.name}</Typography>
|
||||||
<Paper sx={{ p: 1, mb: 1 }}>
|
<Paper sx={{ p: 1, mb: 1 }}>
|
||||||
<Typography>
|
<Typography>
|
||||||
These are all of the Augmentations that are available to purchase from <b>{props.faction.name}</b>.
|
These are all of the Augmentations that are available to purchase from <b>{props.faction.name}</b>.
|
||||||
@ -195,10 +197,11 @@ export function AugmentationsPage(props: IProps): React.ReactElement {
|
|||||||
ownedAugNames={owned}
|
ownedAugNames={owned}
|
||||||
player={player}
|
player={player}
|
||||||
canPurchase={(player, aug) => {
|
canPurchase={(player, aug) => {
|
||||||
|
const costs = aug.getCost(player);
|
||||||
return (
|
return (
|
||||||
hasAugmentationPrereqs(aug) &&
|
hasAugmentationPrereqs(aug) &&
|
||||||
props.faction.playerReputation >= aug.baseRepRequirement &&
|
props.faction.playerReputation >= costs.repCost &&
|
||||||
(aug.baseCost === 0 || player.money > aug.baseCost)
|
(costs.moneyCost === 0 || player.money > costs.moneyCost)
|
||||||
);
|
);
|
||||||
}}
|
}}
|
||||||
purchaseAugmentation={(player, aug, showModal) => {
|
purchaseAugmentation={(player, aug, showModal) => {
|
||||||
|
@ -189,9 +189,9 @@ export const GameOptionsSidebar = (props: IProps): React.ReactElement => {
|
|||||||
title={
|
title={
|
||||||
<Typography>
|
<Typography>
|
||||||
Forcefully kill all active running scripts, in case there is a bug or some unexpected issue with the game.
|
Forcefully kill all active running scripts, in case there is a bug or some unexpected issue with the game.
|
||||||
After using this, save the game and then reload the page. This is different then normal kill in that
|
After using this, save the game and then reload the page. This is different than normal kill in that
|
||||||
normal kill will tell the script to shut down while force kill just removes the references to it (and it
|
normal kill will tell the script to shut down while force kill just removes the references to it (and it
|
||||||
should crash on it's own). This will not remove the files on your computer. Just forcefully kill all
|
should crash on its own). This will not remove the files on your computer, just forcefully kill all
|
||||||
running instances of all scripts.
|
running instances of all scripts.
|
||||||
</Typography>
|
</Typography>
|
||||||
}
|
}
|
||||||
@ -210,7 +210,7 @@ export const GameOptionsSidebar = (props: IProps): React.ReactElement => {
|
|||||||
title={
|
title={
|
||||||
<Typography>
|
<Typography>
|
||||||
If your save file is extremely big you can use this button to view a map of all the files on every server.
|
If your save file is extremely big you can use this button to view a map of all the files on every server.
|
||||||
Be careful there might be spoilers.
|
Be careful: there might be spoilers.
|
||||||
</Typography>
|
</Typography>
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
|
@ -60,15 +60,22 @@ export function HacknetServerElem(props: IProps): React.ReactElement {
|
|||||||
multiplier = Math.min(levelsToMax, purchaseMult as number);
|
multiplier = Math.min(levelsToMax, purchaseMult as number);
|
||||||
}
|
}
|
||||||
|
|
||||||
const increase =
|
const base_increase =
|
||||||
calculateHashGainRate(node.level + multiplier, 0, node.maxRam, node.cores, props.player.hacknet_node_money_mult) -
|
calculateHashGainRate(node.level + multiplier, 0, node.maxRam, node.cores, props.player.hacknet_node_money_mult) -
|
||||||
node.hashRate;
|
calculateHashGainRate(node.level, 0, node.maxRam, node.cores, props.player.hacknet_node_money_mult);
|
||||||
|
const modded_increase = (base_increase * (node.maxRam - node.ramUsed)) / node.maxRam;
|
||||||
|
|
||||||
const upgradeLevelCost = node.calculateLevelUpgradeCost(multiplier, props.player.hacknet_node_level_cost_mult);
|
const upgradeLevelCost = node.calculateLevelUpgradeCost(multiplier, props.player.hacknet_node_level_cost_mult);
|
||||||
upgradeLevelButton = (
|
upgradeLevelButton = (
|
||||||
<Tooltip
|
<Tooltip
|
||||||
title={
|
title={
|
||||||
<Typography>
|
<Typography>
|
||||||
+<HashRate hashes={increase} />
|
+<HashRate hashes={modded_increase} /> (effective increase, taking current RAM usage into account)
|
||||||
|
<br />
|
||||||
|
<span style={{ opacity: 0.5 }}>
|
||||||
|
+<HashRate hashes={base_increase} />
|
||||||
|
</span>{" "}
|
||||||
|
(base increase, attained when no script is running)
|
||||||
</Typography>
|
</Typography>
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
@ -109,20 +116,36 @@ export function HacknetServerElem(props: IProps): React.ReactElement {
|
|||||||
multiplier = Math.min(levelsToMax, purchaseMult as number);
|
multiplier = Math.min(levelsToMax, purchaseMult as number);
|
||||||
}
|
}
|
||||||
|
|
||||||
const increase =
|
const base_increase =
|
||||||
calculateHashGainRate(
|
calculateHashGainRate(
|
||||||
node.level,
|
node.level,
|
||||||
0,
|
0,
|
||||||
node.maxRam * Math.pow(2, multiplier),
|
node.maxRam * Math.pow(2, multiplier),
|
||||||
node.cores,
|
node.cores,
|
||||||
props.player.hacknet_node_money_mult,
|
props.player.hacknet_node_money_mult,
|
||||||
) - node.hashRate;
|
) - calculateHashGainRate(node.level, 0, node.maxRam, node.cores, props.player.hacknet_node_money_mult);
|
||||||
|
|
||||||
|
const modded_increase =
|
||||||
|
calculateHashGainRate(
|
||||||
|
node.level,
|
||||||
|
node.ramUsed,
|
||||||
|
node.maxRam * Math.pow(2, multiplier),
|
||||||
|
node.cores,
|
||||||
|
props.player.hacknet_node_money_mult,
|
||||||
|
) -
|
||||||
|
calculateHashGainRate(node.level, node.ramUsed, node.maxRam, node.cores, props.player.hacknet_node_money_mult);
|
||||||
|
|
||||||
const upgradeRamCost = node.calculateRamUpgradeCost(multiplier, props.player.hacknet_node_ram_cost_mult);
|
const upgradeRamCost = node.calculateRamUpgradeCost(multiplier, props.player.hacknet_node_ram_cost_mult);
|
||||||
upgradeRamButton = (
|
upgradeRamButton = (
|
||||||
<Tooltip
|
<Tooltip
|
||||||
title={
|
title={
|
||||||
<Typography>
|
<Typography>
|
||||||
+<HashRate hashes={increase} />
|
+<HashRate hashes={modded_increase} /> (effective increase, taking current RAM usage into account)
|
||||||
|
<br />
|
||||||
|
<span style={{ opacity: 0.5 }}>
|
||||||
|
+<HashRate hashes={base_increase} />
|
||||||
|
</span>{" "}
|
||||||
|
(base increase, attained when no script is running)
|
||||||
</Typography>
|
</Typography>
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
@ -155,15 +178,22 @@ export function HacknetServerElem(props: IProps): React.ReactElement {
|
|||||||
multiplier = Math.min(levelsToMax, purchaseMult as number);
|
multiplier = Math.min(levelsToMax, purchaseMult as number);
|
||||||
}
|
}
|
||||||
|
|
||||||
const increase =
|
const base_increase =
|
||||||
calculateHashGainRate(node.level, 0, node.maxRam, node.cores + multiplier, props.player.hacknet_node_money_mult) -
|
calculateHashGainRate(node.level, 0, node.maxRam, node.cores + multiplier, props.player.hacknet_node_money_mult) -
|
||||||
node.hashRate;
|
calculateHashGainRate(node.level, 0, node.maxRam, node.cores, props.player.hacknet_node_money_mult);
|
||||||
|
const modded_increase = (base_increase * (node.maxRam - node.ramUsed)) / node.maxRam;
|
||||||
|
|
||||||
const upgradeCoreCost = node.calculateCoreUpgradeCost(multiplier, props.player.hacknet_node_core_cost_mult);
|
const upgradeCoreCost = node.calculateCoreUpgradeCost(multiplier, props.player.hacknet_node_core_cost_mult);
|
||||||
upgradeCoresButton = (
|
upgradeCoresButton = (
|
||||||
<Tooltip
|
<Tooltip
|
||||||
title={
|
title={
|
||||||
<Typography>
|
<Typography>
|
||||||
+<HashRate hashes={increase} />
|
+<HashRate hashes={modded_increase} /> (effective increase, taking current RAM usage into account)
|
||||||
|
<br />
|
||||||
|
<span style={{ opacity: 0.5 }}>
|
||||||
|
+<HashRate hashes={base_increase} />
|
||||||
|
</span>{" "}
|
||||||
|
(base increase, attained when no script is running)
|
||||||
</Typography>
|
</Typography>
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
@ -232,9 +262,31 @@ export function HacknetServerElem(props: IProps): React.ReactElement {
|
|||||||
<Typography>Production:</Typography>
|
<Typography>Production:</Typography>
|
||||||
</TableCell>
|
</TableCell>
|
||||||
<TableCell colSpan={2}>
|
<TableCell colSpan={2}>
|
||||||
<Typography>
|
<Tooltip
|
||||||
<Hashes hashes={node.totalHashesGenerated} /> (<HashRate hashes={node.hashRate} />)
|
title={
|
||||||
</Typography>
|
<Typography>
|
||||||
|
<Hashes hashes={node.totalHashesGenerated} /> hashes produced by this server since last augment
|
||||||
|
installation.
|
||||||
|
<br />
|
||||||
|
<HashRate hashes={node.hashRate} /> current production rate.
|
||||||
|
<br />
|
||||||
|
<span style={{ opacity: 0.5 }}>
|
||||||
|
<HashRate hashes={(node.hashRate * node.maxRam) / (node.maxRam - node.ramUsed)} />
|
||||||
|
</span>{" "}
|
||||||
|
max production rate. (achieved when 100% RAM is allocated to it)
|
||||||
|
<br />
|
||||||
|
{numeralWrapper.formatRAM(node.ramUsed)} / {numeralWrapper.formatRAM(node.maxRam)} (
|
||||||
|
{Math.round((100 * node.ramUsed) / node.maxRam)}%) RAM allocated to script.
|
||||||
|
<br />
|
||||||
|
{numeralWrapper.formatRAM(node.maxRam - node.ramUsed)} / {numeralWrapper.formatRAM(node.maxRam)} (
|
||||||
|
{Math.round((100 * (node.maxRam - node.ramUsed)) / node.maxRam)}%) RAM allocated to hash production.
|
||||||
|
</Typography>
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<Typography>
|
||||||
|
<Hashes hashes={node.totalHashesGenerated} /> (<HashRate hashes={node.hashRate} />)
|
||||||
|
</Typography>
|
||||||
|
</Tooltip>
|
||||||
</TableCell>
|
</TableCell>
|
||||||
</TableRow>
|
</TableRow>
|
||||||
<TableRow>
|
<TableRow>
|
||||||
|
@ -1,15 +1,14 @@
|
|||||||
|
import { Paper, Typography } from "@mui/material";
|
||||||
import React, { useState } from "react";
|
import React, { useState } from "react";
|
||||||
import Grid from "@mui/material/Grid";
|
import { AugmentationNames } from "../../Augmentation/data/AugmentationNames";
|
||||||
|
import { Player } from "../../Player";
|
||||||
|
import { KEY } from "../../utils/helpers/keyCodes";
|
||||||
|
import { random } from "../utils";
|
||||||
|
import { BlinkingCursor } from "./BlinkingCursor";
|
||||||
|
import { interpolate } from "./Difficulty";
|
||||||
|
import { GameTimer } from "./GameTimer";
|
||||||
import { IMinigameProps } from "./IMinigameProps";
|
import { IMinigameProps } from "./IMinigameProps";
|
||||||
import { KeyHandler } from "./KeyHandler";
|
import { KeyHandler } from "./KeyHandler";
|
||||||
import { GameTimer } from "./GameTimer";
|
|
||||||
import { random } from "../utils";
|
|
||||||
import { interpolate } from "./Difficulty";
|
|
||||||
import { BlinkingCursor } from "./BlinkingCursor";
|
|
||||||
import Typography from "@mui/material/Typography";
|
|
||||||
import { KEY } from "../../utils/helpers/keyCodes";
|
|
||||||
import { Player } from "../../Player";
|
|
||||||
import { AugmentationNames } from "../../Augmentation/data/AugmentationNames";
|
|
||||||
|
|
||||||
interface Difficulty {
|
interface Difficulty {
|
||||||
[key: string]: number;
|
[key: string]: number;
|
||||||
@ -48,24 +47,18 @@ export function BackwardGame(props: IMinigameProps): React.ReactElement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Grid container spacing={3}>
|
<>
|
||||||
<GameTimer millis={timer} onExpire={props.onFailure} />
|
<GameTimer millis={timer} onExpire={props.onFailure} />
|
||||||
<Grid item xs={12}>
|
<Paper sx={{ display: "grid", justifyItems: "center", pb: 1 }}>
|
||||||
<Typography variant="h4">Type it{!hasAugment ? " backward" : ""}</Typography>
|
<Typography variant="h4">Type it{!hasAugment ? " backward" : ""}</Typography>
|
||||||
<KeyHandler onKeyDown={press} onFailure={props.onFailure} />
|
<KeyHandler onKeyDown={press} onFailure={props.onFailure} />
|
||||||
</Grid>
|
<Typography style={{ transform: hasAugment ? "none" : "scaleX(-1)" }}>{answer}</Typography>
|
||||||
<Grid item xs={6}>
|
|
||||||
<Typography style={{ transform: hasAugment ? "none" : "scaleX(-1)", marginLeft: hasAugment ? "50%" : "none" }}>
|
|
||||||
{answer}
|
|
||||||
</Typography>
|
|
||||||
</Grid>
|
|
||||||
<Grid item xs={6}>
|
|
||||||
<Typography>
|
<Typography>
|
||||||
{guess}
|
{guess}
|
||||||
<BlinkingCursor />
|
<BlinkingCursor />
|
||||||
</Typography>
|
</Typography>
|
||||||
</Grid>
|
</Paper>
|
||||||
</Grid>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import React, { useState, useEffect } from "react";
|
import React, { useEffect, useState } from "react";
|
||||||
|
|
||||||
export function BlinkingCursor(): React.ReactElement {
|
export function BlinkingCursor(): React.ReactElement {
|
||||||
const [on, setOn] = useState(true);
|
const [on, setOn] = useState(true);
|
||||||
@ -6,5 +6,5 @@ export function BlinkingCursor(): React.ReactElement {
|
|||||||
const i = setInterval(() => setOn((old) => !old), 1000);
|
const i = setInterval(() => setOn((old) => !old), 1000);
|
||||||
return () => clearInterval(i);
|
return () => clearInterval(i);
|
||||||
});
|
});
|
||||||
return <>{on ? "|" : ""}</>;
|
return <>{on ? "|" : <> </>}</>;
|
||||||
}
|
}
|
||||||
|
@ -1,15 +1,14 @@
|
|||||||
|
import { Paper, Typography } from "@mui/material";
|
||||||
import React, { useState } from "react";
|
import React, { useState } from "react";
|
||||||
import Grid from "@mui/material/Grid";
|
import { AugmentationNames } from "../../Augmentation/data/AugmentationNames";
|
||||||
|
import { Player } from "../../Player";
|
||||||
|
import { KEY } from "../../utils/helpers/keyCodes";
|
||||||
|
import { random } from "../utils";
|
||||||
|
import { BlinkingCursor } from "./BlinkingCursor";
|
||||||
|
import { interpolate } from "./Difficulty";
|
||||||
|
import { GameTimer } from "./GameTimer";
|
||||||
import { IMinigameProps } from "./IMinigameProps";
|
import { IMinigameProps } from "./IMinigameProps";
|
||||||
import { KeyHandler } from "./KeyHandler";
|
import { KeyHandler } from "./KeyHandler";
|
||||||
import { GameTimer } from "./GameTimer";
|
|
||||||
import { random } from "../utils";
|
|
||||||
import { interpolate } from "./Difficulty";
|
|
||||||
import { BlinkingCursor } from "./BlinkingCursor";
|
|
||||||
import Typography from "@mui/material/Typography";
|
|
||||||
import { Player } from "../../Player";
|
|
||||||
import { AugmentationNames } from "../../Augmentation/data/AugmentationNames";
|
|
||||||
import { KEY } from "../../utils/helpers/keyCodes";
|
|
||||||
|
|
||||||
interface Difficulty {
|
interface Difficulty {
|
||||||
[key: string]: number;
|
[key: string]: number;
|
||||||
@ -84,16 +83,16 @@ export function BracketGame(props: IMinigameProps): React.ReactElement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Grid container spacing={3}>
|
<>
|
||||||
<GameTimer millis={timer} onExpire={props.onFailure} />
|
<GameTimer millis={timer} onExpire={props.onFailure} />
|
||||||
<Grid item xs={12}>
|
<Paper sx={{ display: "grid", justifyItems: "center" }}>
|
||||||
<Typography variant="h4">Close the brackets</Typography>
|
<Typography variant="h4">Close the brackets</Typography>
|
||||||
<Typography style={{ fontSize: "5em" }}>
|
<Typography style={{ fontSize: "5em" }}>
|
||||||
{`${left}${right}`}
|
{`${left}${right}`}
|
||||||
<BlinkingCursor />
|
<BlinkingCursor />
|
||||||
</Typography>
|
</Typography>
|
||||||
<KeyHandler onKeyDown={press} onFailure={props.onFailure} />
|
<KeyHandler onKeyDown={press} onFailure={props.onFailure} />
|
||||||
</Grid>
|
</Paper>
|
||||||
</Grid>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -1,15 +1,14 @@
|
|||||||
|
import { Paper, Typography } from "@mui/material";
|
||||||
import React, { useEffect, useState } from "react";
|
import React, { useEffect, useState } from "react";
|
||||||
import Grid from "@mui/material/Grid";
|
|
||||||
import { IMinigameProps } from "./IMinigameProps";
|
|
||||||
import { KeyHandler } from "./KeyHandler";
|
|
||||||
import { GameTimer } from "./GameTimer";
|
|
||||||
import { interpolate } from "./Difficulty";
|
|
||||||
import Typography from "@mui/material/Typography";
|
|
||||||
import { KEY } from "../../utils/helpers/keyCodes";
|
|
||||||
import { AugmentationNames } from "../../Augmentation/data/AugmentationNames";
|
import { AugmentationNames } from "../../Augmentation/data/AugmentationNames";
|
||||||
import { Player } from "../../Player";
|
import { Player } from "../../Player";
|
||||||
import { Settings } from "../../Settings/Settings";
|
import { Settings } from "../../Settings/Settings";
|
||||||
|
import { KEY } from "../../utils/helpers/keyCodes";
|
||||||
import { downArrowSymbol, upArrowSymbol } from "../utils";
|
import { downArrowSymbol, upArrowSymbol } from "../utils";
|
||||||
|
import { interpolate } from "./Difficulty";
|
||||||
|
import { GameTimer } from "./GameTimer";
|
||||||
|
import { IMinigameProps } from "./IMinigameProps";
|
||||||
|
import { KeyHandler } from "./KeyHandler";
|
||||||
|
|
||||||
interface Difficulty {
|
interface Difficulty {
|
||||||
[key: string]: number;
|
[key: string]: number;
|
||||||
@ -88,13 +87,11 @@ export function BribeGame(props: IMinigameProps): React.ReactElement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Grid container spacing={3}>
|
<>
|
||||||
<GameTimer millis={timer} onExpire={props.onFailure} />
|
<GameTimer millis={timer} onExpire={props.onFailure} />
|
||||||
<Grid item xs={12}>
|
<Paper sx={{ display: "grid", justifyItems: "center" }}>
|
||||||
<Typography variant="h4">Say something nice about the guard.</Typography>
|
<Typography variant="h4">Say something nice about the guard</Typography>
|
||||||
<KeyHandler onKeyDown={press} onFailure={props.onFailure} />
|
<KeyHandler onKeyDown={press} onFailure={props.onFailure} />
|
||||||
</Grid>
|
|
||||||
<Grid item xs={6}>
|
|
||||||
<Typography variant="h5" color={upColor}>
|
<Typography variant="h5" color={upColor}>
|
||||||
{upArrowSymbol}
|
{upArrowSymbol}
|
||||||
</Typography>
|
</Typography>
|
||||||
@ -104,8 +101,8 @@ export function BribeGame(props: IMinigameProps): React.ReactElement {
|
|||||||
<Typography variant="h5" color={downColor}>
|
<Typography variant="h5" color={downColor}>
|
||||||
{downArrowSymbol}
|
{downArrowSymbol}
|
||||||
</Typography>
|
</Typography>
|
||||||
</Grid>
|
</Paper>
|
||||||
</Grid>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -154,6 +151,7 @@ const positive = [
|
|||||||
"patient",
|
"patient",
|
||||||
"dynamic",
|
"dynamic",
|
||||||
"loyal",
|
"loyal",
|
||||||
|
"based",
|
||||||
];
|
];
|
||||||
|
|
||||||
const negative = [
|
const negative = [
|
||||||
@ -177,4 +175,5 @@ const negative = [
|
|||||||
"picky",
|
"picky",
|
||||||
"tactless",
|
"tactless",
|
||||||
"thoughtless",
|
"thoughtless",
|
||||||
|
"cringe",
|
||||||
];
|
];
|
||||||
|
@ -1,21 +1,20 @@
|
|||||||
|
import { Paper, Typography } from "@mui/material";
|
||||||
import React, { useState } from "react";
|
import React, { useState } from "react";
|
||||||
import Grid from "@mui/material/Grid";
|
import { AugmentationNames } from "../../Augmentation/data/AugmentationNames";
|
||||||
import { IMinigameProps } from "./IMinigameProps";
|
import { Player } from "../../Player";
|
||||||
import { KeyHandler } from "./KeyHandler";
|
|
||||||
import { GameTimer } from "./GameTimer";
|
|
||||||
import {
|
import {
|
||||||
random,
|
downArrowSymbol,
|
||||||
getArrow,
|
getArrow,
|
||||||
getInverseArrow,
|
getInverseArrow,
|
||||||
leftArrowSymbol,
|
leftArrowSymbol,
|
||||||
|
random,
|
||||||
rightArrowSymbol,
|
rightArrowSymbol,
|
||||||
upArrowSymbol,
|
upArrowSymbol,
|
||||||
downArrowSymbol,
|
|
||||||
} from "../utils";
|
} from "../utils";
|
||||||
import { interpolate } from "./Difficulty";
|
import { interpolate } from "./Difficulty";
|
||||||
import Typography from "@mui/material/Typography";
|
import { GameTimer } from "./GameTimer";
|
||||||
import { AugmentationNames } from "../../Augmentation/data/AugmentationNames";
|
import { IMinigameProps } from "./IMinigameProps";
|
||||||
import { Player } from "../../Player";
|
import { KeyHandler } from "./KeyHandler";
|
||||||
|
|
||||||
interface Difficulty {
|
interface Difficulty {
|
||||||
[key: string]: number;
|
[key: string]: number;
|
||||||
@ -55,14 +54,14 @@ export function CheatCodeGame(props: IMinigameProps): React.ReactElement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Grid container spacing={3}>
|
<>
|
||||||
<GameTimer millis={timer} onExpire={props.onFailure} />
|
<GameTimer millis={timer} onExpire={props.onFailure} />
|
||||||
<Grid item xs={12}>
|
<Paper sx={{ display: "grid", justifyItems: "center" }}>
|
||||||
<Typography variant="h4">Enter the Code!</Typography>
|
<Typography variant="h4">Enter the Code!</Typography>
|
||||||
<Typography variant="h4">{code[index]}</Typography>
|
<Typography variant="h4">{code[index]}</Typography>
|
||||||
<KeyHandler onKeyDown={press} onFailure={props.onFailure} />
|
<KeyHandler onKeyDown={press} onFailure={props.onFailure} />
|
||||||
</Grid>
|
</Paper>
|
||||||
</Grid>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
import React, { useState, useEffect } from "react";
|
import { Paper, Typography } from "@mui/material";
|
||||||
import Grid from "@mui/material/Grid";
|
import React, { useEffect, useState } from "react";
|
||||||
|
|
||||||
import Typography from "@mui/material/Typography";
|
|
||||||
interface IProps {
|
interface IProps {
|
||||||
onFinish: () => void;
|
onFinish: () => void;
|
||||||
}
|
}
|
||||||
@ -13,17 +12,13 @@ export function Countdown(props: IProps): React.ReactElement {
|
|||||||
props.onFinish();
|
props.onFinish();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
setTimeout(() => setX(x - 1), 200);
|
setTimeout(() => setX(x - 1), 300);
|
||||||
});
|
});
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<Paper sx={{ p: 1, textAlign: "center" }}>
|
||||||
<Grid container spacing={3}>
|
<Typography variant="h4">Get Ready!</Typography>
|
||||||
<Grid item xs={12}>
|
<Typography variant="h4">{x}</Typography>
|
||||||
<Typography variant="h4">Get Ready!</Typography>
|
</Paper>
|
||||||
<Typography variant="h4">{x}</Typography>
|
|
||||||
</Grid>
|
|
||||||
</Grid>
|
|
||||||
</>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -1,15 +1,14 @@
|
|||||||
|
import { Paper, Typography, Box } from "@mui/material";
|
||||||
import React, { useState } from "react";
|
import React, { useState } from "react";
|
||||||
import Grid from "@mui/material/Grid";
|
|
||||||
import { IMinigameProps } from "./IMinigameProps";
|
|
||||||
import { KeyHandler } from "./KeyHandler";
|
|
||||||
import { GameTimer } from "./GameTimer";
|
|
||||||
import { interpolate } from "./Difficulty";
|
|
||||||
import { downArrowSymbol, getArrow, leftArrowSymbol, rightArrowSymbol, upArrowSymbol } from "../utils";
|
|
||||||
import Typography from "@mui/material/Typography";
|
|
||||||
import { KEY } from "../../utils/helpers/keyCodes";
|
|
||||||
import { Settings } from "../../Settings/Settings";
|
|
||||||
import { AugmentationNames } from "../../Augmentation/data/AugmentationNames";
|
import { AugmentationNames } from "../../Augmentation/data/AugmentationNames";
|
||||||
import { Player } from "../../Player";
|
import { Player } from "../../Player";
|
||||||
|
import { Settings } from "../../Settings/Settings";
|
||||||
|
import { KEY } from "../../utils/helpers/keyCodes";
|
||||||
|
import { downArrowSymbol, getArrow, leftArrowSymbol, rightArrowSymbol, upArrowSymbol } from "../utils";
|
||||||
|
import { interpolate } from "./Difficulty";
|
||||||
|
import { GameTimer } from "./GameTimer";
|
||||||
|
import { IMinigameProps } from "./IMinigameProps";
|
||||||
|
import { KeyHandler } from "./KeyHandler";
|
||||||
|
|
||||||
interface Difficulty {
|
interface Difficulty {
|
||||||
[key: string]: number;
|
[key: string]: number;
|
||||||
@ -19,6 +18,12 @@ interface Difficulty {
|
|||||||
symbols: number;
|
symbols: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface GridItem {
|
||||||
|
content: string;
|
||||||
|
color: string;
|
||||||
|
selected?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
const difficulties: {
|
const difficulties: {
|
||||||
Trivial: Difficulty;
|
Trivial: Difficulty;
|
||||||
Normal: Difficulty;
|
Normal: Difficulty;
|
||||||
@ -76,18 +81,33 @@ export function Cyberpunk2077Game(props: IMinigameProps): React.ReactElement {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const flatGrid: GridItem[] = [];
|
||||||
|
grid.map((line, y) =>
|
||||||
|
line.map((cell, x) => {
|
||||||
|
const isCorrectAnswer = cell === answers[currentAnswerIndex];
|
||||||
|
const optionColor = hasAugment && !isCorrectAnswer ? Settings.theme.disabled : Settings.theme.primary;
|
||||||
|
|
||||||
|
if (x === pos[0] && y === pos[1]) {
|
||||||
|
flatGrid.push({ color: optionColor, content: cell, selected: true });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
flatGrid.push({ color: optionColor, content: cell });
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
const fontSize = "2em";
|
const fontSize = "2em";
|
||||||
return (
|
return (
|
||||||
<Grid container spacing={3}>
|
<>
|
||||||
<GameTimer millis={timer} onExpire={props.onFailure} />
|
<GameTimer millis={timer} onExpire={props.onFailure} />
|
||||||
<Grid item xs={12}>
|
<Paper sx={{ display: "grid", justifyItems: "center", pb: 1 }}>
|
||||||
<Typography variant="h4">Match the symbols!</Typography>
|
<Typography variant="h4">Match the symbols!</Typography>
|
||||||
<Typography variant="h5" color={Settings.theme.primary}>
|
<Typography variant="h5" color={Settings.theme.primary}>
|
||||||
Targets:{" "}
|
Targets:{" "}
|
||||||
{answers.map((a, i) => {
|
{answers.map((a, i) => {
|
||||||
if (i == currentAnswerIndex)
|
if (i == currentAnswerIndex)
|
||||||
return (
|
return (
|
||||||
<span key={`${i}`} style={{ fontSize: "1em", color: "blue" }}>
|
<span key={`${i}`} style={{ fontSize: "1em", color: Settings.theme.infolight }}>
|
||||||
{a}
|
{a}
|
||||||
</span>
|
</span>
|
||||||
);
|
);
|
||||||
@ -99,34 +119,30 @@ export function Cyberpunk2077Game(props: IMinigameProps): React.ReactElement {
|
|||||||
})}
|
})}
|
||||||
</Typography>
|
</Typography>
|
||||||
<br />
|
<br />
|
||||||
{grid.map((line, y) => (
|
<Box
|
||||||
<div key={y}>
|
sx={{
|
||||||
<Typography>
|
display: "grid",
|
||||||
{line.map((cell, x) => {
|
gridTemplateColumns: `repeat(${Math.round(difficulty.width)}, 1fr)`,
|
||||||
const isCorrectAnswer = cell === answers[currentAnswerIndex];
|
gap: 1,
|
||||||
|
}}
|
||||||
if (x == pos[0] && y == pos[1]) {
|
>
|
||||||
return (
|
{flatGrid.map((item) => (
|
||||||
<span key={`${x}${y}`} style={{ fontSize: fontSize, color: "blue" }}>
|
<Typography
|
||||||
{cell}
|
sx={{
|
||||||
</span>
|
fontSize: fontSize,
|
||||||
);
|
color: item.color,
|
||||||
}
|
border: item.selected ? `2px solid ${Settings.theme.infolight}` : "unset",
|
||||||
|
lineHeight: "unset",
|
||||||
const optionColor = hasAugment && !isCorrectAnswer ? Settings.theme.disabled : Settings.theme.primary;
|
p: item.selected ? "2px" : "4px",
|
||||||
return (
|
}}
|
||||||
<span key={`${x}${y}`} style={{ fontSize: fontSize, color: optionColor }}>
|
>
|
||||||
{cell}
|
{item.content}
|
||||||
</span>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
</Typography>
|
</Typography>
|
||||||
<br />
|
))}
|
||||||
</div>
|
</Box>
|
||||||
))}
|
|
||||||
<KeyHandler onKeyDown={press} onFailure={props.onFailure} />
|
<KeyHandler onKeyDown={press} onFailure={props.onFailure} />
|
||||||
</Grid>
|
</Paper>
|
||||||
</Grid>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,19 +1,17 @@
|
|||||||
import { use } from "../../ui/Context";
|
import { Button, Container, Paper, Typography } from "@mui/material";
|
||||||
import React, { useState } from "react";
|
import React, { useState } from "react";
|
||||||
import Grid from "@mui/material/Grid";
|
import { AugmentationNames } from "../../Augmentation/data/AugmentationNames";
|
||||||
import Button from "@mui/material/Button";
|
import { use } from "../../ui/Context";
|
||||||
import { Countdown } from "./Countdown";
|
|
||||||
import { BracketGame } from "./BracketGame";
|
|
||||||
import { SlashGame } from "./SlashGame";
|
|
||||||
import { BackwardGame } from "./BackwardGame";
|
import { BackwardGame } from "./BackwardGame";
|
||||||
|
import { BracketGame } from "./BracketGame";
|
||||||
import { BribeGame } from "./BribeGame";
|
import { BribeGame } from "./BribeGame";
|
||||||
import { CheatCodeGame } from "./CheatCodeGame";
|
import { CheatCodeGame } from "./CheatCodeGame";
|
||||||
|
import { Countdown } from "./Countdown";
|
||||||
import { Cyberpunk2077Game } from "./Cyberpunk2077Game";
|
import { Cyberpunk2077Game } from "./Cyberpunk2077Game";
|
||||||
import { MinesweeperGame } from "./MinesweeperGame";
|
import { MinesweeperGame } from "./MinesweeperGame";
|
||||||
import { WireCuttingGame } from "./WireCuttingGame";
|
import { SlashGame } from "./SlashGame";
|
||||||
import { Victory } from "./Victory";
|
import { Victory } from "./Victory";
|
||||||
import Typography from "@mui/material/Typography";
|
import { WireCuttingGame } from "./WireCuttingGame";
|
||||||
import { AugmentationNames } from "../../Augmentation/data/AugmentationNames";
|
|
||||||
|
|
||||||
interface IProps {
|
interface IProps {
|
||||||
StartingDifficulty: number;
|
StartingDifficulty: number;
|
||||||
@ -139,22 +137,20 @@ export function Game(props: IProps): React.ReactElement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<Container>
|
||||||
<Grid container spacing={3}>
|
<Paper sx={{ p: 1, mb: 1, display: "grid", justifyItems: "center", gap: 1 }}>
|
||||||
<Grid item xs={3}>
|
{stage !== Stage.Sell && (
|
||||||
<Button onClick={cancel}>Cancel</Button>
|
<Button sx={{ width: "100%" }} onClick={cancel}>
|
||||||
</Grid>
|
Cancel Infiltration
|
||||||
<Grid item xs={3}>
|
</Button>
|
||||||
<Typography>
|
)}
|
||||||
Level: {level} / {props.MaxLevel}
|
<Typography variant="h5">
|
||||||
</Typography>
|
Level {level} / {props.MaxLevel}
|
||||||
<Progress />
|
</Typography>
|
||||||
</Grid>
|
<Progress />
|
||||||
|
</Paper>
|
||||||
|
|
||||||
<Grid item xs={12}>
|
{stageComponent}
|
||||||
{stageComponent}
|
</Container>
|
||||||
</Grid>
|
|
||||||
</Grid>
|
|
||||||
</>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -1,24 +1,13 @@
|
|||||||
import LinearProgress from "@mui/material/LinearProgress";
|
import { Paper } from "@mui/material";
|
||||||
import React, { useState, useEffect } from "react";
|
import React, { useEffect, useState } from "react";
|
||||||
import withStyles from "@mui/styles/withStyles";
|
|
||||||
import { Theme } from "@mui/material/styles";
|
|
||||||
import Grid from "@mui/material/Grid";
|
|
||||||
import { use } from "../../ui/Context";
|
|
||||||
import { AugmentationNames } from "../../Augmentation/data/AugmentationNames";
|
import { AugmentationNames } from "../../Augmentation/data/AugmentationNames";
|
||||||
|
import { use } from "../../ui/Context";
|
||||||
const TimerProgress = withStyles((theme: Theme) => ({
|
import { ProgressBar } from "../../ui/React/Progress";
|
||||||
root: {
|
|
||||||
backgroundColor: theme.palette.background.paper,
|
|
||||||
},
|
|
||||||
bar: {
|
|
||||||
transition: "none",
|
|
||||||
backgroundColor: theme.palette.primary.main,
|
|
||||||
},
|
|
||||||
}))(LinearProgress);
|
|
||||||
|
|
||||||
interface IProps {
|
interface IProps {
|
||||||
millis: number;
|
millis: number;
|
||||||
onExpire: () => void;
|
onExpire: () => void;
|
||||||
|
noPaper?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function GameTimer(props: IProps): React.ReactElement {
|
export function GameTimer(props: IProps): React.ReactElement {
|
||||||
@ -42,9 +31,11 @@ export function GameTimer(props: IProps): React.ReactElement {
|
|||||||
// https://stackoverflow.com/questions/55593367/disable-material-uis-linearprogress-animation
|
// https://stackoverflow.com/questions/55593367/disable-material-uis-linearprogress-animation
|
||||||
// TODO(hydroflame): there's like a bug where it triggers the end before the
|
// TODO(hydroflame): there's like a bug where it triggers the end before the
|
||||||
// bar physically reaches the end
|
// bar physically reaches the end
|
||||||
return (
|
return props.noPaper ? (
|
||||||
<Grid item xs={12}>
|
<ProgressBar variant="determinate" value={v} color="primary" />
|
||||||
<TimerProgress variant="determinate" value={v} color="primary" />
|
) : (
|
||||||
</Grid>
|
<Paper sx={{ p: 1, mb: 1 }}>
|
||||||
|
<ProgressBar variant="determinate" value={v} color="primary" />
|
||||||
|
</Paper>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
import React, { useState } from "react";
|
import React, { useState } from "react";
|
||||||
import { Intro } from "./Intro";
|
|
||||||
import { Game } from "./Game";
|
|
||||||
import { Location } from "../../Locations/Location";
|
import { Location } from "../../Locations/Location";
|
||||||
import { use } from "../../ui/Context";
|
import { use } from "../../ui/Context";
|
||||||
import { calculateDifficulty, calculateReward } from "../formulas/game";
|
import { calculateDifficulty, calculateReward } from "../formulas/game";
|
||||||
|
import { Game } from "./Game";
|
||||||
|
import { Intro } from "./Intro";
|
||||||
interface IProps {
|
interface IProps {
|
||||||
location: Location;
|
location: Location;
|
||||||
}
|
}
|
||||||
@ -22,24 +22,24 @@ export function InfiltrationRoot(props: IProps): React.ReactElement {
|
|||||||
router.toCity();
|
router.toCity();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!start) {
|
|
||||||
return (
|
|
||||||
<Intro
|
|
||||||
Location={props.location}
|
|
||||||
Difficulty={difficulty}
|
|
||||||
MaxLevel={props.location.infiltrationData.maxClearanceLevel}
|
|
||||||
start={() => setStart(true)}
|
|
||||||
cancel={cancel}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Game
|
<div style={{ display: "flex", alignItems: "center", height: "calc(100vh - 16px)" }}>
|
||||||
StartingDifficulty={startingSecurityLevel}
|
{start ? (
|
||||||
Difficulty={difficulty}
|
<Game
|
||||||
Reward={reward}
|
StartingDifficulty={startingSecurityLevel}
|
||||||
MaxLevel={props.location.infiltrationData.maxClearanceLevel}
|
Difficulty={difficulty}
|
||||||
/>
|
Reward={reward}
|
||||||
|
MaxLevel={props.location.infiltrationData.maxClearanceLevel}
|
||||||
|
/>
|
||||||
|
) : (
|
||||||
|
<Intro
|
||||||
|
Location={props.location}
|
||||||
|
Difficulty={difficulty}
|
||||||
|
MaxLevel={props.location.infiltrationData.maxClearanceLevel}
|
||||||
|
start={() => setStart(true)}
|
||||||
|
cancel={cancel}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
|
import { Report } from "@mui/icons-material";
|
||||||
|
import { Box, Button, Container, Paper, Tooltip, Typography } from "@mui/material";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { Location } from "../../Locations/Location";
|
import { Location } from "../../Locations/Location";
|
||||||
import Grid from "@mui/material/Grid";
|
import { Settings } from "../../Settings/Settings";
|
||||||
import Typography from "@mui/material/Typography";
|
|
||||||
import Button from "@mui/material/Button";
|
|
||||||
import { numeralWrapper } from "../../ui/numeralFormat";
|
import { numeralWrapper } from "../../ui/numeralFormat";
|
||||||
|
|
||||||
interface IProps {
|
interface IProps {
|
||||||
@ -41,9 +41,9 @@ function coloredArrow(difficulty: number): JSX.Element {
|
|||||||
} else {
|
} else {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{arrowPart("white", difficulty * 13)}
|
{arrowPart(Settings.theme.primary, difficulty * 13)}
|
||||||
{arrowPart("orange", (difficulty - 1) * 13)}
|
{arrowPart(Settings.theme.warning, (difficulty - 1) * 13)}
|
||||||
{arrowPart("red", (difficulty - 2) * 13)}
|
{arrowPart(Settings.theme.error, (difficulty - 2) * 13)}
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -51,65 +51,84 @@ function coloredArrow(difficulty: number): JSX.Element {
|
|||||||
|
|
||||||
export function Intro(props: IProps): React.ReactElement {
|
export function Intro(props: IProps): React.ReactElement {
|
||||||
return (
|
return (
|
||||||
<>
|
<Container sx={{ alignItems: "center" }}>
|
||||||
<Grid container spacing={3}>
|
<Paper sx={{ p: 1, mb: 1, display: "grid", justifyItems: "center" }}>
|
||||||
<Grid item xs={10}>
|
<Typography variant="h4">
|
||||||
<Typography variant="h4">Infiltrating {props.Location.name}</Typography>
|
Infiltrating <b>{props.Location.name}</b>
|
||||||
</Grid>
|
</Typography>
|
||||||
<Grid item xs={10}>
|
<Typography variant="h6">
|
||||||
<Typography variant="h5" color="primary">
|
<b>Maximum Level: </b>
|
||||||
Maximum level: {props.MaxLevel}
|
{props.MaxLevel}
|
||||||
</Typography>
|
</Typography>
|
||||||
</Grid>
|
<Typography
|
||||||
<Grid item xs={10}>
|
variant="h6"
|
||||||
<Typography variant="h5" color="primary">
|
sx={{
|
||||||
Difficulty: {numeralWrapper.format(props.Difficulty * 33.3333, "0")} / 100
|
color:
|
||||||
</Typography>
|
props.Difficulty > 2
|
||||||
</Grid>
|
? Settings.theme.error
|
||||||
|
: props.Difficulty > 1
|
||||||
|
? Settings.theme.warning
|
||||||
|
: Settings.theme.primary,
|
||||||
|
display: "flex",
|
||||||
|
alignItems: "center",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<b>Difficulty: </b>
|
||||||
|
{numeralWrapper.format(props.Difficulty * 33.3333, "0")} / 100
|
||||||
|
{props.Difficulty > 1.5 && (
|
||||||
|
<Tooltip
|
||||||
|
title={
|
||||||
|
<Typography color="error">
|
||||||
|
This location is too heavily guarded for your current stats. It is recommended that you try training,
|
||||||
|
or finding an easier location.
|
||||||
|
</Typography>
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<Report sx={{ ml: 1 }} />
|
||||||
|
</Tooltip>
|
||||||
|
)}
|
||||||
|
</Typography>
|
||||||
|
|
||||||
{props.Difficulty > 1.5 && (
|
<Typography sx={{ lineHeight: "1em", whiteSpace: "pre" }}>[{coloredArrow(props.Difficulty)}]</Typography>
|
||||||
<Grid item xs={10}>
|
<Typography
|
||||||
<Typography variant="h5" color="primary">
|
sx={{ lineHeight: "1em", whiteSpace: "pre" }}
|
||||||
Warning: This location is too heavily guarded for your current stats, try training or finding an easier
|
>{`▲ ▲ ▲ ▲`}</Typography>
|
||||||
location.
|
<Typography
|
||||||
</Typography>
|
sx={{ lineHeight: "1em", whiteSpace: "pre" }}
|
||||||
</Grid>
|
>{` Trivial Normal Hard Impossible`}</Typography>
|
||||||
)}
|
</Paper>
|
||||||
|
|
||||||
<Grid item xs={10}>
|
<Paper sx={{ p: 1, display: "grid", justifyItems: "center" }}>
|
||||||
<Typography sx={{ lineHeight: "1em", whiteSpace: "pre" }}>[{coloredArrow(props.Difficulty)}]</Typography>
|
<Typography sx={{ width: "75%", textAlign: "center" }}>
|
||||||
<Typography
|
<b>Infiltration</b> is a series of short minigames that get progressively harder. You take damage for failing
|
||||||
sx={{ lineHeight: "1em", whiteSpace: "pre" }}
|
them. Reaching the maximum level rewards you with intel that you can trade for money or reputation.
|
||||||
>{` ^ ^ ^ ^`}</Typography>
|
<br />
|
||||||
<Typography
|
<br />
|
||||||
sx={{ lineHeight: "1em", whiteSpace: "pre" }}
|
<b>Gameplay:</b>
|
||||||
>{` Trivial Normal Hard Impossible`}</Typography>
|
</Typography>
|
||||||
</Grid>
|
<ul>
|
||||||
<Grid item xs={10}>
|
|
||||||
<Typography>
|
<Typography>
|
||||||
Infiltration is a series of short minigames that get progressively harder. You take damage for failing them.
|
<li>
|
||||||
Reaching the maximum level rewards you with intel you can trade for money or reputation.
|
The minigames you play are randomly selected.
|
||||||
|
<br />
|
||||||
|
It might take you a few tries to get used to them.
|
||||||
|
</li>
|
||||||
|
<li>No game requires use of the mouse.</li>
|
||||||
|
<li>
|
||||||
|
<b>Spacebar</b> is the default action/confirm button.
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
The <b>arrow keys</b> and <b>WASD</b> can be used interchangeably.
|
||||||
|
</li>
|
||||||
|
<li>Sometimes the rest of the keyboard is used.</li>
|
||||||
</Typography>
|
</Typography>
|
||||||
<br />
|
</ul>
|
||||||
<Typography>
|
|
||||||
The minigames you play are randomly selected. It might take you few tries to get used to them.
|
<Box sx={{ display: "grid", gridTemplateColumns: "1fr 1fr", width: "100%" }}>
|
||||||
</Typography>
|
|
||||||
<br />
|
|
||||||
<Typography>No game require use of the mouse.</Typography>
|
|
||||||
<br />
|
|
||||||
<Typography>Spacebar is the default action/confirm button.</Typography>
|
|
||||||
<br />
|
|
||||||
<Typography>Everything that uses arrow can also use WASD</Typography>
|
|
||||||
<br />
|
|
||||||
<Typography>Sometimes the rest of the keyboard is used.</Typography>
|
|
||||||
</Grid>
|
|
||||||
<Grid item xs={3}>
|
|
||||||
<Button onClick={props.start}>Start</Button>
|
<Button onClick={props.start}>Start</Button>
|
||||||
</Grid>
|
|
||||||
<Grid item xs={3}>
|
|
||||||
<Button onClick={props.cancel}>Cancel</Button>
|
<Button onClick={props.cancel}>Cancel</Button>
|
||||||
</Grid>
|
</Box>
|
||||||
</Grid>
|
</Paper>
|
||||||
</>
|
</Container>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -1,14 +1,16 @@
|
|||||||
import React, { useState, useEffect } from "react";
|
import { Close, Flag, Report } from "@mui/icons-material";
|
||||||
import Grid from "@mui/material/Grid";
|
import { Box, Paper, Typography } from "@mui/material";
|
||||||
import { IMinigameProps } from "./IMinigameProps";
|
import { uniqueId } from "lodash";
|
||||||
import { KeyHandler } from "./KeyHandler";
|
import React, { useEffect, useState } from "react";
|
||||||
import { GameTimer } from "./GameTimer";
|
|
||||||
import { interpolate } from "./Difficulty";
|
|
||||||
import { downArrowSymbol, getArrow, leftArrowSymbol, rightArrowSymbol, upArrowSymbol } from "../utils";
|
|
||||||
import Typography from "@mui/material/Typography";
|
|
||||||
import { KEY } from "../../utils/helpers/keyCodes";
|
|
||||||
import { AugmentationNames } from "../../Augmentation/data/AugmentationNames";
|
import { AugmentationNames } from "../../Augmentation/data/AugmentationNames";
|
||||||
import { Player } from "../../Player";
|
import { Player } from "../../Player";
|
||||||
|
import { Settings } from "../../Settings/Settings";
|
||||||
|
import { KEY } from "../../utils/helpers/keyCodes";
|
||||||
|
import { downArrowSymbol, getArrow, leftArrowSymbol, rightArrowSymbol, upArrowSymbol } from "../utils";
|
||||||
|
import { interpolate } from "./Difficulty";
|
||||||
|
import { GameTimer } from "./GameTimer";
|
||||||
|
import { IMinigameProps } from "./IMinigameProps";
|
||||||
|
import { KeyHandler } from "./KeyHandler";
|
||||||
|
|
||||||
interface Difficulty {
|
interface Difficulty {
|
||||||
[key: string]: number;
|
[key: string]: number;
|
||||||
@ -81,32 +83,77 @@ export function MinesweeperGame(props: IMinigameProps): React.ReactElement {
|
|||||||
return () => clearInterval(id);
|
return () => clearInterval(id);
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
const flatGrid: { flagged?: boolean; current?: boolean; marked?: boolean }[] = [];
|
||||||
|
|
||||||
|
minefield.map((line, y) =>
|
||||||
|
line.map((cell, x) => {
|
||||||
|
if (memoryPhase) {
|
||||||
|
flatGrid.push({ flagged: Boolean(minefield[y][x]) });
|
||||||
|
return;
|
||||||
|
} else if (x === pos[0] && y === pos[1]) {
|
||||||
|
flatGrid.push({ current: true });
|
||||||
|
} else if (answer[y][x]) {
|
||||||
|
flatGrid.push({ marked: true });
|
||||||
|
} else if (hasAugment && minefield[y][x]) {
|
||||||
|
flatGrid.push({ flagged: true });
|
||||||
|
} else {
|
||||||
|
flatGrid.push({});
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Grid container spacing={3}>
|
<>
|
||||||
<GameTimer millis={timer} onExpire={props.onFailure} />
|
<GameTimer millis={timer} onExpire={props.onFailure} />
|
||||||
<Grid item xs={12}>
|
<Paper sx={{ display: "grid", justifyItems: "center", pb: 1 }}>
|
||||||
<Typography variant="h4">{memoryPhase ? "Remember all the mines!" : "Mark all the mines!"}</Typography>
|
<Typography variant="h4">{memoryPhase ? "Remember all the mines!" : "Mark all the mines!"}</Typography>
|
||||||
{minefield.map((line, y) => (
|
<Box
|
||||||
<div key={y}>
|
sx={{
|
||||||
<Typography>
|
display: "grid",
|
||||||
{line.map((cell, x) => {
|
gridTemplateColumns: `repeat(${Math.round(difficulty.width)}, 1fr)`,
|
||||||
if (memoryPhase) {
|
gridTemplateRows: `repeat(${Math.round(difficulty.height)}, 1fr)`,
|
||||||
if (minefield[y][x]) return <span key={x}>[?] </span>;
|
gap: 1,
|
||||||
return <span key={x}>[ ] </span>;
|
}}
|
||||||
} else {
|
>
|
||||||
if (x == pos[0] && y == pos[1]) return <span key={x}>[X] </span>;
|
{flatGrid.map((item) => {
|
||||||
if (answer[y][x]) return <span key={x}>[.] </span>;
|
let color: string;
|
||||||
if (hasAugment && minefield[y][x]) return <span key={x}>[?] </span>;
|
let icon: React.ReactElement;
|
||||||
return <span key={x}>[ ] </span>;
|
|
||||||
}
|
if (item.marked) {
|
||||||
})}
|
color = Settings.theme.warning;
|
||||||
</Typography>
|
icon = <Flag />;
|
||||||
<br />
|
} else if (item.current) {
|
||||||
</div>
|
color = Settings.theme.infolight;
|
||||||
))}
|
icon = <Close />;
|
||||||
|
} else if (item.flagged) {
|
||||||
|
color = Settings.theme.error;
|
||||||
|
icon = <Report />;
|
||||||
|
} else {
|
||||||
|
color = Settings.theme.primary;
|
||||||
|
icon = <></>;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Typography
|
||||||
|
key={`${item}${uniqueId()}`}
|
||||||
|
sx={{
|
||||||
|
color: color,
|
||||||
|
border: `2px solid ${item.current ? Settings.theme.infolight : Settings.theme.primary}`,
|
||||||
|
height: "32px",
|
||||||
|
width: "32px",
|
||||||
|
display: "flex",
|
||||||
|
alignItems: "center",
|
||||||
|
justifyContent: "center",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{icon}
|
||||||
|
</Typography>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</Box>
|
||||||
<KeyHandler onKeyDown={press} onFailure={props.onFailure} />
|
<KeyHandler onKeyDown={press} onFailure={props.onFailure} />
|
||||||
</Grid>
|
</Paper>
|
||||||
</Grid>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,13 +1,12 @@
|
|||||||
import React, { useState, useEffect } from "react";
|
import { Box, Paper, Typography } from "@mui/material";
|
||||||
import Grid from "@mui/material/Grid";
|
import React, { useEffect, useState } from "react";
|
||||||
|
import { AugmentationNames } from "../../Augmentation/data/AugmentationNames";
|
||||||
|
import { Player } from "../../Player";
|
||||||
|
import { KEY } from "../../utils/helpers/keyCodes";
|
||||||
|
import { interpolate } from "./Difficulty";
|
||||||
|
import { GameTimer } from "./GameTimer";
|
||||||
import { IMinigameProps } from "./IMinigameProps";
|
import { IMinigameProps } from "./IMinigameProps";
|
||||||
import { KeyHandler } from "./KeyHandler";
|
import { KeyHandler } from "./KeyHandler";
|
||||||
import { GameTimer } from "./GameTimer";
|
|
||||||
import { interpolate } from "./Difficulty";
|
|
||||||
import Typography from "@mui/material/Typography";
|
|
||||||
import { KEY } from "../../utils/helpers/keyCodes";
|
|
||||||
import { Player } from "../../Player";
|
|
||||||
import { AugmentationNames } from "../../Augmentation/data/AugmentationNames";
|
|
||||||
|
|
||||||
interface Difficulty {
|
interface Difficulty {
|
||||||
[key: string]: number;
|
[key: string]: number;
|
||||||
@ -59,23 +58,25 @@ export function SlashGame(props: IMinigameProps): React.ReactElement {
|
|||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Grid container spacing={3}>
|
<>
|
||||||
<GameTimer millis={5000} onExpire={props.onFailure} />
|
<GameTimer millis={5000} onExpire={props.onFailure} />
|
||||||
<Grid item xs={12}>
|
<Paper sx={{ display: "grid", justifyItems: "center" }}>
|
||||||
<Typography variant="h4">Slash when his guard is down!</Typography>
|
<Typography variant="h4">Slash when his guard is down!</Typography>
|
||||||
|
|
||||||
{hasAugment ? (
|
{hasAugment ? (
|
||||||
<>
|
<Box sx={{ my: 1 }}>
|
||||||
<Typography variant="h4">Guard will drop in...</Typography>
|
<Typography variant="h5">Guard will drop in...</Typography>
|
||||||
<GameTimer millis={timeUntilAttacking} onExpire={props.onFailure} />
|
<GameTimer millis={timeUntilAttacking} onExpire={() => null} noPaper />
|
||||||
</>
|
</Box>
|
||||||
) : (
|
) : (
|
||||||
<></>
|
<></>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{phase === 0 && <Typography variant="h4">Guarding ...</Typography>}
|
{phase === 0 && <Typography variant="h4">Guarding ...</Typography>}
|
||||||
{phase === 1 && <Typography variant="h4">Preparing?</Typography>}
|
{phase === 1 && <Typography variant="h4">Preparing?</Typography>}
|
||||||
{phase === 2 && <Typography variant="h4">ATTACKING!</Typography>}
|
{phase === 2 && <Typography variant="h4">ATTACKING!</Typography>}
|
||||||
<KeyHandler onKeyDown={press} onFailure={props.onFailure} />
|
<KeyHandler onKeyDown={press} onFailure={props.onFailure} />
|
||||||
</Grid>
|
</Paper>
|
||||||
</Grid>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -1,21 +1,17 @@
|
|||||||
import { Factions } from "../../Faction/Factions";
|
import { Box, Button, MenuItem, Paper, Select, SelectChangeEvent, Typography } from "@mui/material";
|
||||||
import React, { useState } from "react";
|
import React, { useState } from "react";
|
||||||
import Grid from "@mui/material/Grid";
|
import { FactionNames } from "../../Faction/data/FactionNames";
|
||||||
|
import { inviteToFaction } from "../../Faction/FactionHelpers";
|
||||||
|
import { Factions } from "../../Faction/Factions";
|
||||||
|
import { use } from "../../ui/Context";
|
||||||
import { Money } from "../../ui/React/Money";
|
import { Money } from "../../ui/React/Money";
|
||||||
import { Reputation } from "../../ui/React/Reputation";
|
import { Reputation } from "../../ui/React/Reputation";
|
||||||
import { use } from "../../ui/Context";
|
|
||||||
import Typography from "@mui/material/Typography";
|
|
||||||
import Button from "@mui/material/Button";
|
|
||||||
import MenuItem from "@mui/material/MenuItem";
|
|
||||||
import Select, { SelectChangeEvent } from "@mui/material/Select";
|
|
||||||
import { FactionNames } from "../../Faction/data/FactionNames";
|
|
||||||
import { formatNumber } from "../../utils/StringHelperFunctions";
|
import { formatNumber } from "../../utils/StringHelperFunctions";
|
||||||
import {
|
import {
|
||||||
calculateInfiltratorsRepReward,
|
calculateInfiltratorsRepReward,
|
||||||
calculateSellInformationCashReward,
|
calculateSellInformationCashReward,
|
||||||
calculateTradeInformationRepReward,
|
calculateTradeInformationRepReward,
|
||||||
} from "../formulas/victory";
|
} from "../formulas/victory";
|
||||||
import { inviteToFaction } from "../../Faction/FactionHelpers";
|
|
||||||
|
|
||||||
interface IProps {
|
interface IProps {
|
||||||
StartingDifficulty: number;
|
StartingDifficulty: number;
|
||||||
@ -66,24 +62,22 @@ export function Victory(props: IProps): React.ReactElement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<Paper sx={{ p: 1, textAlign: "center", display: "flex", alignItems: "center", flexDirection: "column" }}>
|
||||||
<Grid container spacing={3}>
|
<Typography variant="h4">Infiltration successful!</Typography>
|
||||||
<Grid item xs={10}>
|
<Typography variant="h5" color="primary" width="75%">
|
||||||
<Typography variant="h4">Infiltration successful!</Typography>
|
You{" "}
|
||||||
</Grid>
|
{isMemberOfInfiltrators ? (
|
||||||
<Grid item xs={10}>
|
<>
|
||||||
<Typography variant="h5" color="primary">
|
have gained {formatNumber(infiltrationRepGain, 2)} rep for {FactionNames.ShadowsOfAnarchy} and{" "}
|
||||||
You{" "}
|
</>
|
||||||
{isMemberOfInfiltrators ? (
|
) : (
|
||||||
<>
|
<></>
|
||||||
have gained {formatNumber(infiltrationRepGain, 2)} rep for {FactionNames.ShadowsOfAnarchy} and{" "}
|
)}
|
||||||
</>
|
can trade the confidential information you found for money or reputation.
|
||||||
) : (
|
</Typography>
|
||||||
<></>
|
<Box sx={{ width: "fit-content" }}>
|
||||||
)}
|
<Box sx={{ width: "100%" }}>
|
||||||
can trade the confidential information you found for money or reputation.
|
<Select value={faction} onChange={changeDropdown} sx={{ mr: 1 }}>
|
||||||
</Typography>
|
|
||||||
<Select value={faction} onChange={changeDropdown}>
|
|
||||||
<MenuItem key={"none"} value={"none"}>
|
<MenuItem key={"none"} value={"none"}>
|
||||||
{"none"}
|
{"none"}
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
@ -98,17 +92,15 @@ export function Victory(props: IProps): React.ReactElement {
|
|||||||
<Button onClick={trade}>
|
<Button onClick={trade}>
|
||||||
Trade for <Reputation reputation={repGain} /> reputation
|
Trade for <Reputation reputation={repGain} /> reputation
|
||||||
</Button>
|
</Button>
|
||||||
</Grid>
|
</Box>
|
||||||
<Grid item xs={3}>
|
<Button onClick={sell} sx={{ width: "100%" }}>
|
||||||
<Button onClick={sell}>
|
Sell for
|
||||||
Sell for
|
<Money money={moneyGain} />
|
||||||
<Money money={moneyGain} />
|
</Button>
|
||||||
</Button>
|
</Box>
|
||||||
</Grid>
|
<Button onClick={quitInfiltration} sx={{ width: "100%", mt: 1 }}>
|
||||||
<Grid item xs={3}>
|
Quit
|
||||||
<Button onClick={quitInfiltration}>Quit</Button>
|
</Button>
|
||||||
</Grid>
|
</Paper>
|
||||||
</Grid>
|
|
||||||
</>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -1,15 +1,14 @@
|
|||||||
|
import { Box, Paper, Typography } from "@mui/material";
|
||||||
import React, { useEffect, useState } from "react";
|
import React, { useEffect, useState } from "react";
|
||||||
import Grid from "@mui/material/Grid";
|
|
||||||
import Typography from "@mui/material/Typography";
|
|
||||||
import { IMinigameProps } from "./IMinigameProps";
|
|
||||||
import { KeyHandler } from "./KeyHandler";
|
|
||||||
import { GameTimer } from "./GameTimer";
|
|
||||||
import { random } from "../utils";
|
|
||||||
import { interpolate } from "./Difficulty";
|
|
||||||
import { KEY } from "../../utils/helpers/keyCodes";
|
|
||||||
import { AugmentationNames } from "../../Augmentation/data/AugmentationNames";
|
import { AugmentationNames } from "../../Augmentation/data/AugmentationNames";
|
||||||
import { Player } from "../../Player";
|
import { Player } from "../../Player";
|
||||||
import { Settings } from "../../Settings/Settings";
|
import { Settings } from "../../Settings/Settings";
|
||||||
|
import { KEY } from "../../utils/helpers/keyCodes";
|
||||||
|
import { random } from "../utils";
|
||||||
|
import { interpolate } from "./Difficulty";
|
||||||
|
import { GameTimer } from "./GameTimer";
|
||||||
|
import { IMinigameProps } from "./IMinigameProps";
|
||||||
|
import { KeyHandler } from "./KeyHandler";
|
||||||
|
|
||||||
interface Difficulty {
|
interface Difficulty {
|
||||||
[key: string]: number;
|
[key: string]: number;
|
||||||
@ -102,46 +101,53 @@ export function WireCuttingGame(props: IMinigameProps): React.ReactElement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Grid container spacing={3}>
|
<>
|
||||||
<GameTimer millis={timer} onExpire={props.onFailure} />
|
<GameTimer millis={timer} onExpire={props.onFailure} />
|
||||||
<Grid item xs={12}>
|
<Paper sx={{ display: "grid", justifyItems: "center", pb: 1 }}>
|
||||||
<Typography variant="h4">Cut the wires with the following properties! (keyboard 1 to 9)</Typography>
|
<Typography variant="h4" sx={{ width: "75%", textAlign: "center" }}>
|
||||||
|
Cut the wires with the following properties! (keyboard 1 to 9)
|
||||||
|
</Typography>
|
||||||
{questions.map((question, i) => (
|
{questions.map((question, i) => (
|
||||||
<Typography key={i}>{question.toString()}</Typography>
|
<Typography key={i}>{question.toString()}</Typography>
|
||||||
))}
|
))}
|
||||||
<Typography>
|
<Box
|
||||||
|
sx={{
|
||||||
|
display: "grid",
|
||||||
|
gridTemplateColumns: `repeat(${wires.length}, 1fr)`,
|
||||||
|
columnGap: 3,
|
||||||
|
justifyItems: "center",
|
||||||
|
}}
|
||||||
|
>
|
||||||
{new Array(wires.length).fill(0).map((_, i) => {
|
{new Array(wires.length).fill(0).map((_, i) => {
|
||||||
const isCorrectWire = checkWire(i + 1);
|
const isCorrectWire = checkWire(i + 1);
|
||||||
const color = hasAugment && !isCorrectWire ? Settings.theme.disabled : Settings.theme.primary;
|
const color = hasAugment && !isCorrectWire ? Settings.theme.disabled : Settings.theme.primary;
|
||||||
return (
|
return (
|
||||||
<span key={i} style={{ color: color }}>
|
<Typography key={i} style={{ color: color }}>
|
||||||
{i + 1}
|
{i + 1}
|
||||||
</span>
|
</Typography>
|
||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
</Typography>
|
{new Array(8).fill(0).map((_, i) => (
|
||||||
{new Array(8).fill(0).map((_, i) => (
|
<React.Fragment key={i}>
|
||||||
<div key={i}>
|
|
||||||
<Typography>
|
|
||||||
{wires.map((wire, j) => {
|
{wires.map((wire, j) => {
|
||||||
if ((i === 3 || i === 4) && cutWires[j]) {
|
if ((i === 3 || i === 4) && cutWires[j]) {
|
||||||
return <span key={j}> </span>;
|
return <Typography key={j}></Typography>;
|
||||||
}
|
}
|
||||||
const isCorrectWire = checkWire(j + 1);
|
const isCorrectWire = checkWire(j + 1);
|
||||||
const wireColor =
|
const wireColor =
|
||||||
hasAugment && !isCorrectWire ? Settings.theme.disabled : wire.colors[i % wire.colors.length];
|
hasAugment && !isCorrectWire ? Settings.theme.disabled : wire.colors[i % wire.colors.length];
|
||||||
return (
|
return (
|
||||||
<span key={j} style={{ color: wireColor }}>
|
<Typography key={j} style={{ color: wireColor }}>
|
||||||
|{wire.tpe}|
|
|{wire.tpe}|
|
||||||
</span>
|
</Typography>
|
||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
</Typography>
|
</React.Fragment>
|
||||||
</div>
|
))}
|
||||||
))}
|
</Box>
|
||||||
<KeyHandler onKeyDown={press} onFailure={props.onFailure} />
|
<KeyHandler onKeyDown={press} onFailure={props.onFailure} />
|
||||||
</Grid>
|
</Paper>
|
||||||
</Grid>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -7,6 +7,7 @@ import { ITutorialEvents } from "./ui/InteractiveTutorial/ITutorialEvents";
|
|||||||
// Ordered array of keys to Interactive Tutorial Steps
|
// Ordered array of keys to Interactive Tutorial Steps
|
||||||
enum iTutorialSteps {
|
enum iTutorialSteps {
|
||||||
Start,
|
Start,
|
||||||
|
NSSelection,
|
||||||
GoToCharacterPage, // Click on 'Stats' page
|
GoToCharacterPage, // Click on 'Stats' page
|
||||||
CharacterPage, // Introduction to 'Stats' page
|
CharacterPage, // Introduction to 'Stats' page
|
||||||
CharacterGoToTerminalPage, // Go back to Terminal
|
CharacterGoToTerminalPage, // Go back to Terminal
|
||||||
@ -43,6 +44,7 @@ const ITutorial: {
|
|||||||
isRunning: boolean;
|
isRunning: boolean;
|
||||||
stepIsDone: {
|
stepIsDone: {
|
||||||
[iTutorialSteps.Start]: boolean;
|
[iTutorialSteps.Start]: boolean;
|
||||||
|
[iTutorialSteps.NSSelection]: boolean;
|
||||||
[iTutorialSteps.GoToCharacterPage]: boolean;
|
[iTutorialSteps.GoToCharacterPage]: boolean;
|
||||||
[iTutorialSteps.CharacterPage]: boolean;
|
[iTutorialSteps.CharacterPage]: boolean;
|
||||||
[iTutorialSteps.CharacterGoToTerminalPage]: boolean;
|
[iTutorialSteps.CharacterGoToTerminalPage]: boolean;
|
||||||
@ -80,6 +82,7 @@ const ITutorial: {
|
|||||||
// Keeps track of whether each step has been done
|
// Keeps track of whether each step has been done
|
||||||
stepIsDone: {
|
stepIsDone: {
|
||||||
[iTutorialSteps.Start]: false,
|
[iTutorialSteps.Start]: false,
|
||||||
|
[iTutorialSteps.NSSelection]: false,
|
||||||
[iTutorialSteps.GoToCharacterPage]: false,
|
[iTutorialSteps.GoToCharacterPage]: false,
|
||||||
[iTutorialSteps.CharacterPage]: false,
|
[iTutorialSteps.CharacterPage]: false,
|
||||||
[iTutorialSteps.CharacterGoToTerminalPage]: false,
|
[iTutorialSteps.CharacterGoToTerminalPage]: false,
|
||||||
|
@ -17,6 +17,7 @@ import { Money } from "../../ui/React/Money";
|
|||||||
import { IRouter } from "../../ui/Router";
|
import { IRouter } from "../../ui/Router";
|
||||||
import { serverMetadata } from "../../Server/data/servers";
|
import { serverMetadata } from "../../Server/data/servers";
|
||||||
import { Box } from "@mui/material";
|
import { Box } from "@mui/material";
|
||||||
|
import { ClassType } from "../../utils/WorkType";
|
||||||
|
|
||||||
type IProps = {
|
type IProps = {
|
||||||
loc: Location;
|
loc: Location;
|
||||||
@ -33,7 +34,7 @@ export function GymLocation(props: IProps): React.ReactElement {
|
|||||||
return props.loc.costMult * discount;
|
return props.loc.costMult * discount;
|
||||||
}
|
}
|
||||||
|
|
||||||
function train(stat: string): void {
|
function train(stat: ClassType): void {
|
||||||
const loc = props.loc;
|
const loc = props.loc;
|
||||||
props.p.startClass(calculateCost(), loc.expMult, stat);
|
props.p.startClass(calculateCost(), loc.expMult, stat);
|
||||||
props.p.startFocusing();
|
props.p.startFocusing();
|
||||||
@ -41,19 +42,19 @@ export function GymLocation(props: IProps): React.ReactElement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function trainStrength(): void {
|
function trainStrength(): void {
|
||||||
train(CONSTANTS.ClassGymStrength);
|
train(ClassType.GymStrength);
|
||||||
}
|
}
|
||||||
|
|
||||||
function trainDefense(): void {
|
function trainDefense(): void {
|
||||||
train(CONSTANTS.ClassGymDefense);
|
train(ClassType.GymDefense);
|
||||||
}
|
}
|
||||||
|
|
||||||
function trainDexterity(): void {
|
function trainDexterity(): void {
|
||||||
train(CONSTANTS.ClassGymDexterity);
|
train(ClassType.GymDexterity);
|
||||||
}
|
}
|
||||||
|
|
||||||
function trainAgility(): void {
|
function trainAgility(): void {
|
||||||
train(CONSTANTS.ClassGymAgility);
|
train(ClassType.GymAgility);
|
||||||
}
|
}
|
||||||
|
|
||||||
const cost = CONSTANTS.ClassGymBaseCost * calculateCost();
|
const cost = CONSTANTS.ClassGymBaseCost * calculateCost();
|
||||||
|
@ -17,6 +17,8 @@ import { Money } from "../../ui/React/Money";
|
|||||||
import { use } from "../../ui/Context";
|
import { use } from "../../ui/Context";
|
||||||
import { Box } from "@mui/material";
|
import { Box } from "@mui/material";
|
||||||
|
|
||||||
|
import { ClassType } from "../../utils/WorkType";
|
||||||
|
|
||||||
type IProps = {
|
type IProps = {
|
||||||
loc: Location;
|
loc: Location;
|
||||||
};
|
};
|
||||||
@ -32,7 +34,7 @@ export function UniversityLocation(props: IProps): React.ReactElement {
|
|||||||
return props.loc.costMult * discount;
|
return props.loc.costMult * discount;
|
||||||
}
|
}
|
||||||
|
|
||||||
function take(stat: string): void {
|
function take(stat: ClassType): void {
|
||||||
const loc = props.loc;
|
const loc = props.loc;
|
||||||
player.startClass(calculateCost(), loc.expMult, stat);
|
player.startClass(calculateCost(), loc.expMult, stat);
|
||||||
player.startFocusing();
|
player.startFocusing();
|
||||||
@ -40,27 +42,27 @@ export function UniversityLocation(props: IProps): React.ReactElement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function study(): void {
|
function study(): void {
|
||||||
take(CONSTANTS.ClassStudyComputerScience);
|
take(ClassType.StudyComputerScience);
|
||||||
}
|
}
|
||||||
|
|
||||||
function dataStructures(): void {
|
function dataStructures(): void {
|
||||||
take(CONSTANTS.ClassDataStructures);
|
take(ClassType.DataStructures);
|
||||||
}
|
}
|
||||||
|
|
||||||
function networks(): void {
|
function networks(): void {
|
||||||
take(CONSTANTS.ClassNetworks);
|
take(ClassType.Networks);
|
||||||
}
|
}
|
||||||
|
|
||||||
function algorithms(): void {
|
function algorithms(): void {
|
||||||
take(CONSTANTS.ClassAlgorithms);
|
take(ClassType.Algorithms);
|
||||||
}
|
}
|
||||||
|
|
||||||
function management(): void {
|
function management(): void {
|
||||||
take(CONSTANTS.ClassManagement);
|
take(ClassType.Management);
|
||||||
}
|
}
|
||||||
|
|
||||||
function leadership(): void {
|
function leadership(): void {
|
||||||
take(CONSTANTS.ClassLeadership);
|
take(ClassType.Leadership);
|
||||||
}
|
}
|
||||||
|
|
||||||
const costMult: number = calculateCost();
|
const costMult: number = calculateCost();
|
||||||
|
@ -156,6 +156,7 @@ const singularity: IMap<any> = {
|
|||||||
getUpgradeHomeCoresCost: SF4Cost(RamCostConstants.ScriptSingularityFn2RamCost / 2),
|
getUpgradeHomeCoresCost: SF4Cost(RamCostConstants.ScriptSingularityFn2RamCost / 2),
|
||||||
workForCompany: SF4Cost(RamCostConstants.ScriptSingularityFn2RamCost),
|
workForCompany: SF4Cost(RamCostConstants.ScriptSingularityFn2RamCost),
|
||||||
applyToCompany: SF4Cost(RamCostConstants.ScriptSingularityFn2RamCost),
|
applyToCompany: SF4Cost(RamCostConstants.ScriptSingularityFn2RamCost),
|
||||||
|
quitJob: SF4Cost(RamCostConstants.ScriptSingularityFn2RamCost),
|
||||||
getCompanyRep: SF4Cost(RamCostConstants.ScriptSingularityFn2RamCost / 3),
|
getCompanyRep: SF4Cost(RamCostConstants.ScriptSingularityFn2RamCost / 3),
|
||||||
getCompanyFavor: SF4Cost(RamCostConstants.ScriptSingularityFn2RamCost / 3),
|
getCompanyFavor: SF4Cost(RamCostConstants.ScriptSingularityFn2RamCost / 3),
|
||||||
getCompanyFavorGain: SF4Cost(RamCostConstants.ScriptSingularityFn2RamCost / 4),
|
getCompanyFavorGain: SF4Cost(RamCostConstants.ScriptSingularityFn2RamCost / 4),
|
||||||
|
@ -1233,16 +1233,21 @@ export function NetscriptFunctions(workerScript: WorkerScript): NS {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
killall: function (_hostname: unknown = workerScript.hostname): boolean {
|
killall: function (_hostname: unknown = workerScript.hostname, _safetyguard: unknown = true): boolean {
|
||||||
updateDynamicRam("killall", getRamCost(Player, "killall"));
|
updateDynamicRam("killall", getRamCost(Player, "killall"));
|
||||||
const hostname = helper.string("killall", "hostname", _hostname);
|
const hostname = helper.string("killall", "hostname", _hostname);
|
||||||
|
const safetyguard = helper.boolean(_safetyguard);
|
||||||
if (hostname === undefined) {
|
if (hostname === undefined) {
|
||||||
throw makeRuntimeErrorMsg("killall", "Takes 1 argument");
|
throw makeRuntimeErrorMsg("killall", "Usage: killall(hostname, [safetyguard boolean])");
|
||||||
}
|
}
|
||||||
const server = safeGetServer(hostname, "killall");
|
const server = safeGetServer(hostname, "killall");
|
||||||
const scriptsRunning = server.runningScripts.length > 0;
|
|
||||||
|
let scriptsKilled = 0;
|
||||||
|
|
||||||
for (let i = server.runningScripts.length - 1; i >= 0; --i) {
|
for (let i = server.runningScripts.length - 1; i >= 0; --i) {
|
||||||
|
if (safetyguard === true && server.runningScripts[i].pid == workerScript.pid) continue;
|
||||||
killWorkerScript(server.runningScripts[i], server.hostname, false);
|
killWorkerScript(server.runningScripts[i], server.hostname, false);
|
||||||
|
++scriptsKilled;
|
||||||
}
|
}
|
||||||
WorkerScriptStartStopEventEmitter.emit();
|
WorkerScriptStartStopEventEmitter.emit();
|
||||||
workerScript.log(
|
workerScript.log(
|
||||||
@ -1250,7 +1255,7 @@ export function NetscriptFunctions(workerScript: WorkerScript): NS {
|
|||||||
() => `Killing all scripts on '${server.hostname}'. May take a few minutes for the scripts to die.`,
|
() => `Killing all scripts on '${server.hostname}'. May take a few minutes for the scripts to die.`,
|
||||||
);
|
);
|
||||||
|
|
||||||
return scriptsRunning;
|
return scriptsKilled > 0;
|
||||||
},
|
},
|
||||||
exit: function (): void {
|
exit: function (): void {
|
||||||
updateDynamicRam("exit", getRamCost(Player, "exit"));
|
updateDynamicRam("exit", getRamCost(Player, "exit"));
|
||||||
|
@ -295,6 +295,7 @@ export function NetscriptCorporation(
|
|||||||
if (office === 0) continue;
|
if (office === 0) continue;
|
||||||
cities.push(office.loc);
|
cities.push(office.loc);
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
name: division.name,
|
name: division.name,
|
||||||
type: division.type,
|
type: division.type,
|
||||||
@ -309,6 +310,7 @@ export function NetscriptCorporation(
|
|||||||
upgrades: division.upgrades.slice(),
|
upgrades: division.upgrades.slice(),
|
||||||
cities: cities,
|
cities: cities,
|
||||||
products: division.products === undefined ? [] : Object.keys(division.products),
|
products: division.products === undefined ? [] : Object.keys(division.products),
|
||||||
|
makesProducts: division.makesProducts,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -359,6 +361,7 @@ export function NetscriptCorporation(
|
|||||||
const corporation = getCorporation();
|
const corporation = getCorporation();
|
||||||
return {
|
return {
|
||||||
cost: material.bCost,
|
cost: material.bCost,
|
||||||
|
sCost: material.sCost,
|
||||||
name: material.name,
|
name: material.name,
|
||||||
qty: material.qty,
|
qty: material.qty,
|
||||||
qlt: material.qlt,
|
qlt: material.qlt,
|
||||||
|
@ -342,7 +342,7 @@ export function NetscriptGang(player: IPlayer, workerScript: WorkerScript, helpe
|
|||||||
checkGangApiAccess("getBonusTime");
|
checkGangApiAccess("getBonusTime");
|
||||||
const gang = player.gang;
|
const gang = player.gang;
|
||||||
if (gang === null) throw new Error("Should not be called without Gang");
|
if (gang === null) throw new Error("Should not be called without Gang");
|
||||||
return Math.round(gang.storedCycles / 5);
|
return Math.round(gang.storedCycles / 5) * 1000;
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { Augmentations } from "../Augmentation/Augmentations";
|
import { StaticAugmentations } from "../Augmentation/StaticAugmentations";
|
||||||
import { hasAugmentationPrereqs } from "../Faction/FactionHelpers";
|
import { hasAugmentationPrereqs } from "../Faction/FactionHelpers";
|
||||||
import { CityName } from "../Locations/data/CityNames";
|
import { CityName } from "../Locations/data/CityNames";
|
||||||
import { getRamCost } from "../Netscript/RamCostGenerator";
|
import { getRamCost } from "../Netscript/RamCostGenerator";
|
||||||
@ -28,10 +28,10 @@ export function NetscriptGrafting(player: IPlayer, workerScript: WorkerScript, h
|
|||||||
updateRam("getAugmentationGraftPrice");
|
updateRam("getAugmentationGraftPrice");
|
||||||
const augName = helper.string("getAugmentationGraftPrice", "augName", _augName);
|
const augName = helper.string("getAugmentationGraftPrice", "augName", _augName);
|
||||||
checkGraftingAPIAccess("getAugmentationGraftPrice");
|
checkGraftingAPIAccess("getAugmentationGraftPrice");
|
||||||
if (!getGraftingAvailableAugs(player).includes(augName) || !Augmentations.hasOwnProperty(augName)) {
|
if (!getGraftingAvailableAugs(player).includes(augName) || !StaticAugmentations.hasOwnProperty(augName)) {
|
||||||
throw helper.makeRuntimeErrorMsg("grafting.getAugmentationGraftPrice", `Invalid aug: ${augName}`);
|
throw helper.makeRuntimeErrorMsg("grafting.getAugmentationGraftPrice", `Invalid aug: ${augName}`);
|
||||||
}
|
}
|
||||||
const graftableAug = new GraftableAugmentation(Augmentations[augName]);
|
const graftableAug = new GraftableAugmentation(StaticAugmentations[augName]);
|
||||||
return graftableAug.cost;
|
return graftableAug.cost;
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -39,10 +39,10 @@ export function NetscriptGrafting(player: IPlayer, workerScript: WorkerScript, h
|
|||||||
updateRam("getAugmentationGraftTime");
|
updateRam("getAugmentationGraftTime");
|
||||||
const augName = helper.string("getAugmentationGraftTime", "augName", _augName);
|
const augName = helper.string("getAugmentationGraftTime", "augName", _augName);
|
||||||
checkGraftingAPIAccess("getAugmentationGraftTime");
|
checkGraftingAPIAccess("getAugmentationGraftTime");
|
||||||
if (!getGraftingAvailableAugs(player).includes(augName) || !Augmentations.hasOwnProperty(augName)) {
|
if (!getGraftingAvailableAugs(player).includes(augName) || !StaticAugmentations.hasOwnProperty(augName)) {
|
||||||
throw helper.makeRuntimeErrorMsg("grafting.getAugmentationGraftTime", `Invalid aug: ${augName}`);
|
throw helper.makeRuntimeErrorMsg("grafting.getAugmentationGraftTime", `Invalid aug: ${augName}`);
|
||||||
}
|
}
|
||||||
const graftableAug = new GraftableAugmentation(Augmentations[augName]);
|
const graftableAug = new GraftableAugmentation(StaticAugmentations[augName]);
|
||||||
return calculateGraftingTimeWithBonus(player, graftableAug);
|
return calculateGraftingTimeWithBonus(player, graftableAug);
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -64,7 +64,7 @@ export function NetscriptGrafting(player: IPlayer, workerScript: WorkerScript, h
|
|||||||
"You must be in New Tokyo to begin grafting an Augmentation.",
|
"You must be in New Tokyo to begin grafting an Augmentation.",
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
if (!getGraftingAvailableAugs(player).includes(augName) || !Augmentations.hasOwnProperty(augName)) {
|
if (!getGraftingAvailableAugs(player).includes(augName) || !StaticAugmentations.hasOwnProperty(augName)) {
|
||||||
workerScript.log("grafting.graftAugmentation", () => `Invalid aug: ${augName}`);
|
workerScript.log("grafting.graftAugmentation", () => `Invalid aug: ${augName}`);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -75,7 +75,7 @@ export function NetscriptGrafting(player: IPlayer, workerScript: WorkerScript, h
|
|||||||
workerScript.log("graftAugmentation", () => txt);
|
workerScript.log("graftAugmentation", () => txt);
|
||||||
}
|
}
|
||||||
|
|
||||||
const craftableAug = new GraftableAugmentation(Augmentations[augName]);
|
const craftableAug = new GraftableAugmentation(StaticAugmentations[augName]);
|
||||||
if (player.money < craftableAug.cost) {
|
if (player.money < craftableAug.cost) {
|
||||||
workerScript.log("grafting.graftAugmentation", () => `You don't have enough money to craft ${augName}`);
|
workerScript.log("grafting.graftAugmentation", () => `You don't have enough money to craft ${augName}`);
|
||||||
return false;
|
return false;
|
||||||
|
@ -3,7 +3,7 @@ import { IPlayer } from "../PersonObjects/IPlayer";
|
|||||||
import { purchaseAugmentation, joinFaction, getFactionAugmentationsFiltered } from "../Faction/FactionHelpers";
|
import { purchaseAugmentation, joinFaction, getFactionAugmentationsFiltered } from "../Faction/FactionHelpers";
|
||||||
import { startWorkerScript } from "../NetscriptWorker";
|
import { startWorkerScript } from "../NetscriptWorker";
|
||||||
import { Augmentation } from "../Augmentation/Augmentation";
|
import { Augmentation } from "../Augmentation/Augmentation";
|
||||||
import { Augmentations } from "../Augmentation/Augmentations";
|
import { StaticAugmentations } from "../Augmentation/StaticAugmentations";
|
||||||
import { augmentationExists, installAugmentations } from "../Augmentation/AugmentationHelpers";
|
import { augmentationExists, installAugmentations } from "../Augmentation/AugmentationHelpers";
|
||||||
import { AugmentationNames } from "../Augmentation/data/AugmentationNames";
|
import { AugmentationNames } from "../Augmentation/data/AugmentationNames";
|
||||||
import { killWorkerScript } from "../Netscript/killWorkerScript";
|
import { killWorkerScript } from "../Netscript/killWorkerScript";
|
||||||
@ -49,6 +49,7 @@ import { InternalAPI, NetscriptContext } from "src/Netscript/APIWrapper";
|
|||||||
import { BlackOperationNames } from "../Bladeburner/data/BlackOperationNames";
|
import { BlackOperationNames } from "../Bladeburner/data/BlackOperationNames";
|
||||||
import { enterBitNode } from "../RedPill";
|
import { enterBitNode } from "../RedPill";
|
||||||
import { FactionNames } from "../Faction/data/FactionNames";
|
import { FactionNames } from "../Faction/data/FactionNames";
|
||||||
|
import { ClassType, WorkType } from "../utils/WorkType";
|
||||||
|
|
||||||
export function NetscriptSingularity(player: IPlayer, workerScript: WorkerScript): InternalAPI<ISingularity> {
|
export function NetscriptSingularity(player: IPlayer, workerScript: WorkerScript): InternalAPI<ISingularity> {
|
||||||
const getAugmentation = function (_ctx: NetscriptContext, name: string): Augmentation {
|
const getAugmentation = function (_ctx: NetscriptContext, name: string): Augmentation {
|
||||||
@ -56,7 +57,7 @@ export function NetscriptSingularity(player: IPlayer, workerScript: WorkerScript
|
|||||||
throw _ctx.helper.makeRuntimeErrorMsg(`Invalid augmentation: '${name}'`);
|
throw _ctx.helper.makeRuntimeErrorMsg(`Invalid augmentation: '${name}'`);
|
||||||
}
|
}
|
||||||
|
|
||||||
return Augmentations[name];
|
return StaticAugmentations[name];
|
||||||
};
|
};
|
||||||
|
|
||||||
const getFaction = function (_ctx: NetscriptContext, name: string): Faction {
|
const getFaction = function (_ctx: NetscriptContext, name: string): Faction {
|
||||||
@ -122,7 +123,7 @@ export function NetscriptSingularity(player: IPlayer, workerScript: WorkerScript
|
|||||||
_ctx.helper.checkSingularityAccess();
|
_ctx.helper.checkSingularityAccess();
|
||||||
const augName = _ctx.helper.string("augName", _augName);
|
const augName = _ctx.helper.string("augName", _augName);
|
||||||
const aug = getAugmentation(_ctx, augName);
|
const aug = getAugmentation(_ctx, augName);
|
||||||
return [aug.baseRepRequirement, aug.baseCost];
|
return [aug.getCost(player).moneyCost, aug.getCost(player).repCost];
|
||||||
},
|
},
|
||||||
getAugmentationPrereq: (_ctx: NetscriptContext) =>
|
getAugmentationPrereq: (_ctx: NetscriptContext) =>
|
||||||
function (_augName: unknown): string[] {
|
function (_augName: unknown): string[] {
|
||||||
@ -136,14 +137,14 @@ export function NetscriptSingularity(player: IPlayer, workerScript: WorkerScript
|
|||||||
_ctx.helper.checkSingularityAccess();
|
_ctx.helper.checkSingularityAccess();
|
||||||
const augName = _ctx.helper.string("augName", _augName);
|
const augName = _ctx.helper.string("augName", _augName);
|
||||||
const aug = getAugmentation(_ctx, augName);
|
const aug = getAugmentation(_ctx, augName);
|
||||||
return aug.baseCost;
|
return aug.getCost(player).moneyCost;
|
||||||
},
|
},
|
||||||
getAugmentationRepReq: (_ctx: NetscriptContext) =>
|
getAugmentationRepReq: (_ctx: NetscriptContext) =>
|
||||||
function (_augName: unknown): number {
|
function (_augName: unknown): number {
|
||||||
_ctx.helper.checkSingularityAccess();
|
_ctx.helper.checkSingularityAccess();
|
||||||
const augName = _ctx.helper.string("augName", _augName);
|
const augName = _ctx.helper.string("augName", _augName);
|
||||||
const aug = getAugmentation(_ctx, augName);
|
const aug = getAugmentation(_ctx, augName);
|
||||||
return aug.baseRepRequirement;
|
return aug.getCost(player).repCost;
|
||||||
},
|
},
|
||||||
getAugmentationStats: (_ctx: NetscriptContext) =>
|
getAugmentationStats: (_ctx: NetscriptContext) =>
|
||||||
function (_augName: unknown): AugmentationStats {
|
function (_augName: unknown): AugmentationStats {
|
||||||
@ -183,7 +184,7 @@ export function NetscriptSingularity(player: IPlayer, workerScript: WorkerScript
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fac.playerReputation < aug.baseRepRequirement) {
|
if (fac.playerReputation < aug.getCost(player).repCost) {
|
||||||
_ctx.log(() => `You do not have enough reputation with '${fac.name}'.`);
|
_ctx.log(() => `You do not have enough reputation with '${fac.name}'.`);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -298,25 +299,25 @@ export function NetscriptSingularity(player: IPlayer, workerScript: WorkerScript
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
let task = "";
|
let task: ClassType;
|
||||||
switch (className.toLowerCase()) {
|
switch (className.toLowerCase()) {
|
||||||
case "Study Computer Science".toLowerCase():
|
case "Study Computer Science".toLowerCase():
|
||||||
task = CONSTANTS.ClassStudyComputerScience;
|
task = ClassType.StudyComputerScience;
|
||||||
break;
|
break;
|
||||||
case "Data Structures".toLowerCase():
|
case "Data Structures".toLowerCase():
|
||||||
task = CONSTANTS.ClassDataStructures;
|
task = ClassType.DataStructures;
|
||||||
break;
|
break;
|
||||||
case "Networks".toLowerCase():
|
case "Networks".toLowerCase():
|
||||||
task = CONSTANTS.ClassNetworks;
|
task = ClassType.Networks;
|
||||||
break;
|
break;
|
||||||
case "Algorithms".toLowerCase():
|
case "Algorithms".toLowerCase():
|
||||||
task = CONSTANTS.ClassAlgorithms;
|
task = ClassType.Algorithms;
|
||||||
break;
|
break;
|
||||||
case "Management".toLowerCase():
|
case "Management".toLowerCase():
|
||||||
task = CONSTANTS.ClassManagement;
|
task = ClassType.Management;
|
||||||
break;
|
break;
|
||||||
case "Leadership".toLowerCase():
|
case "Leadership".toLowerCase():
|
||||||
task = CONSTANTS.ClassLeadership;
|
task = ClassType.Leadership;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
_ctx.log(() => `Invalid class name: ${className}.`);
|
_ctx.log(() => `Invalid class name: ${className}.`);
|
||||||
@ -415,19 +416,19 @@ export function NetscriptSingularity(player: IPlayer, workerScript: WorkerScript
|
|||||||
switch (stat.toLowerCase()) {
|
switch (stat.toLowerCase()) {
|
||||||
case "strength".toLowerCase():
|
case "strength".toLowerCase():
|
||||||
case "str".toLowerCase():
|
case "str".toLowerCase():
|
||||||
player.startClass(costMult, expMult, CONSTANTS.ClassGymStrength);
|
player.startClass(costMult, expMult, ClassType.GymStrength);
|
||||||
break;
|
break;
|
||||||
case "defense".toLowerCase():
|
case "defense".toLowerCase():
|
||||||
case "def".toLowerCase():
|
case "def".toLowerCase():
|
||||||
player.startClass(costMult, expMult, CONSTANTS.ClassGymDefense);
|
player.startClass(costMult, expMult, ClassType.GymDefense);
|
||||||
break;
|
break;
|
||||||
case "dexterity".toLowerCase():
|
case "dexterity".toLowerCase():
|
||||||
case "dex".toLowerCase():
|
case "dex".toLowerCase():
|
||||||
player.startClass(costMult, expMult, CONSTANTS.ClassGymDexterity);
|
player.startClass(costMult, expMult, ClassType.GymDexterity);
|
||||||
break;
|
break;
|
||||||
case "agility".toLowerCase():
|
case "agility".toLowerCase():
|
||||||
case "agi".toLowerCase():
|
case "agi".toLowerCase():
|
||||||
player.startClass(costMult, expMult, CONSTANTS.ClassGymAgility);
|
player.startClass(costMult, expMult, ClassType.GymAgility);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
_ctx.log(() => `Invalid stat: ${stat}.`);
|
_ctx.log(() => `Invalid stat: ${stat}.`);
|
||||||
@ -650,11 +651,11 @@ export function NetscriptSingularity(player: IPlayer, workerScript: WorkerScript
|
|||||||
}
|
}
|
||||||
if (
|
if (
|
||||||
!(
|
!(
|
||||||
player.workType == CONSTANTS.WorkTypeFaction ||
|
player.workType === WorkType.Faction ||
|
||||||
player.workType == CONSTANTS.WorkTypeCompany ||
|
player.workType === WorkType.Company ||
|
||||||
player.workType == CONSTANTS.WorkTypeCompanyPartTime ||
|
player.workType === WorkType.CompanyPartTime ||
|
||||||
player.workType == CONSTANTS.WorkTypeCreateProgram ||
|
player.workType === WorkType.CreateProgram ||
|
||||||
player.workType == CONSTANTS.WorkTypeStudyClass
|
player.workType === WorkType.StudyClass
|
||||||
)
|
)
|
||||||
) {
|
) {
|
||||||
throw _ctx.helper.makeRuntimeErrorMsg("Cannot change focus for current job");
|
throw _ctx.helper.makeRuntimeErrorMsg("Cannot change focus for current job");
|
||||||
@ -947,6 +948,12 @@ export function NetscriptSingularity(player: IPlayer, workerScript: WorkerScript
|
|||||||
}
|
}
|
||||||
return res;
|
return res;
|
||||||
},
|
},
|
||||||
|
quitJob: (_ctx: NetscriptContext) =>
|
||||||
|
function (_companyName: unknown): void {
|
||||||
|
_ctx.helper.checkSingularityAccess();
|
||||||
|
const companyName = _ctx.helper.string("companyName", _companyName);
|
||||||
|
player.quitJob(companyName);
|
||||||
|
},
|
||||||
getCompanyRep: (_ctx: NetscriptContext) =>
|
getCompanyRep: (_ctx: NetscriptContext) =>
|
||||||
function (_companyName: unknown): number {
|
function (_companyName: unknown): number {
|
||||||
_ctx.helper.checkSingularityAccess();
|
_ctx.helper.checkSingularityAccess();
|
||||||
@ -1079,7 +1086,6 @@ export function NetscriptSingularity(player: IPlayer, workerScript: WorkerScript
|
|||||||
_ctx.log(() => `Invalid work type: '${type}`);
|
_ctx.log(() => `Invalid work type: '${type}`);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
|
||||||
},
|
},
|
||||||
getFactionRep: (_ctx: NetscriptContext) =>
|
getFactionRep: (_ctx: NetscriptContext) =>
|
||||||
function (_facName: unknown): number {
|
function (_facName: unknown): number {
|
||||||
|
@ -5,7 +5,7 @@ import { FactionWorkType } from "../Faction/FactionWorkTypeEnum";
|
|||||||
import { SleeveTaskType } from "../PersonObjects/Sleeve/SleeveTaskTypesEnum";
|
import { SleeveTaskType } from "../PersonObjects/Sleeve/SleeveTaskTypesEnum";
|
||||||
import { WorkerScript } from "../Netscript/WorkerScript";
|
import { WorkerScript } from "../Netscript/WorkerScript";
|
||||||
import { findSleevePurchasableAugs } from "../PersonObjects/Sleeve/SleeveHelpers";
|
import { findSleevePurchasableAugs } from "../PersonObjects/Sleeve/SleeveHelpers";
|
||||||
import { Augmentations } from "../Augmentation/Augmentations";
|
import { StaticAugmentations } from "../Augmentation/StaticAugmentations";
|
||||||
import { CityName } from "../Locations/data/CityNames";
|
import { CityName } from "../Locations/data/CityNames";
|
||||||
import { findCrime } from "../Crime/CrimeHelpers";
|
import { findCrime } from "../Crime/CrimeHelpers";
|
||||||
|
|
||||||
@ -286,7 +286,7 @@ export function NetscriptSleeve(player: IPlayer, workerScript: WorkerScript, hel
|
|||||||
const aug = purchasableAugs[i];
|
const aug = purchasableAugs[i];
|
||||||
augs.push({
|
augs.push({
|
||||||
name: aug.name,
|
name: aug.name,
|
||||||
cost: aug.startingCost,
|
cost: aug.baseCost,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -303,7 +303,7 @@ export function NetscriptSleeve(player: IPlayer, workerScript: WorkerScript, hel
|
|||||||
throw helper.makeRuntimeErrorMsg("sleeve.purchaseSleeveAug", `Sleeve shock too high: Sleeve ${sleeveNumber}`);
|
throw helper.makeRuntimeErrorMsg("sleeve.purchaseSleeveAug", `Sleeve shock too high: Sleeve ${sleeveNumber}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
const aug = Augmentations[augName];
|
const aug = StaticAugmentations[augName];
|
||||||
if (!aug) {
|
if (!aug) {
|
||||||
throw helper.makeRuntimeErrorMsg("sleeve.purchaseSleeveAug", `Invalid aug: ${augName}`);
|
throw helper.makeRuntimeErrorMsg("sleeve.purchaseSleeveAug", `Invalid aug: ${augName}`);
|
||||||
}
|
}
|
||||||
|
@ -18,7 +18,7 @@ export class GraftableAugmentation {
|
|||||||
}
|
}
|
||||||
|
|
||||||
get cost(): number {
|
get cost(): number {
|
||||||
return this.augmentation.startingCost * CONSTANTS.AugmentationGraftingCostMult;
|
return this.augmentation.baseCost * CONSTANTS.AugmentationGraftingCostMult;
|
||||||
}
|
}
|
||||||
|
|
||||||
get time(): number {
|
get time(): number {
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
import { Augmentations } from "../../Augmentation/Augmentations";
|
import { StaticAugmentations } from "../../Augmentation/StaticAugmentations";
|
||||||
import { GraftableAugmentation } from "./GraftableAugmentation";
|
import { GraftableAugmentation } from "./GraftableAugmentation";
|
||||||
import { IPlayer } from "../IPlayer";
|
import { IPlayer } from "../IPlayer";
|
||||||
|
|
||||||
export const getGraftingAvailableAugs = (player: IPlayer): string[] => {
|
export const getGraftingAvailableAugs = (player: IPlayer): string[] => {
|
||||||
const augs: string[] = [];
|
const augs: string[] = [];
|
||||||
|
|
||||||
for (const [augName, aug] of Object.entries(Augmentations)) {
|
for (const [augName, aug] of Object.entries(StaticAugmentations)) {
|
||||||
if (aug.isSpecial) continue;
|
if (aug.isSpecial) continue;
|
||||||
augs.push(augName);
|
augs.push(augName);
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,7 @@ import { Construction, CheckBox, CheckBoxOutlineBlank } from "@mui/icons-materia
|
|||||||
import { Box, Button, Container, List, ListItemButton, Paper, Typography } from "@mui/material";
|
import { Box, Button, Container, List, ListItemButton, Paper, Typography } from "@mui/material";
|
||||||
import React, { useState, useEffect } from "react";
|
import React, { useState, useEffect } from "react";
|
||||||
import { Augmentation } from "../../../Augmentation/Augmentation";
|
import { Augmentation } from "../../../Augmentation/Augmentation";
|
||||||
import { Augmentations } from "../../../Augmentation/Augmentations";
|
import { StaticAugmentations } from "../../../Augmentation/StaticAugmentations";
|
||||||
import { AugmentationNames } from "../../../Augmentation/data/AugmentationNames";
|
import { AugmentationNames } from "../../../Augmentation/data/AugmentationNames";
|
||||||
import { CONSTANTS } from "../../../Constants";
|
import { CONSTANTS } from "../../../Constants";
|
||||||
import { hasAugmentationPrereqs } from "../../../Faction/FactionHelpers";
|
import { hasAugmentationPrereqs } from "../../../Faction/FactionHelpers";
|
||||||
@ -54,7 +54,7 @@ export const GraftingRoot = (): React.ReactElement => {
|
|||||||
const player = use.Player();
|
const player = use.Player();
|
||||||
const router = use.Router();
|
const router = use.Router();
|
||||||
|
|
||||||
for (const aug of Object.values(Augmentations)) {
|
for (const aug of Object.values(StaticAugmentations)) {
|
||||||
const name = aug.name;
|
const name = aug.name;
|
||||||
const graftableAug = new GraftableAugmentation(aug);
|
const graftableAug = new GraftableAugmentation(aug);
|
||||||
GraftableAugmentations[name] = graftableAug;
|
GraftableAugmentations[name] = graftableAug;
|
||||||
@ -62,6 +62,7 @@ export const GraftingRoot = (): React.ReactElement => {
|
|||||||
|
|
||||||
const [selectedAug, setSelectedAug] = useState(getGraftingAvailableAugs(player)[0]);
|
const [selectedAug, setSelectedAug] = useState(getGraftingAvailableAugs(player)[0]);
|
||||||
const [graftOpen, setGraftOpen] = useState(false);
|
const [graftOpen, setGraftOpen] = useState(false);
|
||||||
|
const selectedAugmentation = StaticAugmentations[selectedAug];
|
||||||
|
|
||||||
const setRerender = useState(false)[1];
|
const setRerender = useState(false)[1];
|
||||||
function rerender(): void {
|
function rerender(): void {
|
||||||
@ -148,22 +149,26 @@ export const GraftingRoot = (): React.ReactElement => {
|
|||||||
{/* Use formula so the displayed creation time is accurate to player bonus */}
|
{/* Use formula so the displayed creation time is accurate to player bonus */}
|
||||||
</Typography>
|
</Typography>
|
||||||
|
|
||||||
{Augmentations[selectedAug].prereqs.length > 0 && (
|
{selectedAugmentation.prereqs.length > 0 && (
|
||||||
<AugPreReqsChecklist player={player} aug={Augmentations[selectedAug]} />
|
<AugPreReqsChecklist player={player} aug={selectedAugmentation} />
|
||||||
)}
|
)}
|
||||||
|
|
||||||
<br />
|
<br />
|
||||||
|
|
||||||
<Typography>
|
<Typography>
|
||||||
{(() => {
|
{(() => {
|
||||||
const aug = Augmentations[selectedAug];
|
const info =
|
||||||
|
typeof selectedAugmentation.info === "string" ? (
|
||||||
const info = typeof aug.info === "string" ? <span>{aug.info}</span> : aug.info;
|
<span>{selectedAugmentation.info}</span>
|
||||||
|
) : (
|
||||||
|
selectedAugmentation.info
|
||||||
|
);
|
||||||
const tooltip = (
|
const tooltip = (
|
||||||
<>
|
<>
|
||||||
{info}
|
{info}
|
||||||
<br />
|
<br />
|
||||||
<br />
|
<br />
|
||||||
{aug.stats}
|
{selectedAugmentation.stats}
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
return tooltip;
|
return tooltip;
|
||||||
|
@ -31,6 +31,7 @@ import { HacknetServer } from "../Hacknet/HacknetServer";
|
|||||||
import { ISkillProgress } from "./formulas/skill";
|
import { ISkillProgress } from "./formulas/skill";
|
||||||
import { PlayerAchievement } from "../Achievements/Achievements";
|
import { PlayerAchievement } from "../Achievements/Achievements";
|
||||||
import { IPerson } from "./IPerson";
|
import { IPerson } from "./IPerson";
|
||||||
|
import { WorkType, ClassType, CrimeType } from "../utils/WorkType";
|
||||||
|
|
||||||
export interface IPlayer extends IPerson {
|
export interface IPlayer extends IPerson {
|
||||||
// Class members
|
// Class members
|
||||||
@ -131,14 +132,14 @@ export interface IPlayer extends IPerson {
|
|||||||
timeWorkedCreateProgram: number;
|
timeWorkedCreateProgram: number;
|
||||||
graftAugmentationName: string;
|
graftAugmentationName: string;
|
||||||
timeWorkedGraftAugmentation: number;
|
timeWorkedGraftAugmentation: number;
|
||||||
crimeType: string;
|
crimeType: CrimeType;
|
||||||
committingCrimeThruSingFn: boolean;
|
committingCrimeThruSingFn: boolean;
|
||||||
singFnCrimeWorkerScript: WorkerScript | null;
|
singFnCrimeWorkerScript: WorkerScript | null;
|
||||||
timeNeededToCompleteWork: number;
|
timeNeededToCompleteWork: number;
|
||||||
focus: boolean;
|
focus: boolean;
|
||||||
className: string;
|
className: ClassType;
|
||||||
currentWorkFactionName: string;
|
currentWorkFactionName: string;
|
||||||
workType: string;
|
workType: WorkType;
|
||||||
workCostMult: number;
|
workCostMult: number;
|
||||||
workExpMult: number;
|
workExpMult: number;
|
||||||
currentWorkFactionDescription: string;
|
currentWorkFactionDescription: string;
|
||||||
@ -212,11 +213,11 @@ export interface IPlayer extends IPerson {
|
|||||||
singularityStopWork(): string;
|
singularityStopWork(): string;
|
||||||
startBladeburner(p: any): void;
|
startBladeburner(p: any): void;
|
||||||
startFactionWork(faction: Faction): void;
|
startFactionWork(faction: Faction): void;
|
||||||
startClass(costMult: number, expMult: number, className: string): void;
|
startClass(costMult: number, expMult: number, className: ClassType): void;
|
||||||
startCorporation(corpName: string, additionalShares?: number): void;
|
startCorporation(corpName: string, additionalShares?: number): void;
|
||||||
startCrime(
|
startCrime(
|
||||||
router: IRouter,
|
router: IRouter,
|
||||||
crimeType: string,
|
crimeType: CrimeType,
|
||||||
hackExp: number,
|
hackExp: number,
|
||||||
strExp: number,
|
strExp: number,
|
||||||
defExp: number,
|
defExp: number,
|
||||||
@ -238,7 +239,7 @@ export interface IPlayer extends IPerson {
|
|||||||
giveExploit(exploit: Exploit): void;
|
giveExploit(exploit: Exploit): void;
|
||||||
giveAchievement(achievementId: string): void;
|
giveAchievement(achievementId: string): void;
|
||||||
getCasinoWinnings(): number;
|
getCasinoWinnings(): number;
|
||||||
quitJob(company: string): void;
|
quitJob(company: string, sing?: boolean): void;
|
||||||
hasJob(): boolean;
|
hasJob(): boolean;
|
||||||
createHacknetServer(): HacknetServer;
|
createHacknetServer(): HacknetServer;
|
||||||
startCreateProgramWork(programName: string, time: number, reqLevel: number): void;
|
startCreateProgramWork(programName: string, time: number, reqLevel: number): void;
|
||||||
@ -258,7 +259,7 @@ export interface IPlayer extends IPerson {
|
|||||||
prestigeAugmentation(): void;
|
prestigeAugmentation(): void;
|
||||||
prestigeSourceFile(): void;
|
prestigeSourceFile(): void;
|
||||||
calculateSkillProgress(exp: number, mult?: number): ISkillProgress;
|
calculateSkillProgress(exp: number, mult?: number): ISkillProgress;
|
||||||
resetWorkStatus(generalType?: string, group?: string, workType?: string): void;
|
resetWorkStatus(generalType?: WorkType, group?: string, workType?: string): void;
|
||||||
getWorkHackExpGain(): number;
|
getWorkHackExpGain(): number;
|
||||||
getWorkStrExpGain(): number;
|
getWorkStrExpGain(): number;
|
||||||
getWorkDefExpGain(): number;
|
getWorkDefExpGain(): number;
|
||||||
@ -280,6 +281,6 @@ export interface IPlayer extends IPerson {
|
|||||||
sourceFileLvl(n: number): number;
|
sourceFileLvl(n: number): number;
|
||||||
startGraftAugmentationWork(augmentationName: string, time: number): void;
|
startGraftAugmentationWork(augmentationName: string, time: number): void;
|
||||||
graftAugmentationWork(numCycles: number): boolean;
|
graftAugmentationWork(numCycles: number): boolean;
|
||||||
finishGraftAugmentationWork(cancelled: boolean): string;
|
finishGraftAugmentationWork(cancelled: boolean, singularity?: boolean): string;
|
||||||
applyEntropy(stacks?: number): void;
|
applyEntropy(stacks?: number): void;
|
||||||
}
|
}
|
||||||
|
@ -39,6 +39,7 @@ import { cyrb53 } from "../../utils/StringHelperFunctions";
|
|||||||
import { getRandomInt } from "../../utils/helpers/getRandomInt";
|
import { getRandomInt } from "../../utils/helpers/getRandomInt";
|
||||||
import { ITaskTracker } from "../ITaskTracker";
|
import { ITaskTracker } from "../ITaskTracker";
|
||||||
import { CONSTANTS } from "../../Constants";
|
import { CONSTANTS } from "../../Constants";
|
||||||
|
import { WorkType, ClassType, CrimeType, PlayerFactionWorkType } from "../../utils/WorkType";
|
||||||
|
|
||||||
export class PlayerObject implements IPlayer {
|
export class PlayerObject implements IPlayer {
|
||||||
// Class members
|
// Class members
|
||||||
@ -136,19 +137,19 @@ export class PlayerObject implements IPlayer {
|
|||||||
bladeburner_success_chance_mult: number;
|
bladeburner_success_chance_mult: number;
|
||||||
|
|
||||||
createProgramReqLvl: number;
|
createProgramReqLvl: number;
|
||||||
factionWorkType: string;
|
factionWorkType: PlayerFactionWorkType;
|
||||||
createProgramName: string;
|
createProgramName: string;
|
||||||
timeWorkedCreateProgram: number;
|
timeWorkedCreateProgram: number;
|
||||||
graftAugmentationName: string;
|
graftAugmentationName: string;
|
||||||
timeWorkedGraftAugmentation: number;
|
timeWorkedGraftAugmentation: number;
|
||||||
crimeType: string;
|
crimeType: CrimeType;
|
||||||
committingCrimeThruSingFn: boolean;
|
committingCrimeThruSingFn: boolean;
|
||||||
singFnCrimeWorkerScript: WorkerScript | null;
|
singFnCrimeWorkerScript: WorkerScript | null;
|
||||||
timeNeededToCompleteWork: number;
|
timeNeededToCompleteWork: number;
|
||||||
focus: boolean;
|
focus: boolean;
|
||||||
className: string;
|
className: ClassType;
|
||||||
currentWorkFactionName: string;
|
currentWorkFactionName: string;
|
||||||
workType: string;
|
workType: WorkType;
|
||||||
workCostMult: number;
|
workCostMult: number;
|
||||||
workExpMult: number;
|
workExpMult: number;
|
||||||
currentWorkFactionDescription: string;
|
currentWorkFactionDescription: string;
|
||||||
@ -231,11 +232,11 @@ export class PlayerObject implements IPlayer {
|
|||||||
singularityStopWork: () => string;
|
singularityStopWork: () => string;
|
||||||
startBladeburner: (p: any) => void;
|
startBladeburner: (p: any) => void;
|
||||||
startFactionWork: (faction: Faction) => void;
|
startFactionWork: (faction: Faction) => void;
|
||||||
startClass: (costMult: number, expMult: number, className: string) => void;
|
startClass: (costMult: number, expMult: number, className: ClassType) => void;
|
||||||
startCorporation: (corpName: string, additionalShares?: number) => void;
|
startCorporation: (corpName: string, additionalShares?: number) => void;
|
||||||
startCrime: (
|
startCrime: (
|
||||||
router: IRouter,
|
router: IRouter,
|
||||||
crimeType: string,
|
crimeType: CrimeType,
|
||||||
hackExp: number,
|
hackExp: number,
|
||||||
strExp: number,
|
strExp: number,
|
||||||
defExp: number,
|
defExp: number,
|
||||||
@ -260,7 +261,7 @@ export class PlayerObject implements IPlayer {
|
|||||||
queryStatFromString: (str: string) => number;
|
queryStatFromString: (str: string) => number;
|
||||||
getIntelligenceBonus: (weight: number) => number;
|
getIntelligenceBonus: (weight: number) => number;
|
||||||
getCasinoWinnings: () => number;
|
getCasinoWinnings: () => number;
|
||||||
quitJob: (company: string) => void;
|
quitJob: (company: string, sing?: boolean) => void;
|
||||||
hasJob: () => boolean;
|
hasJob: () => boolean;
|
||||||
process: (router: IRouter, numCycles?: number) => void;
|
process: (router: IRouter, numCycles?: number) => void;
|
||||||
createHacknetServer: () => HacknetServer;
|
createHacknetServer: () => HacknetServer;
|
||||||
@ -282,7 +283,7 @@ export class PlayerObject implements IPlayer {
|
|||||||
prestigeSourceFile: () => void;
|
prestigeSourceFile: () => void;
|
||||||
calculateSkill: (exp: number, mult?: number) => number;
|
calculateSkill: (exp: number, mult?: number) => number;
|
||||||
calculateSkillProgress: (exp: number, mult?: number) => ISkillProgress;
|
calculateSkillProgress: (exp: number, mult?: number) => ISkillProgress;
|
||||||
resetWorkStatus: (generalType?: string, group?: string, workType?: string) => void;
|
resetWorkStatus: (generalType?: WorkType, group?: string, workType?: string) => void;
|
||||||
getWorkHackExpGain: () => number;
|
getWorkHackExpGain: () => number;
|
||||||
getWorkStrExpGain: () => number;
|
getWorkStrExpGain: () => number;
|
||||||
getWorkDefExpGain: () => number;
|
getWorkDefExpGain: () => number;
|
||||||
@ -304,7 +305,7 @@ export class PlayerObject implements IPlayer {
|
|||||||
sourceFileLvl: (n: number) => number;
|
sourceFileLvl: (n: number) => number;
|
||||||
startGraftAugmentationWork: (augmentationName: string, time: number) => void;
|
startGraftAugmentationWork: (augmentationName: string, time: number) => void;
|
||||||
graftAugmentationWork: (numCycles: number) => boolean;
|
graftAugmentationWork: (numCycles: number) => boolean;
|
||||||
finishGraftAugmentationWork: (cancelled: boolean) => string;
|
finishGraftAugmentationWork: (cancelled: boolean, singularity?: boolean) => string;
|
||||||
applyEntropy: (stacks?: number) => void;
|
applyEntropy: (stacks?: number) => void;
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
@ -400,7 +401,7 @@ export class PlayerObject implements IPlayer {
|
|||||||
//Flags/variables for working (Company, Faction, Creating Program, Taking Class)
|
//Flags/variables for working (Company, Faction, Creating Program, Taking Class)
|
||||||
this.isWorking = false;
|
this.isWorking = false;
|
||||||
this.focus = false;
|
this.focus = false;
|
||||||
this.workType = "";
|
this.workType = WorkType.None;
|
||||||
this.workCostMult = 1;
|
this.workCostMult = 1;
|
||||||
this.workExpMult = 1;
|
this.workExpMult = 1;
|
||||||
|
|
||||||
@ -432,9 +433,9 @@ export class PlayerObject implements IPlayer {
|
|||||||
this.graftAugmentationName = "";
|
this.graftAugmentationName = "";
|
||||||
this.timeWorkedGraftAugmentation = 0;
|
this.timeWorkedGraftAugmentation = 0;
|
||||||
|
|
||||||
this.className = "";
|
this.className = ClassType.None;
|
||||||
|
|
||||||
this.crimeType = "";
|
this.crimeType = CrimeType.None;
|
||||||
|
|
||||||
this.timeWorked = 0; //in m;
|
this.timeWorked = 0; //in m;
|
||||||
this.timeWorkedCreateProgram = 0;
|
this.timeWorkedCreateProgram = 0;
|
||||||
@ -465,12 +466,12 @@ export class PlayerObject implements IPlayer {
|
|||||||
this.bladeburner = null;
|
this.bladeburner = null;
|
||||||
this.bladeburner_max_stamina_mult = 1;
|
this.bladeburner_max_stamina_mult = 1;
|
||||||
this.bladeburner_stamina_gain_mult = 1;
|
this.bladeburner_stamina_gain_mult = 1;
|
||||||
this.bladeburner_analysis_mult = 1; //Field Analysis Onl;
|
this.bladeburner_analysis_mult = 1; //Field Analysis Only
|
||||||
this.bladeburner_success_chance_mult = 1;
|
this.bladeburner_success_chance_mult = 1;
|
||||||
|
|
||||||
// Sleeves & Re-sleeving
|
// Sleeves & Re-sleeving
|
||||||
this.sleeves = [];
|
this.sleeves = [];
|
||||||
this.sleevesFromCovenant = 0; // # of Duplicate sleeves purchased from the covenan;
|
this.sleevesFromCovenant = 0; // # of Duplicate sleeves purchased from the covenant
|
||||||
//bitnode
|
//bitnode
|
||||||
this.bitNodeN = 1;
|
this.bitNodeN = 1;
|
||||||
|
|
||||||
@ -485,8 +486,8 @@ export class PlayerObject implements IPlayer {
|
|||||||
this.playtimeSinceLastBitnode = 0;
|
this.playtimeSinceLastBitnode = 0;
|
||||||
|
|
||||||
// Keep track of where money comes from
|
// Keep track of where money comes from
|
||||||
this.moneySourceA = new MoneySourceTracker(); // Where money comes from since last-installed Augmentatio;
|
this.moneySourceA = new MoneySourceTracker(); // Where money comes from since last-installed Augmentation
|
||||||
this.moneySourceB = new MoneySourceTracker(); // Where money comes from for this entire BitNode ru;
|
this.moneySourceB = new MoneySourceTracker(); // Where money comes from for this entire BitNode run
|
||||||
// Production since last Augmentation installation
|
// Production since last Augmentation installation
|
||||||
this.scriptProdSinceLastAug = 0;
|
this.scriptProdSinceLastAug = 0;
|
||||||
|
|
||||||
@ -621,7 +622,7 @@ export class PlayerObject implements IPlayer {
|
|||||||
this.getUpgradeHomeRamCost = serverMethods.getUpgradeHomeRamCost;
|
this.getUpgradeHomeRamCost = serverMethods.getUpgradeHomeRamCost;
|
||||||
this.getUpgradeHomeCoresCost = serverMethods.getUpgradeHomeCoresCost;
|
this.getUpgradeHomeCoresCost = serverMethods.getUpgradeHomeCoresCost;
|
||||||
this.createHacknetServer = serverMethods.createHacknetServer;
|
this.createHacknetServer = serverMethods.createHacknetServer;
|
||||||
this.factionWorkType = "";
|
this.factionWorkType = PlayerFactionWorkType.None;
|
||||||
this.committingCrimeThruSingFn = false;
|
this.committingCrimeThruSingFn = false;
|
||||||
this.singFnCrimeWorkerScript = null;
|
this.singFnCrimeWorkerScript = null;
|
||||||
|
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
import { IPlayer } from "../IPlayer";
|
import { IPlayer } from "../IPlayer";
|
||||||
import { PlayerObject } from "./PlayerObject";
|
import { PlayerObject } from "./PlayerObject";
|
||||||
import { Augmentations } from "../../Augmentation/Augmentations";
|
|
||||||
import { applyAugmentation } from "../../Augmentation/AugmentationHelpers";
|
import { applyAugmentation } from "../../Augmentation/AugmentationHelpers";
|
||||||
import { PlayerOwnedAugmentation } from "../../Augmentation/PlayerOwnedAugmentation";
|
import { PlayerOwnedAugmentation } from "../../Augmentation/PlayerOwnedAugmentation";
|
||||||
import { AugmentationNames } from "../../Augmentation/data/AugmentationNames";
|
import { AugmentationNames } from "../../Augmentation/data/AugmentationNames";
|
||||||
@ -70,6 +69,8 @@ import { IPerson } from "../IPerson";
|
|||||||
import { Player } from "../../Player";
|
import { Player } from "../../Player";
|
||||||
import { graftingIntBonus } from "../Grafting/GraftingHelpers";
|
import { graftingIntBonus } from "../Grafting/GraftingHelpers";
|
||||||
|
|
||||||
|
import { WorkType, PlayerFactionWorkType, ClassType, CrimeType } from "../../utils/WorkType";
|
||||||
|
|
||||||
export function init(this: IPlayer): void {
|
export function init(this: IPlayer): void {
|
||||||
/* Initialize Player's home computer */
|
/* Initialize Player's home computer */
|
||||||
const t_homeComp = safetlyCreateUniqueServer({
|
const t_homeComp = safetlyCreateUniqueServer({
|
||||||
@ -144,8 +145,8 @@ export function prestigeAugmentation(this: PlayerObject): void {
|
|||||||
this.currentWorkFactionName = "";
|
this.currentWorkFactionName = "";
|
||||||
this.currentWorkFactionDescription = "";
|
this.currentWorkFactionDescription = "";
|
||||||
this.createProgramName = "";
|
this.createProgramName = "";
|
||||||
this.className = "";
|
this.className = ClassType.None;
|
||||||
this.crimeType = "";
|
this.crimeType = CrimeType.None;
|
||||||
|
|
||||||
this.workHackExpGainRate = 0;
|
this.workHackExpGainRate = 0;
|
||||||
this.workStrExpGainRate = 0;
|
this.workStrExpGainRate = 0;
|
||||||
@ -514,9 +515,8 @@ export function queryStatFromString(this: IPlayer, str: string): number {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/******* Working functions *******/
|
/******* Working functions *******/
|
||||||
export function resetWorkStatus(this: IPlayer, generalType?: string, group?: string, workType?: string): void {
|
export function resetWorkStatus(this: IPlayer, generalType?: WorkType, group?: string, workType?: string): void {
|
||||||
if (this.workType !== CONSTANTS.WorkTypeFaction && generalType === this.workType && group === this.companyName)
|
if (this.workType !== WorkType.Faction && generalType === this.workType && group === this.companyName) return;
|
||||||
return;
|
|
||||||
if (generalType === this.workType && group === this.currentWorkFactionName && workType === this.factionWorkType)
|
if (generalType === this.workType && group === this.currentWorkFactionName && workType === this.factionWorkType)
|
||||||
return;
|
return;
|
||||||
if (this.isWorking) this.singularityStopWork();
|
if (this.isWorking) this.singularityStopWork();
|
||||||
@ -547,8 +547,8 @@ export function resetWorkStatus(this: IPlayer, generalType?: string, group?: str
|
|||||||
this.currentWorkFactionDescription = "";
|
this.currentWorkFactionDescription = "";
|
||||||
this.createProgramName = "";
|
this.createProgramName = "";
|
||||||
this.graftAugmentationName = "";
|
this.graftAugmentationName = "";
|
||||||
this.className = "";
|
this.className = ClassType.None;
|
||||||
this.workType = "";
|
this.workType = WorkType.None;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function processWorkEarnings(this: IPlayer, numCycles = 1): void {
|
export function processWorkEarnings(this: IPlayer, numCycles = 1): void {
|
||||||
@ -583,10 +583,10 @@ export function processWorkEarnings(this: IPlayer, numCycles = 1): void {
|
|||||||
|
|
||||||
/* Working for Company */
|
/* Working for Company */
|
||||||
export function startWork(this: IPlayer, companyName: string): void {
|
export function startWork(this: IPlayer, companyName: string): void {
|
||||||
this.resetWorkStatus(CONSTANTS.WorkTypeCompany, companyName);
|
this.resetWorkStatus(WorkType.Company, companyName);
|
||||||
this.isWorking = true;
|
this.isWorking = true;
|
||||||
this.companyName = companyName;
|
this.companyName = companyName;
|
||||||
this.workType = CONSTANTS.WorkTypeCompany;
|
this.workType = WorkType.Company;
|
||||||
|
|
||||||
this.workHackExpGainRate = this.getWorkHackExpGain();
|
this.workHackExpGainRate = this.getWorkHackExpGain();
|
||||||
this.workStrExpGainRate = this.getWorkStrExpGain();
|
this.workStrExpGainRate = this.getWorkStrExpGain();
|
||||||
@ -603,27 +603,27 @@ export function startWork(this: IPlayer, companyName: string): void {
|
|||||||
export function process(this: IPlayer, router: IRouter, numCycles = 1): void {
|
export function process(this: IPlayer, router: IRouter, numCycles = 1): void {
|
||||||
// Working
|
// Working
|
||||||
if (this.isWorking) {
|
if (this.isWorking) {
|
||||||
if (this.workType == CONSTANTS.WorkTypeFaction) {
|
if (this.workType === WorkType.Faction) {
|
||||||
if (this.workForFaction(numCycles)) {
|
if (this.workForFaction(numCycles)) {
|
||||||
router.toFaction(Factions[this.currentWorkFactionName]);
|
router.toFaction(Factions[this.currentWorkFactionName]);
|
||||||
}
|
}
|
||||||
} else if (this.workType == CONSTANTS.WorkTypeCreateProgram) {
|
} else if (this.workType === WorkType.CreateProgram) {
|
||||||
if (this.createProgramWork(numCycles)) {
|
if (this.createProgramWork(numCycles)) {
|
||||||
router.toTerminal();
|
router.toTerminal();
|
||||||
}
|
}
|
||||||
} else if (this.workType == CONSTANTS.WorkTypeStudyClass) {
|
} else if (this.workType === WorkType.StudyClass) {
|
||||||
if (this.takeClass(numCycles)) {
|
if (this.takeClass(numCycles)) {
|
||||||
router.toCity();
|
router.toCity();
|
||||||
}
|
}
|
||||||
} else if (this.workType == CONSTANTS.WorkTypeCrime) {
|
} else if (this.workType === WorkType.Crime) {
|
||||||
if (this.commitCrime(numCycles)) {
|
if (this.commitCrime(numCycles)) {
|
||||||
router.toLocation(Locations[LocationName.Slums]);
|
router.toLocation(Locations[LocationName.Slums]);
|
||||||
}
|
}
|
||||||
} else if (this.workType == CONSTANTS.WorkTypeCompanyPartTime) {
|
} else if (this.workType === WorkType.CompanyPartTime) {
|
||||||
if (this.workPartTime(numCycles)) {
|
if (this.workPartTime(numCycles)) {
|
||||||
router.toCity();
|
router.toCity();
|
||||||
}
|
}
|
||||||
} else if (this.workType === CONSTANTS.WorkTypeGraftAugmentation) {
|
} else if (this.workType === WorkType.GraftAugmentation) {
|
||||||
if (this.graftAugmentationWork(numCycles)) {
|
if (this.graftAugmentationWork(numCycles)) {
|
||||||
router.toGrafting();
|
router.toGrafting();
|
||||||
}
|
}
|
||||||
@ -779,10 +779,10 @@ export function finishWork(this: IPlayer, cancelled: boolean, sing = false): str
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function startWorkPartTime(this: IPlayer, companyName: string): void {
|
export function startWorkPartTime(this: IPlayer, companyName: string): void {
|
||||||
this.resetWorkStatus(CONSTANTS.WorkTypeCompanyPartTime, companyName);
|
this.resetWorkStatus(WorkType.CompanyPartTime, companyName);
|
||||||
this.isWorking = true;
|
this.isWorking = true;
|
||||||
this.companyName = companyName;
|
this.companyName = companyName;
|
||||||
this.workType = CONSTANTS.WorkTypeCompanyPartTime;
|
this.workType = WorkType.CompanyPartTime;
|
||||||
|
|
||||||
this.workHackExpGainRate = this.getWorkHackExpGain();
|
this.workHackExpGainRate = this.getWorkHackExpGain();
|
||||||
this.workStrExpGainRate = this.getWorkStrExpGain();
|
this.workStrExpGainRate = this.getWorkStrExpGain();
|
||||||
@ -895,26 +895,26 @@ export function startFactionWork(this: IPlayer, faction: Faction): void {
|
|||||||
this.workRepGainRate *= BitNodeMultipliers.FactionWorkRepGain;
|
this.workRepGainRate *= BitNodeMultipliers.FactionWorkRepGain;
|
||||||
|
|
||||||
this.isWorking = true;
|
this.isWorking = true;
|
||||||
this.workType = CONSTANTS.WorkTypeFaction;
|
this.workType = WorkType.Faction;
|
||||||
this.currentWorkFactionName = faction.name;
|
this.currentWorkFactionName = faction.name;
|
||||||
|
|
||||||
this.timeNeededToCompleteWork = CONSTANTS.MillisecondsPer20Hours;
|
this.timeNeededToCompleteWork = CONSTANTS.MillisecondsPer20Hours;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function startFactionHackWork(this: IPlayer, faction: Faction): void {
|
export function startFactionHackWork(this: IPlayer, faction: Faction): void {
|
||||||
this.resetWorkStatus(CONSTANTS.WorkTypeFaction, faction.name, CONSTANTS.FactionWorkHacking);
|
this.resetWorkStatus(WorkType.Faction, faction.name, PlayerFactionWorkType.Hacking);
|
||||||
|
|
||||||
this.workHackExpGainRate = 0.15 * this.hacking_exp_mult * BitNodeMultipliers.FactionWorkExpGain;
|
this.workHackExpGainRate = 0.15 * this.hacking_exp_mult * BitNodeMultipliers.FactionWorkExpGain;
|
||||||
this.workRepGainRate = getHackingWorkRepGain(this, faction);
|
this.workRepGainRate = getHackingWorkRepGain(this, faction);
|
||||||
|
|
||||||
this.factionWorkType = CONSTANTS.FactionWorkHacking;
|
this.factionWorkType = PlayerFactionWorkType.Hacking;
|
||||||
this.currentWorkFactionDescription = "carrying out hacking contracts";
|
this.currentWorkFactionDescription = "carrying out hacking contracts";
|
||||||
|
|
||||||
this.startFactionWork(faction);
|
this.startFactionWork(faction);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function startFactionFieldWork(this: IPlayer, faction: Faction): void {
|
export function startFactionFieldWork(this: IPlayer, faction: Faction): void {
|
||||||
this.resetWorkStatus(CONSTANTS.WorkTypeFaction, faction.name, CONSTANTS.FactionWorkField);
|
this.resetWorkStatus(WorkType.Faction, faction.name, PlayerFactionWorkType.Field);
|
||||||
|
|
||||||
this.workHackExpGainRate = 0.1 * this.hacking_exp_mult * BitNodeMultipliers.FactionWorkExpGain;
|
this.workHackExpGainRate = 0.1 * this.hacking_exp_mult * BitNodeMultipliers.FactionWorkExpGain;
|
||||||
this.workStrExpGainRate = 0.1 * this.strength_exp_mult * BitNodeMultipliers.FactionWorkExpGain;
|
this.workStrExpGainRate = 0.1 * this.strength_exp_mult * BitNodeMultipliers.FactionWorkExpGain;
|
||||||
@ -924,14 +924,14 @@ export function startFactionFieldWork(this: IPlayer, faction: Faction): void {
|
|||||||
this.workChaExpGainRate = 0.1 * this.charisma_exp_mult * BitNodeMultipliers.FactionWorkExpGain;
|
this.workChaExpGainRate = 0.1 * this.charisma_exp_mult * BitNodeMultipliers.FactionWorkExpGain;
|
||||||
this.workRepGainRate = getFactionFieldWorkRepGain(this, faction);
|
this.workRepGainRate = getFactionFieldWorkRepGain(this, faction);
|
||||||
|
|
||||||
this.factionWorkType = CONSTANTS.FactionWorkField;
|
this.factionWorkType = PlayerFactionWorkType.Field;
|
||||||
this.currentWorkFactionDescription = "carrying out field missions";
|
this.currentWorkFactionDescription = "carrying out field missions";
|
||||||
|
|
||||||
this.startFactionWork(faction);
|
this.startFactionWork(faction);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function startFactionSecurityWork(this: IPlayer, faction: Faction): void {
|
export function startFactionSecurityWork(this: IPlayer, faction: Faction): void {
|
||||||
this.resetWorkStatus(CONSTANTS.WorkTypeFaction, faction.name, CONSTANTS.FactionWorkSecurity);
|
this.resetWorkStatus(WorkType.Faction, faction.name, PlayerFactionWorkType.Security);
|
||||||
|
|
||||||
this.workHackExpGainRate = 0.05 * this.hacking_exp_mult * BitNodeMultipliers.FactionWorkExpGain;
|
this.workHackExpGainRate = 0.05 * this.hacking_exp_mult * BitNodeMultipliers.FactionWorkExpGain;
|
||||||
this.workStrExpGainRate = 0.15 * this.strength_exp_mult * BitNodeMultipliers.FactionWorkExpGain;
|
this.workStrExpGainRate = 0.15 * this.strength_exp_mult * BitNodeMultipliers.FactionWorkExpGain;
|
||||||
@ -941,7 +941,7 @@ export function startFactionSecurityWork(this: IPlayer, faction: Faction): void
|
|||||||
this.workChaExpGainRate = 0.0 * this.charisma_exp_mult * BitNodeMultipliers.FactionWorkExpGain;
|
this.workChaExpGainRate = 0.0 * this.charisma_exp_mult * BitNodeMultipliers.FactionWorkExpGain;
|
||||||
this.workRepGainRate = getFactionSecurityWorkRepGain(this, faction);
|
this.workRepGainRate = getFactionSecurityWorkRepGain(this, faction);
|
||||||
|
|
||||||
this.factionWorkType = CONSTANTS.FactionWorkSecurity;
|
this.factionWorkType = PlayerFactionWorkType.Security;
|
||||||
this.currentWorkFactionDescription = "performing security detail";
|
this.currentWorkFactionDescription = "performing security detail";
|
||||||
|
|
||||||
this.startFactionWork(faction);
|
this.startFactionWork(faction);
|
||||||
@ -956,13 +956,13 @@ export function workForFaction(this: IPlayer, numCycles: number): boolean {
|
|||||||
|
|
||||||
//Constantly update the rep gain rate
|
//Constantly update the rep gain rate
|
||||||
switch (this.factionWorkType) {
|
switch (this.factionWorkType) {
|
||||||
case CONSTANTS.FactionWorkHacking:
|
case PlayerFactionWorkType.Hacking:
|
||||||
this.workRepGainRate = getHackingWorkRepGain(this, faction);
|
this.workRepGainRate = getHackingWorkRepGain(this, faction);
|
||||||
break;
|
break;
|
||||||
case CONSTANTS.FactionWorkField:
|
case PlayerFactionWorkType.Field:
|
||||||
this.workRepGainRate = getFactionFieldWorkRepGain(this, faction);
|
this.workRepGainRate = getFactionFieldWorkRepGain(this, faction);
|
||||||
break;
|
break;
|
||||||
case CONSTANTS.FactionWorkSecurity:
|
case PlayerFactionWorkType.Security:
|
||||||
this.workRepGainRate = getFactionSecurityWorkRepGain(this, faction);
|
this.workRepGainRate = getFactionSecurityWorkRepGain(this, faction);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
@ -1275,7 +1275,7 @@ export function getWorkRepGain(this: IPlayer): number {
|
|||||||
export function startCreateProgramWork(this: IPlayer, programName: string, time: number, reqLevel: number): void {
|
export function startCreateProgramWork(this: IPlayer, programName: string, time: number, reqLevel: number): void {
|
||||||
this.resetWorkStatus();
|
this.resetWorkStatus();
|
||||||
this.isWorking = true;
|
this.isWorking = true;
|
||||||
this.workType = CONSTANTS.WorkTypeCreateProgram;
|
this.workType = WorkType.CreateProgram;
|
||||||
|
|
||||||
//Time needed to complete work affected by hacking skill (linearly based on
|
//Time needed to complete work affected by hacking skill (linearly based on
|
||||||
//ratio of (your skill - required level) to MAX skill)
|
//ratio of (your skill - required level) to MAX skill)
|
||||||
@ -1352,7 +1352,7 @@ export function finishCreateProgramWork(this: IPlayer, cancelled: boolean): stri
|
|||||||
export function startGraftAugmentationWork(this: IPlayer, augmentationName: string, time: number): void {
|
export function startGraftAugmentationWork(this: IPlayer, augmentationName: string, time: number): void {
|
||||||
this.resetWorkStatus();
|
this.resetWorkStatus();
|
||||||
this.isWorking = true;
|
this.isWorking = true;
|
||||||
this.workType = CONSTANTS.WorkTypeGraftAugmentation;
|
this.workType = WorkType.GraftAugmentation;
|
||||||
|
|
||||||
this.timeNeededToCompleteWork = time;
|
this.timeNeededToCompleteWork = time;
|
||||||
this.graftAugmentationName = augmentationName;
|
this.graftAugmentationName = augmentationName;
|
||||||
@ -1377,10 +1377,10 @@ export function craftAugmentationWork(this: IPlayer, numCycles: number): boolean
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function finishGraftAugmentationWork(this: IPlayer, cancelled: boolean): string {
|
export function finishGraftAugmentationWork(this: IPlayer, cancelled: boolean, singularity = false): string {
|
||||||
const augName = this.graftAugmentationName;
|
const augName = this.graftAugmentationName;
|
||||||
if (cancelled === false) {
|
if (cancelled === false) {
|
||||||
applyAugmentation(Augmentations[augName]);
|
applyAugmentation({ name: augName, level: 1 });
|
||||||
|
|
||||||
if (!this.hasAugmentation(AugmentationNames.CongruityImplant)) {
|
if (!this.hasAugmentation(AugmentationNames.CongruityImplant)) {
|
||||||
this.entropy += 1;
|
this.entropy += 1;
|
||||||
@ -1391,7 +1391,7 @@ export function finishGraftAugmentationWork(this: IPlayer, cancelled: boolean):
|
|||||||
`You've finished grafting ${augName}.<br>The augmentation has been applied to your body` +
|
`You've finished grafting ${augName}.<br>The augmentation has been applied to your body` +
|
||||||
(this.hasAugmentation(AugmentationNames.CongruityImplant) ? "." : ", but you feel a bit off."),
|
(this.hasAugmentation(AugmentationNames.CongruityImplant) ? "." : ", but you feel a bit off."),
|
||||||
);
|
);
|
||||||
} else {
|
} else if (cancelled && singularity === false) {
|
||||||
dialogBoxCreate(`You cancelled the grafting of ${augName}.<br>Your money was not returned to you.`);
|
dialogBoxCreate(`You cancelled the grafting of ${augName}.<br>Your money was not returned to you.`);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1406,10 +1406,10 @@ export function finishGraftAugmentationWork(this: IPlayer, cancelled: boolean):
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Studying/Taking Classes */
|
/* Studying/Taking Classes */
|
||||||
export function startClass(this: IPlayer, costMult: number, expMult: number, className: string): void {
|
export function startClass(this: IPlayer, costMult: number, expMult: number, className: ClassType): void {
|
||||||
this.resetWorkStatus();
|
this.resetWorkStatus();
|
||||||
this.isWorking = true;
|
this.isWorking = true;
|
||||||
this.workType = CONSTANTS.WorkTypeStudyClass;
|
this.workType = WorkType.StudyClass;
|
||||||
this.workCostMult = costMult;
|
this.workCostMult = costMult;
|
||||||
this.workExpMult = expMult;
|
this.workExpMult = expMult;
|
||||||
this.className = className;
|
this.className = className;
|
||||||
@ -1501,7 +1501,7 @@ export function finishClass(this: IPlayer, sing = false): string {
|
|||||||
export function startCrime(
|
export function startCrime(
|
||||||
this: IPlayer,
|
this: IPlayer,
|
||||||
router: IRouter,
|
router: IRouter,
|
||||||
crimeType: string,
|
crimeType: CrimeType,
|
||||||
hackExp: number,
|
hackExp: number,
|
||||||
strExp: number,
|
strExp: number,
|
||||||
defExp: number,
|
defExp: number,
|
||||||
@ -1517,7 +1517,7 @@ export function startCrime(
|
|||||||
this.resetWorkStatus();
|
this.resetWorkStatus();
|
||||||
this.isWorking = true;
|
this.isWorking = true;
|
||||||
this.focus = true;
|
this.focus = true;
|
||||||
this.workType = CONSTANTS.WorkTypeCrime;
|
this.workType = WorkType.Crime;
|
||||||
|
|
||||||
if (workerscript !== null) {
|
if (workerscript !== null) {
|
||||||
this.committingCrimeThruSingFn = true;
|
this.committingCrimeThruSingFn = true;
|
||||||
@ -1682,7 +1682,7 @@ export function finishCrime(this: IPlayer, cancelled: boolean): string {
|
|||||||
this.committingCrimeThruSingFn = false;
|
this.committingCrimeThruSingFn = false;
|
||||||
this.singFnCrimeWorkerScript = null;
|
this.singFnCrimeWorkerScript = null;
|
||||||
this.isWorking = false;
|
this.isWorking = false;
|
||||||
this.crimeType = "";
|
this.crimeType = CrimeType.None;
|
||||||
this.resetWorkStatus();
|
this.resetWorkStatus();
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
@ -1695,24 +1695,27 @@ export function singularityStopWork(this: IPlayer): string {
|
|||||||
}
|
}
|
||||||
let res = ""; //Earnings text for work
|
let res = ""; //Earnings text for work
|
||||||
switch (this.workType) {
|
switch (this.workType) {
|
||||||
case CONSTANTS.WorkTypeStudyClass:
|
case WorkType.StudyClass:
|
||||||
res = this.finishClass(true);
|
res = this.finishClass(true);
|
||||||
break;
|
break;
|
||||||
case CONSTANTS.WorkTypeCompany:
|
case WorkType.Company:
|
||||||
res = this.finishWork(true, true);
|
res = this.finishWork(true, true);
|
||||||
break;
|
break;
|
||||||
case CONSTANTS.WorkTypeCompanyPartTime:
|
case WorkType.CompanyPartTime:
|
||||||
res = this.finishWorkPartTime(true);
|
res = this.finishWorkPartTime(true);
|
||||||
break;
|
break;
|
||||||
case CONSTANTS.WorkTypeFaction:
|
case WorkType.Faction:
|
||||||
res = this.finishFactionWork(true, true);
|
res = this.finishFactionWork(true, true);
|
||||||
break;
|
break;
|
||||||
case CONSTANTS.WorkTypeCreateProgram:
|
case WorkType.CreateProgram:
|
||||||
res = this.finishCreateProgramWork(true);
|
res = this.finishCreateProgramWork(true);
|
||||||
break;
|
break;
|
||||||
case CONSTANTS.WorkTypeCrime:
|
case WorkType.Crime:
|
||||||
res = this.finishCrime(true);
|
res = this.finishCrime(true);
|
||||||
break;
|
break;
|
||||||
|
case WorkType.GraftAugmentation:
|
||||||
|
res = this.finishGraftAugmentationWork(true, true);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
console.error(`Unrecognized work type (${this.workType})`);
|
console.error(`Unrecognized work type (${this.workType})`);
|
||||||
return "";
|
return "";
|
||||||
@ -1761,14 +1764,6 @@ export function hospitalize(this: IPlayer): number {
|
|||||||
//The 'sing' argument designates whether or not this is being called from
|
//The 'sing' argument designates whether or not this is being called from
|
||||||
//the applyToCompany() Netscript Singularity function
|
//the applyToCompany() Netscript Singularity function
|
||||||
export function applyForJob(this: IPlayer, entryPosType: CompanyPosition, sing = false): boolean {
|
export function applyForJob(this: IPlayer, entryPosType: CompanyPosition, sing = false): boolean {
|
||||||
// Get current company and job
|
|
||||||
let currCompany = null;
|
|
||||||
if (this.companyName !== "") {
|
|
||||||
currCompany = Companies[this.companyName];
|
|
||||||
}
|
|
||||||
const currPositionName = this.jobs[this.companyName];
|
|
||||||
|
|
||||||
// Get company that's being applied to
|
|
||||||
const company = Companies[this.location]; //Company being applied to
|
const company = Companies[this.location]; //Company being applied to
|
||||||
if (!(company instanceof Company)) {
|
if (!(company instanceof Company)) {
|
||||||
console.error(`Could not find company that matches the location: ${this.location}. Player.applyToCompany() failed`);
|
console.error(`Could not find company that matches the location: ${this.location}. Player.applyToCompany() failed`);
|
||||||
@ -1778,66 +1773,44 @@ export function applyForJob(this: IPlayer, entryPosType: CompanyPosition, sing =
|
|||||||
let pos = entryPosType;
|
let pos = entryPosType;
|
||||||
|
|
||||||
if (!this.isQualified(company, pos)) {
|
if (!this.isQualified(company, pos)) {
|
||||||
const reqText = getJobRequirementText(company, pos);
|
|
||||||
if (!sing) {
|
if (!sing) {
|
||||||
dialogBoxCreate("Unfortunately, you do not qualify for this position<br>" + reqText);
|
dialogBoxCreate("Unfortunately, you do not qualify for this position<br>" + getJobRequirementText(company, pos));
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if this company has the position
|
|
||||||
if (!company.hasPosition(pos)) {
|
if (!company.hasPosition(pos)) {
|
||||||
|
console.error(`Company ${company.name} does not have position ${pos}. Player.applyToCompany() failed`);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
const newPos = getNextCompanyPositionHelper(pos);
|
const nextPos = getNextCompanyPositionHelper(pos);
|
||||||
if (newPos == null) {
|
if (nextPos == null) break;
|
||||||
break;
|
if (company.hasPosition(nextPos) && this.isQualified(company, nextPos)) {
|
||||||
}
|
pos = nextPos;
|
||||||
|
} else break;
|
||||||
//Check if this company has this position
|
|
||||||
if (company.hasPosition(newPos)) {
|
|
||||||
if (!this.isQualified(company, newPos)) {
|
|
||||||
//If player not qualified for next job, break loop so player will be given current job
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
pos = newPos;
|
|
||||||
} else {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//Check if the determined job is the same as the player's current job
|
//Check if player already has the assigned job
|
||||||
if (currCompany != null) {
|
if (this.jobs[company.name] === pos.name) {
|
||||||
if (currCompany.name == company.name && pos.name == currPositionName) {
|
if (!sing) {
|
||||||
const nextPos = getNextCompanyPositionHelper(pos);
|
const nextPos = getNextCompanyPositionHelper(pos);
|
||||||
if (nextPos == null) {
|
if (nextPos == null || !company.hasPosition(nextPos)) {
|
||||||
if (!sing) {
|
dialogBoxCreate("You are already at the highest position for your field! No promotion available");
|
||||||
dialogBoxCreate("You are already at the highest position for your field! No promotion available");
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
} else if (company.hasPosition(nextPos)) {
|
|
||||||
if (!sing) {
|
|
||||||
const reqText = getJobRequirementText(company, nextPos);
|
|
||||||
dialogBoxCreate("Unfortunately, you do not qualify for a promotion<br>" + reqText);
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
} else {
|
} else {
|
||||||
if (!sing) {
|
const reqText = getJobRequirementText(company, nextPos);
|
||||||
dialogBoxCreate("You are already at the highest position for your field! No promotion available");
|
dialogBoxCreate("Unfortunately, you do not qualify for a promotion<br>" + reqText);
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.jobs[company.name] = pos.name;
|
this.jobs[company.name] = pos.name;
|
||||||
if (!this.focus && this.isWorking && this.companyName !== this.location) this.resetWorkStatus();
|
if (!this.isWorking || this.workType !== WorkType.Company) this.companyName = company.name;
|
||||||
this.companyName = this.location;
|
|
||||||
|
|
||||||
if (!sing) {
|
if (!sing) {
|
||||||
dialogBoxCreate("Congratulations! You were offered a new job at " + this.companyName + " as a " + pos.name + "!");
|
dialogBoxCreate("Congratulations! You were offered a new job at " + company.name + " as a " + pos.name + "!");
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -1882,8 +1855,8 @@ export function getNextCompanyPosition(
|
|||||||
return entryPosType;
|
return entryPosType;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function quitJob(this: IPlayer, company: string): void {
|
export function quitJob(this: IPlayer, company: string, _sing = false): void {
|
||||||
if (this.isWorking == true && this.workType.includes("Working for Company") && this.companyName == company) {
|
if (this.isWorking == true && this.workType !== WorkType.Company && this.companyName == company) {
|
||||||
this.finishWork(true);
|
this.finishWork(true);
|
||||||
}
|
}
|
||||||
delete this.jobs[company];
|
delete this.jobs[company];
|
||||||
|
@ -769,7 +769,7 @@ export class Sleeve extends Person {
|
|||||||
}
|
}
|
||||||
|
|
||||||
tryBuyAugmentation(p: IPlayer, aug: Augmentation): boolean {
|
tryBuyAugmentation(p: IPlayer, aug: Augmentation): boolean {
|
||||||
if (!p.canAfford(aug.startingCost)) {
|
if (!p.canAfford(aug.baseCost)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -778,7 +778,7 @@ export class Sleeve extends Person {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
p.loseMoney(aug.startingCost, "sleeves");
|
p.loseMoney(aug.baseCost, "sleeves");
|
||||||
this.installAugmentation(aug);
|
this.installAugmentation(aug);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -4,7 +4,7 @@ import { Sleeve } from "./Sleeve";
|
|||||||
import { IPlayer } from "../IPlayer";
|
import { IPlayer } from "../IPlayer";
|
||||||
|
|
||||||
import { Augmentation } from "../../Augmentation/Augmentation";
|
import { Augmentation } from "../../Augmentation/Augmentation";
|
||||||
import { Augmentations } from "../../Augmentation/Augmentations";
|
import { StaticAugmentations } from "../../Augmentation/StaticAugmentations";
|
||||||
import { Faction } from "../../Faction/Faction";
|
import { Faction } from "../../Faction/Faction";
|
||||||
import { Factions } from "../../Faction/Factions";
|
import { Factions } from "../../Faction/Factions";
|
||||||
|
|
||||||
@ -64,13 +64,13 @@ export function findSleevePurchasableAugs(sleeve: Sleeve, p: IPlayer): Augmentat
|
|||||||
if (p.inGang()) {
|
if (p.inGang()) {
|
||||||
const fac = p.getGangFaction();
|
const fac = p.getGangFaction();
|
||||||
|
|
||||||
for (const augName of Object.keys(Augmentations)) {
|
for (const augName of Object.keys(StaticAugmentations)) {
|
||||||
const aug = Augmentations[augName];
|
const aug = StaticAugmentations[augName];
|
||||||
if (!isAvailableForSleeve(aug)) {
|
if (!isAvailableForSleeve(aug)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fac.playerReputation > aug.baseRepRequirement) {
|
if (fac.playerReputation > aug.getCost(p).repCost) {
|
||||||
availableAugs.push(aug);
|
availableAugs.push(aug);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -89,12 +89,12 @@ export function findSleevePurchasableAugs(sleeve: Sleeve, p: IPlayer): Augmentat
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (const augName of fac.augmentations) {
|
for (const augName of fac.augmentations) {
|
||||||
const aug: Augmentation = Augmentations[augName];
|
const aug: Augmentation = StaticAugmentations[augName];
|
||||||
if (!isAvailableForSleeve(aug)) {
|
if (!isAvailableForSleeve(aug)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fac.playerReputation > aug.baseRepRequirement) {
|
if (fac.playerReputation > aug.getCost(p).repCost) {
|
||||||
availableAugs.push(aug);
|
availableAugs.push(aug);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -52,7 +52,7 @@ export function SleeveAugmentationsModal(props: IProps): React.ReactElement {
|
|||||||
ownedAugNames={ownedAugNames}
|
ownedAugNames={ownedAugNames}
|
||||||
player={player}
|
player={player}
|
||||||
canPurchase={(player, aug) => {
|
canPurchase={(player, aug) => {
|
||||||
return player.money > aug.startingCost;
|
return player.money > aug.baseCost;
|
||||||
}}
|
}}
|
||||||
purchaseAugmentation={(player, aug, _showModal) => {
|
purchaseAugmentation={(player, aug, _showModal) => {
|
||||||
props.sleeve.tryBuyAugmentation(player, aug);
|
props.sleeve.tryBuyAugmentation(player, aug);
|
||||||
|
@ -1,23 +1,19 @@
|
|||||||
|
import { Box, Button, Paper, Tooltip, Typography } from "@mui/material";
|
||||||
import React, { useState } from "react";
|
import React, { useState } from "react";
|
||||||
|
|
||||||
import { Box, Paper, Typography, Button, Tooltip } from "@mui/material";
|
|
||||||
|
|
||||||
import { CONSTANTS } from "../../../Constants";
|
import { CONSTANTS } from "../../../Constants";
|
||||||
import { Crimes } from "../../../Crime/Crimes";
|
import { Crimes } from "../../../Crime/Crimes";
|
||||||
import { numeralWrapper } from "../../../ui/numeralFormat";
|
|
||||||
import { createProgressBarText } from "../../../utils/helpers/createProgressBarText";
|
|
||||||
import { use } from "../../../ui/Context";
|
|
||||||
import { FactionWorkType } from "../../../Faction/FactionWorkTypeEnum";
|
import { FactionWorkType } from "../../../Faction/FactionWorkTypeEnum";
|
||||||
|
import { use } from "../../../ui/Context";
|
||||||
|
import { numeralWrapper } from "../../../ui/numeralFormat";
|
||||||
|
import { ProgressBar } from "../../../ui/React/Progress";
|
||||||
import { Sleeve } from "../Sleeve";
|
import { Sleeve } from "../Sleeve";
|
||||||
import { SleeveTaskType } from "../SleeveTaskTypesEnum";
|
import { SleeveTaskType } from "../SleeveTaskTypesEnum";
|
||||||
|
|
||||||
import { SleeveAugmentationsModal } from "./SleeveAugmentationsModal";
|
|
||||||
import { TravelModal } from "./TravelModal";
|
|
||||||
import { StatsElement, EarningsElement } from "./StatsElement";
|
|
||||||
import { MoreStatsModal } from "./MoreStatsModal";
|
|
||||||
import { MoreEarningsModal } from "./MoreEarningsModal";
|
import { MoreEarningsModal } from "./MoreEarningsModal";
|
||||||
|
import { MoreStatsModal } from "./MoreStatsModal";
|
||||||
|
import { SleeveAugmentationsModal } from "./SleeveAugmentationsModal";
|
||||||
|
import { EarningsElement, StatsElement } from "./StatsElement";
|
||||||
import { TaskSelector } from "./TaskSelector";
|
import { TaskSelector } from "./TaskSelector";
|
||||||
|
import { TravelModal } from "./TravelModal";
|
||||||
|
|
||||||
interface IProps {
|
interface IProps {
|
||||||
sleeve: Sleeve;
|
sleeve: Sleeve;
|
||||||
@ -148,76 +144,72 @@ export function SleeveElem(props: IProps): React.ReactElement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Box component={Paper} sx={{ width: "auto" }}>
|
<>
|
||||||
<Box sx={{ m: 1 }}>
|
<Paper sx={{ p: 1, display: "grid", gridTemplateColumns: "1fr 1fr", width: "auto", gap: 1 }}>
|
||||||
<Box display="grid" sx={{ gridTemplateColumns: "1fr 1fr", width: "100%", gap: 1 }}>
|
<span>
|
||||||
<Box>
|
<StatsElement sleeve={props.sleeve} />
|
||||||
<StatsElement sleeve={props.sleeve} />
|
<Box display="grid" sx={{ gridTemplateColumns: "1fr 1fr", width: "100%" }}>
|
||||||
<Box display="grid" sx={{ gridTemplateColumns: "1fr 1fr", width: "100%" }}>
|
<Button onClick={() => setStatsOpen(true)}>More Stats</Button>
|
||||||
<Button onClick={() => setStatsOpen(true)}>More Stats</Button>
|
<Button onClick={() => setEarningsOpen(true)}>More Earnings Info</Button>
|
||||||
<Button onClick={() => setEarningsOpen(true)}>More Earnings Info</Button>
|
<Tooltip title={player.money < CONSTANTS.TravelCost ? <Typography>Insufficient funds</Typography> : ""}>
|
||||||
<Tooltip title={player.money < CONSTANTS.TravelCost ? <Typography>Insufficient funds</Typography> : ""}>
|
<span>
|
||||||
<span>
|
<Button
|
||||||
<Button
|
onClick={() => setTravelOpen(true)}
|
||||||
onClick={() => setTravelOpen(true)}
|
disabled={player.money < CONSTANTS.TravelCost}
|
||||||
disabled={player.money < CONSTANTS.TravelCost}
|
sx={{ width: "100%", height: "100%" }}
|
||||||
sx={{ width: "100%", height: "100%" }}
|
>
|
||||||
>
|
Travel
|
||||||
Travel
|
</Button>
|
||||||
</Button>
|
</span>
|
||||||
</span>
|
</Tooltip>
|
||||||
</Tooltip>
|
<Tooltip
|
||||||
<Tooltip
|
title={props.sleeve.shock < 100 ? <Typography>Unlocked when sleeve has fully recovered</Typography> : ""}
|
||||||
title={
|
>
|
||||||
props.sleeve.shock < 100 ? <Typography>Unlocked when sleeve has fully recovered</Typography> : ""
|
<span>
|
||||||
}
|
<Button
|
||||||
>
|
onClick={() => setAugmentationsOpen(true)}
|
||||||
<span>
|
disabled={props.sleeve.shock < 100}
|
||||||
<Button
|
sx={{ width: "100%", height: "100%" }}
|
||||||
onClick={() => setAugmentationsOpen(true)}
|
>
|
||||||
disabled={props.sleeve.shock < 100}
|
Manage Augmentations
|
||||||
sx={{ width: "100%", height: "100%" }}
|
</Button>
|
||||||
>
|
</span>
|
||||||
Manage Augmentations
|
</Tooltip>
|
||||||
</Button>
|
|
||||||
</span>
|
|
||||||
</Tooltip>
|
|
||||||
</Box>
|
|
||||||
</Box>
|
</Box>
|
||||||
<Box>
|
</span>
|
||||||
<EarningsElement sleeve={props.sleeve} />
|
<span>
|
||||||
<Box>
|
<EarningsElement sleeve={props.sleeve} />
|
||||||
<TaskSelector player={player} sleeve={props.sleeve} setABC={setABC} />
|
<TaskSelector player={player} sleeve={props.sleeve} setABC={setABC} />
|
||||||
<Button onClick={setTask} sx={{ width: "100%" }}>
|
<Button onClick={setTask} sx={{ width: "100%" }}>
|
||||||
Set Task
|
Set Task
|
||||||
</Button>
|
</Button>
|
||||||
<Typography>{desc}</Typography>
|
<Typography>{desc}</Typography>
|
||||||
<Typography>
|
<Typography>
|
||||||
{(props.sleeve.currentTask === SleeveTaskType.Crime ||
|
{(props.sleeve.currentTask === SleeveTaskType.Crime ||
|
||||||
props.sleeve.currentTask === SleeveTaskType.Bladeburner) &&
|
props.sleeve.currentTask === SleeveTaskType.Bladeburner) &&
|
||||||
props.sleeve.currentTaskMaxTime > 0 &&
|
props.sleeve.currentTaskMaxTime > 0 && (
|
||||||
createProgressBarText({
|
<ProgressBar
|
||||||
progress: props.sleeve.currentTaskTime / props.sleeve.currentTaskMaxTime,
|
variant="determinate"
|
||||||
totalTicks: 25,
|
value={(props.sleeve.currentTaskTime / props.sleeve.currentTaskMaxTime) * 100}
|
||||||
})}
|
color="primary"
|
||||||
</Typography>
|
/>
|
||||||
</Box>
|
)}
|
||||||
</Box>
|
</Typography>
|
||||||
<MoreStatsModal open={statsOpen} onClose={() => setStatsOpen(false)} sleeve={props.sleeve} />
|
</span>
|
||||||
<MoreEarningsModal open={earningsOpen} onClose={() => setEarningsOpen(false)} sleeve={props.sleeve} />
|
</Paper>
|
||||||
<TravelModal
|
<MoreStatsModal open={statsOpen} onClose={() => setStatsOpen(false)} sleeve={props.sleeve} />
|
||||||
open={travelOpen}
|
<MoreEarningsModal open={earningsOpen} onClose={() => setEarningsOpen(false)} sleeve={props.sleeve} />
|
||||||
onClose={() => setTravelOpen(false)}
|
<TravelModal
|
||||||
sleeve={props.sleeve}
|
open={travelOpen}
|
||||||
rerender={props.rerender}
|
onClose={() => setTravelOpen(false)}
|
||||||
/>
|
sleeve={props.sleeve}
|
||||||
<SleeveAugmentationsModal
|
rerender={props.rerender}
|
||||||
open={augmentationsOpen}
|
/>
|
||||||
onClose={() => setAugmentationsOpen(false)}
|
<SleeveAugmentationsModal
|
||||||
sleeve={props.sleeve}
|
open={augmentationsOpen}
|
||||||
/>
|
onClose={() => setAugmentationsOpen(false)}
|
||||||
</Box>
|
sleeve={props.sleeve}
|
||||||
</Box>
|
/>
|
||||||
</Box>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -86,7 +86,9 @@ function possibleFactions(player: IPlayer, sleeve: Sleeve): string[] {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return factions.filter((faction) => {
|
return factions.filter((faction) => {
|
||||||
const facInfo = Factions[faction].getInfo();
|
const factionObj = Factions[faction];
|
||||||
|
if (!factionObj) return false;
|
||||||
|
const facInfo = factionObj.getInfo();
|
||||||
return facInfo.offerHackingWork || facInfo.offerFieldWork || facInfo.offerSecurityWork;
|
return facInfo.offerHackingWork || facInfo.offerFieldWork || facInfo.offerSecurityWork;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import { CONSTANTS } from "../../Constants";
|
import { CONSTANTS } from "../../Constants";
|
||||||
import { BitNodeMultipliers } from "../../BitNode/BitNodeMultipliers";
|
import { BitNodeMultipliers } from "../../BitNode/BitNodeMultipliers";
|
||||||
import { IPlayer } from "../IPlayer";
|
import { IPlayer } from "../IPlayer";
|
||||||
|
import { ClassType } from "../../utils/WorkType";
|
||||||
|
|
||||||
export interface WorkEarnings {
|
export interface WorkEarnings {
|
||||||
workMoneyLossRate: number;
|
workMoneyLossRate: number;
|
||||||
@ -25,43 +26,43 @@ export function calculateClassEarnings(player: IPlayer): WorkEarnings {
|
|||||||
chaExp = 0;
|
chaExp = 0;
|
||||||
const hashManager = player.hashManager;
|
const hashManager = player.hashManager;
|
||||||
switch (player.className) {
|
switch (player.className) {
|
||||||
case CONSTANTS.ClassStudyComputerScience:
|
case ClassType.StudyComputerScience:
|
||||||
hackExp =
|
hackExp =
|
||||||
((CONSTANTS.ClassStudyComputerScienceBaseExp * player.workExpMult) / gameCPS) * hashManager.getStudyMult();
|
((CONSTANTS.ClassStudyComputerScienceBaseExp * player.workExpMult) / gameCPS) * hashManager.getStudyMult();
|
||||||
break;
|
break;
|
||||||
case CONSTANTS.ClassDataStructures:
|
case ClassType.DataStructures:
|
||||||
cost = (CONSTANTS.ClassDataStructuresBaseCost * player.workCostMult) / gameCPS;
|
cost = (CONSTANTS.ClassDataStructuresBaseCost * player.workCostMult) / gameCPS;
|
||||||
hackExp = ((CONSTANTS.ClassDataStructuresBaseExp * player.workExpMult) / gameCPS) * hashManager.getStudyMult();
|
hackExp = ((CONSTANTS.ClassDataStructuresBaseExp * player.workExpMult) / gameCPS) * hashManager.getStudyMult();
|
||||||
break;
|
break;
|
||||||
case CONSTANTS.ClassNetworks:
|
case ClassType.Networks:
|
||||||
cost = (CONSTANTS.ClassNetworksBaseCost * player.workCostMult) / gameCPS;
|
cost = (CONSTANTS.ClassNetworksBaseCost * player.workCostMult) / gameCPS;
|
||||||
hackExp = ((CONSTANTS.ClassNetworksBaseExp * player.workExpMult) / gameCPS) * hashManager.getStudyMult();
|
hackExp = ((CONSTANTS.ClassNetworksBaseExp * player.workExpMult) / gameCPS) * hashManager.getStudyMult();
|
||||||
break;
|
break;
|
||||||
case CONSTANTS.ClassAlgorithms:
|
case ClassType.Algorithms:
|
||||||
cost = (CONSTANTS.ClassAlgorithmsBaseCost * player.workCostMult) / gameCPS;
|
cost = (CONSTANTS.ClassAlgorithmsBaseCost * player.workCostMult) / gameCPS;
|
||||||
hackExp = ((CONSTANTS.ClassAlgorithmsBaseExp * player.workExpMult) / gameCPS) * hashManager.getStudyMult();
|
hackExp = ((CONSTANTS.ClassAlgorithmsBaseExp * player.workExpMult) / gameCPS) * hashManager.getStudyMult();
|
||||||
break;
|
break;
|
||||||
case CONSTANTS.ClassManagement:
|
case ClassType.Management:
|
||||||
cost = (CONSTANTS.ClassManagementBaseCost * player.workCostMult) / gameCPS;
|
cost = (CONSTANTS.ClassManagementBaseCost * player.workCostMult) / gameCPS;
|
||||||
chaExp = ((CONSTANTS.ClassManagementBaseExp * player.workExpMult) / gameCPS) * hashManager.getStudyMult();
|
chaExp = ((CONSTANTS.ClassManagementBaseExp * player.workExpMult) / gameCPS) * hashManager.getStudyMult();
|
||||||
break;
|
break;
|
||||||
case CONSTANTS.ClassLeadership:
|
case ClassType.Leadership:
|
||||||
cost = (CONSTANTS.ClassLeadershipBaseCost * player.workCostMult) / gameCPS;
|
cost = (CONSTANTS.ClassLeadershipBaseCost * player.workCostMult) / gameCPS;
|
||||||
chaExp = ((CONSTANTS.ClassLeadershipBaseExp * player.workExpMult) / gameCPS) * hashManager.getStudyMult();
|
chaExp = ((CONSTANTS.ClassLeadershipBaseExp * player.workExpMult) / gameCPS) * hashManager.getStudyMult();
|
||||||
break;
|
break;
|
||||||
case CONSTANTS.ClassGymStrength:
|
case ClassType.GymStrength:
|
||||||
cost = (CONSTANTS.ClassGymBaseCost * player.workCostMult) / gameCPS;
|
cost = (CONSTANTS.ClassGymBaseCost * player.workCostMult) / gameCPS;
|
||||||
strExp = (player.workExpMult / gameCPS) * hashManager.getTrainingMult();
|
strExp = (player.workExpMult / gameCPS) * hashManager.getTrainingMult();
|
||||||
break;
|
break;
|
||||||
case CONSTANTS.ClassGymDefense:
|
case ClassType.GymDefense:
|
||||||
cost = (CONSTANTS.ClassGymBaseCost * player.workCostMult) / gameCPS;
|
cost = (CONSTANTS.ClassGymBaseCost * player.workCostMult) / gameCPS;
|
||||||
defExp = (player.workExpMult / gameCPS) * hashManager.getTrainingMult();
|
defExp = (player.workExpMult / gameCPS) * hashManager.getTrainingMult();
|
||||||
break;
|
break;
|
||||||
case CONSTANTS.ClassGymDexterity:
|
case ClassType.GymDexterity:
|
||||||
cost = (CONSTANTS.ClassGymBaseCost * player.workCostMult) / gameCPS;
|
cost = (CONSTANTS.ClassGymBaseCost * player.workCostMult) / gameCPS;
|
||||||
dexExp = (player.workExpMult / gameCPS) * hashManager.getTrainingMult();
|
dexExp = (player.workExpMult / gameCPS) * hashManager.getTrainingMult();
|
||||||
break;
|
break;
|
||||||
case CONSTANTS.ClassGymAgility:
|
case ClassType.GymAgility:
|
||||||
cost = (CONSTANTS.ClassGymBaseCost * player.workCostMult) / gameCPS;
|
cost = (CONSTANTS.ClassGymBaseCost * player.workCostMult) / gameCPS;
|
||||||
agiExp = (player.workExpMult / gameCPS) * hashManager.getTrainingMult();
|
agiExp = (player.workExpMult / gameCPS) * hashManager.getTrainingMult();
|
||||||
break;
|
break;
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import { FactionNames } from "./Faction/data/FactionNames";
|
import { FactionNames } from "./Faction/data/FactionNames";
|
||||||
import { CityName } from "./Locations/data/CityNames";
|
import { CityName } from "./Locations/data/CityNames";
|
||||||
import { Augmentations } from "./Augmentation/Augmentations";
|
import { StaticAugmentations } from "./Augmentation/StaticAugmentations";
|
||||||
import { augmentationExists, initAugmentations } from "./Augmentation/AugmentationHelpers";
|
import { augmentationExists, initAugmentations } from "./Augmentation/AugmentationHelpers";
|
||||||
import { AugmentationNames } from "./Augmentation/data/AugmentationNames";
|
import { AugmentationNames } from "./Augmentation/data/AugmentationNames";
|
||||||
import { initBitNodeMultipliers } from "./BitNode/BitNode";
|
import { initBitNodeMultipliers } from "./BitNode/BitNode";
|
||||||
@ -225,9 +225,9 @@ export function prestigeSourceFile(flume: boolean): void {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Delete all Augmentations
|
// Delete all Augmentations
|
||||||
for (const name of Object.keys(Augmentations)) {
|
for (const name of Object.keys(StaticAugmentations)) {
|
||||||
if (Augmentations.hasOwnProperty(name)) {
|
if (StaticAugmentations.hasOwnProperty(name)) {
|
||||||
delete Augmentations[name];
|
delete StaticAugmentations[name];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -414,6 +414,26 @@ function evaluateVersionCompatibility(ver: string | number): void {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Fix bugged NFG accumulation in owned augmentations
|
||||||
|
if (ver < 17) {
|
||||||
|
let ownedNFGs = [...Player.augmentations];
|
||||||
|
ownedNFGs = ownedNFGs.filter((aug) => aug.name === AugmentationNames.NeuroFluxGovernor);
|
||||||
|
const newNFG = new PlayerOwnedAugmentation(AugmentationNames.NeuroFluxGovernor);
|
||||||
|
newNFG.level = 0;
|
||||||
|
|
||||||
|
for (const nfg of ownedNFGs) {
|
||||||
|
newNFG.level += nfg.level;
|
||||||
|
}
|
||||||
|
|
||||||
|
Player.augmentations = [
|
||||||
|
...Player.augmentations.filter((aug) => aug.name !== AugmentationNames.NeuroFluxGovernor),
|
||||||
|
newNFG,
|
||||||
|
];
|
||||||
|
|
||||||
|
Player.reapplyAllAugmentations(true);
|
||||||
|
Player.reapplyAllSourceFiles();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
42
src/ScriptEditor/NetscriptDefinitions.d.ts
vendored
42
src/ScriptEditor/NetscriptDefinitions.d.ts
vendored
@ -1800,6 +1800,18 @@ export interface Singularity {
|
|||||||
*/
|
*/
|
||||||
workForCompany(companyName?: string, focus?: boolean): boolean;
|
workForCompany(companyName?: string, focus?: boolean): boolean;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Quit jobs by company.
|
||||||
|
* @remarks
|
||||||
|
* RAM cost: 3 GB * 16/4/1
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* This function will finish work with the company provided and quit any jobs.
|
||||||
|
*
|
||||||
|
* @param companyName - Name of the company.
|
||||||
|
*/
|
||||||
|
quitJob(companyName?: string): void;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Apply for a job at a company.
|
* Apply for a job at a company.
|
||||||
* @remarks
|
* @remarks
|
||||||
@ -2340,13 +2352,13 @@ export interface Singularity {
|
|||||||
* @example
|
* @example
|
||||||
* ```ts
|
* ```ts
|
||||||
* // NS1
|
* // NS1
|
||||||
* getDarkwebProgramsAvailable();
|
* getDarkwebPrograms();
|
||||||
* // returns ['BruteSSH.exe', 'FTPCrack.exe'...etc]
|
* // returns ['BruteSSH.exe', 'FTPCrack.exe'...etc]
|
||||||
* ```
|
* ```
|
||||||
* @example
|
* @example
|
||||||
* ```ts
|
* ```ts
|
||||||
* // NS2
|
* // NS2
|
||||||
* ns.getDarkwebProgramsAvailable();
|
* ns.getDarkwebPrograms();
|
||||||
* // returns ['BruteSSH.exe', 'FTPCrack.exe'...etc]
|
* // returns ['BruteSSH.exe', 'FTPCrack.exe'...etc]
|
||||||
* ```
|
* ```
|
||||||
* @returns - a list of programs available for purchase on the dark web, or [] if Tor has not
|
* @returns - a list of programs available for purchase on the dark web, or [] if Tor has not
|
||||||
@ -5325,9 +5337,10 @@ export interface NS {
|
|||||||
* If no host is defined, it will kill all scripts, where the script is running.
|
* If no host is defined, it will kill all scripts, where the script is running.
|
||||||
*
|
*
|
||||||
* @param host - IP or hostname of the server on which to kill all scripts.
|
* @param host - IP or hostname of the server on which to kill all scripts.
|
||||||
|
* @param safetyguard - Skips the script that calls this function
|
||||||
* @returns True if any scripts were killed, and false otherwise.
|
* @returns True if any scripts were killed, and false otherwise.
|
||||||
*/
|
*/
|
||||||
killall(host?: string): boolean;
|
killall(host?: string, safetyguard?: boolean): boolean;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Terminates the current script immediately.
|
* Terminates the current script immediately.
|
||||||
@ -6140,7 +6153,7 @@ export interface NS {
|
|||||||
* Returns 0 if the script does not exist.
|
* Returns 0 if the script does not exist.
|
||||||
*
|
*
|
||||||
* @param script - Filename of script. This is case-sensitive.
|
* @param script - Filename of script. This is case-sensitive.
|
||||||
* @param host - Host of target server the script is located on. This is optional, If it is not specified then the function will se the current server as the target server.
|
* @param host - Host of target server the script is located on. This is optional, if it is not specified then the function will use the current server as the target server.
|
||||||
* @returns Amount of RAM (in GB) required to run the specified script on the target server, and 0 if the script does not exist.
|
* @returns Amount of RAM (in GB) required to run the specified script on the target server, and 0 if the script does not exist.
|
||||||
*/
|
*/
|
||||||
getScriptRam(script: string, host?: string): number;
|
getScriptRam(script: string, host?: string): number;
|
||||||
@ -7058,22 +7071,27 @@ interface CorporationInfo {
|
|||||||
interface Employee {
|
interface Employee {
|
||||||
/** Name of the employee */
|
/** Name of the employee */
|
||||||
name: string;
|
name: string;
|
||||||
/** Morale */
|
/** Morale of the employee */
|
||||||
mor: number;
|
mor: number;
|
||||||
/** Happiness */
|
/** Happiness of the employee */
|
||||||
hap: number;
|
hap: number;
|
||||||
/** Energy */
|
/** Energy of the employee */
|
||||||
ene: number;
|
ene: number;
|
||||||
|
/** Intelligence of the employee */
|
||||||
int: number;
|
int: number;
|
||||||
|
/** Charisma of the employee */
|
||||||
cha: number;
|
cha: number;
|
||||||
|
/** Experience of the employee */
|
||||||
exp: number;
|
exp: number;
|
||||||
|
/** Creativity of the employee */
|
||||||
cre: number;
|
cre: number;
|
||||||
|
/** Efficiency of the employee */
|
||||||
eff: number;
|
eff: number;
|
||||||
/** Salary */
|
/** Salary of the employee */
|
||||||
sal: number;
|
sal: number;
|
||||||
/** City */
|
/** Current Location (city) */
|
||||||
loc: string;
|
loc: string;
|
||||||
/** Current job */
|
/** Current job position */
|
||||||
pos: string;
|
pos: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -7125,6 +7143,8 @@ interface Material {
|
|||||||
sell: number;
|
sell: number;
|
||||||
/** cost to buy material */
|
/** cost to buy material */
|
||||||
cost: number;
|
cost: number;
|
||||||
|
/** Sell cost, can be "MP+5" */
|
||||||
|
sCost: string | number;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -7216,6 +7236,8 @@ interface Division {
|
|||||||
cities: string[];
|
cities: string[];
|
||||||
/** Products developed by this division */
|
/** Products developed by this division */
|
||||||
products: string[];
|
products: string[];
|
||||||
|
/** Whether the industry this division is in is capable of making products */
|
||||||
|
makesProducts: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -544,11 +544,14 @@ export function Root(props: IProps): React.ReactElement {
|
|||||||
// this is duplicate code with saving later.
|
// this is duplicate code with saving later.
|
||||||
if (ITutorial.isRunning && ITutorial.currStep === iTutorialSteps.TerminalTypeScript) {
|
if (ITutorial.isRunning && ITutorial.currStep === iTutorialSteps.TerminalTypeScript) {
|
||||||
//Make sure filename + code properly follow tutorial
|
//Make sure filename + code properly follow tutorial
|
||||||
if (currentScript.fileName !== "n00dles.script") {
|
if (currentScript.fileName !== "n00dles.script" && currentScript.fileName !== "n00dles.js") {
|
||||||
dialogBoxCreate("Leave the script name as 'n00dles.script'!");
|
dialogBoxCreate("Don't change the script name for now.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (currentScript.code.replace(/\s/g, "").indexOf("while(true){hack('n00dles');}") == -1) {
|
const cleanCode = currentScript.code.replace(/\s/g, "");
|
||||||
|
const ns1 = "while(true){hack('n00dles');}";
|
||||||
|
const ns2 = `exportasyncfunctionmain(ns){while(true){awaitns.hack('n00dles');}}`;
|
||||||
|
if (cleanCode.indexOf(ns1) == -1 && cleanCode.indexOf(ns2) == -1) {
|
||||||
dialogBoxCreate("Please copy and paste the code from the tutorial!");
|
dialogBoxCreate("Please copy and paste the code from the tutorial!");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -692,7 +695,7 @@ export function Root(props: IProps): React.ReactElement {
|
|||||||
const serverScriptIndex = server.scripts.findIndex((script) => script.filename === closingScript.fileName);
|
const serverScriptIndex = server.scripts.findIndex((script) => script.filename === closingScript.fileName);
|
||||||
if (serverScriptIndex === -1 || savedScriptCode !== server.scripts[serverScriptIndex as number].code) {
|
if (serverScriptIndex === -1 || savedScriptCode !== server.scripts[serverScriptIndex as number].code) {
|
||||||
PromptEvent.emit({
|
PromptEvent.emit({
|
||||||
txt: "Do you want to save changes to " + closingScript.fileName + "?",
|
txt: `Do you want to save changes to ${closingScript.fileName} on ${closingScript.hostname}?`,
|
||||||
resolve: (result: boolean | string) => {
|
resolve: (result: boolean | string) => {
|
||||||
if (result) {
|
if (result) {
|
||||||
// Save changes
|
// Save changes
|
||||||
@ -855,22 +858,31 @@ export function Root(props: IProps): React.ReactElement {
|
|||||||
)}
|
)}
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
{filteredOpenScripts.map(({ fileName, hostname }, index) => {
|
{filteredOpenScripts.map(({ fileName, hostname }, index) => {
|
||||||
|
const editingCurrentScript =
|
||||||
|
currentScript?.fileName === filteredOpenScripts[index].fileName &&
|
||||||
|
currentScript?.hostname === filteredOpenScripts[index].hostname;
|
||||||
|
const externalScript = hostname !== "home";
|
||||||
|
const colorProps = editingCurrentScript
|
||||||
|
? {
|
||||||
|
background: Settings.theme.button,
|
||||||
|
borderColor: Settings.theme.button,
|
||||||
|
color: Settings.theme.primary,
|
||||||
|
}
|
||||||
|
: {
|
||||||
|
background: Settings.theme.backgroundsecondary,
|
||||||
|
borderColor: Settings.theme.backgroundsecondary,
|
||||||
|
color: Settings.theme.secondary,
|
||||||
|
};
|
||||||
|
|
||||||
|
if (externalScript) {
|
||||||
|
colorProps.color = Settings.theme.info;
|
||||||
|
}
|
||||||
const iconButtonStyle = {
|
const iconButtonStyle = {
|
||||||
maxWidth: `${tabIconWidth}px`,
|
maxWidth: `${tabIconWidth}px`,
|
||||||
minWidth: `${tabIconWidth}px`,
|
minWidth: `${tabIconWidth}px`,
|
||||||
minHeight: "38.5px",
|
minHeight: "38.5px",
|
||||||
maxHeight: "38.5px",
|
maxHeight: "38.5px",
|
||||||
...(currentScript?.fileName === filteredOpenScripts[index].fileName
|
...colorProps,
|
||||||
? {
|
|
||||||
background: Settings.theme.button,
|
|
||||||
borderColor: Settings.theme.button,
|
|
||||||
color: Settings.theme.primary,
|
|
||||||
}
|
|
||||||
: {
|
|
||||||
background: Settings.theme.backgroundsecondary,
|
|
||||||
borderColor: Settings.theme.backgroundsecondary,
|
|
||||||
color: Settings.theme.secondary,
|
|
||||||
}),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const scriptTabText = `${hostname}:~/${fileName} ${dirty(index)}`;
|
const scriptTabText = `${hostname}:~/${fileName} ${dirty(index)}`;
|
||||||
@ -905,17 +917,7 @@ export function Root(props: IProps): React.ReactElement {
|
|||||||
maxWidth: `${tabTextWidth}px`,
|
maxWidth: `${tabTextWidth}px`,
|
||||||
minHeight: "38.5px",
|
minHeight: "38.5px",
|
||||||
overflow: "hidden",
|
overflow: "hidden",
|
||||||
...(currentScript?.fileName === filteredOpenScripts[index].fileName
|
...colorProps,
|
||||||
? {
|
|
||||||
background: Settings.theme.button,
|
|
||||||
borderColor: Settings.theme.button,
|
|
||||||
color: Settings.theme.primary,
|
|
||||||
}
|
|
||||||
: {
|
|
||||||
background: Settings.theme.backgroundsecondary,
|
|
||||||
borderColor: Settings.theme.backgroundsecondary,
|
|
||||||
color: Settings.theme.secondary,
|
|
||||||
}),
|
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<span style={{ overflow: "hidden", direction: "rtl", textOverflow: "ellipsis" }}>
|
<span style={{ overflow: "hidden", direction: "rtl", textOverflow: "ellipsis" }}>
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import React, { useState, useEffect } from "react";
|
import React, { useState, useEffect } from "react";
|
||||||
import { KEY } from "../../utils/helpers/keyCodes";
|
import { KEYCODE } from "../../utils/helpers/keyCodes";
|
||||||
import clsx from "clsx";
|
import clsx from "clsx";
|
||||||
import { styled, Theme, CSSObject } from "@mui/material/styles";
|
import { styled, Theme, CSSObject } from "@mui/material/styles";
|
||||||
import createStyles from "@mui/styles/createStyles";
|
import createStyles from "@mui/styles/createStyles";
|
||||||
@ -275,57 +275,53 @@ export function SidebarRoot(props: IProps): React.ReactElement {
|
|||||||
function handleShortcuts(this: Document, event: KeyboardEvent): any {
|
function handleShortcuts(this: Document, event: KeyboardEvent): any {
|
||||||
if (Settings.DisableHotkeys) return;
|
if (Settings.DisableHotkeys) return;
|
||||||
if ((props.player.isWorking && props.player.focus) || props.router.page() === Page.BitVerse) return;
|
if ((props.player.isWorking && props.player.focus) || props.router.page() === Page.BitVerse) return;
|
||||||
if (event.key === KEY.T && event.altKey) {
|
if (event.code === KEYCODE.T && event.altKey) {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
clickTerminal();
|
clickTerminal();
|
||||||
} else if (event.key === KEY.C && event.altKey) {
|
} else if (event.code === KEYCODE.C && event.altKey) {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
clickStats();
|
clickStats();
|
||||||
} else if (event.key === KEY.E && event.altKey) {
|
} else if (event.code === KEYCODE.E && event.altKey) {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
clickScriptEditor();
|
clickScriptEditor();
|
||||||
} else if (event.key === KEY.S && event.altKey) {
|
} else if (event.code === KEYCODE.S && event.altKey) {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
clickActiveScripts();
|
clickActiveScripts();
|
||||||
} else if (event.key === KEY.H && event.altKey) {
|
} else if (event.code === KEYCODE.H && event.altKey) {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
clickHacknet();
|
clickHacknet();
|
||||||
} else if (event.key === KEY.W && event.altKey) {
|
} else if (event.code === KEYCODE.W && event.altKey) {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
clickCity();
|
clickCity();
|
||||||
} else if (event.key === KEY.J && event.altKey && !event.ctrlKey && !event.metaKey && canJob) {
|
} else if (event.code === KEYCODE.J && event.altKey && !event.ctrlKey && !event.metaKey && canJob) {
|
||||||
// ctrl/cmd + alt + j is shortcut to open Chrome dev tools
|
// ctrl/cmd + alt + j is shortcut to open Chrome dev tools
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
clickJob();
|
clickJob();
|
||||||
} else if (event.key === KEY.R && event.altKey) {
|
} else if (event.code === KEYCODE.R && event.altKey) {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
clickTravel();
|
clickTravel();
|
||||||
} else if (event.key === KEY.P && event.altKey) {
|
} else if (event.code === KEYCODE.P && event.altKey) {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
clickCreateProgram();
|
clickCreateProgram();
|
||||||
} else if (event.key === KEY.F && event.altKey) {
|
} else if (event.code === KEYCODE.F && event.altKey) {
|
||||||
if (props.page == Page.Terminal && Settings.EnableBashHotkeys) {
|
if (props.page == Page.Terminal && Settings.EnableBashHotkeys) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
clickFactions();
|
clickFactions();
|
||||||
} else if (event.key === KEY.A && event.altKey) {
|
} else if (event.code === KEYCODE.A && event.altKey) {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
clickAugmentations();
|
clickAugmentations();
|
||||||
} else if (event.key === KEY.U && event.altKey) {
|
} else if (event.code === KEYCODE.U && event.altKey) {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
clickTutorial();
|
clickTutorial();
|
||||||
} else if (event.key === KEY.B && event.altKey && props.player.bladeburner) {
|
} else if (event.code === KEYCODE.B && event.altKey && props.player.bladeburner) {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
clickBladeburner();
|
clickBladeburner();
|
||||||
} else if (event.key === KEY.G && event.altKey && props.player.gang) {
|
} else if (event.code === KEYCODE.G && event.altKey && props.player.gang) {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
clickGang();
|
clickGang();
|
||||||
}
|
}
|
||||||
// if (event.key === KEY.O && event.altKey) {
|
|
||||||
// event.preventDefault();
|
|
||||||
// gameOptionsBoxOpen();
|
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
document.addEventListener("keydown", handleShortcuts);
|
document.addEventListener("keydown", handleShortcuts);
|
||||||
|
@ -718,7 +718,11 @@ export class Terminal implements ITerminal {
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case iTutorialSteps.TerminalCreateScript:
|
case iTutorialSteps.TerminalCreateScript:
|
||||||
if (commandArray.length == 2 && commandArray[0] == "nano" && commandArray[1] == "n00dles.script") {
|
if (
|
||||||
|
commandArray.length == 2 &&
|
||||||
|
commandArray[0] == "nano" &&
|
||||||
|
(commandArray[1] == "n00dles.script" || commandArray[1] == "n00dles.js")
|
||||||
|
) {
|
||||||
iTutorialNextStep();
|
iTutorialNextStep();
|
||||||
} else {
|
} else {
|
||||||
this.error("Bad command. Please follow the tutorial");
|
this.error("Bad command. Please follow the tutorial");
|
||||||
@ -734,7 +738,11 @@ export class Terminal implements ITerminal {
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case iTutorialSteps.TerminalRunScript:
|
case iTutorialSteps.TerminalRunScript:
|
||||||
if (commandArray.length == 2 && commandArray[0] == "run" && commandArray[1] == "n00dles.script") {
|
if (
|
||||||
|
commandArray.length == 2 &&
|
||||||
|
commandArray[0] == "run" &&
|
||||||
|
(commandArray[1] == "n00dles.script" || commandArray[1] == "n00dles.js")
|
||||||
|
) {
|
||||||
iTutorialNextStep();
|
iTutorialNextStep();
|
||||||
} else {
|
} else {
|
||||||
this.error("Bad command. Please follow the tutorial");
|
this.error("Bad command. Please follow the tutorial");
|
||||||
@ -742,7 +750,11 @@ export class Terminal implements ITerminal {
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case iTutorialSteps.ActiveScriptsToTerminal:
|
case iTutorialSteps.ActiveScriptsToTerminal:
|
||||||
if (commandArray.length == 2 && commandArray[0] == "tail" && commandArray[1] == "n00dles.script") {
|
if (
|
||||||
|
commandArray.length == 2 &&
|
||||||
|
commandArray[0] == "tail" &&
|
||||||
|
(commandArray[1] == "n00dles.script" || commandArray[1] == "n00dles.js")
|
||||||
|
) {
|
||||||
iTutorialNextStep();
|
iTutorialNextStep();
|
||||||
} else {
|
} else {
|
||||||
this.error("Bad command. Please follow the tutorial");
|
this.error("Bad command. Please follow the tutorial");
|
||||||
|
@ -7,7 +7,7 @@ import Paper from "@mui/material/Paper";
|
|||||||
import Popper from "@mui/material/Popper";
|
import Popper from "@mui/material/Popper";
|
||||||
import TextField from "@mui/material/TextField";
|
import TextField from "@mui/material/TextField";
|
||||||
|
|
||||||
import { KEY } from "../../utils/helpers/keyCodes";
|
import { KEY, KEYCODE } from "../../utils/helpers/keyCodes";
|
||||||
import { ITerminal } from "../ITerminal";
|
import { ITerminal } from "../ITerminal";
|
||||||
import { IRouter } from "../../ui/Router";
|
import { IRouter } from "../../ui/Router";
|
||||||
import { IPlayer } from "../../PersonObjects/IPlayer";
|
import { IPlayer } from "../../PersonObjects/IPlayer";
|
||||||
@ -318,57 +318,57 @@ export function TerminalInput({ terminal, router, player }: IProps): React.React
|
|||||||
|
|
||||||
// Extra Bash Emulation Hotkeys, must be enabled through options
|
// Extra Bash Emulation Hotkeys, must be enabled through options
|
||||||
if (Settings.EnableBashHotkeys) {
|
if (Settings.EnableBashHotkeys) {
|
||||||
if (event.key === KEY.A && event.ctrlKey) {
|
if (event.code === KEYCODE.A && event.ctrlKey) {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
moveTextCursor("home");
|
moveTextCursor("home");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (event.key === KEY.E && event.ctrlKey) {
|
if (event.code === KEYCODE.E && event.ctrlKey) {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
moveTextCursor("end");
|
moveTextCursor("end");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (event.key === KEY.B && event.ctrlKey) {
|
if (event.code === KEYCODE.B && event.ctrlKey) {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
moveTextCursor("prevchar");
|
moveTextCursor("prevchar");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (event.key === KEY.B && event.altKey) {
|
if (event.code === KEYCODE.B && event.altKey) {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
moveTextCursor("prevword");
|
moveTextCursor("prevword");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (event.key === KEY.F && event.ctrlKey) {
|
if (event.code === KEYCODE.F && event.ctrlKey) {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
moveTextCursor("nextchar");
|
moveTextCursor("nextchar");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (event.key === KEY.F && event.altKey) {
|
if (event.code === KEYCODE.F && event.altKey) {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
moveTextCursor("nextword");
|
moveTextCursor("nextword");
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((event.key === KEY.H || event.key === KEY.D) && event.ctrlKey) {
|
if ((event.code === KEYCODE.H || event.code === KEYCODE.D) && event.ctrlKey) {
|
||||||
modifyInput("backspace");
|
modifyInput("backspace");
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (event.key === KEY.W && event.ctrlKey) {
|
if (event.code === KEYCODE.W && event.ctrlKey) {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
modifyInput("deletewordbefore");
|
modifyInput("deletewordbefore");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (event.key === KEY.D && event.altKey) {
|
if (event.code === KEYCODE.D && event.altKey) {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
modifyInput("deletewordafter");
|
modifyInput("deletewordafter");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (event.key === KEY.U && event.ctrlKey) {
|
if (event.code === KEYCODE.U && event.ctrlKey) {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
modifyInput("clearbefore");
|
modifyInput("clearbefore");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (event.key === KEY.K && event.ctrlKey) {
|
if (event.code === KEYCODE.K && event.ctrlKey) {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
modifyInput("clearafter");
|
modifyInput("clearafter");
|
||||||
}
|
}
|
||||||
|
@ -134,20 +134,191 @@ export function TerminalRoot({ terminal, router, player }: IProps): React.ReactE
|
|||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
function lineClass(s: string): string {
|
function lineClass(s: string): string {
|
||||||
if (s === "error") {
|
const lineClassMap: Record<string, string> = {
|
||||||
return classes.error;
|
error: classes.error,
|
||||||
}
|
success: classes.success,
|
||||||
if (s === "success") {
|
info: classes.info,
|
||||||
return classes.success;
|
warn: classes.warning,
|
||||||
}
|
};
|
||||||
if (s === "info") {
|
return lineClassMap[s] || classes.primary;
|
||||||
return classes.info;
|
}
|
||||||
}
|
|
||||||
if (s === "warn") {
|
function ansiCodeStyle(code: string | null): Record<string, any> {
|
||||||
return classes.warning;
|
// The ANSI colors actually have the dark color set as default and require extra work to get
|
||||||
|
// bright colors. But these are rarely used or, if they are, are often re-mapped by the
|
||||||
|
// terminal emulator to brighter colors. So for foreground colors we use the bright color set
|
||||||
|
// and for background colors we use the dark color set. Of course, all colors are available
|
||||||
|
// via the longer ESC[n8;5;c] sequence (n={3,4}, c=color). Ideally, these 8-bit maps could
|
||||||
|
// be managed in the user preferences/theme.
|
||||||
|
const COLOR_MAP_BRIGHT: Record<string | number, string> = {
|
||||||
|
0: "#404040",
|
||||||
|
1: "#ff0000",
|
||||||
|
2: "#00ff00",
|
||||||
|
3: "#ffff00",
|
||||||
|
4: "#0000ff",
|
||||||
|
5: "#ff00ff",
|
||||||
|
6: "#00ffff",
|
||||||
|
7: "#ffffff",
|
||||||
|
};
|
||||||
|
const COLOR_MAP_DARK: Record<string | number, string> = {
|
||||||
|
0: "#000000",
|
||||||
|
1: "#800000",
|
||||||
|
2: "#008000",
|
||||||
|
3: "#808000",
|
||||||
|
4: "#000080",
|
||||||
|
5: "#800080",
|
||||||
|
6: "#008080",
|
||||||
|
7: "#c0c0c0",
|
||||||
|
};
|
||||||
|
|
||||||
|
const ansi2rgb = (code: number): string => {
|
||||||
|
/* eslint-disable yoda */
|
||||||
|
if (0 <= code && code < 8) {
|
||||||
|
// x8 RGB
|
||||||
|
return COLOR_MAP_BRIGHT[code];
|
||||||
|
}
|
||||||
|
if (8 <= code && code < 16) {
|
||||||
|
// x8 RGB - "High Intensity" (but here, actually the dark set)
|
||||||
|
return COLOR_MAP_DARK[code];
|
||||||
|
}
|
||||||
|
if (16 <= code && code < 232) {
|
||||||
|
// x216 RGB
|
||||||
|
const base = code - 16;
|
||||||
|
const ir = Math.floor(base / 36);
|
||||||
|
const ig = Math.floor((base % 36) / 6);
|
||||||
|
const ib = Math.floor((base % 6) / 1);
|
||||||
|
const r = ir <= 0 ? 0 : 55 + ir * 40;
|
||||||
|
const g = ig <= 0 ? 0 : 55 + ig * 40;
|
||||||
|
const b = ib <= 0 ? 0 : 55 + ib * 40;
|
||||||
|
return `rgb(${r}, ${g}, ${b})`;
|
||||||
|
}
|
||||||
|
if (232 <= code && code < 256) {
|
||||||
|
// x32 greyscale
|
||||||
|
const base = code - 232;
|
||||||
|
const grey = base * 10 + 8;
|
||||||
|
return `rgb(${grey}, ${grey}, ${grey})`;
|
||||||
|
}
|
||||||
|
// shouldn't get here (under normal circumstances), but just in case
|
||||||
|
return "initial";
|
||||||
|
};
|
||||||
|
|
||||||
|
type styleKey = "fontWeight" | "textDecoration" | "color" | "backgroundColor" | "display";
|
||||||
|
const style: {
|
||||||
|
fontWeight?: string;
|
||||||
|
textDecoration?: string;
|
||||||
|
color?: string;
|
||||||
|
backgroundColor?: string;
|
||||||
|
display?: string;
|
||||||
|
} = {};
|
||||||
|
|
||||||
|
if (code === null || code === "0") {
|
||||||
|
return style;
|
||||||
}
|
}
|
||||||
|
|
||||||
return classes.primary;
|
const codeParts = code
|
||||||
|
.split(";")
|
||||||
|
.map((p) => parseInt(p))
|
||||||
|
.filter(
|
||||||
|
(p, i, arr) =>
|
||||||
|
// If the sequence is 38;5 (x256 foreground color) or 48;5 (x256 background color),
|
||||||
|
// filter out the 5 so the next codePart after {38,48} is the color code.
|
||||||
|
p != 5 || i == 0 || (arr[i - 1] != 38 && arr[i - 1] != 48),
|
||||||
|
);
|
||||||
|
|
||||||
|
let nextStyleKey: styleKey | null = null;
|
||||||
|
codeParts.forEach((codePart) => {
|
||||||
|
/* eslint-disable yoda */
|
||||||
|
if (nextStyleKey !== null) {
|
||||||
|
style[nextStyleKey] = ansi2rgb(codePart);
|
||||||
|
nextStyleKey = null;
|
||||||
|
}
|
||||||
|
// Decorations
|
||||||
|
else if (codePart == 1) {
|
||||||
|
style.fontWeight = "bold";
|
||||||
|
} else if (codePart == 4) {
|
||||||
|
style.textDecoration = "underline";
|
||||||
|
}
|
||||||
|
// Forground Color (x8)
|
||||||
|
else if (30 <= codePart && codePart < 38) {
|
||||||
|
if (COLOR_MAP_BRIGHT[codePart % 10]) {
|
||||||
|
style.color = COLOR_MAP_BRIGHT[codePart % 10];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Background Color (x8)
|
||||||
|
else if (40 <= codePart && codePart < 48) {
|
||||||
|
if (COLOR_MAP_DARK[codePart % 10]) {
|
||||||
|
style.backgroundColor = COLOR_MAP_DARK[codePart % 10];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Forground Color (x256)
|
||||||
|
else if (codePart == 38) {
|
||||||
|
nextStyleKey = "color";
|
||||||
|
}
|
||||||
|
// Background Color (x256)
|
||||||
|
else if (codePart == 48) {
|
||||||
|
nextStyleKey = "backgroundColor";
|
||||||
|
}
|
||||||
|
});
|
||||||
|
// If a background color is set, render this as an inline block element (instead of inline)
|
||||||
|
// so that the background between lines (at least those that don't wrap) is uninterrupted.
|
||||||
|
if (style.backgroundColor !== undefined) {
|
||||||
|
style.display = "inline-block";
|
||||||
|
}
|
||||||
|
return style;
|
||||||
|
}
|
||||||
|
|
||||||
|
function parseOutputText(item: Output): React.ReactElement {
|
||||||
|
const parts = [];
|
||||||
|
// Some things, oddly, can cause item.text to not be a string (e.g. expr from the CLI), which
|
||||||
|
// causes .matchAll to throw. Ensure it's a string immediately
|
||||||
|
if (typeof item.text === "string") {
|
||||||
|
// eslint-disable-next-line no-control-regex
|
||||||
|
const ANSI_ESCAPE = new RegExp("\u{001b}\\[(?<code>.*?)m", "ug");
|
||||||
|
// Build a look-alike regex match to place at the front of the matches list
|
||||||
|
const INITIAL = {
|
||||||
|
0: "",
|
||||||
|
index: 0,
|
||||||
|
groups: { code: null },
|
||||||
|
};
|
||||||
|
const matches = [INITIAL, ...item.text.matchAll(ANSI_ESCAPE), null];
|
||||||
|
if (matches.length > 2) {
|
||||||
|
matches.slice(0, -1).forEach((m, i) => {
|
||||||
|
const n = matches[i + 1];
|
||||||
|
if (!m || m.index === undefined || m.groups === undefined) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const startIndex = m.index + m[0].length;
|
||||||
|
const stopIndex = n ? n.index : item.text.length;
|
||||||
|
const partText = item.text.slice(startIndex, stopIndex);
|
||||||
|
if (startIndex !== stopIndex) {
|
||||||
|
// Don't generate "empty" spans
|
||||||
|
parts.push({ code: m.groups.code, text: partText });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (parts.length === 0) {
|
||||||
|
// For example, if the string was empty or there were no escape sequence matches
|
||||||
|
parts.push({ code: null, text: item.text });
|
||||||
|
}
|
||||||
|
return (
|
||||||
|
<Typography classes={{ root: lineClass(item.color) }} paragraph={false}>
|
||||||
|
{parts.map((part, index) => {
|
||||||
|
const spanStyle = ansiCodeStyle(part.code);
|
||||||
|
if (!_.isEmpty(spanStyle)) {
|
||||||
|
// Only wrap parts with spans if the calculated spanStyle is non-empty...
|
||||||
|
return (
|
||||||
|
<Typography key={index} paragraph={false} component="span" sx={spanStyle}>
|
||||||
|
{part.text}
|
||||||
|
</Typography>
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
// ... otherwise yield the unmodified, unwrapped part.
|
||||||
|
return part.text;
|
||||||
|
}
|
||||||
|
})}
|
||||||
|
</Typography>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const classes = useStyles();
|
const classes = useStyles();
|
||||||
@ -160,7 +331,7 @@ export function TerminalRoot({ terminal, router, player }: IProps): React.ReactE
|
|||||||
return (
|
return (
|
||||||
<ListItem key={i} classes={{ root: classes.nopadding }}>
|
<ListItem key={i} classes={{ root: classes.nopadding }}>
|
||||||
<Typography classes={{ root: lineClass(item.color) }} paragraph={false}>
|
<Typography classes={{ root: lineClass(item.color) }} paragraph={false}>
|
||||||
{item.text}
|
{parseOutputText(item)}
|
||||||
</Typography>
|
</Typography>
|
||||||
</ListItem>
|
</ListItem>
|
||||||
);
|
);
|
||||||
|
@ -1532,7 +1532,8 @@ export const codingContractTypesMetadata: ICodingContractTypeMetadata[] = [
|
|||||||
length += 2;
|
length += 2;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return ans.length === length;
|
|
||||||
|
return ans.length <= length;
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -1555,12 +1556,12 @@ export const codingContractTypesMetadata: ICodingContractTypeMetadata[] = [
|
|||||||
"You are given the following LZ-encoded string:\n",
|
"You are given the following LZ-encoded string:\n",
|
||||||
` ${compressed}\n`,
|
` ${compressed}\n`,
|
||||||
"Decode it and output the original string.\n\n",
|
"Decode it and output the original string.\n\n",
|
||||||
"Example: decoding '5aaabc340533bca' chunk-by-chunk\n",
|
"Example: decoding '5aaabb450723abb' chunk-by-chunk\n",
|
||||||
" 5aaabc -> aaabc\n",
|
" 5aaabb -> aaabb\n",
|
||||||
" 5aaabc34 -> aaabcaab\n",
|
" 5aaabb45 -> aaabbaaab\n",
|
||||||
" 5aaabc340 -> aaabcaab\n",
|
" 5aaabb450 -> aaabbaaab\n",
|
||||||
" 5aaabc34053 -> aaabcaabaabaa\n",
|
" 5aaabb45072 -> aaabbaaababababa\n",
|
||||||
" 5aaabc340533bca -> aaabcaabaabaabca",
|
" 5aaabb450723abb -> aaabbaaababababaabb",
|
||||||
].join(" ");
|
].join(" ");
|
||||||
},
|
},
|
||||||
gen: (): string => {
|
gen: (): string => {
|
||||||
@ -1591,21 +1592,21 @@ export const codingContractTypesMetadata: ICodingContractTypeMetadata[] = [
|
|||||||
` ${plaintext}\n`,
|
` ${plaintext}\n`,
|
||||||
"Encode it using Lempel-Ziv encoding with the minimum possible output length.\n\n",
|
"Encode it using Lempel-Ziv encoding with the minimum possible output length.\n\n",
|
||||||
"Examples (some have other possible encodings of minimal length):\n",
|
"Examples (some have other possible encodings of minimal length):\n",
|
||||||
" abracadabra -> 7abracad47\n",
|
" abracadabra -> 7abracad47\n",
|
||||||
" mississippi -> 4miss433ppi\n",
|
" mississippi -> 4miss433ppi\n",
|
||||||
" aAAaAAaAaAA -> 3aAA53035\n",
|
" aAAaAAaAaAA -> 3aAA53035\n",
|
||||||
" 2718281828 -> 627182844\n",
|
" 2718281828 -> 627182844\n",
|
||||||
" abcdefghijk -> 9abcdefghi02jk\n",
|
" abcdefghijk -> 9abcdefghi02jk\n",
|
||||||
" aaaaaaaaaaa -> 1a911a\n",
|
" aaaaaaaaaaaa -> 3aaa91\n",
|
||||||
" aaaaaaaaaaaa -> 1a912aa\n",
|
" aaaaaaaaaaaaa -> 1a91031\n",
|
||||||
" aaaaaaaaaaaaa -> 1a91031",
|
" aaaaaaaaaaaaaa -> 1a91041",
|
||||||
].join(" ");
|
].join(" ");
|
||||||
},
|
},
|
||||||
gen: (): string => {
|
gen: (): string => {
|
||||||
return comprLZGenerate();
|
return comprLZGenerate();
|
||||||
},
|
},
|
||||||
solver: (plain: string, ans: string): boolean => {
|
solver: (plain: string, ans: string): boolean => {
|
||||||
return comprLZDecode(ans) === plain && ans.length === comprLZEncode(plain).length;
|
return comprLZDecode(ans) === plain && ans.length <= comprLZEncode(plain).length;
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
@ -50,6 +50,8 @@ import { setupUncaughtPromiseHandler } from "./UncaughtPromiseHandler";
|
|||||||
import { Button, Typography } from "@mui/material";
|
import { Button, Typography } from "@mui/material";
|
||||||
import { SnackbarEvents, ToastVariant } from "./ui/React/Snackbar";
|
import { SnackbarEvents, ToastVariant } from "./ui/React/Snackbar";
|
||||||
|
|
||||||
|
import { WorkType } from "./utils/WorkType";
|
||||||
|
|
||||||
const Engine: {
|
const Engine: {
|
||||||
_lastUpdate: number;
|
_lastUpdate: number;
|
||||||
updateGame: (numCycles?: number) => void;
|
updateGame: (numCycles?: number) => void;
|
||||||
@ -292,20 +294,27 @@ const Engine: {
|
|||||||
loadAllRunningScripts(Player); // This also takes care of offline production for those scripts
|
loadAllRunningScripts(Player); // This also takes care of offline production for those scripts
|
||||||
if (Player.isWorking) {
|
if (Player.isWorking) {
|
||||||
Player.focus = true;
|
Player.focus = true;
|
||||||
if (Player.workType == CONSTANTS.WorkTypeFaction) {
|
switch (Player.workType) {
|
||||||
Player.workForFaction(numCyclesOffline);
|
case WorkType.Faction:
|
||||||
} else if (Player.workType == CONSTANTS.WorkTypeCreateProgram) {
|
Player.workForFaction(numCyclesOffline);
|
||||||
Player.createProgramWork(numCyclesOffline);
|
break;
|
||||||
} else if (Player.workType == CONSTANTS.WorkTypeStudyClass) {
|
case WorkType.CreateProgram:
|
||||||
Player.takeClass(numCyclesOffline);
|
Player.createProgramWork(numCyclesOffline);
|
||||||
} else if (Player.workType == CONSTANTS.WorkTypeCrime) {
|
break;
|
||||||
Player.commitCrime(numCyclesOffline);
|
case WorkType.StudyClass:
|
||||||
} else if (Player.workType == CONSTANTS.WorkTypeCompanyPartTime) {
|
Player.takeClass(numCyclesOffline);
|
||||||
Player.workPartTime(numCyclesOffline);
|
break;
|
||||||
} else if (Player.workType === CONSTANTS.WorkTypeGraftAugmentation) {
|
case WorkType.Crime:
|
||||||
Player.graftAugmentationWork(numCyclesOffline);
|
Player.commitCrime(numCyclesOffline);
|
||||||
} else {
|
break;
|
||||||
Player.work(numCyclesOffline);
|
case WorkType.CompanyPartTime:
|
||||||
|
Player.workPartTime(numCyclesOffline);
|
||||||
|
break;
|
||||||
|
case WorkType.GraftAugmentation:
|
||||||
|
Player.graftAugmentationWork(numCyclesOffline);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
Player.work(numCyclesOffline);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
for (let i = 0; i < Player.factions.length; i++) {
|
for (let i = 0; i < Player.factions.length; i++) {
|
||||||
|
@ -9,6 +9,7 @@ import ArrowBackIos from "@mui/icons-material/ArrowBackIos";
|
|||||||
import { ITutorialEvents } from "./ITutorialEvents";
|
import { ITutorialEvents } from "./ITutorialEvents";
|
||||||
import { CopyableText } from "../React/CopyableText";
|
import { CopyableText } from "../React/CopyableText";
|
||||||
|
|
||||||
|
import List from "@mui/material/List";
|
||||||
import ListItem from "@mui/material/ListItem";
|
import ListItem from "@mui/material/ListItem";
|
||||||
import EqualizerIcon from "@mui/icons-material/Equalizer";
|
import EqualizerIcon from "@mui/icons-material/Equalizer";
|
||||||
import LastPageIcon from "@mui/icons-material/LastPage";
|
import LastPageIcon from "@mui/icons-material/LastPage";
|
||||||
@ -27,6 +28,7 @@ import {
|
|||||||
iTutorialSteps,
|
iTutorialSteps,
|
||||||
iTutorialEnd,
|
iTutorialEnd,
|
||||||
} from "../../InteractiveTutorial";
|
} from "../../InteractiveTutorial";
|
||||||
|
import { NSSelection } from "./NSSelection";
|
||||||
|
|
||||||
interface IContent {
|
interface IContent {
|
||||||
content: React.ReactElement;
|
content: React.ReactElement;
|
||||||
@ -45,9 +47,23 @@ const useStyles = makeStyles((theme: Theme) =>
|
|||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
enum Language {
|
||||||
|
None,
|
||||||
|
NS1,
|
||||||
|
NS2,
|
||||||
|
}
|
||||||
|
|
||||||
export function InteractiveTutorialRoot(): React.ReactElement {
|
export function InteractiveTutorialRoot(): React.ReactElement {
|
||||||
|
const [nsSelectionOpen, setNSSelectionOpen] = useState(false);
|
||||||
|
const [language, setLanguage] = useState(Language.None);
|
||||||
const classes = useStyles();
|
const classes = useStyles();
|
||||||
|
|
||||||
|
const tutorialScriptName = {
|
||||||
|
[Language.None]: "n00dles.script",
|
||||||
|
[Language.NS1]: "n00dles.script",
|
||||||
|
[Language.NS2]: "n00dles.js",
|
||||||
|
}[language];
|
||||||
|
|
||||||
const contents: { [number: string]: IContent | undefined } = {
|
const contents: { [number: string]: IContent | undefined } = {
|
||||||
[iTutorialSteps.Start as number]: {
|
[iTutorialSteps.Start as number]: {
|
||||||
content: (
|
content: (
|
||||||
@ -66,6 +82,47 @@ export function InteractiveTutorialRoot(): React.ReactElement {
|
|||||||
),
|
),
|
||||||
canNext: true,
|
canNext: true,
|
||||||
},
|
},
|
||||||
|
[iTutorialSteps.NSSelection as number]: {
|
||||||
|
content: (
|
||||||
|
<>
|
||||||
|
<Typography>The tutorial will adjust to your programming ability.</Typography>
|
||||||
|
<Typography>Bitburner has 2 types of scripts:</Typography>
|
||||||
|
<List>
|
||||||
|
<ListItem>
|
||||||
|
<Typography>NS1: Javascript from 2009, very simple. Recommended for beginners to programming.</Typography>
|
||||||
|
</ListItem>
|
||||||
|
<ListItem>
|
||||||
|
<Typography>
|
||||||
|
NS2: Native, modern Javascript. Recommended if you know any programming language or are serious about
|
||||||
|
learning programming.
|
||||||
|
</Typography>
|
||||||
|
</ListItem>
|
||||||
|
</List>
|
||||||
|
<Typography>
|
||||||
|
Both are available at all time and interchangeably. This choice is only for the tutorial.
|
||||||
|
</Typography>
|
||||||
|
<Button
|
||||||
|
onClick={() => {
|
||||||
|
setLanguage(Language.NS1);
|
||||||
|
iTutorialNextStep();
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Use NS1
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
onClick={() => {
|
||||||
|
setLanguage(Language.NS2);
|
||||||
|
iTutorialNextStep();
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Use NS2
|
||||||
|
</Button>
|
||||||
|
<Button onClick={() => setNSSelectionOpen(true)}>More info</Button>
|
||||||
|
<br />
|
||||||
|
</>
|
||||||
|
),
|
||||||
|
canNext: false,
|
||||||
|
},
|
||||||
[iTutorialSteps.GoToCharacterPage as number]: {
|
[iTutorialSteps.GoToCharacterPage as number]: {
|
||||||
content: (
|
content: (
|
||||||
<>
|
<>
|
||||||
@ -321,7 +378,7 @@ export function InteractiveTutorialRoot(): React.ReactElement {
|
|||||||
<Typography classes={{ root: classes.textfield }}>{"[home ~/]> nano"}</Typography>
|
<Typography classes={{ root: classes.textfield }}>{"[home ~/]> nano"}</Typography>
|
||||||
|
|
||||||
<Typography>Scripts must end with the .script extension. Let's make a script now by entering </Typography>
|
<Typography>Scripts must end with the .script extension. Let's make a script now by entering </Typography>
|
||||||
<Typography classes={{ root: classes.textfield }}>{"[home ~/]> nano n00dles.script"}</Typography>
|
<Typography classes={{ root: classes.textfield }}>{`[home ~/]> nano ${tutorialScriptName}`}</Typography>
|
||||||
|
|
||||||
<Typography>
|
<Typography>
|
||||||
after the hack command finishes running (Sidenote: Pressing ctrl + c will end a command like hack early)
|
after the hack command finishes running (Sidenote: Pressing ctrl + c will end a command like hack early)
|
||||||
@ -334,16 +391,28 @@ export function InteractiveTutorialRoot(): React.ReactElement {
|
|||||||
content: (
|
content: (
|
||||||
<>
|
<>
|
||||||
<Typography>
|
<Typography>
|
||||||
This is the script editor. You can use it to program your scripts. Scripts are written in a simplified
|
This is the script editor. You can use it to program your scripts.{" "}
|
||||||
version of javascript. Copy and paste the following code into the script editor: <br />
|
{language !== Language.NS2 && <>Scripts are written in a simplified version of javascript.</>} Copy and
|
||||||
|
paste the following code into the script editor: <br />
|
||||||
</Typography>
|
</Typography>
|
||||||
|
|
||||||
<Typography classes={{ root: classes.code }}>
|
<Typography classes={{ root: classes.code }}>
|
||||||
<CopyableText
|
{language !== Language.NS2 && (
|
||||||
value={`while(true) {
|
<CopyableText
|
||||||
|
value={`while(true) {
|
||||||
hack('n00dles');
|
hack('n00dles');
|
||||||
}`}
|
}`}
|
||||||
/>
|
/>
|
||||||
|
)}
|
||||||
|
{language === Language.NS2 && (
|
||||||
|
<CopyableText
|
||||||
|
value={`export async function main(ns) {
|
||||||
|
while(true) {
|
||||||
|
await ns.hack('n00dles');
|
||||||
|
}
|
||||||
|
}`}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
</Typography>
|
</Typography>
|
||||||
<Typography>
|
<Typography>
|
||||||
For anyone with basic programming experience, this code should be straightforward. This script will
|
For anyone with basic programming experience, this code should be straightforward. This script will
|
||||||
@ -378,7 +447,7 @@ export function InteractiveTutorialRoot(): React.ReactElement {
|
|||||||
<Typography>
|
<Typography>
|
||||||
We have 8GB of free RAM on this machine, which is enough to run our script. Let's run our script using
|
We have 8GB of free RAM on this machine, which is enough to run our script. Let's run our script using
|
||||||
</Typography>
|
</Typography>
|
||||||
<Typography classes={{ root: classes.textfield }}>{"[home ~/]> run n00dles.script"}</Typography>
|
<Typography classes={{ root: classes.textfield }}>{`[home ~/]> run ${tutorialScriptName}`}</Typography>
|
||||||
</>
|
</>
|
||||||
),
|
),
|
||||||
canNext: false,
|
canNext: false,
|
||||||
@ -425,7 +494,7 @@ export function InteractiveTutorialRoot(): React.ReactElement {
|
|||||||
One last thing about scripts, each active script contains logs that detail what it's doing. We can check
|
One last thing about scripts, each active script contains logs that detail what it's doing. We can check
|
||||||
these logs using the tail command. Do that now for the script we just ran by typing{" "}
|
these logs using the tail command. Do that now for the script we just ran by typing{" "}
|
||||||
</Typography>
|
</Typography>
|
||||||
<Typography classes={{ root: classes.textfield }}>{"[home ~/]> tail n00dles.script"}</Typography>
|
<Typography classes={{ root: classes.textfield }}>{`[home ~/]> tail ${tutorialScriptName}`}</Typography>
|
||||||
</>
|
</>
|
||||||
),
|
),
|
||||||
canNext: false,
|
canNext: false,
|
||||||
@ -447,14 +516,6 @@ export function InteractiveTutorialRoot(): React.ReactElement {
|
|||||||
in the main navigation menu to look at the documentation.
|
in the main navigation menu to look at the documentation.
|
||||||
<br />
|
<br />
|
||||||
<br />
|
<br />
|
||||||
If you know even a little bit of programming it is highly recommended you use NS2 instead. You will enjoy
|
|
||||||
the game much more. NS1 files end with .script and are a subset of javascript. NS2 files end with .js and
|
|
||||||
are full speed native javascript.
|
|
||||||
<br />
|
|
||||||
<br />
|
|
||||||
You can learn more about the difference between them later in the documentation.
|
|
||||||
<br />
|
|
||||||
<br />
|
|
||||||
For now, let's move on to something else!
|
For now, let's move on to something else!
|
||||||
</Typography>
|
</Typography>
|
||||||
</>
|
</>
|
||||||
@ -549,25 +610,30 @@ export function InteractiveTutorialRoot(): React.ReactElement {
|
|||||||
const content = contents[step];
|
const content = contents[step];
|
||||||
if (content === undefined) throw new Error("error in the tutorial");
|
if (content === undefined) throw new Error("error in the tutorial");
|
||||||
return (
|
return (
|
||||||
<Paper square sx={{ maxWidth: "70vw", p: 2 }}>
|
<>
|
||||||
{content.content}
|
<NSSelection open={nsSelectionOpen} onClose={() => setNSSelectionOpen(false)} />
|
||||||
{step !== iTutorialSteps.TutorialPageInfo && (
|
<Paper square sx={{ maxWidth: "70vw", p: 2 }}>
|
||||||
<>
|
{content.content}
|
||||||
<IconButton onClick={iTutorialPrevStep} aria-label="previous">
|
{step !== iTutorialSteps.TutorialPageInfo && (
|
||||||
<ArrowBackIos />
|
<>
|
||||||
</IconButton>
|
{step !== iTutorialSteps.Start && (
|
||||||
{content.canNext && (
|
<IconButton onClick={iTutorialPrevStep} aria-label="previous">
|
||||||
<IconButton onClick={iTutorialNextStep} aria-label="next">
|
<ArrowBackIos />
|
||||||
<ArrowForwardIos />
|
</IconButton>
|
||||||
</IconButton>
|
)}
|
||||||
)}
|
{content.canNext && (
|
||||||
</>
|
<IconButton onClick={iTutorialNextStep} aria-label="next">
|
||||||
)}
|
<ArrowForwardIos />
|
||||||
<br />
|
</IconButton>
|
||||||
<br />
|
)}
|
||||||
<Button onClick={iTutorialEnd}>
|
</>
|
||||||
{step !== iTutorialSteps.TutorialPageInfo ? "SKIP TUTORIAL" : "FINISH TUTORIAL"}
|
)}
|
||||||
</Button>
|
<br />
|
||||||
</Paper>
|
<br />
|
||||||
|
<Button onClick={iTutorialEnd}>
|
||||||
|
{step !== iTutorialSteps.TutorialPageInfo ? "SKIP TUTORIAL" : "FINISH TUTORIAL"}
|
||||||
|
</Button>
|
||||||
|
</Paper>
|
||||||
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
82
src/ui/InteractiveTutorial/NSSelection.tsx
Normal file
82
src/ui/InteractiveTutorial/NSSelection.tsx
Normal file
@ -0,0 +1,82 @@
|
|||||||
|
import Editor from "@monaco-editor/react";
|
||||||
|
import { Tab, Tabs, Typography } from "@mui/material";
|
||||||
|
import React from "react";
|
||||||
|
|
||||||
|
import { Modal } from "../React/Modal";
|
||||||
|
|
||||||
|
import * as monaco from "monaco-editor";
|
||||||
|
|
||||||
|
type IStandaloneCodeEditor = monaco.editor.IStandaloneCodeEditor;
|
||||||
|
|
||||||
|
interface IProps {
|
||||||
|
open: boolean;
|
||||||
|
onClose: () => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
const ns1Example = `while(true) {
|
||||||
|
hack('n00dles');
|
||||||
|
}`;
|
||||||
|
const ns2Example = `/** @param {NS} ns */
|
||||||
|
export async function main(ns) {
|
||||||
|
while(true) {
|
||||||
|
await ns.hack('n00dles');
|
||||||
|
}
|
||||||
|
}`;
|
||||||
|
|
||||||
|
export function NSSelection(props: IProps): React.ReactElement {
|
||||||
|
const [value, setValue] = React.useState(0);
|
||||||
|
|
||||||
|
function handleChange(event: React.SyntheticEvent, tab: number): void {
|
||||||
|
setValue(tab);
|
||||||
|
}
|
||||||
|
|
||||||
|
function onMount(editor: IStandaloneCodeEditor): void {
|
||||||
|
editor.updateOptions({ readOnly: true });
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Modal open={props.open} onClose={props.onClose}>
|
||||||
|
<Tabs variant="fullWidth" value={value} onChange={handleChange}>
|
||||||
|
<Tab label="NS1" />
|
||||||
|
<Tab label="NS2" />
|
||||||
|
</Tabs>
|
||||||
|
|
||||||
|
{value === 0 && (
|
||||||
|
<>
|
||||||
|
<Typography>
|
||||||
|
These scripts end with '.script'. Using a very old interpreted version of javascript. It is perfect for
|
||||||
|
beginner to programming.
|
||||||
|
</Typography>
|
||||||
|
<Typography>Example script using NS1:</Typography>
|
||||||
|
<Editor
|
||||||
|
loading={<></>}
|
||||||
|
defaultLanguage="javascript"
|
||||||
|
defaultValue={ns1Example}
|
||||||
|
height={`${300}px`}
|
||||||
|
theme={"vs-dark"}
|
||||||
|
onMount={onMount}
|
||||||
|
options={{ fontSize: 30 }}
|
||||||
|
/>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
{value === 1 && (
|
||||||
|
<>
|
||||||
|
<Typography>
|
||||||
|
These scripts end with '.js'. Scripts using ns2 are running natively along the game. If you know any
|
||||||
|
programming language you should be using this. However if you're unfamiliar with javascript Promises you
|
||||||
|
might want to read up on them a little bit before diving in.
|
||||||
|
</Typography>
|
||||||
|
<Typography>Example script using NS2:</Typography>
|
||||||
|
<Editor
|
||||||
|
loading={<></>}
|
||||||
|
defaultLanguage="javascript"
|
||||||
|
defaultValue={ns2Example}
|
||||||
|
height={`${300}px`}
|
||||||
|
theme={"vs-dark"}
|
||||||
|
options={{ fontSize: 30 }}
|
||||||
|
/>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</Modal>
|
||||||
|
);
|
||||||
|
}
|
@ -25,7 +25,8 @@ import { StatsProgressOverviewCell } from "./StatsProgressBar";
|
|||||||
import { BitNodeMultipliers } from "../../BitNode/BitNodeMultipliers";
|
import { BitNodeMultipliers } from "../../BitNode/BitNodeMultipliers";
|
||||||
|
|
||||||
import { Box, Tooltip } from "@mui/material";
|
import { Box, Tooltip } from "@mui/material";
|
||||||
import { CONSTANTS } from "../../Constants";
|
|
||||||
|
import { WorkType } from "../../utils/WorkType";
|
||||||
|
|
||||||
interface IProps {
|
interface IProps {
|
||||||
save: () => void;
|
save: () => void;
|
||||||
@ -144,8 +145,8 @@ function Work(): React.ReactElement {
|
|||||||
let header = <></>;
|
let header = <></>;
|
||||||
let innerText = <></>;
|
let innerText = <></>;
|
||||||
switch (player.workType) {
|
switch (player.workType) {
|
||||||
case CONSTANTS.WorkTypeCompanyPartTime:
|
case WorkType.CompanyPartTime:
|
||||||
case CONSTANTS.WorkTypeCompany:
|
case WorkType.Company:
|
||||||
details = (
|
details = (
|
||||||
<>
|
<>
|
||||||
{player.jobs[player.companyName]} at <strong>{player.companyName}</strong>
|
{player.jobs[player.companyName]} at <strong>{player.companyName}</strong>
|
||||||
@ -162,7 +163,7 @@ function Work(): React.ReactElement {
|
|||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
break;
|
break;
|
||||||
case CONSTANTS.WorkTypeFaction:
|
case WorkType.Faction:
|
||||||
details = (
|
details = (
|
||||||
<>
|
<>
|
||||||
{player.factionWorkType} for <strong>{player.currentWorkFactionName}</strong>
|
{player.factionWorkType} for <strong>{player.currentWorkFactionName}</strong>
|
||||||
@ -179,12 +180,12 @@ function Work(): React.ReactElement {
|
|||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
break;
|
break;
|
||||||
case CONSTANTS.WorkTypeStudyClass:
|
case WorkType.StudyClass:
|
||||||
details = <>{player.workType}</>;
|
details = <>{player.workType}</>;
|
||||||
header = <>You are {player.className}</>;
|
header = <>You are {player.className}</>;
|
||||||
innerText = <>{convertTimeMsToTimeElapsedString(player.timeWorked)}</>;
|
innerText = <>{convertTimeMsToTimeElapsedString(player.timeWorked)}</>;
|
||||||
break;
|
break;
|
||||||
case CONSTANTS.WorkTypeCreateProgram:
|
case WorkType.CreateProgram:
|
||||||
details = <>Coding {player.createProgramName}</>;
|
details = <>Coding {player.createProgramName}</>;
|
||||||
header = <>Creating a program</>;
|
header = <>Creating a program</>;
|
||||||
innerText = (
|
innerText = (
|
||||||
@ -194,7 +195,7 @@ function Work(): React.ReactElement {
|
|||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
break;
|
break;
|
||||||
case CONSTANTS.WorkTypeGraftAugmentation:
|
case WorkType.GraftAugmentation:
|
||||||
details = <>Grafting {player.graftAugmentationName}</>;
|
details = <>Grafting {player.graftAugmentationName}</>;
|
||||||
header = <>Grafting an Augmentation</>;
|
header = <>Grafting an Augmentation</>;
|
||||||
innerText = (
|
innerText = (
|
||||||
|
@ -12,6 +12,7 @@ const useStyles = makeStyles((theme: Theme) =>
|
|||||||
display: "flex",
|
display: "flex",
|
||||||
alignItems: "center",
|
alignItems: "center",
|
||||||
justifyContent: "center",
|
justifyContent: "center",
|
||||||
|
zIndex: 999999,
|
||||||
},
|
},
|
||||||
paper: {
|
paper: {
|
||||||
backgroundColor: theme.palette.background.default,
|
backgroundColor: theme.palette.background.default,
|
||||||
|
13
src/ui/React/Progress.tsx
Normal file
13
src/ui/React/Progress.tsx
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
import LinearProgress from "@mui/material/LinearProgress";
|
||||||
|
import { Theme } from "@mui/material/styles";
|
||||||
|
import withStyles from "@mui/styles/withStyles";
|
||||||
|
|
||||||
|
export const ProgressBar = withStyles((theme: Theme) => ({
|
||||||
|
root: {
|
||||||
|
backgroundColor: theme.palette.background.paper,
|
||||||
|
},
|
||||||
|
bar: {
|
||||||
|
transition: "none",
|
||||||
|
backgroundColor: theme.palette.primary.main,
|
||||||
|
},
|
||||||
|
}))(LinearProgress);
|
@ -16,19 +16,21 @@ interface IProps {
|
|||||||
name: string;
|
name: string;
|
||||||
color: string;
|
color: string;
|
||||||
classes?: any;
|
classes?: any;
|
||||||
data: ITableRowData;
|
data?: ITableRowData;
|
||||||
children?: React.ReactElement;
|
children?: React.ReactElement;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const StatsRow = ({ name, color, classes = useStyles(), children, data }: IProps): React.ReactElement => {
|
export const StatsRow = ({ name, color, classes = useStyles(), children, data }: IProps): React.ReactElement => {
|
||||||
let content;
|
let content = "";
|
||||||
|
|
||||||
if (data.content !== undefined) {
|
if (data) {
|
||||||
content = data.content;
|
if (data.content !== undefined) {
|
||||||
} else if (data.level !== undefined && data.exp !== undefined) {
|
content = data.content;
|
||||||
content = `${formatNumber(data.level, 0)} (${numeralWrapper.formatExp(data.exp)} exp)`;
|
} else if (data.level !== undefined && data.exp !== undefined) {
|
||||||
} else if (data.level !== undefined && data.exp === undefined) {
|
content = `${formatNumber(data.level, 0)} (${numeralWrapper.formatExp(data.exp)} exp)`;
|
||||||
content = `${formatNumber(data.level, 0)}`;
|
} else if (data.level !== undefined && data.exp === undefined) {
|
||||||
|
content = `${formatNumber(data.level, 0)}`;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -105,6 +105,13 @@ export function comprLZEncode(plain: string): string {
|
|||||||
|
|
||||||
// start new literal
|
// start new literal
|
||||||
set(new_state, 0, 1, string + length + offset);
|
set(new_state, 0, 1, string + length + offset);
|
||||||
|
|
||||||
|
// end current backreference and start new backreference
|
||||||
|
for (let new_offset = 1; new_offset <= Math.min(9, i); ++new_offset) {
|
||||||
|
if (plain[i - new_offset] === c) {
|
||||||
|
set(new_state, new_offset, 1, string + length + offset + "0");
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
49
src/utils/WorkType.ts
Normal file
49
src/utils/WorkType.ts
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
export enum WorkType {
|
||||||
|
None = "",
|
||||||
|
Company = "Working for Company",
|
||||||
|
CompanyPartTime = "Working for Company part-time",
|
||||||
|
Faction = "Working for Faction",
|
||||||
|
CreateProgram = "Working on Create a Program",
|
||||||
|
StudyClass = "Studying or Taking a class at university",
|
||||||
|
Crime = "Committing a crime",
|
||||||
|
GraftAugmentation = "Grafting an Augmentation",
|
||||||
|
}
|
||||||
|
|
||||||
|
export enum PlayerFactionWorkType {
|
||||||
|
None = "",
|
||||||
|
Hacking = "Faction Hacking Work",
|
||||||
|
Field = "Faction Field Work",
|
||||||
|
Security = "Faction Security Work",
|
||||||
|
}
|
||||||
|
|
||||||
|
export enum ClassType {
|
||||||
|
None = "",
|
||||||
|
StudyComputerScience = "studying Computer Science",
|
||||||
|
DataStructures = "taking a Data Structures course",
|
||||||
|
Networks = "taking a Networks course",
|
||||||
|
Algorithms = "taking an Algorithms course",
|
||||||
|
|
||||||
|
Management = "taking a Management course",
|
||||||
|
Leadership = "taking a Leadership course",
|
||||||
|
|
||||||
|
GymStrength = "training your strength at a gym",
|
||||||
|
GymDefense = "training your defense at a gym",
|
||||||
|
GymDexterity = "training your dexterity at a gym",
|
||||||
|
GymAgility = "training your agility at a gym",
|
||||||
|
}
|
||||||
|
|
||||||
|
export enum CrimeType {
|
||||||
|
None = "",
|
||||||
|
Shoplift = "shoplift",
|
||||||
|
RobStore = "rob a store",
|
||||||
|
Mug = "mug someone",
|
||||||
|
Larceny = "commit larceny",
|
||||||
|
Drugs = "deal drugs",
|
||||||
|
BondForgery = "forge corporate bonds",
|
||||||
|
TraffickArms = "traffick illegal arms",
|
||||||
|
Homicide = "commit homicide",
|
||||||
|
GrandTheftAuto = "commit grand theft auto",
|
||||||
|
Kidnap = "kidnap someone for ransom",
|
||||||
|
Assassination = "assassinate a high-profile target",
|
||||||
|
Heist = "pull off the ultimate heist",
|
||||||
|
}
|
@ -20,6 +20,6 @@ export function exceptionAlert(e: IError | string): void {
|
|||||||
"This is a bug, please report to game developer with this " +
|
"This is a bug, please report to game developer with this " +
|
||||||
"message as well as details about how to reproduce the bug.<br><br>" +
|
"message as well as details about how to reproduce the bug.<br><br>" +
|
||||||
"If you want to be safe, I suggest refreshing the game WITHOUT saving so that your " +
|
"If you want to be safe, I suggest refreshing the game WITHOUT saving so that your " +
|
||||||
"safe doesn't get corrupted",
|
"save doesn't get corrupted",
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/**
|
/**
|
||||||
* Keyboard key codes
|
* Keyboard key codes as returned by event.key
|
||||||
*/
|
*/
|
||||||
export enum KEY {
|
export enum KEY {
|
||||||
//SHIFT: 16, // Check by `&& event.shiftKey`
|
//SHIFT: 16, // Check by `&& event.shiftKey`
|
||||||
@ -70,3 +70,69 @@ export enum KEY {
|
|||||||
Y = "y",
|
Y = "y",
|
||||||
Z = "z",
|
Z = "z",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Keyboard key codes as returned by event.code
|
||||||
|
*/
|
||||||
|
export enum KEYCODE {
|
||||||
|
//SHIFT: 16, // Check by `&& event.shiftKey`
|
||||||
|
//CTRL: 17, // Check by `&& event.ctrlKey`
|
||||||
|
//ALT: 18, // Check by `&& event.altKey`
|
||||||
|
ENTER = "Enter",
|
||||||
|
ESC = "Escape",
|
||||||
|
TAB = "Tab",
|
||||||
|
SPACE = "Space",
|
||||||
|
BACKSPACE = "Backspace",
|
||||||
|
UP_ARROW = "ArrowUp",
|
||||||
|
DOWN_ARROW = "ArrowDown",
|
||||||
|
LEFT_ARROW = "ArrowLeft",
|
||||||
|
RIGHT_ARROW = "ArrowRight",
|
||||||
|
|
||||||
|
BACKWARD_SLASH = "Backslash",
|
||||||
|
BACKQUOTE = "Backquote",
|
||||||
|
COMMA = "Comma",
|
||||||
|
DOT = "Period",
|
||||||
|
EQUAL = "Equal",
|
||||||
|
FORWARD_SLASH = "Slash",
|
||||||
|
HYPHEN = "Minus",
|
||||||
|
SEMICOLON = "Semicolon",
|
||||||
|
QUOTE = "Quote",
|
||||||
|
|
||||||
|
k0 = "Digit0",
|
||||||
|
k1 = "Digit1",
|
||||||
|
k2 = "Digit2",
|
||||||
|
k3 = "Digit3",
|
||||||
|
k4 = "Digit4",
|
||||||
|
k5 = "Digit5",
|
||||||
|
k6 = "Digit6",
|
||||||
|
k7 = "Digit7",
|
||||||
|
k8 = "Digit8",
|
||||||
|
k9 = "Digit9",
|
||||||
|
|
||||||
|
A = "KeyA",
|
||||||
|
B = "KeyB",
|
||||||
|
C = "KeyC",
|
||||||
|
D = "KeyD",
|
||||||
|
E = "KeyE",
|
||||||
|
F = "KeyF",
|
||||||
|
G = "KeyG",
|
||||||
|
H = "KeyH",
|
||||||
|
I = "KeyI",
|
||||||
|
J = "KeyJ",
|
||||||
|
K = "KeyK",
|
||||||
|
L = "KeyL",
|
||||||
|
M = "KeyM",
|
||||||
|
N = "KeyN",
|
||||||
|
O = "KeyO",
|
||||||
|
P = "KeyP",
|
||||||
|
Q = "KeyQ",
|
||||||
|
R = "KeyR",
|
||||||
|
S = "KeyS",
|
||||||
|
T = "KeyT",
|
||||||
|
U = "KeyU",
|
||||||
|
V = "KeyV",
|
||||||
|
W = "KeyW",
|
||||||
|
X = "KeyX",
|
||||||
|
Y = "KeyY",
|
||||||
|
Z = "KeyZ",
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user