mirror of
https://github.com/bitburner-official/bitburner-src.git
synced 2024-11-19 14:13:48 +01:00
Merge branch 'dev' into wrap-api
This commit is contained in:
commit
b80e2d5fd1
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
11
doc/NEW_BN_GUIDELINE.md
Normal file
11
doc/NEW_BN_GUIDELINE.md
Normal file
@ -0,0 +1,11 @@
|
||||
Promote:
|
||||
|
||||
- New mechanic
|
||||
- Coding problems based on NP problems. This makes solution that are easy to implement inefficient and solutions that are hard to implement efficent. (eg. Stanek)
|
||||
- inter-mechanic synergy
|
||||
- Simplicity (eg. Stanek, Hashnet. bad example: Corp)
|
||||
|
||||
Avoid:
|
||||
|
||||
- Failure conditions, it's very frustrating to revert several days worth of progress.
|
||||
- Making existing mechanic harder. This makes it hard to port the content to other BNs.
|
1
doc/POTENTIAL_BN_1.md
Normal file
1
doc/POTENTIAL_BN_1.md
Normal file
@ -0,0 +1 @@
|
||||
Sleeves meet Screeps (That's all I got)
|
3
doc/POTENTIAL_BN_2.md
Normal file
3
doc/POTENTIAL_BN_2.md
Normal file
@ -0,0 +1,3 @@
|
||||
A game of risk from the point of view of a politician.
|
||||
|
||||
You allocate resources on a world map, trying to win elections.
|
@ -1 +0,0 @@
|
||||
I want the wiki here https://bitburner.fandom.com/wiki/Bitburner_Wiki taken down please.
|
@ -631,6 +631,7 @@ export class Augmentation {
|
||||
augmentationReference.baseCost *
|
||||
getGenericAugmentationPriceMultiplier() *
|
||||
BitNodeMultipliers.AugmentationMoneyCost;
|
||||
repCost = augmentationReference.baseRepRequirement * BitNodeMultipliers.AugmentationRepCost;
|
||||
}
|
||||
return { moneyCost, repCost };
|
||||
}
|
||||
|
@ -45,13 +45,13 @@ function BitNodeModifiedStats(props: IBitNodeModifiedStatsProps): React.ReactEle
|
||||
);
|
||||
}
|
||||
|
||||
type MultiplierListItemData = [
|
||||
multiplier: string,
|
||||
currentValue: number,
|
||||
augmentedValue: number,
|
||||
bitNodeMultiplier: number,
|
||||
color: string,
|
||||
];
|
||||
interface MultiplierListItemData {
|
||||
mult: string;
|
||||
current: number;
|
||||
augmented: number;
|
||||
bnMult?: number;
|
||||
color?: string;
|
||||
}
|
||||
|
||||
interface IMultiplierListProps {
|
||||
rows: MultiplierListItemData[];
|
||||
@ -60,23 +60,23 @@ interface IMultiplierListProps {
|
||||
function MultiplierList(props: IMultiplierListProps): React.ReactElement {
|
||||
const listItems = props.rows
|
||||
.map((data) => {
|
||||
const [multiplier, currentValue, augmentedValue, bitNodeMultiplier, color] = data;
|
||||
const { mult, current, augmented, bnMult = 1, color = Settings.theme.primary } = data;
|
||||
|
||||
if (!isNaN(augmentedValue)) {
|
||||
if (!isNaN(augmented)) {
|
||||
return (
|
||||
<ListItem key={multiplier} disableGutters sx={{ py: 0 }}>
|
||||
<ListItem key={mult} disableGutters sx={{ py: 0 }}>
|
||||
<ListItemText
|
||||
sx={{ my: 0.1 }}
|
||||
primary={
|
||||
<Typography color={color}>
|
||||
<b>{multiplier}</b>
|
||||
<b>{mult}</b>
|
||||
</Typography>
|
||||
}
|
||||
secondary={
|
||||
<span style={{ display: "flex", alignItems: "center", flexWrap: "wrap" }}>
|
||||
<BitNodeModifiedStats base={currentValue} mult={bitNodeMultiplier} color={color} />
|
||||
<BitNodeModifiedStats base={current} mult={bnMult} color={color} />
|
||||
<DoubleArrow fontSize="small" color="success" sx={{ mb: 0.5, mx: 1 }} />
|
||||
<BitNodeModifiedStats base={augmentedValue} mult={bitNodeMultiplier} color={Settings.theme.success} />
|
||||
<BitNodeModifiedStats base={augmented} mult={bnMult} color={Settings.theme.success} />
|
||||
</span>
|
||||
}
|
||||
disableTypography
|
||||
@ -94,177 +94,205 @@ function MultiplierList(props: IMultiplierListProps): React.ReactElement {
|
||||
export function PlayerMultipliers(): React.ReactElement {
|
||||
const mults = calculateAugmentedStats();
|
||||
|
||||
// Column data is a bit janky, so it's set up here to allow for
|
||||
// easier logic in setting up the layout
|
||||
const leftColData: MultiplierListItemData[] = [
|
||||
...[
|
||||
["Hacking Chance ", Player.hacking_chance_mult, Player.hacking_chance_mult * mults.hacking_chance_mult, 1],
|
||||
["Hacking Speed ", Player.hacking_speed_mult, Player.hacking_speed_mult * mults.hacking_speed_mult, 1],
|
||||
["Hacking Money ", Player.hacking_money_mult, Player.hacking_money_mult * mults.hacking_money_mult, 1],
|
||||
["Hacking Growth ", Player.hacking_grow_mult, Player.hacking_grow_mult * mults.hacking_grow_mult, 1],
|
||||
[
|
||||
"Hacking Level ",
|
||||
Player.hacking_mult,
|
||||
Player.hacking_mult * mults.hacking_mult,
|
||||
BitNodeMultipliers.HackingLevelMultiplier,
|
||||
],
|
||||
[
|
||||
"Hacking Experience ",
|
||||
Player.hacking_exp_mult,
|
||||
Player.hacking_exp_mult * mults.hacking_exp_mult,
|
||||
BitNodeMultipliers.HackExpGain,
|
||||
],
|
||||
].map((data): MultiplierListItemData => (data as any).concat([Settings.theme.hack])),
|
||||
{
|
||||
mult: "Hacking Chance",
|
||||
current: Player.hacking_chance_mult,
|
||||
augmented: Player.hacking_chance_mult * mults.hacking_chance_mult,
|
||||
},
|
||||
{
|
||||
mult: "Hacking Speed",
|
||||
current: Player.hacking_speed_mult,
|
||||
augmented: Player.hacking_speed_mult * mults.hacking_speed_mult,
|
||||
},
|
||||
{
|
||||
mult: "Hacking Money",
|
||||
current: Player.hacking_money_mult,
|
||||
augmented: Player.hacking_money_mult * mults.hacking_money_mult,
|
||||
bnMult: BitNodeMultipliers.ScriptHackMoney,
|
||||
},
|
||||
{
|
||||
mult: "Hacking Growth",
|
||||
current: Player.hacking_grow_mult,
|
||||
augmented: Player.hacking_grow_mult * mults.hacking_grow_mult,
|
||||
},
|
||||
{
|
||||
mult: "Hacking Level",
|
||||
current: Player.hacking_mult,
|
||||
augmented: Player.hacking_mult * mults.hacking_mult,
|
||||
bnMult: BitNodeMultipliers.HackingLevelMultiplier,
|
||||
},
|
||||
{
|
||||
mult: "Hacking Experience",
|
||||
current: Player.hacking_exp_mult,
|
||||
augmented: Player.hacking_exp_mult * mults.hacking_exp_mult,
|
||||
bnMult: BitNodeMultipliers.HackExpGain,
|
||||
},
|
||||
].map((data: MultiplierListItemData) =>
|
||||
Object.defineProperty(data, "color", {
|
||||
value: Settings.theme.hack,
|
||||
}),
|
||||
),
|
||||
...[
|
||||
[
|
||||
"Strength Level ",
|
||||
Player.strength_mult,
|
||||
Player.strength_mult * mults.strength_mult,
|
||||
BitNodeMultipliers.StrengthLevelMultiplier,
|
||||
],
|
||||
["Strength Experience ", Player.strength_exp_mult, Player.strength_exp_mult * mults.strength_exp_mult, 1],
|
||||
[
|
||||
"Defense Level ",
|
||||
Player.defense_mult,
|
||||
Player.defense_mult * mults.defense_mult,
|
||||
BitNodeMultipliers.DefenseLevelMultiplier,
|
||||
],
|
||||
["Defense Experience ", Player.defense_exp_mult, Player.defense_exp_mult * mults.defense_exp_mult, 1],
|
||||
[
|
||||
"Dexterity Level ",
|
||||
Player.dexterity_mult,
|
||||
Player.dexterity_mult * mults.dexterity_mult,
|
||||
BitNodeMultipliers.DexterityLevelMultiplier,
|
||||
],
|
||||
["Dexterity Experience ", Player.dexterity_exp_mult, Player.dexterity_exp_mult * mults.dexterity_exp_mult, 1],
|
||||
[
|
||||
"Agility Level ",
|
||||
Player.agility_mult,
|
||||
Player.agility_mult * mults.agility_mult,
|
||||
BitNodeMultipliers.AgilityLevelMultiplier,
|
||||
],
|
||||
["Agility Experience ", Player.agility_exp_mult, Player.agility_exp_mult * mults.agility_exp_mult, 1],
|
||||
].map((data): MultiplierListItemData => (data as any).concat([Settings.theme.combat])),
|
||||
[
|
||||
"Charisma Level ",
|
||||
Player.charisma_mult,
|
||||
Player.charisma_mult * mults.charisma_mult,
|
||||
BitNodeMultipliers.CharismaLevelMultiplier,
|
||||
Settings.theme.cha,
|
||||
],
|
||||
[
|
||||
"Charisma Experience ",
|
||||
Player.charisma_exp_mult,
|
||||
Player.charisma_exp_mult * mults.charisma_exp_mult,
|
||||
1,
|
||||
Settings.theme.cha,
|
||||
],
|
||||
{
|
||||
mult: "Strength Level",
|
||||
current: Player.strength_mult,
|
||||
augmented: Player.strength_mult * mults.strength_mult,
|
||||
bnMult: BitNodeMultipliers.StrengthLevelMultiplier,
|
||||
},
|
||||
{
|
||||
mult: "Strength Experience",
|
||||
current: Player.strength_exp_mult,
|
||||
augmented: Player.strength_exp_mult * mults.strength_exp_mult,
|
||||
},
|
||||
{
|
||||
mult: "Defense Level",
|
||||
current: Player.defense_mult,
|
||||
augmented: Player.defense_mult * mults.defense_mult,
|
||||
bnMult: BitNodeMultipliers.DefenseLevelMultiplier,
|
||||
},
|
||||
{
|
||||
mult: "Defense Experience",
|
||||
current: Player.defense_exp_mult,
|
||||
augmented: Player.defense_exp_mult * mults.defense_exp_mult,
|
||||
},
|
||||
{
|
||||
mult: "Dexterity Level",
|
||||
current: Player.dexterity_mult,
|
||||
augmented: Player.dexterity_mult * mults.dexterity_mult,
|
||||
bnMult: BitNodeMultipliers.DexterityLevelMultiplier,
|
||||
},
|
||||
{
|
||||
mult: "Dexterity Experience",
|
||||
current: Player.dexterity_exp_mult,
|
||||
augmented: Player.dexterity_exp_mult * mults.dexterity_exp_mult,
|
||||
},
|
||||
{
|
||||
mult: "Agility Level",
|
||||
current: Player.agility_mult,
|
||||
augmented: Player.agility_mult * mults.agility_mult,
|
||||
bnMult: BitNodeMultipliers.AgilityLevelMultiplier,
|
||||
},
|
||||
{
|
||||
mult: "Agility Experience",
|
||||
current: Player.agility_exp_mult,
|
||||
augmented: Player.agility_exp_mult * mults.agility_exp_mult,
|
||||
},
|
||||
].map((data: MultiplierListItemData) =>
|
||||
Object.defineProperty(data, "color", {
|
||||
value: Settings.theme.combat,
|
||||
}),
|
||||
),
|
||||
{
|
||||
mult: "Charisma Level",
|
||||
current: Player.charisma_mult,
|
||||
augmented: Player.charisma_mult * mults.charisma_mult,
|
||||
bnMult: BitNodeMultipliers.CharismaLevelMultiplier,
|
||||
color: Settings.theme.cha,
|
||||
},
|
||||
{
|
||||
mult: "Charisma Experience",
|
||||
current: Player.charisma_exp_mult,
|
||||
augmented: Player.charisma_exp_mult * mults.charisma_exp_mult,
|
||||
color: Settings.theme.cha,
|
||||
},
|
||||
];
|
||||
const rightColData: MultiplierListItemData[] = [
|
||||
...[
|
||||
[
|
||||
"Hacknet Node production ",
|
||||
Player.hacknet_node_money_mult,
|
||||
Player.hacknet_node_money_mult * mults.hacknet_node_money_mult,
|
||||
BitNodeMultipliers.HacknetNodeMoney,
|
||||
],
|
||||
[
|
||||
"Hacknet Node purchase cost ",
|
||||
Player.hacknet_node_purchase_cost_mult,
|
||||
Player.hacknet_node_purchase_cost_mult * mults.hacknet_node_purchase_cost_mult,
|
||||
1,
|
||||
],
|
||||
[
|
||||
"Hacknet Node RAM upgrade cost ",
|
||||
Player.hacknet_node_ram_cost_mult,
|
||||
Player.hacknet_node_ram_cost_mult * mults.hacknet_node_ram_cost_mult,
|
||||
1,
|
||||
],
|
||||
[
|
||||
"Hacknet Node Core purchase cost ",
|
||||
Player.hacknet_node_core_cost_mult,
|
||||
Player.hacknet_node_core_cost_mult * mults.hacknet_node_core_cost_mult,
|
||||
1,
|
||||
],
|
||||
[
|
||||
"Hacknet Node level upgrade cost ",
|
||||
Player.hacknet_node_level_cost_mult,
|
||||
Player.hacknet_node_level_cost_mult * mults.hacknet_node_level_cost_mult,
|
||||
1,
|
||||
],
|
||||
["Company reputation gain ", Player.company_rep_mult, Player.company_rep_mult * mults.company_rep_mult, 1],
|
||||
[
|
||||
"Faction reputation gain ",
|
||||
Player.faction_rep_mult,
|
||||
Player.faction_rep_mult * mults.faction_rep_mult,
|
||||
BitNodeMultipliers.FactionWorkRepGain,
|
||||
],
|
||||
].map((data): MultiplierListItemData => (data as any).concat([Settings.theme.primary])),
|
||||
[
|
||||
"Salary ",
|
||||
Player.work_money_mult,
|
||||
Player.work_money_mult * mults.work_money_mult,
|
||||
BitNodeMultipliers.CompanyWorkMoney,
|
||||
Settings.theme.money,
|
||||
],
|
||||
[
|
||||
"Crime success ",
|
||||
Player.crime_success_mult,
|
||||
Player.crime_success_mult * mults.crime_success_mult,
|
||||
1,
|
||||
Settings.theme.combat,
|
||||
],
|
||||
[
|
||||
"Crime money ",
|
||||
Player.crime_money_mult,
|
||||
Player.crime_money_mult * mults.crime_money_mult,
|
||||
BitNodeMultipliers.CrimeMoney,
|
||||
Settings.theme.money,
|
||||
],
|
||||
{
|
||||
mult: "Hacknet Node Production",
|
||||
current: Player.hacknet_node_money_mult,
|
||||
augmented: Player.hacknet_node_money_mult * mults.hacknet_node_money_mult,
|
||||
bnMult: BitNodeMultipliers.HacknetNodeMoney,
|
||||
},
|
||||
{
|
||||
mult: "Hacknet Node Purchase Cost",
|
||||
current: Player.hacknet_node_purchase_cost_mult,
|
||||
augmented: Player.hacknet_node_purchase_cost_mult * mults.hacknet_node_purchase_cost_mult,
|
||||
},
|
||||
{
|
||||
mult: "Hacknet Node RAM Upgrade Cost",
|
||||
current: Player.hacknet_node_ram_cost_mult,
|
||||
augmented: Player.hacknet_node_ram_cost_mult * mults.hacknet_node_ram_cost_mult,
|
||||
},
|
||||
{
|
||||
mult: "Hacknet Node Core Purchase Cost",
|
||||
current: Player.hacknet_node_core_cost_mult,
|
||||
augmented: Player.hacknet_node_core_cost_mult * mults.hacknet_node_core_cost_mult,
|
||||
},
|
||||
{
|
||||
mult: "Hacknet Node Level Upgrade Cost",
|
||||
current: Player.hacknet_node_level_cost_mult,
|
||||
augmented: Player.hacknet_node_level_cost_mult * mults.hacknet_node_level_cost_mult,
|
||||
},
|
||||
{
|
||||
mult: "Company Reputation Gain",
|
||||
current: Player.company_rep_mult,
|
||||
augmented: Player.company_rep_mult * mults.company_rep_mult,
|
||||
},
|
||||
{
|
||||
mult: "Faction Reputation Gain",
|
||||
current: Player.faction_rep_mult,
|
||||
augmented: Player.faction_rep_mult * mults.faction_rep_mult,
|
||||
bnMult: BitNodeMultipliers.FactionWorkRepGain,
|
||||
},
|
||||
{
|
||||
mult: "Salary",
|
||||
current: Player.work_money_mult,
|
||||
augmented: Player.work_money_mult * mults.work_money_mult,
|
||||
bnMult: BitNodeMultipliers.CompanyWorkMoney,
|
||||
color: Settings.theme.money,
|
||||
},
|
||||
{
|
||||
mult: "Crime Success Chance",
|
||||
current: Player.crime_success_mult,
|
||||
augmented: Player.crime_success_mult * mults.crime_success_mult,
|
||||
color: Settings.theme.combat,
|
||||
},
|
||||
{
|
||||
mult: "Crime Money",
|
||||
current: Player.crime_money_mult,
|
||||
augmented: Player.crime_money_mult * mults.crime_money_mult,
|
||||
bnMult: BitNodeMultipliers.CrimeMoney,
|
||||
color: Settings.theme.money,
|
||||
},
|
||||
];
|
||||
|
||||
if (Player.canAccessBladeburner()) {
|
||||
rightColData.push(
|
||||
...[
|
||||
[
|
||||
"Bladeburner Success Chance",
|
||||
Player.bladeburner_success_chance_mult,
|
||||
Player.bladeburner_success_chance_mult * mults.bladeburner_success_chance_mult,
|
||||
1,
|
||||
],
|
||||
[
|
||||
"Bladeburner Max Stamina",
|
||||
Player.bladeburner_max_stamina_mult,
|
||||
Player.bladeburner_max_stamina_mult * mults.bladeburner_max_stamina_mult,
|
||||
1,
|
||||
],
|
||||
[
|
||||
"Bladeburner Stamina Gain",
|
||||
Player.bladeburner_stamina_gain_mult,
|
||||
Player.bladeburner_stamina_gain_mult * mults.bladeburner_stamina_gain_mult,
|
||||
1,
|
||||
],
|
||||
[
|
||||
"Bladeburner Field Analysis",
|
||||
Player.bladeburner_analysis_mult,
|
||||
Player.bladeburner_analysis_mult * mults.bladeburner_analysis_mult,
|
||||
1,
|
||||
],
|
||||
].map((data): MultiplierListItemData => (data as any).concat([Settings.theme.primary])),
|
||||
{
|
||||
mult: "Bladeburner Success Chance",
|
||||
current: Player.bladeburner_success_chance_mult,
|
||||
augmented: Player.bladeburner_success_chance_mult * mults.bladeburner_success_chance_mult,
|
||||
},
|
||||
{
|
||||
mult: "Bladeburner Max Stamina",
|
||||
current: Player.bladeburner_max_stamina_mult,
|
||||
augmented: Player.bladeburner_max_stamina_mult * mults.bladeburner_max_stamina_mult,
|
||||
},
|
||||
{
|
||||
mult: "Bladeburner Stamina Gain",
|
||||
current: Player.bladeburner_stamina_gain_mult,
|
||||
augmented: Player.bladeburner_stamina_gain_mult * mults.bladeburner_stamina_gain_mult,
|
||||
},
|
||||
{
|
||||
mult: "Bladeburner Field Analysis",
|
||||
current: Player.bladeburner_analysis_mult,
|
||||
augmented: Player.bladeburner_analysis_mult * mults.bladeburner_analysis_mult,
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
const hasLeftImprovements = +!!(leftColData.filter((item) => item[2] !== 0).length > 0),
|
||||
hasRightImprovements = +!!(rightColData.filter((item) => item[2] !== 0).length > 0);
|
||||
|
||||
return (
|
||||
<Paper
|
||||
sx={{
|
||||
p: 1,
|
||||
maxHeight: 400,
|
||||
overflowY: "scroll",
|
||||
display: "grid",
|
||||
gridTemplateColumns: `repeat(${hasLeftImprovements + hasRightImprovements}, 1fr)`,
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
flexWrap: "wrap",
|
||||
gap: 1,
|
||||
}}
|
||||
>
|
||||
<MultiplierList rows={leftColData} />
|
||||
|
@ -488,7 +488,7 @@ export const defaultMultipliers: IBitNodeMultipliers = {
|
||||
FourSigmaMarketDataApiCost: 1,
|
||||
|
||||
CorporationValuation: 1,
|
||||
CorporationSoftCap: 1,
|
||||
CorporationSoftcap: 1,
|
||||
|
||||
BladeburnerRank: 1,
|
||||
BladeburnerSkillCost: 1,
|
||||
@ -504,6 +504,8 @@ export const defaultMultipliers: IBitNodeMultipliers = {
|
||||
WorldDaemonDifficulty: 1,
|
||||
};
|
||||
|
||||
Object.freeze(defaultMultipliers);
|
||||
|
||||
export function getBitNodeMultipliers(n: number, lvl: number): IBitNodeMultipliers {
|
||||
const mults = Object.assign({}, defaultMultipliers);
|
||||
switch (n) {
|
||||
@ -523,7 +525,7 @@ export function getBitNodeMultipliers(n: number, lvl: number): IBitNodeMultiplie
|
||||
StaneksGiftPowerMultiplier: 2,
|
||||
StaneksGiftExtraSize: -6,
|
||||
PurchasedServerSoftcap: 1.3,
|
||||
CorporationSoftCap: 0.9,
|
||||
CorporationSoftcap: 0.9,
|
||||
WorldDaemonDifficulty: 5,
|
||||
});
|
||||
}
|
||||
@ -609,7 +611,7 @@ export function getBitNodeMultipliers(n: number, lvl: number): IBitNodeMultiplie
|
||||
StaneksGiftPowerMultiplier: 0.5,
|
||||
StaneksGiftExtraSize: 2,
|
||||
GangSoftcap: 0.7,
|
||||
CorporationSoftCap: 0.9,
|
||||
CorporationSoftcap: 0.9,
|
||||
WorldDaemonDifficulty: 2,
|
||||
GangUniqueAugs: 0.2,
|
||||
});
|
||||
@ -637,7 +639,7 @@ export function getBitNodeMultipliers(n: number, lvl: number): IBitNodeMultiplie
|
||||
StaneksGiftPowerMultiplier: 0.9,
|
||||
StaneksGiftExtraSize: -1,
|
||||
GangSoftcap: 0.7,
|
||||
CorporationSoftCap: 0.9,
|
||||
CorporationSoftcap: 0.9,
|
||||
WorldDaemonDifficulty: 2,
|
||||
GangUniqueAugs: 0.2,
|
||||
});
|
||||
@ -657,7 +659,7 @@ export function getBitNodeMultipliers(n: number, lvl: number): IBitNodeMultiplie
|
||||
StaneksGiftExtraSize: -99,
|
||||
PurchasedServerSoftcap: 4,
|
||||
GangSoftcap: 0,
|
||||
CorporationSoftCap: 0,
|
||||
CorporationSoftcap: 0,
|
||||
GangUniqueAugs: 0,
|
||||
});
|
||||
}
|
||||
@ -685,7 +687,7 @@ export function getBitNodeMultipliers(n: number, lvl: number): IBitNodeMultiplie
|
||||
StaneksGiftPowerMultiplier: 0.5,
|
||||
StaneksGiftExtraSize: 2,
|
||||
GangSoftcap: 0.8,
|
||||
CorporationSoftCap: 0.7,
|
||||
CorporationSoftcap: 0.7,
|
||||
WorldDaemonDifficulty: 2,
|
||||
GangUniqueAugs: 0.25,
|
||||
});
|
||||
@ -717,7 +719,7 @@ export function getBitNodeMultipliers(n: number, lvl: number): IBitNodeMultiplie
|
||||
StaneksGiftExtraSize: -3,
|
||||
PurchasedServerSoftcap: 1.1,
|
||||
GangSoftcap: 0.9,
|
||||
CorporationSoftCap: 0.9,
|
||||
CorporationSoftcap: 0.9,
|
||||
WorldDaemonDifficulty: 2,
|
||||
GangUniqueAugs: 0.25,
|
||||
});
|
||||
@ -741,7 +743,7 @@ export function getBitNodeMultipliers(n: number, lvl: number): IBitNodeMultiplie
|
||||
FourSigmaMarketDataCost: 4,
|
||||
FourSigmaMarketDataApiCost: 4,
|
||||
PurchasedServerSoftcap: 2,
|
||||
CorporationSoftCap: 0.9,
|
||||
CorporationSoftcap: 0.9,
|
||||
WorldDaemonDifficulty: 1.5,
|
||||
GangUniqueAugs: 0.75,
|
||||
});
|
||||
@ -809,7 +811,7 @@ export function getBitNodeMultipliers(n: number, lvl: number): IBitNodeMultiplie
|
||||
StaneksGiftPowerMultiplier: inc,
|
||||
StaneksGiftExtraSize: inc,
|
||||
GangSoftcap: 0.8,
|
||||
CorporationSoftCap: 0.8,
|
||||
CorporationSoftcap: 0.8,
|
||||
WorldDaemonDifficulty: inc,
|
||||
|
||||
GangUniqueAugs: dec,
|
||||
@ -854,7 +856,7 @@ export function getBitNodeMultipliers(n: number, lvl: number): IBitNodeMultiplie
|
||||
StaneksGiftPowerMultiplier: 2,
|
||||
StaneksGiftExtraSize: 1,
|
||||
GangSoftcap: 0.3,
|
||||
CorporationSoftCap: 0.3,
|
||||
CorporationSoftcap: 0.3,
|
||||
WorldDaemonDifficulty: 3,
|
||||
GangUniqueAugs: 0.1,
|
||||
});
|
||||
|
@ -242,7 +242,7 @@ export interface IBitNodeMultipliers {
|
||||
/**
|
||||
* Influences corporation dividends.
|
||||
*/
|
||||
CorporationSoftCap: number;
|
||||
CorporationSoftcap: number;
|
||||
|
||||
// Index signature
|
||||
[key: string]: number;
|
||||
@ -252,4 +252,4 @@ export interface IBitNodeMultipliers {
|
||||
* The multipliers that are influenced by current Bitnode progression.
|
||||
*/
|
||||
// tslint:disable-next-line:variable-name
|
||||
export const BitNodeMultipliers = defaultMultipliers;
|
||||
export const BitNodeMultipliers = Object.assign({}, defaultMultipliers);
|
||||
|
@ -1,554 +1,335 @@
|
||||
import ExpandMore from "@mui/icons-material/ExpandMore";
|
||||
import ExpandLess from "@mui/icons-material/ExpandLess";
|
||||
import { Box, Collapse, ListItemButton, ListItemText, Paper, Typography } from "@mui/material";
|
||||
import ExpandMore from "@mui/icons-material/ExpandMore";
|
||||
import { Box, Collapse, ListItemButton, ListItemText, Paper, Table, TableBody, Typography } from "@mui/material";
|
||||
import { uniqueId } from "lodash";
|
||||
import React from "react";
|
||||
import { SpecialServers } from "../../Server/data/SpecialServers";
|
||||
import { Settings } from "../../Settings/Settings";
|
||||
import { use } from "../../ui/Context";
|
||||
import { StatsRow } from "../../ui/React/StatsRow";
|
||||
import { defaultMultipliers, getBitNodeMultipliers } from "../BitNode";
|
||||
import { IBitNodeMultipliers } from "../BitNodeMultipliers";
|
||||
import { SpecialServers } from "../../Server/data/SpecialServers";
|
||||
|
||||
interface IProps {
|
||||
n: number;
|
||||
level?: number;
|
||||
}
|
||||
|
||||
export function BitnodeMultiplierDescription({ n }: IProps): React.ReactElement {
|
||||
const player = use.Player();
|
||||
export function BitnodeMultiplierDescription({ n, level }: IProps): React.ReactElement {
|
||||
const [open, setOpen] = React.useState(false);
|
||||
const mults = getBitNodeMultipliers(n, player.sourceFileLvl(n));
|
||||
if (n === 1) return <></>;
|
||||
|
||||
return (
|
||||
<>
|
||||
<br />
|
||||
<Box component={Paper}>
|
||||
<ListItemButton onClick={() => setOpen((old) => !old)}>
|
||||
<ListItemText primary={<Typography>Bitnode multipliers:</Typography>} />
|
||||
{open ? <ExpandLess color="primary" /> : <ExpandMore color="primary" />}
|
||||
</ListItemButton>
|
||||
<Box mx={2}>
|
||||
<Collapse in={open}>
|
||||
<GeneralMults n={n} mults={mults} />
|
||||
<FactionMults n={n} mults={mults} />
|
||||
<AugmentationMults n={n} mults={mults} />
|
||||
<StockMults n={n} mults={mults} />
|
||||
<SkillMults n={n} mults={mults} />
|
||||
<HackingMults n={n} mults={mults} />
|
||||
<PurchasedServersMults n={n} mults={mults} />
|
||||
<CrimeMults n={n} mults={mults} />
|
||||
<InfiltrationMults n={n} mults={mults} />
|
||||
<CompanyMults n={n} mults={mults} />
|
||||
<GangMults n={n} mults={mults} />
|
||||
<CorporationMults n={n} mults={mults} />
|
||||
<BladeburnerMults n={n} mults={mults} />
|
||||
<StanekMults n={n} mults={mults} />
|
||||
<br />
|
||||
</Collapse>
|
||||
</Box>
|
||||
</Box>
|
||||
</>
|
||||
<Box component={Paper} sx={{ mt: 1, p: 1 }}>
|
||||
<ListItemButton disableGutters onClick={() => setOpen((old) => !old)}>
|
||||
<ListItemText primary={<Typography variant="h6">Bitnode Multipliers</Typography>} />
|
||||
{open ? <ExpandLess color="primary" /> : <ExpandMore color="primary" />}
|
||||
</ListItemButton>
|
||||
<Collapse in={open}>
|
||||
<BitNodeMultipliersDisplay n={n} level={level} />
|
||||
</Collapse>
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
|
||||
export const BitNodeMultipliersDisplay = ({ n, level }: IProps): React.ReactElement => {
|
||||
const player = use.Player();
|
||||
// If a level argument has been provided, use that as the multiplier level
|
||||
// If not, then we have to assume that we want the next level up from the
|
||||
// current node's source file, so we get the min of that, the SF's max level,
|
||||
// or if it's BN12, ∞
|
||||
const maxSfLevel = n === 12 ? Infinity : 3;
|
||||
const mults = getBitNodeMultipliers(n, level ?? Math.min(player.sourceFileLvl(n) + 1, maxSfLevel));
|
||||
|
||||
return (
|
||||
<Box sx={{ columnCount: 2, columnGap: 1, mb: -2 }}>
|
||||
<GeneralMults n={n} mults={mults} />
|
||||
<SkillMults n={n} mults={mults} />
|
||||
<FactionMults n={n} mults={mults} />
|
||||
<AugmentationMults n={n} mults={mults} />
|
||||
<HackingMults n={n} mults={mults} />
|
||||
<PurchasedServersMults n={n} mults={mults} />
|
||||
<StockMults n={n} mults={mults} />
|
||||
<CrimeMults n={n} mults={mults} />
|
||||
<InfiltrationMults n={n} mults={mults} />
|
||||
<CompanyMults n={n} mults={mults} />
|
||||
<GangMults n={n} mults={mults} />
|
||||
<CorporationMults n={n} mults={mults} />
|
||||
<BladeburnerMults n={n} mults={mults} />
|
||||
<StanekMults n={n} mults={mults} />
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
|
||||
interface IBNMultRows {
|
||||
[mult: string]: {
|
||||
name: string;
|
||||
content?: string;
|
||||
color?: string;
|
||||
};
|
||||
}
|
||||
|
||||
interface IBNMultTableProps {
|
||||
sectionName: string;
|
||||
rowData: IBNMultRows;
|
||||
mults: IBitNodeMultipliers;
|
||||
}
|
||||
|
||||
const BNMultTable = (props: IBNMultTableProps): React.ReactElement => {
|
||||
const rowsArray = Object.entries(props.rowData)
|
||||
.filter(([key, _value]) => props.mults[key] !== defaultMultipliers[key])
|
||||
.map(([key, value]) => (
|
||||
<StatsRow
|
||||
key={uniqueId()}
|
||||
name={value.name}
|
||||
data={{ content: value.content ?? `${(props.mults[key] * 100).toFixed(3)}%` }}
|
||||
color={value.color ?? Settings.theme.primary}
|
||||
/>
|
||||
));
|
||||
|
||||
return rowsArray.length > 0 ? (
|
||||
<span style={{ display: "inline-block", width: "100%", marginBottom: "16px" }}>
|
||||
<Typography variant="h6">{props.sectionName}</Typography>
|
||||
<Table>
|
||||
<TableBody>{rowsArray}</TableBody>
|
||||
</Table>
|
||||
</span>
|
||||
) : (
|
||||
<></>
|
||||
);
|
||||
};
|
||||
|
||||
interface IMultsProps {
|
||||
n: number;
|
||||
mults: IBitNodeMultipliers;
|
||||
}
|
||||
|
||||
function GeneralMults({ mults }: IMultsProps): React.ReactElement {
|
||||
// is it empty check
|
||||
if (
|
||||
mults.ClassGymExpGain === defaultMultipliers.ClassGymExpGain &&
|
||||
mults.CodingContractMoney === defaultMultipliers.CodingContractMoney &&
|
||||
mults.DaedalusAugsRequirement === defaultMultipliers.DaedalusAugsRequirement &&
|
||||
mults.WorldDaemonDifficulty === defaultMultipliers.WorldDaemonDifficulty &&
|
||||
mults.HacknetNodeMoney === defaultMultipliers.HacknetNodeMoney
|
||||
)
|
||||
return <></>;
|
||||
return (
|
||||
<>
|
||||
<br />
|
||||
<Typography variant={"h5"}>General:</Typography>
|
||||
<Box mx={1}>
|
||||
{mults.WorldDaemonDifficulty !== defaultMultipliers.WorldDaemonDifficulty ? (
|
||||
<Typography>
|
||||
{SpecialServers.WorldDaemon} difficulty: x{mults.WorldDaemonDifficulty.toFixed(3)}
|
||||
</Typography>
|
||||
) : (
|
||||
<></>
|
||||
)}
|
||||
{mults.DaedalusAugsRequirement !== defaultMultipliers.DaedalusAugsRequirement ? (
|
||||
<Typography>Daedalus aug req.: {mults.DaedalusAugsRequirement}</Typography>
|
||||
) : (
|
||||
<></>
|
||||
)}
|
||||
{mults.HacknetNodeMoney !== defaultMultipliers.HacknetNodeMoney ? (
|
||||
<Typography>Hacknet production: x{mults.HacknetNodeMoney.toFixed(3)}</Typography>
|
||||
) : (
|
||||
<></>
|
||||
)}
|
||||
{mults.CodingContractMoney !== defaultMultipliers.CodingContractMoney ? (
|
||||
<Typography>Coding contract reward: x{mults.CodingContractMoney.toFixed(3)}</Typography>
|
||||
) : (
|
||||
<></>
|
||||
)}
|
||||
{mults.ClassGymExpGain !== defaultMultipliers.ClassGymExpGain ? (
|
||||
<Typography>Class/Gym exp: x{mults.ClassGymExpGain.toFixed(3)}</Typography>
|
||||
) : (
|
||||
<></>
|
||||
)}
|
||||
</Box>
|
||||
</>
|
||||
);
|
||||
const rows: IBNMultRows = {
|
||||
WorldDaemonDifficulty: { name: `${SpecialServers.WorldDaemon} Difficulty` },
|
||||
DaedalusAugsRequirement: {
|
||||
name: "Daedalus Augs Requirement",
|
||||
content: String(mults.DaedalusAugsRequirement),
|
||||
},
|
||||
HacknetNodeMoney: { name: "Hacknet Production" },
|
||||
CodingContractMoney: { name: "Coding Contract Reward" },
|
||||
ClassGymExpGain: { name: "Class/Gym Exp" },
|
||||
};
|
||||
|
||||
return <BNMultTable sectionName="General" rowData={rows} mults={mults} />;
|
||||
}
|
||||
|
||||
function AugmentationMults({ mults }: IMultsProps): React.ReactElement {
|
||||
// is it empty check
|
||||
if (
|
||||
mults.AugmentationMoneyCost === defaultMultipliers.AugmentationMoneyCost &&
|
||||
mults.AugmentationRepCost === defaultMultipliers.AugmentationRepCost
|
||||
)
|
||||
return <></>;
|
||||
return (
|
||||
<>
|
||||
<br />
|
||||
<Typography variant={"h5"}>Augmentations:</Typography>
|
||||
<Box mx={1}>
|
||||
{mults.AugmentationMoneyCost !== defaultMultipliers.AugmentationMoneyCost ? (
|
||||
<Typography>Cost: x{mults.AugmentationMoneyCost.toFixed(3)}</Typography>
|
||||
) : (
|
||||
<></>
|
||||
)}
|
||||
{mults.AugmentationRepCost !== defaultMultipliers.AugmentationRepCost ? (
|
||||
<Typography>Reputation: x{mults.AugmentationRepCost.toFixed(3)}</Typography>
|
||||
) : (
|
||||
<></>
|
||||
)}
|
||||
</Box>
|
||||
</>
|
||||
);
|
||||
const rows: IBNMultRows = {
|
||||
AugmentationMoneyCost: { name: "Money Cost" },
|
||||
AugmentationRepCost: {
|
||||
name: "Reputation Cost",
|
||||
color: Settings.theme.rep,
|
||||
},
|
||||
};
|
||||
|
||||
return <BNMultTable sectionName="Augmentations" rowData={rows} mults={mults} />;
|
||||
}
|
||||
|
||||
function CompanyMults({ mults }: IMultsProps): React.ReactElement {
|
||||
// is it empty check
|
||||
if (
|
||||
mults.CompanyWorkExpGain === defaultMultipliers.CompanyWorkExpGain &&
|
||||
mults.CompanyWorkMoney === defaultMultipliers.CompanyWorkMoney
|
||||
)
|
||||
return <></>;
|
||||
return (
|
||||
<>
|
||||
<br />
|
||||
<Typography variant={"h5"}>Company:</Typography>
|
||||
<Box mx={1}>
|
||||
{mults.CompanyWorkMoney !== defaultMultipliers.CompanyWorkMoney ? (
|
||||
<Typography>Money: x{mults.CompanyWorkMoney.toFixed(3)}</Typography>
|
||||
) : (
|
||||
<></>
|
||||
)}
|
||||
{mults.CompanyWorkExpGain !== defaultMultipliers.CompanyWorkExpGain ? (
|
||||
<Typography>Exp: x{mults.CompanyWorkExpGain.toFixed(3)}</Typography>
|
||||
) : (
|
||||
<></>
|
||||
)}
|
||||
</Box>
|
||||
</>
|
||||
);
|
||||
const rows: IBNMultRows = {
|
||||
CompanyWorkMoney: {
|
||||
name: "Work Money",
|
||||
color: Settings.theme.money,
|
||||
},
|
||||
CompanyWorkExpGain: { name: "Work Exp" },
|
||||
};
|
||||
|
||||
return <BNMultTable sectionName="Company" rowData={rows} mults={mults} />;
|
||||
}
|
||||
|
||||
function StockMults({ mults }: IMultsProps): React.ReactElement {
|
||||
// is it empty check
|
||||
if (
|
||||
mults.FourSigmaMarketDataApiCost === defaultMultipliers.FourSigmaMarketDataApiCost &&
|
||||
mults.FourSigmaMarketDataCost === defaultMultipliers.FourSigmaMarketDataCost
|
||||
)
|
||||
return <></>;
|
||||
return (
|
||||
<>
|
||||
<br />
|
||||
<Typography variant={"h5"}>Stock market:</Typography>
|
||||
<Box mx={1}>
|
||||
{mults.FourSigmaMarketDataCost !== defaultMultipliers.FourSigmaMarketDataCost ? (
|
||||
<Typography>Market data cost: x{mults.FourSigmaMarketDataCost.toFixed(3)}</Typography>
|
||||
) : (
|
||||
<></>
|
||||
)}
|
||||
{mults.FourSigmaMarketDataApiCost !== defaultMultipliers.FourSigmaMarketDataApiCost ? (
|
||||
<Typography>Market data API cost: x{mults.FourSigmaMarketDataApiCost.toFixed(3)}</Typography>
|
||||
) : (
|
||||
<></>
|
||||
)}
|
||||
</Box>
|
||||
</>
|
||||
);
|
||||
const rows: IBNMultRows = {
|
||||
FourSigmaMarketDataCost: { name: "Market Data Cost" },
|
||||
FourSigmaMarketDataApiCost: { name: "Market Data API Cost" },
|
||||
};
|
||||
|
||||
return <BNMultTable sectionName="Stock Market" rowData={rows} mults={mults} />;
|
||||
}
|
||||
|
||||
function FactionMults({ mults }: IMultsProps): React.ReactElement {
|
||||
// is it empty check
|
||||
if (
|
||||
mults.FactionPassiveRepGain === defaultMultipliers.FactionPassiveRepGain &&
|
||||
mults.FactionWorkExpGain === defaultMultipliers.FactionWorkExpGain &&
|
||||
mults.FactionWorkRepGain === defaultMultipliers.FactionWorkRepGain &&
|
||||
mults.RepToDonateToFaction === defaultMultipliers.RepToDonateToFaction
|
||||
)
|
||||
return <></>;
|
||||
return (
|
||||
<>
|
||||
<br />
|
||||
<Typography variant={"h5"}>Faction:</Typography>
|
||||
<Box mx={1}>
|
||||
{mults.RepToDonateToFaction !== defaultMultipliers.RepToDonateToFaction ? (
|
||||
<Typography>Favor to donate: x{mults.RepToDonateToFaction.toFixed(3)}</Typography>
|
||||
) : (
|
||||
<></>
|
||||
)}
|
||||
{mults.FactionWorkRepGain !== defaultMultipliers.FactionWorkRepGain ? (
|
||||
<Typography>Work rep: x{mults.FactionWorkRepGain.toFixed(3)}</Typography>
|
||||
) : (
|
||||
<></>
|
||||
)}
|
||||
{mults.FactionWorkExpGain !== defaultMultipliers.FactionWorkExpGain ? (
|
||||
<Typography>Work exp: x{mults.FactionWorkExpGain.toFixed(3)}</Typography>
|
||||
) : (
|
||||
<></>
|
||||
)}
|
||||
{mults.FactionPassiveRepGain !== defaultMultipliers.FactionPassiveRepGain ? (
|
||||
<Typography>Passive rep: x{mults.FactionPassiveRepGain.toFixed(3)}</Typography>
|
||||
) : (
|
||||
<></>
|
||||
)}
|
||||
</Box>
|
||||
</>
|
||||
);
|
||||
const rows: IBNMultRows = {
|
||||
RepToDonateToFaction: { name: "Favor to Donate" },
|
||||
FactionWorkRepGain: {
|
||||
name: "Work Reputation",
|
||||
color: Settings.theme.rep,
|
||||
},
|
||||
FactionWorkExpGain: { name: "Work Exp" },
|
||||
FactionPassiveRepGain: {
|
||||
name: "Passive Rep",
|
||||
color: Settings.theme.rep,
|
||||
},
|
||||
};
|
||||
|
||||
return <BNMultTable sectionName="Faction" rowData={rows} mults={mults} />;
|
||||
}
|
||||
|
||||
function CrimeMults({ mults }: IMultsProps): React.ReactElement {
|
||||
// is it empty check
|
||||
if (mults.CrimeExpGain === defaultMultipliers.CrimeExpGain && mults.CrimeMoney === defaultMultipliers.CrimeMoney)
|
||||
return <></>;
|
||||
return (
|
||||
<>
|
||||
<br />
|
||||
<Typography variant={"h5"}>Crime:</Typography>
|
||||
<Box mx={1}>
|
||||
{mults.CrimeExpGain !== defaultMultipliers.CrimeExpGain ? (
|
||||
<Typography>Exp: x{mults.CrimeExpGain.toFixed(3)}</Typography>
|
||||
) : (
|
||||
<></>
|
||||
)}
|
||||
{mults.CrimeMoney !== defaultMultipliers.CrimeMoney ? (
|
||||
<Typography>Money: x{mults.CrimeMoney.toFixed(3)}</Typography>
|
||||
) : (
|
||||
<></>
|
||||
)}
|
||||
</Box>
|
||||
</>
|
||||
);
|
||||
const rows: IBNMultRows = {
|
||||
CrimeExpGain: {
|
||||
name: "Crime Exp",
|
||||
color: Settings.theme.combat,
|
||||
},
|
||||
CrimeMoney: {
|
||||
name: "Crime Money",
|
||||
color: Settings.theme.combat,
|
||||
},
|
||||
};
|
||||
|
||||
return <BNMultTable sectionName="Crime" rowData={rows} mults={mults} />;
|
||||
}
|
||||
|
||||
function SkillMults({ mults }: IMultsProps): React.ReactElement {
|
||||
// is it empty check
|
||||
if (
|
||||
mults.HackingLevelMultiplier === defaultMultipliers.HackingLevelMultiplier &&
|
||||
mults.AgilityLevelMultiplier === defaultMultipliers.AgilityLevelMultiplier &&
|
||||
mults.DefenseLevelMultiplier === defaultMultipliers.DefenseLevelMultiplier &&
|
||||
mults.DexterityLevelMultiplier === defaultMultipliers.DexterityLevelMultiplier &&
|
||||
mults.StrengthLevelMultiplier === defaultMultipliers.StrengthLevelMultiplier &&
|
||||
mults.CharismaLevelMultiplier === defaultMultipliers.CharismaLevelMultiplier
|
||||
)
|
||||
return <></>;
|
||||
return (
|
||||
<>
|
||||
<br />
|
||||
<Typography variant={"h5"}>Skills:</Typography>
|
||||
<Box mx={1}>
|
||||
{mults.HackingLevelMultiplier !== defaultMultipliers.HackingLevelMultiplier ? (
|
||||
<Typography>Hacking: x{mults.HackingLevelMultiplier.toFixed(3)}</Typography>
|
||||
) : (
|
||||
<></>
|
||||
)}
|
||||
{mults.AgilityLevelMultiplier !== defaultMultipliers.AgilityLevelMultiplier ? (
|
||||
<Typography>Agility: x{mults.AgilityLevelMultiplier.toFixed(3)}</Typography>
|
||||
) : (
|
||||
<></>
|
||||
)}
|
||||
{mults.DefenseLevelMultiplier !== defaultMultipliers.DefenseLevelMultiplier ? (
|
||||
<Typography>Defense: x{mults.DefenseLevelMultiplier.toFixed(3)}</Typography>
|
||||
) : (
|
||||
<></>
|
||||
)}
|
||||
{mults.DexterityLevelMultiplier !== defaultMultipliers.DexterityLevelMultiplier ? (
|
||||
<Typography>Dexterity: x{mults.DexterityLevelMultiplier.toFixed(3)}</Typography>
|
||||
) : (
|
||||
<></>
|
||||
)}
|
||||
{mults.StrengthLevelMultiplier !== defaultMultipliers.StrengthLevelMultiplier ? (
|
||||
<Typography>Strength: x{mults.StrengthLevelMultiplier.toFixed(3)}</Typography>
|
||||
) : (
|
||||
<></>
|
||||
)}
|
||||
{mults.CharismaLevelMultiplier !== defaultMultipliers.CharismaLevelMultiplier ? (
|
||||
<Typography>Charisma: x{mults.CharismaLevelMultiplier.toFixed(3)}</Typography>
|
||||
) : (
|
||||
<></>
|
||||
)}
|
||||
</Box>
|
||||
</>
|
||||
);
|
||||
const rows: IBNMultRows = {
|
||||
HackingLevelMultiplier: {
|
||||
name: "Hacking Level",
|
||||
color: Settings.theme.hack,
|
||||
},
|
||||
StrengthLevelMultiplier: {
|
||||
name: "Strength Level",
|
||||
color: Settings.theme.combat,
|
||||
},
|
||||
DefenseLevelMultiplier: {
|
||||
name: "Defense Level",
|
||||
color: Settings.theme.combat,
|
||||
},
|
||||
DexterityLevelMultiplier: {
|
||||
name: "Dexterity Level",
|
||||
color: Settings.theme.combat,
|
||||
},
|
||||
AgilityLevelMultiplier: {
|
||||
name: "Agility Level",
|
||||
color: Settings.theme.combat,
|
||||
},
|
||||
CharismaLevelMultiplier: {
|
||||
name: "Charisma Level",
|
||||
color: Settings.theme.cha,
|
||||
},
|
||||
};
|
||||
|
||||
return <BNMultTable sectionName="Skills" rowData={rows} mults={mults} />;
|
||||
}
|
||||
|
||||
function HackingMults({ mults }: IMultsProps): React.ReactElement {
|
||||
// is it empty check
|
||||
if (
|
||||
mults.ServerGrowthRate === defaultMultipliers.ServerGrowthRate &&
|
||||
mults.ServerMaxMoney === defaultMultipliers.ServerMaxMoney &&
|
||||
mults.ServerStartingMoney === defaultMultipliers.ServerStartingMoney &&
|
||||
mults.ServerStartingSecurity === defaultMultipliers.ServerStartingSecurity &&
|
||||
mults.ServerWeakenRate === defaultMultipliers.ServerWeakenRate &&
|
||||
mults.ManualHackMoney === defaultMultipliers.ManualHackMoney &&
|
||||
mults.ScriptHackMoney === defaultMultipliers.ScriptHackMoney &&
|
||||
mults.ScriptHackMoneyGain === defaultMultipliers.ScriptHackMoneyGain &&
|
||||
mults.HackExpGain === defaultMultipliers.HackExpGain
|
||||
)
|
||||
return <></>;
|
||||
const rows: IBNMultRows = {
|
||||
HackExpGain: {
|
||||
name: "Hacking Exp",
|
||||
color: Settings.theme.hack,
|
||||
},
|
||||
ServerGrowthRate: { name: "Server Growth Rate" },
|
||||
ServerMaxMoney: { name: "Server Max Money" },
|
||||
ServerStartingMoney: { name: "Server Starting Money" },
|
||||
ServerStartingSecurity: { name: "Server Starting Security" },
|
||||
ServerWeakenRate: { name: "Server Weaken Rate" },
|
||||
ManualHackMoney: {
|
||||
name: "Manual Hack Money",
|
||||
color: Settings.theme.money,
|
||||
},
|
||||
ScriptHackMoney: {
|
||||
name: "Script Hack Money",
|
||||
color: Settings.theme.money,
|
||||
},
|
||||
ScriptHackMoneyGain: {
|
||||
name: "Money Gained From Hack",
|
||||
color: Settings.theme.money,
|
||||
},
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<br />
|
||||
<Typography variant={"h5"}>Hacking:</Typography>
|
||||
<Box mx={1}>
|
||||
{mults.HackExpGain !== defaultMultipliers.HackExpGain ? (
|
||||
<Typography>Exp: x{mults.HackExpGain.toFixed(3)}</Typography>
|
||||
) : (
|
||||
<></>
|
||||
)}
|
||||
{mults.ServerGrowthRate !== defaultMultipliers.ServerGrowthRate ? (
|
||||
<Typography>Growth rate: x{mults.ServerGrowthRate.toFixed(3)}</Typography>
|
||||
) : (
|
||||
<></>
|
||||
)}
|
||||
{mults.ServerMaxMoney !== defaultMultipliers.ServerMaxMoney ? (
|
||||
<Typography>Max money: x{mults.ServerMaxMoney.toFixed(3)}</Typography>
|
||||
) : (
|
||||
<></>
|
||||
)}
|
||||
{mults.ServerStartingMoney !== defaultMultipliers.ServerStartingMoney ? (
|
||||
<Typography>Starting money: x{mults.ServerStartingMoney.toFixed(3)}</Typography>
|
||||
) : (
|
||||
<></>
|
||||
)}
|
||||
{mults.ServerStartingSecurity !== defaultMultipliers.ServerStartingSecurity ? (
|
||||
<Typography>Starting security: x{mults.ServerStartingSecurity.toFixed(3)}</Typography>
|
||||
) : (
|
||||
<></>
|
||||
)}
|
||||
{mults.ServerWeakenRate !== defaultMultipliers.ServerWeakenRate ? (
|
||||
<Typography>Weaken rate: x{mults.ServerWeakenRate.toFixed(3)}</Typography>
|
||||
) : (
|
||||
<></>
|
||||
)}
|
||||
{mults.ManualHackMoney !== defaultMultipliers.ManualHackMoney ? (
|
||||
<Typography>Manual hack money: x{mults.ManualHackMoney.toFixed(3)}</Typography>
|
||||
) : (
|
||||
<></>
|
||||
)}
|
||||
{mults.ScriptHackMoney !== defaultMultipliers.ScriptHackMoney ? (
|
||||
<Typography>Hack money stolen: x{mults.ScriptHackMoney.toFixed(3)}</Typography>
|
||||
) : (
|
||||
<></>
|
||||
)}
|
||||
{mults.ScriptHackMoneyGain !== defaultMultipliers.ScriptHackMoneyGain ? (
|
||||
<Typography>Money gained from hack: x{mults.ScriptHackMoneyGain.toFixed(3)}</Typography>
|
||||
) : (
|
||||
<></>
|
||||
)}
|
||||
</Box>
|
||||
</>
|
||||
);
|
||||
return <BNMultTable sectionName="Hacking" rowData={rows} mults={mults} />;
|
||||
}
|
||||
|
||||
function PurchasedServersMults({ mults }: IMultsProps): React.ReactElement {
|
||||
// is it empty check
|
||||
if (
|
||||
mults.PurchasedServerCost === defaultMultipliers.PurchasedServerCost &&
|
||||
mults.PurchasedServerSoftcap === defaultMultipliers.PurchasedServerSoftcap &&
|
||||
mults.PurchasedServerLimit === defaultMultipliers.PurchasedServerLimit &&
|
||||
mults.PurchasedServerMaxRam === defaultMultipliers.PurchasedServerMaxRam &&
|
||||
mults.HomeComputerRamCost === defaultMultipliers.HomeComputerRamCost
|
||||
)
|
||||
return <></>;
|
||||
return (
|
||||
<>
|
||||
<br />
|
||||
<Typography variant={"h5"}>Purchased servers:</Typography>
|
||||
<Box mx={1}>
|
||||
{mults.PurchasedServerCost !== defaultMultipliers.PurchasedServerCost ? (
|
||||
<Typography>Base cost: {mults.PurchasedServerCost.toFixed(3)}</Typography>
|
||||
) : (
|
||||
<></>
|
||||
)}
|
||||
{mults.PurchasedServerSoftcap !== defaultMultipliers.PurchasedServerSoftcap ? (
|
||||
<Typography>Softcap cost: {mults.PurchasedServerSoftcap.toFixed(3)}</Typography>
|
||||
) : (
|
||||
<></>
|
||||
)}
|
||||
{mults.PurchasedServerLimit !== defaultMultipliers.PurchasedServerLimit ? (
|
||||
<Typography>Limit: x{mults.PurchasedServerLimit.toFixed(3)}</Typography>
|
||||
) : (
|
||||
<></>
|
||||
)}
|
||||
{mults.PurchasedServerMaxRam !== defaultMultipliers.PurchasedServerMaxRam ? (
|
||||
<Typography>Max ram: x{mults.PurchasedServerMaxRam.toFixed(3)}</Typography>
|
||||
) : (
|
||||
<></>
|
||||
)}
|
||||
{mults.HomeComputerRamCost !== defaultMultipliers.HomeComputerRamCost ? (
|
||||
<Typography>Home ram cost: x{mults.HomeComputerRamCost.toFixed(3)}</Typography>
|
||||
) : (
|
||||
<></>
|
||||
)}
|
||||
</Box>
|
||||
</>
|
||||
);
|
||||
const rows: IBNMultRows = {
|
||||
PurchasedServerCost: {
|
||||
name: "Base Cost",
|
||||
content: mults.PurchasedServerCost.toFixed(3),
|
||||
},
|
||||
PurchasedServerSoftcap: {
|
||||
name: "Softcap Cost",
|
||||
content: mults.PurchasedServerSoftcap.toFixed(3),
|
||||
},
|
||||
PurchasedServerLimit: { name: "Server Limit" },
|
||||
PurchasedServerMaxRam: { name: "Max RAM" },
|
||||
HomeComputerRamCost: { name: "Home RAM Cost" },
|
||||
};
|
||||
|
||||
return <BNMultTable sectionName="Purchased Servers" rowData={rows} mults={mults} />;
|
||||
}
|
||||
|
||||
function InfiltrationMults({ mults }: IMultsProps): React.ReactElement {
|
||||
// is it empty check
|
||||
if (
|
||||
mults.InfiltrationMoney === defaultMultipliers.InfiltrationMoney &&
|
||||
mults.InfiltrationRep === defaultMultipliers.InfiltrationRep
|
||||
)
|
||||
return <></>;
|
||||
return (
|
||||
<>
|
||||
<br />
|
||||
<Typography variant={"h5"}>Infiltration:</Typography>
|
||||
<Box mx={1}>
|
||||
{mults.InfiltrationMoney !== defaultMultipliers.InfiltrationMoney ? (
|
||||
<Typography>Money: {mults.InfiltrationMoney.toFixed(3)}</Typography>
|
||||
) : (
|
||||
<></>
|
||||
)}
|
||||
{mults.InfiltrationRep !== defaultMultipliers.InfiltrationRep ? (
|
||||
<Typography>Reputation: x{mults.InfiltrationRep.toFixed(3)}</Typography>
|
||||
) : (
|
||||
<></>
|
||||
)}
|
||||
</Box>
|
||||
</>
|
||||
);
|
||||
const rows: IBNMultRows = {
|
||||
InfiltrationMoney: {
|
||||
name: "Infiltration Money",
|
||||
color: Settings.theme.money,
|
||||
},
|
||||
InfiltrationRep: {
|
||||
name: "Infiltration Reputation",
|
||||
color: Settings.theme.rep,
|
||||
},
|
||||
};
|
||||
|
||||
return <BNMultTable sectionName="Infiltration" rowData={rows} mults={mults} />;
|
||||
}
|
||||
|
||||
function BladeburnerMults({ n, mults }: IMultsProps): React.ReactElement {
|
||||
function BladeburnerMults({ mults }: IMultsProps): React.ReactElement {
|
||||
const player = use.Player();
|
||||
// access check
|
||||
if (n !== 6 && n !== 7 && player.sourceFileLvl(6) === 0) return <></>;
|
||||
//default mults check
|
||||
if (mults.BladeburnerRank === 1 && mults.BladeburnerSkillCost === 1) return <></>;
|
||||
return (
|
||||
<>
|
||||
<br />
|
||||
<Typography variant={"h5"}>Bladeburner:</Typography>
|
||||
<Box mx={1}>
|
||||
{mults.BladeburnerRank !== 1 ? <Typography>Rank gain: x{mults.BladeburnerRank.toFixed(3)}</Typography> : <></>}
|
||||
{mults.BladeburnerSkillCost !== 1 ? (
|
||||
<Typography>Skill cost: x{mults.BladeburnerSkillCost.toFixed(3)}</Typography>
|
||||
) : (
|
||||
<></>
|
||||
)}
|
||||
</Box>
|
||||
</>
|
||||
);
|
||||
if (!player.canAccessBladeburner()) return <></>;
|
||||
|
||||
const rows: IBNMultRows = {
|
||||
BladeburnerRank: { name: "Rank Gain" },
|
||||
BladeburnerSkillCost: { name: "Skill Cost" },
|
||||
};
|
||||
|
||||
return <BNMultTable sectionName="Bladeburner" rowData={rows} mults={mults} />;
|
||||
}
|
||||
|
||||
function StanekMults({ n, mults }: IMultsProps): React.ReactElement {
|
||||
function StanekMults({ mults }: IMultsProps): React.ReactElement {
|
||||
const player = use.Player();
|
||||
// access check
|
||||
if (n !== 13 && player.sourceFileLvl(13) === 0) return <></>;
|
||||
//default mults check
|
||||
if (
|
||||
mults.StaneksGiftExtraSize === defaultMultipliers.StaneksGiftExtraSize &&
|
||||
mults.StaneksGiftPowerMultiplier === defaultMultipliers.StaneksGiftPowerMultiplier
|
||||
)
|
||||
return <></>;
|
||||
if (!player.canAccessCotMG()) return <></>;
|
||||
|
||||
const s = mults.StaneksGiftExtraSize;
|
||||
return (
|
||||
<>
|
||||
<br />
|
||||
<Typography variant={"h5"}>Stanek's Gift:</Typography>
|
||||
<Box mx={1}>
|
||||
{mults.StaneksGiftPowerMultiplier !== defaultMultipliers.StaneksGiftPowerMultiplier ? (
|
||||
<Typography>Gift power: x{mults.StaneksGiftPowerMultiplier.toFixed(3)}</Typography>
|
||||
) : (
|
||||
<></>
|
||||
)}
|
||||
{s !== defaultMultipliers.StaneksGiftExtraSize ? (
|
||||
<Typography>Base size modifier: {s > defaultMultipliers.StaneksGiftExtraSize ? `+${s}` : s}</Typography>
|
||||
) : (
|
||||
<></>
|
||||
)}
|
||||
</Box>
|
||||
</>
|
||||
);
|
||||
const extraSize = mults.StaneksGiftExtraSize.toFixed(3);
|
||||
const rows: IBNMultRows = {
|
||||
StnakesGiftPowerMultiplier: { name: "Gift Power" },
|
||||
StaneksGiftExtraSize: {
|
||||
name: "Base Size Modifier",
|
||||
content: `${mults.StaneksGiftExtraSize > defaultMultipliers.StaneksGiftExtraSize ? `+${extraSize}` : extraSize}`,
|
||||
},
|
||||
};
|
||||
|
||||
return <BNMultTable sectionName="Stanek's Gift" rowData={rows} mults={mults} />;
|
||||
}
|
||||
|
||||
function GangMults({ n, mults }: IMultsProps): React.ReactElement {
|
||||
function GangMults({ mults }: IMultsProps): React.ReactElement {
|
||||
const player = use.Player();
|
||||
// access check
|
||||
if (n !== 2 && player.sourceFileLvl(2) === 0) return <></>;
|
||||
// is it empty check
|
||||
if (
|
||||
mults.GangSoftcap === defaultMultipliers.GangSoftcap &&
|
||||
mults.GangUniqueAugs === defaultMultipliers.GangUniqueAugs
|
||||
)
|
||||
return <></>;
|
||||
return (
|
||||
<>
|
||||
<br />
|
||||
<Typography variant={"h5"}>Gang:</Typography>
|
||||
<Box mx={1}>
|
||||
{mults.GangSoftcap !== defaultMultipliers.GangSoftcap ? (
|
||||
<Typography>Softcap: {mults.GangSoftcap.toFixed(3)}</Typography>
|
||||
) : (
|
||||
<></>
|
||||
)}
|
||||
{mults.GangUniqueAugs !== defaultMultipliers.GangUniqueAugs ? (
|
||||
<Typography>Unique augs: x{mults.GangUniqueAugs.toFixed(3)}</Typography>
|
||||
) : (
|
||||
<></>
|
||||
)}
|
||||
</Box>
|
||||
</>
|
||||
);
|
||||
if (player.bitNodeN !== 2 && player.sourceFileLvl(2) <= 0) return <></>;
|
||||
|
||||
const rows: IBNMultRows = {
|
||||
GangSoftcap: {
|
||||
name: "Gang Softcap",
|
||||
content: mults.GangSoftcap.toFixed(3),
|
||||
},
|
||||
GangUniqueAugs: { name: "Unique Augmentations" },
|
||||
};
|
||||
|
||||
return <BNMultTable sectionName="Gang" rowData={rows} mults={mults} />;
|
||||
}
|
||||
|
||||
function CorporationMults({ n, mults }: IMultsProps): React.ReactElement {
|
||||
function CorporationMults({ mults }: IMultsProps): React.ReactElement {
|
||||
const player = use.Player();
|
||||
// access check
|
||||
if (n !== 3 && player.sourceFileLvl(3) === 0) return <></>;
|
||||
// is it empty check
|
||||
if (
|
||||
mults.CorporationSoftCap === defaultMultipliers.CorporationSoftCap &&
|
||||
mults.CorporationValuation === defaultMultipliers.CorporationValuation
|
||||
)
|
||||
return <></>;
|
||||
if (!player.canAccessCorporation()) return <></>;
|
||||
|
||||
return (
|
||||
<>
|
||||
<br />
|
||||
<Typography variant={"h5"}>Corporation:</Typography>
|
||||
<Box mx={1}>
|
||||
{mults.CorporationSoftCap !== defaultMultipliers.CorporationSoftCap ? (
|
||||
<Typography>Softcap: {mults.CorporationSoftCap.toFixed(3)}</Typography>
|
||||
) : (
|
||||
<></>
|
||||
)}
|
||||
{mults.CorporationValuation !== defaultMultipliers.CorporationValuation ? (
|
||||
<Typography>Valuation: x{mults.CorporationValuation.toFixed(3)}</Typography>
|
||||
) : (
|
||||
<></>
|
||||
)}
|
||||
</Box>
|
||||
</>
|
||||
);
|
||||
const rows: IBNMultRows = {
|
||||
CorporationSoftcap: {
|
||||
name: "Corporation Softcap",
|
||||
content: mults.CorporationSoftcap.toFixed(3),
|
||||
},
|
||||
CorporationValuation: { name: "Valuation" },
|
||||
};
|
||||
|
||||
return <BNMultTable sectionName="Corporation" rowData={rows} mults={mults} />;
|
||||
}
|
||||
|
@ -41,7 +41,7 @@ export function PortalModal(props: IProps): React.ReactElement {
|
||||
<br />
|
||||
<br />
|
||||
<Typography>{bitNode.info}</Typography>
|
||||
<BitnodeMultiplierDescription n={props.n} />
|
||||
<BitnodeMultiplierDescription n={props.n} level={newLevel} />
|
||||
<br />
|
||||
<br />
|
||||
<Button
|
||||
|
@ -697,7 +697,7 @@ export class Bladeburner implements IBladeburner {
|
||||
|
||||
// Set variables
|
||||
if (args.length === 4) {
|
||||
const variable = args[1];
|
||||
const variable = args[1].toLowerCase(); // allows Action Type to be with or without capitalisation.
|
||||
const val = args[2];
|
||||
|
||||
let highLow = false; // True for high, false for low
|
||||
@ -1919,7 +1919,7 @@ export class Bladeburner implements IBladeburner {
|
||||
}
|
||||
|
||||
// If the Player starts doing some other actions, set action to idle and alert
|
||||
if (player.hasAugmentation(AugmentationNames.BladesSimulacrum) === false && player.isWorking) {
|
||||
if (!player.hasAugmentation(AugmentationNames.BladesSimulacrum, true) && player.isWorking) {
|
||||
if (this.action.type !== ActionTypes["Idle"]) {
|
||||
let msg = "Your Bladeburner action was cancelled because you started doing something else.";
|
||||
if (this.automateEnabled) {
|
||||
|
@ -84,6 +84,7 @@ export const CONSTANTS: {
|
||||
SoARepMult: number;
|
||||
EntropyEffect: number;
|
||||
TotalNumBitNodes: number;
|
||||
InfiniteLoopLimit: number;
|
||||
Donations: number; // number of blood/plasma/palette donation the dev have verified., boosts NFG
|
||||
LatestUpdate: string;
|
||||
} = {
|
||||
@ -226,6 +227,8 @@ export const CONSTANTS: {
|
||||
// BitNode/Source-File related stuff
|
||||
TotalNumBitNodes: 24,
|
||||
|
||||
InfiniteLoopLimit: 1000,
|
||||
|
||||
Donations: 7,
|
||||
|
||||
LatestUpdate: `
|
||||
|
@ -159,7 +159,7 @@ export class Corporation {
|
||||
if (this.unlockUpgrades[6] === 1) {
|
||||
upgrades += 0.1;
|
||||
}
|
||||
return Math.pow(dividends, BitNodeMultipliers.CorporationSoftCap + upgrades);
|
||||
return Math.pow(dividends, BitNodeMultipliers.CorporationSoftcap + upgrades);
|
||||
}
|
||||
|
||||
determineValuation(): number {
|
||||
|
@ -68,13 +68,7 @@ export class ActiveFragment {
|
||||
}
|
||||
|
||||
copy(): ActiveFragment {
|
||||
// We have to do a round trip because the constructor.
|
||||
const fragment = FragmentById(this.id);
|
||||
if (fragment === null) throw new Error("ActiveFragment id refers to unknown Fragment.");
|
||||
const c = new ActiveFragment({ x: this.x, y: this.y, rotation: this.rotation, fragment: fragment });
|
||||
c.highestCharge = this.highestCharge;
|
||||
c.numCharge = this.numCharge;
|
||||
return c;
|
||||
return Object.assign({}, this);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -76,13 +76,7 @@ export class Fragment {
|
||||
}
|
||||
|
||||
copy(): Fragment {
|
||||
return new Fragment(
|
||||
this.id,
|
||||
this.shape.map((a) => a.slice()),
|
||||
this.type,
|
||||
this.power,
|
||||
this.limit,
|
||||
);
|
||||
return Object.assign({}, this);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -136,8 +136,9 @@ export class StaneksGift implements IStaneksGift {
|
||||
}
|
||||
|
||||
updateMults(p: IPlayer): void {
|
||||
p.reapplyAllAugmentations(true);
|
||||
p.reapplyAllSourceFiles();
|
||||
// applyEntropy also reapplies all augmentations and source files
|
||||
// This wraps up the reset nicely
|
||||
p.applyEntropy(p.entropy);
|
||||
|
||||
for (const aFrag of this.fragments) {
|
||||
const fragment = aFrag.fragment();
|
||||
|
@ -70,7 +70,7 @@ export const CurrentOptionsPage = (props: IProps): React.ReactElement => {
|
||||
<>
|
||||
<OptionsSlider
|
||||
label=".script exec time (ms)"
|
||||
value={execTime}
|
||||
initialValue={execTime}
|
||||
callback={handleExecTimeChange}
|
||||
step={1}
|
||||
min={5}
|
||||
@ -84,7 +84,7 @@ export const CurrentOptionsPage = (props: IProps): React.ReactElement => {
|
||||
/>
|
||||
<OptionsSlider
|
||||
label="Recently killed scripts size"
|
||||
value={recentScriptsSize}
|
||||
initialValue={recentScriptsSize}
|
||||
callback={handleRecentScriptsSizeChange}
|
||||
step={25}
|
||||
min={0}
|
||||
@ -98,7 +98,7 @@ export const CurrentOptionsPage = (props: IProps): React.ReactElement => {
|
||||
/>
|
||||
<OptionsSlider
|
||||
label="Netscript log size"
|
||||
value={logSize}
|
||||
initialValue={logSize}
|
||||
callback={handleLogSizeChange}
|
||||
step={20}
|
||||
min={20}
|
||||
@ -112,7 +112,7 @@ export const CurrentOptionsPage = (props: IProps): React.ReactElement => {
|
||||
/>
|
||||
<OptionsSlider
|
||||
label="Netscript port size"
|
||||
value={portSize}
|
||||
initialValue={portSize}
|
||||
callback={handlePortSizeChange}
|
||||
step={1}
|
||||
min={20}
|
||||
@ -126,7 +126,7 @@ export const CurrentOptionsPage = (props: IProps): React.ReactElement => {
|
||||
/>
|
||||
<OptionsSlider
|
||||
label="Terminal capacity"
|
||||
value={terminalSize}
|
||||
initialValue={terminalSize}
|
||||
callback={handleTerminalSizeChange}
|
||||
step={50}
|
||||
min={50}
|
||||
@ -141,7 +141,7 @@ export const CurrentOptionsPage = (props: IProps): React.ReactElement => {
|
||||
/>
|
||||
<OptionsSlider
|
||||
label="Autosave interval (s)"
|
||||
value={autosaveInterval}
|
||||
initialValue={autosaveInterval}
|
||||
callback={handleAutosaveIntervalChange}
|
||||
step={30}
|
||||
min={0}
|
||||
@ -179,6 +179,12 @@ export const CurrentOptionsPage = (props: IProps): React.ReactElement => {
|
||||
</>
|
||||
}
|
||||
/>
|
||||
<OptionSwitch
|
||||
checked={Settings.InfinityLoopSafety}
|
||||
onChange={(newValue) => (Settings.InfinityLoopSafety = newValue)}
|
||||
text="Script infinite loop safety net"
|
||||
tooltip={<>If this is set the game will attempt to automatically kill scripts stuck in infinite loops.</>}
|
||||
/>
|
||||
</GameOptionsPage>
|
||||
),
|
||||
[GameOptionsTab.INTERFACE]: (
|
||||
|
@ -1,8 +1,8 @@
|
||||
import { Slider, Tooltip, Typography, Box } from "@mui/material";
|
||||
import React from "react";
|
||||
import React, { useState } from "react";
|
||||
|
||||
interface IProps {
|
||||
value: any;
|
||||
initialValue: any;
|
||||
callback: (event: any, newValue: number | number[]) => void;
|
||||
step: number;
|
||||
min: number;
|
||||
@ -13,14 +13,21 @@ interface IProps {
|
||||
}
|
||||
|
||||
export const OptionsSlider = (props: IProps): React.ReactElement => {
|
||||
const [value, setValue] = useState(props.initialValue);
|
||||
|
||||
const onChange = (_evt: Event, newValue: number | Array<number>): void => {
|
||||
setValue(newValue);
|
||||
};
|
||||
|
||||
return (
|
||||
<Box>
|
||||
<Tooltip title={<Typography>{props.tooltip}</Typography>}>
|
||||
<Typography>{props.label}</Typography>
|
||||
</Tooltip>
|
||||
<Slider
|
||||
value={props.value}
|
||||
onChange={props.callback}
|
||||
value={value}
|
||||
onChange={onChange}
|
||||
onChangeCommitted={props.callback}
|
||||
step={props.step}
|
||||
min={props.min}
|
||||
max={props.max}
|
||||
|
@ -85,9 +85,15 @@ export function TerritorySubpage(): React.ReactElement {
|
||||
</Typography>
|
||||
</Box>
|
||||
<Box sx={{ display: "grid", gridTemplateColumns: "repeat(3, 1fr)" }}>
|
||||
{gangNames.map((name) => (
|
||||
<OtherGangTerritory key={name} name={name} />
|
||||
))}
|
||||
{gangNames
|
||||
.sort((a, b) => {
|
||||
if (AllGangs[a].territory <= 0 && AllGangs[b].territory > 0) return 1;
|
||||
if (AllGangs[a].territory > 0 && AllGangs[b].territory <= 0) return -1;
|
||||
return 0;
|
||||
})
|
||||
.map((name) => (
|
||||
<OtherGangTerritory key={name} name={name} />
|
||||
))}
|
||||
</Box>
|
||||
<TerritoryInfoModal open={infoOpen} onClose={() => setInfoOpen(false)} />
|
||||
</Container>
|
||||
@ -114,14 +120,16 @@ function OtherGangTerritory(props: ITerritoryProps): React.ReactElement {
|
||||
const playerPower = AllGangs[gang.facName].power;
|
||||
const power = AllGangs[props.name].power;
|
||||
const clashVictoryChance = playerPower / (power + playerPower);
|
||||
const territory = AllGangs[props.name].territory;
|
||||
const opacity = territory ? 1 : 0.75;
|
||||
return (
|
||||
<Box component={Paper} sx={{ p: 1 }}>
|
||||
<Box component={Paper} sx={{ p: 1, opacity }}>
|
||||
<Typography variant="h6" sx={{ display: "flex", alignItems: "center", flexWrap: "wrap" }}>
|
||||
{props.name}
|
||||
</Typography>
|
||||
<Typography>
|
||||
<b>Power:</b> {formatNumber(power, 3)} <br />
|
||||
<b>Territory:</b> {formatTerritory(AllGangs[props.name].territory)}% <br />
|
||||
<b>Territory:</b> {formatTerritory(territory)}% <br />
|
||||
<b>Clash Win Chance:</b> {numeralWrapper.formatPercentage(clashVictoryChance, 3)}
|
||||
</Typography>
|
||||
</Box>
|
||||
|
@ -36,7 +36,7 @@ export function calculateTradeInformationRepReward(
|
||||
30 *
|
||||
levelBonus *
|
||||
(player.hasAugmentation(AugmentationNames.WKSharmonizer, true) ? 1.5 : 1) *
|
||||
BitNodeMultipliers.InfiltrationMoney
|
||||
BitNodeMultipliers.InfiltrationRep
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -37,9 +37,13 @@ export function BackwardGame(props: IMinigameProps): React.ReactElement {
|
||||
const [guess, setGuess] = useState("");
|
||||
const hasAugment = Player.hasAugmentation(AugmentationNames.ChaosOfDionysus, true);
|
||||
|
||||
function ignorableKeyboardEvent(event: KeyboardEvent): boolean {
|
||||
return event.key === KEY.BACKSPACE || (event.shiftKey && event.key === "Shift") || event.ctrlKey || event.altKey;
|
||||
}
|
||||
|
||||
function press(this: Document, event: KeyboardEvent): void {
|
||||
event.preventDefault();
|
||||
if (event.key === KEY.BACKSPACE) return;
|
||||
if (ignorableKeyboardEvent(event)) return;
|
||||
const nextGuess = guess + event.key.toUpperCase();
|
||||
if (!answer.startsWith(nextGuess)) props.onFailure();
|
||||
else if (answer === nextGuess) props.onSuccess();
|
||||
|
@ -317,7 +317,7 @@ export function SpecialLocation(props: IProps): React.ReactElement {
|
||||
return renderGrafting();
|
||||
}
|
||||
case LocationName.Sector12CityHall: {
|
||||
return (BitNodeMultipliers.CorporationSoftCap < 0.15 && <></>) || <CreateCorporation />;
|
||||
return (BitNodeMultipliers.CorporationSoftcap < 0.15 && <></>) || <CreateCorporation />;
|
||||
}
|
||||
case LocationName.Sector12NSA: {
|
||||
return renderBladeburner();
|
||||
|
@ -5,6 +5,8 @@ import type { WorkerScript } from "./WorkerScript";
|
||||
import { makeRuntimeRejectMsg } from "../NetscriptEvaluator";
|
||||
import { Player } from "../Player";
|
||||
import { CityName } from "src/Locations/data/CityNames";
|
||||
import { Settings } from "../Settings/Settings";
|
||||
import { CONSTANTS } from "../Constants";
|
||||
|
||||
type ExternalFunction = (...args: any[]) => any;
|
||||
type ExternalAPI = {
|
||||
@ -91,8 +93,14 @@ function wrapFunction(
|
||||
getValidPort: (port: any) => helpers.getValidPort(functionPath, port),
|
||||
},
|
||||
};
|
||||
const safetyEnabled = Settings.InfinityLoopSafety;
|
||||
function wrappedFunction(...args: unknown[]): unknown {
|
||||
helpers.updateDynamicRam(ctx.function, getRamCost(Player, ...tree, ctx.function));
|
||||
if (safetyEnabled) workerScript.infiniteLoopSafetyCounter++;
|
||||
if (workerScript.infiniteLoopSafetyCounter > CONSTANTS.InfiniteLoopLimit)
|
||||
throw new Error(
|
||||
`Infinite loop without sleep detected. ${CONSTANTS.InfiniteLoopLimit} ns functions were called without sleep. This will cause your UI to hang.`,
|
||||
);
|
||||
return func(ctx)(...args);
|
||||
}
|
||||
const parent = getNestedProperty(wrappedAPI, ...tree);
|
||||
|
@ -51,6 +51,7 @@ export const RamCostConstants: IMap<number> = {
|
||||
ScriptCodingContractBaseRamCost: 10,
|
||||
ScriptSleeveBaseRamCost: 4,
|
||||
ScriptGetOwnedSourceFiles: 5,
|
||||
ScriptClearTerminalCost: 0.2,
|
||||
|
||||
ScriptSingularityFn1RamCost: 2,
|
||||
ScriptSingularityFn2RamCost: 3,
|
||||
@ -358,6 +359,7 @@ export const RamCosts: IMap<any> = {
|
||||
enableLog: 0,
|
||||
isLogEnabled: 0,
|
||||
getScriptLogs: 0,
|
||||
clearTerminal: RamCostConstants.ScriptClearTerminalCost,
|
||||
nuke: RamCostConstants.ScriptPortProgramRamCost,
|
||||
brutessh: RamCostConstants.ScriptPortProgramRamCost,
|
||||
ftpcrack: RamCostConstants.ScriptPortProgramRamCost,
|
||||
|
@ -111,6 +111,11 @@ export class WorkerScript {
|
||||
*/
|
||||
atExit: any;
|
||||
|
||||
/**
|
||||
* Once this counter reaches it's limit the script crashes. It is reset when a promise completes.
|
||||
*/
|
||||
infiniteLoopSafetyCounter = 0;
|
||||
|
||||
constructor(runningScriptObj: RunningScript, pid: number, nsFuncsGenerator?: (ws: WorkerScript) => any) {
|
||||
this.name = runningScriptObj.filename;
|
||||
this.hostname = runningScriptObj.server;
|
||||
|
@ -14,6 +14,7 @@ export function netscriptDelay(time: number, workerScript: WorkerScript): Promis
|
||||
workerScript.delay = null;
|
||||
workerScript.delayReject = undefined;
|
||||
|
||||
workerScript.infiniteLoopSafetyCounter = 0;
|
||||
if (workerScript.env.stopFlag) reject(new ScriptDeath(workerScript));
|
||||
else resolve();
|
||||
}, time);
|
||||
|
@ -55,7 +55,7 @@ import { makeRuntimeRejectMsg, netscriptDelay, resolveNetscriptRequestedThreads
|
||||
import { numeralWrapper } from "./ui/numeralFormat";
|
||||
import { convertTimeMsToTimeElapsedString } from "./utils/StringHelperFunctions";
|
||||
|
||||
import { LogBoxEvents } from "./ui/React/LogBoxManager";
|
||||
import { LogBoxEvents, LogBoxCloserEvents } from "./ui/React/LogBoxManager";
|
||||
import { arrayToString } from "./utils/helpers/arrayToString";
|
||||
import { isString } from "./utils/helpers/isString";
|
||||
|
||||
@ -1007,6 +1007,12 @@ export function NetscriptFunctions(workerScript: WorkerScript): NS {
|
||||
|
||||
LogBoxEvents.emit(runningScriptObj);
|
||||
},
|
||||
closeTail: function (_pid: unknown = workerScript.scriptRef.pid): void {
|
||||
updateDynamicRam("closeTail", getRamCost(Player, "closeTail"));
|
||||
const pid = helper.number("closeTail", "pid", _pid);
|
||||
//Emit an event to tell the game to close the tail window if it exists
|
||||
LogBoxCloserEvents.emit(pid);
|
||||
},
|
||||
nuke: function (_hostname: unknown): boolean {
|
||||
updateDynamicRam("nuke", getRamCost(Player, "nuke"));
|
||||
const hostname = helper.string("tail", "hostname", _hostname);
|
||||
|
@ -74,7 +74,7 @@ export function NetscriptCorporation(player: IPlayer, workerScript: WorkerScript
|
||||
if (!player.canAccessCorporation() || player.hasCorporation()) return false;
|
||||
if (!corporationName) return false;
|
||||
if (player.bitNodeN !== 3 && !selfFund) throw new Error("cannot use seed funds outside of BitNode 3");
|
||||
if (BitNodeMultipliers.CorporationSoftCap < 0.15)
|
||||
if (BitNodeMultipliers.CorporationSoftcap < 0.15)
|
||||
throw new Error(`You cannot create a corporation in Bitnode ${player.bitNodeN}`);
|
||||
|
||||
if (selfFund) {
|
||||
|
@ -84,7 +84,7 @@ export function NetscriptSingularity(player: IPlayer, workerScript: WorkerScript
|
||||
if (script.filename === cbScript) {
|
||||
const ramUsage = script.ramUsage;
|
||||
const ramAvailable = home.maxRam - home.ramUsed;
|
||||
if (ramUsage > ramAvailable) {
|
||||
if (ramUsage > ramAvailable + 0.001) {
|
||||
return; // Not enough RAM
|
||||
}
|
||||
const runningScriptObj = new RunningScript(script, []); // No args
|
||||
@ -123,7 +123,8 @@ export function NetscriptSingularity(player: IPlayer, workerScript: WorkerScript
|
||||
_ctx.helper.checkSingularityAccess();
|
||||
const augName = _ctx.helper.string("augName", _augName);
|
||||
const aug = getAugmentation(_ctx, augName);
|
||||
return [aug.getCost(player).moneyCost, aug.getCost(player).repCost];
|
||||
const costs = aug.getCost(player);
|
||||
return [costs.repCost, costs.moneyCost];
|
||||
},
|
||||
getAugmentationPrereq: (_ctx: NetscriptContext) =>
|
||||
function (_augName: unknown): string[] {
|
||||
|
@ -5,6 +5,7 @@ import { netscriptDelay } from "../NetscriptEvaluator";
|
||||
|
||||
import { staneksGift } from "../CotMG/Helper";
|
||||
import { Fragments, FragmentById } from "../CotMG/Fragment";
|
||||
import { FragmentType } from "../CotMG/FragmentType";
|
||||
|
||||
import {
|
||||
Fragment as IFragment,
|
||||
@ -42,11 +43,19 @@ export function NetscriptStanek(
|
||||
},
|
||||
chargeFragment: (_ctx: NetscriptContext) =>
|
||||
function (_rootX: unknown, _rootY: unknown): Promise<void> {
|
||||
//Get the fragment object using the given coordinates
|
||||
const rootX = _ctx.helper.number("rootX", _rootX);
|
||||
const rootY = _ctx.helper.number("rootY", _rootY);
|
||||
checkStanekAPIAccess("chargeFragment");
|
||||
const fragment = staneksGift.findFragment(rootX, rootY);
|
||||
//Check whether the selected fragment can ge charged
|
||||
if (!fragment) throw _ctx.makeRuntimeErrorMsg(`No fragment with root (${rootX}, ${rootY}).`);
|
||||
if (fragment.fragment().type == FragmentType.Booster) {
|
||||
throw _ctx.makeRuntimeErrorMsg(
|
||||
`The fragment with root (${rootX}, ${rootY}) is a Booster Fragment and thus cannot be charged.`,
|
||||
);
|
||||
}
|
||||
//Charge the fragment
|
||||
const time = staneksGift.inBonus() ? 200 : 1000;
|
||||
return netscriptDelay(time, workerScript).then(function () {
|
||||
const charge = staneksGift.charge(player, fragment, workerScript.scriptRef.threads);
|
||||
|
@ -11,6 +11,7 @@ import { defaultStyles } from "../Themes/Styles";
|
||||
import { CONSTANTS } from "../Constants";
|
||||
import { hash } from "../hash/hash";
|
||||
import { InternalAPI, NetscriptContext } from "src/Netscript/APIWrapper";
|
||||
import { Terminal } from "../../src/Terminal";
|
||||
|
||||
export function NetscriptUserInterface(): InternalAPI<IUserInterface> {
|
||||
return {
|
||||
@ -96,5 +97,11 @@ export function NetscriptUserInterface(): InternalAPI<IUserInterface> {
|
||||
|
||||
return gameInfo;
|
||||
},
|
||||
|
||||
clearTerminal: function (): void {
|
||||
updateRam("clearTerminal");
|
||||
workerScript.log("ui.clearTerminal", () => `Clearing terminal`);
|
||||
Terminal.clear();
|
||||
},
|
||||
};
|
||||
}
|
||||
|
@ -532,7 +532,7 @@ function createAndAddWorkerScript(
|
||||
const oneRamUsage = getRamUsageFromRunningScript(runningScriptObj);
|
||||
const ramUsage = roundToTwo(oneRamUsage * threads);
|
||||
const ramAvailable = server.maxRam - server.ramUsed;
|
||||
if (ramUsage > ramAvailable) {
|
||||
if (ramUsage > ramAvailable + 0.001) {
|
||||
dialogBoxCreate(
|
||||
`Not enough RAM to run script ${runningScriptObj.filename} with args ` +
|
||||
`${arrayToString(runningScriptObj.args)}. This likely occurred because you re-loaded ` +
|
||||
@ -750,7 +750,7 @@ export function runScriptFromScript(
|
||||
if (server.hasAdminRights == false) {
|
||||
workerScript.log(caller, () => `You do not have root access on '${server.hostname}'`);
|
||||
return 0;
|
||||
} else if (ramUsage > ramAvailable) {
|
||||
} else if (ramUsage > ramAvailable + 0.001) {
|
||||
workerScript.log(
|
||||
caller,
|
||||
() =>
|
||||
|
@ -1,13 +1,14 @@
|
||||
import { Construction, CheckBox, CheckBoxOutlineBlank } from "@mui/icons-material";
|
||||
import { CheckBox, CheckBoxOutlineBlank, Construction } from "@mui/icons-material";
|
||||
import { Box, Button, Container, List, ListItemButton, Paper, Typography } from "@mui/material";
|
||||
import React, { useState, useEffect } from "react";
|
||||
import React, { useEffect, useState } from "react";
|
||||
import { Augmentation } from "../../../Augmentation/Augmentation";
|
||||
import { StaticAugmentations } from "../../../Augmentation/StaticAugmentations";
|
||||
import { AugmentationNames } from "../../../Augmentation/data/AugmentationNames";
|
||||
import { StaticAugmentations } from "../../../Augmentation/StaticAugmentations";
|
||||
import { CONSTANTS } from "../../../Constants";
|
||||
import { hasAugmentationPrereqs } from "../../../Faction/FactionHelpers";
|
||||
import { LocationName } from "../../../Locations/data/LocationNames";
|
||||
import { Locations } from "../../../Locations/Locations";
|
||||
import { PurchaseAugmentationsOrderSetting } from "../../../Settings/SettingEnums";
|
||||
import { Settings } from "../../../Settings/Settings";
|
||||
import { IMap } from "../../../types";
|
||||
import { use } from "../../../ui/Context";
|
||||
@ -15,8 +16,8 @@ import { ConfirmationModal } from "../../../ui/React/ConfirmationModal";
|
||||
import { Money } from "../../../ui/React/Money";
|
||||
import { convertTimeMsToTimeElapsedString, formatNumber } from "../../../utils/StringHelperFunctions";
|
||||
import { IPlayer } from "../../IPlayer";
|
||||
import { getGraftingAvailableAugs, calculateGraftingTimeWithBonus } from "../GraftingHelpers";
|
||||
import { GraftableAugmentation } from "../GraftableAugmentation";
|
||||
import { calculateGraftingTimeWithBonus, getGraftingAvailableAugs } from "../GraftingHelpers";
|
||||
|
||||
const GraftableAugmentations: IMap<GraftableAugmentation> = {};
|
||||
|
||||
@ -69,6 +70,21 @@ export const GraftingRoot = (): React.ReactElement => {
|
||||
setRerender((old) => !old);
|
||||
}
|
||||
|
||||
const getAugsSorted = (): string[] => {
|
||||
const augs = getGraftingAvailableAugs(player);
|
||||
switch (Settings.PurchaseAugmentationsOrder) {
|
||||
case PurchaseAugmentationsOrderSetting.Cost:
|
||||
return augs.sort((a, b) => GraftableAugmentations[a].cost - GraftableAugmentations[b].cost);
|
||||
default:
|
||||
return augs;
|
||||
}
|
||||
};
|
||||
|
||||
const switchSortOrder = (newOrder: PurchaseAugmentationsOrderSetting): void => {
|
||||
Settings.PurchaseAugmentationsOrder = newOrder;
|
||||
rerender();
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
const id = setInterval(rerender, 200);
|
||||
return () => clearInterval(id);
|
||||
@ -91,13 +107,31 @@ export const GraftingRoot = (): React.ReactElement => {
|
||||
</Typography>
|
||||
|
||||
<Box sx={{ my: 3 }}>
|
||||
<Typography variant="h5">Graft Augmentations</Typography>
|
||||
<Paper sx={{ p: 1 }}>
|
||||
<Typography variant="h5">Graft Augmentations</Typography>
|
||||
<Box sx={{ display: "grid", gridTemplateColumns: "1fr 1fr" }}>
|
||||
<Button sx={{ width: "100%" }} onClick={() => switchSortOrder(PurchaseAugmentationsOrderSetting.Cost)}>
|
||||
Sort by Cost
|
||||
</Button>
|
||||
<Button sx={{ width: "100%" }} onClick={() => switchSortOrder(PurchaseAugmentationsOrderSetting.Default)}>
|
||||
Sort by Default Order
|
||||
</Button>
|
||||
</Box>
|
||||
</Paper>
|
||||
{getGraftingAvailableAugs(player).length > 0 ? (
|
||||
<Paper sx={{ my: 1, width: "fit-content", display: "grid", gridTemplateColumns: "1fr 3fr" }}>
|
||||
<Paper sx={{ mb: 1, width: "fit-content", display: "grid", gridTemplateColumns: "1fr 3fr" }}>
|
||||
<List sx={{ height: 400, overflowY: "scroll", borderRight: `1px solid ${Settings.theme.welllight}` }}>
|
||||
{getGraftingAvailableAugs(player).map((k, i) => (
|
||||
{getAugsSorted().map((k, i) => (
|
||||
<ListItemButton key={i + 1} onClick={() => setSelectedAug(k)} selected={selectedAug === k}>
|
||||
<Typography>{k}</Typography>
|
||||
<Typography
|
||||
sx={{
|
||||
color: canGraft(player, GraftableAugmentations[k])
|
||||
? Settings.theme.primary
|
||||
: Settings.theme.disabled,
|
||||
}}
|
||||
>
|
||||
{k}
|
||||
</Typography>
|
||||
</ListItemButton>
|
||||
))}
|
||||
</List>
|
||||
|
24
src/ScriptEditor/NetscriptDefinitions.d.ts
vendored
24
src/ScriptEditor/NetscriptDefinitions.d.ts
vendored
@ -560,7 +560,7 @@ export interface BitNodeMultipliers {
|
||||
/** Influences how much money the player earns when completing working their job. */
|
||||
CompanyWorkMoney: number;
|
||||
/** Influences the money gain from dividends of corporations created by the player. */
|
||||
CorporationSoftCap: number;
|
||||
CorporationSoftcap: number;
|
||||
/** Influences the valuation of corporations created by the player. */
|
||||
CorporationValuation: number;
|
||||
/** Influences the base experience gained for each ability when the player commits a crime. */
|
||||
@ -4391,6 +4391,13 @@ interface UserInterface {
|
||||
* RAM cost: 0 GB
|
||||
*/
|
||||
getGameInfo(): GameInfo;
|
||||
|
||||
/**
|
||||
* Clear the Terminal window, as if the player ran `clear` in the terminal
|
||||
* @remarks
|
||||
* RAM cost: 0.2 GB
|
||||
*/
|
||||
clearTerminal(): void;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -4974,6 +4981,21 @@ export interface NS {
|
||||
*/
|
||||
tail(fn?: FilenameOrPID, host?: string, ...args: any[]): void;
|
||||
|
||||
/**
|
||||
* Close the tail window of a script.
|
||||
* @remarks
|
||||
* RAM cost: 0 GB
|
||||
*
|
||||
* Closes a script’s logs. This is functionally the same pressing the "Close" button on the tail window.
|
||||
*
|
||||
* If the function is called with no arguments, it will close the current script’s logs.
|
||||
*
|
||||
* Otherwise, the pid argument can be used to close the logs from another script.
|
||||
*
|
||||
* @param pid - Optional. PID of the script having its tail closed. If omitted, the current script is used.
|
||||
*/
|
||||
closeTail(pid?: number): void;
|
||||
|
||||
/**
|
||||
* Get the list of servers connected to a server.
|
||||
* @remarks
|
||||
|
@ -54,6 +54,11 @@ interface IDefaultSettings {
|
||||
*/
|
||||
EnableBashHotkeys: boolean;
|
||||
|
||||
/**
|
||||
* Infinite loop safety net
|
||||
*/
|
||||
InfinityLoopSafety: boolean;
|
||||
|
||||
/**
|
||||
* Timestamps format
|
||||
*/
|
||||
@ -201,6 +206,7 @@ export const defaultSettings: IDefaultSettings = {
|
||||
DisableOverviewProgressBars: false,
|
||||
EnableBashHotkeys: false,
|
||||
TimestampsFormat: "",
|
||||
InfinityLoopSafety: true,
|
||||
Locale: "en",
|
||||
MaxRecentScriptsCapacity: 50,
|
||||
MaxLogCapacity: 50,
|
||||
@ -241,6 +247,7 @@ export const Settings: ISettings & ISelfInitializer & ISelfLoading = {
|
||||
DisableOverviewProgressBars: defaultSettings.DisableOverviewProgressBars,
|
||||
EnableBashHotkeys: defaultSettings.EnableBashHotkeys,
|
||||
TimestampsFormat: defaultSettings.TimestampsFormat,
|
||||
InfinityLoopSafety: defaultSettings.InfinityLoopSafety,
|
||||
Locale: "en",
|
||||
MaxRecentScriptsCapacity: defaultSettings.MaxRecentScriptsCapacity,
|
||||
MaxLogCapacity: defaultSettings.MaxLogCapacity,
|
||||
|
@ -67,8 +67,18 @@ SourceFiles["SourceFile5"] = new SourceFile(
|
||||
This Source-File grants a special new stat called Intelligence. Intelligence is unique because it is permanent and
|
||||
persistent (it never gets reset back to 1). However, gaining Intelligence experience is much slower than other
|
||||
stats. Higher Intelligence levels will boost your production for many actions in the game. In addition, this
|
||||
Source-File will unlock the getBitNodeMultipliers() Netscript function and let you start with Formulas.exe, and
|
||||
will raise all of your hacking-related multipliers by:
|
||||
Source-File will unlock:
|
||||
<br />
|
||||
<ul>
|
||||
<li>
|
||||
The <code>getBitNodeMultipliers()</code> Netscript function
|
||||
</li>
|
||||
<li>Permanent access to Formulas.exe</li>
|
||||
<li>
|
||||
Access to BitNode multiplier information on the <b>Stats</b> page
|
||||
</li>
|
||||
</ul>
|
||||
It will also raise all of your hacking-related multipliers by:
|
||||
<br />
|
||||
<br />
|
||||
Level 1: 8%
|
||||
|
@ -463,6 +463,12 @@ export class Terminal implements ITerminal {
|
||||
this.contractOpen = true;
|
||||
const res = await contract.prompt();
|
||||
|
||||
//Check if the contract still exists by the time the promise is fullfilled
|
||||
if (serv.getContract(contractName) == null) {
|
||||
this.contractOpen = false;
|
||||
return this.error("Contract no longer exists (Was it solved by a script?)");
|
||||
}
|
||||
|
||||
switch (res) {
|
||||
case CodingContractResult.Success:
|
||||
if (contract.reward !== null) {
|
||||
|
@ -63,13 +63,11 @@ export function runScript(
|
||||
return;
|
||||
}
|
||||
|
||||
if (ramUsage > ramAvailable) {
|
||||
if (ramUsage > ramAvailable + 0.001) {
|
||||
terminal.error(
|
||||
"This machine does not have enough RAM to run this script with " +
|
||||
numThreads +
|
||||
" threads. Script requires " +
|
||||
numeralWrapper.formatRAM(ramUsage) +
|
||||
" of RAM",
|
||||
"This machine does not have enough RAM to run this script" +
|
||||
(numThreads === 1 ? "" : ` with ${numThreads} threads`) +
|
||||
`. Script requires ${numeralWrapper.formatRAM(ramUsage)} of RAM`,
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
@ -1382,7 +1382,8 @@ export const codingContractTypesMetadata: ICodingContractTypeMetadata[] = [
|
||||
return [n + m, edges];
|
||||
},
|
||||
solver: (data: [number, [number, number][]], ans: string): boolean => {
|
||||
//Case where the player believes there is no solution
|
||||
//Case where the player believes there is no solution.
|
||||
//Attempt to construct one to check if this is correct.
|
||||
if (ans == "[]") {
|
||||
//Helper function to get neighbourhood of a vertex
|
||||
function neighbourhood(vertex: number): number[] {
|
||||
|
@ -1,8 +1,9 @@
|
||||
import { Paper, Table, TableBody, Box, IconButton, Typography, Container, Tooltip } from "@mui/material";
|
||||
import { MoreHoriz, Info } from "@mui/icons-material";
|
||||
import React, { useEffect, useState } from "react";
|
||||
import { BitNodes } from "../BitNode/BitNode";
|
||||
import { BitNodes, defaultMultipliers, getBitNodeMultipliers } from "../BitNode/BitNode";
|
||||
import { BitNodeMultipliers } from "../BitNode/BitNodeMultipliers";
|
||||
import { BitNodeMultipliersDisplay } from "../BitNode/ui/BitnodeMultipliersDescription";
|
||||
import { HacknetServerConstants } from "../Hacknet/data/Constants";
|
||||
import { getPurchaseServerLimit } from "../Server/ServerPurchases";
|
||||
import { Settings } from "../Settings/Settings";
|
||||
@ -14,6 +15,7 @@ import { Modal } from "./React/Modal";
|
||||
import { Money } from "./React/Money";
|
||||
import { StatsRow } from "./React/StatsRow";
|
||||
import { StatsTable } from "./React/StatsTable";
|
||||
import { isEqual } from "lodash";
|
||||
|
||||
interface EmployersModalProps {
|
||||
open: boolean;
|
||||
@ -36,8 +38,22 @@ const EmployersModal = ({ open, onClose }: EmployersModalProps): React.ReactElem
|
||||
);
|
||||
};
|
||||
|
||||
interface IMultRow {
|
||||
// The name of the multiplier
|
||||
mult: string;
|
||||
|
||||
// The player's raw multiplier value
|
||||
value: number;
|
||||
|
||||
// The player's effective multiplier value, affected by BitNode mults
|
||||
effValue?: number;
|
||||
|
||||
// The text color for the row
|
||||
color?: string;
|
||||
}
|
||||
|
||||
interface MultTableProps {
|
||||
rows: (string | number)[][];
|
||||
rows: IMultRow[];
|
||||
color: string;
|
||||
noMargin?: boolean;
|
||||
}
|
||||
@ -48,29 +64,22 @@ function MultiplierTable(props: MultTableProps): React.ReactElement {
|
||||
<Table sx={{ display: "table", width: "100%", mb: (props.noMargin ?? false) === true ? 0 : 2 }}>
|
||||
<TableBody>
|
||||
{props.rows.map((data) => {
|
||||
const mult = data[0] as string,
|
||||
value = data[1] as number,
|
||||
modded = data[2] as number | null;
|
||||
const { mult, value, effValue = null, color = props.color } = data;
|
||||
|
||||
if (modded && modded !== value && player.sourceFileLvl(5) > 0) {
|
||||
if (effValue !== null && effValue !== value && player.sourceFileLvl(5) > 0) {
|
||||
return (
|
||||
<StatsRow key={mult} name={mult} color={props.color} data={{}}>
|
||||
<StatsRow key={mult} name={mult} color={color} data={{}}>
|
||||
<>
|
||||
<Typography color={props.color}>
|
||||
<Typography color={color}>
|
||||
<span style={{ opacity: 0.5 }}>{numeralWrapper.formatPercentage(value)}</span>{" "}
|
||||
{numeralWrapper.formatPercentage(modded)}
|
||||
{numeralWrapper.formatPercentage(effValue)}
|
||||
</Typography>
|
||||
</>
|
||||
</StatsRow>
|
||||
);
|
||||
}
|
||||
return (
|
||||
<StatsRow
|
||||
key={mult}
|
||||
name={mult}
|
||||
color={props.color}
|
||||
data={{ content: numeralWrapper.formatPercentage(value) }}
|
||||
/>
|
||||
<StatsRow key={mult} name={mult} color={color} data={{ content: numeralWrapper.formatPercentage(value) }} />
|
||||
);
|
||||
})}
|
||||
</TableBody>
|
||||
@ -82,16 +91,14 @@ function CurrentBitNode(): React.ReactElement {
|
||||
const player = use.Player();
|
||||
if (player.sourceFiles.length > 0) {
|
||||
const index = "BitNode" + player.bitNodeN;
|
||||
const lvl = player.sourceFileLvl(player.bitNodeN) + 1;
|
||||
const lvl = Math.min(player.sourceFileLvl(player.bitNodeN) + 1, player.bitNodeN === 12 ? Infinity : 3);
|
||||
return (
|
||||
<Box>
|
||||
<Paper sx={{ p: 1 }}>
|
||||
<Typography variant="h5">
|
||||
BitNode {player.bitNodeN}: {BitNodes[index].name} (Level {lvl})
|
||||
</Typography>
|
||||
<Typography sx={{ whiteSpace: "pre-wrap", overflowWrap: "break-word" }}>{BitNodes[index].info}</Typography>
|
||||
</Paper>
|
||||
</Box>
|
||||
<Paper sx={{ mb: 1, p: 1 }}>
|
||||
<Typography variant="h5">
|
||||
BitNode {player.bitNodeN}: {BitNodes[index].name} (Level {lvl})
|
||||
</Typography>
|
||||
<Typography sx={{ whiteSpace: "pre-wrap", overflowWrap: "break-word" }}>{BitNodes[index].info}</Typography>
|
||||
</Paper>
|
||||
);
|
||||
}
|
||||
|
||||
@ -218,6 +225,14 @@ export function CharacterStats(): React.ReactElement {
|
||||
}
|
||||
timeRows.push(["Total", convertTimeMsToTimeElapsedString(player.totalPlaytime)]);
|
||||
|
||||
let showBitNodeMults = false;
|
||||
if (player.sourceFileLvl(5) > 0) {
|
||||
const n = player.bitNodeN;
|
||||
const maxSfLevel = n === 12 ? Infinity : 3;
|
||||
const mults = getBitNodeMultipliers(n, Math.min(player.sourceFileLvl(n) + 1, maxSfLevel));
|
||||
showBitNodeMults = !isEqual(mults, defaultMultipliers);
|
||||
}
|
||||
|
||||
return (
|
||||
<Container maxWidth="lg" disableGutters sx={{ mx: 0 }}>
|
||||
<Typography variant="h4">Stats</Typography>
|
||||
@ -332,186 +347,255 @@ export function CharacterStats(): React.ReactElement {
|
||||
</Table>
|
||||
</Paper>
|
||||
</Box>
|
||||
<Box sx={{ mb: 1 }}>
|
||||
<Paper sx={{ p: 1 }}>
|
||||
<Typography variant="h5" color="primary" sx={{ display: "flex", alignItems: "center", flexWrap: "wrap" }}>
|
||||
Multipliers
|
||||
{player.sourceFileLvl(5) > 0 && (
|
||||
<Tooltip
|
||||
title={
|
||||
<Typography>
|
||||
Displays your current multipliers.
|
||||
<br />
|
||||
<br />
|
||||
When there is a dim number next to a multiplier, that means that the multiplier in question is being
|
||||
affected by BitNode multipliers.
|
||||
<br />
|
||||
<br />
|
||||
The dim number is the raw multiplier, and the undimmed number is the effective multiplier, as
|
||||
dictated by the BitNode.
|
||||
</Typography>
|
||||
}
|
||||
>
|
||||
<Info sx={{ ml: 1, mb: 0.5 }} color="info" />
|
||||
</Tooltip>
|
||||
)}
|
||||
</Typography>
|
||||
<Box sx={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: 1 }}>
|
||||
<Box>
|
||||
<MultiplierTable
|
||||
rows={[
|
||||
["Hacking Chance", player.hacking_chance_mult],
|
||||
["Hacking Speed", player.hacking_speed_mult],
|
||||
[
|
||||
"Hacking Money",
|
||||
player.hacking_money_mult,
|
||||
player.hacking_money_mult * BitNodeMultipliers.ScriptHackMoney,
|
||||
],
|
||||
[
|
||||
"Hacking Growth",
|
||||
player.hacking_grow_mult,
|
||||
player.hacking_grow_mult * BitNodeMultipliers.ServerGrowthRate,
|
||||
],
|
||||
]}
|
||||
color={Settings.theme.hack}
|
||||
/>
|
||||
<MultiplierTable
|
||||
rows={[
|
||||
[
|
||||
"Hacking Level",
|
||||
player.hacking_mult,
|
||||
player.hacking_mult * BitNodeMultipliers.HackingLevelMultiplier,
|
||||
],
|
||||
[
|
||||
"Hacking Experience",
|
||||
player.hacking_exp_mult,
|
||||
player.hacking_exp_mult * BitNodeMultipliers.HackExpGain,
|
||||
],
|
||||
]}
|
||||
color={Settings.theme.hack}
|
||||
/>
|
||||
<MultiplierTable
|
||||
rows={[
|
||||
[
|
||||
"Strength Level",
|
||||
player.strength_mult,
|
||||
player.strength_mult * BitNodeMultipliers.StrengthLevelMultiplier,
|
||||
],
|
||||
["Strength Experience", player.strength_exp_mult],
|
||||
]}
|
||||
color={Settings.theme.combat}
|
||||
/>
|
||||
<MultiplierTable
|
||||
rows={[
|
||||
[
|
||||
"Defense Level",
|
||||
player.defense_mult,
|
||||
player.defense_mult * BitNodeMultipliers.DefenseLevelMultiplier,
|
||||
],
|
||||
["Defense Experience", player.defense_exp_mult],
|
||||
]}
|
||||
color={Settings.theme.combat}
|
||||
/>
|
||||
<MultiplierTable
|
||||
rows={[
|
||||
[
|
||||
"Dexterity Level",
|
||||
player.dexterity_mult,
|
||||
player.dexterity_mult * BitNodeMultipliers.DexterityLevelMultiplier,
|
||||
],
|
||||
["Dexterity Experience", player.dexterity_exp_mult],
|
||||
]}
|
||||
color={Settings.theme.combat}
|
||||
/>
|
||||
<MultiplierTable
|
||||
rows={[
|
||||
[
|
||||
"Agility Level",
|
||||
player.agility_mult,
|
||||
player.agility_mult * BitNodeMultipliers.AgilityLevelMultiplier,
|
||||
],
|
||||
["Agility Experience", player.agility_exp_mult],
|
||||
]}
|
||||
color={Settings.theme.combat}
|
||||
/>
|
||||
<MultiplierTable
|
||||
rows={[
|
||||
[
|
||||
"Charisma Level",
|
||||
player.charisma_mult,
|
||||
player.charisma_mult * BitNodeMultipliers.CharismaLevelMultiplier,
|
||||
],
|
||||
["Charisma Experience", player.charisma_exp_mult],
|
||||
]}
|
||||
color={Settings.theme.cha}
|
||||
noMargin
|
||||
/>
|
||||
</Box>
|
||||
|
||||
<Box>
|
||||
<Paper sx={{ p: 1, mb: 1 }}>
|
||||
<Typography variant="h5" color="primary" sx={{ display: "flex", alignItems: "center", flexWrap: "wrap" }}>
|
||||
Multipliers
|
||||
{player.sourceFileLvl(5) > 0 && (
|
||||
<Tooltip
|
||||
title={
|
||||
<Typography>
|
||||
Displays your current multipliers.
|
||||
<br />
|
||||
<br />
|
||||
When there is a dim number next to a multiplier, that means that the multiplier in question is being
|
||||
affected by BitNode multipliers.
|
||||
<br />
|
||||
<br />
|
||||
The dim number is the raw multiplier, and the undimmed number is the effective multiplier, as dictated
|
||||
by the BitNode.
|
||||
</Typography>
|
||||
}
|
||||
>
|
||||
<Info sx={{ ml: 1, mb: 0.5 }} color="info" />
|
||||
</Tooltip>
|
||||
)}
|
||||
</Typography>
|
||||
<Box sx={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: 1 }}>
|
||||
<Box>
|
||||
<MultiplierTable
|
||||
rows={[
|
||||
{
|
||||
mult: "Hacking Chance",
|
||||
value: player.hacking_chance_mult,
|
||||
},
|
||||
{
|
||||
mult: "Hacking Speed",
|
||||
value: player.hacking_speed_mult,
|
||||
},
|
||||
{
|
||||
mult: "Hacking Money",
|
||||
value: player.hacking_money_mult,
|
||||
effValue: player.hacking_money_mult * BitNodeMultipliers.ScriptHackMoney,
|
||||
},
|
||||
{
|
||||
mult: "Hacking Growth",
|
||||
value: player.hacking_grow_mult,
|
||||
effValue: player.hacking_grow_mult * BitNodeMultipliers.ServerGrowthRate,
|
||||
},
|
||||
]}
|
||||
color={Settings.theme.hack}
|
||||
/>
|
||||
<MultiplierTable
|
||||
rows={[
|
||||
{
|
||||
mult: "Hacking Level",
|
||||
value: player.hacking_mult,
|
||||
effValue: player.hacking_mult * BitNodeMultipliers.HackingLevelMultiplier,
|
||||
},
|
||||
{
|
||||
mult: "Hacking Experience",
|
||||
value: player.hacking_exp_mult,
|
||||
effValue: player.hacking_exp_mult * BitNodeMultipliers.HackExpGain,
|
||||
},
|
||||
]}
|
||||
color={Settings.theme.hack}
|
||||
/>
|
||||
<MultiplierTable
|
||||
rows={[
|
||||
{
|
||||
mult: "Strength Level",
|
||||
value: player.strength_mult,
|
||||
effValue: player.strength_mult * BitNodeMultipliers.StrengthLevelMultiplier,
|
||||
},
|
||||
{
|
||||
mult: "Strength Experience",
|
||||
value: player.strength_exp_mult,
|
||||
},
|
||||
]}
|
||||
color={Settings.theme.combat}
|
||||
/>
|
||||
<MultiplierTable
|
||||
rows={[
|
||||
{
|
||||
mult: "Defense Level",
|
||||
value: player.defense_mult,
|
||||
effValue: player.defense_mult * BitNodeMultipliers.DefenseLevelMultiplier,
|
||||
},
|
||||
{
|
||||
mult: "Defense Experience",
|
||||
value: player.defense_exp_mult,
|
||||
},
|
||||
]}
|
||||
color={Settings.theme.combat}
|
||||
/>
|
||||
<MultiplierTable
|
||||
rows={[
|
||||
{
|
||||
mult: "Dexterity Level",
|
||||
value: player.dexterity_mult,
|
||||
effValue: player.dexterity_mult * BitNodeMultipliers.DexterityLevelMultiplier,
|
||||
},
|
||||
{
|
||||
mult: "Dexterity Experience",
|
||||
value: player.dexterity_exp_mult,
|
||||
},
|
||||
]}
|
||||
color={Settings.theme.combat}
|
||||
/>
|
||||
<MultiplierTable
|
||||
rows={[
|
||||
{
|
||||
mult: "Agility Level",
|
||||
value: player.agility_mult,
|
||||
effValue: player.agility_mult * BitNodeMultipliers.AgilityLevelMultiplier,
|
||||
},
|
||||
{
|
||||
mult: "Agility Experience",
|
||||
value: player.agility_exp_mult,
|
||||
},
|
||||
]}
|
||||
color={Settings.theme.combat}
|
||||
/>
|
||||
<MultiplierTable
|
||||
rows={[
|
||||
{
|
||||
mult: "Charisma Level",
|
||||
value: player.charisma_mult,
|
||||
effValue: player.charisma_mult * BitNodeMultipliers.CharismaLevelMultiplier,
|
||||
},
|
||||
{
|
||||
mult: "Charisma Experience",
|
||||
value: player.charisma_exp_mult,
|
||||
},
|
||||
]}
|
||||
color={Settings.theme.cha}
|
||||
noMargin
|
||||
/>
|
||||
</Box>
|
||||
|
||||
<Box>
|
||||
<MultiplierTable
|
||||
rows={[
|
||||
{
|
||||
mult: "Hacknet Node Production",
|
||||
value: player.hacknet_node_money_mult,
|
||||
effValue: player.hacknet_node_money_mult * BitNodeMultipliers.HacknetNodeMoney,
|
||||
},
|
||||
{
|
||||
mult: "Hacknet Node Purchase Cost",
|
||||
value: player.hacknet_node_purchase_cost_mult,
|
||||
},
|
||||
{
|
||||
mult: "Hacknet Node RAM Upgrade Cost",
|
||||
value: player.hacknet_node_ram_cost_mult,
|
||||
},
|
||||
{
|
||||
mult: "Hacknet Node Core Purchase Cost",
|
||||
value: player.hacknet_node_core_cost_mult,
|
||||
},
|
||||
{
|
||||
mult: "Hacknet Node Level Upgrade Cost",
|
||||
value: player.hacknet_node_level_cost_mult,
|
||||
},
|
||||
]}
|
||||
color={Settings.theme.primary}
|
||||
/>
|
||||
<MultiplierTable
|
||||
rows={[
|
||||
{
|
||||
mult: "Company Reputation Gain",
|
||||
value: player.company_rep_mult,
|
||||
color: Settings.theme.rep,
|
||||
},
|
||||
{
|
||||
mult: "Faction Reputation Gain",
|
||||
value: player.faction_rep_mult,
|
||||
effValue: player.faction_rep_mult * BitNodeMultipliers.FactionWorkRepGain,
|
||||
color: Settings.theme.rep,
|
||||
},
|
||||
{
|
||||
mult: "Salary",
|
||||
value: player.work_money_mult,
|
||||
effValue: player.work_money_mult * BitNodeMultipliers.CompanyWorkMoney,
|
||||
color: Settings.theme.money,
|
||||
},
|
||||
]}
|
||||
color={Settings.theme.money}
|
||||
/>
|
||||
<MultiplierTable
|
||||
rows={[
|
||||
{
|
||||
mult: "Crime Success Chance",
|
||||
value: player.crime_success_mult,
|
||||
},
|
||||
{
|
||||
mult: "Crime Money",
|
||||
value: player.crime_money_mult,
|
||||
effValue: player.crime_money_mult * BitNodeMultipliers.CrimeMoney,
|
||||
color: Settings.theme.money,
|
||||
},
|
||||
]}
|
||||
color={Settings.theme.combat}
|
||||
/>
|
||||
{player.canAccessBladeburner() && (
|
||||
<MultiplierTable
|
||||
rows={[
|
||||
[
|
||||
"Hacknet Node production",
|
||||
player.hacknet_node_money_mult,
|
||||
player.hacknet_node_money_mult * BitNodeMultipliers.HacknetNodeMoney,
|
||||
],
|
||||
["Hacknet Node purchase cost", player.hacknet_node_purchase_cost_mult],
|
||||
["Hacknet Node RAM upgrade cost", player.hacknet_node_ram_cost_mult],
|
||||
["Hacknet Node Core purchase cost", player.hacknet_node_core_cost_mult],
|
||||
["Hacknet Node level upgrade cost", player.hacknet_node_level_cost_mult],
|
||||
{
|
||||
mult: "Bladeburner Success Chance",
|
||||
value: player.bladeburner_success_chance_mult,
|
||||
},
|
||||
{
|
||||
mult: "Bladeburner Max Stamina",
|
||||
value: player.bladeburner_max_stamina_mult,
|
||||
},
|
||||
{
|
||||
mult: "Bladeburner Stamina Gain",
|
||||
value: player.bladeburner_stamina_gain_mult,
|
||||
},
|
||||
{
|
||||
mult: "Bladeburner Field Analysis",
|
||||
value: player.bladeburner_analysis_mult,
|
||||
},
|
||||
]}
|
||||
color={Settings.theme.primary}
|
||||
noMargin
|
||||
/>
|
||||
<MultiplierTable
|
||||
rows={[
|
||||
["Company reputation gain", player.company_rep_mult],
|
||||
[
|
||||
"Faction reputation gain",
|
||||
player.faction_rep_mult,
|
||||
player.faction_rep_mult * BitNodeMultipliers.FactionWorkRepGain,
|
||||
],
|
||||
["Salary", player.work_money_mult, player.work_money_mult * BitNodeMultipliers.CompanyWorkMoney],
|
||||
]}
|
||||
color={Settings.theme.money}
|
||||
/>
|
||||
<MultiplierTable
|
||||
rows={[
|
||||
["Crime success", player.crime_success_mult],
|
||||
["Crime money", player.crime_money_mult, player.crime_money_mult * BitNodeMultipliers.CrimeMoney],
|
||||
]}
|
||||
color={Settings.theme.combat}
|
||||
/>
|
||||
{player.canAccessBladeburner() && (
|
||||
<MultiplierTable
|
||||
rows={[
|
||||
["Bladeburner Success Chance", player.bladeburner_success_chance_mult],
|
||||
["Bladeburner Max Stamina", player.bladeburner_max_stamina_mult],
|
||||
["Bladeburner Stamina Gain", player.bladeburner_stamina_gain_mult],
|
||||
["Bladeburner Field Analysis", player.bladeburner_analysis_mult],
|
||||
]}
|
||||
color={Settings.theme.primary}
|
||||
noMargin
|
||||
/>
|
||||
)}
|
||||
</Box>
|
||||
)}
|
||||
</Box>
|
||||
</Paper>
|
||||
</Box>
|
||||
</Box>
|
||||
</Paper>
|
||||
|
||||
<Paper sx={{ p: 1, mb: 1 }}>
|
||||
<Typography variant="h5">Time Played</Typography>
|
||||
<Table>
|
||||
<TableBody>
|
||||
{timeRows.map(([name, content]) => (
|
||||
<StatsRow key={name} name={name} color={Settings.theme.primary} data={{ content: content }} />
|
||||
))}
|
||||
</TableBody>
|
||||
</Table>
|
||||
</Paper>
|
||||
|
||||
<Box sx={{ mb: 1 }}>
|
||||
<Paper sx={{ p: 1 }}>
|
||||
<Typography variant="h5">Time Played</Typography>
|
||||
<Table>
|
||||
<TableBody>
|
||||
{timeRows.map(([name, content]) => (
|
||||
<StatsRow key={name} name={name} color={Settings.theme.primary} data={{ content: content }} />
|
||||
))}
|
||||
</TableBody>
|
||||
</Table>
|
||||
</Paper>
|
||||
</Box>
|
||||
<CurrentBitNode />
|
||||
|
||||
{showBitNodeMults && (
|
||||
<Paper sx={{ p: 1, mb: 1 }}>
|
||||
<Typography variant="h5">BitNode Multipliers</Typography>
|
||||
<BitNodeMultipliersDisplay n={player.bitNodeN} />
|
||||
</Paper>
|
||||
)}
|
||||
|
||||
<MoneyModal open={moneyOpen} onClose={() => setMoneyOpen(false)} />
|
||||
<EmployersModal open={employersOpen} onClose={() => setEmployersOpen(false)} />
|
||||
</Container>
|
||||
|
@ -35,7 +35,7 @@ export function NSSelection(props: IProps): React.ReactElement {
|
||||
}
|
||||
|
||||
return (
|
||||
<Modal open={props.open} onClose={props.onClose}>
|
||||
<Modal open={props.open} onClose={props.onClose} sx={{ zIndex: 999999 }}>
|
||||
<Tabs variant="fullWidth" value={value} onChange={handleChange}>
|
||||
<Tab label="NS1" />
|
||||
<Tab label="NS2" />
|
||||
|
@ -18,10 +18,12 @@ import { Theme } from "@mui/material";
|
||||
import { findRunningScript } from "../../Script/ScriptHelpers";
|
||||
import { Player } from "../../Player";
|
||||
import { debounce } from "lodash";
|
||||
import { Settings } from "../../Settings/Settings";
|
||||
|
||||
let layerCounter = 0;
|
||||
|
||||
export const LogBoxEvents = new EventEmitter<[RunningScript]>();
|
||||
export const LogBoxCloserEvents = new EventEmitter<[number]>();
|
||||
export const LogBoxClearEvents = new EventEmitter<[]>();
|
||||
|
||||
interface Log {
|
||||
@ -50,6 +52,15 @@ export function LogBoxManager(): React.ReactElement {
|
||||
[],
|
||||
);
|
||||
|
||||
//Event used by ns.closeTail to close tail windows
|
||||
useEffect(
|
||||
() =>
|
||||
LogBoxCloserEvents.subscribe((pid: number) => {
|
||||
closePid(pid);
|
||||
}),
|
||||
[],
|
||||
);
|
||||
|
||||
useEffect(() =>
|
||||
LogBoxClearEvents.subscribe(() => {
|
||||
logs = [];
|
||||
@ -57,11 +68,18 @@ export function LogBoxManager(): React.ReactElement {
|
||||
}),
|
||||
);
|
||||
|
||||
//Close tail windows by their id
|
||||
function close(id: string): void {
|
||||
logs = logs.filter((l) => l.id !== id);
|
||||
rerender();
|
||||
}
|
||||
|
||||
//Close tail windows by their pid
|
||||
function closePid(pid: number): void {
|
||||
logs = logs.filter((log) => log.script.pid != pid);
|
||||
rerender();
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
{logs.map((log) => (
|
||||
@ -77,42 +95,18 @@ interface IProps {
|
||||
onClose: () => void;
|
||||
}
|
||||
|
||||
const useStyles = makeStyles((theme: Theme) =>
|
||||
const useStyles = makeStyles((_theme: Theme) =>
|
||||
createStyles({
|
||||
title: {
|
||||
"&.is-minimized + *": {
|
||||
border: "none",
|
||||
margin: 0,
|
||||
"max-height": 0,
|
||||
padding: 0,
|
||||
"pointer-events": "none",
|
||||
visibility: "hidden",
|
||||
},
|
||||
},
|
||||
logs: {
|
||||
overflowY: "scroll",
|
||||
overflowX: "hidden",
|
||||
scrollbarWidth: "auto",
|
||||
display: "flex",
|
||||
flexDirection: "column-reverse",
|
||||
whiteSpace: "pre-wrap",
|
||||
},
|
||||
titleButton: {
|
||||
padding: "1px 6px",
|
||||
},
|
||||
success: {
|
||||
color: theme.colors.success,
|
||||
},
|
||||
error: {
|
||||
color: theme.palette.error.main,
|
||||
},
|
||||
primary: {
|
||||
color: theme.palette.primary.main,
|
||||
},
|
||||
info: {
|
||||
color: theme.palette.info.main,
|
||||
},
|
||||
warning: {
|
||||
color: theme.palette.warning.main,
|
||||
padding: "1px 0",
|
||||
height: "100%",
|
||||
},
|
||||
}),
|
||||
);
|
||||
@ -190,20 +184,20 @@ function LogWindow(props: IProps): React.ReactElement {
|
||||
setMinimized(!minimized);
|
||||
}
|
||||
|
||||
function lineClass(s: string): string {
|
||||
function lineColor(s: string): string {
|
||||
if (s.match(/(^\[[^\]]+\] )?ERROR/) || s.match(/(^\[[^\]]+\] )?FAIL/)) {
|
||||
return classes.error;
|
||||
return Settings.theme.error;
|
||||
}
|
||||
if (s.match(/(^\[[^\]]+\] )?SUCCESS/)) {
|
||||
return classes.success;
|
||||
return Settings.theme.success;
|
||||
}
|
||||
if (s.match(/(^\[[^\]]+\] )?WARN/)) {
|
||||
return classes.warning;
|
||||
return Settings.theme.warning;
|
||||
}
|
||||
if (s.match(/(^\[[^\]]+\] )?INFO/)) {
|
||||
return classes.info;
|
||||
return Settings.theme.info;
|
||||
}
|
||||
return classes.primary;
|
||||
return Settings.theme.primary;
|
||||
}
|
||||
|
||||
// And trigger fakeDrag when the window is resized
|
||||
@ -242,74 +236,99 @@ function LogWindow(props: IProps): React.ReactElement {
|
||||
if (e.clientX < 0 || e.clientY < 0 || e.clientX > innerWidth || e.clientY > innerHeight) return false;
|
||||
};
|
||||
|
||||
// Max [width, height]
|
||||
const minConstraints: [number, number] = [250, 33];
|
||||
|
||||
return (
|
||||
<Draggable handle=".drag" onDrag={boundToBody} ref={rootRef}>
|
||||
<Paper
|
||||
style={{
|
||||
display: "flex",
|
||||
<Draggable handle=".drag" onDrag={boundToBody} ref={rootRef} onMouseDown={updateLayer}>
|
||||
<Box
|
||||
display="flex"
|
||||
sx={{
|
||||
flexFlow: "column",
|
||||
position: "fixed",
|
||||
left: "40%",
|
||||
top: "30%",
|
||||
zIndex: 1400,
|
||||
minWidth: `${minConstraints[0]}px`,
|
||||
minHeight: `${minConstraints[1]}px`,
|
||||
...(minimized
|
||||
? {
|
||||
border: "none",
|
||||
margin: 0,
|
||||
maxHeight: 0,
|
||||
padding: 0,
|
||||
}
|
||||
: {
|
||||
border: `1px solid ${Settings.theme.welllight}`,
|
||||
}),
|
||||
}}
|
||||
ref={container}
|
||||
>
|
||||
<div onMouseDown={updateLayer}>
|
||||
<Paper
|
||||
className={classes.title + " " + (minimized ? "is-minimized" : "")}
|
||||
style={{
|
||||
cursor: "grab",
|
||||
}}
|
||||
>
|
||||
<Box className="drag" display="flex" alignItems="center" ref={draggableRef}>
|
||||
<Typography color="primary" variant="h6" sx={{ marginRight: "auto" }} title={title(true)}>
|
||||
{title()}
|
||||
<ResizableBox
|
||||
height={500}
|
||||
width={500}
|
||||
minConstraints={minConstraints}
|
||||
handle={
|
||||
<span
|
||||
style={{
|
||||
position: "absolute",
|
||||
right: "-10px",
|
||||
bottom: "-16px",
|
||||
cursor: "nw-resize",
|
||||
display: minimized ? "none" : "inline-block",
|
||||
}}
|
||||
>
|
||||
<ArrowForwardIosIcon color="primary" style={{ transform: "rotate(45deg)", fontSize: "1.75rem" }} />
|
||||
</span>
|
||||
}
|
||||
>
|
||||
<>
|
||||
<Paper className="drag" sx={{ display: "flex", alignItems: "center", cursor: "grab" }} ref={draggableRef}>
|
||||
<Typography
|
||||
variant="h6"
|
||||
sx={{ marginRight: "auto", textOverflow: "ellipsis", whiteSpace: "nowrap", overflow: "hidden" }}
|
||||
title={title(true)}
|
||||
>
|
||||
{title(true)}
|
||||
</Typography>
|
||||
|
||||
{!workerScripts.has(script.pid) ? (
|
||||
<Button className={classes.titleButton} onClick={run} onTouchEnd={run}>
|
||||
Run
|
||||
<span style={{ minWidth: "fit-content", height: `${minConstraints[1]}px` }}>
|
||||
{!workerScripts.has(script.pid) ? (
|
||||
<Button className={classes.titleButton} onClick={run} onTouchEnd={run}>
|
||||
Run
|
||||
</Button>
|
||||
) : (
|
||||
<Button className={classes.titleButton} onClick={kill} onTouchEnd={kill}>
|
||||
Kill
|
||||
</Button>
|
||||
)}
|
||||
<Button className={classes.titleButton} onClick={minimize} onTouchEnd={minimize}>
|
||||
{minimized ? "\u{1F5D6}" : "\u{1F5D5}"}
|
||||
</Button>
|
||||
) : (
|
||||
<Button className={classes.titleButton} onClick={kill} onTouchEnd={kill}>
|
||||
Kill
|
||||
<Button className={classes.titleButton} onClick={props.onClose} onTouchEnd={props.onClose}>
|
||||
Close
|
||||
</Button>
|
||||
)}
|
||||
<Button className={classes.titleButton} onClick={minimize} onTouchEnd={minimize}>
|
||||
{minimized ? "\u{1F5D6}" : "\u{1F5D5}"}
|
||||
</Button>
|
||||
<Button className={classes.titleButton} onClick={props.onClose} onTouchEnd={props.onClose}>
|
||||
Close
|
||||
</Button>
|
||||
</Box>
|
||||
</Paper>
|
||||
<Paper sx={{ overflow: "scroll", overflowWrap: "break-word", whiteSpace: "pre-wrap" }}>
|
||||
<ResizableBox
|
||||
</span>
|
||||
</Paper>
|
||||
|
||||
<Paper
|
||||
className={classes.logs}
|
||||
height={500}
|
||||
width={500}
|
||||
minConstraints={[250, 30]}
|
||||
handle={
|
||||
<span style={{ position: "absolute", right: "-10px", bottom: "-13px", cursor: "nw-resize" }}>
|
||||
<ArrowForwardIosIcon color="primary" style={{ transform: "rotate(45deg)" }} />
|
||||
</span>
|
||||
}
|
||||
sx={{ height: `calc(100% - ${minConstraints[1]}px)`, display: minimized ? "none" : "flex" }}
|
||||
>
|
||||
<Box>
|
||||
<span style={{ display: "flex", flexDirection: "column" }}>
|
||||
{script.logs.map(
|
||||
(line: string, i: number): JSX.Element => (
|
||||
<Typography key={i} className={lineClass(line)}>
|
||||
<Typography key={i} sx={{ color: lineColor(line) }}>
|
||||
{line}
|
||||
<br />
|
||||
</Typography>
|
||||
),
|
||||
)}
|
||||
</Box>
|
||||
</ResizableBox>
|
||||
</Paper>
|
||||
</div>
|
||||
</Paper>
|
||||
</span>
|
||||
</Paper>
|
||||
</>
|
||||
</ResizableBox>
|
||||
</Box>
|
||||
</Draggable>
|
||||
);
|
||||
}
|
||||
|
@ -1,10 +1,11 @@
|
||||
import React from "react";
|
||||
import { Theme } from "@mui/material";
|
||||
import makeStyles from "@mui/styles/makeStyles";
|
||||
import createStyles from "@mui/styles/createStyles";
|
||||
import M from "@mui/material/Modal";
|
||||
import Fade from "@mui/material/Fade";
|
||||
import Box from "@mui/material/Box";
|
||||
import Fade from "@mui/material/Fade";
|
||||
import M from "@mui/material/Modal";
|
||||
import createStyles from "@mui/styles/createStyles";
|
||||
import makeStyles from "@mui/styles/makeStyles";
|
||||
import { SxProps } from "@mui/system";
|
||||
import React from "react";
|
||||
|
||||
const useStyles = makeStyles((theme: Theme) =>
|
||||
createStyles({
|
||||
@ -12,7 +13,6 @@ const useStyles = makeStyles((theme: Theme) =>
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
zIndex: 999999,
|
||||
},
|
||||
paper: {
|
||||
backgroundColor: theme.palette.background.default,
|
||||
@ -35,6 +35,7 @@ interface IProps {
|
||||
open: boolean;
|
||||
onClose: () => void;
|
||||
children: React.ReactNode;
|
||||
sx?: SxProps<Theme>;
|
||||
}
|
||||
|
||||
export const Modal = (props: IProps): React.ReactElement => {
|
||||
@ -49,6 +50,7 @@ export const Modal = (props: IProps): React.ReactElement => {
|
||||
onClose={props.onClose}
|
||||
closeAfterTransition
|
||||
className={classes.modal}
|
||||
sx={props.sx}
|
||||
>
|
||||
<Fade in={props.open}>
|
||||
<div className={classes.paper}>
|
||||
|
Loading…
Reference in New Issue
Block a user