mirror of
https://github.com/bitburner-official/bitburner-src.git
synced 2024-11-18 13:43:49 +01:00
CODEBASE: Follow-up for lint rules PR + address some eslint disables (#651)
This commit is contained in:
parent
bc00a1c134
commit
48e7bd6471
@ -1,5 +1,3 @@
|
||||
import type { PlayerObject } from "../PersonObjects/Player/PlayerObject";
|
||||
|
||||
import {
|
||||
AugmentationName,
|
||||
BlackOperationName,
|
||||
@ -69,24 +67,24 @@ function bitNodeFinishedState(): boolean {
|
||||
return Player.bladeburner !== null && BlackOperationName.OperationDaedalus in Player.bladeburner.blackops;
|
||||
}
|
||||
|
||||
function hasAccessToSF(player: PlayerObject, bn: number): boolean {
|
||||
return player.bitNodeN === bn || player.sourceFileLvl(bn) > 0;
|
||||
function hasAccessToSF(bn: number): boolean {
|
||||
return Player.bitNodeN === bn || Player.sourceFileLvl(bn) > 0;
|
||||
}
|
||||
|
||||
function knowsAboutBitverse(player: PlayerObject): boolean {
|
||||
return player.sourceFiles.size > 0;
|
||||
function knowsAboutBitverse(): boolean {
|
||||
return Player.sourceFiles.size > 0;
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
function sfAchievement(): Achievement[] {
|
||||
const achs: Achievement[] = [];
|
||||
for (let i = 0; i <= 11; i++) {
|
||||
for (let j = 1; j <= 3; j++) {
|
||||
achs.push({
|
||||
ID: `SF${i}.${j}`,
|
||||
Condition: () => Player.sourceFileLvl(i) >= j,
|
||||
});
|
||||
}
|
||||
function sfAchievements(): Record<string, Achievement> {
|
||||
const achs: Record<string, Achievement> = {};
|
||||
for (let i = 1; i <= 12; i++) {
|
||||
const ID = `SF${i}.1`;
|
||||
achs[ID] = {
|
||||
...achievementData[ID],
|
||||
Icon: ID,
|
||||
Visible: knowsAboutBitverse,
|
||||
Condition: () => Player.sourceFileLvl(i) >= 1,
|
||||
};
|
||||
}
|
||||
return achs;
|
||||
}
|
||||
@ -158,78 +156,7 @@ export const achievements: Record<string, Achievement> = {
|
||||
Icon: "formulas",
|
||||
Condition: () => Player.getHomeComputer().programs.includes(CompletedProgramName.formulas),
|
||||
},
|
||||
"SF1.1": {
|
||||
...achievementData["SF1.1"],
|
||||
Icon: "SF1.1",
|
||||
Visible: () => hasAccessToSF(Player, 1),
|
||||
Condition: () => Player.sourceFileLvl(1) >= 1,
|
||||
},
|
||||
"SF2.1": {
|
||||
...achievementData["SF2.1"],
|
||||
Icon: "SF2.1",
|
||||
Visible: () => hasAccessToSF(Player, 2),
|
||||
Condition: () => Player.sourceFileLvl(2) >= 1,
|
||||
},
|
||||
"SF3.1": {
|
||||
...achievementData["SF3.1"],
|
||||
Icon: "SF3.1",
|
||||
Visible: () => hasAccessToSF(Player, 3),
|
||||
Condition: () => Player.sourceFileLvl(3) >= 1,
|
||||
},
|
||||
"SF4.1": {
|
||||
...achievementData["SF4.1"],
|
||||
Icon: "SF4.1",
|
||||
Visible: () => hasAccessToSF(Player, 4),
|
||||
Condition: () => Player.sourceFileLvl(4) >= 1,
|
||||
},
|
||||
"SF5.1": {
|
||||
...achievementData["SF5.1"],
|
||||
Icon: "SF5.1",
|
||||
Visible: () => hasAccessToSF(Player, 5),
|
||||
Condition: () => Player.sourceFileLvl(5) >= 1,
|
||||
},
|
||||
"SF6.1": {
|
||||
...achievementData["SF6.1"],
|
||||
Icon: "SF6.1",
|
||||
Visible: () => hasAccessToSF(Player, 6),
|
||||
Condition: () => Player.sourceFileLvl(6) >= 1,
|
||||
},
|
||||
"SF7.1": {
|
||||
...achievementData["SF7.1"],
|
||||
Icon: "SF7.1",
|
||||
Visible: () => hasAccessToSF(Player, 7),
|
||||
Condition: () => Player.sourceFileLvl(7) >= 1,
|
||||
},
|
||||
"SF8.1": {
|
||||
...achievementData["SF8.1"],
|
||||
Icon: "SF8.1",
|
||||
Visible: () => hasAccessToSF(Player, 8),
|
||||
Condition: () => Player.sourceFileLvl(8) >= 1,
|
||||
},
|
||||
"SF9.1": {
|
||||
...achievementData["SF9.1"],
|
||||
Icon: "SF9.1",
|
||||
Visible: () => hasAccessToSF(Player, 9),
|
||||
Condition: () => Player.sourceFileLvl(9) >= 1,
|
||||
},
|
||||
"SF10.1": {
|
||||
...achievementData["SF10.1"],
|
||||
Icon: "SF10.1",
|
||||
Visible: () => hasAccessToSF(Player, 10),
|
||||
Condition: () => Player.sourceFileLvl(10) >= 1,
|
||||
},
|
||||
"SF11.1": {
|
||||
...achievementData["SF11.1"],
|
||||
Icon: "SF11.1",
|
||||
Visible: () => hasAccessToSF(Player, 11),
|
||||
Condition: () => Player.sourceFileLvl(11) >= 1,
|
||||
},
|
||||
"SF12.1": {
|
||||
...achievementData["SF12.1"],
|
||||
Icon: "SF12.1",
|
||||
Visible: () => hasAccessToSF(Player, 12),
|
||||
Condition: () => Player.sourceFileLvl(12) >= 1,
|
||||
},
|
||||
...sfAchievements(),
|
||||
MONEY_1Q: {
|
||||
...achievementData.MONEY_1Q,
|
||||
Icon: "$1Q",
|
||||
@ -410,25 +337,25 @@ export const achievements: Record<string, Achievement> = {
|
||||
GANG: {
|
||||
...achievementData.GANG,
|
||||
Icon: "GANG",
|
||||
Visible: () => hasAccessToSF(Player, 2),
|
||||
Visible: () => hasAccessToSF(2),
|
||||
Condition: () => Player.gang !== null,
|
||||
},
|
||||
FULL_GANG: {
|
||||
...achievementData.FULL_GANG,
|
||||
Icon: "GANGMAX",
|
||||
Visible: () => hasAccessToSF(Player, 2),
|
||||
Visible: () => hasAccessToSF(2),
|
||||
Condition: () => Player.gang !== null && Player.gang.members.length === GangConstants.MaximumGangMembers,
|
||||
},
|
||||
GANG_TERRITORY: {
|
||||
...achievementData.GANG_TERRITORY,
|
||||
Icon: "GANG100%",
|
||||
Visible: () => hasAccessToSF(Player, 2),
|
||||
Visible: () => hasAccessToSF(2),
|
||||
Condition: () => Player.gang !== null && AllGangs[Player.gang.facName].territory >= 0.999,
|
||||
},
|
||||
GANG_MEMBER_POWER: {
|
||||
...achievementData.GANG_MEMBER_POWER,
|
||||
Icon: "GANG10000",
|
||||
Visible: () => hasAccessToSF(Player, 2),
|
||||
Visible: () => hasAccessToSF(2),
|
||||
Condition: () =>
|
||||
Player.gang !== null &&
|
||||
Player.gang.members.some(
|
||||
@ -439,19 +366,19 @@ export const achievements: Record<string, Achievement> = {
|
||||
CORPORATION: {
|
||||
...achievementData.CORPORATION,
|
||||
Icon: "CORP",
|
||||
Visible: () => hasAccessToSF(Player, 3),
|
||||
Visible: () => hasAccessToSF(3),
|
||||
Condition: () => Player.corporation !== null,
|
||||
},
|
||||
CORPORATION_BRIBE: {
|
||||
...achievementData.CORPORATION_BRIBE,
|
||||
Icon: "CORPLOBBY",
|
||||
Visible: () => hasAccessToSF(Player, 3),
|
||||
Visible: () => hasAccessToSF(3),
|
||||
Condition: () => !!Player.corporation && Player.corporation.unlocks.has(CorpUnlockName.GovernmentPartnership),
|
||||
},
|
||||
CORPORATION_PROD_1000: {
|
||||
...achievementData.CORPORATION_PROD_1000,
|
||||
Icon: "CORP1000",
|
||||
Visible: () => hasAccessToSF(Player, 3),
|
||||
Visible: () => hasAccessToSF(3),
|
||||
Condition: () => {
|
||||
if (!Player.corporation) return false;
|
||||
for (const division of Player.corporation.divisions.values()) {
|
||||
@ -463,7 +390,7 @@ export const achievements: Record<string, Achievement> = {
|
||||
CORPORATION_EMPLOYEE_3000: {
|
||||
...achievementData.CORPORATION_EMPLOYEE_3000,
|
||||
Icon: "CORPCITY",
|
||||
Visible: () => hasAccessToSF(Player, 3),
|
||||
Visible: () => hasAccessToSF(3),
|
||||
Condition: (): boolean => {
|
||||
if (!Player.corporation) return false;
|
||||
for (const division of Player.corporation.divisions.values()) {
|
||||
@ -478,7 +405,7 @@ export const achievements: Record<string, Achievement> = {
|
||||
Icon: "CORPRE",
|
||||
Name: "Own the land",
|
||||
Description: "Expand to the Real Estate division.",
|
||||
Visible: () => hasAccessToSF(Player, 3),
|
||||
Visible: () => hasAccessToSF(3),
|
||||
Condition: () => {
|
||||
if (!Player.corporation) return false;
|
||||
for (const division of Player.corporation.divisions.values()) {
|
||||
@ -490,19 +417,19 @@ export const achievements: Record<string, Achievement> = {
|
||||
INTELLIGENCE_255: {
|
||||
...achievementData.INTELLIGENCE_255,
|
||||
Icon: "INT255",
|
||||
Visible: () => hasAccessToSF(Player, 5),
|
||||
Visible: () => hasAccessToSF(5),
|
||||
Condition: () => Player.skills.intelligence >= 255,
|
||||
},
|
||||
BLADEBURNER_DIVISION: {
|
||||
...achievementData.BLADEBURNER_DIVISION,
|
||||
Icon: "BLADE",
|
||||
Visible: () => hasAccessToSF(Player, 6),
|
||||
Visible: () => hasAccessToSF(6),
|
||||
Condition: () => Player.bladeburner !== null,
|
||||
},
|
||||
BLADEBURNER_OVERCLOCK: {
|
||||
...achievementData.BLADEBURNER_OVERCLOCK,
|
||||
Icon: "BLADEOVERCLOCK",
|
||||
Visible: () => hasAccessToSF(Player, 6),
|
||||
Visible: () => hasAccessToSF(6),
|
||||
Condition: () =>
|
||||
Player.bladeburner !== null &&
|
||||
Player.bladeburner.skills[SkillNames.Overclock] === Skills[SkillNames.Overclock].maxLvl,
|
||||
@ -510,7 +437,7 @@ export const achievements: Record<string, Achievement> = {
|
||||
BLADEBURNER_UNSPENT_100000: {
|
||||
...achievementData.BLADEBURNER_UNSPENT_100000,
|
||||
Icon: "BLADE100K",
|
||||
Visible: () => hasAccessToSF(Player, 6),
|
||||
Visible: () => hasAccessToSF(6),
|
||||
Condition: () => Player.bladeburner !== null && Player.bladeburner.skillPoints >= 100000,
|
||||
},
|
||||
"4S": {
|
||||
@ -521,21 +448,21 @@ export const achievements: Record<string, Achievement> = {
|
||||
FIRST_HACKNET_SERVER: {
|
||||
...achievementData.FIRST_HACKNET_SERVER,
|
||||
Icon: "HASHNET",
|
||||
Visible: () => hasAccessToSF(Player, 9),
|
||||
Visible: () => hasAccessToSF(9),
|
||||
Condition: () => hasHacknetServers() && Player.hacknetNodes.length > 0,
|
||||
AdditionalUnlock: [achievementData.FIRST_HACKNET_NODE.ID],
|
||||
},
|
||||
ALL_HACKNET_SERVER: {
|
||||
...achievementData.ALL_HACKNET_SERVER,
|
||||
Icon: "HASHNETALL",
|
||||
Visible: () => hasAccessToSF(Player, 9),
|
||||
Visible: () => hasAccessToSF(9),
|
||||
Condition: () => hasHacknetServers() && Player.hacknetNodes.length === HacknetServerConstants.MaxServers,
|
||||
AdditionalUnlock: [achievementData["30_HACKNET_NODE"].ID],
|
||||
},
|
||||
MAX_HACKNET_SERVER: {
|
||||
...achievementData.MAX_HACKNET_SERVER,
|
||||
Icon: "HASHNETALL",
|
||||
Visible: () => hasAccessToSF(Player, 9),
|
||||
Visible: () => hasAccessToSF(9),
|
||||
Condition: (): boolean => {
|
||||
if (!hasHacknetServers()) return false;
|
||||
for (const h of Player.hacknetNodes) {
|
||||
@ -557,14 +484,14 @@ export const achievements: Record<string, Achievement> = {
|
||||
HACKNET_SERVER_1B: {
|
||||
...achievementData.HACKNET_SERVER_1B,
|
||||
Icon: "HASHNETMONEY",
|
||||
Visible: () => hasAccessToSF(Player, 9),
|
||||
Visible: () => hasAccessToSF(9),
|
||||
Condition: () => hasHacknetServers() && Player.moneySourceB.hacknet >= 1e9,
|
||||
AdditionalUnlock: [achievementData.HACKNET_NODE_10M.ID],
|
||||
},
|
||||
MAX_CACHE: {
|
||||
...achievementData.MAX_CACHE,
|
||||
Icon: "HASHNETCAP",
|
||||
Visible: () => hasAccessToSF(Player, 9),
|
||||
Visible: () => hasAccessToSF(9),
|
||||
Condition: () =>
|
||||
hasHacknetServers() &&
|
||||
Player.hashManager.hashes === Player.hashManager.capacity &&
|
||||
@ -573,13 +500,13 @@ export const achievements: Record<string, Achievement> = {
|
||||
SLEEVE_8: {
|
||||
...achievementData.SLEEVE_8,
|
||||
Icon: "SLEEVE8",
|
||||
Visible: () => hasAccessToSF(Player, 10),
|
||||
Visible: () => hasAccessToSF(10),
|
||||
Condition: () => Player.sleeves.length === 8 && Player.sourceFileLvl(10) === 3,
|
||||
},
|
||||
INDECISIVE: {
|
||||
...achievementData.INDECISIVE,
|
||||
Icon: "1H",
|
||||
Visible: () => knowsAboutBitverse(Player),
|
||||
Visible: knowsAboutBitverse,
|
||||
Condition: (function () {
|
||||
let c = 0;
|
||||
setInterval(() => {
|
||||
@ -595,13 +522,13 @@ export const achievements: Record<string, Achievement> = {
|
||||
FAST_BN: {
|
||||
...achievementData.FAST_BN,
|
||||
Icon: "2DAYS",
|
||||
Visible: () => knowsAboutBitverse(Player),
|
||||
Visible: knowsAboutBitverse,
|
||||
Condition: () => bitNodeFinishedState() && Player.playtimeSinceLastBitnode < 1000 * 60 * 60 * 24 * 2,
|
||||
},
|
||||
CHALLENGE_BN1: {
|
||||
...achievementData.CHALLENGE_BN1,
|
||||
Icon: "BN1+",
|
||||
Visible: () => knowsAboutBitverse(Player),
|
||||
Visible: knowsAboutBitverse,
|
||||
Condition: () =>
|
||||
Player.bitNodeN === 1 &&
|
||||
bitNodeFinishedState() &&
|
||||
@ -611,37 +538,37 @@ export const achievements: Record<string, Achievement> = {
|
||||
CHALLENGE_BN2: {
|
||||
...achievementData.CHALLENGE_BN2,
|
||||
Icon: "BN2+",
|
||||
Visible: () => hasAccessToSF(Player, 2),
|
||||
Visible: () => hasAccessToSF(2),
|
||||
Condition: () => Player.bitNodeN === 2 && bitNodeFinishedState() && Player.gang === null,
|
||||
},
|
||||
CHALLENGE_BN3: {
|
||||
...achievementData.CHALLENGE_BN3,
|
||||
Icon: "BN3+",
|
||||
Visible: () => hasAccessToSF(Player, 3),
|
||||
Visible: () => hasAccessToSF(3),
|
||||
Condition: () => Player.bitNodeN === 3 && bitNodeFinishedState() && Player.corporation === null,
|
||||
},
|
||||
CHALLENGE_BN6: {
|
||||
...achievementData.CHALLENGE_BN6,
|
||||
Icon: "BN6+",
|
||||
Visible: () => hasAccessToSF(Player, 6),
|
||||
Visible: () => hasAccessToSF(6),
|
||||
Condition: () => Player.bitNodeN === 6 && bitNodeFinishedState() && Player.bladeburner === null,
|
||||
},
|
||||
CHALLENGE_BN7: {
|
||||
...achievementData.CHALLENGE_BN7,
|
||||
Icon: "BN7+",
|
||||
Visible: () => hasAccessToSF(Player, 7),
|
||||
Visible: () => hasAccessToSF(7),
|
||||
Condition: () => Player.bitNodeN === 7 && bitNodeFinishedState() && Player.bladeburner === null,
|
||||
},
|
||||
CHALLENGE_BN8: {
|
||||
...achievementData.CHALLENGE_BN8,
|
||||
Icon: "BN8+",
|
||||
Visible: () => hasAccessToSF(Player, 8),
|
||||
Visible: () => hasAccessToSF(8),
|
||||
Condition: () => Player.bitNodeN === 8 && bitNodeFinishedState() && !Player.has4SData && !Player.has4SDataTixApi,
|
||||
},
|
||||
CHALLENGE_BN9: {
|
||||
...achievementData.CHALLENGE_BN9,
|
||||
Icon: "BN9+",
|
||||
Visible: () => hasAccessToSF(Player, 9),
|
||||
Visible: () => hasAccessToSF(9),
|
||||
Condition: () =>
|
||||
Player.bitNodeN === 9 &&
|
||||
bitNodeFinishedState() &&
|
||||
@ -651,7 +578,7 @@ export const achievements: Record<string, Achievement> = {
|
||||
CHALLENGE_BN10: {
|
||||
...achievementData.CHALLENGE_BN10,
|
||||
Icon: "BN10+",
|
||||
Visible: () => hasAccessToSF(Player, 10),
|
||||
Visible: () => hasAccessToSF(10),
|
||||
Condition: () =>
|
||||
Player.bitNodeN === 10 &&
|
||||
bitNodeFinishedState() &&
|
||||
@ -669,7 +596,7 @@ export const achievements: Record<string, Achievement> = {
|
||||
CHALLENGE_BN12: {
|
||||
...achievementData.CHALLENGE_BN12,
|
||||
Icon: "BN12+",
|
||||
Visible: () => hasAccessToSF(Player, 12),
|
||||
Visible: () => hasAccessToSF(12),
|
||||
Condition: () => Player.sourceFileLvl(12) >= 50,
|
||||
},
|
||||
BYPASS: {
|
||||
@ -730,7 +657,7 @@ export const achievements: Record<string, Achievement> = {
|
||||
CHALLENGE_BN13: {
|
||||
...achievementData.CHALLENGE_BN13,
|
||||
Icon: "BN13+",
|
||||
Visible: () => hasAccessToSF(Player, 13),
|
||||
Visible: () => hasAccessToSF(13),
|
||||
Condition: () =>
|
||||
Player.bitNodeN === 13 &&
|
||||
bitNodeFinishedState() &&
|
||||
|
@ -184,14 +184,12 @@ export class Action {
|
||||
return Math.ceil(baseTime * this.getActionTimePenalty());
|
||||
}
|
||||
|
||||
// For actions that have teams. To be implemented by subtypes.
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
getTeamSuccessBonus(inst: Bladeburner): number {
|
||||
// Subtypes of Action implement these differently
|
||||
getTeamSuccessBonus(__inst: Bladeburner): number {
|
||||
return 1;
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
getActionTypeSkillSuccessBonus(inst: Bladeburner): number {
|
||||
getActionTypeSkillSuccessBonus(__inst: Bladeburner): number {
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { Box, Paper, Typography } from "@mui/material";
|
||||
import React, { useEffect, useRef, useState } from "react";
|
||||
import React, { useEffect, useState } from "react";
|
||||
import { AugmentationName } from "@enums";
|
||||
import { Player } from "@player";
|
||||
import { KEY } from "../../utils/helpers/keyCodes";
|
||||
@ -25,11 +25,35 @@ const difficulties: {
|
||||
Impossible: { window: 150 },
|
||||
};
|
||||
|
||||
export function SlashGame({ difficulty: _difficulty, onSuccess, onFailure }: IMinigameProps): React.ReactElement {
|
||||
const difficulty: Difficulty = { window: 0 };
|
||||
interpolate(difficulties, _difficulty, difficulty);
|
||||
|
||||
export function SlashGame({ difficulty, onSuccess, onFailure }: IMinigameProps): React.ReactElement {
|
||||
const [phase, setPhase] = useState(0);
|
||||
const [hasAugment, setHasAugment] = useState(false);
|
||||
const [guardingTime, setGuardingTime] = useState(0);
|
||||
|
||||
useEffect(() => {
|
||||
// Determine timeframes for game phase changes
|
||||
const newDifficulty: Difficulty = { window: 0 };
|
||||
interpolate(difficulties, difficulty, newDifficulty);
|
||||
const timePreparing = newDifficulty.window;
|
||||
const timeAttacking = 250;
|
||||
const timeGuarding = Math.random() * 3250 + 1500 - (timeAttacking + timePreparing);
|
||||
|
||||
// Set initial game state
|
||||
setPhase(0);
|
||||
setGuardingTime(timeGuarding);
|
||||
setHasAugment(Player.hasAugmentation(AugmentationName.MightOfAres, true));
|
||||
|
||||
// Setup timer for game phases
|
||||
let id = setTimeout(() => {
|
||||
setPhase(1);
|
||||
id = setTimeout(() => {
|
||||
setPhase(2);
|
||||
id = setTimeout(() => onFailure(), timeAttacking);
|
||||
}, timePreparing);
|
||||
}, timeGuarding);
|
||||
|
||||
return () => clearTimeout(id);
|
||||
}, [difficulty, onSuccess, onFailure]);
|
||||
|
||||
function press(this: Document, event: KeyboardEvent): void {
|
||||
event.preventDefault();
|
||||
@ -41,39 +65,16 @@ export function SlashGame({ difficulty: _difficulty, onSuccess, onFailure }: IMi
|
||||
}
|
||||
}
|
||||
|
||||
const guardingTimeRef = useRef(Math.random() * 3250 + 1500 - (250 + difficulty.window));
|
||||
|
||||
useEffect(() => {
|
||||
const preparingTime = difficulty.window;
|
||||
const attackingTime = 250;
|
||||
|
||||
let id = window.setTimeout(() => {
|
||||
setPhase(1);
|
||||
id = window.setTimeout(() => {
|
||||
setPhase(2);
|
||||
id = window.setTimeout(() => onFailure(), attackingTime);
|
||||
}, preparingTime);
|
||||
}, guardingTimeRef.current);
|
||||
|
||||
return () => {
|
||||
clearInterval(id);
|
||||
};
|
||||
}, [difficulty.window, onFailure]);
|
||||
|
||||
const hasAugment = Player.hasAugmentation(AugmentationName.MightOfAres, true);
|
||||
return (
|
||||
<>
|
||||
<GameTimer millis={5000} onExpire={onFailure} />
|
||||
<Paper sx={{ display: "grid", justifyItems: "center" }}>
|
||||
<Typography variant="h4">Attack when his guard is down!</Typography>
|
||||
|
||||
{hasAugment ? (
|
||||
{hasAugment && (
|
||||
<Box sx={{ my: 1 }}>
|
||||
<Typography variant="h5">Guard will drop in...</Typography>
|
||||
<GameTimer millis={guardingTimeRef.current} onExpire={() => null} ignoreAugment_WKSharmonizer noPaper />
|
||||
<GameTimer millis={guardingTime} onExpire={() => null} ignoreAugment_WKSharmonizer noPaper />
|
||||
</Box>
|
||||
) : (
|
||||
<></>
|
||||
)}
|
||||
|
||||
{phase === 0 && <Typography variant="h4">Guarding ...</Typography>}
|
||||
|
@ -1,4 +1,4 @@
|
||||
import React, { useEffect, useState, useRef } from "react";
|
||||
import React, { useEffect, useState } from "react";
|
||||
|
||||
import { Box, Paper, Typography } from "@mui/material";
|
||||
import { AugmentationName } from "@enums";
|
||||
@ -10,6 +10,7 @@ import { interpolate } from "./Difficulty";
|
||||
import { GameTimer } from "./GameTimer";
|
||||
import { IMinigameProps } from "./IMinigameProps";
|
||||
import { KeyHandler } from "./KeyHandler";
|
||||
import { isPositiveInteger } from "../../types";
|
||||
|
||||
interface Difficulty {
|
||||
[key: string]: number;
|
||||
@ -43,7 +44,7 @@ const colorNames: Record<string, string> = {
|
||||
};
|
||||
|
||||
interface Wire {
|
||||
tpe: string;
|
||||
wireType: string;
|
||||
colors: string[];
|
||||
}
|
||||
|
||||
@ -52,55 +53,66 @@ interface Question {
|
||||
shouldCut: (wire: Wire, index: number) => boolean;
|
||||
}
|
||||
|
||||
export function WireCuttingGame({ onSuccess, onFailure, ...otherProps }: IMinigameProps): React.ReactElement {
|
||||
const difficulty: Difficulty = {
|
||||
timer: 0,
|
||||
wiresmin: 0,
|
||||
wiresmax: 0,
|
||||
rules: 0,
|
||||
};
|
||||
interpolate(difficulties, otherProps.difficulty, difficulty);
|
||||
const timer = difficulty.timer;
|
||||
const wiresRef = useRef(generateWires(difficulty));
|
||||
const questionsRef = useRef(generateQuestion(wiresRef.current, difficulty));
|
||||
export function WireCuttingGame({ onSuccess, onFailure, difficulty }: IMinigameProps): React.ReactElement {
|
||||
const [questions, setQuestions] = useState<Question[]>([]);
|
||||
const [wires, setWires] = useState<Wire[]>([]);
|
||||
const [timer, setTimer] = useState(0);
|
||||
const [cutWires, setCutWires] = useState<boolean[]>([]);
|
||||
const [wiresToCut, setWiresToCut] = useState(new Set<number>());
|
||||
const [hasAugment, setHasAugment] = useState(false);
|
||||
|
||||
const [cutWires, setCutWires] = useState(new Array(wiresRef.current.length).fill(false));
|
||||
const hasAugment = Player.hasAugmentation(AugmentationName.KnowledgeOfApollo, true);
|
||||
|
||||
// TODO: refactor, move the code from this effect to a `press` function
|
||||
useEffect(() => {
|
||||
// check if we won
|
||||
const wiresToBeCut = [];
|
||||
for (let j = 0; j < wiresRef.current.length; j++) {
|
||||
let shouldBeCut = false;
|
||||
for (let i = 0; i < questionsRef.current.length; i++) {
|
||||
shouldBeCut = shouldBeCut || questionsRef.current[i].shouldCut(wiresRef.current[j], j);
|
||||
}
|
||||
wiresToBeCut.push(shouldBeCut);
|
||||
}
|
||||
if (wiresToBeCut.every((b, i) => b === cutWires[i])) {
|
||||
onSuccess();
|
||||
}
|
||||
}, [cutWires, onSuccess]);
|
||||
// Determine game difficulty
|
||||
const gameDifficulty: Difficulty = {
|
||||
timer: 0,
|
||||
wiresmin: 0,
|
||||
wiresmax: 0,
|
||||
rules: 0,
|
||||
};
|
||||
interpolate(difficulties, difficulty, gameDifficulty);
|
||||
|
||||
function checkWire(wireNum: number): boolean {
|
||||
return questionsRef.current.some((q) => q.shouldCut(wiresRef.current[wireNum - 1], wireNum - 1));
|
||||
}
|
||||
// Calculate initial game data
|
||||
const gameWires = generateWires(gameDifficulty);
|
||||
const gameQuestions = generateQuestion(gameWires, gameDifficulty);
|
||||
const gameWiresToCut = new Set<number>();
|
||||
gameWires.forEach((wire, index) => {
|
||||
for (const question of gameQuestions) {
|
||||
if (question.shouldCut(wire, index)) {
|
||||
gameWiresToCut.add(index);
|
||||
return; // go to next wire
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Initialize the game state
|
||||
setTimer(gameDifficulty.timer);
|
||||
setWires(gameWires);
|
||||
setCutWires(gameWires.map((__) => false));
|
||||
setQuestions(gameQuestions);
|
||||
setWiresToCut(gameWiresToCut);
|
||||
setHasAugment(Player.hasAugmentation(AugmentationName.KnowledgeOfApollo, true));
|
||||
}, [difficulty]);
|
||||
|
||||
function press(this: Document, event: KeyboardEvent): void {
|
||||
event.preventDefault();
|
||||
const wireNum = parseInt(event.key);
|
||||
if (!isPositiveInteger(wireNum) || wireNum > wires.length) return;
|
||||
|
||||
if (wireNum < 1 || wireNum > wiresRef.current.length || isNaN(wireNum)) return;
|
||||
setCutWires((old) => {
|
||||
const next = [...old];
|
||||
next[wireNum - 1] = true;
|
||||
if (!checkWire(wireNum)) {
|
||||
onFailure();
|
||||
}
|
||||
const wireIndex = wireNum - 1;
|
||||
if (cutWires[wireIndex]) return;
|
||||
|
||||
return next;
|
||||
});
|
||||
// Check if game has been lost
|
||||
if (!wiresToCut.has(wireIndex)) return onFailure();
|
||||
|
||||
// Check if game has been won
|
||||
const newWiresToCut = new Set(wiresToCut);
|
||||
newWiresToCut.delete(wireIndex);
|
||||
if (newWiresToCut.size === 0) return onSuccess();
|
||||
|
||||
// Rerender with new state if game has not been won or lost yet
|
||||
const newCutWires = cutWires.map((old, i) => (i === wireIndex ? true : old));
|
||||
setWiresToCut(newWiresToCut);
|
||||
setCutWires(newCutWires);
|
||||
}
|
||||
|
||||
return (
|
||||
@ -110,19 +122,19 @@ export function WireCuttingGame({ onSuccess, onFailure, ...otherProps }: IMiniga
|
||||
<Typography variant="h4" sx={{ width: "75%", textAlign: "center" }}>
|
||||
Cut the wires with the following properties! (keyboard 1 to 9)
|
||||
</Typography>
|
||||
{questionsRef.current.map((question, i) => (
|
||||
{questions.map((question, i) => (
|
||||
<Typography key={i}>{question.toString()}</Typography>
|
||||
))}
|
||||
<Box
|
||||
sx={{
|
||||
display: "grid",
|
||||
gridTemplateColumns: `repeat(${wiresRef.current.length}, 1fr)`,
|
||||
gridTemplateColumns: `repeat(${wires.length}, 1fr)`,
|
||||
columnGap: 3,
|
||||
justifyItems: "center",
|
||||
}}
|
||||
>
|
||||
{Array.from({ length: wiresRef.current.length }).map((_, i) => {
|
||||
const isCorrectWire = checkWire(i + 1);
|
||||
{Array.from({ length: wires.length }).map((_, i) => {
|
||||
const isCorrectWire = cutWires[i + 1] || wiresToCut.has(i + 1);
|
||||
const color = hasAugment && !isCorrectWire ? Settings.theme.disabled : Settings.theme.primary;
|
||||
return (
|
||||
<Typography key={i} style={{ color: color }}>
|
||||
@ -132,16 +144,16 @@ export function WireCuttingGame({ onSuccess, onFailure, ...otherProps }: IMiniga
|
||||
})}
|
||||
{new Array(8).fill(0).map((_, i) => (
|
||||
<React.Fragment key={i}>
|
||||
{wiresRef.current.map((wire, j) => {
|
||||
{wires.map((wire, j) => {
|
||||
if ((i === 3 || i === 4) && cutWires[j]) {
|
||||
return <Typography key={j}></Typography>;
|
||||
}
|
||||
const isCorrectWire = checkWire(j + 1);
|
||||
const isCorrectWire = cutWires[j + 1] || wiresToCut.has(j + 1);
|
||||
const wireColor =
|
||||
hasAugment && !isCorrectWire ? Settings.theme.disabled : wire.colors[i % wire.colors.length];
|
||||
return (
|
||||
<Typography key={j} style={{ color: wireColor }}>
|
||||
|{wire.tpe}|
|
||||
|{wire.wireType}|
|
||||
</Typography>
|
||||
);
|
||||
})}
|
||||
@ -198,7 +210,7 @@ function generateWires(difficulty: Difficulty): Wire[] {
|
||||
wireColors.push(colors[Math.floor(Math.random() * colors.length)]);
|
||||
}
|
||||
wires.push({
|
||||
tpe: types[Math.floor(Math.random() * types.length)],
|
||||
wireType: types[Math.floor(Math.random() * types.length)],
|
||||
colors: wireColors,
|
||||
});
|
||||
}
|
||||
|
@ -36,7 +36,7 @@ import { getHospitalizationCost } from "../../Hospital/Hospital";
|
||||
import { HacknetServer } from "../../Hacknet/HacknetServer";
|
||||
|
||||
import { formatMoney } from "../../ui/formatNumber";
|
||||
import { MoneySourceTracker } from "../../utils/MoneySourceTracker";
|
||||
import { MoneySource, MoneySourceTracker } from "../../utils/MoneySourceTracker";
|
||||
import { dialogBoxCreate } from "../../ui/React/DialogBox";
|
||||
|
||||
import { SnackbarEvents } from "../../ui/React/Snackbar";
|
||||
@ -183,7 +183,7 @@ export function setMoney(this: PlayerObject, money: number): void {
|
||||
this.money = money;
|
||||
}
|
||||
|
||||
export function gainMoney(this: PlayerObject, money: number, source: string): void {
|
||||
export function gainMoney(this: PlayerObject, money: number, source: MoneySource): void {
|
||||
if (isNaN(money)) {
|
||||
console.error("NaN passed into Player.gainMoney()");
|
||||
return;
|
||||
@ -193,7 +193,7 @@ export function gainMoney(this: PlayerObject, money: number, source: string): vo
|
||||
this.recordMoneySource(money, source);
|
||||
}
|
||||
|
||||
export function loseMoney(this: PlayerObject, money: number, source: string): void {
|
||||
export function loseMoney(this: PlayerObject, money: number, source: MoneySource): void {
|
||||
if (isNaN(money)) {
|
||||
console.error("NaN passed into Player.loseMoney()");
|
||||
return;
|
||||
@ -211,7 +211,7 @@ export function canAfford(this: PlayerObject, cost: number): boolean {
|
||||
return this.money >= cost;
|
||||
}
|
||||
|
||||
export function recordMoneySource(this: PlayerObject, amt: number, source: string): void {
|
||||
export function recordMoneySource(this: PlayerObject, amt: number, source: MoneySource): void {
|
||||
if (!(this.moneySourceA instanceof MoneySourceTracker)) {
|
||||
console.warn(`Player.moneySourceA was not properly initialized. Resetting`);
|
||||
this.moneySourceA = new MoneySourceTracker();
|
||||
@ -1101,7 +1101,6 @@ export function gainCodingContractReward(
|
||||
): string {
|
||||
if (!reward) return `No reward for this contract`;
|
||||
|
||||
/* eslint-disable no-case-declarations */
|
||||
switch (reward.type) {
|
||||
case CodingContractRewardType.FactionReputation: {
|
||||
if (!Factions[reward.name]) {
|
||||
@ -1152,7 +1151,6 @@ export function gainCodingContractReward(
|
||||
return `Gained ${formatMoney(moneyGain)}`;
|
||||
}
|
||||
}
|
||||
/* eslint-enable no-case-declarations */
|
||||
}
|
||||
|
||||
export function travel(this: PlayerObject, to: CityName): boolean {
|
||||
|
@ -1,12 +1,12 @@
|
||||
import React, { useEffect } from "react";
|
||||
import { find } from "lodash";
|
||||
|
||||
import { Box, Typography, Button, Container, Paper } from "@mui/material";
|
||||
import { Check, Lock, Create } from "@mui/icons-material";
|
||||
|
||||
import { Player } from "@player";
|
||||
import { CompletedProgramName } from "@enums";
|
||||
import { Router } from "../../ui/GameRoot";
|
||||
import { Page } from "../../ui/Router";
|
||||
import { Player } from "@player";
|
||||
import { Settings } from "../../Settings/Settings";
|
||||
|
||||
import { Programs } from "../Programs";
|
||||
@ -22,7 +22,7 @@ export function ProgramsRoot(): React.ReactElement {
|
||||
.filter((prog) => {
|
||||
const create = prog.create;
|
||||
if (create === null) return false;
|
||||
if (prog.name === "b1t_flum3.exe") {
|
||||
if (prog.name === CompletedProgramName.bitFlume) {
|
||||
return create.req();
|
||||
}
|
||||
return true;
|
||||
@ -37,8 +37,7 @@ export function ProgramsRoot(): React.ReactElement {
|
||||
programs.forEach((p) => {
|
||||
ProgramsSeen.add(p.name);
|
||||
});
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, []);
|
||||
});
|
||||
|
||||
const getHackingLevelRemaining = (lvl: number): number => {
|
||||
return Math.ceil(Math.max(lvl - (Player.skills.hacking + Player.skills.intelligence / 2), 0));
|
||||
|
@ -60,7 +60,7 @@ const RotatedDoubleArrowIcon = React.forwardRef(function RotatedDoubleArrowIcon(
|
||||
props: { color: "primary" | "secondary" | "error" },
|
||||
__ref: React.ForwardedRef<SVGSVGElement>,
|
||||
) {
|
||||
return <DoubleArrowIcon color={props.color} style={{ transform: "rotate(-90deg)" }} ref={__ref} />;
|
||||
return <DoubleArrowIcon {...props} style={{ transform: "rotate(-90deg)" }} ref={__ref} />;
|
||||
});
|
||||
|
||||
const openedMixin = (theme: Theme): CSSObject => ({
|
||||
|
@ -1,3 +1,5 @@
|
||||
import type { MoneySource } from "../utils/MoneySourceTracker";
|
||||
|
||||
import { Person } from "../PersonObjects/Person";
|
||||
import { Player } from "@player";
|
||||
import { Multipliers } from "../PersonObjects/Multipliers";
|
||||
@ -59,7 +61,12 @@ export const scaleWorkStats = (w: WorkStats, n: number, scaleMoney = true): Work
|
||||
};
|
||||
};
|
||||
|
||||
export const applyWorkStats = (target: Person, workStats: WorkStats, cycles: number, source: string): WorkStats => {
|
||||
export const applyWorkStats = (
|
||||
target: Person,
|
||||
workStats: WorkStats,
|
||||
cycles: number,
|
||||
source: MoneySource,
|
||||
): WorkStats => {
|
||||
const expStats = applyWorkStatsExp(target, workStats, cycles);
|
||||
const gains = {
|
||||
money: workStats.money * cycles,
|
||||
|
@ -3,7 +3,7 @@ export type Integer = number & { __Integer: true };
|
||||
export type PositiveNumber = number & { __Positive: true };
|
||||
export type PositiveInteger = Integer & PositiveNumber;
|
||||
|
||||
// Numeric typechecking functions
|
||||
// Numeric typechecking functions - these should be moved somewhere else
|
||||
export const isInteger = (n: unknown): n is Integer => Number.isInteger(n);
|
||||
export const isPositiveInteger = (n: unknown): n is PositiveInteger => isInteger(n) && n > 0;
|
||||
|
||||
@ -16,6 +16,9 @@ export type Unknownify<T> = {
|
||||
/** Get the member type of either an array or an object */
|
||||
export type Member<T> = T extends (infer arrayMember)[] ? arrayMember : T[keyof T];
|
||||
|
||||
//** Get the keys of an object where the values match a given type */
|
||||
export type TypedKeys<Obj, T> = { [K in keyof Obj]-?: Obj[K] extends T ? K : never }[keyof Obj];
|
||||
|
||||
/** Status object for functions that return a boolean indicating success/failure
|
||||
* and an optional message */
|
||||
export interface IReturnStatus {
|
||||
|
@ -147,7 +147,6 @@ function ansiCodeStyle(code: string | null): Record<string, any> {
|
||||
return [codeParts.length - startIdx, "inherit"];
|
||||
}
|
||||
const code = codeParts[startIdx + 1];
|
||||
/* eslint-disable yoda */
|
||||
if (0 <= code && code < 8) {
|
||||
// x8 RGB
|
||||
return [2, COLOR_MAP_DARK[code]];
|
||||
@ -210,7 +209,6 @@ function ansiCodeStyle(code: string | null): Record<string, any> {
|
||||
} else if (codePart === 4) {
|
||||
style.textDecoration = "underline";
|
||||
}
|
||||
/* eslint-disable yoda */
|
||||
// Foreground Color (x8)
|
||||
else if (30 <= codePart && codePart < 38) {
|
||||
style.color = COLOR_MAP_BRIGHT[codePart - 30];
|
||||
|
@ -1,13 +1,10 @@
|
||||
/**
|
||||
* This is an object that is used to keep track of where all of the player's
|
||||
* money is coming from (or going to)
|
||||
*/
|
||||
import type { TypedKeys } from "../types";
|
||||
|
||||
import { Generic_fromJSON, Generic_toJSON, constructorsForReviver, IReviverValue } from "./JSONReviver";
|
||||
|
||||
export class MoneySourceTracker {
|
||||
// eslint-disable-next-line @typescript-eslint/ban-types
|
||||
[key: string]: number | Function;
|
||||
export type MoneySource = TypedKeys<MoneySourceTracker, number>;
|
||||
|
||||
export class MoneySourceTracker {
|
||||
bladeburner = 0;
|
||||
casino = 0;
|
||||
class = 0;
|
||||
@ -29,14 +26,8 @@ export class MoneySourceTracker {
|
||||
augmentations = 0;
|
||||
|
||||
// Record money earned
|
||||
record(amt: number, source: string): void {
|
||||
const sanitizedSource = source.toLowerCase();
|
||||
if (typeof this[sanitizedSource] !== "number" && this[sanitizedSource] !== null) {
|
||||
console.warn(`MoneySourceTracker.record() called with invalid source: ${source}`);
|
||||
return;
|
||||
}
|
||||
|
||||
(this[sanitizedSource] as number) += amt;
|
||||
record(amt: number, source: MoneySource): void {
|
||||
this[source] += amt;
|
||||
this.total += amt;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user