mirror of
https://github.com/bitburner-official/bitburner-src.git
synced 2024-11-17 13:13:49 +01:00
CODEBASE: Fix lint errors 2 (#1756)
This commit is contained in:
parent
e3c10e9f0f
commit
36c143b687
@ -35,6 +35,7 @@ module.exports = {
|
|||||||
"@typescript-eslint/no-explicit-any": "off",
|
"@typescript-eslint/no-explicit-any": "off",
|
||||||
"react/no-unescaped-entities": "off",
|
"react/no-unescaped-entities": "off",
|
||||||
"@typescript-eslint/restrict-template-expressions": "off",
|
"@typescript-eslint/restrict-template-expressions": "off",
|
||||||
|
"@typescript-eslint/no-unsafe-enum-comparison": "off",
|
||||||
},
|
},
|
||||||
settings: {
|
settings: {
|
||||||
react: {
|
react: {
|
||||||
|
11
src/@types/global.d.ts
vendored
11
src/@types/global.d.ts
vendored
@ -49,3 +49,14 @@ declare global {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
module "monaco-vim" {
|
||||||
|
export const initVimMode: (...args: unknown[]) => { dispose: () => void };
|
||||||
|
export const VimMode: {
|
||||||
|
Vim: {
|
||||||
|
defineEx: (...args: unknown[]) => void;
|
||||||
|
mapCommand: (...args: unknown[]) => void;
|
||||||
|
defineAction: (...args: unknown[]) => void;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
|
@ -3,6 +3,7 @@ import { Card, Suit } from "./Card";
|
|||||||
|
|
||||||
import { makeStyles } from "tss-react/mui";
|
import { makeStyles } from "tss-react/mui";
|
||||||
import Paper from "@mui/material/Paper";
|
import Paper from "@mui/material/Paper";
|
||||||
|
import { throwIfReachable } from "../../utils/helpers/throwIfReachable";
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
card: Card;
|
card: Card;
|
||||||
@ -51,7 +52,7 @@ export const ReactCard: FC<Props> = ({ card, hidden }) => {
|
|||||||
suit = <span>♠</span>;
|
suit = <span>♠</span>;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
throw new Error(`MissingCaseException: ${card.suit}`);
|
throwIfReachable(card.suit);
|
||||||
}
|
}
|
||||||
return (
|
return (
|
||||||
<Paper className={`${classes.card} ${card.isRedSuit() ? classes.red : classes.black}`}>
|
<Paper className={`${classes.card} ${card.isRedSuit() ? classes.red : classes.black}`}>
|
||||||
|
@ -2,13 +2,15 @@ import { Company } from "./Company";
|
|||||||
import { CompanyPosition } from "./CompanyPosition";
|
import { CompanyPosition } from "./CompanyPosition";
|
||||||
|
|
||||||
import { PlayerCondition, haveSkill, haveCompanyRep } from "../Faction/FactionJoinCondition";
|
import { PlayerCondition, haveSkill, haveCompanyRep } from "../Faction/FactionJoinCondition";
|
||||||
import type { Skills } from "../PersonObjects/Skills";
|
import { getRecordEntries } from "../Types/Record";
|
||||||
|
|
||||||
export function getJobRequirements(company: Company, pos: CompanyPosition): PlayerCondition[] {
|
export function getJobRequirements(company: Company, pos: CompanyPosition): PlayerCondition[] {
|
||||||
const reqSkills = pos.requiredSkills(company.jobStatReqOffset);
|
const reqSkills = pos.requiredSkills(company.jobStatReqOffset);
|
||||||
const reqs = [];
|
const reqs = [];
|
||||||
for (const [skillName, value] of Object.entries(reqSkills)) {
|
for (const [skillName, value] of getRecordEntries(reqSkills)) {
|
||||||
if (value > 0) reqs.push(haveSkill(skillName as keyof Skills, value));
|
if (value > 0) {
|
||||||
|
reqs.push(haveSkill(skillName, value));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (pos.requiredReputation > 0) {
|
if (pos.requiredReputation > 0) {
|
||||||
reqs.push(haveCompanyRep(company.name, pos.requiredReputation));
|
reqs.push(haveCompanyRep(company.name, pos.requiredReputation));
|
||||||
|
@ -17,7 +17,7 @@ import { dialogBoxCreate } from "../ui/React/DialogBox";
|
|||||||
import { constructorsForReviver, Generic_toJSON, Generic_fromJSON, IReviverValue } from "../utils/JSONReviver";
|
import { constructorsForReviver, Generic_toJSON, Generic_fromJSON, IReviverValue } from "../utils/JSONReviver";
|
||||||
import { JSONMap, JSONSet } from "../Types/Jsonable";
|
import { JSONMap, JSONSet } from "../Types/Jsonable";
|
||||||
import { formatMoney } from "../ui/formatNumber";
|
import { formatMoney } from "../ui/formatNumber";
|
||||||
import { isPositiveInteger } from "../types";
|
import { isPositiveInteger, type Result } from "../types";
|
||||||
import { createEnumKeyedRecord, getRecordValues } from "../Types/Record";
|
import { createEnumKeyedRecord, getRecordValues } from "../Types/Record";
|
||||||
import { getKeyList } from "../utils/helpers/getKeyList";
|
import { getKeyList } from "../utils/helpers/getKeyList";
|
||||||
|
|
||||||
@ -372,29 +372,56 @@ export class Corporation {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Purchasing a one-time unlock
|
/**
|
||||||
* @returns A string on failure, indicating the reason for failure. */
|
* Purchasing a one-time unlock
|
||||||
purchaseUnlock(unlockName: CorpUnlockName): string | void {
|
*/
|
||||||
if (this.unlocks.has(unlockName)) return `The corporation has already unlocked ${unlockName}`;
|
purchaseUnlock(unlockName: CorpUnlockName): Result {
|
||||||
|
if (this.unlocks.has(unlockName)) {
|
||||||
|
return {
|
||||||
|
success: false,
|
||||||
|
message: `${unlockName} has already been unlocked.`,
|
||||||
|
};
|
||||||
|
}
|
||||||
const price = CorpUnlocks[unlockName].price;
|
const price = CorpUnlocks[unlockName].price;
|
||||||
if (this.funds < price) return `Insufficient funds to purchase ${unlockName}, requires ${formatMoney(price)}`;
|
if (this.funds < price) {
|
||||||
|
return {
|
||||||
|
success: false,
|
||||||
|
message: `Insufficient funds to purchase ${unlockName}, requires ${formatMoney(price)}.`,
|
||||||
|
};
|
||||||
|
}
|
||||||
this.loseFunds(price, "upgrades");
|
this.loseFunds(price, "upgrades");
|
||||||
this.unlocks.add(unlockName);
|
this.unlocks.add(unlockName);
|
||||||
|
|
||||||
// Apply effects for one-time unlocks
|
// Apply effects for one-time unlocks
|
||||||
if (unlockName === CorpUnlockName.ShadyAccounting) this.dividendTax -= 0.05;
|
if (unlockName === CorpUnlockName.ShadyAccounting) {
|
||||||
if (unlockName === CorpUnlockName.GovernmentPartnership) this.dividendTax -= 0.1;
|
this.dividendTax -= 0.05;
|
||||||
|
}
|
||||||
|
if (unlockName === CorpUnlockName.GovernmentPartnership) {
|
||||||
|
this.dividendTax -= 0.1;
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
success: true,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Purchasing a levelable upgrade
|
/**
|
||||||
* @returns A string on failure, indicating the reason for failure. */
|
* Purchasing a levelable upgrade
|
||||||
purchaseUpgrade(upgradeName: CorpUpgradeName, amount = 1): string | void {
|
*/
|
||||||
|
purchaseUpgrade(upgradeName: CorpUpgradeName, amount = 1): Result {
|
||||||
if (!isPositiveInteger(amount)) {
|
if (!isPositiveInteger(amount)) {
|
||||||
return `Number of upgrade levels purchased must be a positive integer (attempted: ${amount}).`;
|
return {
|
||||||
|
success: false,
|
||||||
|
message: `Number of upgrade levels purchased must be a positive integer (attempted: ${amount}).`,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
const upgrade = CorpUpgrades[upgradeName];
|
const upgrade = CorpUpgrades[upgradeName];
|
||||||
const totalCost = calculateUpgradeCost(this, upgrade, amount);
|
const totalCost = calculateUpgradeCost(this, upgrade, amount);
|
||||||
if (this.funds < totalCost) return `Not enough funds to purchase ${amount} of upgrade ${upgradeName}.`;
|
if (this.funds < totalCost) {
|
||||||
|
return {
|
||||||
|
success: false,
|
||||||
|
message: `Not enough funds to purchase ${amount} of upgrade ${upgradeName}.`,
|
||||||
|
};
|
||||||
|
}
|
||||||
this.loseFunds(totalCost, "upgrades");
|
this.loseFunds(totalCost, "upgrades");
|
||||||
this.upgrades[upgradeName].level += amount;
|
this.upgrades[upgradeName].level += amount;
|
||||||
this.upgrades[upgradeName].value += upgrade.benefit * amount;
|
this.upgrades[upgradeName].value += upgrade.benefit * amount;
|
||||||
@ -407,6 +434,9 @@ export class Corporation {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return {
|
||||||
|
success: true,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
getProductionMultiplier(): number {
|
getProductionMultiplier(): number {
|
||||||
|
@ -16,6 +16,7 @@ import { PartialRecord, getRecordEntries, getRecordKeys, getRecordValues } from
|
|||||||
import { Material } from "./Material";
|
import { Material } from "./Material";
|
||||||
import { getKeyList } from "../utils/helpers/getKeyList";
|
import { getKeyList } from "../utils/helpers/getKeyList";
|
||||||
import { calculateMarkupMultiplier } from "./helpers";
|
import { calculateMarkupMultiplier } from "./helpers";
|
||||||
|
import { throwIfReachable } from "../utils/helpers/throwIfReachable";
|
||||||
|
|
||||||
interface DivisionParams {
|
interface DivisionParams {
|
||||||
name: string;
|
name: string;
|
||||||
@ -704,8 +705,7 @@ export class Division {
|
|||||||
case "START":
|
case "START":
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
console.error(`Invalid state: ${state}`);
|
throwIfReachable(state);
|
||||||
break;
|
|
||||||
} //End switch(this.state)
|
} //End switch(this.state)
|
||||||
this.updateWarehouseSizeUsed(warehouse);
|
this.updateWarehouseSizeUsed(warehouse);
|
||||||
}
|
}
|
||||||
@ -936,8 +936,7 @@ export class Division {
|
|||||||
case "EXPORT":
|
case "EXPORT":
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
console.error(`Invalid State: ${state}`);
|
throwIfReachable(state);
|
||||||
break;
|
|
||||||
} //End switch(this.state)
|
} //End switch(this.state)
|
||||||
this.updateWarehouseSizeUsed(warehouse);
|
this.updateWarehouseSizeUsed(warehouse);
|
||||||
}
|
}
|
||||||
|
@ -5,6 +5,7 @@ import { Division } from "./Division";
|
|||||||
import { Corporation } from "./Corporation";
|
import { Corporation } from "./Corporation";
|
||||||
import { getRandomIntInclusive } from "../utils/helpers/getRandomIntInclusive";
|
import { getRandomIntInclusive } from "../utils/helpers/getRandomIntInclusive";
|
||||||
import { createEnumKeyedRecord, getRecordKeys } from "../Types/Record";
|
import { createEnumKeyedRecord, getRecordKeys } from "../Types/Record";
|
||||||
|
import { throwIfReachable } from "../utils/helpers/throwIfReachable";
|
||||||
|
|
||||||
interface IParams {
|
interface IParams {
|
||||||
city: CityName;
|
city: CityName;
|
||||||
@ -165,8 +166,7 @@ export class OfficeSpace {
|
|||||||
case "total":
|
case "total":
|
||||||
continue;
|
continue;
|
||||||
default:
|
default:
|
||||||
console.error(`Invalid employee position: ${name}`);
|
throwIfReachable(name);
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
this.employeeProductionByJob[name] = this.employeeJobs[name] * prodMult * prodBase;
|
this.employeeProductionByJob[name] = this.employeeJobs[name] * prodMult * prodBase;
|
||||||
total += this.employeeProductionByJob[name];
|
total += this.employeeProductionByJob[name];
|
||||||
|
@ -214,7 +214,9 @@ export class Product {
|
|||||||
|
|
||||||
calculateRating(industry: Division): void {
|
calculateRating(industry: Division): void {
|
||||||
const weights = IndustriesData[industry.type].product?.ratingWeights;
|
const weights = IndustriesData[industry.type].product?.ratingWeights;
|
||||||
if (!weights) return console.error(`Could not find product rating weights for: ${industry}`);
|
if (!weights) {
|
||||||
|
return console.error(`Could not find product rating weights for: ${industry.name}`);
|
||||||
|
}
|
||||||
this.rating = getRecordEntries(weights).reduce(
|
this.rating = getRecordEntries(weights).reduce(
|
||||||
(total, [statName, weight]) => total + this.stats[statName] * weight,
|
(total, [statName, weight]) => total + this.stats[statName] * weight,
|
||||||
0,
|
0,
|
||||||
|
@ -31,8 +31,10 @@ export function LevelableUpgrade({ upgradeName, mult, rerender }: IProps): React
|
|||||||
const tooltip = data.desc;
|
const tooltip = data.desc;
|
||||||
function onClick(): void {
|
function onClick(): void {
|
||||||
if (corp.funds < cost) return;
|
if (corp.funds < cost) return;
|
||||||
const message = corp.purchaseUpgrade(upgradeName, amount);
|
const result = corp.purchaseUpgrade(upgradeName, amount);
|
||||||
if (message) dialogBoxCreate(`Could not upgrade ${upgradeName} ${amount} times:\n${message}`);
|
if (!result.success) {
|
||||||
|
dialogBoxCreate(`Could not upgrade ${upgradeName} ${amount} times:\n${result.message}`);
|
||||||
|
}
|
||||||
rerender();
|
rerender();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -25,8 +25,10 @@ export function Unlock(props: UnlockProps): React.ReactElement {
|
|||||||
|
|
||||||
function onClick(): void {
|
function onClick(): void {
|
||||||
// corp.unlock handles displaying a dialog on failure
|
// corp.unlock handles displaying a dialog on failure
|
||||||
const message = corp.purchaseUnlock(props.name);
|
const result = corp.purchaseUnlock(props.name);
|
||||||
if (message) dialogBoxCreate(`Error while attempting to purchase ${props.name}:\n${message}`);
|
if (!result.success) {
|
||||||
|
dialogBoxCreate(`Error while attempting to purchase ${props.name}:\n${result.message}`);
|
||||||
|
}
|
||||||
// Rerenders the parent, which should remove this item if the purchase was successful
|
// Rerenders the parent, which should remove this item if the purchase was successful
|
||||||
props.rerender();
|
props.rerender();
|
||||||
}
|
}
|
||||||
|
@ -44,8 +44,8 @@ export function SellSharesModal(props: IProps): React.ReactElement {
|
|||||||
props.onClose();
|
props.onClose();
|
||||||
props.rerender();
|
props.rerender();
|
||||||
setShares(NaN);
|
setShares(NaN);
|
||||||
} catch (err) {
|
} catch (error) {
|
||||||
dialogBoxCreate(`${err as Error}`);
|
dialogBoxCreate(String(error));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -7,17 +7,17 @@ export let staneksGift = new StaneksGift();
|
|||||||
|
|
||||||
export function loadStaneksGift(saveString: string): void {
|
export function loadStaneksGift(saveString: string): void {
|
||||||
if (saveString) {
|
if (saveString) {
|
||||||
staneksGift = JSON.parse(saveString, Reviver);
|
staneksGift = JSON.parse(saveString, Reviver) as StaneksGift;
|
||||||
} else {
|
} else {
|
||||||
staneksGift = new StaneksGift();
|
staneksGift = new StaneksGift();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function zeros(width: number, height: number): number[][] {
|
export function zeros(width: number, height: number): number[][] {
|
||||||
const array = [];
|
const array: number[][] = [];
|
||||||
|
|
||||||
for (let i = 0; i < width; ++i) {
|
for (let i = 0; i < width; ++i) {
|
||||||
array.push(Array(height).fill(0));
|
array.push(Array<number>(height).fill(0));
|
||||||
}
|
}
|
||||||
|
|
||||||
return array;
|
return array;
|
||||||
|
@ -18,9 +18,6 @@ export class StaneksGift extends BaseGift {
|
|||||||
isBonusCharging = false;
|
isBonusCharging = false;
|
||||||
justCharged = true;
|
justCharged = true;
|
||||||
storedCycles = 0;
|
storedCycles = 0;
|
||||||
constructor() {
|
|
||||||
super();
|
|
||||||
}
|
|
||||||
|
|
||||||
baseSize(): number {
|
baseSize(): number {
|
||||||
return StanekConstants.BaseSize + currentNodeMults.StaneksGiftExtraSize + Player.activeSourceFileLvl(13);
|
return StanekConstants.BaseSize + currentNodeMults.StaneksGiftExtraSize + Player.activeSourceFileLvl(13);
|
||||||
|
@ -155,13 +155,27 @@ export const GameOptionsSidebar = (props: IProps): React.ReactElement => {
|
|||||||
>
|
>
|
||||||
<Button onClick={startImport} startIcon={<Upload />} sx={{ gridArea: "import" }}>
|
<Button onClick={startImport} startIcon={<Upload />} sx={{ gridArea: "import" }}>
|
||||||
Import Game
|
Import Game
|
||||||
<input ref={importInput} id="import-game-file-selector" type="file" hidden onChange={onImport} />
|
<input
|
||||||
|
ref={importInput}
|
||||||
|
id="import-game-file-selector"
|
||||||
|
type="file"
|
||||||
|
hidden
|
||||||
|
onChange={(event) => {
|
||||||
|
onImport(event).catch((error) => {
|
||||||
|
console.error(error);
|
||||||
|
});
|
||||||
|
}}
|
||||||
|
/>
|
||||||
</Button>
|
</Button>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
<ConfirmationModal
|
<ConfirmationModal
|
||||||
open={importSaveOpen}
|
open={importSaveOpen}
|
||||||
onClose={() => setImportSaveOpen(false)}
|
onClose={() => setImportSaveOpen(false)}
|
||||||
onConfirm={() => confirmedImportGame()}
|
onConfirm={() => {
|
||||||
|
confirmedImportGame().catch((error) => {
|
||||||
|
console.error(error);
|
||||||
|
});
|
||||||
|
}}
|
||||||
additionalButton={<Button onClick={compareSaveGame}>Compare Save</Button>}
|
additionalButton={<Button onClick={compareSaveGame}>Compare Save</Button>}
|
||||||
confirmationText={
|
confirmationText={
|
||||||
<>
|
<>
|
||||||
|
@ -15,6 +15,7 @@ import { Settings } from "../../Settings/Settings";
|
|||||||
import { MoneyRate } from "../../ui/React/MoneyRate";
|
import { MoneyRate } from "../../ui/React/MoneyRate";
|
||||||
import { StatsRow } from "../../ui/React/StatsRow";
|
import { StatsRow } from "../../ui/React/StatsRow";
|
||||||
import { useStyles } from "../../ui/React/CharacterOverview";
|
import { useStyles } from "../../ui/React/CharacterOverview";
|
||||||
|
import { getKeyFromReactElements } from "../../utils/StringHelperFunctions";
|
||||||
|
|
||||||
interface IProps {
|
interface IProps {
|
||||||
member: GangMember;
|
member: GangMember;
|
||||||
@ -103,7 +104,7 @@ export function GangMemberStats(props: IProps): React.ReactElement {
|
|||||||
</TableCell>
|
</TableCell>
|
||||||
</TableRow>
|
</TableRow>
|
||||||
{data.map(([a, b]) => (
|
{data.map(([a, b]) => (
|
||||||
<TableRow key={a.toString() + b.toString()}>
|
<TableRow key={getKeyFromReactElements(a, b)}>
|
||||||
<TableCell classes={{ root: classes.cellNone }}>
|
<TableCell classes={{ root: classes.cellNone }}>
|
||||||
<Typography>{a}</Typography>
|
<Typography>{a}</Typography>
|
||||||
</TableCell>
|
</TableCell>
|
||||||
|
@ -83,7 +83,11 @@ export function loadGo(data: unknown): boolean {
|
|||||||
Go.storeCycles(loadStoredCycles(parsedData.storedCycles));
|
Go.storeCycles(loadStoredCycles(parsedData.storedCycles));
|
||||||
|
|
||||||
// If it's the AI's turn, initiate their turn, which will populate nextTurn
|
// If it's the AI's turn, initiate their turn, which will populate nextTurn
|
||||||
if (currentGame.previousPlayer === GoColor.black && currentGame.ai !== GoOpponent.none) makeAIMove(currentGame);
|
if (currentGame.previousPlayer === GoColor.black && currentGame.ai !== GoOpponent.none) {
|
||||||
|
makeAIMove(currentGame).catch((error) => {
|
||||||
|
showError(error);
|
||||||
|
});
|
||||||
|
}
|
||||||
// If it's not the AI's turn and we're not in gameover status, initialize nextTurn promise based on the previous move/pass
|
// If it's not the AI's turn and we're not in gameover status, initialize nextTurn promise based on the previous move/pass
|
||||||
else if (currentGame.previousPlayer) {
|
else if (currentGame.previousPlayer) {
|
||||||
const previousMove = getPreviousMove();
|
const previousMove = getPreviousMove();
|
||||||
|
@ -135,7 +135,7 @@ export function MinesweeperGame(props: IMinigameProps): React.ReactElement {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<Typography
|
<Typography
|
||||||
key={`${item}${uniqueId()}`}
|
key={uniqueId()}
|
||||||
sx={{
|
sx={{
|
||||||
color: color,
|
color: color,
|
||||||
border: `2px solid ${item.current ? Settings.theme.infolight : Settings.theme.primary}`,
|
border: `2px solid ${item.current ? Settings.theme.infolight : Settings.theme.primary}`,
|
||||||
|
@ -66,7 +66,7 @@ class NSProxyHandler<API extends GenericAPI<API>> {
|
|||||||
|
|
||||||
const descriptor = Object.getOwnPropertyDescriptor(this.ns, key);
|
const descriptor = Object.getOwnPropertyDescriptor(this.ns, key);
|
||||||
if (!descriptor) return descriptor;
|
if (!descriptor) return descriptor;
|
||||||
const field = descriptor.value;
|
const field: unknown = descriptor.value;
|
||||||
|
|
||||||
if (typeof field === "function") {
|
if (typeof field === "function") {
|
||||||
const arrayPath = [...this.tree, key];
|
const arrayPath = [...this.tree, key];
|
||||||
@ -74,7 +74,7 @@ class NSProxyHandler<API extends GenericAPI<API>> {
|
|||||||
const ctx = { workerScript: this.ws, function: key, functionPath };
|
const ctx = { workerScript: this.ws, function: key, functionPath };
|
||||||
// Only do the context-binding once, instead of each time the function
|
// Only do the context-binding once, instead of each time the function
|
||||||
// is called.
|
// is called.
|
||||||
const func: any = field(ctx);
|
const func = field(ctx) as (...args: unknown[]) => unknown;
|
||||||
const wrappedFunction = function (...args: unknown[]): unknown {
|
const wrappedFunction = function (...args: unknown[]): unknown {
|
||||||
// What remains *must* be called every time.
|
// What remains *must* be called every time.
|
||||||
helpers.checkEnvFlags(ctx);
|
helpers.checkEnvFlags(ctx);
|
||||||
|
@ -692,8 +692,11 @@ function getRunningScript(ctx: NetscriptContext, ident: ScriptIdentifier): Runni
|
|||||||
return findRunningScriptByPid(ident);
|
return findRunningScriptByPid(ident);
|
||||||
} else {
|
} else {
|
||||||
const scripts = getRunningScriptsByArgs(ctx, ident.scriptname, ident.hostname, ident.args);
|
const scripts = getRunningScriptsByArgs(ctx, ident.scriptname, ident.hostname, ident.args);
|
||||||
if (scripts === null) return null;
|
if (scripts === null) {
|
||||||
return scripts.values().next().value ?? null;
|
return null;
|
||||||
|
}
|
||||||
|
const next = scripts.values().next();
|
||||||
|
return !next.done ? next.value : null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -624,15 +624,19 @@ export function NetscriptCorporation(): InternalAPI<NSCorporation> {
|
|||||||
checkAccess(ctx);
|
checkAccess(ctx);
|
||||||
const unlockName = getEnumHelper("CorpUnlockName").nsGetMember(ctx, _unlockName, "unlockName");
|
const unlockName = getEnumHelper("CorpUnlockName").nsGetMember(ctx, _unlockName, "unlockName");
|
||||||
const corporation = getCorporation();
|
const corporation = getCorporation();
|
||||||
const message = corporation.purchaseUnlock(unlockName);
|
const result = corporation.purchaseUnlock(unlockName);
|
||||||
if (message) throw new Error(`Could not unlock ${unlockName}: ${message}`);
|
if (!result.success) {
|
||||||
|
throw new Error(`Could not unlock ${unlockName}: ${result.message}`);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
levelUpgrade: (ctx) => (_upgradeName) => {
|
levelUpgrade: (ctx) => (_upgradeName) => {
|
||||||
checkAccess(ctx);
|
checkAccess(ctx);
|
||||||
const upgradeName = getEnumHelper("CorpUpgradeName").nsGetMember(ctx, _upgradeName, "upgradeName");
|
const upgradeName = getEnumHelper("CorpUpgradeName").nsGetMember(ctx, _upgradeName, "upgradeName");
|
||||||
const corporation = getCorporation();
|
const corporation = getCorporation();
|
||||||
const message = corporation.purchaseUpgrade(upgradeName, 1);
|
const result = corporation.purchaseUpgrade(upgradeName, 1);
|
||||||
if (message) throw new Error(`Could not upgrade ${upgradeName}: ${message}`);
|
if (!result.success) {
|
||||||
|
throw new Error(`Could not upgrade ${upgradeName}: ${result.message}`);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
issueDividends: (ctx) => (_rate) => {
|
issueDividends: (ctx) => (_rate) => {
|
||||||
checkAccess(ctx);
|
checkAccess(ctx);
|
||||||
|
@ -13,6 +13,7 @@ import { Factions } from "../Faction/Factions";
|
|||||||
import { getEnumHelper } from "../utils/EnumHelper";
|
import { getEnumHelper } from "../utils/EnumHelper";
|
||||||
import { helpers } from "../Netscript/NetscriptHelpers";
|
import { helpers } from "../Netscript/NetscriptHelpers";
|
||||||
import { filterTruthy } from "../utils/helpers/ArrayHelpers";
|
import { filterTruthy } from "../utils/helpers/ArrayHelpers";
|
||||||
|
import { exceptionAlert } from "../utils/helpers/exceptionAlert";
|
||||||
|
|
||||||
export function NetscriptInfiltration(): InternalAPI<NetscriptInfiltation> {
|
export function NetscriptInfiltration(): InternalAPI<NetscriptInfiltation> {
|
||||||
const getLocationsWithInfiltrations = Object.values(Locations).filter(
|
const getLocationsWithInfiltrations = Object.values(Locations).filter(
|
||||||
@ -21,16 +22,29 @@ export function NetscriptInfiltration(): InternalAPI<NetscriptInfiltation> {
|
|||||||
|
|
||||||
const calculateInfiltrationData = (ctx: NetscriptContext, locationName: LocationName): InfiltrationLocation => {
|
const calculateInfiltrationData = (ctx: NetscriptContext, locationName: LocationName): InfiltrationLocation => {
|
||||||
const location = Locations[locationName];
|
const location = Locations[locationName];
|
||||||
if (location === undefined) throw helpers.errorMessage(ctx, `Location '${location}' does not exists.`);
|
if (location === undefined) {
|
||||||
if (location.infiltrationData === undefined)
|
throw helpers.errorMessage(ctx, `Location "${locationName}" does not exist.`);
|
||||||
throw helpers.errorMessage(ctx, `Location '${location}' does not provide infiltrations.`);
|
}
|
||||||
|
if (location.infiltrationData === undefined) {
|
||||||
|
throw helpers.errorMessage(ctx, `Location "${locationName}" does not provide infiltrations.`);
|
||||||
|
}
|
||||||
|
const locationCity = location.city;
|
||||||
|
/**
|
||||||
|
* location.city is only null when the location is available in all cities. This kind of location does not have
|
||||||
|
* infiltration data.
|
||||||
|
*/
|
||||||
|
if (locationCity === null) {
|
||||||
|
const errorMessage = `Location "${locationName}" is available in all cities, but it still has infiltration data.`;
|
||||||
|
exceptionAlert(new Error(errorMessage));
|
||||||
|
throw helpers.errorMessage(ctx, errorMessage);
|
||||||
|
}
|
||||||
const startingSecurityLevel = location.infiltrationData.startingSecurityLevel;
|
const startingSecurityLevel = location.infiltrationData.startingSecurityLevel;
|
||||||
const difficulty = calculateDifficulty(startingSecurityLevel);
|
const difficulty = calculateDifficulty(startingSecurityLevel);
|
||||||
const reward = calculateReward(startingSecurityLevel);
|
const reward = calculateReward(startingSecurityLevel);
|
||||||
const maxLevel = location.infiltrationData.maxClearanceLevel;
|
const maxLevel = location.infiltrationData.maxClearanceLevel;
|
||||||
return {
|
return {
|
||||||
location: {
|
location: {
|
||||||
city: location.city!,
|
city: locationCity,
|
||||||
name: location.name,
|
name: location.name,
|
||||||
},
|
},
|
||||||
reward: {
|
reward: {
|
||||||
|
@ -47,7 +47,7 @@ export function portHandle(n: PortNumber): NetscriptPort {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export function writePort(n: PortNumber, value: unknown): any {
|
export function writePort(n: PortNumber, value: unknown): unknown {
|
||||||
const port = getPort(n);
|
const port = getPort(n);
|
||||||
// Primitives don't need to be cloned.
|
// Primitives don't need to be cloned.
|
||||||
port.add(isObjectLike(value) ? structuredClone(value) : value);
|
port.add(isObjectLike(value) ? structuredClone(value) : value);
|
||||||
@ -63,15 +63,15 @@ export function tryWritePort(n: PortNumber, value: unknown): boolean {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function readPort(n: PortNumber): any {
|
export function readPort(n: PortNumber): unknown {
|
||||||
const port = NetscriptPorts.get(n);
|
const port = NetscriptPorts.get(n);
|
||||||
if (!port || !port.data.length) return emptyPortData;
|
if (!port || !port.data.length) return emptyPortData;
|
||||||
const returnVal = port.data.shift();
|
const returnVal: unknown = port.data.shift();
|
||||||
if (!port.data.length && !port.resolver) NetscriptPorts.delete(n);
|
if (!port.data.length && !port.resolver) NetscriptPorts.delete(n);
|
||||||
return returnVal;
|
return returnVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function peekPort(n: PortNumber): any {
|
export function peekPort(n: PortNumber): unknown {
|
||||||
const port = NetscriptPorts.get(n);
|
const port = NetscriptPorts.get(n);
|
||||||
if (!port || !port.data.length) return emptyPortData;
|
if (!port || !port.data.length) return emptyPortData;
|
||||||
// Needed to avoid exposing internal objects.
|
// Needed to avoid exposing internal objects.
|
||||||
|
@ -26,6 +26,7 @@ import { isSleeveFactionWork } from "../Work/SleeveFactionWork";
|
|||||||
import { isSleeveCompanyWork } from "../Work/SleeveCompanyWork";
|
import { isSleeveCompanyWork } from "../Work/SleeveCompanyWork";
|
||||||
import { isSleeveCrimeWork } from "../Work/SleeveCrimeWork";
|
import { isSleeveCrimeWork } from "../Work/SleeveCrimeWork";
|
||||||
import { canAccessBitNodeFeature } from "../../../BitNode/BitNodeUtils";
|
import { canAccessBitNodeFeature } from "../../../BitNode/BitNodeUtils";
|
||||||
|
import { getKeyFromReactElements } from "../../../utils/StringHelperFunctions";
|
||||||
|
|
||||||
const CYCLES_PER_SEC = 1000 / CONSTANTS.MilliPerCycle;
|
const CYCLES_PER_SEC = 1000 / CONSTANTS.MilliPerCycle;
|
||||||
|
|
||||||
@ -177,7 +178,7 @@ export function EarningsElement(props: IProps): React.ReactElement {
|
|||||||
</TableCell>
|
</TableCell>
|
||||||
</TableRow>
|
</TableRow>
|
||||||
{data.map(([a, b]) => (
|
{data.map(([a, b]) => (
|
||||||
<TableRow key={a.toString() + b.toString()}>
|
<TableRow key={getKeyFromReactElements(a, b)}>
|
||||||
<TableCell classes={{ root: classes.cellNone }}>
|
<TableCell classes={{ root: classes.cellNone }}>
|
||||||
<Typography>{a}</Typography>
|
<Typography>{a}</Typography>
|
||||||
</TableCell>
|
</TableCell>
|
||||||
|
@ -231,16 +231,16 @@ function parseOnlyRamCalculate(
|
|||||||
prefix: string,
|
prefix: string,
|
||||||
obj: object,
|
obj: object,
|
||||||
ref: string,
|
ref: string,
|
||||||
): { func: () => number | number; refDetail: string } | undefined => {
|
): { func: (() => number) | number; refDetail: string } | undefined => {
|
||||||
if (!obj) {
|
if (!obj) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const elem = Object.entries(obj).find(([key]) => key === ref);
|
const elem = Object.entries(obj).find(([key]) => key === ref);
|
||||||
if (elem !== undefined && (typeof elem[1] === "function" || typeof elem[1] === "number")) {
|
if (elem !== undefined && (typeof elem[1] === "function" || typeof elem[1] === "number")) {
|
||||||
return { func: elem[1], refDetail: `${prefix}${ref}` };
|
return { func: elem[1] as (() => number) | number, refDetail: `${prefix}${ref}` };
|
||||||
}
|
}
|
||||||
for (const [key, value] of Object.entries(obj)) {
|
for (const [key, value] of Object.entries(obj)) {
|
||||||
const found = findFunc(`${key}.`, value, ref);
|
const found = findFunc(`${key}.`, value as object, ref);
|
||||||
if (found) {
|
if (found) {
|
||||||
return found;
|
return found;
|
||||||
}
|
}
|
||||||
|
@ -76,7 +76,7 @@ export class Script implements ContentFile {
|
|||||||
const ramCalc = calculateRamUsage(this.code, this.filename, this.server, otherScripts);
|
const ramCalc = calculateRamUsage(this.code, this.filename, this.server, otherScripts);
|
||||||
if (ramCalc.cost && ramCalc.cost >= RamCostConstants.Base) {
|
if (ramCalc.cost && ramCalc.cost >= RamCostConstants.Base) {
|
||||||
this.ramUsage = roundToTwo(ramCalc.cost);
|
this.ramUsage = roundToTwo(ramCalc.cost);
|
||||||
this.ramUsageEntries = ramCalc.entries as RamUsageEntry[];
|
this.ramUsageEntries = ramCalc.entries;
|
||||||
this.ramCalculationError = null;
|
this.ramCalculationError = null;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
import React, { useEffect, useRef, useState } from "react";
|
import React, { useEffect, useRef, useState } from "react";
|
||||||
// @ts-expect-error This library does not have types.
|
|
||||||
import * as MonacoVim from "monaco-vim";
|
import * as MonacoVim from "monaco-vim";
|
||||||
import type { editor } from "monaco-editor";
|
import type { editor } from "monaco-editor";
|
||||||
type IStandaloneCodeEditor = editor.IStandaloneCodeEditor;
|
type IStandaloneCodeEditor = editor.IStandaloneCodeEditor;
|
||||||
@ -18,8 +17,7 @@ interface IProps {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function useVimEditor({ editor, vim, onOpenNextTab, onOpenPreviousTab, onSave }: IProps) {
|
export function useVimEditor({ editor, vim, onOpenNextTab, onOpenPreviousTab, onSave }: IProps) {
|
||||||
// monaco-vim does not have types, so this is an any
|
const [vimEditor, setVimEditor] = useState<ReturnType<typeof MonacoVim.initVimMode> | null>(null);
|
||||||
const [vimEditor, setVimEditor] = useState<any>(null);
|
|
||||||
|
|
||||||
const statusBarRef = useRef<React.ReactElement | null>(null);
|
const statusBarRef = useRef<React.ReactElement | null>(null);
|
||||||
const rerender = useRerender();
|
const rerender = useRerender();
|
||||||
@ -30,7 +28,6 @@ export function useVimEditor({ editor, vim, onOpenNextTab, onOpenPreviousTab, on
|
|||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
// setup monaco-vim
|
// setup monaco-vim
|
||||||
if (vim && editor && !vimEditor) {
|
if (vim && editor && !vimEditor) {
|
||||||
// Using try/catch because MonacoVim does not have types.
|
|
||||||
try {
|
try {
|
||||||
setVimEditor(MonacoVim.initVimMode(editor, statusBarRef, StatusBar, rerender));
|
setVimEditor(MonacoVim.initVimMode(editor, statusBarRef, StatusBar, rerender));
|
||||||
MonacoVim.VimMode.Vim.defineEx("write", "w", function () {
|
MonacoVim.VimMode.Vim.defineEx("write", "w", function () {
|
||||||
@ -65,8 +62,7 @@ export function useVimEditor({ editor, vim, onOpenNextTab, onOpenPreviousTab, on
|
|||||||
MonacoVim.VimMode.Vim.mapCommand("gT", "action", "prevTabs", {}, { context: "normal" });
|
MonacoVim.VimMode.Vim.mapCommand("gT", "action", "prevTabs", {}, { context: "normal" });
|
||||||
editor.focus();
|
editor.focus();
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error("An error occurred while loading monaco-vim:");
|
console.error("An error occurred while loading monaco-vim:", e);
|
||||||
console.error(e);
|
|
||||||
}
|
}
|
||||||
} else if (!vim) {
|
} else if (!vim) {
|
||||||
// When vim mode is disabled
|
// When vim mode is disabled
|
||||||
|
@ -2,6 +2,7 @@ import { GetServer } from "../../Server/AllServers";
|
|||||||
import { editor, Uri } from "monaco-editor";
|
import { editor, Uri } from "monaco-editor";
|
||||||
import { OpenScript } from "./OpenScript";
|
import { OpenScript } from "./OpenScript";
|
||||||
import { getFileType, FileType } from "../../utils/ScriptTransformer";
|
import { getFileType, FileType } from "../../utils/ScriptTransformer";
|
||||||
|
import { throwIfReachable } from "../../utils/helpers/throwIfReachable";
|
||||||
|
|
||||||
function getServerCode(scripts: OpenScript[], index: number): string | null {
|
function getServerCode(scripts: OpenScript[], index: number): string | null {
|
||||||
const openScript = scripts[index];
|
const openScript = scripts[index];
|
||||||
@ -48,7 +49,7 @@ function makeModel(hostname: string, filename: string, code: string) {
|
|||||||
language = "javascript";
|
language = "javascript";
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
throw new Error(`Invalid file type: ${fileType}. Filename: ${filename}.`);
|
throwIfReachable(fileType);
|
||||||
}
|
}
|
||||||
//if somehow a model already exist return it
|
//if somehow a model already exist return it
|
||||||
return editor.getModel(uri) ?? editor.createModel(code, language, uri);
|
return editor.getModel(uri) ?? editor.createModel(code, language, uri);
|
||||||
|
@ -8,8 +8,9 @@ import Typography from "@mui/material/Typography";
|
|||||||
import ExpandLessIcon from "@mui/icons-material/ExpandLess";
|
import ExpandLessIcon from "@mui/icons-material/ExpandLess";
|
||||||
import ExpandMoreIcon from "@mui/icons-material/ExpandMore";
|
import ExpandMoreIcon from "@mui/icons-material/ExpandMore";
|
||||||
|
|
||||||
import { SidebarItem, ICreateProps as IItemProps } from "./SidebarItem";
|
import { SidebarItem, ICreateProps as IItemProps, type SidebarItemProps } from "./SidebarItem";
|
||||||
import type { Page } from "../../ui/Router";
|
import type { Page } from "../../ui/Router";
|
||||||
|
import type { PartialRecord } from "../../Types/Record";
|
||||||
|
|
||||||
type SidebarAccordionProps = {
|
type SidebarAccordionProps = {
|
||||||
key_: string;
|
key_: string;
|
||||||
@ -19,9 +20,12 @@ type SidebarAccordionProps = {
|
|||||||
items: (IItemProps | boolean)[];
|
items: (IItemProps | boolean)[];
|
||||||
icon: React.ReactElement["type"];
|
icon: React.ReactElement["type"];
|
||||||
sidebarOpen: boolean;
|
sidebarOpen: boolean;
|
||||||
classes: any;
|
classes: Record<"listitem" | "active", string>;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
type ClickFnCacheKeyType = (page: Page) => void;
|
||||||
|
type ClickFnCacheValueType = PartialRecord<Page, SidebarItemProps["clickFn"]>;
|
||||||
|
|
||||||
// We can't useCallback for this, because in the items map it would be
|
// We can't useCallback for this, because in the items map it would be
|
||||||
// called a changing number of times, and hooks can't be called in loops. So
|
// called a changing number of times, and hooks can't be called in loops. So
|
||||||
// we set up this explicit cache of function objects instead.
|
// we set up this explicit cache of function objects instead.
|
||||||
@ -30,7 +34,7 @@ type SidebarAccordionProps = {
|
|||||||
// WeakMap prevents memory leaks. We won't drop slices of the cache too soon,
|
// WeakMap prevents memory leaks. We won't drop slices of the cache too soon,
|
||||||
// because the fn keys are themselves memoized elsewhere, which keeps them
|
// because the fn keys are themselves memoized elsewhere, which keeps them
|
||||||
// alive and thus keeps the WeakMap entries alive.
|
// alive and thus keeps the WeakMap entries alive.
|
||||||
const clickFnCache = new WeakMap();
|
const clickFnCache = new WeakMap<ClickFnCacheKeyType, ClickFnCacheValueType>();
|
||||||
function getClickFn(toWrap: (page: Page) => void, page: Page) {
|
function getClickFn(toWrap: (page: Page) => void, page: Page) {
|
||||||
let first = clickFnCache.get(toWrap);
|
let first = clickFnCache.get(toWrap);
|
||||||
if (first === undefined) {
|
if (first === undefined) {
|
||||||
|
@ -18,7 +18,7 @@ export interface ICreateProps {
|
|||||||
export interface SidebarItemProps extends ICreateProps {
|
export interface SidebarItemProps extends ICreateProps {
|
||||||
clickFn: () => void;
|
clickFn: () => void;
|
||||||
flash: boolean;
|
flash: boolean;
|
||||||
classes: any;
|
classes: Record<"listitem" | "active", string>;
|
||||||
sidebarOpen: boolean;
|
sidebarOpen: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -17,6 +17,7 @@ import { dialogBoxCreate } from "../ui/React/DialogBox";
|
|||||||
import { Settings } from "../Settings/Settings";
|
import { Settings } from "../Settings/Settings";
|
||||||
|
|
||||||
import * as React from "react";
|
import * as React from "react";
|
||||||
|
import { throwIfReachable } from "../utils/helpers/throwIfReachable";
|
||||||
|
|
||||||
export interface IProcessOrderRefs {
|
export interface IProcessOrderRefs {
|
||||||
stockMarket: IStockMarket;
|
stockMarket: IStockMarket;
|
||||||
@ -50,8 +51,8 @@ export function processOrders(
|
|||||||
return; // Newly created, so no orders to process
|
return; // Newly created, so no orders to process
|
||||||
}
|
}
|
||||||
let stockOrders = orderBook[stock.symbol];
|
let stockOrders = orderBook[stock.symbol];
|
||||||
if (stockOrders == null || !(stockOrders.constructor === Array)) {
|
if (stockOrders == null || !Array.isArray(stockOrders)) {
|
||||||
console.error(`Invalid Order book for ${stock.symbol} in processOrders(): ${stockOrders}`);
|
console.error(`Invalid Order book for ${stock.symbol} in processOrders(). stockOrders: ${stockOrders}`);
|
||||||
stockOrders = [];
|
stockOrders = [];
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -88,8 +89,7 @@ export function processOrders(
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
console.warn(`Invalid order type: ${order.type}`);
|
throwIfReachable(order.type);
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -137,8 +137,7 @@ function executeOrder(order: Order, refs: IProcessOrderRefs): void {
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
console.warn(`Invalid order type: ${order.type}`);
|
throwIfReachable(order.type);
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Position type, for logging/message purposes
|
// Position type, for logging/message purposes
|
||||||
|
@ -21,6 +21,9 @@ export function check(args: (string | number | boolean)[], server: BaseServer):
|
|||||||
Terminal.error(`No script named ${scriptName} is running on the server`);
|
Terminal.error(`No script named ${scriptName} is running on the server`);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
runningScripts.values().next().value.displayLog();
|
const next = runningScripts.values().next();
|
||||||
|
if (!next.done) {
|
||||||
|
next.value.displayLog();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -9,11 +9,11 @@ export function expr(args: (string | number | boolean)[]): void {
|
|||||||
|
|
||||||
// Sanitize the math expression
|
// Sanitize the math expression
|
||||||
const sanitizedExpr = expr.replace(/[^-()\d/*+.%]/g, "");
|
const sanitizedExpr = expr.replace(/[^-()\d/*+.%]/g, "");
|
||||||
let result;
|
let result: string;
|
||||||
try {
|
try {
|
||||||
result = eval?.(sanitizedExpr);
|
result = String(eval?.(sanitizedExpr));
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
Terminal.error(`Could not evaluate expression: ${sanitizedExpr}`);
|
Terminal.error(`Could not evaluate expression: ${sanitizedExpr}. Error: ${e}.`);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Terminal.print(result);
|
Terminal.print(result);
|
||||||
|
@ -86,7 +86,7 @@ export function TerminalInput(): React.ReactElement {
|
|||||||
function getSearchSuggestionPrespace() {
|
function getSearchSuggestionPrespace() {
|
||||||
const currentPrefix = `[${Player.getCurrentServer().hostname} /${Terminal.cwd()}]> `;
|
const currentPrefix = `[${Player.getCurrentServer().hostname} /${Terminal.cwd()}]> `;
|
||||||
const prefixLength = `${currentPrefix}${value}`.length;
|
const prefixLength = `${currentPrefix}${value}`.length;
|
||||||
return Array(prefixLength).fill(" ");
|
return Array<string>(prefixLength).fill(" ");
|
||||||
}
|
}
|
||||||
|
|
||||||
function modifyInput(mod: Modification): void {
|
function modifyInput(mod: Modification): void {
|
||||||
@ -206,7 +206,7 @@ export function TerminalInput(): React.ReactElement {
|
|||||||
return () => document.removeEventListener("keydown", keyDown);
|
return () => document.removeEventListener("keydown", keyDown);
|
||||||
});
|
});
|
||||||
|
|
||||||
async function onKeyDown(event: React.KeyboardEvent<HTMLInputElement>): Promise<void> {
|
async function onKeyDown(event: React.KeyboardEvent<HTMLInputElement | HTMLTextAreaElement>): Promise<void> {
|
||||||
const ref = terminalInput.current;
|
const ref = terminalInput.current;
|
||||||
|
|
||||||
// Run command or insert newline
|
// Run command or insert newline
|
||||||
@ -427,7 +427,11 @@ export function TerminalInput(): React.ReactElement {
|
|||||||
setPossibilities([]);
|
setPossibilities([]);
|
||||||
resetSearch();
|
resetSearch();
|
||||||
},
|
},
|
||||||
onKeyDown: onKeyDown,
|
onKeyDown: (event) => {
|
||||||
|
onKeyDown(event).catch((error) => {
|
||||||
|
console.error(error);
|
||||||
|
});
|
||||||
|
},
|
||||||
}}
|
}}
|
||||||
></TextField>
|
></TextField>
|
||||||
<Popper
|
<Popper
|
||||||
|
@ -41,7 +41,7 @@ export function TerminalRoot(): React.ReactElement {
|
|||||||
const [key, setKey] = useState(0);
|
const [key, setKey] = useState(0);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const debounced = _.debounce(async () => rerender(), 25, { maxWait: 50 });
|
const debounced = _.debounce(() => rerender(), 25, { maxWait: 50 });
|
||||||
const unsubscribe = TerminalEvents.subscribe(debounced);
|
const unsubscribe = TerminalEvents.subscribe(debounced);
|
||||||
return () => {
|
return () => {
|
||||||
debounced.cancel();
|
debounced.cancel();
|
||||||
@ -51,7 +51,7 @@ export function TerminalRoot(): React.ReactElement {
|
|||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const clear = () => setKey((key) => key + 1);
|
const clear = () => setKey((key) => key + 1);
|
||||||
const debounced = _.debounce(async () => clear(), 25, { maxWait: 50 });
|
const debounced = _.debounce(() => clear(), 25, { maxWait: 50 });
|
||||||
const unsubscribe = TerminalClearEvents.subscribe(debounced);
|
const unsubscribe = TerminalClearEvents.subscribe(debounced);
|
||||||
return () => {
|
return () => {
|
||||||
debounced.cancel();
|
debounced.cancel();
|
||||||
|
@ -917,7 +917,7 @@ export const codingContractTypesMetadata: CodingContractType<any>[] = [
|
|||||||
desc: (data: number[][]): string => {
|
desc: (data: number[][]): string => {
|
||||||
return [
|
return [
|
||||||
"You are located in the top-left corner of the following grid:\n\n",
|
"You are located in the top-left corner of the following grid:\n\n",
|
||||||
` [${data.map((line) => "[" + line + "]").join(",\n ")}]\n\n`,
|
` [${data.map((line) => `[${line}]`).join(",\n ")}]\n\n`,
|
||||||
"You are trying to find the shortest path to the bottom-right corner of the grid,",
|
"You are trying to find the shortest path to the bottom-right corner of the grid,",
|
||||||
"but there are obstacles on the grid that you cannot move onto.",
|
"but there are obstacles on the grid that you cannot move onto.",
|
||||||
"These obstacles are denoted by '1', while empty spaces are denoted by 0.\n\n",
|
"These obstacles are denoted by '1', while empty spaces are denoted by 0.\n\n",
|
||||||
@ -945,8 +945,8 @@ export const codingContractTypesMetadata: CodingContractType<any>[] = [
|
|||||||
const dstX = width - 1;
|
const dstX = width - 1;
|
||||||
const minPathLength = dstY + dstX; // Math.abs(dstY - srcY) + Math.abs(dstX - srcX)
|
const minPathLength = dstY + dstX; // Math.abs(dstY - srcY) + Math.abs(dstX - srcX)
|
||||||
|
|
||||||
const grid: number[][] = new Array(height);
|
const grid: number[][] = new Array<number[]>(height);
|
||||||
for (let y = 0; y < height; y++) grid[y] = new Array(width).fill(0);
|
for (let y = 0; y < height; y++) grid[y] = new Array<number>(width).fill(0);
|
||||||
|
|
||||||
for (let y = 0; y < height; y++) {
|
for (let y = 0; y < height; y++) {
|
||||||
for (let x = 0; x < width; x++) {
|
for (let x = 0; x < width; x++) {
|
||||||
@ -969,12 +969,12 @@ export const codingContractTypesMetadata: CodingContractType<any>[] = [
|
|||||||
const dstY = height - 1;
|
const dstY = height - 1;
|
||||||
const dstX = width - 1;
|
const dstX = width - 1;
|
||||||
|
|
||||||
const distance: [number][] = new Array(height);
|
const distance: number[][] = new Array<number[]>(height);
|
||||||
//const prev: [[number, number] | undefined][] = new Array(height);
|
//const prev: [[number, number] | undefined][] = new Array(height);
|
||||||
const queue: [number, number][] = [];
|
const queue: [number, number][] = [];
|
||||||
|
|
||||||
for (let y = 0; y < height; y++) {
|
for (let y = 0; y < height; y++) {
|
||||||
distance[y] = new Array(width).fill(Infinity) as [number];
|
distance[y] = new Array<number>(width).fill(Infinity);
|
||||||
//prev[y] = new Array(width).fill(undefined) as [undefined];
|
//prev[y] = new Array(width).fill(undefined) as [undefined];
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1422,7 +1422,7 @@ export const codingContractTypesMetadata: CodingContractType<any>[] = [
|
|||||||
//Attempt to construct one to check if this is correct.
|
//Attempt to construct one to check if this is correct.
|
||||||
if (sanitizedPlayerAns === "") {
|
if (sanitizedPlayerAns === "") {
|
||||||
//Verify that there is no solution by attempting to create a proper 2-coloring.
|
//Verify that there is no solution by attempting to create a proper 2-coloring.
|
||||||
const coloring: (number | undefined)[] = Array(data[0]).fill(undefined);
|
const coloring: (number | undefined)[] = Array<number | undefined>(data[0]).fill(undefined);
|
||||||
while (coloring.some((val) => val === undefined)) {
|
while (coloring.some((val) => val === undefined)) {
|
||||||
//Color a vertex in the graph
|
//Color a vertex in the graph
|
||||||
const initialVertex: number = coloring.findIndex((val) => val === undefined);
|
const initialVertex: number = coloring.findIndex((val) => val === undefined);
|
||||||
@ -1435,9 +1435,7 @@ export const codingContractTypesMetadata: CodingContractType<any>[] = [
|
|||||||
const neighbors: number[] = neighbourhood(v);
|
const neighbors: number[] = neighbourhood(v);
|
||||||
|
|
||||||
//For each vertex u adjacent to v
|
//For each vertex u adjacent to v
|
||||||
for (const id in neighbors) {
|
for (const u of neighbors) {
|
||||||
const u: number = neighbors[id];
|
|
||||||
|
|
||||||
//Set the color of u to the opposite of v's color if it is new,
|
//Set the color of u to the opposite of v's color if it is new,
|
||||||
//then add u to the frontier to continue the algorithm.
|
//then add u to the frontier to continue the algorithm.
|
||||||
if (coloring[u] === undefined) {
|
if (coloring[u] === undefined) {
|
||||||
|
@ -46,7 +46,7 @@ export const A = (props: React.PropsWithChildren<{ href?: string }>): React.Reac
|
|||||||
cursor: "pointer",
|
cursor: "pointer",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<CorruptableText content={props.children + ""} spoiler={true} />
|
<CorruptableText content={String(props.children)} spoiler={true} />
|
||||||
</span>
|
</span>
|
||||||
);
|
);
|
||||||
return (
|
return (
|
||||||
|
@ -38,7 +38,7 @@ type RowName = SkillRowName | "HP" | "Money";
|
|||||||
const OverviewEventEmitter = new EventEmitter();
|
const OverviewEventEmitter = new EventEmitter();
|
||||||
|
|
||||||
// These values aren't displayed, they're just used for comparison to check if state has changed
|
// These values aren't displayed, they're just used for comparison to check if state has changed
|
||||||
const valUpdaters: Record<RowName, () => any> = {
|
const valUpdaters: Record<RowName, () => unknown> = {
|
||||||
HP: () => Player.hp.current + "|" + Player.hp.max, // This isn't displayed, it's just compared for updates.
|
HP: () => Player.hp.current + "|" + Player.hp.max, // This isn't displayed, it's just compared for updates.
|
||||||
Money: () => Player.money,
|
Money: () => Player.money,
|
||||||
Hack: () => Player.skills.hacking,
|
Hack: () => Player.skills.hacking,
|
||||||
|
@ -26,9 +26,11 @@ export function CinematicLine(props: IProps): React.ReactElement {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
let cancel = false;
|
let cancel = false;
|
||||||
(async () => {
|
sleep(10)
|
||||||
await sleep(10).then(() => !cancel && advance());
|
.then(() => !cancel && advance())
|
||||||
})();
|
.catch((error) => {
|
||||||
|
console.error(error);
|
||||||
|
});
|
||||||
return () => {
|
return () => {
|
||||||
cancel = true;
|
cancel = true;
|
||||||
};
|
};
|
||||||
|
@ -399,7 +399,11 @@ export const ImportSave = (props: { saveData: SaveData; automatic: boolean }): J
|
|||||||
<ConfirmationModal
|
<ConfirmationModal
|
||||||
open={isImportModalOpen}
|
open={isImportModalOpen}
|
||||||
onClose={closeImportModal}
|
onClose={closeImportModal}
|
||||||
onConfirm={handleImport}
|
onConfirm={() => {
|
||||||
|
handleImport().catch((error) => {
|
||||||
|
console.error(error);
|
||||||
|
});
|
||||||
|
}}
|
||||||
confirmationText={
|
confirmationText={
|
||||||
<>
|
<>
|
||||||
Importing new save game data will <strong>completely wipe</strong> the current game data!
|
Importing new save game data will <strong>completely wipe</strong> the current game data!
|
||||||
|
@ -298,7 +298,16 @@ function LogWindow({ hidden, script, onClose }: LogWindowProps): React.ReactElem
|
|||||||
return !(bounds.right < 0 || bounds.bottom < 0 || bounds.left > innerWidth || bounds.top > outerWidth);
|
return !(bounds.right < 0 || bounds.bottom < 0 || bounds.left > innerWidth || bounds.top > outerWidth);
|
||||||
};
|
};
|
||||||
|
|
||||||
const onDrag = (e: DraggableEvent): void | false => {
|
/**
|
||||||
|
* The returned type of onDrag is a bit weird here. The Draggable component expects an onDrag that returns "void | false".
|
||||||
|
* In that component's internal code, it checks for the explicit "false" value. If onDrag returns false, the component
|
||||||
|
* cancels the dragging.
|
||||||
|
*
|
||||||
|
* That's why they use "void | false" as the returned type. However, in TypeScript, "void" is not supposed to be used
|
||||||
|
* like that. ESLint will complain "void is not valid as a constituent in a union type". Please check its documentation
|
||||||
|
* for the reason. In order to solve this problem, I changed the returned type to "undefined | false".
|
||||||
|
*/
|
||||||
|
const onDrag = (e: DraggableEvent): undefined | false => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
// bound to body
|
// bound to body
|
||||||
if (
|
if (
|
||||||
|
@ -98,7 +98,7 @@ export function RecoveryRoot({ softReset, errorData, resetError }: IProps): Reac
|
|||||||
{sourceError && (
|
{sourceError && (
|
||||||
<Box>
|
<Box>
|
||||||
<Typography variant="h6" color={Settings.theme.error}>
|
<Typography variant="h6" color={Settings.theme.error}>
|
||||||
Error: {sourceError.toString()}
|
Error: {String(sourceError)}
|
||||||
</Typography>
|
</Typography>
|
||||||
<br />
|
<br />
|
||||||
</Box>
|
</Box>
|
||||||
|
@ -14,7 +14,7 @@ interface IProps {
|
|||||||
const useStyles = makeStyles()({
|
const useStyles = makeStyles()({
|
||||||
snackbar: {
|
snackbar: {
|
||||||
// Log popup z-index increments, so let's add a padding to be well above them.
|
// Log popup z-index increments, so let's add a padding to be well above them.
|
||||||
zIndex: `${logBoxBaseZIndex + 1000} !important` as any,
|
zIndex: `${logBoxBaseZIndex + 1000} !important`,
|
||||||
|
|
||||||
"& .MuiAlert-icon": {
|
"& .MuiAlert-icon": {
|
||||||
alignSelf: "center",
|
alignSelf: "center",
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
// choose random character for generating plaintexts to compress
|
// choose random characters for generating plaintext to compress
|
||||||
export function comprGenChar(): string {
|
export function comprGenChar(): string {
|
||||||
const r = Math.random();
|
const r = Math.random();
|
||||||
if (r < 0.4) {
|
if (r < 0.4) {
|
||||||
@ -34,13 +34,13 @@ export function comprLZGenerate(): string {
|
|||||||
return plain.substring(0, length);
|
return plain.substring(0, length);
|
||||||
}
|
}
|
||||||
|
|
||||||
// compress plaintest string
|
// compress plaintext string
|
||||||
export function comprLZEncode(plain: string): string {
|
export function comprLZEncode(plain: string): string {
|
||||||
// for state[i][j]:
|
// for state[i][j]:
|
||||||
// if i is 0, we're adding a literal of length j
|
// if i is 0, we're adding a literal of length j
|
||||||
// else, we're adding a backreference of offset i and length j
|
// else, we're adding a backreference of offset i and length j
|
||||||
let cur_state: (string | null)[][] = Array.from(Array(10), () => Array(10).fill(null));
|
let cur_state: (string | null)[][] = Array.from(Array(10), () => Array<string | null>(10).fill(null));
|
||||||
let new_state: (string | null)[][] = Array.from(Array(10), () => Array(10));
|
let new_state: (string | null)[][] = Array.from(Array(10), () => Array<string | null>(10));
|
||||||
|
|
||||||
function set(state: (string | null)[][], i: number, j: number, str: string): void {
|
function set(state: (string | null)[][], i: number, j: number, str: string): void {
|
||||||
const current = state[i][j];
|
const current = state[i][j];
|
||||||
|
@ -3,7 +3,7 @@ import { Terminal } from "../Terminal";
|
|||||||
const deprecatedWarningsGiven = new Set();
|
const deprecatedWarningsGiven = new Set();
|
||||||
export function setDeprecatedProperties(
|
export function setDeprecatedProperties(
|
||||||
obj: object,
|
obj: object,
|
||||||
properties: Record<string, { identifier: string; message: string; value: any }>,
|
properties: Record<string, { identifier: string; message: string; value: unknown }>,
|
||||||
) {
|
) {
|
||||||
for (const [name, info] of Object.entries(properties)) {
|
for (const [name, info] of Object.entries(properties)) {
|
||||||
Object.defineProperty(obj, name, {
|
Object.defineProperty(obj, name, {
|
||||||
@ -11,7 +11,7 @@ export function setDeprecatedProperties(
|
|||||||
deprecationWarning(info.identifier, info.message);
|
deprecationWarning(info.identifier, info.message);
|
||||||
return info.value;
|
return info.value;
|
||||||
},
|
},
|
||||||
set: (value: any) => (info.value = value),
|
set: (value: unknown) => (info.value = value),
|
||||||
enumerable: true,
|
enumerable: true,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -5,6 +5,7 @@ import * as allEnums from "../Enums";
|
|||||||
import { assertString } from "../Netscript/TypeAssertion";
|
import { assertString } from "../Netscript/TypeAssertion";
|
||||||
import { errorMessage } from "../Netscript/ErrorMessages";
|
import { errorMessage } from "../Netscript/ErrorMessages";
|
||||||
import { getRandomIntInclusive } from "./helpers/getRandomIntInclusive";
|
import { getRandomIntInclusive } from "./helpers/getRandomIntInclusive";
|
||||||
|
import { getRecordValues } from "../Types/Record";
|
||||||
|
|
||||||
interface GetMemberOptions {
|
interface GetMemberOptions {
|
||||||
/** Whether to use fuzzy matching on the input (case insensitive, ignore spaces and dashes) */
|
/** Whether to use fuzzy matching on the input (case insensitive, ignore spaces and dashes) */
|
||||||
@ -22,7 +23,7 @@ class EnumHelper<EnumObj extends object, EnumMember extends Member<EnumObj> & st
|
|||||||
constructor(obj: EnumObj, name: string) {
|
constructor(obj: EnumObj, name: string) {
|
||||||
this.name = name;
|
this.name = name;
|
||||||
this.defaultArgName = name.charAt(0).toLowerCase() + name.slice(1);
|
this.defaultArgName = name.charAt(0).toLowerCase() + name.slice(1);
|
||||||
this.valueArray = Object.values(obj);
|
this.valueArray = getRecordValues(obj);
|
||||||
this.valueSet = new Set(this.valueArray);
|
this.valueSet = new Set(this.valueArray);
|
||||||
this.fuzzMap = new Map(this.valueArray.map((val) => [val.toLowerCase().replace(/[ -]+/g, ""), val]));
|
this.fuzzMap = new Map(this.valueArray.map((val) => [val.toLowerCase().replace(/[ -]+/g, ""), val]));
|
||||||
}
|
}
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
export function HammingEncode(data: number): string {
|
export function HammingEncode(data: number): string {
|
||||||
const enc: number[] = [0];
|
const enc: number[] = [0];
|
||||||
const data_bits: any[] = data.toString(2).split("").reverse();
|
const data_bits: number[] = data
|
||||||
|
.toString(2)
|
||||||
data_bits.forEach((e, i, a) => {
|
.split("")
|
||||||
a[i] = parseInt(e);
|
.reverse()
|
||||||
});
|
.map((value) => parseInt(value));
|
||||||
|
|
||||||
let k = data_bits.length;
|
let k = data_bits.length;
|
||||||
|
|
||||||
@ -18,35 +18,36 @@ export function HammingEncode(data: number): string {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let parity: any = 0;
|
let parityNumber = 0;
|
||||||
|
|
||||||
/* Figure out the subsection parities */
|
/* Figure out the subsection parities */
|
||||||
for (let i = 0; i < enc.length; i++) {
|
for (let i = 0; i < enc.length; i++) {
|
||||||
if (enc[i]) {
|
if (enc[i]) {
|
||||||
parity ^= i;
|
parityNumber ^= i;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
parity = parity.toString(2).split("").reverse();
|
const parityArray = parityNumber
|
||||||
parity.forEach((e: any, i: any, a: any) => {
|
.toString(2)
|
||||||
a[i] = parseInt(e);
|
.split("")
|
||||||
});
|
.reverse()
|
||||||
|
.map((value) => parseInt(value));
|
||||||
|
|
||||||
/* Set the parity bits accordingly */
|
/* Set the parity bits accordingly */
|
||||||
for (let i = 0; i < parity.length; i++) {
|
for (let i = 0; i < parityArray.length; i++) {
|
||||||
enc[2 ** i] = parity[i] ? 1 : 0;
|
enc[2 ** i] = parityArray[i] ? 1 : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
parity = 0;
|
parityNumber = 0;
|
||||||
/* Figure out the overall parity for the entire block */
|
/* Figure out the overall parity for the entire block */
|
||||||
for (let i = 0; i < enc.length; i++) {
|
for (let i = 0; i < enc.length; i++) {
|
||||||
if (enc[i]) {
|
if (enc[i]) {
|
||||||
parity++;
|
parityNumber++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Finally set the overall parity bit */
|
/* Finally set the overall parity bit */
|
||||||
enc[0] = parity % 2 == 0 ? 0 : 1;
|
enc[0] = parityNumber % 2 == 0 ? 0 : 1;
|
||||||
|
|
||||||
return enc.join("");
|
return enc.join("");
|
||||||
}
|
}
|
||||||
@ -68,11 +69,11 @@ export function HammingEncodeProperly(data: number): string {
|
|||||||
const k: number = 2 ** m - m - 1;
|
const k: number = 2 ** m - m - 1;
|
||||||
|
|
||||||
const enc: number[] = [0];
|
const enc: number[] = [0];
|
||||||
const data_bits: any[] = data.toString(2).split("").reverse();
|
const data_bits: number[] = data
|
||||||
|
.toString(2)
|
||||||
data_bits.forEach((e, i, a) => {
|
.split("")
|
||||||
a[i] = parseInt(e);
|
.reverse()
|
||||||
});
|
.map((value) => parseInt(value));
|
||||||
|
|
||||||
/* Flip endianness as in the original implementation by Hedrauta
|
/* Flip endianness as in the original implementation by Hedrauta
|
||||||
* and write the data back to front
|
* and write the data back to front
|
||||||
@ -83,35 +84,36 @@ export function HammingEncodeProperly(data: number): string {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let parity: any = 0;
|
let parityNumber = 0;
|
||||||
|
|
||||||
/* Figure out the subsection parities */
|
/* Figure out the subsection parities */
|
||||||
for (let i = 0; i < n; i++) {
|
for (let i = 0; i < n; i++) {
|
||||||
if (enc[i]) {
|
if (enc[i]) {
|
||||||
parity ^= i;
|
parityNumber ^= i;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
parity = parity.toString(2).split("").reverse();
|
const parityArray = parityNumber
|
||||||
parity.forEach((e: any, i: any, a: any) => {
|
.toString(2)
|
||||||
a[i] = parseInt(e);
|
.split("")
|
||||||
});
|
.reverse()
|
||||||
|
.map((value) => parseInt(value));
|
||||||
|
|
||||||
/* Set the parity bits accordingly */
|
/* Set the parity bits accordingly */
|
||||||
for (let i = 0; i < m; i++) {
|
for (let i = 0; i < m; i++) {
|
||||||
enc[2 ** i] = parity[i] ? 1 : 0;
|
enc[2 ** i] = parityArray[i] ? 1 : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
parity = 0;
|
parityNumber = 0;
|
||||||
/* Figure out the overall parity for the entire block */
|
/* Figure out the overall parity for the entire block */
|
||||||
for (let i = 0; i < n; i++) {
|
for (let i = 0; i < n; i++) {
|
||||||
if (enc[i]) {
|
if (enc[i]) {
|
||||||
parity++;
|
parityNumber++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Finally set the overall parity bit */
|
/* Finally set the overall parity bit */
|
||||||
enc[0] = parity % 2 == 0 ? 0 : 1;
|
enc[0] = parityNumber % 2 == 0 ? 0 : 1;
|
||||||
|
|
||||||
return enc.join("");
|
return enc.join("");
|
||||||
}
|
}
|
||||||
@ -121,8 +123,9 @@ export function HammingDecode(data: string): number {
|
|||||||
const bits: number[] = [];
|
const bits: number[] = [];
|
||||||
|
|
||||||
/* TODO why not just work with an array of digits from the start? */
|
/* TODO why not just work with an array of digits from the start? */
|
||||||
for (const i in data.split("")) {
|
const bitStringArray = data.split("");
|
||||||
const bit = parseInt(data[i]);
|
for (let i = 0; i < bitStringArray.length; ++i) {
|
||||||
|
const bit = parseInt(bitStringArray[i]);
|
||||||
bits[i] = bit;
|
bits[i] = bit;
|
||||||
|
|
||||||
if (bit) {
|
if (bit) {
|
||||||
|
@ -125,3 +125,9 @@ export function getNsApiDocumentationUrl(isDevBranch: boolean = CONSTANTS.isDevB
|
|||||||
isDevBranch ? "dev" : "stable"
|
isDevBranch ? "dev" : "stable"
|
||||||
}/markdown/bitburner.ns.md`;
|
}/markdown/bitburner.ns.md`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function getKeyFromReactElements(a: string | React.JSX.Element, b: string | React.JSX.Element): string {
|
||||||
|
const keyOfA = typeof a === "string" ? a : a.key ?? "";
|
||||||
|
const keyOfb = typeof b === "string" ? b : b.key ?? "";
|
||||||
|
return keyOfA + keyOfb;
|
||||||
|
}
|
||||||
|
3
src/utils/helpers/throwIfReachable.ts
Normal file
3
src/utils/helpers/throwIfReachable.ts
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
export function throwIfReachable(missingCase: never) {
|
||||||
|
throw new Error(`The case of ${missingCase} was not handled.`);
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user