CODEBASE: Follow-up for lint rules PR + address some eslint disables (#651)

This commit is contained in:
Snarling 2023-06-29 13:22:10 -04:00 committed by GitHub
parent bc00a1c134
commit 48e7bd6471
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 169 additions and 235 deletions

@ -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;
}